Страницы

Поиск по вопросам

пятница, 26 октября 2018 г.

Поворот текста на Canvas

Есть Canvas, на котором отрисовывается изображение. На изображение можно накладывать текст. Можно выбирать угол наклона текста. Изображение можно перемещать по канвасу. Суть в том, что перемещение изображения работает нормально, но текст должен перемещаться вместе с ним. Однако, так как canvas.context в момент отрисовки текста под углом повернут, оси x и y для текста получаются смещенными. То есть, если повернуть текст на 90 градусов, а потом потянуть картинку вниз/вверх, то текст уедет вправо/влево.
Как можно это исправить? Чтобы текст перемещался вместе с картинкой?
Отрисовка изображения:
ctx.drawImage(img, 0, 0, canvas.width, canvas.height, viewportOffsetX, viewportOffsetY, img.width, img.height);
Отрисовка текста поверх изображения:
ctx.save(); var offsetX = textObj.x; var offsetY = textObj.y;
ctx.translate(offsetX, offsetY); ctx.rotate(textObj.rotation); ctx.translate(-offsetX, -offsetY); ctx.font = textObj.fontSize + 'px ' + textObj.font; ctx.fillStyle = textObj.color;
ctx.fillText(textObj.text, textObj.x, textObj.y); textObj.x -= viewportOffsetX; textObj.y -= viewportOffsetY;
ctx.restore();
Изменение viewportOffsetX/viewportOffsetY происходит при драге в mousemove.
viewportOffsetX += deltaX; // смещение по X viewportOffsetY += deltaY; // смещение по Y
var textInput = null; var canvasImage = null; var canvas = null; var ctx = null; var renderingInterval = null; var textComponents = []; var scale = 1; var viewportOffsetX = 0; var viewportOffsetY = 0; var drag = false; var img = null; var text = null; var font = 'arial'; var fontSize = 20; var color = '#000'; var textRotation = 0; var originX = 0; var originY = 0; $(document).ready(function(){ img = new Image(); img.src = "http://www.catster.com/wp-content/uploads/2018/01/Cat-flehmen-response.jpg"; canvas = document.getElementById('canvas'); ctx = canvas.getContext("2d"); textComponents.push({text: 'Test', x: 0, y: 0, saved: true, font: 'arial', fontSize: 30, color: 'red', rotation: Math.PI / 2}); canvas.addEventListener('mousemove', onMouseMove); canvas.addEventListener('touchmove', onMouseMove); canvas.addEventListener('mouseup', onMouseUp); canvas.addEventListener('touchend', onMouseUp); canvas.addEventListener('touchstart', onMouseDown); canvas.addEventListener('mousedown', onMouseDown); img.onload = function(){ renderTextCanvas(); }; }); function renderTextCanvas() { ctx.clearRect(0, 0, img.width, img.height); ctx.scale(scale, scale); ctx.drawImage(img, 0, 0, canvas.width, canvas.height, viewportOffsetX, viewportOffsetY, img.width, img.height); textComponents.forEach(function (textObj) { ctx.save(); ctx.font = textObj.fontSize + 'px ' + textObj.font; ctx.fillStyle = textObj.color; ctx.rotate(textObj.rotation); if (textObj.saved) { ctx.fillText(textObj.text, textObj.x + viewportOffsetX, textObj.y + viewportOffsetY); } else { ctx.fillText(textObj.text, textObj.x, textObj.y); textObj.saved = true; textObj.x -= viewportOffsetX; textObj.y -= viewportOffsetY; } ctx.restore(); }); } function onMouseUp(e) { drag = false; } function onMouseDown(event) { originX = event.pageX; originY = event.pageY; if (event.touches) { var touches = event.touches[0]; originX = touches.pageX; originY = touches.pageY; } if (textInput) { var rect = canvas.getBoundingClientRect(); var x = originX - rect.left; var y = originY - rect.top; registerTextComponent(textInput, x, y); textInput = null; return; } drag = true; } function onMouseMove(e) { if (drag) { var pageX = e.pageX; var pageY = e.pageY; if (e.touches) { var touches = e.touches[0]; pageX = touches.pageX; pageY = touches.pageY; } var deltaX = pageX - originX; var deltaY = pageY - originY; if (Math.abs(viewportOffsetX) < Math.abs(img.width / 2)) { viewportOffsetX += deltaX; } else { if (viewportOffsetX < 0) { viewportOffsetX += 1; } else { viewportOffsetX -= 1; } } if (Math.abs(viewportOffsetY) < Math.abs(img.height / 2)) { viewportOffsetY += deltaY; } else { if (viewportOffsetY < 0) { viewportOffsetY += 1; } else { viewportOffsetY -= 1; } } originX = pageX; originY = pageY; renderTextCanvas(); } } #canvas{ background: #ffe; }


