Перетаскивание содержимого холста.
Используйте mousedown
, mouseup
и mousemove
прослушиватели событий только для обновления состояния мыши. Например, положение и состояние кнопки.
Логика c для перетаскивания визуализированных элементов должна быть сделана в основном рендере l oop. В примере renderLoop
вызывает handleMouse
перед рендерингом любого контента.
Вместо того, чтобы сделать полный пример приложения VUE, я выполнил наиболее простой c перетаскивание текста, чтобы вы могли увидеть код пример.
Перетаскивание start и перетаскивание move
В handleMouse
проверьте, не нажата ли мышь mouse.button === true
- , если это так, и не перетаскивает, и есть текст для перетащите под мышью, установите перетаскивание в true и рассчитайте смещение от позиции мыши до текста
x
, y
- «Перетаскивание», если мышь нажата и перетаскивание true, затем обновите выбранную позицию текста с помощью установив его в положение мыши плюс смещение перетаскивания
Drag drop
Если мышь нажата mouse.button === false
- и перетаскивание равно true, тогда установите
dragging
в ложь. Выбранный текстовый элемент отбрасывается - , устанавливая
selectedText
на первый текстовый элемент под мышью.
Render l oop
Также обрабатывает подсветку и курсоры для мыши и текста, чтобы дать положительный отзыв пользователю.
Текстовые элементы
Я расширил массив для обработки текстовых элементов. Важная функция почти такая же, как если бы вы textItems.getUnder(point)
возвращали текстовый элемент в point.x
point.y
. Если точка не находится над текстовым элементом, функция возвращает undefined
.
Пример
В качестве примера она может не удовлетворять всем вашим потребностям и ни в коем случае не является единственным способом обработайте перетаскивание для визуализированного содержимого холста.
Надеюсь, это поможет.
requestAnimationFrame(renderLoop);
const ctx = canvas.getContext("2d");
var selectedText;
const mouse = {
x: 0,
y: 0,
bounds: canvas.getBoundingClientRect(),
button: false,
dragging: false,
dragOffsetX: 0,
dragOffsetY: 0,
events(event) { // mouse event handler should only record current mouse state
const m = mouse;
if (event.type === "mousedown") { m.button = true }
else if (event.type === "mouseup") { m.button = false }
m.x = event.pageX - m.bounds.left - scrollX;
m.y = event.pageY - m.bounds.top - scrollY;
}
};
document.addEventListener("mousemove", mouse.events);
document.addEventListener("mousedown", mouse.events);
document.addEventListener("mouseup", mouse.events);
function renderLoop(time) {
if (!textItems.length) { addDemoText() }
textItems[0].update("Frame time: " + time.toFixed(3) + "ms");
var cursor = "default";
handleMouse();
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
textItems.draw(ctx);
if (selectedText) {
cursor = mouse.dragging ? "none" : "move";
ctx.fillStyle = "#08F"; // highlight selected text
selectedText.draw();
}
canvas.style.cursor = cursor;
requestAnimationFrame(renderLoop);
}
function handleMouse() {
const m = mouse;
const text = selectedText;
if (m.button) {
if (!m.dragging && text !== undefined) {
m.dragging = true;
m.dragOffsetX = text.x - m.x;
m.dragOffsetY = text.y - m.y;
}
if (m.dragging) {
text.x = m.x + m.dragOffsetX;
text.y = m.y + m.dragOffsetY;
text.keepOnCanvas()
}
} else {
if (m.dragging) {
selectedText = undefined;
m.dragging = false;
}
selectedText = textItems.getUnder(m);
}
}
const textItems = Object.assign([],{
getUnder(point) { // returns undefined if no text under
for(const t of this) {
if (point.x >= t.x && point.x <= t.x + t.width && point.y < t.y + t.size && point.y >= t.y) {
return t;
}
}
},
add(ctx, text, x, y, color = "#000", size = 24, font = "arial") { // context ctx to measure the text
var item;
ctx.font = size + "px " + font;
const width = ctx.measureText(text).width;
this.push(item = {text, x, y, color, font, size, width,
draw() {
ctx.font = this.size + "px " + this.font;
ctx.textBaseline = "hanging";
ctx.fillText(this.text, this.x, this.y);
},
keepOnCanvas() {
const maxX = ctx.canvas.width - this.width;
const maxY = ctx.canvas.height - this.size;
this.x < 0 && (this.x = 0);
this.y < 0 && (this.y = 0);
this.x >= maxX && (this.x = maxX - 1);
this.y >= maxY && (this.y = maxY - 1);
},
update(text) {
this.text = text;
ctx.font = this.size + "px " + this.font;
this.width = ctx.measureText(text).width;
this.keepOnCanvas();
}
});
return item;
},
draw(ctx) {
for(const text of this) {
ctx.fillStyle = text.color;
text.draw();
}
}
});
function addDemoText() {
var idx = 0;
textItems.add(ctx, "", 0, 0);
for (const t of "HI there! Some text to move with the mouse. Move mouse ? over text items. Click and drag to move the text. ? ?".split(" ")) {
const text = textItems.add(ctx, t, idx % (canvas.width - 80), (idx / (canvas.width - 80) | 0) * 26 + 26);
text.keepOnCanvas();
idx += text.width + 12
}
}
canvas {
border: 1px solid black;
};
<canvas id="canvas" width="600" height="180">