@drauu/core
Advanced tools
Comparing version 0.3.7 to 0.4.0
@@ -102,2 +102,9 @@ interface Unsubscribe { | ||
/** | ||
* Listen to a different window for mouse events. | ||
* Useful when you have an iframe or a popup. | ||
* | ||
* @default window | ||
*/ | ||
window?: Window; | ||
/** | ||
* When you apply a scale transform to the svg container, | ||
@@ -115,2 +122,11 @@ * set this property to let drauu aware of the currect coordinates. | ||
coordinateTransform?: boolean; | ||
/** | ||
* Sets the offset of the transformation when calculating coordinates. | ||
* | ||
* @default { x: 0, y: 0 } | ||
*/ | ||
offset?: { | ||
x: number; | ||
y: number; | ||
}; | ||
} | ||
@@ -126,2 +142,6 @@ interface EventsMap { | ||
} | ||
interface Operation { | ||
undo: () => void; | ||
redo: () => void; | ||
} | ||
@@ -139,3 +159,3 @@ declare abstract class BaseModel<T extends SVGElement> { | ||
onMove(_point: Point): boolean; | ||
onEnd(_point: Point): SVGElement | boolean | undefined; | ||
onEnd(_point: Point): Operation | boolean | undefined; | ||
get brush(): Brush; | ||
@@ -160,3 +180,3 @@ get shiftPressed(): boolean; | ||
*/ | ||
_eventUp(event: PointerEvent): boolean | SVGElement | undefined; | ||
_eventUp(event: PointerEvent): boolean | Operation | undefined; | ||
} | ||
@@ -210,2 +230,10 @@ | ||
interface EraserPathFragment { | ||
x1: number; | ||
x2: number; | ||
y1: number; | ||
y2: number; | ||
segment: number; | ||
element: any; | ||
} | ||
declare class EraserModel extends BaseModel<SVGRectElement> { | ||
@@ -215,10 +243,4 @@ svgPointPrevious?: DOMPoint; | ||
pathSubFactor: number; | ||
pathFragments: { | ||
x1: number; | ||
x2: number; | ||
y1: number; | ||
y2: number; | ||
segment: number; | ||
element: any; | ||
}[]; | ||
pathFragments: EraserPathFragment[]; | ||
private _erased; | ||
onSelected(el: SVGSVGElement | null): void; | ||
@@ -228,3 +250,3 @@ onUnselected(): void; | ||
onMove(point: Point): boolean; | ||
onEnd(): boolean; | ||
onEnd(): Operation; | ||
private checkAndEraseElement; | ||
@@ -246,4 +268,6 @@ private lineLineIntersect; | ||
private _currentNode; | ||
private _undoStack; | ||
private _opStack; | ||
private _opIndex; | ||
private _disposables; | ||
private _elements; | ||
constructor(options?: Options); | ||
@@ -257,3 +281,3 @@ get model(): StylusModel | EllipseModel | LineModel | RectModel | DrawModel | EraserModel; | ||
resolveSelector<T>(selector: string | T | null | undefined): T | null; | ||
mount(el: string | SVGSVGElement, eventEl?: string | Element): void; | ||
mount(el: string | SVGSVGElement, eventEl?: string | Element, listenWindow?: Window): void; | ||
unmount(): void; | ||
@@ -275,5 +299,17 @@ on<K extends keyof EventsMap>(type: K, fn: EventsMap[K]): Unsubscribe; | ||
load(svg: string): void; | ||
/** | ||
* @internal | ||
*/ | ||
_appendNode(node: SVGElement): void; | ||
/** | ||
* @internal | ||
*/ | ||
_removeNode(node: SVGElement): void; | ||
/** | ||
* @internal | ||
*/ | ||
_restoreNode(node: SVGElement): void; | ||
} | ||
declare function createDrauu(options?: Options): Drauu; | ||
export { Brush, Drauu, DrawModel, DrawingMode, EllipseModel, EraserModel, EventsMap, LineModel, Options, Point, RectModel, StylusModel, createDrauu }; | ||
export { type Brush, Drauu, DrawModel, type DrawingMode, EllipseModel, EraserModel, type EventsMap, LineModel, type Operation, type Options, type Point, RectModel, StylusModel, createDrauu }; |
@@ -20,7 +20,6 @@ "use strict"; | ||
// ../../node_modules/.pnpm/nanoevents@8.0.0/node_modules/nanoevents/index.js | ||
// ../../node_modules/.pnpm/nanoevents@9.0.0/node_modules/nanoevents/index.js | ||
var createNanoEvents = () => ({ | ||
emit(event, ...args) { | ||
let callbacks = this.events[event] || []; | ||
for (let i = 0, length = callbacks.length; i < length; i++) { | ||
for (let i = 0, callbacks = this.events[event] || [], length = callbacks.length; i < length; i++) { | ||
callbacks[i](...args); | ||
@@ -32,3 +31,4 @@ } | ||
var _a; | ||
((_a = this.events[event]) == null ? void 0 : _a.push(cb)) || (this.events[event] = [cb]); | ||
; | ||
((_a = this.events)[event] || (_a[event] = [])).push(cb); | ||
return () => { | ||
@@ -257,10 +257,11 @@ var _a2; | ||
getMousePosition(event) { | ||
var _a, _b; | ||
var _a, _b, _c; | ||
const el = this.drauu.el; | ||
const scale = (_a = this.drauu.options.coordinateScale) != null ? _a : 1; | ||
const offset = (_b = this.drauu.options.offset) != null ? _b : { x: 0, y: 0 }; | ||
if (this.drauu.options.coordinateTransform === false) { | ||
const rect = this.drauu.el.getBoundingClientRect(); | ||
return { | ||
x: (event.pageX - rect.left) * scale, | ||
y: (event.pageY - rect.top) * scale, | ||
x: (event.pageX - rect.left + offset.x) * scale, | ||
y: (event.pageY - rect.top + offset.y) * scale, | ||
pressure: event.pressure | ||
@@ -270,5 +271,5 @@ }; | ||
const point = this.drauu.svgPoint; | ||
point.x = event.clientX; | ||
point.y = event.clientY; | ||
const loc = point.matrixTransform((_b = el.getScreenCTM()) == null ? void 0 : _b.inverse()); | ||
point.x = event.clientX + offset.x; | ||
point.y = event.clientY + offset.y; | ||
const loc = point.matrixTransform((_c = el.getScreenCTM()) == null ? void 0 : _c.inverse()); | ||
return { | ||
@@ -708,2 +709,3 @@ x: loc.x * scale, | ||
this.pathFragments = []; | ||
this._erased = []; | ||
} | ||
@@ -759,6 +761,10 @@ onSelected(el) { | ||
this.svgPointCurrent = void 0; | ||
return true; | ||
const erased = this._erased; | ||
this._erased = []; | ||
return { | ||
undo: () => erased.forEach((v) => this.drauu._restoreNode(v)), | ||
redo: () => erased.forEach((v) => this.drauu._removeNode(v)) | ||
}; | ||
} | ||
checkAndEraseElement() { | ||
const erased = []; | ||
if (this.pathFragments.length) { | ||
@@ -774,10 +780,10 @@ for (let i = 0; i < this.pathFragments.length; i++) { | ||
if (this.lineLineIntersect(segment, line)) { | ||
segment.element.remove(); | ||
erased.push(i); | ||
this.drauu._removeNode(segment.element); | ||
this._erased.push(segment.element); | ||
} | ||
} | ||
} | ||
if (erased.length) | ||
this.pathFragments = this.pathFragments.filter((v, i) => !erased.includes(i)); | ||
return erased.length > 0; | ||
if (this._erased.length) | ||
this.pathFragments = this.pathFragments.filter((v) => !this._erased.includes(v.element)); | ||
return this._erased.length > 0; | ||
} | ||
@@ -838,8 +844,10 @@ lineLineIntersect(line1, line2) { | ||
this._models = createModels(this); | ||
this._undoStack = []; | ||
this._opStack = []; | ||
this._opIndex = 0; | ||
this._disposables = []; | ||
this._elements = []; | ||
if (!this.options.brush) | ||
this.options.brush = { color: "black", size: 3, mode: "stylus" }; | ||
if (options.el) | ||
this.mount(options.el, options.eventTarget); | ||
this.mount(options.el, options.eventTarget, options.window); | ||
} | ||
@@ -873,3 +881,3 @@ get model() { | ||
} | ||
mount(el, eventEl) { | ||
mount(el, eventEl, listenWindow = window) { | ||
if (this.el) | ||
@@ -891,14 +899,14 @@ throw new Error("[drauu] already mounted, unmount previous target first"); | ||
target.addEventListener("pointerdown", start, { passive: false }); | ||
window.addEventListener("pointermove", move, { passive: false }); | ||
window.addEventListener("pointerup", end, { passive: false }); | ||
window.addEventListener("pointercancel", end, { passive: false }); | ||
window.addEventListener("keydown", keyboard, false); | ||
window.addEventListener("keyup", keyboard, false); | ||
listenWindow.addEventListener("pointermove", move, { passive: false }); | ||
listenWindow.addEventListener("pointerup", end, { passive: false }); | ||
listenWindow.addEventListener("pointercancel", end, { passive: false }); | ||
listenWindow.addEventListener("keydown", keyboard, false); | ||
listenWindow.addEventListener("keyup", keyboard, false); | ||
this._disposables.push(() => { | ||
target.removeEventListener("pointerdown", start); | ||
window.removeEventListener("pointermove", move); | ||
window.removeEventListener("pointerup", end); | ||
window.removeEventListener("pointercancel", end); | ||
window.removeEventListener("keydown", keyboard, false); | ||
window.removeEventListener("keyup", keyboard, false); | ||
listenWindow.removeEventListener("pointermove", move); | ||
listenWindow.removeEventListener("pointerup", end); | ||
listenWindow.removeEventListener("pointercancel", end); | ||
listenWindow.removeEventListener("keydown", keyboard, false); | ||
listenWindow.removeEventListener("keyup", keyboard, false); | ||
}); | ||
@@ -910,2 +918,3 @@ this._emitter.emit("mounted"); | ||
this._disposables.length = 0; | ||
this._elements.length = 0; | ||
this.el = null; | ||
@@ -918,7 +927,5 @@ this._emitter.emit("unmounted"); | ||
undo() { | ||
const el = this.el; | ||
if (!el.lastElementChild) | ||
if (!this.canUndo() || this.drawing) | ||
return false; | ||
this._undoStack.push(el.lastElementChild.cloneNode(true)); | ||
el.lastElementChild.remove(); | ||
this._opStack[--this._opIndex].undo(); | ||
this._emitter.emit("changed"); | ||
@@ -928,5 +935,5 @@ return true; | ||
redo() { | ||
if (!this._undoStack.length) | ||
if (!this.canRedo() || this.drawing) | ||
return false; | ||
this.el.appendChild(this._undoStack.pop()); | ||
this._opStack[this._opIndex++].redo(); | ||
this._emitter.emit("changed"); | ||
@@ -936,7 +943,6 @@ return true; | ||
canRedo() { | ||
return !!this._undoStack.length; | ||
return this._opIndex < this._opStack.length; | ||
} | ||
canUndo() { | ||
var _a; | ||
return !!((_a = this.el) == null ? void 0 : _a.lastElementChild); | ||
return this._opIndex > 0; | ||
} | ||
@@ -973,6 +979,11 @@ eventMove(event) { | ||
this.cancel(); | ||
} else if (result === true) { | ||
const el = this._currentNode; | ||
this._appendNode(el); | ||
this.commit({ | ||
undo: () => this._removeNode(el), | ||
redo: () => this._restoreNode(el) | ||
}); | ||
} else { | ||
if (result instanceof Element && result !== this._currentNode) | ||
this._currentNode = result; | ||
this.commit(); | ||
this.commit(result); | ||
} | ||
@@ -997,4 +1008,6 @@ this.drawing = false; | ||
} | ||
commit() { | ||
this._undoStack.length = 0; | ||
commit(op) { | ||
this._opStack.length = this._opIndex; | ||
this._opStack.push(op); | ||
this._opIndex++; | ||
const node = this._currentNode; | ||
@@ -1005,3 +1018,4 @@ this._currentNode = void 0; | ||
clear() { | ||
this._undoStack.length = 0; | ||
this._opStack.length = 0; | ||
this._opIndex = 0; | ||
this.cancel(); | ||
@@ -1025,2 +1039,36 @@ this.el.innerHTML = ""; | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
_appendNode(node) { | ||
const last = this._elements.at(-1); | ||
if (last) | ||
last.after(node); | ||
else | ||
this.el.append(node); | ||
const index = this._elements.push(node) - 1; | ||
node.dataset.drauu_index = index.toString(); | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
_removeNode(node) { | ||
node.remove(); | ||
this._elements[+node.dataset.drauu_index] = null; | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
_restoreNode(node) { | ||
const index = +node.dataset.drauu_index; | ||
this._elements[index] = node; | ||
for (let i = index - 1; i >= 0; i--) { | ||
const last = this._elements[i]; | ||
if (last) { | ||
last.after(node); | ||
return; | ||
} | ||
} | ||
this.el.prepend(node); | ||
} | ||
}; | ||
@@ -1027,0 +1075,0 @@ function createDrauu(options) { |
@@ -48,7 +48,6 @@ "use strict"; | ||
// ../../node_modules/.pnpm/nanoevents@8.0.0/node_modules/nanoevents/index.js | ||
// ../../node_modules/.pnpm/nanoevents@9.0.0/node_modules/nanoevents/index.js | ||
var createNanoEvents = () => ({ | ||
emit(event, ...args) { | ||
let callbacks = this.events[event] || []; | ||
for (let i = 0, length = callbacks.length; i < length; i++) { | ||
for (let i = 0, callbacks = this.events[event] || [], length = callbacks.length; i < length; i++) { | ||
callbacks[i](...args); | ||
@@ -60,3 +59,4 @@ } | ||
var _a; | ||
((_a = this.events[event]) == null ? void 0 : _a.push(cb)) || (this.events[event] = [cb]); | ||
; | ||
((_a = this.events)[event] || (_a[event] = [])).push(cb); | ||
return () => { | ||
@@ -285,10 +285,11 @@ var _a2; | ||
getMousePosition(event) { | ||
var _a, _b; | ||
var _a, _b, _c; | ||
const el = this.drauu.el; | ||
const scale = (_a = this.drauu.options.coordinateScale) != null ? _a : 1; | ||
const offset = (_b = this.drauu.options.offset) != null ? _b : { x: 0, y: 0 }; | ||
if (this.drauu.options.coordinateTransform === false) { | ||
const rect = this.drauu.el.getBoundingClientRect(); | ||
return { | ||
x: (event.pageX - rect.left) * scale, | ||
y: (event.pageY - rect.top) * scale, | ||
x: (event.pageX - rect.left + offset.x) * scale, | ||
y: (event.pageY - rect.top + offset.y) * scale, | ||
pressure: event.pressure | ||
@@ -298,5 +299,5 @@ }; | ||
const point = this.drauu.svgPoint; | ||
point.x = event.clientX; | ||
point.y = event.clientY; | ||
const loc = point.matrixTransform((_b = el.getScreenCTM()) == null ? void 0 : _b.inverse()); | ||
point.x = event.clientX + offset.x; | ||
point.y = event.clientY + offset.y; | ||
const loc = point.matrixTransform((_c = el.getScreenCTM()) == null ? void 0 : _c.inverse()); | ||
return { | ||
@@ -736,2 +737,3 @@ x: loc.x * scale, | ||
this.pathFragments = []; | ||
this._erased = []; | ||
} | ||
@@ -787,6 +789,10 @@ onSelected(el) { | ||
this.svgPointCurrent = void 0; | ||
return true; | ||
const erased = this._erased; | ||
this._erased = []; | ||
return { | ||
undo: () => erased.forEach((v) => this.drauu._restoreNode(v)), | ||
redo: () => erased.forEach((v) => this.drauu._removeNode(v)) | ||
}; | ||
} | ||
checkAndEraseElement() { | ||
const erased = []; | ||
if (this.pathFragments.length) { | ||
@@ -802,10 +808,10 @@ for (let i = 0; i < this.pathFragments.length; i++) { | ||
if (this.lineLineIntersect(segment, line)) { | ||
segment.element.remove(); | ||
erased.push(i); | ||
this.drauu._removeNode(segment.element); | ||
this._erased.push(segment.element); | ||
} | ||
} | ||
} | ||
if (erased.length) | ||
this.pathFragments = this.pathFragments.filter((v, i) => !erased.includes(i)); | ||
return erased.length > 0; | ||
if (this._erased.length) | ||
this.pathFragments = this.pathFragments.filter((v) => !this._erased.includes(v.element)); | ||
return this._erased.length > 0; | ||
} | ||
@@ -866,8 +872,10 @@ lineLineIntersect(line1, line2) { | ||
this._models = createModels(this); | ||
this._undoStack = []; | ||
this._opStack = []; | ||
this._opIndex = 0; | ||
this._disposables = []; | ||
this._elements = []; | ||
if (!this.options.brush) | ||
this.options.brush = { color: "black", size: 3, mode: "stylus" }; | ||
if (options.el) | ||
this.mount(options.el, options.eventTarget); | ||
this.mount(options.el, options.eventTarget, options.window); | ||
} | ||
@@ -901,3 +909,3 @@ get model() { | ||
} | ||
mount(el, eventEl) { | ||
mount(el, eventEl, listenWindow = window) { | ||
if (this.el) | ||
@@ -919,14 +927,14 @@ throw new Error("[drauu] already mounted, unmount previous target first"); | ||
target.addEventListener("pointerdown", start, { passive: false }); | ||
window.addEventListener("pointermove", move, { passive: false }); | ||
window.addEventListener("pointerup", end, { passive: false }); | ||
window.addEventListener("pointercancel", end, { passive: false }); | ||
window.addEventListener("keydown", keyboard, false); | ||
window.addEventListener("keyup", keyboard, false); | ||
listenWindow.addEventListener("pointermove", move, { passive: false }); | ||
listenWindow.addEventListener("pointerup", end, { passive: false }); | ||
listenWindow.addEventListener("pointercancel", end, { passive: false }); | ||
listenWindow.addEventListener("keydown", keyboard, false); | ||
listenWindow.addEventListener("keyup", keyboard, false); | ||
this._disposables.push(() => { | ||
target.removeEventListener("pointerdown", start); | ||
window.removeEventListener("pointermove", move); | ||
window.removeEventListener("pointerup", end); | ||
window.removeEventListener("pointercancel", end); | ||
window.removeEventListener("keydown", keyboard, false); | ||
window.removeEventListener("keyup", keyboard, false); | ||
listenWindow.removeEventListener("pointermove", move); | ||
listenWindow.removeEventListener("pointerup", end); | ||
listenWindow.removeEventListener("pointercancel", end); | ||
listenWindow.removeEventListener("keydown", keyboard, false); | ||
listenWindow.removeEventListener("keyup", keyboard, false); | ||
}); | ||
@@ -938,2 +946,3 @@ this._emitter.emit("mounted"); | ||
this._disposables.length = 0; | ||
this._elements.length = 0; | ||
this.el = null; | ||
@@ -946,7 +955,5 @@ this._emitter.emit("unmounted"); | ||
undo() { | ||
const el = this.el; | ||
if (!el.lastElementChild) | ||
if (!this.canUndo() || this.drawing) | ||
return false; | ||
this._undoStack.push(el.lastElementChild.cloneNode(true)); | ||
el.lastElementChild.remove(); | ||
this._opStack[--this._opIndex].undo(); | ||
this._emitter.emit("changed"); | ||
@@ -956,5 +963,5 @@ return true; | ||
redo() { | ||
if (!this._undoStack.length) | ||
if (!this.canRedo() || this.drawing) | ||
return false; | ||
this.el.appendChild(this._undoStack.pop()); | ||
this._opStack[this._opIndex++].redo(); | ||
this._emitter.emit("changed"); | ||
@@ -964,7 +971,6 @@ return true; | ||
canRedo() { | ||
return !!this._undoStack.length; | ||
return this._opIndex < this._opStack.length; | ||
} | ||
canUndo() { | ||
var _a; | ||
return !!((_a = this.el) == null ? void 0 : _a.lastElementChild); | ||
return this._opIndex > 0; | ||
} | ||
@@ -1001,6 +1007,11 @@ eventMove(event) { | ||
this.cancel(); | ||
} else if (result === true) { | ||
const el = this._currentNode; | ||
this._appendNode(el); | ||
this.commit({ | ||
undo: () => this._removeNode(el), | ||
redo: () => this._restoreNode(el) | ||
}); | ||
} else { | ||
if (result instanceof Element && result !== this._currentNode) | ||
this._currentNode = result; | ||
this.commit(); | ||
this.commit(result); | ||
} | ||
@@ -1025,4 +1036,6 @@ this.drawing = false; | ||
} | ||
commit() { | ||
this._undoStack.length = 0; | ||
commit(op) { | ||
this._opStack.length = this._opIndex; | ||
this._opStack.push(op); | ||
this._opIndex++; | ||
const node = this._currentNode; | ||
@@ -1033,3 +1046,4 @@ this._currentNode = void 0; | ||
clear() { | ||
this._undoStack.length = 0; | ||
this._opStack.length = 0; | ||
this._opIndex = 0; | ||
this.cancel(); | ||
@@ -1053,2 +1067,36 @@ this.el.innerHTML = ""; | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
_appendNode(node) { | ||
const last = this._elements.at(-1); | ||
if (last) | ||
last.after(node); | ||
else | ||
this.el.append(node); | ||
const index = this._elements.push(node) - 1; | ||
node.dataset.drauu_index = index.toString(); | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
_removeNode(node) { | ||
node.remove(); | ||
this._elements[+node.dataset.drauu_index] = null; | ||
} | ||
/** | ||
* @internal | ||
*/ | ||
_restoreNode(node) { | ||
const index = +node.dataset.drauu_index; | ||
this._elements[index] = node; | ||
for (let i = index - 1; i >= 0; i--) { | ||
const last = this._elements[i]; | ||
if (last) { | ||
last.after(node); | ||
return; | ||
} | ||
} | ||
this.el.prepend(node); | ||
} | ||
}; | ||
@@ -1055,0 +1103,0 @@ function createDrauu(options) { |
{ | ||
"name": "@drauu/core", | ||
"version": "0.3.7", | ||
"version": "0.4.0", | ||
"author": "Anthony Fu <anthonyfu117@hotmail.com>", | ||
@@ -5,0 +5,0 @@ "license": "MIT", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
116267
3475