Увеличьте точку на холсте - PullRequest
0 голосов
/ 22 октября 2018

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

Сначала я получаю точку мыши и использую матрицу преобразования холста, чтобы получить точку в контексте холста (https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-gettransform).

const domPoint = new window.DOMPoint(event.offsetX, event.offsetY);
const currMatrix = this.canvasManager.ctx.getTransform();
const canvasPoint = domPoint.matrixTransform(currMatrix);

Затем я перевожу, масштабирую и перевожу обратно, используя матрицу, возвращенную в getTransform (объект DOMMatrix).

const m = currMatrix
.translateSelf(canvasPoint.x, canvasPoint.y)
.scaleSelf(scale, scale)
.translateSelf(-canvasPoint.x, -canvasPoint.y);

Наконец, я установил преобразование, используя последнюю матрицу.

this.ctx.setTransform(this.zoom.matrix)

Метод, который я использую, основан на одном ответе переполнения стека .

Вот мой код

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var currMatrix = ctx.getTransform();

var plusBtn = document.getElementById("plus");
var minusBtn = document.getElementById("minus");
var infoP = document.getElementById("info");

var zoom;
var scale = 1;
const scaleFactor = 0.1;

function draw() {
	ctx.clearRect(0, 0, canvas.width, canvas.height);
	ctx.setTransform(currMatrix)
	ctx.fillStyle = "blue";
	ctx.fillRect(50, 50, 100, 100);
}
draw()

function getDomPoint(event) {
	const offSetCanvasLeft = canvas.getBoundingClientRect().left;
  const offSetCanvasTop = canvas.getBoundingClientRect().top;

	return {
    x: event.pageX - offSetCanvasLeft,
    y: event.pageY - offSetCanvasTop,
  }
}

function domToCanvasPoint(point) {
	const domPoint = new window.DOMPoint(point.x, point.y);
	return domPoint.matrixTransform(currMatrix);
}

function updateScale() {
  scale = zoom === 'in' ? scale + scaleFactor : scale - scaleFactor ;
  setDebugInfo(scale)
}

function zoomMatrixIntoPoint(point) {
	currMatrix = currMatrix
    .translateSelf(point.x, point.y)
    .scaleSelf(scale, scale)
    .translateSelf(-point.x, -point.y);
}

function setDebugInfo(msg) {
	infoP.innerHTML = msg;
}

canvas.addEventListener('mousedown', function(event) {  
	const domPoint = getDomPoint(event);
  const canvasPoint = domToCanvasPoint(domPoint);
  updateScale();
  zoomMatrixIntoPoint(canvasPoint);
  draw()
}, false);

plusBtn.addEventListener('click', function(event) {    
	zoom = 'in'
  setDebugInfo(`ZOOM IN with scale ${scale}`)
}, false);

minusBtn.addEventListener('click', function(event) {    
	zoom = 'out'
  setDebugInfo(`ZOOM OUT with scale ${scale}`)
}, false);
<canvas id="myCanvas" width="300" height="300" style="border:1px solid black"></canvas>
<button id="plus">+</button>
<button id="minus">-</button>
<p id="info">info here!</p>

Буду признателен за любую помощь.Спасибо.

1 Ответ

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

Ваша проблема - простая логическая ошибка.

Вы сохраняете curMatrix и обновляете ее каждый раз.Это означает, что все значения, которые вы передаете translateSelf и scaleSelf, относятся к предыдущим значениям.

Однако, когда вы делаете scale -= scaleFactor или scale += scaleFactor, scale является абсолютным значением шкалы.
Поэтому, когда вы используете его позже в scaleSelf, выбыстро установить огромное абсолютное значение шкалы, которое не будет уменьшаться до тех пор, пока оно не станет меньше 1.

(1.1 * 1.2 * 1.3 * 1.4 * 1.5 * 1.6) => real scale is 5.8

и

(1.1 * 1.2 * 1.3 * 1.2 * 1.1 * 1) => real scale is 2.3
                 ^-- click zoom-out

Так что все, что вам нужно исправить, этострока, которая устанавливает это scale значение: вместо того, чтобы увеличивать это значение, всегда устанавливайте его на 1 основе.

scale = zoom === 'in' ? 1 + scaleFactor : 1 - scaleFactor ;

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var currMatrix = ctx.getTransform();

var plusBtn = document.getElementById("plus");
var minusBtn = document.getElementById("minus");
var infoP = document.getElementById("info");

var zoom;
var scale = 1;
const scaleFactor = 0.1;

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.setTransform(currMatrix)
  ctx.fillStyle = "blue";
  ctx.fillRect(50, 50, 100, 100);
}
draw()

function getDomPoint(event) {
  const offSetCanvasLeft = canvas.getBoundingClientRect().left;
  const offSetCanvasTop = canvas.getBoundingClientRect().top;

  return {
    x: event.pageX - offSetCanvasLeft,
    y: event.pageY - offSetCanvasTop,
  }
}

function domToCanvasPoint(point) {
  const domPoint = new window.DOMPoint(point.x, point.y);
  return domPoint.matrixTransform(currMatrix);
}

function updateScale() {
  scale = zoom === 'in' ? 1 + scaleFactor : 1 - scaleFactor;
  setDebugInfo(scale)
}

function zoomMatrixIntoPoint(point) {
  currMatrix
    .translateSelf(point.x, point.y)
    .scaleSelf(scale, scale)
    .translateSelf(-point.x, -point.y);
}

