UNPKG

svg-action

Version:

控制SVG拖动,缩放,旋转,转图片等

401 lines (400 loc) 12.5 kB
a.defaultOption = { // 鼠标超过多少才移动 threshold: 15, // 每次放大比例 deltaThreshold: 0.1, // 可缩放倍数 range: { min: 0.4, max: 100 }, // 每次缩放比例 scale: 0.25, // ctrl | shift + 鼠标滚轮每次移动的像素 stepSize: 75, // 键盘或调用移动方法时默认步长 keyStepSize: 10, // 滚轮缩放 mouseScale: !0, // 平移 mouseMove: !0, // 拖动 mouseDrag: !0, // 旋转 mouseRotate: !0, // 翻转 mouseFlip: !0 }; let y; function a(e, o) { let t = this; if (!e) throw new Error("初始化失败,找不到SVG!"); t._svg = e, t.options = { ...a.defaultOption, ...o }, t.options.mouseControl = t.getControlElement(), t.options.keyControl = t.getKeyElement(), t._totalDelta = 0, t._previouScale = 1, t._deg = 0, t._init(); } a.prototype._init = function() { this._initSvg(), B(), this.buildEvent(); }; a.prototype.buildEvent = function() { this.eventState || (this.eventState = !0, T.call(this), D.call(this), K.call(this)); }; function E(e) { let o = e || window.event; o.preventDefault && o.preventDefault(), o.stopPropagation ? o.stopPropagation() : window.event.cancelBubble = !0; } function k(e, o, t) { var n = e.createSVGPoint(); return n.x = o, n.y = t, n.matrixTransform(e.getScreenCTM().inverse()); } function T() { let e = this, o = e.options, t = {}, n = o.mouseControl; n.addEventListener("mousedown", r, !1), n.addEventListener("touchstart", i, { passive: !1 }); function r(l) { t.start = v(l), e._svg.className.baseVal = "move-cursor-grabbing", document.addEventListener("mousemove", s, !1), document.addEventListener("mouseup", p, !1); } function i(l) { if (E(l), t.start = v(l), document.addEventListener("touchmove", s, { passive: !1 }), document.addEventListener("touchend", p, { passive: !1 }), l.touches.length >= 2) { let h = v(l.touches[0]), c = v(l.touches[1]), d = z(h.x, h.y, c.x, c.y); d = k(e._svg, d.x, d.y), t.doubleStart = { fast: h, last: c, cente: d, length: b(h.x, h.y, c.x, c.y) }; } } function s(l) { if (E(l), l.type == "touchmove" && l.touches.length >= 2) { let c = v(l.touches[0]), d = v(l.touches[1]), m = t.doubleStart; m.cente; let _ = b(c.x, c.y, d.x, d.y); _ > m.length ? e._zoom(1, m.cente, 0.025) : e._zoom(-1, m.cente, 0.025), m.length = _; return; } t.position = v(l), t.delta = M(t.position, t.start); let h = !1; !t.dragging && R(t.delta) > o.threshold && (t.dragging = !0, h = !0), t.dragging && (o.mouseRotate && l.ctrlKey ? f(l, h) : o.mouseFlip && l.shiftKey ? g(l, h) : o.mouseDrag && u(), t.last = t.position); } function u(l) { let h = t.last || t.start, c = M(t.position, h); e.move({ dx: c.x, dy: c.y }); } function f(l, h) { let c = S(); h && (document.body.appendChild(c), c.show = !0); let d = t.last || t.start, m = M(t.position, d), L = (m.x || m.y) < 0 ? -1 : 1; e.rotate(L), c.style.top = l.clientY + "px", c.style.left = l.clientX + 20 + "px", c.innerText = e._deg + "°"; } function g(l, h) { h && (t.delta.x >= o.threshold ? e.flipX() : t.delta.x < o.threshold && e.flipY()); } function p(l) { e._svg.className.baseVal = "move-cursor-grab", t = {}, document.removeEventListener("mousemove", s), document.removeEventListener("mouseup", p), document.removeEventListener("touchmove", s), document.removeEventListener("touchend", p), S().remove(); } e._eventFn = { handleMousedown: r, handleTouchstart: i, handleMouseMove: s, handleEnd: p }; } function b(e, o, t, n) { return Math.hypot(t - e, n - o); } function z(e, o, t, n) { let r = (e - t) / 2, i = (o - n) / 2; return { x: e + (0 - r), y: o + (0 - i) }; } function S() { return y || (y = document.createElement("span"), y.style.position = "fixed", y.style.userSelect = "none", y); } function D() { let e = this, o = e.options.mouseControl; o.addEventListener("mousewheel", t, !1); function t(i) { E(i), e.options.mouseMove && (i.ctrlKey || i.shiftKey) ? n(i) : e.options.mouseScale && r(i); } e._eventFn.handleMousewheel = t; function n(i) { let s = e.options.stepSize / 100, u; i.shiftKey ? u = { // 水平 dx: s * i.deltaY, dy: 0 } : u = { dx: s * i.deltaX, dy: s * i.deltaY }, e.move(u); } function r(i) { var s = o.getBoundingClientRect(), u = { x: i.clientX - s.left, y: i.clientY - s.top }; e.zoom(i.wheelDelta < 0 ? "out" : "in", u); } } function K() { let e = this; e.options.keyControl.addEventListener("keydown", o); function o(i) { let s = P(i); s && (i.ctrlKey ? n(s) : i.shiftKey ? r(s) : s == "center" ? e.reset() : t(s)); } e._eventFn.handleKeydown = o; function t(i) { e[i](); } function n(i) { switch (i) { case "up": e.zoomIn(); break; case "left": e.rotate(); break; case "down": e.zoomOut(); break; case "right": e.rotate(-45); break; } } function r(i) { switch (i) { case "up": case "down": e.flipY(); break; case "left": case "right": e.flipX(); break; } } } function P(e) { switch (e.key) { case "w": case "ArrowUp": return "up"; case "s": case "ArrowDown": return "down"; case "a": case "ArrowLeft": return "left"; case "d": case "ArrowRight": return "right"; case "0": case "`": return "center"; default: return null; } } a.prototype._initSvg = function() { let e = this._svg; if (e.className.baseVal = "move-cursor-grab", e.tagName === "g") { let o = function(t) { return t.parentElement.tagName == "svg" ? t.parentElement : o(t.parentElement); }; this._viewport = e, this._svg = o(this._viewport) || this._viewport; } if (e.childNodes.length === 1 && e.firstElementChild.tagName === "g") this._viewport = e.firstElementChild; else { let o = document.createElementNS(e.namespaceURI, "g"), t = e.childNodes; for (; t.length !== 0; ) o.appendChild(t[0]); e.appendChild(o), this._viewport = o; } }; a.prototype.zoomIn = function(e) { e = e || this.options.scale, this._zoom(1, C.call(this), e); }; a.prototype.zoomOut = function(e) { e = e || this.options.scale, this._zoom(-1, C.call(this), e); }; a.prototype.reset = function() { this.zoom("center"); }; a.prototype.zoom = function(e, o) { let t = this; if (!e) return x(t._viewport.getCTM().a, 1e3); var n = t.options.scale; if (e === "center") return t._fitViewport(e); if (e === "in") e = 1; else if (e === "out") e = -1; else if (typeof e == "number") n = Math.abs(e); else return x(t._viewport.getCTM().a, 1e3); if (t._totalDelta += e, Math.abs(t._totalDelta) > t.options.deltaThreshold) { let r = t._zoom(e, o, n); return t._totalDelta = 0, r; } }; a.prototype._zoom = function(e, o, t) { let n = this; var r = e > 0 ? 1 : -1, i = N(n._previouScale), s = Math.round(i / t) * t; s += t * r; var u = Math.pow(10, s); return A.call(n, V(n.options.range, u), o), this._previouScale = x(n._viewport.getCTM().a, 1e3), this._previouScale; }; function A(e, o) { var t = this._svg, n = this._viewport, r = t.createSVGMatrix(), i = t.createSVGPoint(), s, u, f, g, p; f = n.getCTM(); var l = f.a; return o ? (i.x = o.x, i.y = o.y, s = i, u = s.matrixTransform(f.inverse()), g = r.translate(u.x, u.y).scale(1 / l * e).translate(-u.x, -u.y), p = f.multiply(g)) : p = r.scale(e), w(this._viewport, { matrix: p }), p; } a.prototype._fitViewport = function(e) { let o = this, t = { height: o._svg.clientHeight, width: o._svg.clientWidth }, n = o._viewport.getBBox(), r, i; if (n.x >= 0 && n.y >= 0 && n.x + n.width <= t.width && n.y + n.height <= t.height && !e) i = { x: 0, y: 0, width: Math.max(n.width + n.x, t.width), height: Math.max(n.height + n.y, t.height) }; else { r = Math.min(1, t.width / n.width, t.height / n.height); let u = -n.x * r, f = -n.y * r, g = t.width / 2 - n.width * r / 2, p = t.height / 2 - n.height * r / 2; i = { x: g >= 0 ? g + u : u, y: p >= 0 ? p + f : f }; } let s = o._svg.createSVGMatrix().translate(i.x, i.y).scale(r); return w(o._viewport, { matrix: s }), o._deg = 0, o._previouScale = x(o._viewport.getCTM().a, 1e3); }; a.prototype.move = function(e) { let o = this._viewport; var t = o.getCTM(); return e && (e.dx = e.dx || e.x || 0, e.dy = e.dy || e.y || 0, e = Object.assign({ dx: 0, dy: 0 }, e), t = this._svg.createSVGMatrix().translate(e.dx, e.dy).multiply(t), w(o, { matrix: t })), { x: t.e, y: t.f }; }; a.prototype.up = function(e) { return e = e || this.options.keyStepSize, this.move({ dy: -e }); }; a.prototype.down = function(e) { return e = e || this.options.keyStepSize, this.move({ dy: e }); }; a.prototype.left = function(e) { return e = e || this.options.keyStepSize, this.move({ dx: -e }); }; a.prototype.right = function(e) { return e = e || this.options.keyStepSize, this.move({ dx: e }); }; a.prototype.rotate = function(e = 45) { let o = this._viewport.getBBox(); w(this._viewport, { rotate: { angle: e, x: o.width / 2 + o.x, y: o.height / 2 + o.y } }), this._deg += e; }; a.prototype.flipX = function() { let e = this._viewport.getCTM(); w(this._viewport, { matrix: e.flipX() }); }; a.prototype.flipY = function() { let e = this._viewport.getCTM(); w(this._viewport, { matrix: e.flipY() }); }; a.prototype.getControlElement = function() { return this.options.mouseControl || this._svg.parentElement || document; }; a.prototype.getKeyElement = function() { return this.options.keyControl || document; }; a.prototype.toImage = function() { let e = this, o = new Image(), t = e._svg.getBoundingClientRect(); return o.width = t.width, o.height = t.height, o.src = "data:image/svg+xml;utf8," + unescape(e._svg.outerHTML), new Promise((n) => { o.onload = function() { let r = document.createElement("canvas"); r.width = t.width, r.height = t.height, r.getContext("2d").drawImage(o, 0, 0, t.width, t.height), n(r.toDataURL("image/png")); }; }); }; a.prototype.save = function() { this.toImage().then((e) => { var o = document.createElement("a"); o.href = e, o.download = "svg.png", o.click(); }); }; a.prototype.disableEvent = function() { let e = this, o = e.options, t = e._eventFn, n = o.mouseControl; e.eventState = !1, n.removeEventListener("mousedown", t.handleMousedown), n.removeEventListener("touchstart", t.handleTouchstart), document.removeEventListener("mousemove", t.handleMouseMove), document.removeEventListener("mouseup", t.handleEnd), document.removeEventListener("touchmove", t.handleMouseMove), document.removeEventListener("touchend", t.handleEnd), n.removeEventListener("mousewheel", t.handleMousewheel), o.keyControl.removeEventListener("keydown", t.handleKeydown); }; function C() { let e = this._viewport.getBoundingClientRect(), o = this._viewport.getCTM(); return { x: o.e + e.width / 2, y: o.f + e.height / 2 }; } function w(e, { matrix: o, rotate: t }) { o = o || e.getCTM(); var n = `matrix(${o.a}, ${o.b}, ${o.c}, ${o.d}, ${o.e}, ${o.f})`; t && (n += `, rotate(${t.angle}, ${t.x}, ${t.y})`), e.setAttribute("transform", n); } function V(e, o) { return Math.max(e.min, Math.min(e.max, o)); } function x(e, o) { return Math.round(e * o) / o; } function N(e) { return Math.log(e) / Math.log(10); } function M(e, o) { return { x: e.x - o.x, y: e.y - o.y }; } function v(e) { return e.pointers && e.pointers.length && (e = e.pointers[0]), e.touches && e.touches.length && (e = e.touches[0]), e ? { x: e.clientX, y: e.clientY } : null; } function R(e) { return Math.sqrt(Math.pow(e.x, 2) + Math.pow(e.y, 2)); } function B() { if (document.getElementById("SvgAction")) return; let o = ` .move-cursor-grab{ cursor: grab; cursor: -webkit-grab; } .move-cursor-grabbing{ cursor: grabbing; cursor: -webkit-grabbing; } `, t = document.createElement("style"); t.id = "SvgAction", t.innerText = o, document.head.appendChild(t); } window.SvgAction = a; export { a as default };