|
|
@ -46,7 +46,9 @@ export default function MiddlePane(props) {
|
|
|
|
y: 0,
|
|
|
|
y: 0,
|
|
|
|
click_x: 0,
|
|
|
|
click_x: 0,
|
|
|
|
click_y: 0,
|
|
|
|
click_y: 0,
|
|
|
|
hovering: false
|
|
|
|
hovering: false,
|
|
|
|
|
|
|
|
down: false,
|
|
|
|
|
|
|
|
touches: [],
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
createEffect(() => {
|
|
|
|
createEffect(() => {
|
|
|
@ -239,10 +241,18 @@ export default function MiddlePane(props) {
|
|
|
|
function resize_cb() {
|
|
|
|
function resize_cb() {
|
|
|
|
if (!canvas.element) return;
|
|
|
|
if (!canvas.element) return;
|
|
|
|
setCanvas((obj) => {
|
|
|
|
setCanvas((obj) => {
|
|
|
|
|
|
|
|
let dpr = window.devicePixelRatio ?? 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let width = Math.round(container.clientWidth * dpr);
|
|
|
|
|
|
|
|
let height = Math.round(container.clientHeight * dpr);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
obj.element.style.width = `${width / dpr}px`;
|
|
|
|
|
|
|
|
obj.element.style.height = `${height / dpr}px`;
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
...obj,
|
|
|
|
...obj,
|
|
|
|
width: obj.element.width = canvas.element.clientWidth,
|
|
|
|
width: obj.element.width = width,
|
|
|
|
height: obj.element.height = canvas.element.clientHeight,
|
|
|
|
height: obj.element.height = height,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -251,13 +261,13 @@ export default function MiddlePane(props) {
|
|
|
|
|
|
|
|
|
|
|
|
function set_resize() {
|
|
|
|
function set_resize() {
|
|
|
|
setTimeout(() => {
|
|
|
|
setTimeout(() => {
|
|
|
|
resize_listener.observe(canvas.element);
|
|
|
|
resize_listener.observe(container);
|
|
|
|
}, 0);
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function remove_resize() {
|
|
|
|
function remove_resize() {
|
|
|
|
setTimeout(() => {
|
|
|
|
setTimeout(() => {
|
|
|
|
resize_listener.unobserve(canvas.element);
|
|
|
|
resize_listener.unobserve(container);
|
|
|
|
}, 0);
|
|
|
|
}, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -291,8 +301,9 @@ export default function MiddlePane(props) {
|
|
|
|
onMount={() => {mounted = true}}
|
|
|
|
onMount={() => {mounted = true}}
|
|
|
|
onCleanup={() => {mounted = false}}
|
|
|
|
onCleanup={() => {mounted = false}}
|
|
|
|
onMouseDown={(evt) => {
|
|
|
|
onMouseDown={(evt) => {
|
|
|
|
let mouse_x = evt.clientX - container.offsetLeft;
|
|
|
|
let dpr = window.devicePixelRatio ?? 1;
|
|
|
|
let mouse_y = evt.clientY - container.offsetTop;
|
|
|
|
let mouse_x = (evt.clientX - container.offsetLeft) * dpr;
|
|
|
|
|
|
|
|
let mouse_y = (evt.clientY - container.offsetTop) * dpr;
|
|
|
|
setMouse((mouse) => {
|
|
|
|
setMouse((mouse) => {
|
|
|
|
return {
|
|
|
|
return {
|
|
|
|
...mouse,
|
|
|
|
...mouse,
|
|
|
@ -306,21 +317,23 @@ export default function MiddlePane(props) {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
onMouseMove={(evt) => {
|
|
|
|
onMouseMove={(evt) => {
|
|
|
|
|
|
|
|
let dpr = window.devicePixelRatio ?? 1;
|
|
|
|
setMouse("hovering", true);
|
|
|
|
setMouse("hovering", true);
|
|
|
|
|
|
|
|
|
|
|
|
if (mouse.down) {
|
|
|
|
if (mouse.down) {
|
|
|
|
// TODO: numerically stable solution
|
|
|
|
// TODO: numerically stable solution
|
|
|
|
setView("cx", view.cx + (evt.clientX - container.offsetLeft) - mouse.x);
|
|
|
|
setView("cx", view.cx + (evt.clientX - container.offsetLeft) * dpr - mouse.x);
|
|
|
|
setView("cy", view.cy + (evt.clientY - container.offsetTop) - mouse.y);
|
|
|
|
setView("cy", view.cy + (evt.clientY - container.offsetTop) * dpr - mouse.y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setMouse("x", evt.clientX - container.offsetLeft);
|
|
|
|
setMouse("x", (evt.clientX - container.offsetLeft) * dpr);
|
|
|
|
setMouse("y", evt.clientY - container.offsetTop);
|
|
|
|
setMouse("y", (evt.clientY - container.offsetTop) * dpr);
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
onMouseUp={(evt) => {
|
|
|
|
onMouseUp={(evt) => {
|
|
|
|
|
|
|
|
let dpr = window.devicePixelRatio ?? 1;
|
|
|
|
setMouse("down", false);
|
|
|
|
setMouse("down", false);
|
|
|
|
setMouse("x", evt.clientX - container.offsetLeft);
|
|
|
|
setMouse("x", (evt.clientX - container.offsetLeft) * dpr);
|
|
|
|
setMouse("y", evt.clientY - container.offsetTop);
|
|
|
|
setMouse("y", (evt.clientY - container.offsetTop) * dpr);
|
|
|
|
|
|
|
|
|
|
|
|
let dist = Math.sqrt((mouse.x - mouse.click_x) ** 2 + (mouse.y - mouse.click_y) ** 2);
|
|
|
|
let dist = Math.sqrt((mouse.x - mouse.click_x) ** 2 + (mouse.y - mouse.click_y) ** 2);
|
|
|
|
if (dist < 10) {
|
|
|
|
if (dist < 10) {
|
|
|
@ -335,9 +348,92 @@ export default function MiddlePane(props) {
|
|
|
|
setMouse("down", false);
|
|
|
|
setMouse("down", false);
|
|
|
|
setMouse("hovering", false);
|
|
|
|
setMouse("hovering", false);
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
|
|
|
|
onTouchStart={(evt) => {
|
|
|
|
|
|
|
|
let dpr = window.devicePixelRatio ?? 1;
|
|
|
|
|
|
|
|
setMouse("hovering", false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setMouse("touches", [...evt.touches].map(touch => ({
|
|
|
|
|
|
|
|
x: (touch.clientX - container.offsetLeft) * dpr,
|
|
|
|
|
|
|
|
y: (touch.clientY - container.offsetTop) * dpr,
|
|
|
|
|
|
|
|
identifier: touch.identifier,
|
|
|
|
|
|
|
|
})));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (evt.touches.length === 1) {
|
|
|
|
|
|
|
|
setMouse("down", true);
|
|
|
|
|
|
|
|
setMouse("x", mouse.touches[0].x);
|
|
|
|
|
|
|
|
setMouse("y", mouse.touches[0].y);
|
|
|
|
|
|
|
|
setMouse("click_x", mouse.touches[0].x);
|
|
|
|
|
|
|
|
setMouse("click_y", mouse.touches[0].y);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
setMouse("down", false);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
onTouchEnd={(evt) => {
|
|
|
|
|
|
|
|
let identifiers = [...evt.changedTouches].map(t => t.identifier);
|
|
|
|
|
|
|
|
setMouse("touches", (arr) => {
|
|
|
|
|
|
|
|
return arr.filter(touch => !identifiers.includes(touch.identifier));
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (evt.touches.length === 1) {
|
|
|
|
|
|
|
|
setMouse("down", true);
|
|
|
|
|
|
|
|
setMouse("x", mouse.touches[0].x);
|
|
|
|
|
|
|
|
setMouse("y", mouse.touches[0].y);
|
|
|
|
|
|
|
|
setMouse("click_x", mouse.touches[0].x);
|
|
|
|
|
|
|
|
setMouse("click_y", mouse.touches[0].y);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
setMouse("down", false);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
oncapture:touchmove={(evt) => {
|
|
|
|
|
|
|
|
evt.preventDefault();
|
|
|
|
|
|
|
|
let dpr = window.devicePixelRatio ?? 1;
|
|
|
|
|
|
|
|
let touches = [...evt.touches].map(touch => ({
|
|
|
|
|
|
|
|
x: (touch.clientX - container.offsetLeft) * dpr,
|
|
|
|
|
|
|
|
y: (touch.clientY - container.offsetTop) * dpr,
|
|
|
|
|
|
|
|
identifier: touch.identifier,
|
|
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (evt.touches.length === 1) {
|
|
|
|
|
|
|
|
let mouse_x = (evt.touches[0].clientX - container.offsetLeft) * dpr;
|
|
|
|
|
|
|
|
let mouse_y = (evt.touches[0].clientY - container.offsetTop) * dpr;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setView("cx", view.cx + mouse_x - mouse.x);
|
|
|
|
|
|
|
|
setView("cy", view.cy + mouse_y - mouse.y);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setMouse("x", mouse_x);
|
|
|
|
|
|
|
|
setMouse("y", mouse_y);
|
|
|
|
|
|
|
|
} else if (evt.touches.length === 2) {
|
|
|
|
|
|
|
|
let mx = (touches[0].x + touches[1].x) / 2;
|
|
|
|
|
|
|
|
let my = (touches[0].y + touches[1].y) / 2;
|
|
|
|
|
|
|
|
let dx = mx - (mouse.touches[0].x + mouse.touches[1].x) / 2;
|
|
|
|
|
|
|
|
let dy = my - (mouse.touches[0].y + mouse.touches[1].y) / 2;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let prev_dist = Math.sqrt(
|
|
|
|
|
|
|
|
(mouse.touches[0].x - mouse.touches[1].x) ** 2
|
|
|
|
|
|
|
|
+ (mouse.touches[0].y - mouse.touches[1].y) ** 2
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let dist = Math.sqrt(
|
|
|
|
|
|
|
|
(touches[0].x - touches[1].x) ** 2 + (touches[0].y - touches[1].y) ** 2
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let old_zoom = view.zoom;
|
|
|
|
|
|
|
|
setView("zoom", Math.min(Math.max(view.zoom + Math.log2(dist / prev_dist), 0.0), 4.0));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let delta = Math.ceil(Math.pow(2, view.zoom)) / Math.ceil(Math.pow(2, old_zoom));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mx -= canvas.width / 2;
|
|
|
|
|
|
|
|
my -= canvas.height / 2;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setView("cx", (view.cx - mx) * delta + mx + dx);
|
|
|
|
|
|
|
|
setView("cy", (view.cy - my) * delta + my + dy);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setMouse("touches", touches);
|
|
|
|
|
|
|
|
}}
|
|
|
|
onWheel={(evt) => {
|
|
|
|
onWheel={(evt) => {
|
|
|
|
let old_zoom = view.zoom;
|
|
|
|
let old_zoom = view.zoom;
|
|
|
|
let zoom = view.zoom + event.deltaY * ZOOM_STRENGTH;
|
|
|
|
let zoom = view.zoom + evt.deltaY * ZOOM_STRENGTH;
|
|
|
|
zoom = Math.min(Math.max(zoom, 0.0), 4.0);
|
|
|
|
zoom = Math.min(Math.max(zoom, 0.0), 4.0);
|
|
|
|
setView("zoom", zoom);
|
|
|
|
setView("zoom", zoom);
|
|
|
|
|
|
|
|
|
|
|
@ -356,12 +452,13 @@ export default function MiddlePane(props) {
|
|
|
|
setSettings("selected", getHovered());
|
|
|
|
setSettings("selected", getHovered());
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
onDragOver={(evt) => {
|
|
|
|
onDragOver={(evt) => {
|
|
|
|
|
|
|
|
let dpr = window.devicePixelRatio ?? 1;
|
|
|
|
evt.preventDefault();
|
|
|
|
evt.preventDefault();
|
|
|
|
|
|
|
|
|
|
|
|
container.classList.add(styles.dragging);
|
|
|
|
container.classList.add(styles.dragging);
|
|
|
|
setMouse("hovering", true);
|
|
|
|
setMouse("hovering", true);
|
|
|
|
setMouse("x", evt.clientX - container.offsetLeft);
|
|
|
|
setMouse("x", (evt.clientX - container.offsetLeft) * dpr);
|
|
|
|
setMouse("y", evt.clientY - container.offsetTop);
|
|
|
|
setMouse("y", (evt.clientY - container.offsetTop) * dpr);
|
|
|
|
}}
|
|
|
|
}}
|
|
|
|
onDragLeave={(evt) => {
|
|
|
|
onDragLeave={(evt) => {
|
|
|
|
setMouse("hovering", false);
|
|
|
|
setMouse("hovering", false);
|
|
|
|