Touch support, build.sh

main
Shad Amethyst 2 years ago
parent 4961c555d1
commit fe76e817df
Signed by: amethyst
GPG Key ID: D970C8DD1D6DEE36

@ -0,0 +1,7 @@
wasm-pack build --release stackline-wasm --target web --out-dir ../editor-solidjs/stackline-wasm
[ -d editor-solidjs/font ] && rm editor-solidjs/font
ln -s ../font editor-solidjs/font
[ -f editor-solidjs/prime.json ] && rm editor-solidjs/prime.json
ln -s ../stackline/tests/other/prime.json editor-solidjs/prime.json

@ -2,3 +2,4 @@ node_modules
dist dist
stackline-wasm stackline-wasm
font font
prime.json

@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#000000" />
<!-- <link rel="shortcut icon" type="image/ico" href="/src/assets/favicon.ico" /> --> <!-- <link rel="shortcut icon" type="image/ico" href="/src/assets/favicon.ico" /> -->
<title>Stackline web Editor</title> <title>Stackline web Editor</title>

@ -11,7 +11,7 @@ import RightPane from "./RightPane.jsx";
import {World, Pane} from "../stackline-wasm/stackline_wasm.js"; import {World, Pane} from "../stackline-wasm/stackline_wasm.js";
let json = await (await fetch("/stackline-wasm/prime.json")).json(); let json = await (await fetch("/prime.json")).json();
export default function Editor() { export default function Editor() {
let [world, setWorld] = createSignal(World.deserialize(json), {equals: false}); let [world, setWorld] = createSignal(World.deserialize(json), {equals: false});

@ -5,4 +5,5 @@
flex-direction: row; flex-direction: row;
align-items: stretch; align-items: stretch;
overflow-y: hidden; overflow-y: hidden;
flex-wrap: nowrap;
} }

@ -4,6 +4,7 @@
padding: 1.5em 1em; padding: 1.5em 1em;
font-family: monospace; font-family: monospace;
font-size: 15px; font-size: 15px;
flex-shrink: 0;
overflow-y: scroll; overflow-y: scroll;
} }

@ -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);

@ -1,12 +1,17 @@
.MiddlePane { .MiddlePane {
flex-grow: 1; flex-grow: 1;
flex-shrink: 1;
background: #202027; background: #202027;
position: relative; position: relative;
height: 100vh;
width: 100%;
overflow-x: hidden;
overflow-y: hidden;
} }
.canvas { .canvas {
width: 100%; /* width: 100%; */
height: 100vh; /* height: 100vh; */
} }
.MiddlePane.dragging::after { .MiddlePane.dragging::after {

@ -6,6 +6,7 @@
padding: 1.5em 1em; padding: 1.5em 1em;
font-family: monospace; font-family: monospace;
font-size: 15px; font-size: 15px;
flex-shrink: 0;
} }
.gray, .empty { .gray, .empty {

@ -1,4 +1,4 @@
import {createMemo, createUniqueId} from "solid-js"; import {createEffect, createMemo, createUniqueId} from "solid-js";
import {Pane} from "../stackline-wasm/stackline_wasm.js"; import {Pane} from "../stackline-wasm/stackline_wasm.js";
@ -21,6 +21,8 @@ export default function TilePreset(props) {
let id = createUniqueId(); let id = createUniqueId();
let preview;
return (<div return (<div
class={styles.TilePreset} class={styles.TilePreset}
class={settings.picked === index() ? styles.picked : ""} class={settings.picked === index() ? styles.picked : ""}
@ -53,7 +55,7 @@ export default function TilePreset(props) {
evt.dataTransfer.setDragImage(canvas, canvas.width / 2, canvas.height / 2); evt.dataTransfer.setDragImage(canvas, canvas.width / 2, canvas.height / 2);
}} }}
> >
<pre class={styles.preview} style={{width: 30 * rendered().width + "px"}} id={id}>{rendered().text}</pre> <pre ref={preview} class={styles.preview} style={{width: 30 * rendered().width + "px"}} id={id}>{rendered().text}</pre>
<div>{props.name}</div> <div>{props.name}</div>
</div>); </div>);
} }

@ -1,4 +1,5 @@
body { body {
margin: 0; margin: 0;
height: 100vh; height: 100vh;
overflow: hidden;
} }

Loading…
Cancel
Save