UNPKG

dada-datav-vue3

Version:

dataV组件vue3版本

1,541 lines 407 kB
import { ref, onMounted, onUnmounted, nextTick, reactive, watch, openBlock, createElementBlock, unref, Fragment, renderList, createElementVNode, normalizeStyle, toDisplayString, createCommentVNode, computed, onBeforeUnmount, renderSlot, createStaticVNode, getCurrentInstance, createVNode, defineComponent, normalizeClass } from "vue"; var colorKeywords = /* @__PURE__ */ new Map([ ["transparent", "rgba(0,0,0,0)"], ["black", "#000000"], ["silver", "#C0C0C0"], ["gray", "#808080"], ["white", "#FFFFFF"], ["maroon", "#800000"], ["red", "#FF0000"], ["purple", "#800080"], ["fuchsia", "#FF00FF"], ["green", "#008000"], ["lime", "#00FF00"], ["olive", "#808000"], ["yellow", "#FFFF00"], ["navy", "#000080"], ["blue", "#0000FF"], ["teal", "#008080"], ["aqua", "#00FFFF"], ["aliceblue", "#f0f8ff"], ["antiquewhite", "#faebd7"], ["aquamarine", "#7fffd4"], ["azure", "#f0ffff"], ["beige", "#f5f5dc"], ["bisque", "#ffe4c4"], ["blanchedalmond", "#ffebcd"], ["blueviolet", "#8a2be2"], ["brown", "#a52a2a"], ["burlywood", "#deb887"], ["cadetblue", "#5f9ea0"], ["chartreuse", "#7fff00"], ["chocolate", "#d2691e"], ["coral", "#ff7f50"], ["cornflowerblue", "#6495ed"], ["cornsilk", "#fff8dc"], ["crimson", "#dc143c"], ["cyan", "#00ffff"], ["darkblue", "#00008b"], ["darkcyan", "#008b8b"], ["darkgoldenrod", "#b8860b"], ["darkgray", "#a9a9a9"], ["darkgreen", "#006400"], ["darkgrey", "#a9a9a9"], ["darkkhaki", "#bdb76b"], ["darkmagenta", "#8b008b"], ["darkolivegreen", "#556b2f"], ["darkorange", "#ff8c00"], ["darkorchid", "#9932cc"], ["darkred", "#8b0000"], ["darksalmon", "#e9967a"], ["darkseagreen", "#8fbc8f"], ["darkslateblue", "#483d8b"], ["darkslategray", "#2f4f4f"], ["darkslategrey", "#2f4f4f"], ["darkturquoise", "#00ced1"], ["darkviolet", "#9400d3"], ["deeppink", "#ff1493"], ["deepskyblue", "#00bfff"], ["dimgray", "#696969"], ["dimgrey", "#696969"], ["dodgerblue", "#1e90ff"], ["firebrick", "#b22222"], ["floralwhite", "#fffaf0"], ["forestgreen", "#228b22"], ["gainsboro", "#dcdcdc"], ["ghostwhite", "#f8f8ff"], ["gold", "#ffd700"], ["goldenrod", "#daa520"], ["greenyellow", "#adff2f"], ["grey", "#808080"], ["honeydew", "#f0fff0"], ["hotpink", "#ff69b4"], ["indianred", "#cd5c5c"], ["indigo", "#4b0082"], ["ivory", "#fffff0"], ["khaki", "#f0e68c"], ["lavender", "#e6e6fa"], ["lavenderblush", "#fff0f5"], ["lawngreen", "#7cfc00"], ["lemonchiffon", "#fffacd"], ["lightblue", "#add8e6"], ["lightcoral", "#f08080"], ["lightcyan", "#e0ffff"], ["lightgoldenrodyellow", "#fafad2"], ["lightgray", "#d3d3d3"], ["lightgreen", "#90ee90"], ["lightgrey", "#d3d3d3"], ["lightpink", "#ffb6c1"], ["lightsalmon", "#ffa07a"], ["lightseagreen", "#20b2aa"], ["lightskyblue", "#87cefa"], ["lightslategray", "#778899"], ["lightslategrey", "#778899"], ["lightsteelblue", "#b0c4de"], ["lightyellow", "#ffffe0"], ["limegreen", "#32cd32"], ["linen", "#faf0e6"], ["magenta", "#ff00ff"], ["mediumaquamarine", "#66cdaa"], ["mediumblue", "#0000cd"], ["mediumorchid", "#ba55d3"], ["mediumpurple", "#9370db"], ["mediumseagreen", "#3cb371"], ["mediumslateblue", "#7b68ee"], ["mediumspringgreen", "#00fa9a"], ["mediumturquoise", "#48d1cc"], ["mediumvioletred", "#c71585"], ["midnightblue", "#191970"], ["mintcream", "#f5fffa"], ["mistyrose", "#ffe4e1"], ["moccasin", "#ffe4b5"], ["navajowhite", "#ffdead"], ["oldlace", "#fdf5e6"], ["olivedrab", "#6b8e23"], ["orange", "#ffa500"], ["orangered", "#ff4500"], ["orchid", "#da70d6"], ["palegoldenrod", "#eee8aa"], ["palegreen", "#98fb98"], ["paleturquoise", "#afeeee"], ["palevioletred", "#db7093"], ["papayawhip", "#ffefd5"], ["peachpuff", "#ffdab9"], ["peru", "#cd853f"], ["pink", "#ffc0cb"], ["plum", "#dda0dd"], ["powderblue", "#b0e0e6"], ["rosybrown", "#bc8f8f"], ["royalblue", "#4169e1"], ["saddlebrown", "#8b4513"], ["salmon", "#fa8072"], ["sandybrown", "#f4a460"], ["seagreen", "#2e8b57"], ["seashell", "#fff5ee"], ["sienna", "#a0522d"], ["skyblue", "#87ceeb"], ["slateblue", "#6a5acd"], ["slategray", "#708090"], ["slategrey", "#708090"], ["snow", "#fffafa"], ["springgreen", "#00ff7f"], ["steelblue", "#4682b4"], ["tan", "#d2b48c"], ["thistle", "#d8bfd8"], ["tomato", "#ff6347"], ["turquoise", "#40e0d0"], ["violet", "#ee82ee"], ["wheat", "#f5deb3"], ["whitesmoke", "#f5f5f5"], ["yellowgreen", "#9acd32"] ]); const hexReg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; const rgbReg = /^(rgb|rgba|RGB|RGBA)/; const rgbaReg = /^(rgba|RGBA)/; function validator(color2) { let isHex = hexReg.test(color2); let isRgb = rgbReg.test(color2); if (isHex || isRgb) return color2; color2 = getColorByKeyword(color2); if (!color2) { console.error("Color: Invalid color!"); return false; } return color2; } function getColorByKeyword(keyword) { if (!keyword) { console.error("getColorByKeywords: Missing parameters!"); return false; } if (!colorKeywords.has(keyword)) return false; return colorKeywords.get(keyword); } function getRgbValue(color2) { if (!color2) { console.error("getRgbValue: Missing parameters!"); return false; } color2 = validator(color2); if (!color2) return false; const isHex = hexReg.test(color2); const isRgb = rgbReg.test(color2); const lowerColor = color2.toLowerCase(); if (isHex) return getRgbValueFromHex(lowerColor); if (isRgb) return getRgbValueFromRgb(lowerColor); } function getRgbValueFromHex(color2) { color2 = color2.replace("#", ""); if (color2.length === 3) color2 = Array.from(color2).map((hexNum) => hexNum + hexNum).join(""); color2 = color2.split(""); return new Array(3).fill(0).map((t, i) => parseInt(`0x${color2[i * 2]}${color2[i * 2 + 1]}`)); } function getRgbValueFromRgb(color2) { return color2.replace(/rgb\(|rgba\(|\)/g, "").split(",").slice(0, 3).map((n) => parseInt(n)); } function getRgbaValue(color2) { if (!color2) { console.error("getRgbaValue: Missing parameters!"); return false; } const colorValue = getRgbValue(color2); if (!colorValue) return false; colorValue.push(getOpacity(color2)); return colorValue; } function getOpacity(color2) { if (!color2) { console.error("getOpacity: Missing parameters!"); return false; } color2 = validator(color2); if (!color2) return false; const isRgba = rgbaReg.test(color2); if (!isRgba) return 1; color2 = color2.toLowerCase(); return Number(color2.split(",").slice(-1)[0].replace(/[)|\s]/g, "")); } function toRgb(color2, opacity) { if (!color2) { console.error("toRgb: Missing parameters!"); return false; } const rgbValue = getRgbValue(color2); if (!rgbValue) return false; const addOpacity = typeof opacity === "number"; if (addOpacity) return "rgba(" + rgbValue.join(",") + `,${opacity})`; return "rgb(" + rgbValue.join(",") + ")"; } function toHex(color2) { if (!color2) { console.error("toHex: Missing parameters!"); return false; } if (hexReg.test(color2)) return color2; color2 = getRgbValue(color2); if (!color2) return false; return "#" + color2.map((n) => Number(n).toString(16)).map((n) => n === "0" ? "00" : n).join(""); } function getColorFromRgbValue(value) { if (!value) { console.error("getColorFromRgbValue: Missing parameters!"); return false; } const valueLength = value.length; if (valueLength !== 3 && valueLength !== 4) { console.error("getColorFromRgbValue: Value is illegal!"); return false; } let color2 = valueLength === 3 ? "rgb(" : "rgba("; color2 += value.join(",") + ")"; return color2; } function darken(color2, percent = 0) { if (!color2) { console.error("darken: Missing parameters!"); return false; } let rgbaValue = getRgbaValue(color2); if (!rgbaValue) return false; rgbaValue = rgbaValue.map((v, i) => i === 3 ? v : v - Math.ceil(2.55 * percent)).map((v) => v < 0 ? 0 : v); return getColorFromRgbValue(rgbaValue); } function lighten(color2, percent = 0) { if (!color2) { console.error("lighten: Missing parameters!"); return false; } let rgbaValue = getRgbaValue(color2); if (!rgbaValue) return false; rgbaValue = rgbaValue.map((v, i) => i === 3 ? v : v + Math.ceil(2.55 * percent)).map((v) => v > 255 ? 255 : v); return getColorFromRgbValue(rgbaValue); } function fade(color2, percent = 100) { if (!color2) { console.error("fade: Missing parameters!"); return false; } const rgbValue = getRgbValue(color2); if (!rgbValue) return false; const rgbaValue = [...rgbValue, percent / 100]; return getColorFromRgbValue(rgbaValue); } var color = { fade, toHex, toRgb, darken, lighten, getOpacity, getRgbValue, getRgbaValue, getColorFromRgbValue }; function randomExtend(minNum, maxNum) { if (arguments.length === 1) return parseInt((Math.random() * minNum + 1).toString(), 10); else return parseInt((Math.random() * (maxNum - minNum + 1) + minNum).toString(), 10); } function debounce(delay2, callback, vm) { let lastTime; return function() { clearTimeout(lastTime); lastTime = setTimeout(() => { callback.call(vm, ...arguments); }, delay2); }; } function observerDomResize(dom, callback) { const MutationObserver = window.MutationObserver; const observer = new MutationObserver(callback); observer.observe(dom, { attributes: true, attributeFilter: ["style"], attributeOldValue: true }); return observer; } function getPointDistance(pointOne, pointTwo) { const minusX = Math.abs(pointOne[0] - pointTwo[0]); const minusY = Math.abs(pointOne[1] - pointTwo[1]); return Math.sqrt(minusX * minusX + minusY * minusY); } function getCircleRadianPoint$1(x, y, radius, radian) { return [x + Math.cos(radian) * radius, y + Math.sin(radian) * radius]; } function filterNonNumber$1(array) { return array.filter((n) => { return typeof n === "number"; }); } function mulAdd$1(nums) { nums = filterNonNumber$1(nums); return nums.reduce((all, num) => { return all + num; }, 0); } function getTwoPointDistance$3(pointOne, pointTwo) { const minusX = Math.abs(pointOne.x - pointTwo.x); const minusY = Math.abs(pointOne.y - pointTwo.y); return Math.sqrt(minusX * minusX + minusY * minusY); } function getPolylineLength$1(points) { const lineSegments = new Array(points.length - 1).fill(0).map((foo, i) => { return [points[i], points[i + 1]]; }); const lengths = lineSegments.map((item) => { return getTwoPointDistance$3(item[0], item[1]); }); return mulAdd$1(lengths); } function PointToString(point) { return `${point.x},${point.y}`; } function PointsToString(points) { return points.map(PointToString).join(" "); } function uuid(hasHyphen) { return (hasHyphen ? "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" : "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx").replace(/[xy]/g, (c) => { const r = Math.random() * 16 | 0; const v = c === "x" ? r : r & 3 | 8; return v.toString(16); }); } function deepMerge$1(target, merged) { for (const key in merged) { if (target[key] && typeof target[key] === "object") { deepMerge$1(target[key], merged[key]); continue; } if (typeof merged[key] === "object") { target[key] = deepClone$1(merged[key], true); continue; } target[key] = merged[key]; } return target; } function deepClone$1(object, recursion) { if (!object) return object; const { parse, stringify } = JSON; if (!recursion) return parse(stringify(object)); const clonedObj = object instanceof Array ? [] : {}; if (object && typeof object === "object") { for (const key in object) { if (Object.prototype.hasOwnProperty.call(object, key)) { if (object[key] && typeof object[key] === "object") clonedObj[key] = deepClone$1(object[key], true); else clonedObj[key] = object[key]; } } } return clonedObj; } const autoResize = (dom, onResize, afterAutoResizeMixinInit) => { const width = ref(0); const height = ref(0); let debounceInitWHFun; let domObserver = null; let domHtml = null; const initWH = (resize = true) => { return new Promise((resolve) => { nextTick(() => { domHtml = dom.value; width.value = dom.value ? dom.value.clientWidth : 0; height.value = dom.value ? dom.value.clientHeight : 0; if (!dom.value) console.warn("DataV: Failed to get dom node, component rendering may be abnormal!"); else if (!width.value || !height.value) console.warn("DataV: Component width or height is 0px, rendering abnormality may occur!"); if (typeof onResize === "function" && resize) onResize(); resolve(true); }); }); }; const getDebounceInitWHFun = () => { debounceInitWHFun = debounce(100, initWH, void 0); }; const bindDomResizeCallback = () => { domObserver = observerDomResize(domHtml, debounceInitWHFun); window.addEventListener("resize", debounceInitWHFun); }; const unbindDomResizeCallback = () => { if (!domObserver) return; domObserver.disconnect(); domObserver.takeRecords(); domObserver = null; window.removeEventListener("resize", debounceInitWHFun); }; const autoResizeMixinInit = async () => { await initWH(false); getDebounceInitWHFun(); bindDomResizeCallback(); if (typeof afterAutoResizeMixinInit === "function") afterAutoResizeMixinInit(); }; onMounted(() => { autoResizeMixinInit(); }); onUnmounted(() => { unbindDomResizeCallback(); }); return { width, height }; }; var index_vue_vue_type_style_index_0_lang$B = /* @__PURE__ */ (() => ".dv-conical-column-chart{width:100%;height:100%}.dv-conical-column-chart text{text-anchor:middle}\n")(); const _hoisted_1$z = ["width", "height"]; const _hoisted_2$y = ["d", "fill"]; const _hoisted_3$w = ["fill", "x", "y"]; const _hoisted_4$t = ["xlink:href", "width", "height", "x", "y"]; const _hoisted_5$q = ["fill", "x", "y"]; const _sfc_main$B = { __name: "index", props: { config: { type: Object, default: () => ({}) } }, setup(__props) { const props = __props; const conicalColumnChart = ref(null); const { width, height } = autoResize(conicalColumnChart, onResize, afterAutoResizeMixinInit); const state = reactive({ defaultConfig: { data: [], img: [], fontSize: 12, imgSideLength: 30, columnColor: "rgba(0, 194, 255, 0.4)", textColor: "#fff", showValue: false }, mergedConfig: null, column: [] }); watch(() => props.config, () => { calcData(); }, { deep: true }); function afterAutoResizeMixinInit() { calcData(); } function onResize() { calcData(); } function calcData() { mergeConfig(); initData(); calcSVGPath(); } function mergeConfig() { state.mergedConfig = deepMerge$1(deepClone$1(state.defaultConfig, true), props.config || {}); } function initData() { let { data } = state.mergedConfig; data = deepClone$1(data, true); data.sort(({ value: a }, { value: b }) => { if (a > b) return -1; else if (a < b) return 1; else return 0; }); const max2 = data[0] ? data[0].value : 10; data = data.map((item) => ({ ...item, percent: item.value / max2 })); state.mergedConfig.data = data; } function calcSVGPath() { const { imgSideLength, fontSize, data } = state.mergedConfig; const itemNum = data.length; const gap = width.value / (itemNum + 1); const useAbleHeight = height.value - imgSideLength - fontSize - 5; const svgBottom = height.value - fontSize - 5; state.column = data.map((item, i) => { const { percent } = item; const middleXPos = gap * (i + 1); const leftXPos = gap * i; const rightXpos = gap * (i + 2); const middleYPos = svgBottom - useAbleHeight * percent; const controlYPos = useAbleHeight * percent * 0.6 + middleYPos; const d = ` M${leftXPos}, ${svgBottom} Q${middleXPos}, ${controlYPos} ${middleXPos},${middleYPos} M${middleXPos},${middleYPos} Q${middleXPos}, ${controlYPos} ${rightXpos},${svgBottom} L${leftXPos}, ${svgBottom} Z `; const textY = (svgBottom + middleYPos) / 2 + fontSize / 2; return { ...item, d, x: middleXPos, y: middleYPos, textY }; }); } return (_ctx, _cache) => { return openBlock(), createElementBlock("div", { ref_key: "conicalColumnChart", ref: conicalColumnChart, class: "dv-conical-column-chart" }, [ (openBlock(), createElementBlock("svg", { width: unref(width), height: unref(height) }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(state.column, (item, i) => { return openBlock(), createElementBlock("g", { key: i }, [ createElementVNode("path", { d: item.d, fill: state.mergedConfig.columnColor }, null, 8, _hoisted_2$y), createElementVNode("text", { style: normalizeStyle(`fontSize:${state.mergedConfig.fontSize}px`), fill: state.mergedConfig.textColor, x: item.x, y: unref(height) - 4 }, toDisplayString(item.name), 13, _hoisted_3$w), state.mergedConfig.img.length ? (openBlock(), createElementBlock("image", { key: 0, "xlink:href": state.mergedConfig.img[i % state.mergedConfig.img.length], width: state.mergedConfig.imgSideLength, height: state.mergedConfig.imgSideLength, x: item.x - state.mergedConfig.imgSideLength / 2, y: item.y - state.mergedConfig.imgSideLength }, null, 8, _hoisted_4$t)) : createCommentVNode("", true), state.mergedConfig.showValue ? (openBlock(), createElementBlock("text", { key: 1, style: normalizeStyle(`fontSize:${state.mergedConfig.fontSize}px`), fill: state.mergedConfig.textColor, x: item.x, y: item.textY }, toDisplayString(item.value), 13, _hoisted_5$q)) : createCommentVNode("", true) ]); }), 128)) ], 8, _hoisted_1$z)) ], 512); }; } }; const ConicalColumnChartPlugin = { install(app) { app.component("DvConicalColumnChart", _sfc_main$B); } }; var index_vue_vue_type_style_index_0_lang$A = /* @__PURE__ */ (() => ".dv-percent-pond{position:relative;display:flex;flex-direction:column}.dv-percent-pond svg{position:absolute;left:0px;top:0px;width:100%;height:100%}.dv-percent-pond polyline{transition:all .3s}.dv-percent-pond text{font-size:25px;font-weight:700;text-anchor:middle;dominant-baseline:middle}\n")(); const _hoisted_1$y = ["id"]; const _hoisted_2$x = ["offset", "stop-color"]; const _hoisted_3$v = ["id", "x2"]; const _hoisted_4$s = ["offset", "stop-color"]; const _hoisted_5$p = ["x", "y", "rx", "ry", "stroke-width", "stroke", "width", "height"]; const _hoisted_6$n = ["stroke-width", "stroke-dasharray", "stroke", "points"]; const _hoisted_7$m = ["stroke", "fill", "x", "y"]; const _sfc_main$A = { __name: "index", props: { config: { type: Object, default: () => ({}) } }, setup(__props) { const props = __props; const id = uuid(); const percentPond = ref(null); const state = reactive({ gradientId1: `percent-pond-gradientId1-${id}`, gradientId2: `percent-pond-gradientId2-${id}`, width: 0, height: 0, defaultConfig: { value: 0, colors: ["#3DE7C9", "#00BAFF"], borderWidth: 3, borderGap: 3, lineDash: [5, 1], textColor: "#fff", borderRadius: 5, localGradient: false, formatter: "{value}%" }, mergedConfig: null }); const rectWidth = computed(() => { if (!state.mergedConfig) return 0; const { borderWidth } = state.mergedConfig; return state.width - borderWidth; }); const rectHeight = computed(() => { if (!state.mergedConfig) return 0; const { borderWidth } = state.mergedConfig; return state.height - borderWidth; }); const points = computed(() => { const halfHeight = state.height / 2; if (!state.mergedConfig) return `0, ${halfHeight} 0, ${halfHeight}`; const { borderWidth, borderGap, value } = state.mergedConfig; const polylineLength = (state.width - (borderWidth + borderGap) * 2) / 100 * value; return ` ${borderWidth + borderGap}, ${halfHeight} ${borderWidth + borderGap + polylineLength}, ${halfHeight + 1e-3} `; }); const polylineWidth = computed(() => { if (!state.mergedConfig) return 0; const { borderWidth, borderGap } = state.mergedConfig; return state.height - (borderWidth + borderGap) * 2; }); const linearGradient = computed(() => { if (!state.mergedConfig) return []; const { colors } = state.mergedConfig; const colorNum = colors.length; const colorOffsetGap = 100 / (colorNum - 1); return colors.map((c, i) => [colorOffsetGap * i, c]); }); const polylineGradient = computed(() => { if (!state.mergedConfig) return state.gradientId2; if (state.mergedConfig.localGradient) return state.gradientId1; return state.gradientId2; }); const gradient2XPos = computed(() => { if (!state.mergedConfig) return "100%"; const { value } = state.mergedConfig; return `${200 - value}%`; }); const details = computed(() => { if (!state.mergedConfig) return ""; const { value, formatter } = state.mergedConfig; return formatter.replace("{value}", value); }); watch(() => props.config, () => { mergeConfig(); }, { deep: true }); onMounted(() => { init(); }); async function init() { await initWH(); if (!props.config) return; mergeConfig(); } async function initWH() { await nextTick(); const { clientWidth, clientHeight } = percentPond.value; state.width = clientWidth; state.height = clientHeight; } function mergeConfig() { state.mergedConfig = deepMerge$1(deepClone$1(state.defaultConfig, true), props.config || {}); } return (_ctx, _cache) => { return openBlock(), createElementBlock("div", { ref_key: "percentPond", ref: percentPond, class: "dv-percent-pond" }, [ (openBlock(), createElementBlock("svg", null, [ createElementVNode("defs", null, [ createElementVNode("linearGradient", { id: state.gradientId1, x1: "0%", y1: "0%", x2: "100%", y2: "0%" }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(unref(linearGradient), (lc) => { return openBlock(), createElementBlock("stop", { key: lc[0], offset: `${lc[0]}%`, "stop-color": lc[1] }, null, 8, _hoisted_2$x); }), 128)) ], 8, _hoisted_1$y), createElementVNode("linearGradient", { id: state.gradientId2, x1: "0%", y1: "0%", x2: unref(gradient2XPos), y2: "0%" }, [ (openBlock(true), createElementBlock(Fragment, null, renderList(unref(linearGradient), (lc) => { return openBlock(), createElementBlock("stop", { key: lc[0], offset: `${lc[0]}%`, "stop-color": lc[1] }, null, 8, _hoisted_4$s); }), 128)) ], 8, _hoisted_3$v) ]), createElementVNode("rect", { x: state.mergedConfig ? state.mergedConfig.borderWidth / 2 : "0", y: state.mergedConfig ? state.mergedConfig.borderWidth / 2 : "0", rx: state.mergedConfig ? state.mergedConfig.borderRadius : "0", ry: state.mergedConfig ? state.mergedConfig.borderRadius : "0", fill: "transparent", "stroke-width": state.mergedConfig ? state.mergedConfig.borderWidth : "0", stroke: `url(#${state.gradientId1})`, width: unref(rectWidth) > 0 ? unref(rectWidth) : 0, height: unref(rectHeight) > 0 ? unref(rectHeight) : 0 }, null, 8, _hoisted_5$p), createElementVNode("polyline", { "stroke-width": unref(polylineWidth), "stroke-dasharray": state.mergedConfig ? state.mergedConfig.lineDash.join(",") : "0", stroke: `url(#${unref(polylineGradient)})`, points: unref(points) }, null, 8, _hoisted_6$n), createElementVNode("text", { stroke: state.mergedConfig ? state.mergedConfig.textColor : "#fff", fill: state.mergedConfig ? state.mergedConfig.textColor : "#fff", x: state.width / 2, y: state.height / 2 }, toDisplayString(unref(details)), 9, _hoisted_7$m) ])) ], 512); }; } }; const PercentPondPlugin = { install(app) { app.component("DvPercentPond", _sfc_main$A); } }; const { sqrt: sqrt$1, pow: pow$1, ceil, abs: abs$2 } = Math; const defaultSegmentPointsNum = 50; function abstractBezierCurveToPolyline(bezierCurve2, precision = 5) { const segmentsNum = bezierCurve2.length - 1; const startPoint = bezierCurve2[0]; const endPoint = bezierCurve2[segmentsNum][2]; const segments = bezierCurve2.slice(1); const getSegmentTPointFuns = segments.map((seg, i) => { let beginPoint = i === 0 ? startPoint : segments[i - 1][2]; return createGetBezierCurveTPointFun(beginPoint, ...seg); }); let segmentPointsNum = new Array(segmentsNum).fill(defaultSegmentPointsNum); let segmentPoints = getSegmentPointsByNum(getSegmentTPointFuns, segmentPointsNum); const result = calcUniformPointsByIteration(segmentPoints, getSegmentTPointFuns, segments, precision); result.segmentPoints.push(endPoint); return result; } function createGetBezierCurveTPointFun(beginPoint, controlPoint1, controlPoint2, endPoint) { return function(t) { const tSubed1 = 1 - t; const tSubed1Pow3 = pow$1(tSubed1, 3); const tSubed1Pow2 = pow$1(tSubed1, 2); const tPow3 = pow$1(t, 3); const tPow2 = pow$1(t, 2); return [ beginPoint[0] * tSubed1Pow3 + 3 * controlPoint1[0] * t * tSubed1Pow2 + 3 * controlPoint2[0] * tPow2 * tSubed1 + endPoint[0] * tPow3, beginPoint[1] * tSubed1Pow3 + 3 * controlPoint1[1] * t * tSubed1Pow2 + 3 * controlPoint2[1] * tPow2 * tSubed1 + endPoint[1] * tPow3 ]; }; } function getTwoPointDistance$2([ax, ay], [bx, by]) { return sqrt$1(pow$1(ax - bx, 2) + pow$1(ay - by, 2)); } function getNumsSum(nums) { return nums.reduce((sum, num) => sum + num, 0); } function getSegmentPointsDistance(segmentPoints) { return segmentPoints.map((points, i) => { return new Array(points.length - 1).fill(0).map((temp, j) => getTwoPointDistance$2(points[j], points[j + 1])); }); } function getSegmentPointsByNum(getSegmentTPointFuns, segmentPointsNum) { return getSegmentTPointFuns.map((getSegmentTPointFun, i) => { const tGap = 1 / segmentPointsNum[i]; return new Array(segmentPointsNum[i]).fill("").map((foo, j) => getSegmentTPointFun(j * tGap)); }); } function getAllDeviations(segmentPointsDistance, avgLength) { return segmentPointsDistance.map((seg) => seg.map((s) => abs$2(s - avgLength))).map((seg) => getNumsSum(seg)).reduce((total, v) => total + v, 0); } function calcUniformPointsByIteration(segmentPoints, getSegmentTPointFuns, segments, precision) { let rounds = 4; let cycles = 1; do { let totalPointsNum = segmentPoints.reduce((total, seg) => total + seg.length, 0); segmentPoints.forEach((seg, i) => seg.push(segments[i][2])); let segmentPointsDistance = getSegmentPointsDistance(segmentPoints); let lineSegmentNum = segmentPointsDistance.reduce((total, seg) => total + seg.length, 0); let segmentlength = segmentPointsDistance.map((seg) => getNumsSum(seg)); let totalLength = getNumsSum(segmentlength); let avgLength = totalLength / lineSegmentNum; let allDeviations = getAllDeviations(segmentPointsDistance, avgLength); if (allDeviations <= precision) break; totalPointsNum = ceil(avgLength / precision * totalPointsNum * 1.1); const segmentPointsNum = segmentlength.map((length) => ceil(length / totalLength * totalPointsNum)); segmentPoints = getSegmentPointsByNum(getSegmentTPointFuns, segmentPointsNum); totalPointsNum = segmentPoints.reduce((total, seg) => total + seg.length, 0); let segmentPointsForLength = JSON.parse(JSON.stringify(segmentPoints)); segmentPointsForLength.forEach((seg, i) => seg.push(segments[i][2])); segmentPointsDistance = getSegmentPointsDistance(segmentPointsForLength); lineSegmentNum = segmentPointsDistance.reduce((total, seg) => total + seg.length, 0); segmentlength = segmentPointsDistance.map((seg) => getNumsSum(seg)); totalLength = getNumsSum(segmentlength); avgLength = totalLength / lineSegmentNum; const stepSize = 1 / totalPointsNum / 10; getSegmentTPointFuns.forEach((getSegmentTPointFun, i) => { const currentSegmentPointsNum = segmentPointsNum[i]; const t = new Array(currentSegmentPointsNum).fill("").map((foo, j) => j / segmentPointsNum[i]); for (let r = 0; r < rounds; r++) { let distance = getSegmentPointsDistance([segmentPoints[i]])[0]; const deviations = distance.map((d) => d - avgLength); let offset = 0; for (let j = 0; j < currentSegmentPointsNum; j++) { if (j === 0) return; offset += deviations[j - 1]; t[j] -= stepSize * offset; if (t[j] > 1) t[j] = 1; if (t[j] < 0) t[j] = 0; segmentPoints[i][j] = getSegmentTPointFun(t[j]); } } }); rounds *= 4; cycles++; } while (rounds <= 1025); segmentPoints = segmentPoints.reduce((all, seg) => all.concat(seg), []); return { segmentPoints, cycles, rounds }; } function bezierCurveToPolyline$1(bezierCurve2, precision = 5) { if (!bezierCurve2) { console.error("bezierCurveToPolyline: Missing parameters!"); return false; } if (!(bezierCurve2 instanceof Array)) { console.error("bezierCurveToPolyline: Parameter bezierCurve must be an array!"); return false; } if (typeof precision !== "number") { console.error("bezierCurveToPolyline: Parameter precision must be a number!"); return false; } const { segmentPoints } = abstractBezierCurveToPolyline(bezierCurve2, precision); return segmentPoints; } function getBezierCurveLength$1(bezierCurve2, precision = 5) { if (!bezierCurve2) { console.error("getBezierCurveLength: Missing parameters!"); return false; } if (!(bezierCurve2 instanceof Array)) { console.error("getBezierCurveLength: Parameter bezierCurve must be an array!"); return false; } if (typeof precision !== "number") { console.error("getBezierCurveLength: Parameter precision must be a number!"); return false; } const { segmentPoints } = abstractBezierCurveToPolyline(bezierCurve2, precision); const pointsDistance = getSegmentPointsDistance([segmentPoints])[0]; const length = getNumsSum(pointsDistance); return length; } function polylineToBezierCurve$2(polyline2, close = false, offsetA = 0.25, offsetB = 0.25) { if (!(polyline2 instanceof Array)) { console.error("polylineToBezierCurve: Parameter polyline must be an array!"); return false; } if (polyline2.length <= 2) { console.error("polylineToBezierCurve: Converting to a curve requires at least 3 points!"); return false; } const startPoint = polyline2[0]; const bezierCurveLineNum = polyline2.length - 1; const bezierCurvePoints = new Array(bezierCurveLineNum).fill(0).map((foo, i) => [...getBezierCurveLineControlPoints(polyline2, i, close, offsetA, offsetB), polyline2[i + 1]]); if (close) closeBezierCurve(bezierCurvePoints, startPoint); bezierCurvePoints.unshift(polyline2[0]); return bezierCurvePoints; } function getBezierCurveLineControlPoints(polyline2, index, close = false, offsetA = 0.25, offsetB = 0.25) { const pointNum = polyline2.length; if (pointNum < 3 || index >= pointNum) return; let beforePointIndex = index - 1; if (beforePointIndex < 0) beforePointIndex = close ? pointNum + beforePointIndex : 0; let afterPointIndex = index + 1; if (afterPointIndex >= pointNum) afterPointIndex = close ? afterPointIndex - pointNum : pointNum - 1; let afterNextPointIndex = index + 2; if (afterNextPointIndex >= pointNum) afterNextPointIndex = close ? afterNextPointIndex - pointNum : pointNum - 1; const pointBefore = polyline2[beforePointIndex]; const pointMiddle = polyline2[index]; const pointAfter = polyline2[afterPointIndex]; const pointAfterNext = polyline2[afterNextPointIndex]; return [ [ pointMiddle[0] + offsetA * (pointAfter[0] - pointBefore[0]), pointMiddle[1] + offsetA * (pointAfter[1] - pointBefore[1]) ], [ pointAfter[0] - offsetB * (pointAfterNext[0] - pointMiddle[0]), pointAfter[1] - offsetB * (pointAfterNext[1] - pointMiddle[1]) ] ]; } function closeBezierCurve(bezierCurve2, startPoint) { const firstSubCurve = bezierCurve2[0]; const lastSubCurve = bezierCurve2.slice(-1)[0]; bezierCurve2.push([ getSymmetryPoint(lastSubCurve[1], lastSubCurve[2]), getSymmetryPoint(firstSubCurve[0], startPoint), startPoint ]); return bezierCurve2; } function getSymmetryPoint(point, centerPoint) { const [px, py] = point; const [cx, cy] = centerPoint; const minusX = cx - px; const minusY = cy - py; return [cx + minusX, cy + minusY]; } var bezierCurve$1 = { bezierCurveToPolyline: bezierCurveToPolyline$1, getBezierCurveLength: getBezierCurveLength$1, polylineToBezierCurve: polylineToBezierCurve$2 }; const { abs: abs$1, sqrt, sin, cos, max: max$1, min: min$1, PI } = Math; function deepClone(object, recursion = false) { if (!object) return object; const { parse, stringify } = JSON; if (!recursion) return parse(stringify(object)); const clonedObj = object instanceof Array ? [] : {}; if (object && typeof object === "object") { for (let key in object) { if (object.hasOwnProperty(key)) { if (object[key] && typeof object[key] === "object") { clonedObj[key] = deepClone(object[key], true); } else { clonedObj[key] = object[key]; } } } } return clonedObj; } function eliminateBlur(points) { return points.map(([x, y]) => [parseInt(x) + 0.5, parseInt(y) + 0.5]); } function checkPointIsInCircle(point, rx, ry, r) { return getTwoPointDistance$1(point, [rx, ry]) <= r; } function getTwoPointDistance$1([xa, ya], [xb, yb]) { const minusX = abs$1(xa - xb); const minusY = abs$1(ya - yb); return sqrt(minusX * minusX + minusY * minusY); } function checkPointIsInPolygon(point, polygon) { let counter = 0; const [x, y] = point; const pointNum = polygon.length; for (let i = 1, p1 = polygon[0]; i <= pointNum; i++) { const p2 = polygon[i % pointNum]; if (x > min$1(p1[0], p2[0]) && x <= max$1(p1[0], p2[0])) { if (y <= max$1(p1[1], p2[1])) { if (p1[0] !== p2[0]) { const xinters = (x - p1[0]) * (p2[1] - p1[1]) / (p2[0] - p1[0]) + p1[1]; if (p1[1] === p2[1] || y <= xinters) { counter++; } } } } p1 = p2; } return counter % 2 === 1; } function checkPointIsInSector(point, rx, ry, r, startAngle, endAngle, clockWise) { if (!point) return false; if (getTwoPointDistance$1(point, [rx, ry]) > r) return false; if (!clockWise) [startAngle, endAngle] = deepClone([endAngle, startAngle]); const reverseBE = startAngle > endAngle; if (reverseBE) [startAngle, endAngle] = [endAngle, startAngle]; const minus = endAngle - startAngle; if (minus >= PI * 2) return true; const [x, y] = point; const [bx, by] = getCircleRadianPoint(rx, ry, r, startAngle); const [ex, ey] = getCircleRadianPoint(rx, ry, r, endAngle); const vPoint = [x - rx, y - ry]; let vBArm = [bx - rx, by - ry]; let vEArm = [ex - rx, ey - ry]; const reverse = minus > PI; if (reverse) [vBArm, vEArm] = deepClone([vEArm, vBArm]); let inSector = isClockWise(vBArm, vPoint) && !isClockWise(vEArm, vPoint); if (reverse) inSector = !inSector; if (reverseBE) inSector = !inSector; return inSector; } function isClockWise(vArm, vPoint) { const [ax, ay] = vArm; const [px, py] = vPoint; return -ay * px + ax * py > 0; } function checkPointIsNearPolyline(point, polyline2, lineWidth) { const halfLineWidth = lineWidth / 2; const moveUpPolyline = polyline2.map(([x, y]) => [x, y - halfLineWidth]); const moveDownPolyline = polyline2.map(([x, y]) => [x, y + halfLineWidth]); const polygon = [...moveUpPolyline, ...moveDownPolyline.reverse()]; return checkPointIsInPolygon(point, polygon); } function checkPointIsInRect([px, py], x, y, width, height) { if (px < x) return false; if (py < y) return false; if (px > x + width) return false; if (py > y + height) return false; return true; } function getRotatePointPos(rotate = 0, point, origin = [0, 0]) { if (!point) return false; if (rotate % 360 === 0) return point; const [x, y] = point; const [ox, oy] = origin; rotate *= PI / 180; return [ (x - ox) * cos(rotate) - (y - oy) * sin(rotate) + ox, (x - ox) * sin(rotate) + (y - oy) * cos(rotate) + oy ]; } function getScalePointPos(scale = [1, 1], point, origin = [0, 0]) { if (!point) return false; if (scale === 1) return point; const [x, y] = point; const [ox, oy] = origin; const [xs, ys] = scale; const relativePosX = x - ox; const relativePosY = y - oy; return [ relativePosX * xs + ox, relativePosY * ys + oy ]; } function getTranslatePointPos(translate, point) { if (!translate || !point) return false; const [x, y] = point; const [tx, ty] = translate; return [x + tx, y + ty]; } function getCircleRadianPoint(x, y, radius, radian) { return [x + cos(radian) * radius, y + sin(radian) * radius]; } function getRegularPolygonPoints(rx, ry, r, side, minus = PI * -0.5) { const radianGap = PI * 2 / side; const radians = new Array(side).fill("").map((t, i) => i * radianGap + minus); return radians.map((radian) => getCircleRadianPoint(rx, ry, r, radian)); } function drawPolylinePath(ctx, points, beginPath = false, closePath = false) { if (!ctx || points.length < 2) return false; if (beginPath) ctx.beginPath(); points.forEach((point, i) => point && (i === 0 ? ctx.moveTo(...point) : ctx.lineTo(...point))); if (closePath) ctx.closePath(); } function drawBezierCurvePath(ctx, points, moveTo = false, beginPath = false, closePath = false) { if (!ctx || !points) return false; if (beginPath) ctx.beginPath(); if (moveTo) ctx.moveTo(...moveTo); points.forEach((item) => item && ctx.bezierCurveTo(...item[0], ...item[1], ...item[2])); if (closePath) ctx.closePath(); } const { polylineToBezierCurve: polylineToBezierCurve$1, bezierCurveToPolyline } = bezierCurve$1; const circle = { shape: { rx: 0, ry: 0, r: 0 }, validator({ shape }) { const { rx, ry, r } = shape; if (typeof rx !== "number" || typeof ry !== "number" || typeof r !== "number") { console.error("Circle shape configuration is abnormal!"); return false; } return true; }, draw({ ctx }, { shape }) { ctx.beginPath(); const { rx, ry, r } = shape; ctx.arc(rx, ry, r > 0 ? r : 0.01, 0, Math.PI * 2); ctx.fill(); ctx.stroke(); ctx.closePath(); }, hoverCheck(position, { shape }) { const { rx, ry, r } = shape; return checkPointIsInCircle(position, rx, ry, r); }, setGraphCenter(e, { shape, style }) { const { rx, ry } = shape; style.graphCenter = [rx, ry]; }, move({ movementX, movementY }, { shape }) { this.attr("shape", { rx: shape.rx + movementX, ry: shape.ry + movementY }); } }; const ellipse = { shape: { rx: 0, ry: 0, hr: 0, vr: 0 }, validator({ shape }) { const { rx, ry, hr, vr } = shape; if (typeof rx !== "number" || typeof ry !== "number" || typeof hr !== "number" || typeof vr !== "number") { console.error("Ellipse shape configuration is abnormal!"); return false; } return true; }, draw({ ctx }, { shape }) { ctx.beginPath(); let { rx, ry, hr, vr } = shape; ctx.ellipse(rx, ry, hr > 0 ? hr : 0.01, vr > 0 ? vr : 0.01, 0, 0, Math.PI * 2); ctx.fill(); ctx.stroke(); ctx.closePath(); }, hoverCheck(position, { shape }) { const { rx, ry, hr, vr } = shape; const a = Math.max(hr, vr); const b = Math.min(hr, vr); const c = Math.sqrt(a * a - b * b); const leftFocusPoint = [rx - c, ry]; const rightFocusPoint = [rx + c, ry]; const distance = getTwoPointDistance$1(position, leftFocusPoint) + getTwoPointDistance$1(position, rightFocusPoint); return distance <= 2 * a; }, setGraphCenter(e, { shape, style }) { const { rx, ry } = shape; style.graphCenter = [rx, ry]; }, move({ movementX, movementY }, { shape }) { this.attr("shape", { rx: shape.rx + movementX, ry: shape.ry + movementY }); } }; const rect = { shape: { x: 0, y: 0, w: 0, h: 0 }, validator({ shape }) { const { x, y, w, h } = shape; if (typeof x !== "number" || typeof y !== "number" || typeof w !== "number" || typeof h !== "number") { console.error("Rect shape configuration is abnormal!"); return false; } return true; }, draw({ ctx }, { shape }) { ctx.beginPath(); let { x, y, w, h } = shape; ctx.rect(x, y, w, h); ctx.fill(); ctx.stroke(); ctx.closePath(); }, hoverCheck(position, { shape }) { let { x, y, w, h } = shape; return checkPointIsInRect(position, x, y, w, h); }, setGraphCenter(e, { shape, style }) { const { x, y, w, h } = shape; style.graphCenter = [x + w / 2, y + h / 2]; }, move({ movementX, movementY }, { shape }) { this.attr("shape", { x: shape.x + movementX, y: shape.y + movementY }); } }; const ring = { shape: { rx: 0, ry: 0, r: 0 }, validator({ shape }) { const { rx, ry, r } = shape; if (typeof rx !== "number" || typeof ry !== "number" || typeof r !== "number") { console.error("Ring shape configuration is abnormal!"); return false; } return true; }, draw({ ctx }, { shape }) { ctx.beginPath(); const { rx, ry, r } = shape; ctx.arc(rx, ry, r > 0 ? r : 0.01, 0, Math.PI * 2); ctx.stroke(); ctx.closePath(); }, hoverCheck(position, { shape, style }) { const { rx, ry, r } = shape; const { lineWidth } = style; const halfLineWidth = lineWidth / 2; const minDistance = r - halfLineWidth; const maxDistance = r + halfLineWidth; const distance = getTwoPointDistance$1(position, [rx, ry]); return distance >= minDistance && distance <= maxDistance; }, setGraphCenter(e, { shape, style }) { const { rx, ry } = shape; style.graphCenter = [rx, ry]; }, move({ movementX, movementY }, { shape }) { this.attr("shape", { rx: shape.rx + movementX, ry: shape.ry + movementY }); } }; const arc = { shape: { rx: 0, ry: 0, r: 0, startAngle: 0, endAngle: 0, clockWise: true }, validator({ shape }) { const keys = ["rx", "ry", "r", "startAngle", "endAngle"]; if (keys.find((key) => typeof shape[key] !== "number")) { console.error("Arc shape configuration is abnormal!"); return false; } return true; }, draw({ ctx }, { shape }) { ctx.beginPath(); const { rx, ry, r, startAngle, endAngle, clockWise } = shape; ctx.arc(rx, ry, r > 0 ? r : 1e-3, startAngle, endAngle, !clockWise); ctx.stroke(); ctx.closePath(); }, hoverCheck(position, { shape, style }) { const { rx, ry, r, startAngle, endAngle, clockWise } = shape; const { lineWidth } = style; const halfLineWidth = lineWidth / 2; const insideRadius = r - halfLineWidth; const outsideRadius = r + halfLineWidth; return !checkPointIsInSector(position, rx, ry, insideRadius, startAngle, endAngle, clockWise) && checkPointIsInSector(position, rx, ry, outsideRadius, startAngle, endAngle, clockWise); }, setGraphCenter(e, { shape, style }) { const { rx, ry } = shape; style.graphCenter = [rx, ry]; }, move({ movementX, movementY }, { shape }) { this.attr("shape", { rx: shape.rx + movementX, ry: shape.ry + movementY }); } }; const sector = { shape: { rx: 0, ry: 0, r: 0, startAngle: 0, endAngle: 0, clockWise: true }, validator({ shape }) { const keys = ["rx", "ry", "r", "startAngle", "endAngle"]; if (keys.find((key) => typeof shape[key] !== "number")) { console.error("Sector shape configuration is abnormal!"); return false; } return true; }, draw({ ctx }, { shape }) { ctx.beginPath(); const { rx, ry, r, startAngle, endAngle, clockWise } = shape; ctx.arc(rx, ry, r > 0 ? r : 0.01, startAngle, endAngle, !clockWise); ctx.lineTo(rx, ry); ctx.closePath(); ctx.stroke(); ctx.fill(); }, hoverCheck(position, { shape }) { const { rx, ry, r, startAngle, endAngle, clockWise } = shape; return checkPointIsInSector(position, rx, ry, r, startAngle, endAngle, clockWise); }, setGraphCenter(e, { shape, style }) { const { rx, ry } = shape; style.graphCenter = [rx, ry]; }, move({ movementX, movementY }, { shape }) { const { rx, ry } = shape; this.attr("shape", { rx: rx + movementX, ry: ry + movementY }); } }; const regPolygon = { shape: { rx: 0, ry: 0, r: 0, side: 0 }, validator({ shape }) { const { side } = shape; const keys = ["rx", "ry", "r", "side"]; if (keys.find((key) => typeof shape[key] !== "number")) { console.error("RegPolygon shape configuration is abnormal!"); return false; } if (side < 3) { console.error("RegPolygon at least trigon!"); return false; } return true; }, draw({ ctx }, { shape, cache }) { ctx.beginPath(); const { rx, ry, r, side } = shape; if (!cache.points || cache.rx !== rx || cache.ry !== ry || cache.r !== r || cache.side !== side) { const points2 = getRegularPolygonPoints(rx, ry, r, side); Object.assign(cache, { points: points2, rx, ry, r, side }); } const { points } = cache; drawPolylinePath(ctx, points); ctx.closePath(); ctx.stroke(); ctx.fill(); }, hoverCheck(position, { cache }) { let { points } = cache; return checkPointIsInPolygon(position, points); }, setGraphCenter(e, { shape, style }) { const { rx, ry } = shape; style.graphCenter = [rx, ry]; }, move({ movementX, movementY }, { shape, cache }) { const { rx, ry } = shape; cache.rx += movementX; cache.ry += movementY; this.attr("shape", { rx: rx + movementX, ry: ry + movementY }); cache.points = cache.points.map(([x, y]) => [x + movementX, y + movementY]); } }; const polyline = { shape: { points: [], close: false }, validator({ shape }) { const { points } = shape; if (!(points instanceof Array)) { console.error("Polyline points should be an array!"); return false; } return true; }, draw({ ctx }, { shape, style: { lineWidth } }) { ctx.beginPath(); let { points, close } = shape; if (lineWidth === 1) points = eliminateBlur(points); drawPolylinePath(ctx, points); if (close) { ctx.closePath(); ctx.fill(); ctx.stroke(); } else { ctx.stroke(); } }, hoverCheck(position, { shape, style }) { const { points, close } = shape; const { lineWidth } = style; if (close) { return checkPointIsInPolygon(position, points); } else { return checkPointIsNearPolyline(position, points, lineWidth); } }, setGraphCenter(e, { shape, style }) { const { points } = shape; style.graphCenter = points[0]; }, move({ movementX, movementY }, { shape }) { const { points } = shape; const moveAfterPoints = points.map(([x, y]) => [x + movementX, y + movementY]); this.attr("shape", { points: moveAfterPoints }); } }; const smoothline = { shape: { points: [], close: false }, validator({ shape }) { const { points } = shape; if (!(points instanceof Array)) { console.error("Smoothline points should be an array!"); return false; } return true; }, draw({ ctx }, { shape, cache }) { const { points, close } = shape; if (!cache.points || cache.points.toString() !== points.toString()) { const bezierCurve3 = polylineToBezierCurve$1(points, close); const hoverPoints = bezierCurveToPolyline(bezierCurve3); Object.assign(cache, { points: deepClone(point