@kangwuyi/vue3-sketch-ruler
Version:
A sketch ruler for VueJS 3
480 lines (479 loc) • 16.2 kB
JavaScript
import { h as Y, defineComponent as q, inject as R, ref as C, computed as M, createElementBlock as T, openBlock as p, withModifiers as j, normalizeStyle as A, normalizeClass as z, createElementVNode as O, toDisplayString as _, watch as F, onMounted as ce, createVNode as H, createCommentVNode as G, withDirectives as ue, unref as K, Fragment as ee, renderList as de, createBlock as Z, vShow as he, mergeDefaults as ve, provide as $ } from "vue";
import fe from "lodash";
/**
* @license @tabler/icons-vue v3.31.0 - MIT
*
* This source code is licensed under the MIT license.
* See the LICENSE file in the root directory of this source tree.
*/
var W = {
outline: {
xmlns: "http://www.w3.org/2000/svg",
width: 24,
height: 24,
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
"stroke-width": 2,
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
filled: {
xmlns: "http://www.w3.org/2000/svg",
width: 24,
height: 24,
viewBox: "0 0 24 24",
fill: "currentColor",
stroke: "none"
}
};
/**
* @license @tabler/icons-vue v3.31.0 - MIT
*
* This source code is licensed under the MIT license.
* See the LICENSE file in the root directory of this source tree.
*/
const te = (e, t, u, s) => ({ color: d = "currentColor", size: i = 24, stroke: v = 2, title: r, class: h, ...L }, { attrs: n, slots: g }) => {
let o = [...s.map((a) => Y(...a)), ...g.default ? [g.default()] : []];
return r && (o = [Y("title", r), ...o]), Y(
"svg",
{
...W[e],
width: i,
height: i,
...n,
class: ["tabler-icon", `tabler-icon-${t}`],
...e === "filled" ? {
fill: d
} : {
"stroke-width": v ?? W[e]["stroke-width"],
stroke: d
},
...L
},
o
);
};
/**
* @license @tabler/icons-vue v3.31.0 - MIT
*
* This source code is licensed under the MIT license.
* See the LICENSE file in the root directory of this source tree.
*/
var me = te("outline", "eye-x", "IconEyeX", [["path", { d: "M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0", key: "svg-0" }], ["path", { d: "M13.048 17.942a9.298 9.298 0 0 1 -1.048 .058c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6a17.986 17.986 0 0 1 -1.362 1.975", key: "svg-1" }], ["path", { d: "M22 22l-5 -5", key: "svg-2" }], ["path", { d: "M17 22l5 -5", key: "svg-3" }]]);
/**
* @license @tabler/icons-vue v3.31.0 - MIT
*
* This source code is licensed under the MIT license.
* See the LICENSE file in the root directory of this source tree.
*/
var ge = te("outline", "eye", "IconEye", [["path", { d: "M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0", key: "svg-0" }], ["path", { d: "M21 12c-2.4 4 -5.4 6 -9 6c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6", key: "svg-1" }]]);
const I = {
bgColor: "#171a24",
// ruler bg color
// 刻度尺
longfgColor: "#3B3B3B",
// ruler longer mark color
shortfgColor: "#3B3B3B",
// ruler shorter mark color
fontColor: "#f3f3f3",
// ruler font color
shadowColor: "#3275ff1a",
// ruler shadow color
lineColor: "#E02020",
borderColor: "#3B3B3B",
cornerActiveColor: "rgb(235, 86, 72, 0.6)"
};
var B = /* @__PURE__ */ ((e) => (e.DEL = "del", e.ADD = "add", e.UPDATE = "update", e))(B || {}), D = /* @__PURE__ */ ((e) => (e.HORIZONTAL = "horizontal", e.VERTICAL = "vertical", e))(D || {});
const P = Symbol("lineListCb"), Ne = {
lineList: {
horizontal: [],
vertical: []
},
updateLineList: () => {
}
}, ie = {
x: 0,
y: 0,
width: 0,
height: 0
}, ne = Symbol("rect"), le = window.devicePixelRatio || 1, oe = Symbol("wdpRatio"), U = 1, X = Symbol("scaleFigure"), be = ["tabindex"], Le = { class: "value" }, ke = /* @__PURE__ */ q({
__name: "line",
props: {
start: { type: Number, required: !0 },
isVertical: { type: Boolean, required: !0 },
rollback: { type: Number, required: !0 },
value: { type: Number, required: !0 },
thick: { type: Number, required: !0 }
},
emits: ["onIsMovingStart", "onIsMovingEnd", "onUpdateLine"],
setup(e, { emit: t }) {
const u = R(X, C(U)), s = R(P, () => {
}), d = t, i = C(e.value), v = M(() => ({
[e.isVertical ? "top" : "left"]: `${(i.value - e.start) * u.value}px`,
[e.isVertical ? "borderTop" : "borderLeft"]: `1px solid ${I.lineColor}`,
// ns↕️ ew↔️
cursor: e.isVertical ? "ns-resize" : "ew-resize",
[e.isVertical ? "width" : "height"]: `${e.rollback + e.thick}px`
})), r = M(() => ({
[e.isVertical ? "left" : "top"]: `${e.thick - (e.isVertical, 22)}px`
})), h = (n) => {
d("onIsMovingStart");
const g = e.isVertical ? n.clientY : n.clientX, o = i.value, a = (y) => {
const k = e.isVertical ? y.clientY : y.clientX, l = Math.round(o + (k - g) / u.value);
i.value = l;
}, c = () => {
d("onIsMovingEnd"), d("onUpdateLine", i.value), document.removeEventListener("mousemove", a), document.removeEventListener("mouseup", c);
};
document.addEventListener("mousemove", a), document.addEventListener("mouseup", c);
}, L = () => s(
e.isVertical ? D.VERTICAL : D.HORIZONTAL,
B.DEL,
e.value
);
return (n, g) => (p(), T("div", {
class: z({
"ruler-_-line": !0,
"ruler-_-line-v": e.isVertical,
"ruler-_-line-h": !e.isVertical
}),
style: A(v.value),
onDblclick: j(L, ["stop", "prevent"]),
onMousedown: j(h, ["stop", "prevent"]),
tabindex: e.value
}, [
O("div", {
class: "action",
style: A(r.value)
}, [
O("span", Le, _(i.value), 1)
], 4)
], 46, be));
}
}), Ve = (e) => e <= 0.25 ? 40 : e <= 0.5 ? 20 : e <= 1 ? 10 : e <= 2 ? 5 : e <= 4 ? 2 : 1, J = 0.83, we = (e, t, u, s, d) => {
const { scale: i, width: v, height: r, ratio: h } = d, { bgColor: L, fontColor: n, shadowColor: g, longfgColor: o, shortfgColor: a } = I;
if (t.scale(h, h), t.clearRect(0, 0, v, r), t.fillStyle = L, t.fillRect(0, 0, v, r), s) {
const m = ((e ? s.y : s.x) - u) * i, E = (e ? s.height : s.width) * i;
t.fillStyle = g;
const V = e ? 0 : m, re = e ? m : 0, ae = e ? v : E, se = e ? E : r;
t.fillRect(V, re, ae, se);
}
const c = Ve(i), y = c * i, k = c * 10, l = k * i, b = Math.floor(u / c) * c, w = Math.floor(u / k) * k, f = (b - u) / c * y, S = (w - u) / k * l, N = u + Math.ceil((e ? r : v) / i);
t.beginPath(), t.fillStyle = n, t.strokeStyle = o, t.font = '"PingFang SC","Microsoft YaHei"';
for (let m = w, E = 0; m < N; m += k, E += 1) {
const V = S + E * l + 0.5;
e ? t.moveTo(0, V) : t.moveTo(V, 0), t.save(), e ? t.translate(v * 0.4, V) : t.translate(V, r * 0.4), e && t.rotate(-Math.PI / 2), t.scale(J / h, J / h), t.fillText(String(m), 4 * h, 9 * h), t.restore(), e ? t.lineTo(v * 15 / 16, V) : t.lineTo(V, r * 15 / 16);
}
t.stroke(), t.closePath(), t.beginPath(), t.strokeStyle = a;
for (let m = b, E = 0; m < N; m += c, E += 1) {
const V = f + E * y + 0.5;
e ? t.moveTo(0, V) : t.moveTo(V, 0), m % k !== 0 && (e ? t.lineTo(v * 1 / 4, V) : t.lineTo(V, r * 1 / 4));
}
t.stroke(), t.closePath(), t.setTransform(1, 0, 0, 1, 0, 0);
}, ye = /* @__PURE__ */ q({
__name: "canvas",
props: {
isVertical: { type: Boolean, required: !0 },
lineVisible: { type: Boolean, required: !0 },
start: { type: Number, required: !0 },
width: { type: Number, required: !0 },
height: { type: Number, required: !0 }
},
emits: ["onLineVisible", "onLineMove", "onLineDisable", "onLineMoveEnd"],
setup(e, { emit: t }) {
const u = t, s = R(oe, C(le));
F(s, (l) => {
}, { deep: !0 });
const d = R(X, C(U)), i = R(
ne,
M(() => ie)
);
F(
[i, d],
([l, b]) => {
o();
},
{ deep: !0 }
);
const v = R(P, () => {
}), r = (l, b, w) => Math.round(b + l / w), h = C(null), L = C(null), n = e;
F(
() => [n.start],
() => {
o();
}
), F(
() => [n.width, n.height],
() => {
g(), o();
}
), ce(() => {
g(), o();
});
const g = () => {
if (!h.value) return;
h.value.width = n.width * s.value, h.value.height = n.height * s.value;
const l = h.value.getContext("2d");
l.font = `normal ${12 * s.value}px 'PingFang SC', 'Microsoft YaHei', monospace, sans-serif`, l.lineWidth = 1, l.textBaseline = "middle", L.value = l;
}, o = () => {
if (!L.value) return;
const l = {
scale: d.value,
ratio: s.value,
width: n.width,
height: n.height
};
we(
n.isVertical,
L.value,
n.start,
{
x: n.isVertical ? 0 : i.value.x,
width: n.isVertical ? 0 : i.value.width,
y: n.isVertical ? i.value.y : 0,
height: n.isVertical ? i.value.height : 0
},
l
);
}, a = (l) => {
const b = n.isVertical ? l.offsetY : l.offsetX, w = r(b, n.start, d.value);
v(
n.isVertical ? D.VERTICAL : D.HORIZONTAL,
B.ADD,
w
);
}, c = (l) => {
const b = n.isVertical ? l.offsetY : l.offsetX, w = r(b, n.start, d.value);
u("onLineVisible", w);
}, y = (l) => {
const b = n.isVertical ? l.offsetY : l.offsetX, w = r(b, n.start, d.value);
u("onLineMove", w);
}, k = () => u("onLineMoveEnd", !1);
return (l, b) => (p(), T("canvas", {
class: z({
"ruler-_-canvas": !0,
"ruler-_-canvas-noevent": !e.lineVisible
}),
ref_key: "canvasRef",
ref: h,
onClick: a,
onMouseenter: c,
onMousemove: y,
onMouseleave: k
}, null, 34));
}
}), Ce = {
key: 0,
class: "ruler-_-line-box"
}, Me = { class: "value" }, Q = /* @__PURE__ */ q({
__name: "wrapper",
props: {
isVertical: { type: Boolean, required: !0 },
width: { type: Number, required: !0 },
height: { type: Number, required: !0 },
thick: { type: Number, required: !0 },
// 缓存被 thick 替换的宽高
rollback: { type: Number, required: !0, defalut: 0 },
start: { type: Number, required: !0 },
lineVisible: { type: Boolean, required: !0 },
markLineList: Array
},
emits: ["update:lineVisible"],
setup(e, { emit: t }) {
const u = R(P, () => {
}), s = R(X, C(U)), d = t, i = e, v = M(() => {
const f = {
width: `calc(100% - ${i.thick}px)`,
height: `${i.thick}px`,
left: `${i.thick}px`
}, S = {
width: `${i.thick}px`,
height: `calc(100% - ${i.thick}px)`,
top: `${i.thick}px`
};
return i.isVertical ? S : f;
}), r = C(0), h = M(() => ({
[i.isVertical ? "top" : "left"]: `${(r.value - i.start) * s.value}px`,
[i.isVertical ? "borderTop" : "borderLeft"]: `1px dashed ${I.cornerActiveColor}`,
[i.isVertical ? "width" : "height"]: `${i.rollback + i.thick}px`
})), L = (f) => {
k.value || (r.value = f), y(!0);
}, n = fe.debounce((f) => {
r.value = f;
}, 1), g = () => y(!1), o = () => d("update:lineVisible", !1), a = (f) => {
const S = f - i.start, N = (i.isVertical ? i.height : i.width) / s.value, m = i.isVertical ? D.VERTICAL : D.HORIZONTAL;
S < 0 || S > N ? u(m, B.DEL, f) : u(m, B.UPDATE, f);
}, c = C(!1), y = (f) => c.value = f, k = C(!1), l = (f) => k.value = f, b = () => {
l(!0), y(!1);
}, w = () => {
l(!1);
};
return (f, S) => (p(), T("div", {
class: z({
"ruler-_-wrapper": !0,
"ruler-_-wrapper-v": e.isVertical,
"ruler-_-wrapper-h": !e.isVertical
}),
style: A(v.value)
}, [
H(ye, {
lineVisible: e.lineVisible,
isVertical: e.isVertical,
width: e.width,
height: e.height,
start: e.start,
onOnLineMove: K(n),
onOnLineMoveEnd: g,
onOnLineVisible: L,
onOnLineDisable: o
}, null, 8, ["lineVisible", "isVertical", "width", "height", "start", "onOnLineMove"]),
e.lineVisible ? (p(), T("div", Ce, [
(p(!0), T(ee, null, de(e.markLineList, (N, m) => (p(), Z(ke, {
key: "line" + N,
index: m,
start: e.start,
isVertical: e.isVertical,
rollback: e.rollback,
thick: e.thick,
value: N >> 0,
onOnIsMovingEnd: w,
onOnIsMovingStart: b,
onOnUpdateLine: a
}, null, 8, ["index", "start", "isVertical", "rollback", "thick", "value"]))), 128))
])) : G("", !0),
c.value ? ue((p(), T("div", {
key: 1,
class: "indicator",
style: A(h.value)
}, [
O("div", Me, _(r.value), 1)
], 4)), [
[he, e.lineVisible]
]) : G("", !0)
], 6));
}
}), x = /* @__PURE__ */ q({
__name: "ruler",
props: /* @__PURE__ */ ve({
// 变量
// Window.devicePixelRatio = {物理像素分辨率/CSS 像素分辨率}
wdpRatio: Number,
// ------------------
scaleFigure: Number,
// 传入阴影部分,选中画布组件,在标尺中标注组件位置
rect: Object,
// 常量
thick: Number,
width: Number,
height: Number,
startX: Number,
startY: Number,
markLineList: Array
}, {
wdpRatio: le,
__skip_wdpRatio: !0,
scaleFigure: U,
__skip_scaleFigure: !0,
rect: ie,
__skip_rect: !0,
thick: 24,
width: 0,
height: 0,
startX: 0,
startY: 0,
markLineList: () => []
}),
emits: [
// 选中组件的坐标值发生改变, rect.rect|rect.y
// 可能的情况,选中组件移动过程中发生吸附其他组件或中轴线或边界线
// 标注线
"onMarkLineList"
],
setup(e, { emit: t }) {
const u = t, s = M(() => e.wdpRatio);
$(oe, s);
const d = M(() => e.scaleFigure);
$(X, d), $("updateRect", () => {
});
const v = M(() => e.rect);
$(ne, v);
const r = M(
() => e.markLineList.reduce((o, a) => (o.horizontal || (o.horizontal = []), o.vertical || (o.vertical = []), a.type === "horizontal" ? o.horizontal.push(a.value) : a.type === "vertical" && o.vertical.push(a.value), o), {})
);
$(P, (o, a, c) => {
u("onMarkLineList", o, a, c);
});
const L = M(() => ({
backgroundColor: I.bgColor,
width: `${e.thick}px`,
height: `${e.thick}px`,
borderRight: `1px solid ${I.borderColor}`,
borderBottom: `1px solid ${I.borderColor}`
})), n = C(!1), g = () => n.value = !n.value;
return (o, a) => (p(), T(ee, null, [
H(Q, {
isVertical: !1,
markLineList: r.value.horizontal,
width: e.width,
height: e.thick,
thick: e.thick,
rollback: e.height,
start: e.startX,
lineVisible: n.value,
"onUpdate:lineVisible": a[0] || (a[0] = (c) => n.value = c)
}, null, 8, ["markLineList", "width", "height", "thick", "rollback", "start", "lineVisible"]),
H(Q, {
isVertical: !0,
markLineList: r.value.vertical,
width: e.thick,
height: e.height,
thick: e.thick,
rollback: e.width,
start: e.startY,
lineVisible: n.value,
"onUpdate:lineVisible": a[1] || (a[1] = (c) => n.value = c)
}, null, 8, ["markLineList", "width", "height", "thick", "rollback", "start", "lineVisible"]),
O("span", {
class: z(["", {
"ruler-_-corner": !0
}]),
style: A(L.value),
onClick: g
}, [
n.value ? (p(), Z(K(ge), {
key: 0,
class: "ruler-_-corner-icon"
})) : (p(), Z(K(me), {
key: 1,
class: "ruler-_-corner-icon"
}))
], 4)
], 64));
}
});
x.install = function(e) {
e.component("imp-sketch-ruler", x);
};
const pe = [x], Ee = function(e) {
pe.forEach((t) => {
e.component("imp-sketch-ruler", t);
});
}, Te = {
// 导出的对象必须具有 install,才能被 app.use() 方法安装
install: Ee,
SketchRuler: x
};
export {
Ne as DEFAULT_LINELIST,
ie as DEFAULT_RECT,
U as DEFAULT_SCALE_FIGURE,
I as DEFAULT_THEME,
le as DEFAULT_WDP_RATIO,
B as ELineActionType,
D as ELineDirectionType,
Te as default,
P as lineListCbKey,
ne as rectKey,
X as scaleFigureKey,
oe as wdpRatioKey
};