Skip to content

Instantly share code, notes, and snippets.

@6174
Last active October 19, 2018 08:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save 6174/b9ca2869b2c47d934b67 to your computer and use it in GitHub Desktop.
Save 6174/b9ca2869b2c47d934b67 to your computer and use it in GitHub Desktop.
learn Snapsvg
Snap.plugin(function(Snap, Element, Paper, global, Fragment) {
// Snap.newmethod = function () {};
// Paper.prototype.newmethod = function () {};
/**
* connection
*/
Paper.prototype.connection = function(obj1, obj2, line, bg) {
if (obj1.line && obj1.from && obj1.to) {
line = obj1;
obj1 = line.from;
obj2 = line.to;
}
var bb1 = obj1.getBBox(),
bb2 = obj2.getBBox(),
p = [{
x: bb1.x + bb1.width / 2,
y: bb1.y - 1
}, {
x: bb1.x + bb1.width / 2,
y: bb1.y + bb1.height + 1
}, {
x: bb1.x - 1,
y: bb1.y + bb1.height / 2
}, {
x: bb1.x + bb1.width + 1,
y: bb1.y + bb1.height / 2
}, {
x: bb2.x + bb2.width / 2,
y: bb2.y - 1
}, {
x: bb2.x + bb2.width / 2,
y: bb2.y + bb2.height + 1
}, {
x: bb2.x - 1,
y: bb2.y + bb2.height / 2
}, {
x: bb2.x + bb2.width + 1,
y: bb2.y + bb2.height / 2
}],
d = {},
dis = [];
for (var i = 0; i < 4; i++) {
for (var j = 4; j < 8; j++) {
var dx = Math.abs(p[i].x - p[j].x),
dy = Math.abs(p[i].y - p[j].y);
if ((i == j - 4) || (((i != 3 && j != 6) || p[i].x < p[j].x) && ((i != 2 && j != 7) || p[i].x > p[j].x) && ((i != 0 && j != 5) || p[i].y > p[j].y) && ((i != 1 && j != 4) || p[i].y < p[j].y))) {
dis.push(dx + dy);
d[dis[dis.length - 1]] = [i, j];
}
}
}
if (dis.length == 0) {
var res = [0, 4];
} else {
res = d[Math.min.apply(Math, dis)];
}
var x1 = p[res[0]].x,
y1 = p[res[0]].y,
x4 = p[res[1]].x,
y4 = p[res[1]].y;
dx = Math.max(Math.abs(x1 - x4) / 2, 10);
dy = Math.max(Math.abs(y1 - y4) / 2, 10);
var x2 = [x1, x1, x1 - dx, x1 + dx][res[0]].toFixed(3),
y2 = [y1 - dy, y1 + dy, y1, y1][res[0]].toFixed(3),
x3 = [0, 0, 0, 0, x4, x4, x4 - dx, x4 + dx][res[1]].toFixed(3),
y3 = [0, 0, 0, 0, y1 + dy, y1 - dy, y4, y4][res[1]].toFixed(3);
var path = ["M" + x1.toFixed(3), y1.toFixed(3) + "C" + x2, y2, x3, y3, x4.toFixed(3), y4.toFixed(3)].join(",");
if (line && line.line) {
line.bg && line.bg.attr({
path: path
});
line.line.attr({
path: path
});
} else {
var color = typeof line == "string" ? line : "#000";
return {
bg: bg && bg.split && this.path(path).attr({
stroke: bg.split("|")[0],
fill: "none",
"stroke-width": bg.split("|")[1] || 3
}),
line: this.path(path).attr({
stroke: color,
fill: "none"
}),
from: obj1,
to: obj2
};
}
};
});
Snap.plugin(function(Snap, Element, Paper, global) {
Element.prototype.getCenter = function() {
var bbox = this.getBBox();
return [bbox.cx, bbox.cy]
};
});
/**
* snap drag-drop example
*/
var s = Snap("#svg");
var circles = [
s.circle(150, 400, 30),
s.circle(600, 150, 30)
];
circles.forEach(function(circle) {
circle.attr({
fill: "#bada55",
stroke: "#000",
strokeWidth: 5
});
circle.drag(onDragMove, onDragStart, onDragEnd);
});
connection = s.connection(circles[0], circles[1], "#fff", "#000|5");
/**
* onmove
*/
function onDragMove(dx, dy, ex, ey, ev) {
var attr = this.type == "rect" ? {
x: this.ox + dx,
y: this.oy + dy
} : {
cx: this.ox + dx,
cy: this.oy + dy
};
this.attr(attr);
s.connection(connection);
}
/**
* ondrag
*/
function onDragStart(ex, ey, ev) {
this.ox = Number(this.type == "rect" ? this.attr("x") : this.attr("cx"));
this.oy = Number(this.type == "rect" ? this.attr("y") : this.attr("cy"));
this.animate({
"fill-opacity": .2
}, 500);
}
/**
* onend
*/
function onDragEnd(ev) {
this.animate({
"fill-opacity": 1
}, 500);
}
/**
* snap drag-drop example
*/
var s = Snap("#svg");
var bigCircle = s.circle(150, 150, 30);
bigCircle.attr({
fill: "#bada55",
stroke: "#000",
strokeWidth: 5
});
bigCircle.drag(onDragMove, onDragStart, onDragEnd);
/**
* onmove
*/
function onDragMove(dx, dy, ex, ey, ev) {
var attr = this.type == "rect" ? {
x: this.ox + dx,
y: this.oy + dy
} : {
cx: this.ox + dx,
cy: this.oy + dy
};
this.attr(attr);
}
/**
* ondrag
*/
function onDragStart(ex, ey, ev) {
this.ox = Number(this.type == "rect" ? this.attr("x") : this.attr("cx"));
this.oy = Number(this.type == "rect" ? this.attr("y") : this.attr("cy"));
this.animate({
"fill-opacity": .2
}, 500);
}
/**
* onend
*/
function onDragEnd(ev) {
this.animate({
"fill-opacity": 1
}, 500);
}
//http://stackoverflow.com/questions/16359246/how-to-extract-position-rotation-and-scale-from-matrix-svg
function deltaTransformPoint(matrix, point) {
var dx = point.x * matrix.a + point.y * matrix.c + 0;
var dy = point.x * matrix.b + point.y * matrix.d + 0;
return { x: dx, y: dy };
}
function decomposeMatrix(matrix) {
// @see https://gist.github.com/2052247
// calculate delta transform point
var px = deltaTransformPoint(matrix, { x: 0, y: 1 });
var py = deltaTransformPoint(matrix, { x: 1, y: 0 });
// calculate skew
var skewX = ((180 / Math.PI) * Math.atan2(px.y, px.x) - 90);
var skewY = ((180 / Math.PI) * Math.atan2(py.y, py.x));
return {
translateX: matrix.e,
translateY: matrix.f,
scaleX: Math.sqrt(matrix.a * matrix.a + matrix.b * matrix.b),
scaleY: Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d),
skewX: skewX,
skewY: skewY,
rotation: skewX // rotation is the same as skew x
};
}
var s = Snap("#svgout");
var r1 = s.rect(0,0,100,100).attr({ fill: "red", opacity: "0.2", stroke: "black", strokeWidth: "2" });
var g1 = s.group( r1 ).transform("t100,100r10");
var g2 = s.group( g1 ).transform("t100,100r20");
var g3 = s.group( g2 ).transform("t100,100r30");
console.log( r1.transform() );
console.log( decomposeMatrix( r1.transform().globalMatrix ) ) ;
s.text( 100, 20, "rect1 localMatrix: " + r1.transform().localMatrix + "... rotation " + decomposeMatrix( r1.transform().localMatrix ).rotation );
s.text( 100, 40, "rect1 diffMatrix: " + r1.transform().diffMatrix + "... rotation " + decomposeMatrix( r1.transform().diffMatrix ).rotation );
s.text( 100, 60, "rect1 globalTransform: " + r1.transform().globalMatrix + "... rotation " + decomposeMatrix( r1.transform().globalMatrix ).rotation );
s.text( 100, 100, "g1 localMatrix: " + g1.transform().localMatrix + "... rotation " + decomposeMatrix( g1.transform().localMatrix ).rotation ) ;
s.text( 100, 120, "g1 diffMatrix: " + g1.transform().diffMatrix + "... rotation " + decomposeMatrix( g1.transform().diffMatrix ).rotation );
s.text( 100, 140, "g1 globalTransform: " + g1.transform().globalMatrix + "... rotation " + decomposeMatrix( g1.transform().globalMatrix ).rotation );
s.text( 100, 180, "g2 localMatrix: " + g2.transform().localMatrix + "... rotation " + decomposeMatrix( g2.transform().localMatrix ).rotation);
s.text( 100, 200, "g2 diffMatrix: " + g2.transform().diffMatrix + "... rotation " + decomposeMatrix( g2.transform().diffMatrix ).rotation );
s.text( 100, 220, "g2 globalTransform: " + g2.transform().globalMatrix + "... rotation " + decomposeMatrix( g2.transform().globalMatrix ).rotation );
s.text( 100, 260, "g3 localMatrix: " + g3.transform().localMatrix + "... rotation " + decomposeMatrix( g3.transform().localMatrix ).rotation);
s.text( 100, 280, "g3 diffMatrix: " + g3.transform().diffMatrix + "... rotation " + decomposeMatrix( g3.transform().diffMatrix ).rotation );
s.text( 100, 300, "g3 globalTransform: " + g3.transform().globalMatrix + "... rotation " + decomposeMatrix( g3.transform().globalMatrix ).rotation );
/**
* 放大到某一个节点
* @description:
* 1. 先找到节点的中心在svg中的位置
* 2. 计算出在该节点放大z倍的矩阵
* 3. 找出放大过后的视图中心点在svg中的位置
* 4. 计算出视图中心点和节点的向量
* 5. 放大矩阵做translate上次计算出来的向量
*/
zoomToNode: function(node, z) {
node = node || this.root;
z = z || 2;
// compute node position in svg
var $el = node.$el;
var box = $el.getBBox();
var nodeCenterPoint = {
x: box.cx,
y: box.cy
};
// compute the scale matrix
// scale the node at node's center point
var m = Snap.matrix();
m.translate(nodeCenterPoint.x, nodeCenterPoint.y).scale(z).translate(-nodeCenterPoint.x, -nodeCenterPoint.y);
// find centerPoint position in view
var centerPointInView = {
x: $('#svg').width()/2,
y: $('#svg').height()/2
};
// compute current centerPoint position in svg after scale
var s = Share.s;
var $zpd = s.select('#snapsvg-zpd-' + s.id);
var inverseMatrix = $zpd.transform().globalMatrix.add(m).invert();
var centerPointInSvg = {
x: inverseMatrix.x(centerPointInView.x, centerPointInView.y),
y: inverseMatrix.y(centerPointInView.x, centerPointInView.y)
};
// compute the vector form nodeCenterPoint to centerPointInSvg
var v = {
x: centerPointInSvg.x - nodeCenterPoint.x ,
y: centerPointInSvg.y - nodeCenterPoint.y
};
m.translate(v.x, v.y);
// record the matrix for transform back
$zpd.transform($zpd.transform().globalMatrix.add(m));
this._previewsScaleMatrix = m;
},
/**
* snap drag-drop example
*/
var s = Snap("#svg");
var circles = [
s.circle(150, 400, 30),
s.circle(600, 150, 30)
];
circles.forEach(function(circle) {
circle.attr({
fill: "#bada55",
stroke: "#000",
strokeWidth: 5
});
draggable(circle);
});
connection = s.connection(circles[0], circles[1], "#fff", "#000|5");
s.zpd({
drag: false,
pan: false
});
s.panTo(200, 200, null, testTransform);
function testTransform() {
// s.panTo(200, 200);
var g = s.zpd.node;
var $node = circles[1];
console.log($node.transform());
// create a point
var point = getSVGPoint(0, 450, s);
var point2 = getSVGPoint(100, 100, s);
var ctm = g.getCTM();
console.log(ctm);
// 将viewPort的坐标转为
console.log(point2, point2.matrixTransform(ctm.inverse()));
var m = s.node.createSVGMatrix().translate(110, 110);
console.log(m);
};
/**
* draggable plugin
*/
function draggable($node) {
$node.drag(onDragMove, onDragStart, onDragEnd);
/**
* onmove
*/
function onDragMove(dx, dy, ex, ey, ev) {
var snapInvMatrix = this.transform().diffMatrix.invert();
snapInvMatrix.e = snapInvMatrix.f = 0;
var tdx = snapInvMatrix.x(dx, dy);
var tdy = snapInvMatrix.y(dx, dy);
this.transform(this.data('ot') + "t" + [tdx, tdy]);
s.connection(connection);
};
/**
* ondrag
*/
function onDragStart(ex, ey, ev) {
this.data('ot', this.transform().local);
this.animate({
"fill-opacity": .2
}, 500);
};
/**
* onend
*/
function onDragEnd(ev) {
this.animate({
"fill-opacity": 1
}, 500);
}
};
/**
* Instance an SVGPoint object with given event coordinates.
*/
function getSVGPoint(x, y, svgNode) {
var p = svgNode.node.createSVGPoint();
p.x = x;
p.y = y;
return p;
};
/**
* Sets the current transform matrix of an element.
*/
function setCTM(element, matrix, threshold) {
if (threshold && typeof threshold === 'object') { // array [0.5,2]
if (matrix.a <= threshold[0]) {
return;
}
if (matrix.d >= threshold[1]) {
return;
}
}
var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";
element.setAttribute("transform", s);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment