vue3-sketch-ruler
Version:
> 是一个基于 Vue 3 + TypeScript 的标尺组件库,适用于低代码平台、大屏可视化、做图工具等场景,提供类似 Photoshop 的缩放与标尺辅助线体验。
1,654 lines • 61 kB
JavaScript
/*!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