Ответ

Здесь нужно пересчитывать координаты для текста с использованием матрицы поворота в двухмерном пространстве.
var textInput = null; var canvasImage = null; var canvas = null; var ctx = null; var renderingInterval = null; var textComponents = []; var scale = 1; var viewportOffsetX = 0; var viewportOffsetY = 0; var drag = false; var img = null; var text = null; var font = 'arial'; var fontSize = 20; var color = '#000'; var textRotation = 0; var originX = 0; var originY = 0; $(document).ready(function() { img = new Image(); img.src = "http://www.catster.com/wp-content/uploads/2018/01/Cat-flehmen-response.jpg"; canvas = document.getElementById('canvas'); ctx = canvas.getContext("2d"); textComponents.push({ text: 'Test', x: 0, y: 0, saved: true, font: 'arial', fontSize: 30, color: 'red', rotation: Math.PI / 2 }); canvas.addEventListener('mousemove', onMouseMove); canvas.addEventListener('touchmove', onMouseMove); canvas.addEventListener('mouseup', onMouseUp); canvas.addEventListener('touchend', onMouseUp); canvas.addEventListener('touchstart', onMouseDown); canvas.addEventListener('mousedown', onMouseDown); img.onload = function() { renderTextCanvas(); }; }); function renderTextCanvas() { ctx.clearRect(0, 0, img.width, img.height); ctx.scale(scale, scale); ctx.drawImage(img, 0, 0, canvas.width, canvas.height, viewportOffsetX, viewportOffsetY, img.width, img.height); textComponents.forEach(function(textObj) { ctx.save(); ctx.font = textObj.fontSize + 'px ' + textObj.font; ctx.fillStyle = textObj.color; ctx.rotate(textObj.rotation); if (textObj.saved) { //!!!! var x = viewportOffsetX * Math.cos(textObj.rotation) + viewportOffsetY * Math.sin(textObj.rotation); var y = -viewportOffsetX * Math.sin(textObj.rotation) + viewportOffsetY * Math.cos(textObj.rotation); ctx.fillText(textObj.text, textObj.x + x, textObj.y + y); } else { ctx.fillText(textObj.text, textObj.x, textObj.y); textObj.saved = true; textObj.x -= viewportOffsetX; textObj.y -= viewportOffsetY; } ctx.restore(); }); } function onMouseUp(e) { drag = false; } function onMouseDown(event) { originX = event.pageX; originY = event.pageY; if (event.touches) { var touches = event.touches[0]; originX = touches.pageX; originY = touches.pageY; } if (textInput) { var rect = canvas.getBoundingClientRect(); var x = originX - rect.left; var y = originY - rect.top; registerTextComponent(textInput, x, y); textInput = null; return; } drag = true; } function onMouseMove(e) { if (drag) { var pageX = e.pageX; var pageY = e.pageY; if (e.touches) { var touches = e.touches[0]; pageX = touches.pageX; pageY = touches.pageY; } var deltaX = pageX - originX; var deltaY = pageY - originY; if (Math.abs(viewportOffsetX) < Math.abs(img.width / 2)) { viewportOffsetX += deltaX; } else { if (viewportOffsetX < 0) { viewportOffsetX += 1; } else { viewportOffsetX -= 1; } } if (Math.abs(viewportOffsetY) < Math.abs(img.height / 2)) { viewportOffsetY += deltaY; } else { if (viewportOffsetY < 0) { viewportOffsetY += 1; } else { viewportOffsetY -= 1; } } originX = pageX; originY = pageY; renderTextCanvas(); } } #canvas { background: #ffe; }

Комментариев нет:

Отправить комментарий