UNPKG

vue3-sketch-ruler

Version:

> 是一个基于 Vue 3 + TypeScript 的标尺组件库,适用于低代码平台、大屏可视化、做图工具等场景,提供类似 Photoshop 的缩放与标尺辅助线体验。

1,654 lines 61 kB
/*!vue3-sketch-ruler v3.1.52026年7月Mon Jul 27 2026 08:57:07 GMT+0800 (中国标准时间)制作*/ import { Fragment as e, computed as t, createCommentVNode as n, createElementBlock as r, createElementVNode as i, createVNode as a, defineComponent as o, markRaw as s, normalizeClass as c, normalizeStyle as l, onMounted as u, onUnmounted as d, openBlock as f, provide as p, ref as m, renderList as h, renderSlot as g, toDisplayString as _, unref as v, useCssVars as y, vShow as b, watch as x, withDirectives as S, withModifiers as C } from "vue"; //#region ../core/lib/index.js function w(e, t, n) { return new Float64Array([ e, 0, 0, e, t, n ]); } function T(e, t, n) { let r = e[0] * e[3] - e[1] * e[2]; if (Math.abs(r) < 1e-10) return { x: 0, y: 0 }; let i = 1 / r, a = t - e[4], o = n - e[5]; return { x: (e[3] * a - e[2] * o) * i, y: (-e[1] * a + e[0] * o) * i }; } function E(e, t, n) { return { x: e[0] * t + e[2] * n + e[4], y: e[1] * t + e[3] * n + e[5] }; } function D(e) { let { mode: t, viewportSize: n, contentSize: r, offset: i, scale: a, pointerPosition: o } = e; switch (t) { case "viewport-center": return { x: n.width / 2, y: n.height / 2 }; case "content-center": return { x: i.x + r.width * a / 2, y: i.y + r.height * a / 2 }; default: return o ? { x: o.x, y: o.y } : { x: n.width / 2, y: n.height / 2 }; } } function O(e, t, n = "contain", r = 0) { if (e.width <= 0 || e.height <= 0) return { scale: 1, x: t.x, y: t.y }; let i = { x: t.x + t.width * r / 2, y: t.y + t.height * r / 2, width: t.width * (1 - r), height: t.height * (1 - r) }, a = i.width / e.width, o = i.height / e.height, s; s = n === "contain" ? Math.min(a, o) : n === "cover" ? Math.max(a, o) : 1; let c = i.x + (i.width - e.width * s) / 2, l = i.y + (i.height - e.height * s) / 2; return { scale: s, x: c, y: l }; } var k = class { matrix; targetState; currentState; minZoom; maxZoom; enableAnimation; animationDuration; animationMode; dampingRatio; naturalFrequency; timeConstant; pendingTransform = !1; rafId = null; callbacks = /* @__PURE__ */ new Set(); lastFrameTime = 0; velocity = { x: 0, y: 0, scale: 0 }; constructor(e = { x: 0, y: 0, scale: 1 }, t = {}) { this.minZoom = t.minZoom ?? .1, this.maxZoom = t.maxZoom ?? 10, this.enableAnimation = t.enableAnimation ?? !1, this.animationDuration = t.animationDuration ?? 200, this.animationMode = t.animationMode ?? "ease-out", this.dampingRatio = t.dampingRatio ?? .8, this.naturalFrequency = t.naturalFrequency ?? 20, this.timeConstant = t.timeConstant ?? 80; let n = this.clampScale(e.scale); this.currentState = { ...e, scale: n }, this.targetState = { ...this.currentState }, this.matrix = w(n, e.x, e.y); } onUpdate(e) { return this.callbacks.add(e), e({ ...this.currentState }), () => { this.callbacks.delete(e); }; } setTransform(e) { e.scale !== void 0 && (this.targetState.scale = this.clampScale(e.scale)), e.x !== void 0 && (this.targetState.x = e.x), e.y !== void 0 && (this.targetState.y = e.y), this.enableAnimation ? this.scheduleUpdate() : (this.currentState = { ...this.targetState }, this.updateMatrix(), this.notify()); } panBy(e, t) { this.targetState.x += e, this.targetState.y += t, this.enableAnimation ? this.scheduleUpdate() : (this.currentState = { ...this.targetState }, this.updateMatrix(), this.notify()); } zoomBy(e, t, n) { let r = this.targetState.scale, i = this.clampScale(r + e), a = i / r; Math.abs(a - 1) < 1e-6 || (this.targetState.x = t - (t - this.targetState.x) * a, this.targetState.y = n - (n - this.targetState.y) * a, this.targetState.scale = i, this.enableAnimation ? this.scheduleUpdate() : (this.currentState = { ...this.targetState }, this.updateMatrix(), this.notify())); } zoomTo(e, t, n) { let r = this.clampScale(e) - this.targetState.scale; this.zoomBy(r, t, n); } toWorldPoint(e, t) { return T(this.matrix, e, t); } toScreenPoint(e, t) { return E(this.matrix, e, t); } getState() { return { ...this.currentState }; } getMatrix() { return new Float64Array(this.matrix); } setAnimationMode(e) { this.animationMode = e, this.lastFrameTime = 0, this.velocity = { x: 0, y: 0, scale: 0 }; } destroy() { this.rafId !== null && (cancelAnimationFrame(this.rafId), this.rafId = null), this.callbacks.clear(); } clampScale(e) { return Math.max(this.minZoom, Math.min(this.maxZoom, e)); } updateMatrix() { this.matrix = w(this.currentState.scale, this.currentState.x, this.currentState.y); } scheduleUpdate() { this.pendingTransform = !0, this.rafId === null && (this.rafId = requestAnimationFrame((e) => this.onFrame(e))); } onFrame(e) { if (this.rafId = null, !this.pendingTransform) return; if (this.pendingTransform = !1, !this.enableAnimation) { this.currentState = { ...this.targetState }, this.updateMatrix(), this.notify(); return; } let t = this.lastFrameTime === 0 ? 16 : e - this.lastFrameTime; this.lastFrameTime = e; let n = t / 1e3; switch (this.animationMode) { case "direct": this.currentState = { ...this.targetState }; break; case "ease-out": { let e = 1 - (1 - Math.min(1, t / this.animationDuration)) ** 3; this.currentState.x = this.lerp(this.currentState.x, this.targetState.x, e), this.currentState.y = this.lerp(this.currentState.y, this.targetState.y, e), this.currentState.scale = this.lerp(this.currentState.scale, this.targetState.scale, e); break; } case "exponential": { let e = this.timeConstant / 1e3, t = 1 - Math.exp(-n / e); this.currentState.x = this.lerp(this.currentState.x, this.targetState.x, t), this.currentState.y = this.lerp(this.currentState.y, this.targetState.y, t), this.currentState.scale = this.lerp(this.currentState.scale, this.targetState.scale, t); break; } case "damped": { let e = this.dampingRatio, t = this.naturalFrequency, r = t * t, i = r * (this.targetState.x - this.currentState.x) - 2 * e * t * this.velocity.x; this.velocity.x += i * n, this.currentState.x += this.velocity.x * n; let a = r * (this.targetState.y - this.currentState.y) - 2 * e * t * this.velocity.y; this.velocity.y += a * n, this.currentState.y += this.velocity.y * n; let o = r * (this.targetState.scale - this.currentState.scale) - 2 * e * t * this.velocity.scale; this.velocity.scale += o * n, this.currentState.scale += this.velocity.scale * n; break; } } this.currentState.scale = this.clampScale(this.currentState.scale); let r = this.animationMode === "damped" ? .01 : 1e-4, i = Math.abs(this.currentState.x - this.targetState.x) > r || Math.abs(this.currentState.y - this.targetState.y) > r || Math.abs(this.currentState.scale - this.targetState.scale) > r || this.animationMode === "damped" && (Math.abs(this.velocity.x) > r || Math.abs(this.velocity.y) > r || Math.abs(this.velocity.scale) > r); this.updateMatrix(), this.notify(), i ? this.scheduleUpdate() : (this.currentState = { ...this.targetState }, this.velocity = { x: 0, y: 0, scale: 0 }, this.lastFrameTime = 0); } lerp(e, t, n) { return e + (t - e) * n; } notify() { let e = { ...this.currentState }; this.callbacks.forEach((t) => t(e)); } }; function A() { return { lines: [], palette: { bgColor: "#f6f7f9", tickColor: "#BABBBC", labelColor: "#7D8694", guideLineColor: "#51d6a9", guideLineLockedColor: "#d4d7dc", hoverBg: "#000", hoverColor: "#fff", borderColor: "#eeeeef", shadowColor: "#e9f7fe", guideLineStyle: "dashed", guideLineWidth: 1, labelEnabled: !0, labelPosition: "end" }, snapConfig: { enabled: !0, threshold: 5, strength: .5 }, showReferLine: !0 }; } function j(e, t) { switch (t.type) { case "addLine": return { ...e, lines: [...e.lines, t.line] }; case "removeLine": { let n = e.lines.filter((e) => e.id !== t.id); return n.length === e.lines.length ? e : { ...e, lines: n }; } case "moveLine": { let n = e.lines.findIndex((e) => e.id === t.id); if (n === -1) return e; let r = [...e.lines]; return r[n] = { ...r[n], position: t.position }, { ...e, lines: r }; } case "updateLine": { let n = e.lines.findIndex((e) => e.id === t.id); if (n === -1) return e; let r = [...e.lines]; return r[n] = { ...r[n], ...t.updates }, { ...e, lines: r }; } case "setLines": return t.lines === e.lines ? e : { ...e, lines: t.lines }; case "setPalette": return { ...e, palette: { ...e.palette, ...t.palette } }; case "setSnapConfig": return { ...e, snapConfig: { ...e.snapConfig, ...t.config } }; case "toggleReferLine": return { ...e, showReferLine: t.value === void 0 ? !e.showReferLine : t.value }; default: return e; } } var ee = class { plugins = []; renderers = /* @__PURE__ */ new Map(); rendererOwners = /* @__PURE__ */ new WeakMap(); activeRenderer = null; api = null; setApi(e) { this.api = e; } register(e) { if (this.plugins.push(e), this.sortPlugins(), e.registerRenderer) { let t = e.registerRenderer(); this.renderers.set(t.name, t.renderer), this.rendererOwners.set(e, t), this.activeRenderer === null && (this.activeRenderer = t.name); } return () => this.unregister(e); } unregister(e) { let t = this.plugins.indexOf(e); t !== -1 && this.plugins.splice(t, 1); let n = this.rendererOwners.get(e); n && (this.renderers.delete(n.name), this.rendererOwners.delete(e), this.activeRenderer === n.name && (this.activeRenderer = this.renderers.keys().next().value ?? null)); } sortPlugins() { this.plugins.sort((e, t) => (t.priority ?? 0) - (e.priority ?? 0)); } getContext(e) { if (!this.api) throw Error("[PluginManager] api not set. Call setApi() before dispatching hooks."); return { ...e, api: this.api }; } safeCall(e, t, n) { try { e(); } catch (e) { console.error(`[PluginManager] Plugin "${t}" ${n} threw:`, e); } } async safeCallAsync(e, t, n) { try { await e(); } catch (e) { console.error(`[PluginManager] Plugin "${t}" ${n} threw:`, e); } } async beforeZoom(e) { let t = !1, n = () => { t = !0; }, r = this.getContext({ ...e, cancel: n }); for (let e of this.plugins) if (e.beforeZoom && (await this.safeCallAsync(() => e.beforeZoom(r), e.name, "beforeZoom"), t)) return !1; return !0; } afterZoom(e) { let t = this.getContext(e); for (let e of this.plugins) e.afterZoom && this.safeCall(() => e.afterZoom(t), e.name, "afterZoom"); } async beforePan(e) { let t = !1, n = () => { t = !0; }, r = this.getContext({ ...e, cancel: n }); for (let e of this.plugins) if (e.beforePan && (await this.safeCallAsync(() => e.beforePan(r), e.name, "beforePan"), t)) return !1; return !0; } afterPan(e) { let t = this.getContext(e); for (let e of this.plugins) e.afterPan && this.safeCall(() => e.afterPan(t), e.name, "afterPan"); } onSnap(e) { let t = this.getContext(e); for (let e of this.plugins) e.onSnap && this.safeCall(() => e.onSnap(t), e.name, "onSnap"); } onLineCreate(e) { let t = this.getContext(e); for (let e of this.plugins) e.onLineCreate && this.safeCall(() => e.onLineCreate(t), e.name, "onLineCreate"); } onLineDelete(e) { let t = this.getContext(e); for (let e of this.plugins) e.onLineDelete && this.safeCall(() => e.onLineDelete(t), e.name, "onLineDelete"); } onLineMove(e) { let t = this.getContext(e); for (let e of this.plugins) e.onLineMove && this.safeCall(() => e.onLineMove(t), e.name, "onLineMove"); } setActiveRenderer(e) { return this.renderers.has(e) ? (this.activeRenderer = e, !0) : !1; } getActiveRenderer() { return this.activeRenderer ? this.renderers.get(this.activeRenderer) ?? null : null; } getRendererNames() { return Array.from(this.renderers.keys()); } hasRenderer(e) { return this.renderers.has(e); } clear() { this.plugins = [], this.renderers.clear(), this.rendererOwners = /* @__PURE__ */ new WeakMap(), this.activeRenderer = null; } }, M = [ { maxScale: .2, interval: 500, subdivisions: 5, showLabel: !0, formatLabel: (e) => `${Math.round(e / 1e3)}k` }, { maxScale: .5, interval: 200, subdivisions: 4, showLabel: !0 }, { maxScale: 1, interval: 100, subdivisions: 5, showLabel: !0 }, { maxScale: 2, interval: 50, subdivisions: 5, showLabel: !0 }, { maxScale: 5, interval: 20, subdivisions: 4, showLabel: !0 }, { maxScale: 10, interval: 10, subdivisions: 5, showLabel: !0 }, { maxScale: Infinity, interval: 5, subdivisions: 5, showLabel: !0 } ], N = 1.1, P = .9; function F(e) { let t = M.findIndex((t) => e < t.maxScale); return M[t === -1 ? M.length - 1 : t]; } function I(e, t) { let n = e; for (; n < M.length - 1 && t >= M[n].maxScale * N;) n++; for (; n > 0 && t < M[n - 1].maxScale * P;) n--; return n; } function L(e) { let { scale: t, offset: n, viewportSize: r, thick: i, canvasSize: a, showMinorTicks: o } = e; if (r <= 0 || t <= 0) return []; let s = F(t), c = s.interval, l = s.subdivisions, u = c / l, d = -n / t, f = (r - n) / t, p = r / t, m = d - p * .5, h = f + p * .5, g = Math.floor(m / c) * c, _ = [], v = a ?? Infinity; for (let e = g; e <= h; e += c) { let a = e * t + n; if (a >= -i && a <= r + i) { let t = e >= 0 && e <= v && (v === Infinity || e === v || v - e >= c); _.push({ position: a, length: i * .6, isMajor: !0, label: t ? s.formatLabel ? s.formatLabel(e) : `${Math.round(e)}` : void 0, value: e }); } if (o) for (let a = 1; a < l; a++) { let o = e + a * u, s = o * t + n; s >= -i && s <= r + i && _.push({ position: s, length: i * .3, isMajor: !1, value: o }); } } if (v !== Infinity && v > 0 && !_.some((e) => e.isMajor && e.value === v)) { let e = v * t + n; e >= -i && e <= r + i * 2 && (_.push({ position: e, length: i * .6, isMajor: !0, label: `${Math.round(v)}`, value: v }), _.sort((e, t) => e.position - t.position)); } return _; } var R = 0, z = 0; function B() { return `line-${++R}-${Date.now()}`; } function V() { return `canvas-${++z}-${Date.now()}`; } function H(e) { if (!e) return []; let t = [], n = 0; for (let r of e.h) t.push({ id: `h-${n++}-${Date.now()}`, orientation: "h", position: r, visible: !0, locked: !1 }); for (let r of e.v) t.push({ id: `v-${n++}-${Date.now()}`, orientation: "v", position: r, visible: !0, locked: !1 }); return t; } var U = { "A4 Portrait": { name: "A4 纵向", width: 794, height: 1123 }, "A4 Landscape": { name: "A4 横向", width: 1123, height: 794 }, "Web 1920": { name: "Web 1920", width: 1920, height: 1080 }, "Web 1440": { name: "Web 1440", width: 1440, height: 900 }, "Mobile 375": { name: "Mobile 375", width: 375, height: 812 }, "Mobile 414": { name: "Mobile 414", width: 414, height: 896 } }, W = class { canvases = []; activeId = ""; templates = /* @__PURE__ */ new Map(); globalLines = []; listeners = /* @__PURE__ */ new Set(); constructor(e = []) { for (let [e, t] of Object.entries(U)) this.templates.set(e, t); for (let t of e) this.addCanvas(t); } notify() { let e = { canvases: [...this.canvases], activeId: this.activeId }; this.listeners.forEach((t) => t(e)); } onUpdate(e) { return this.listeners.add(e), () => this.listeners.delete(e); } getState() { return { canvases: [...this.canvases], activeId: this.activeId }; } get activeCanvas() { return this.canvases.find((e) => e.id === this.activeId) ?? null; } addCanvas(e) { let t = e?.id ?? V(), n = { id: t, name: e?.name ?? `画布 ${this.canvases.length + 1}`, width: e?.width ?? 1920, height: e?.height ?? 1080, scale: e?.scale ?? 1, offsetX: e?.offsetX ?? 0, offsetY: e?.offsetY ?? 0, lines: H(e?.lines), thumbnail: null }; return this.canvases = [...this.canvases, n], this.activeId ||= t, this.notify(), t; } removeCanvas(e) { let t = this.canvases.findIndex((t) => t.id === e); if (t === -1) return; let n = [...this.canvases]; n.splice(t, 1), this.canvases = n, this.activeId === e && n.length > 0 && (this.activeId = n[0].id), this.notify(); } switchCanvas(e) { if (!this.canvases.some((t) => t.id === e)) return; let t = this.activeCanvas; t && t.id !== e && this.captureThumbnail(t.id), this.activeId = e; let n = this.canvases.find((t) => t.id === e); n && (n.thumbnail = null), this.notify(); } updateCanvasState(e, t) { this.canvases = this.canvases.map((n) => n.id === e ? { ...n, ...t } : n), this.notify(); } updateCanvasLines(e, t) { this.canvases = this.canvases.map((n) => n.id === e ? { ...n, lines: [...t] } : n), this.notify(); } registerTemplate(e, t) { this.templates.set(e, t); } getTemplateNames() { return Array.from(this.templates.keys()); } applyTemplate(e) { let t = this.templates.get(e); return t ? this.addCanvas(t) : null; } setGlobalLines(e) { this.globalLines = H(e); } getGlobalLines() { return [...this.globalLines]; } getMergedLines(e) { let t = this.canvases.find((t) => t.id === e); return t ? [...this.globalLines, ...t.lines] : []; } exportCanvas(e) { let t = this.canvases.find((t) => t.id === e); return t ? { ...t } : null; } importCanvas(e) { this.canvases.some((t) => t.id === e.id) ? this.canvases = this.canvases.map((t) => t.id === e.id ? { ...e } : t) : this.canvases = [...this.canvases, { ...e }], this.notify(); } captureThumbnail(e) { let t = this.canvases.find((t) => t.id === e); t && (t.thumbnail = "data:image/png;base64,placeholder"); } }; //#endregion //#region src/composables/useCanvasTransform.ts function G(e = {}) { let { initialScale: t = 1, initialOffset: n = { x: 0, y: 0 }, minZoom: r = .1, maxZoom: i = 10, enableAnimation: a = !1, animationMode: o, dampingRatio: c, naturalFrequency: l, timeConstant: u, autoCenter: d = !1, canvasSize: f, viewportSize: p, paddingRatio: h = .2 } = e, g = t, _ = { x: n.x, y: n.y }; if (d && f && p) { let e = O({ x: 0, y: 0, width: f.width, height: f.height }, { x: 0, y: 0, width: p.width, height: p.height }, "contain", h); g = e.scale, _ = { x: e.x, y: e.y }; } let v = m(g), y = m({ x: _.x, y: _.y }), b = s(new k({ x: _.x, y: _.y, scale: g }, { minZoom: r, maxZoom: i, enableAnimation: a, animationMode: o, dampingRatio: c, naturalFrequency: l, timeConstant: u })); return b.onUpdate((e) => { v.value = e.scale, y.value = { x: e.x, y: e.y }; }), x(v, (e) => { let t = b.getState(); Math.abs(t.scale - e) > 1e-10 && b.setTransform({ scale: e }); }), x(() => y.value, (e) => { let t = b.getState(); (Math.abs(t.x - e.x) > 1e-10 || Math.abs(t.y - e.y) > 1e-10) && b.setTransform({ x: e.x, y: e.y }); }, { deep: !0 }), { scale: v, offset: y, engine: b, setTransform: (e) => { b.setTransform(e); }, panBy: (e, t) => { b.panBy(e, t); }, zoomBy: (e, t, n) => { b.zoomBy(e, t, n); }, zoomTo: (e, t, n) => { b.zoomTo(e, t, n); }, toWorldPoint: (e, t) => b.toWorldPoint(e, t), toScreenPoint: (e, t) => b.toScreenPoint(e, t), reset: () => { b.setTransform({ scale: g, x: _.x, y: _.y }); } }; } //#endregion //#region ../canvas/lib/index.js var te = class { canvas = null; ctx = null; lastFingerprint = ""; drawStatic(e, t, n) { let r = this.buildFingerprint(t, n); return (r !== this.lastFingerprint || !this.canvas) && (this.rebuild(t, n), this.lastFingerprint = r), this.canvas ? (e.drawImage(this.canvas, 0, 0), !0) : !1; } rebuild(e, t) { let { width: n, height: r, ratio: i, palette: a, thick: o, vertical: s } = t; this.canvas ||= document.createElement("canvas"), this.canvas.width = Math.round(n * i), this.canvas.height = Math.round(r * i); let c = this.canvas.getContext("2d"); this.ctx = c, c.setTransform(1, 0, 0, 1, 0, 0), c.scale(i, i), c.clearRect(0, 0, n, r), c.fillStyle = a.bgColor, c.fillRect(0, 0, n, r), c.strokeStyle = a.tickColor, c.lineWidth = 1, c.beginPath(); for (let i of e) { let e = i.position; i.isMajor ? i.value === 0 || i.value === t.canvasSize ? s ? (c.moveTo(0, e), c.lineTo(n, e)) : (c.moveTo(e, 0), c.lineTo(e, r)) : s ? (c.moveTo(n, e), c.lineTo(n * .65, e)) : (c.moveTo(e, r), c.lineTo(e, r * .65)) : s ? (c.moveTo(n, e), c.lineTo(n * .8, e)) : (c.moveTo(e, r), c.lineTo(e, r * .8)); } c.stroke(), c.closePath(); } buildFingerprint(e, t) { let { thick: n, palette: r, vertical: i, width: a, height: o } = t, s = e.length > 1 ? e[1].value - e[0].value : 0, c = 1, l = 0; if (e.length >= 2) { let t = e[0], n = e.find((e) => e.value !== t.value) ?? e[1]; n && n.value !== t.value && (c = (n.position - t.position) / (n.value - t.value), l = t.position - t.value * c); } return `${n}:${r.bgColor}:${r.tickColor}:${r.labelColor}:${i}:${a}:${o}:${s}:${c.toFixed(4)}:${l.toFixed(2)}`; } clear() { this.canvas = null, this.ctx = null, this.lastFingerprint = ""; } }, K = class { cache = /* @__PURE__ */ new Map(); maxSize; constructor(e = 500) { this.maxSize = e; } get(e, t) { let n = this.hashKey(t), r = this.cache.get(n); if (r) return this.cache.delete(n), this.cache.set(n, r), r; let i = this.createEntry(e, t); return this.cache.set(n, i), this.evictIfNeeded(), i; } createEntry(e, t) { let { text: n, font: r, color: i } = t; e.font = r; let a = e.measureText(n), o = Math.ceil(a.width), s = Math.ceil(a.actualBoundingBoxAscent + a.actualBoundingBoxDescent) || 12; if (o === 0 || s === 0) return { canvas: document.createElement("canvas"), width: 0, height: 0 }; let c = document.createElement("canvas"); c.width = o + 2, c.height = s + 2; let l = c.getContext("2d"); return l.font = r, l.fillStyle = i, l.textBaseline = "alphabetic", l.fillText(n, 1, 1 + a.actualBoundingBoxAscent), { canvas: c, width: o, height: s }; } evictIfNeeded() { if (this.cache.size <= this.maxSize) return; let e = this.cache.keys().next().value; e !== void 0 && this.cache.delete(e); } hashKey(e) { return `${e.text}:${e.font}:${e.color}`; } clear() { this.cache.clear(); } size() { return this.cache.size; } }, ne = "#e9f7fe", re = class { offscreenCache = new te(); labelCache = new K(); render(e, t, n) { for (let r of t) r.type === "ruler" && this.renderRuler(e, r, n); } renderRuler(e, t, n) { let { marks: r, vertical: i, thick: a, width: o, height: s, ratio: c, palette: l, shadowStart: u, shadowLength: d, showShadowText: f } = t; e.setTransform(1, 0, 0, 1, 0, 0), e.scale(c, c), e.clearRect(0, 0, o, s), this.offscreenCache.drawStatic(e, r, t); let p = []; if (d && r.length > 0) { let t = u ?? 0, n = r[0], c = r.find((e) => e.value !== n.value) ?? n, m = c && c.value !== n.value ? (c.position - n.position) / (c.value - n.value) : 1, h = n.position - n.value * m, g = t * m + h, _ = d * m; if (_ > 0 && (e.fillStyle = l.shadowColor ?? ne, i ? e.fillRect(0, g, o, _) : e.fillRect(g, 0, _, s), f)) { this.renderShadowText(e, t, g, a, i, l, !1); let n = t + d, r = n * m + h; this.renderShadowText(e, n, r, a, i, l, !0), p.push(g, r); } } for (let n of r) if (n.isMajor && n.label) { if (p.some((e) => Math.abs(n.position - e) < a * 1.5)) continue; e.save(), e.fillStyle = l.labelColor, e.font = `${Math.max(11, Math.floor(a * .5) + 2)}px -apple-system, "Helvetica Neue", ".SFNSDisplay-Regular", "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", sans-serif`, i ? (n.value === 0 ? e.translate(o * .4, n.position - 3) : n.value === t.canvasSize ? e.translate(o * .2, n.position + 32) : e.translate(o * .15, n.position + 14), e.rotate(-90 * Math.PI / 180), e.fillText(n.label, 4, 9)) : (n.value === 0 ? e.translate(n.position - 15, s * .13) : n.value === t.canvasSize ? e.translate(n.position + 5, s * .3) : e.translate(n.position - 12, s * .18), e.fillText(n.label, 4, 9)), e.restore(); } } renderShadowText(e, t, n, r, i, a, o) { e.save(), e.fillStyle = a.labelColor, e.font = "bold 12px sans-serif", i ? (e.translate(r * .6, n + (o ? -8 : 8)), e.rotate(-Math.PI / 2)) : e.translate(n + (o ? -8 : 8), r * .6), e.fillText(Math.round(t).toString(), 0, 0), e.restore(); } destroy() { this.offscreenCache.clear(), this.labelCache.clear(); } }; function q(e) { let t = e.deltaX, n = e.deltaY, r = e.deltaZ || 0, i = e.deltaMode; return i === WheelEvent.DOM_DELTA_LINE ? (t *= 40, n *= 40, r *= 40) : i === WheelEvent.DOM_DELTA_PAGE && (t *= 800, n *= 800, r *= 800), { deltaX: t, deltaY: n, deltaZ: r, deltaMode: i }; } var J = class { container; callbacks; boundWheel; boundMouseDown; boundMouseMove; boundMouseUp; boundMouseEnter; boundMouseLeave; isBound = !1; constructor(e, t) { this.container = e, this.callbacks = t, this.boundWheel = this.handleWheel.bind(this), this.boundMouseDown = this.handleMouseDown.bind(this), this.boundMouseMove = this.handleMouseMove.bind(this), this.boundMouseUp = this.handleMouseUp.bind(this), this.boundMouseEnter = () => this.callbacks.onMouseEnter?.(), this.boundMouseLeave = () => this.callbacks.onMouseLeave?.(); } bind() { this.isBound || (this.isBound = !0, this.container.addEventListener("wheel", this.boundWheel, { passive: !1 }), this.container.addEventListener("mousedown", this.boundMouseDown), document.addEventListener("mousemove", this.boundMouseMove), document.addEventListener("mouseup", this.boundMouseUp), this.container.addEventListener("mouseenter", this.boundMouseEnter), this.container.addEventListener("mouseleave", this.boundMouseLeave)); } unbind() { this.isBound && (this.isBound = !1, this.container.removeEventListener("wheel", this.boundWheel), this.container.removeEventListener("mousedown", this.boundMouseDown), document.removeEventListener("mousemove", this.boundMouseMove), document.removeEventListener("mouseup", this.boundMouseUp), this.container.removeEventListener("mouseenter", this.boundMouseEnter), this.container.removeEventListener("mouseleave", this.boundMouseLeave)); } handleWheel(e) { let t = q(e); this.callbacks.onWheel?.(e, t); } handleMouseDown(e) { this.callbacks.onMouseDown?.(e); } handleMouseMove(e) { this.callbacks.onMouseMove?.(e); } handleMouseUp(e) { this.callbacks.onMouseUp?.(e); } }, Y = class { callbacks; boundKeyDown; isBound = !1; constructor(e) { this.callbacks = e, this.boundKeyDown = this.handleKeyDown.bind(this); } bind() { this.isBound || (this.isBound = !0, document.addEventListener("keydown", this.boundKeyDown)); } unbind() { this.isBound && (this.isBound = !1, document.removeEventListener("keydown", this.boundKeyDown)); } handleKeyDown(e) { if (e.repeat) return; let t = document.activeElement; if (t?.closest(".monaco-editor") || t?.tagName === "INPUT" || t?.tagName === "TEXTAREA" || t?.getAttribute("contenteditable") === "true") return; let n = this.parseCombo(e); this.callbacks.onShortcut?.(n, e); } parseCombo(e) { let t = []; (e.ctrlKey || e.metaKey) && t.push("ctrl"), e.altKey && t.push("alt"), e.shiftKey && t.push("shift"); let n = e.key.toLowerCase(); return n === " " && (n = "space"), n === "+" && (n = "plus"), n === "-" && (n = "minus"), n === "=" && (n = "equal"), t.push(n), t.join("+"); } }, ie = class { engine; zoomStep; selfHandle; zoomMode; viewportSize; contentSize; container = null; mouseAdapter = null; isSpacePressed = !1; isDragging = !1; dragStart = { x: 0, y: 0 }; lastMouse = { x: 0, y: 0 }; isHovered = !1; boundKeyUp; keyboardAdapter = null; pendingWheelDelta = 0; wheelRafId = null; onCursorChange = null; zoomInterceptor = null; panInterceptor = null; constructor(e, t = {}) { this.engine = e, this.zoomStep = t.zoomStep ?? .25, this.selfHandle = t.selfHandle ?? !1, this.zoomMode = t.zoomMode ?? "pointer", this.viewportSize = t.viewportSize ?? { width: 0, height: 0 }, this.contentSize = t.contentSize ?? { width: 0, height: 0 }, this.onCursorChange = t.onCursorChange ?? null, this.zoomInterceptor = t.zoomInterceptor ?? null, this.panInterceptor = t.panInterceptor ?? null, this.boundKeyUp = this.handleKeyUp.bind(this); } bind(e) { if (this.selfHandle) return; this.unbind(), this.container = e; let t = e.parentElement; if (!t) return; document.addEventListener("keyup", this.boundKeyUp); let n = { onWheel: this.handleWheel.bind(this), onMouseDown: this.handleMouseDown.bind(this), onMouseMove: this.handleMouseMove.bind(this), onMouseUp: this.handleMouseUp.bind(this), onMouseEnter: () => { this.isHovered = !0; }, onMouseLeave: () => { this.isHovered = !1; } }; this.mouseAdapter = new J(t, n), this.mouseAdapter.bind(), this.keyboardAdapter = new Y({ onShortcut: this.handleShortcut.bind(this) }), this.keyboardAdapter.bind(); } unbind() { this.mouseAdapter?.unbind(), this.mouseAdapter = null, this.keyboardAdapter?.unbind(), this.keyboardAdapter = null, document.removeEventListener("keyup", this.boundKeyUp), this.container = null; } destroy() { this.wheelRafId !== null && (cancelAnimationFrame(this.wheelRafId), this.wheelRafId = null), this.unbind(); } setZoomMode(e) { this.zoomMode = e; } handleWheel(e) { if (e.ctrlKey || e.metaKey) { e.preventDefault(); let t = this.container?.parentElement, n = t ? t.getBoundingClientRect() : new DOMRect(0, 0, 0, 0), r = this.engine.getState(), i = D({ mode: this.zoomMode, viewportSize: this.viewportSize, contentSize: this.contentSize, offset: { x: r.x, y: r.y }, scale: r.scale, pointerPosition: { x: e.clientX - n.left, y: e.clientY - n.top } }), a = i.x, o = i.y, s = e.deltaY === 0 ? e.deltaX : e.deltaY; this.pendingWheelDelta += s < 0 ? 1 : -1, this.wheelRafId === null && (this.wheelRafId = requestAnimationFrame(() => { if (this.wheelRafId = null, this.pendingWheelDelta === 0) return; let e = this.engine.getState().scale, t = e * Math.exp(this.pendingWheelDelta * this.zoomStep / 3); this.pendingWheelDelta = 0, this.executeZoom(() => this.engine.zoomTo(t, a, o), e, t, a, o); })); } } handleShortcut(e, t) { if (!this.isHovered) return; let n = this.viewportSize.width / 2, r = this.viewportSize.height / 2, i = (e) => { e(); }; switch (e) { case "ctrl+0": t.preventDefault(), i(() => this.executeZoom(() => this.engine.zoomTo(1, n, r), this.engine.getState().scale, 1, n, r)); break; case "ctrl+minus": { t.preventDefault(); let e = this.engine.getState().scale, a = e - this.zoomStep; i(() => this.executeZoom(() => this.engine.zoomBy(-this.zoomStep, n, r), e, a, n, r)); break; } case "ctrl+equal": case "ctrl+plus": { t.preventDefault(); let e = this.engine.getState().scale, a = e + this.zoomStep; i(() => this.executeZoom(() => this.engine.zoomBy(this.zoomStep, n, r), e, a, n, r)); break; } case "ctrl+1": { t.preventDefault(); let e = this.viewportSize.width, a = this.viewportSize.height, o = this.contentSize.width, s = this.contentSize.height; if (e > 0 && a > 0 && o > 0 && s > 0) { let t = e * .9 / o, c = a * .9 / s, l = Math.min(t, c), u = (e - o * l) / 2, d = (a - s * l) / 2, f = this.engine.getState().scale; i(() => this.executeZoom(() => this.engine.setTransform({ scale: l, x: u, y: d }), f, l, n, r)); } break; } case "space": this.isSpacePressed || (this.isSpacePressed = !0, t.preventDefault(), this.notifyCursorChange()); break; default: break; } } handleKeyUp(e) { e.key === " " && (this.isSpacePressed = !1, this.isDragging = !1, this.notifyCursorChange()); } handleMouseDown(e) { this.isSpacePressed && e.button === 0 && (this.isDragging = !0, this.dragStart = { x: e.clientX, y: e.clientY }, this.lastMouse = { x: e.clientX, y: e.clientY }, e.preventDefault(), this.notifyCursorChange()); } async handleMouseMove(e) { if (this.isDragging && this.isSpacePressed) { let t = e.clientX - this.lastMouse.x, n = e.clientY - this.lastMouse.y; (!this.panInterceptor?.beforePan || await this.panInterceptor.beforePan(t, n)) && (this.engine.panBy(t, n), this.panInterceptor?.afterPan?.(t, n)), this.lastMouse = { x: e.clientX, y: e.clientY }; } } handleMouseUp() { this.isDragging = !1, this.notifyCursorChange(); } async executeZoom(e, t, n, r, i) { (!this.zoomInterceptor?.beforeZoom || await this.zoomInterceptor.beforeZoom(t, n, r, i)) && (e(), this.zoomInterceptor?.afterZoom?.(t, this.engine.getState().scale, r, i)); } getCursorClass() { return this.isSpacePressed ? this.isDragging ? "grabbing" : "grab" : "default"; } notifyCursorChange() { this.onCursorChange?.(this.getCursorClass()); } }, ae = Symbol("RulerContext"); //#endregion //#region src/composables/useRulerScale.ts function X(e) { let { thick: n, viewportSize: r, scale: i, offset: a, vertical: o = !1, canvasSize: s, showMinorTicks: c } = e, l = m(0); return x(i, (e) => { l.value = I(l.value, e); }, { immediate: !0 }), { ticks: t(() => L({ scale: i.value, offset: o ? a.value.y : a.value.x, viewportSize: o ? r.value.height : r.value.width, thick: n, canvasSize: s?.value, showMinorTicks: c?.value })), currentConfig: t(() => F(i.value)) }; } //#endregion //#region src/components/RulerWrapperV3.vue?vue&type=script&setup=true&lang.ts var oe = { class: "preview-label" }, se = { class: "lines" }, ce = ["onMouseenter", "onMousedown"], Z = { key: 0, class: "line-label" }, le = /* @__PURE__ */ o({ __name: "RulerWrapperV3", props: { vertical: { type: Boolean }, width: {}, height: {}, thick: {}, scale: {}, offset: {}, lines: {}, palette: {}, showReferLine: { type: Boolean }, renderLinesInCanvas: { type: Boolean, default: !1 }, shadowStart: {}, shadowLength: {}, canvasSize: {}, showMinorTicks: { type: Boolean }, canvasWidth: { default: 1e3 }, canvasHeight: { default: 1e3 }, deleteLabel: { default: "放开删除" }, lockLine: { type: Boolean, default: !1 } }, emits: [ "addLine", "updateLine", "deleteLine" ], setup(a, { emit: o }) { y((e) => ({ v6f4fe4e5: e.palette.hoverColor })); let s = a, d = o, p = m(null), g = m(typeof window < "u" ? window.devicePixelRatio : 1), v = t(() => s.vertical ? "v-container" : "h-container"), w = t(() => ({ width: s.width + "px", height: s.height + "px", cursor: s.lockLine ? "default" : s.vertical ? "ew-resize" : "ns-resize", [s.vertical ? "borderRight" : "borderBottom"]: `1px solid ${s.palette.borderColor}` })), T = t(() => s.lines), E = m(null), D = m(null), O = m(!1), k = null, A = () => { k && clearTimeout(k), k = setTimeout(() => { O.value = !1; }, 1e3); }; x(() => s.scale, () => { O.value = !0, A(); }); function j(e) { e.locked || s.lockLine || (E.value = e.id); } function ee() { E.value = null; } function M(e) { if (E.value === e.id && D.value !== null) { let e = s.vertical ? s.canvasWidth : s.canvasHeight, t = D.value < 0 || D.value > e, n = D.value * s.scale + (s.vertical ? s.offset.x : s.offset.y) <= s.thick; if (t || n) return s.deleteLabel; } return String(Math.round(e.position)); } function N(e, t) { if (e.locked || s.lockLine) return; t.preventDefault(), E.value = e.id, D.value = e.position; let n = p.value?.getBoundingClientRect(); if (!n) return; let r = s.vertical ? t.clientX - n.left : t.clientY - n.top, i = e.position, a = !1, o = (t) => { let o = i + ((s.vertical ? t.clientX - n.left : t.clientY - n.top) - r) / s.scale, c = 10 / s.scale, l = F(s.scale).interval, u = Math.round(o / l) * l; Math.abs(o - u) < c && (o = u); let f = s.vertical ? s.canvasWidth : s.canvasHeight, p = o < 0 || o > f, m = o * s.scale + (s.vertical ? s.offset.x : s.offset.y) <= s.thick; a = p || m, D.value = o, d("updateLine", e.id, Math.round(o)); }, c = () => { a && d("deleteLine", e.id), document.removeEventListener("mousemove", o), document.removeEventListener("mouseup", c), E.value = null, D.value = null; }; document.addEventListener("mousemove", o), document.addEventListener("mouseup", c); } let P = m(!1), I = m(0), L = m(0), R = t(() => { let e = I.value, t = `1px dashed ${s.palette.guideLineColor}`; return s.vertical ? { left: `${e}px`, top: 0, height: "100%", width: "1px", borderLeft: t } : { top: `${e}px`, left: 0, width: "100%", height: "1px", borderBottom: t }; }); function z(e) { if (s.lockLine) return; P.value = !0, B(e); let t = (e) => { B(e); }, n = () => { if (document.removeEventListener("mousemove", t), document.removeEventListener("mouseup", n), P.value) { let e = L.value, t = s.vertical ? s.canvasWidth : s.canvasHeight, n = I.value <= s.thick; e >= 0 && e <= t && !n && d("addLine", { orientation: s.vertical ? "v" : "h", position: Math.round(e), visible: !0, locked: !1 }); } P.value = !1; }; document.addEventListener("mousemove", t), document.addEventListener("mouseup", n); } function B(e) { let t = p.value?.getBoundingClientRect(); if (!t) return; let n = s.vertical ? e.clientX - t.left : e.clientY - t.top, r = s.vertical ? s.offset.x : s.offset.y, i = (n - r) / s.scale, a = 10 / s.scale, o = F(s.scale).interval, c = Math.round(i / o) * o; Math.abs(i - c) < a && (i = c), I.value = i * s.scale + r, L.value = i; } let V = (e) => { let t = s.vertical ? s.offset.x : s.offset.y, n = e.position * s.scale + t, r = e.locked || s.lockLine ? "default" : s.vertical ? "ew-resize" : "ns-resize", i = e.locked || s.lockLine || O.value ? "none" : "auto"; return s.vertical ? { left: `${n}px`, top: 0, height: "100vh", width: "1px", borderLeft: `1px dashed ${s.palette.guideLineColor}`, cursor: r, pointerEvents: i } : { top: `${n}px`, left: 0, width: "100vw", height: "1px", borderBottom: `1px dashed ${s.palette.guideLineColor}`, cursor: r, pointerEvents: i }; }, H = t(() => ({ width: s.width, height: s.height })), U = t(() => s.scale), W = t(() => ({ x: s.vertical ? 0 : s.offset.x, y: s.vertical ? s.offset.y : 0 })), G = t(() => s.canvasSize ?? Infinity), te = t(() => s.showMinorTicks ?? !1), { ticks: K } = X({ thick: s.thick, viewportSize: H, scale: U, offset: W, vertical: s.vertical, canvasSize: G, showMinorTicks: te }), ne = new re(); function q() { let e = p.value; if (!e) return; let t = e.getContext("2d"); if (!t) return; let n = g.value; e.width = Math.round(s.width * n), e.height = Math.round(s.height * n), ne.render(t, [{ type: "ruler", marks: K.value, vertical: s.vertical, thick: s.thick, width: s.width, height: s.height, ratio: n, palette: s.palette, shadowStart: s.shadowStart, shadowLength: s.shadowLength, showShadowText: !0, canvasSize: s.canvasSize }], { x: 0, y: 0, width: s.width, height: s.height }); } return u(() => { q(); }), x(() => [ s.scale, s.offset, s.width, s.height, s.palette, s.shadowStart, s.shadowLength, s.showMinorTicks ], () => { q(); }, { deep: !0 }), (t, o) => (f(), r("div", { class: c(v.value) }, [ i("canvas", { ref_key: "canvasRef", ref: p, class: "ruler", style: l(w.value), onMousedown: C(z, ["stop"]) }, null, 36), P.value ? (f(), r("div", { key: 0, class: "preview-line", style: l(R.value) }, [i("span", oe, _(Math.round(L.value)), 1)], 4)) : n("", !0), S(i("div", se, [(f(!0), r(e, null, h(T.value, (e) => (f(), r("div", { key: e.id, class: c(["line", { active: E.value === e.id }]), style: l(V(e)), onMouseenter: C((t) => j(e), ["stop"]), onMouseleave: C(ee, ["stop"]), onMousedown: C((t) => N(e, t), ["stop"]) }, [e.locked ? n("", !0) : (f(), r("span", Z, _(M(e)), 1))], 46, ce))), 128))], 512), [[b, a.showReferLine && !a.renderLinesInCanvas]]) ], 2)); } }), ue = (e, t) => { let n = e.__vccOpts || e; for (let [e, r] of t) n[e] = r; return n; }, de = /* @__PURE__ */ ue(le, [["__scopeId", "data-v-8e5d5262"]]), fe = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAopJREFUOE/FlE9IVEEcx7+/N9ouds1Mu0QUSFZYdIgoUqQoKPBQHsKozpXE7jbTO/U8xLJvn6usBHWQ6hBFXupSkQeVbh0KJEPp0sH+eLGTsKs77xcj78m0ax0E8cHjzZv5zef3/c33xxA24KENYGJzoEEQbNNaN4Zh2OQ4znwYhr9c1/39vwrXVDo0NNS0tLR0GYB5D64BmAMwzMyvlFKz1es10Hw+f4mZ7wHYBeA9gNdENFepVOaEEM3M3OI4Thczn41gt6WUgQ3+C+r7/h0AWQD3mXnYqPA8L9nQ0HCemduIaFpKOWoAhUJhT6VSuQXgOjP3K6W8GLwKzeVyp4jonR0QBEErM48w8zFLyayUsjX+z+VyHhHdZebTSqkxM78CHRgYOKS1/ghgVErZY214RkQ7ADyRUj72ff8qgCtmXUrZGcf5vv8CwEUhxOF0Ov1pBRpla5dSdseBhUJhpznH6tIsZb1KqacW+BGArUaUXX63UuplHJTNZjuEEONSyhozfd/n6mQ1RkXZL2itz7mu+80EDA4ONi8vL/8AcM2UbikyR2BU9cSmmTU70YqKIAj2hWFo2uenlHK/BRg3Y2aeNO5GyU8S0ZbFxcUuz/NKEXAGQKPjOCcymcyX1dIi8DSAiWQyeaavr68cbSgCuBknYubnQoj+TCYzUywWE6VS6S2ADsdx2gxw1X3L7SNENMbMnwE8qK+vf5NKpRaMaeVyeW8ikfiaSqW+R7BuZr5BRMe11p2u607U9Gk8kc/ntzPzQwCmExYATDLzVBiGE0KIowAOADDf3QA+aK2VDaxRajto3K+rq+tl5nYAzQBamHmeiOYBTGmtR6ph/1Rqg9c73pz7dD1qN0TpHyNQRCUDJXrAAAAAAElFTkSuQmCC", pe = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAVCAYAAACpF6WWAAAAAXNSR0IArs4c6QAAAjtJREFUOE/NlD9oFEEUxn9v9ghC0hpRUogIAUmniGAT/5Q2FrETPSNRJILg7RwimI0ox85eQFCEBGIUO1PYpFM0jSConQoBEZGgGPsgl+w+2eM2bC57SopAFqYZ3v7m+977ZoQt+GQLmGxPaBiGgYiMWWvXBHZUGoZhH3BERPYC+4F+4Keq/urt7b1RLpf/ZEBVHa9Wq0HWyg3QKIoGVPU8cA7wgK/pUtXPQJ8xZk+pVBpuNBqXUoUiEvi+P56fzTpo6+SbwHNg1lo7WzTITGEKXFlZeeB53tVCpa3CK8AFa+1cBgvD8LKIXAQOJkkyICJDeYVBEJS6u7s/qeoLa+1o+l9TqXNuBLhmjDlbqVQ+5ICjInIfOBPH8W9jzGCR5YmJiRNxHM+papgqzqDvgSlr7VTernPuO3An3c9bBt74vv+yrdaKyLDv+/1Sq9UGPc97nY9EVuycU2AQOA7cAm4Dr4D5TvVxHB9rKo2iaEFVp621Ln96FEUngaOqGmSxabVqsh3a2h+x1h5qQjNrae/yE4+iaCwDJkky73neTuBZe129Xk+H+BS4l7ZqLVIZ2BhzuFKpvMsDVXXWGPMxFdAedOfcKeCRqj7MYrUhpz09PfXl5eXfectFWXXODQHpOq2qd/95o/JXr6ura3J1dXU6SZIfwKKIHAD2tVYMPBGRx77vN10UXtO85fTkmZmZHUtLSzUR2QXsBhaAL6r6DXhbrVYXi1yss59GqOgub/bN3Z7v6X/tb9Zmp/q/kN8s+lJb8oEAAAAASUVORK5CYII=", me = /* @__PURE__ */ o({ __name: "SketchRuler", props: { showRuler: { type: Boolean, default: !0 }, scale: { default: 1 }, thick: { default: 16 }, width: { default: 1400 }, height: { default: 800 }, canvasWidth: { default: 700 }, canvasHeight: { default: 700 }, palette: { default: () => ({}) }, lines: { default: () => ({ h: [], v: [] }) }, isShowReferLine: { type: Boolean, default: !0 }, snapThreshold: { default: 5 }, lockLine: { type: Boolean, default: !1 }, selfHandle: { type: Boolean, default: !1 }, zoomStep: { default: .25 }, minZoom: { default: .1 }, maxZoom: { default: 10 }, animationMode: { default: "ease-out" }, zoomMode: { default: "pointer" }, enableAnimation: { type: Boolean, default: !1 }, plugins: { default: () => [] }, autoCenter: { type: Boolean, default: !0 }, shadow: { default: () => ({ x: 0, y: 0, width: 0, height: 0 }) }, initialOffset: { default: () => ({ x: 0, y: 0 }) }, showMinorTicks: { type: Boolean, default: !1 }, paddingRatio: { default: .2 }, eyeIcon: {}, closeEyeIcon: {}, deleteLabel: { default: "放开删除" } }, emits: [ "update:scale", "update:offset", "zoomchange", "update:lines", "update:lockLine", "onCornerClick" ], setup(e, { expose: n, emit: o }) { let h = e, _ = o, y = t(() => h.width), C = t(() => h.height), { scale: w, offset: T, engine: E, setTransform: k, zoomBy: A, zoomTo: j, panBy: M, reset: N } = G({ initialScale: h.scale, initialOffset: h.initialOffset, minZoom: h.minZoom, maxZoom: h.maxZoom, enableAnimation: h.enableAnimation, animationMode: h.animationMode, autoCenter: h.autoCenter, canvasSize: { width: h.canvasWidth, height: h.canvasHeight }, viewportSize: { width: y.value, height: C.value }, paddingRatio: h.paddingRatio }), P = t(() => w.value); x(() => h.scale, (e) => { if (e !== void 0 && Math.abs(e - w.value) > 1e-10) { let t = D({ mode: h.zoomMode, viewportSize: { width: y.value, height: C.value }, contentSize: { width: h.canvasWidth, height: h.canvasHeight }, offset: { x: T.value.x, y: T.value.y }, scale: w.value }); E.zoomTo(e, t.x, t.y); } }), x(() => h.zoomMode, (e) => { z?.setZoomMode(e); }), x(() => h.animationMode, (e) => { e && E.setAnimationMode(e); }), x(() => h.paddingRatio, () => { if (h.autoCenter) { let e = O({ x: 0, y: 0, width: h.canvasWidth, height: h.canvasHeight }, { x: 0, y: 0, width: y.value, height: C.value }, "contain", h.paddingRatio); k({ scale: e.scale, x: e.x, y: e.y }); } }); let F = !1; x(w, (e) => { F || (F = !0, _("update:scale", e), requestAnimationFrame(() => { F = !1; })); }); let I = !1; x(T, (e) => { I || (I = !0, _("zoomchange", { scale: w.value, x: e.x, y: e.y }), _("update:offset", { x: e.x, y: e.y }), L.value && (L.value.style.transform = `matrix(${w.value}, 0, 0, ${w.value}, ${e.x}, ${e.y})`), requestAnimationFrame(() => { I = !1; })); }, { deep: !0 }); let L = m(null), R = m(!1), z = null; u(() => { if (L.value) { let e = w.value, t = T.value; L.value.style.transform = `matrix(${e}, 0, 0, ${e}, ${t.x}, ${t.y})`; } L.value && !h.selfHandle && (z = new ie(E, { zoomStep: h.zoomStep, selfHandle: !1, zoomMode: h.zoomMode, viewportSize: { width: y.value, height: C.value }, contentSize: { width: h.canvasWidth, height: h.canvasHeight }, onCursorChange: (e) => { V.value = e; }, zoomInterceptor: { beforeZoom: async (e, t, n, r) => await K.beforeZoom({ from: e, to: t, center: { x: n, y: r }, cancel: () => {} }), afterZoom: (e, t, n, r) => { K.afterZoom({ from: e, to: t, center: { x: n, y: r } }); } }, panInterceptor: { beforePan: async (e, t) => await K.beforePan({ offset: { ...T.value }, delta: { x: e, y: t }, cancel: () => {} }), afterPan: (e, t) => { K.afterPan({ offset: { ...T.value }, delta: { x: e, y: t } }); } } }), z.bind(L.value), V.value = z.getCursorClass()); }), d(() => { z?.destroy(), z = null; }); let V = m("default"), U = m(H(h.lines)), W = t(() => U.value.filter((e) => e.orientation === "h" && e.visible !== !1)), te = t(() => U.value.filter((e) => e.orientation === "v" && e.visible !== !1)), K = new ee(), ne = { getState: () => ({ scale: w.value, offset: { ...T.value }, lines: U.value }), zoomBy: A, zoomTo: j, panBy: M, setTransform: k }; K.setApi(ne), x(() => h.plugins, (e, t) => { if (e !== t) { K.clear(); for (let t of e ?? []) K.register(t); } }, { immediate: !0 }); function re(e) { let t = U.value, n = [], r = t.filter((e) => e.orientation === "h"); e.h.forEach((e, t) => { t < r.length ? n.push({ ...r[t], position: e }) : n.push({ id: B(), orientation: "h", position: e, visible: !0, locked: !1 }); }); let i = t.filter((e) => e.orientation === "v"); e.v.forEach((e, t) => { t < i.length ? n.push({ ...i[t], position: e }) : n.push({ id: B(), orientation: "v", position: e, visible: !0, locked: !1 }); }), U.value = n; } x(() => h.lines, (e) => { e && re(e); }, { deep: !0 }), x([ () => h.canvasWidth, () => h.canvasHeight, () => h.width, () => h.height ], () => { if (!h.autoCenter) return; let e = h.width, t = h.height, n = h.canvasWidth, r = h.canvasHeight; if (e > 0 && t > 0 && n > 0 && r > 0) { let i = O({ x: 0, y: 0, width: n, height: r }, { x: 0, y: 0, width: e, height: t }, "contain", h.paddingRatio); k({ scale: i.scale, x: i.x, y: i.y }); } }); let q = m(h.isShowReferLine); x(() => h.isShowReferLine, (e) => { q.value = e; }), x(() => h.showRuler, (e) => { le.showRuler.value = e; }); function J() { let e = [], t = []; for (let n of U.value) n.visible !== !1 && (n.orientation === "h" ? e.push(n.position) : t.push(n.position)); return { h: e, v: t }; } let Y = (e) => { let t = { ...e, id: B() }; U.value = [...U.value, t], K.onLineCreate({ line: t }), _("update:lines", J()); }, X = (e, t) => { let n = U.value.find((t) => t.id === e); if (!n) return; let r = n.position; U.value = U.value.map((n) => n.id === e ? { ...n, position: t } : n), K.onLineMove({ line: { ...n, position: t }, from: r, to: t }), _("update:lines", J()); }, oe = (e) => { let t = U.value.find((t) => t.id === e); U.value = U.value.filter((t) => t.id !== e), t && K.onLineDelete({ line: t }), _("update:lines", J()); }, se = m({ width: h.width, height: h.height }), ce = m({ width: h.canvasWidth, height: h.canvasHeight }), Z = t(() => ({ bgColor: "#f6f7f9", tickColor: "#BABBBC", labelColor: "#7D8694", guideLineColor: "#51d6a9", guideLineLockedColor: "#d4d7dc", hoverBg: "transparent", hoverColor: "#000", borderColor: "#eeeeef", shadowCol