drawing ink
This commit is contained in:
parent
9420e9e7bd
commit
487090cf58
|
|
@ -13,15 +13,14 @@
|
|||
min-height: 100%;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
spatial-ink {
|
||||
position: absolute;
|
||||
inset: 0 0 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav>
|
||||
<button on:click="DRAW">Draw</button>
|
||||
</nav>
|
||||
<script type="module">
|
||||
import { SpatialGeometry } from '../src/canvas/spatial-geometry.ts';
|
||||
import { SpatialInk } from '../src/canvas/spatial-ink.ts';
|
||||
|
|
@ -29,15 +28,50 @@
|
|||
SpatialGeometry.register();
|
||||
SpatialInk.register();
|
||||
|
||||
function trace() {
|
||||
const drawButton = document.querySelector('button');
|
||||
|
||||
async function draw(e) {
|
||||
if (e.target === drawButton) return;
|
||||
|
||||
const ink = document.createElement('spatial-ink');
|
||||
document.body.append(ink);
|
||||
ink.trace();
|
||||
ink.style.cursor = 'var(--tracing-cursor, crosshair)';
|
||||
ink.style.position = 'fixed';
|
||||
ink.style.inset = '0 0 0 0';
|
||||
ink.style.zIndex = 'calc(infinity)';
|
||||
|
||||
document.body.appendChild(ink);
|
||||
|
||||
const rect = await ink.draw(e);
|
||||
const geometry = document.createElement('spatial-geometry');
|
||||
geometry.x = rect.x;
|
||||
geometry.y = rect.y;
|
||||
geometry.height = rect.height;
|
||||
geometry.width = rect.width;
|
||||
|
||||
ink.points = ink.points.map(([x, y, p]) => [x - rect.x, y - rect.y, p]);
|
||||
ink.style.cursor = '';
|
||||
ink.style.position = '';
|
||||
ink.style.inset = '';
|
||||
ink.style.zIndex = '';
|
||||
geometry.appendChild(ink);
|
||||
|
||||
document.body.appendChild(geometry);
|
||||
}
|
||||
|
||||
document.addEventListener('pointerdown', trace);
|
||||
let isDrawing = false;
|
||||
document.addEventListener('click', (e) => {
|
||||
if (e.target !== drawButton) return;
|
||||
|
||||
trace();
|
||||
isDrawing = !isDrawing;
|
||||
|
||||
if (isDrawing) {
|
||||
document.addEventListener('pointerdown', draw);
|
||||
drawButton.textContent = 'Drawing';
|
||||
} else {
|
||||
document.removeEventListener('pointerdown', draw);
|
||||
drawButton.textContent = 'Draw';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -29,32 +29,18 @@ styles.replaceSync(`
|
|||
:host {
|
||||
display: block;
|
||||
position: absolute;
|
||||
padding: 20px 10px 10px;
|
||||
cursor: var(--fc-move, move);
|
||||
content-visibility: auto;
|
||||
}
|
||||
|
||||
::slotted(*) {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
:host > div {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:host > div > div {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
:host(:focus-within) > div {
|
||||
:host(:focus-within) {
|
||||
outline: solid 1px hsl(214, 84%, 56%);
|
||||
}
|
||||
|
||||
:host(:hover) > div {
|
||||
:host(:hover) {
|
||||
outline: solid 2px hsl(214, 84%, 56%);
|
||||
}
|
||||
|
||||
|
|
@ -155,17 +141,15 @@ export class SpatialGeometry extends HTMLElement {
|
|||
// Maybe can add the first resize handler here, and lazily instantiate the rest when needed?
|
||||
// I can see it becoming important at scale
|
||||
shadowRoot.innerHTML = `
|
||||
<div>
|
||||
<button part="rotate"></button>
|
||||
<button part="resize-nw"></button>
|
||||
<button part="resize-ne"></button>
|
||||
<button part="resize-se"></button>
|
||||
<button part="resize-sw"></button>
|
||||
<div><slot></slot></div>
|
||||
</div>`;
|
||||
<slot></slot>`;
|
||||
}
|
||||
|
||||
#type: Shape = 'rectangle';
|
||||
#type = (this.getAttribute('type') || 'rectangle') as Shape;
|
||||
get type(): Shape {
|
||||
return this.#type;
|
||||
}
|
||||
|
|
@ -175,7 +159,7 @@ export class SpatialGeometry extends HTMLElement {
|
|||
}
|
||||
|
||||
#previousX = 0;
|
||||
#x = 0;
|
||||
#x = Number(this.getAttribute('x')) || 0;
|
||||
get x(): number {
|
||||
return this.#x;
|
||||
}
|
||||
|
|
@ -186,7 +170,7 @@ export class SpatialGeometry extends HTMLElement {
|
|||
}
|
||||
|
||||
#previousY = 0;
|
||||
#y = 0;
|
||||
#y = Number(this.getAttribute('y')) || 0;
|
||||
get y(): number {
|
||||
return this.#y;
|
||||
}
|
||||
|
|
@ -197,7 +181,7 @@ export class SpatialGeometry extends HTMLElement {
|
|||
}
|
||||
|
||||
#previousWidth = 0;
|
||||
#width = 1;
|
||||
#width = Number(this.getAttribute('width')) || 1;
|
||||
get width(): number {
|
||||
return this.#width;
|
||||
}
|
||||
|
|
@ -208,7 +192,7 @@ export class SpatialGeometry extends HTMLElement {
|
|||
}
|
||||
|
||||
#previousHeight = 0;
|
||||
#height = 1;
|
||||
#height = Number(this.getAttribute('height')) || 1;
|
||||
get height(): number {
|
||||
return this.#height;
|
||||
}
|
||||
|
|
@ -219,7 +203,7 @@ export class SpatialGeometry extends HTMLElement {
|
|||
}
|
||||
|
||||
#previousRotate = 0;
|
||||
#rotate = 0;
|
||||
#rotate = Number(this.getAttribute('rotate')) || 0;
|
||||
get rotate(): number {
|
||||
return this.#rotate;
|
||||
}
|
||||
|
|
@ -229,15 +213,6 @@ export class SpatialGeometry extends HTMLElement {
|
|||
this.#requestUpdate('rotate');
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.type = (this.getAttribute('type') || 'rectangle') as Shape;
|
||||
this.x = Number(this.getAttribute('x')) || 0;
|
||||
this.y = Number(this.getAttribute('y')) || 0;
|
||||
this.height = Number(this.getAttribute('height')) || 0;
|
||||
this.width = Number(this.getAttribute('width')) || 0;
|
||||
this.rotate = Number(this.getAttribute('rotate')) || 0;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
cancelAnimationFrame(this.#rAFId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,18 +8,12 @@ export type Stroke = number[][];
|
|||
// https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-pointer
|
||||
const styles = new CSSStyleSheet();
|
||||
styles.replaceSync(`
|
||||
svg {
|
||||
:host, svg {
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
:host(:state(tracing)) {
|
||||
cursor: var(--tracing-cursor, crosshair);
|
||||
position: fixed;
|
||||
inset: 0 0 0 0;
|
||||
z-index: calc(infinity);
|
||||
}
|
||||
`);
|
||||
|
||||
export class SpatialInk extends HTMLElement {
|
||||
|
|
@ -117,12 +111,19 @@ export class SpatialInk extends HTMLElement {
|
|||
this.#update();
|
||||
}
|
||||
|
||||
#tracingPromise: PromiseWithResolvers<DOMRectReadOnly | undefined> | null = null;
|
||||
|
||||
// TODO: cancel trace?
|
||||
trace() {
|
||||
async draw(event: PointerEvent): Promise<DOMRectReadOnly | undefined> {
|
||||
if (event.button !== 0 || event.ctrlKey) return;
|
||||
|
||||
this.points = [];
|
||||
this.#internals.states.add('tracing');
|
||||
this.addEventListener('pointerdown', this);
|
||||
this.addPoint([event.pageX, event.pageY, event.pressure]);
|
||||
this.addEventListener('lostpointercapture', this);
|
||||
this.addEventListener('pointermove', this);
|
||||
this.setPointerCapture(event.pointerId);
|
||||
this.#tracingPromise = Promise.withResolvers<DOMRectReadOnly | undefined>();
|
||||
return this.#tracingPromise.promise;
|
||||
}
|
||||
|
||||
addPoint(point: Point) {
|
||||
|
|
@ -132,23 +133,16 @@ export class SpatialInk extends HTMLElement {
|
|||
|
||||
handleEvent(event: PointerEvent) {
|
||||
switch (event.type) {
|
||||
case 'pointerdown': {
|
||||
if (event.button !== 0 || event.ctrlKey) return;
|
||||
|
||||
this.addEventListener('pointermove', this);
|
||||
this.setPointerCapture(event.pointerId);
|
||||
this.addPoint([event.pageX, event.pageY, event.pressure]);
|
||||
return;
|
||||
}
|
||||
case 'pointermove': {
|
||||
this.addPoint([event.pageX, event.pageY, event.pressure]);
|
||||
return;
|
||||
}
|
||||
case 'lostpointercapture': {
|
||||
this.#internals.states.delete('tracing');
|
||||
this.removeEventListener('pointermove', this);
|
||||
this.removeEventListener('pointerdown', this);
|
||||
this.removeEventListener('lostpointercapture', this);
|
||||
this.#tracingPromise?.resolve(this.#path.getBoundingClientRect());
|
||||
this.#tracingPromise = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue