2d-transform - Как сохранить позицию? - PullRequest
0 голосов
/ 04 октября 2018

Я хочу нарисовать несколько трансформированных в перспективе прямоугольников (фигур) в правом нижнем углу холста.Для этого я использовал ctx.transform: ctx.transform(1, 0, -1, 1, 10, 10).

. Теперь я хочу масштабировать размер моего чертежа с помощью переменной scale=n, но при этом сохранить позицию именно в этой точке (в центре).

Это код, который я написал до сих пор.Перемещение ползунка изменяет положение фигур.Как я могу избежать этого?

let canvas = document.getElementById("canvas")
canvas.width = canvas.height = 200;
$(canvas).appendTo(document.body)
let ctx = canvas.getContext("2d")

let update = function(input) {
  let scale = input.value;
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  ctx.transform(1, 0, -1, 1, 10, 10)
  for (let i = 0; i < 4; i++) {
    ctx.fillStyle = (i === 2) ? "#3b2a19" : "#957e67"
    let layer = {
      x: canvas.width + scale * 7 - i * scale,
      y: canvas.height - scale * 5 - i * scale,
      width: scale * 3,
      height: scale * 1.5
    }
    ctx.fillRect(layer.x, layer.y, layer.width, layer.height)
    ctx.strokeRect(layer.x, layer.y, layer.width, layer.height)
  }
  ctx.resetTransform();
}

$("input").trigger("input")
#canvas {
  border: 2px solid red
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas"></canvas>

<input oninput="update(this)" type="range" min="1" max="20" />

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

Избегайте большого количества вычислений на чертежах.

Все фигуры фактически имеют одинаковую постоянную ширину и высоту и постоянное смещение относительно предыдущей в стеке.
Единственная действительная переменная весть положение камеры.

Поэтому измените только эту камеру, и для этого измените только матрицу преобразования вашего контекста.

Вам необходимо

  • перевести контекст в начало координат первой фигуры
  • масштабировать контекст по текущему значению масштаба
  • наклонитьконтекст по -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>
0 голосов
/ 05 октября 2018

Вместо того, чтобы использовать преобразование, я бы порекомендовал вам рисовать фигуры самостоятельно.

См. Пример кода ниже:

let canvas = document.getElementById("canvas")
canvas.width = canvas.height = 200;
$(canvas).appendTo(document.body)
let ctx = canvas.getContext("2d")

function shape(x,y,s) {
  var f = s/18
  ctx.moveTo(x-10*f, y-60*f);
  ctx.lineTo(x-110*f, y-60*f);
  ctx.lineTo(x-160*f, y-10*f);
  ctx.lineTo(x-60*f, y-10*f);
  ctx.lineTo(x-10*f, y-60*f);
  ctx.fill();
  ctx.stroke();
}

let update = function(input) {
  let scale = input.value;
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  ctx.lineWidth = Math.min(scale/2, 2);
  for (let i = 0; i < 4; i++) {
    ctx.beginPath();
    ctx.fillStyle = (i === 2) ? "#3b2a19" : "#957e67"
    shape(canvas.width, canvas.height -i * scale * 1.5, scale)
  }
}

$("input").trigger("input")
canvas { border: 1px solid red }
input { position: absolute }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input oninput="update(this)" type="range" min="1" max="20" >
<canvas id="canvas"></canvas>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...