function setDebugInfo(msg) {
  infoP.innerHTML = msg;
}

canvas.addEventListener('mousedown', function(event) {
  const domPoint = getDomPoint(event);
  const canvasPoint = domToCanvasPoint(domPoint);
  updateScale();
  zoomMatrixIntoPoint(canvasPoint);
  draw()
}, false);

plusBtn.addEventListener('click', function(event) {
  zoom = 'in'
  setDebugInfo(`ZOOM IN with scale ${scale}`)
}, false);

minusBtn.addEventListener('click', function(event) {
  zoom = 'out'
  setDebugInfo(`ZOOM OUT with scale ${scale}`)
}, false);
<canvas id="myCanvas" width="300" height="300" style="border:1px solid black"></canvas>
<button id="plus">+</button>
<button id="minus">-</button>
<p id="info">info here!</p>

Также обратите внимание, что DOMMatrix # scale () принимает необязательные origin аргументы, которыепозволит вам избежать двух вызовов преобразования:

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var currMatrix = ctx.getTransform();

var plusBtn = document.getElementById("plus");
var minusBtn = document.getElementById("minus");
var infoP = document.getElementById("info");

var zoom;
var scale = 1;
const scaleFactor = 0.1;

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.setTransform(currMatrix)
  ctx.fillStyle = "blue";
  ctx.fillRect(50, 50, 100, 100);
}
draw()

function getDomPoint(event) {
  const offSetCanvasLeft = canvas.getBoundingClientRect().left;
  const offSetCanvasTop = canvas.getBoundingClientRect().top;

  return {
    x: event.pageX - offSetCanvasLeft,
    y: event.pageY - offSetCanvasTop,
  }
}

function domToCanvasPoint(point) {
  const domPoint = new window.DOMPoint(point.x, point.y);
  return domPoint.matrixTransform(currMatrix);
}

function updateScale() {
  scale = zoom === 'in' ? 1 + scaleFactor : 1 - scaleFactor;
  setDebugInfo(scale)
}

function zoomMatrixIntoPoint(point) {
  currMatrix
  // scaleSelf(scaleX, scaleY, scaleZ, originX, originY, originZ)  
    .scaleSelf(scale, scale, 1, point.x, point.y, 0)
}

function setDebugInfo(msg) {
  infoP.innerHTML = msg;
}

canvas.addEventListener('mousedown', function(event) {
  const domPoint = getDomPoint(event);
  const canvasPoint = domToCanvasPoint(domPoint);
  updateScale();
  zoomMatrixIntoPoint(canvasPoint);
  draw()
}, false);

plusBtn.addEventListener('click', function(event) {
  zoom = 'in'
  setDebugInfo(`ZOOM IN with scale ${scale}`)
}, false);

minusBtn.addEventListener('click', function(event) {
  zoom = 'out'
  setDebugInfo(`ZOOM OUT with scale ${scale}`)
}, false);
<canvas id="myCanvas" width="300" height="300" style="border:1px solid black"></canvas>
<button id="plus">+</button>
<button id="minus">-</button>
<p id="info">info here!</p>

И если вам нужно, чтобы все ваши значения были абсолютными (т.е. тоже переводились), то просто каждый раз создавайте новую DOMMatrix, и здесь сохраняйте исходное приращение масштаба:

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var currMatrix = ctx.getTransform();

var plusBtn = document.getElementById("plus");
var minusBtn = document.getElementById("minus");
var infoP = document.getElementById("info");

var zoom;
var scale = 1;
const scaleFactor = 0.1;

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.setTransform(currMatrix)
  ctx.fillStyle = "blue";
  ctx.fillRect(50, 50, 100, 100);
}
draw()

function getDomPoint(event) {
  const offSetCanvasLeft = canvas.getBoundingClientRect().left;
  const offSetCanvasTop = canvas.getBoundingClientRect().top;

  return {
    x: event.pageX - offSetCanvasLeft,
    y: event.pageY - offSetCanvasTop,
  }
}

function domToCanvasPoint(point) {
  const domPoint = new window.DOMPoint(point.x, point.y);
  return domPoint.matrixTransform(currMatrix);
}

function updateScale() {
  scale = zoom === 'in' ? scale + scaleFactor : scale - scaleFactor;
  setDebugInfo(scale)
}

function zoomMatrixIntoPoint(point) {
  // create a new DOMMatrix
  currMatrix = new DOMMatrix()
    .scaleSelf(scale, scale, 1, point.x, point.y, 0)
}

function setDebugInfo(msg) {
  infoP.innerHTML = msg;
}

canvas.addEventListener('mousedown', function(event) {
  const domPoint = getDomPoint(event);
  const canvasPoint = domToCanvasPoint(domPoint);
  updateScale();
  zoomMatrixIntoPoint(canvasPoint);
  draw()
}, false);

plusBtn.addEventListener('click', function(event) {
  zoom = 'in'
  setDebugInfo(`ZOOM IN with scale ${scale}`)
}, false);

minusBtn.addEventListener('click', function(event) {
  zoom = 'out'
  setDebugInfo(`ZOOM OUT with scale ${scale}`)
}, false);
<canvas id="myCanvas" width="300" height="300" style="border:1px solid black"></canvas>
<button id="plus">+</button>
<button id="minus">-</button>
<p id="info">info here!</p>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...