-
Notifications
You must be signed in to change notification settings - Fork 0
Snap之Path
何波 edited this page Jul 14, 2019
·
3 revisions
[TOC]
let svg = Snap("#svg");
let path = svg.paper.path('M30 75 Q240 30, 300 120').attr({stroke:'black',fill:'none'})
console.info(path.attr('d'))
let d = path.attr('d')
let bound = Snap.path.getBBox(d);
console.dir(bound);
svg.rect(bound.x, bound.y, bound.width,bound.height).attr({stroke:'red',fill:'none'})let svg = Snap("#svg");
let path = svg.paper.path('M30 75 Q240 30, 300 120').attr({stroke:'black',fill:'none'})
let d = path.attr('d')
let total = Snap.path.getTotalLength(d)
let p = Snap.path.getPointAtLength(d, 0)
let circle = svg.circle(p.x, p.y, 5).attr({stroke:'red',fill:'none'})
Snap.animate(0, total, function (val) {
let p = Snap.path.getPointAtLength(d, val)
circle.attr({
cx: p.x,
cy: p.y
});
}, 1000, mina.bounce)Returns the subpath of a given path between given start and end lengths
let svg = new Snap('#svg')
let path = svg.path("M 25,40 Q 150,150 200,150 T 375,40 Z")
.attr({fill: 'none', stroke: "blue", strokeWidth: 2})
let pathStng = path.attr("d")
let subPathStg = Snap.path.getSubpath(pathStng, 100, 350)
console.info(subPathStg)
let subPath = svg.path(subPathStg)
.attr({id: 'subPath', fill: 'none', stroke: "red", strokeWidth: 3})Returns the length of the path in pixels (only works for
pathelements)
let svg = new Snap('#svg')
let path = svg.path("M 25,40 Q 150,150 200,150 T 375,40 Z")
.attr({fill: 'none', stroke: "blue", strokeWidth: 2})
let pathStng = path.attr("d")
let totalLen = Snap.path.getTotalLength(pathStng)
console.info(totalLen)- path (string) path string
- matrix (object) see @Matrix
Transform the path string with the given matrix
path通过变换后,其MoveTo等属性相对来说变化了,但其realPath不会变化,通过map函数,返回经matrix后变化后的新path
let svg = new Snap('#svg')
let path = svg.path("M 25,25 Q 150,190 200,190 T 375,25 Z")
.attr({fill: 'none', stroke: 'blue', strokeWidth: 2})
let pathString = path.attr("d")
let myMatrix = Snap.matrix()
myMatrix.scale(.8, .5)
myMatrix.rotate(20)
myMatrix.translate(100, 50)
let d = Snap.path.map(pathString, myMatrix)
path.attr("d", d)let svg = Snap("#svg");
let path1 = svg.paper.path('M90 140 Q240 30, 300 120').attr({stroke:'green','stroke-width': 1, fill:'none'})
let path2 = svg.paper.path('M30 100 Q 80 30, 100 100 T 200 80').attr({stroke:'blue','stroke-width': 1, fill:'none'})
let d1 = path1.attr('d')
let d2 = path2.attr('d')
// let inters = Snap.path.intersection(path1, path2); 也可以
let inters = Snap.path.intersection(d1, d2);
inters.forEach((v) => {
let circle = svg.circle(v.x, v.y, 10)
})拖动两条曲线,动态获得相交点(还不完善)
let svg = Snap("#svg");
let path1 = svg.paper.path('M90 140 Q240 30, 300 120').attr({stroke:'green','stroke-width': 10, fill:'none', id: 'path1'})
let path2 = svg.paper.path('M30 100 Q 80 30, 100 100 T 200 80').attr({stroke:'blue','stroke-width': 10, fill:'none', id: 'path2'})
let d1 = path1.attr('d')
let d2 = path2.attr('d')
let origTransform
let dd1
let set = new Snap.set()
function onMove(dx, dy) {
this.attr({
transform: origTransform + (origTransform ? "T" : "t") + [dx, dy]
})
// 非常棒,可以把path中的d属性和matrix后转成matrix后的d
let changePath
if (this.attr('id') === 'path1') {
changePath = d1
}
if (this.attr('id') === 'path2') {
changePath = d2
}
let pathTransform = Snap.path.map(changePath, this.matrix)
dd1 = pathTransform.toString()
let dd2 = d1 === changePath ? d2 : d1
let inters = Snap.path.intersection(dd1, dd2);
// 这里用set操作,非常方便
set.forEach((ele) => {
ele.remove()
})
set.clear()
inters.forEach((v) => {
let circle = svg.circle(v.x, v.y, 10)
set.push(circle)
})
}
function onStart () {
origTransform = this.transform().local;
}
function onEnd () {
if (this.attr('id') === 'path1') {
d1 = dd1
}
}
function onEnd2 () {
if (this.attr('id') === 'path2') {
d2 = dd1
}
}
path1.drag(onMove, onStart, onEnd)
path2.drag(onMove, onStart, onEnd2)- bbox1 (string) first bounding box
- bbox2 (string) second bounding box
Returns
trueif two bounding boxes intersect
let svg = new Snap('#svg')
let origTransform
let path1 = svg.path("M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80")
.attr({fill: 'none', stroke: 'blue', strokeWidth: 5})
let path2 = svg.path("M80 150 L 240 110 L 265 90, L 200 90,Z")
.attr({fill: 'none', stroke: 'green', strokeWidth: 5})
let bb1 = path1.getBBox()
let bb2 = path2.getBBox()
let rect1 = svg.paper.rect(bb1.x, bb1.y, bb1.width, bb1.height).attr({fill: 'none', stroke: 'blue', strokeWidth: 1, strokeDasharray: '8,8'})
let rect2 = svg.paper.rect(bb2.x, bb2.y, bb2.width, bb2.height).attr({fill: 'none', stroke: 'green', strokeWidth: 1, strokeDasharray: '8,8'})
let g1 = svg.paper.g(rect1, path1)
let g2 = svg.paper.g(rect2, path2)
function onMove(dx, dy, x, y) {
this.attr({
transform: origTransform + (origTransform ? "T" : "t") + [dx, dy]
})
let pathTransform = Snap.path.map(this.realPath, this.matrix).toString()
bb1 = Snap.path.getBBox(pathTransform)
bb2 = path2.getBBox()
let isBBInterset = Snap.path.isBBoxIntersect(bb1, bb2)
console.info(isBBInterset)
}
function onStart() {
origTransform = this.transform().local;
}
g1.drag(onMove, onStart)- x (number) x of the point
- y (number) y of the point
Returns
trueif given point is inside a given closed path
let svg = new Snap('#svg')
let origTransform
let path = svg.path("M 25,25 Q 150,190 200,190 T 375,25 Z")
.attr({fill: 'none', stroke: 'blue', strokeWidth: 2});
function onMove(dx, dy, x, y) {
this.attr({
transform: origTransform + (origTransform ? "T" : "t") + [dx, dy]
})
// 注意把body的margin,padding设为0
let pntInside = Snap.path.isPointInside(path.attr("d"), x, y)
console.info(pntInside)
}
function onStart () {
origTransform = this.transform().local;
}
svg.circle(200, 100, 4).attr({fill: 'red'}).drag(onMove, onStart)- bbox (string) bounding box
- x (string) x coordinate of the point
- y (string) y coordinate of the point
Returns
trueif given point is inside bounding box
let svg = new Snap('#svg')
let origTransform
let path = svg.path("M 25,25 Q 150,190 200,190 T 375,25 Z")
.attr({fill: 'none', stroke: 'blue', strokeWidth: 2});
let bb = path.getBBox()
svg.paper.rect(bb.x,bb.y,bb.width, bb.height).attr({
fill: 'none',
'stroke': 'green',
strokeDasharray: '8,8'
})
function onMove(dx, dy, x, y) {
this.attr({
transform: origTransform + (origTransform ? "T" : "t") + [dx, dy]
})
let pntInsideBB = Snap.path.isPointInsideBBox(bb, x, y)
console.info(pntInsideBB)
}
function onStart() {
origTransform = this.transform().local;
}
svg.circle(200, 100, 4).attr({fill: 'red'}).drag(onMove, onStart)http://svgdiscovery.com/Snap.svg/08-snap-path-methods.htm
http://svgdiscovery.com/Snap.svg/Snap.svg-API/Snap.svg-API-Examples.htm
- p1x 数值。曲线第1个点的x位置。
- p1y 数值。曲线第1个点的y位置。
- c1x 数值。曲线第1个锚的x位置。
- c1y 数值。曲线第1个锚的y位置。
- c2x 数值。曲线第2个锚的x位置。
- c2y 数值。曲线第2个锚的y位置。
- p2x 数值。曲线第2个点的x位置。
- p2y 数值。曲线第2个点的y位置。
或者
- bez 数组。包含6个点的贝塞尔曲线数组。
返回:
{
x:数值。盒子左上点的x坐标。
y:数值。盒子左上点的y坐标。
x2:数值。盒子右下点的x坐标。
y2:数值。盒子右下点的y坐标。
width:数值。盒子的宽度。
height:数值。盒子的高度。
}返回一个给定的三次贝塞尔曲线的边界框
let svg = new Snap('#svg')
let path = svg.path("M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80").attr({
fill: 'none',
stroke: 'blue',
strokeWidth: 3
});
let pathStng = path.attr("d")
let pathSegments = Snap.parsePathString(pathStng)
/* pathSegments
[
[M,10,80]
[C,40,10,65,10,95,80]
[S,150,150,180,80]
]
--------------------------
[
[M,p1x,p1y]
[C,c1x,c1y,c2x,c2y,p2x,p2y]
[S,150,150,180,80]
]
*/
let p1x = pathSegments[0][1]
let p1y = pathSegments[0][2]
let c1x = pathSegments[1][1]
let c1y = pathSegments[1][2]
let c2x = pathSegments[1][3]
let c2y = pathSegments[1][4]
let p2x = pathSegments[1][5]
let p2y = pathSegments[1][6]
let bb = Snap.path.bezierBBox(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y)
let rect = svg.rect(bb.x, bb.y, bb.w, bb.h)
.attr({fill: 'none', stroke: "black", strokeWidth: 1})function screenPath(pathSnap) {
let path = pathSnap.node
let sCTM = path.getCTM()
let svgRoot = path.ownerSVGElement
let pathStng = pathSnap.attr("d")
let segList = Snap.parsePathString(pathStng)
let segs = segList.length
//---change segObj values
for (let k = 0; k < segs; k++) {
let segObj = segList[k]
let sol = segObj.length
let cmd = segObj[0]
if (cmd != "A" && cmd != "a") {
for (let n = 1; n < sol; n++) {
let mySVGPoint = svgRoot.createSVGPoint();
mySVGPoint.x = segObj[n]
mySVGPoint.y = segObj[n + 1]
mySVGPointTrans = mySVGPoint.matrixTransform(sCTM)
segObj[n] = mySVGPointTrans.x
segObj[n + 1] = mySVGPointTrans.y
n++
}
}
}
pathSnap.attr({d: segList.toString()})
path.removeAttribute("transform")
}
let svg = Snap("#svg");
// let path1 = svg.path("M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80").attr({id: 'path1', fill: 'none', stroke: 'green', strokeWidth: 2, transform: ("t(100,60) s(2,1)")});
// screenPath(path1) // 可以把上面transform后转成下面的path
let path1 = svg.path("M25,140C85,70,135,70,195,140S305,210,365,140").attr({
id: 'path1',
fill: 'none',
stroke: 'green',
strokeWidth: 2
})
let pathStng = path1.attr("d")
let pathSegments = Snap.parsePathString(pathStng)
console.info(pathSegments)
/* pathSegments
[
["M", 25, 140]
["C", 85, 70, 135, 70, 195, 140]
["S", 305, 210, 365, 140]
]
--------------------------
[
[M,p1x,p1y]
[C,c1x,c1y,c2x,c2y,p2x,p2y]
[S,305, 210, 365, 140]
]
*/
let p1x = pathSegments[0][1]
let p1y = pathSegments[0][2]
let c1x = pathSegments[1][1]
let c1y = pathSegments[1][2]
let c2x = pathSegments[1][3]
let c2y = pathSegments[1][4]
let p2x = pathSegments[1][5]
let p2y = pathSegments[1][6]
let dots = Snap.path.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, 0)
svg.circle(dots.x, dots.y, 4).attr({fill: 'black'})
console.info(dots)
dots = Snap.path.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, .2)
svg.circle(dots.x, dots.y, 4).attr({fill: 'orange'})
dots = Snap.path.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, .4)
svg.circle(dots.x, dots.y, 4).attr({fill: 'violet'})
dots = Snap.path.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, .5)
svg.circle(dots.x, dots.y, 4).attr({fill: 'red'})
dots = Snap.path.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, .6)
svg.circle(dots.x, dots.y, 4).attr({fill: 'lime'})
dots = Snap.path.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, .8)
svg.circle(dots.x, dots.y, 4).attr({fill: 'aqua'})
dots = Snap.path.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, 1)
svg.circle(dots.x, dots.y, 4).attr({fill: 'white'})
Snap.animate(0, 1, function (val) {
dots = Snap.path.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y,val)
anCircle.attr({
cx: dots.x,
cy: dots.y
})
}, 1000)Converts path coordinates into absolute values
let svg = new Snap('#svg')
let dRel = "M25,140c60,-70,110,-70,170,0s110,70,170,0"
let relPath = svg.path(dRel).attr({strokeWidth: 3, stroke: 'black', strokeDasharray: "8,8", fill: 'none'})
let dAbs = Snap.path.toAbsolute(dRel)
console.info(dAbs.toString()) // 大写
let absPath = svg.path(dAbs).attr({strokeWidth: 2, stroke: 'red', fill: 'none'})Converts path coordinates into relative values
let svg = new Snap('#svg')
let dAbs = 'M25,140 C 85,70 135,70 195,140 S 305,210 365,140'
let absPath = svg.path(dAbs).attr({strokeWidth: 3, stroke: 'black', strokeDasharray: "8,8", fill: 'none'})
let dRel = Snap.path.toRelative(dAbs)
console.info(dRel.toString()) // 小写
let relPath = svg.path(dRel).attr({strokeWidth: 2, stroke: 'red', fill: 'none'})转换一个路径为一个全部路径段采用三次贝塞尔曲线表示的新路径
let svg = new Snap('#svg')
let path = svg.path("M 25,25 Q 150,190 200,190 T 375,25 Z")
.attr({fill: 'none', stroke: 'blue', strokeWidth: 4, strokeDasharray: '8,8'})
let pathString = path.attr("d")
let pathStringCubic = Snap.path.toCubic(pathString)
console.info(pathStringCubic.toString())
let cubicPath = svg.path(pathStringCubic).attr({strokeWidth: 2, stroke: 'red', fill: 'none'})