update ink
This commit is contained in:
parent
90825c289d
commit
ecdf5878b6
|
|
@ -19,11 +19,12 @@ deno i
|
||||||
# then
|
# then
|
||||||
deno task dev
|
deno task dev
|
||||||
```
|
```
|
||||||
|
|
||||||
All config is in `deno.json`.
|
All config is in `deno.json`.
|
||||||
|
|
||||||
## Primitives
|
## Primitives
|
||||||
|
|
||||||
- `<fc-geometry>`: Manipulate HTML elements in space.
|
- `<folk-shape>`: Manipulate HTML elements in space.
|
||||||
- `<fc-ink>`: Draw lines of ink.
|
- `<folk-ink>`: Draw lines of ink.
|
||||||
- `<fc-arrow>`: Define connection between HTML elements.
|
- `<folk-arrow>`: Define connection between HTML elements.
|
||||||
- `<fc-canvas>`: Control a camera (panning/zoom) and query elements in space
|
- `<folk-canvas>`: Control a camera (panning/zoom) and query elements in space
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
const ink = document.createElement('fc-ink');
|
const ink = document.createElement('folk-ink');
|
||||||
|
|
||||||
document.body.appendChild(ink);
|
document.body.appendChild(ink);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getStroke, StrokeOptions } from "perfect-freehand";
|
import { getStroke, StrokeOptions } from 'perfect-freehand';
|
||||||
|
|
||||||
export type Point = [x: number, y: number, pressure: number];
|
export type Point = [x: number, y: number, pressure: number];
|
||||||
|
|
||||||
|
|
@ -25,12 +25,12 @@ styles.replaceSync(`
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"fc-ink": FolkInk;
|
'folk-ink': FolkInk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FolkInk extends HTMLElement {
|
export class FolkInk extends HTMLElement {
|
||||||
static tagName = "fc-ink";
|
static tagName = 'folk-ink';
|
||||||
|
|
||||||
static register() {
|
static register() {
|
||||||
customElements.define(this.tagName, this);
|
customElements.define(this.tagName, this);
|
||||||
|
|
@ -38,10 +38,10 @@ export class FolkInk extends HTMLElement {
|
||||||
|
|
||||||
#internals = this.attachInternals();
|
#internals = this.attachInternals();
|
||||||
|
|
||||||
#svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
#svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
||||||
#path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
#path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
||||||
|
|
||||||
#size = Number(this.getAttribute("size") || 16);
|
#size = Number(this.getAttribute('size') || 16);
|
||||||
|
|
||||||
get size() {
|
get size() {
|
||||||
return this.#size;
|
return this.#size;
|
||||||
|
|
@ -51,7 +51,7 @@ export class FolkInk extends HTMLElement {
|
||||||
this.#update();
|
this.#update();
|
||||||
}
|
}
|
||||||
|
|
||||||
#thinning = Number(this.getAttribute("thinning") || 0.5);
|
#thinning = Number(this.getAttribute('thinning') || 0.5);
|
||||||
|
|
||||||
get thinning() {
|
get thinning() {
|
||||||
return this.#thinning;
|
return this.#thinning;
|
||||||
|
|
@ -61,7 +61,7 @@ export class FolkInk extends HTMLElement {
|
||||||
this.#update();
|
this.#update();
|
||||||
}
|
}
|
||||||
|
|
||||||
#smoothing = Number(this.getAttribute("smoothing") || 0.5);
|
#smoothing = Number(this.getAttribute('smoothing') || 0.5);
|
||||||
|
|
||||||
get smoothing() {
|
get smoothing() {
|
||||||
return this.#smoothing;
|
return this.#smoothing;
|
||||||
|
|
@ -71,7 +71,7 @@ export class FolkInk extends HTMLElement {
|
||||||
this.#update();
|
this.#update();
|
||||||
}
|
}
|
||||||
|
|
||||||
#streamline = Number(this.getAttribute("streamline") || 0.5);
|
#streamline = Number(this.getAttribute('streamline') || 0.5);
|
||||||
|
|
||||||
get streamline() {
|
get streamline() {
|
||||||
return this.#streamline;
|
return this.#streamline;
|
||||||
|
|
@ -81,8 +81,7 @@ export class FolkInk extends HTMLElement {
|
||||||
this.#update();
|
this.#update();
|
||||||
}
|
}
|
||||||
|
|
||||||
#simulatePressure =
|
#simulatePressure = this.getAttribute('streamline') === 'false' ? false : true;
|
||||||
this.getAttribute("streamline") === "false" ? false : true;
|
|
||||||
|
|
||||||
get simulatePressure() {
|
get simulatePressure() {
|
||||||
return this.#simulatePressure;
|
return this.#simulatePressure;
|
||||||
|
|
@ -92,7 +91,7 @@ export class FolkInk extends HTMLElement {
|
||||||
this.#update();
|
this.#update();
|
||||||
}
|
}
|
||||||
|
|
||||||
#points: Point[] = JSON.parse(this.getAttribute("points") || "[]");
|
#points: Point[] = JSON.parse(this.getAttribute('points') || '[]');
|
||||||
|
|
||||||
get points() {
|
get points() {
|
||||||
return this.#points;
|
return this.#points;
|
||||||
|
|
@ -106,7 +105,7 @@ export class FolkInk extends HTMLElement {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
const shadowRoot = this.attachShadow({
|
const shadowRoot = this.attachShadow({
|
||||||
mode: "open",
|
mode: 'open',
|
||||||
delegatesFocus: true,
|
delegatesFocus: true,
|
||||||
});
|
});
|
||||||
shadowRoot.adoptedStyleSheets.push(styles);
|
shadowRoot.adoptedStyleSheets.push(styles);
|
||||||
|
|
@ -130,10 +129,10 @@ export class FolkInk extends HTMLElement {
|
||||||
|
|
||||||
// TODO: cancel trace?
|
// TODO: cancel trace?
|
||||||
draw(event?: PointerEvent) {
|
draw(event?: PointerEvent) {
|
||||||
if (event?.type === "pointerdown") {
|
if (event?.type === 'pointerdown') {
|
||||||
this.handleEvent(event);
|
this.handleEvent(event);
|
||||||
} else {
|
} else {
|
||||||
this.addEventListener("pointerdown", this);
|
this.addEventListener('pointerdown', this);
|
||||||
}
|
}
|
||||||
this.#tracingPromise = Promise.withResolvers();
|
this.#tracingPromise = Promise.withResolvers();
|
||||||
return this.#tracingPromise.promise;
|
return this.#tracingPromise.promise;
|
||||||
|
|
@ -146,26 +145,26 @@ export class FolkInk extends HTMLElement {
|
||||||
|
|
||||||
handleEvent(event: PointerEvent) {
|
handleEvent(event: PointerEvent) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case "pointerdown": {
|
case 'pointerdown': {
|
||||||
if (event.button !== 0 || event.ctrlKey) return;
|
if (event.button !== 0 || event.ctrlKey) return;
|
||||||
|
|
||||||
this.points = [];
|
this.points = [];
|
||||||
this.addPoint([event.offsetX, event.offsetY, event.pressure]);
|
this.addPoint([event.offsetX, event.offsetY, event.pressure]);
|
||||||
this.addEventListener("lostpointercapture", this);
|
this.addEventListener('lostpointercapture', this);
|
||||||
this.addEventListener("pointermove", this);
|
this.addEventListener('pointermove', this);
|
||||||
this.setPointerCapture(event.pointerId);
|
this.setPointerCapture(event.pointerId);
|
||||||
this.#internals.states.add("drawing");
|
this.#internals.states.add('drawing');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case "pointermove": {
|
case 'pointermove': {
|
||||||
this.addPoint([event.offsetX, event.offsetY, event.pressure]);
|
this.addPoint([event.offsetX, event.offsetY, event.pressure]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case "lostpointercapture": {
|
case 'lostpointercapture': {
|
||||||
this.removeEventListener("pointerdown", this);
|
this.removeEventListener('pointerdown', this);
|
||||||
this.removeEventListener("pointermove", this);
|
this.removeEventListener('pointermove', this);
|
||||||
this.removeEventListener("lostpointercapture", this);
|
this.removeEventListener('lostpointercapture', this);
|
||||||
this.#internals.states.delete("drawing");
|
this.#internals.states.delete('drawing');
|
||||||
this.#tracingPromise?.resolve();
|
this.#tracingPromise?.resolve();
|
||||||
this.#tracingPromise = null;
|
this.#tracingPromise = null;
|
||||||
return;
|
return;
|
||||||
|
|
@ -193,14 +192,11 @@ export class FolkInk extends HTMLElement {
|
||||||
cap: true,
|
cap: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this.#path.setAttribute(
|
this.#path.setAttribute('d', this.#getSvgPathFromStroke(getStroke(this.#points, options)));
|
||||||
"d",
|
|
||||||
this.#getSvgPathFromStroke(getStroke(this.#points, options))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#getSvgPathFromStroke(stroke: Stroke): string {
|
#getSvgPathFromStroke(stroke: Stroke): string {
|
||||||
if (stroke.length === 0) return "";
|
if (stroke.length === 0) return '';
|
||||||
|
|
||||||
const d = stroke.reduce(
|
const d = stroke.reduce(
|
||||||
(acc, [x0, y0], i, arr) => {
|
(acc, [x0, y0], i, arr) => {
|
||||||
|
|
@ -208,10 +204,10 @@ export class FolkInk extends HTMLElement {
|
||||||
acc.push(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2);
|
acc.push(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2);
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
["M", ...stroke[0], "Q"]
|
['M', ...stroke[0], 'Q']
|
||||||
);
|
);
|
||||||
|
|
||||||
d.push("Z");
|
d.push('Z');
|
||||||
return d.join(" ");
|
return d.join(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue