Избегайте большого количества вычислений на чертежах.
Все фигуры фактически имеют одинаковую постоянную ширину и высоту и постоянное смещение относительно предыдущей в стеке.
Единственная действительная переменная весть положение камеры.
Поэтому измените только эту камеру, и для этого измените только матрицу преобразования вашего контекста.
Вам необходимо
- перевести контекст в начало координат первой фигуры
- масштабировать контекст по текущему значению масштаба
- наклонитьконтекст по -1 по оси Y
- нарисуйте свой стек с постоянными значениями
Три первых шага можно сделать за один вызов абсолютного setTransform Метод.
Параметры будут,
setTransform(
scale, // scale-x
0, // skew-x
- scale, // skew-y (we use '- scale' here because skew should be made
// after scale so we need to multiply by scale)
scale, // scale-y
origin_x, // these should be made before so normal scale is ok
origin_y
)
После этого реальная часть чертежа всегда будет одинаковой.
const canvas = document.getElementById("canvas")
canvas.width = canvas.height = 200;
const ctx = canvas.getContext("2d")
const input = document.querySelector('input');
function update() {
// some constants about our shapes
const origin_x = 160; // center of all the rects
const origin_y = 160; // bottom of all the shapes
const w = 33; // width of each rect
const h = 16.5; // height of each rect
const offset = 11; // axis offset (* i)
const scale = input.value;
// first reset the transformation matrix
ctx.setTransform(1,0,0,1,0,0);
// so we clear everything
ctx.clearRect(0, 0, canvas.width, canvas.height)
// now we move our context
// so that our origins are in the top - left
// and that we are already scaled and skewed
ctx.setTransform(scale, 0, -scale, scale, origin_x, origin_y);
// from now on, we don't care about the scale
for (let i = 0; i < 4; i++) {
ctx.fillStyle = (i === 2) ? "#3b2a19" : "#957e67"
let layer = {
x: -i * offset - w/2,
y: -i * offset,
width: w,
height: h
}
ctx.fillRect(layer.x, layer.y, layer.width, layer.height)
ctx.strokeRect(layer.x, layer.y, layer.width, layer.height)
}
}
input.oninput = update;
input.oninput();
#canvas {
border: 2px solid red
}
input {
display: block;
width: 75vw;
}
<input type="range" min="0.01" max="20" value="1" step="0.001" id="inp"/>
<canvas id="canvas"></canvas>