Я хочу масштабировать одну ось на чертеже. Как отмечали другие, наивное выполнение этого также приведет к масштабированию lineWidth при обводке контура. В других решениях также указано, что вы можете сделать следующее, чтобы не искажать lineWidth:
ctx.save();
ctx.scale(1, 2);
ctx.beginPath();
// draw shape
ctx.restore();
ctx.stroke();
К сожалению, мне также нужна сложная область обрезки, и метод restore () уничтожает область обрезки. Попробовал просто восстановить масштаб:
ctx.save();
ctx.scale(1, 2);
ctx.beginPath();
// draw shape
ctx.scale(1, 1);
ctx.stroke();
Но это не сработало, и ширина линии осталась искаженной.
Это моделирование физической системы, и задействованные формы являются как дугами, так и линиями. Важно, чтобы пересечения различных форм были точными, поэтому обойтись без зажима и вычислить все возможные пересечения намного сложнее. Кроме того, простое использование шкалы приведет к появлению эллиптических кривых, чего я стараюсь избегать, но это последнее средство.
Любые идеи?
Я не совсем понимаю, что именно вы делаете, и полагаю, что вы могли бы избежать отсечения, используя вместо этого композитинг, который в большинстве случаев обеспечивает лучшую производительность и более чистые результаты.
Но в любом случае, давайте предположим, что вы абсолютно хотите обрезать ...
ctx.save()
будет складывать сохраненные состояния во внутренний объект ArrayLike. Каждый вызов restore()
будет восстанавливать только извлеченный из pop
элемент (т. Е. Самый новый в стеке).
Таким образом, вы можете очень хорошо восстановить состояние до масштабирования, но после обрезки, просто вызвав ctx.save()
между этими двумя операциями.
ctx = c.getContext('2d');
ctx.save(); // stack a first state without clipping, just in case
// define our clipping region
ctx.arc(53,50,30,0,Math.PI*2);
ctx.stroke();
ctx.clip();
// draw once at normal scale
drawShape();
ctx.strokeStyle = 'blue';
ctx.stroke();
// save our context state before we scale
ctx.save();
// now draw scaled
ctx.scale(2, 1);
drawShape();
// restore to before we applied the scale
ctx.restore();
ctx.strokeStyle = 'red';
ctx.stroke();
// restore before clipping
ctx.restore();
// next drawings would be unclipped...
function drawShape() {
ctx.beginPath();
ctx.rect(25, 30, 20, 20);
}
<canvas id = "c"></cavnas>
Теперь вам даже не нужно управлять этим беспорядком состояний контекста, и вы можете просто восстановить матрицу преобразования контекста.
В вашем коде вы используете ctx.scale(1, 1)
. Это запретная операция (ничего не сделает). ctx.scale(factor, factor)
умножит текущие значения шкалы на пройденные вами значения factor
. Так что, начиная с п * 1 = п, это ничего не даст.
Итак, да, вы можете вычислить обратный коэффициент, который вам нужно будет передать (как в вашем примере, это будет ctx.scale(1, 0.5)
), но самым простым решением является использование абсолютного метода setTransform(xScale, xSkew, ySkew, yScale, xTranslate, yTranslate)
.
Чтобы сбросить матрицу контекста к значениям по умолчанию, вам просто нужно запомнить ctx.setTransform(1,0,0,1,0,0);
.
ctx = c.getContext('2d');
// as a bonus, we will use compositing instead of clipping
// but this has no incidence on the demo
// draw once at normal scale
drawShape();
ctx.strokeStyle = 'blue';
ctx.stroke();
// now draw scaled
ctx.scale(2, 1);
drawShape();
// restore the context's matrix
ctx.setTransform(1,0,0,1,0,0);
ctx.strokeStyle = 'red';
ctx.stroke();
// clipping (compositing)
// only the pixels that are currenlty on the context,
// and whose position will match with one of the to be drawn will be kept
ctx.globalCompositeOperation = 'destination-in';
ctx.beginPath();
ctx.arc(53,50,30,0,Math.PI*2);
ctx.fill();
// restore to default
ctx.globalCompositeOperation = 'source-over';
// just to show the clipped area
ctx.strokeStyle = '#000';
ctx.stroke();
function drawShape() {
ctx.beginPath();
ctx.rect(25, 30, 20, 20);
}
<canvas id = "c"></canvas>
Дох! конечно же scale (1, 1) не работает. Я закончил вырезку с "destination-out", которая работала нормально. Прежде чем я наткнулся на это, я попытался просто заполнить форму отсечения с помощью rbga (0, 0, 0, 0), но это не сработало, поскольку оно было наложено поверх оригинала, вместо того, чтобы очищать его. В любом случае, спасибо, что поправили меня.
вы можете предоставить фрагмент кода, воспроизводящий вашу проблему?