svg-action
Version:
控制SVG拖动,缩放,旋转,转图片等
401 lines (400 loc) • 12.5 kB
JavaScript
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
};