簡體   English   中英

如何從SVG路徑的交叉點找到新路徑(形狀)?

[英]How to find a new path (shape) from intersection of SVG paths?

我需要相交 2 條 SVG 路徑並獲得與它們相交的路徑。

它應該在瀏覽器或 Node.js 中工作(它們中的任何一個,而不是兩者)。
我需要交集, clip-path使用不行。
如果由於某種原因,intersection 將使用transform就可以了(我會自己刪除它)。

我認為有一個圖書館,但我發現只有


例如交叉以下路徑:

M 24.379464,51.504463 23.434524,23.156249 38.742559,12.572916 c 0,0 29.860118,-9.0714281 17.00893,0.755953 -12.851191,9.82738 13.229166,19.465774 13.229166,19.465774 z
m 32.883928,0.28869028 c 0,0 -15.686011,1.51190452 -8.504463,7.18154712 7.181546,5.6696426 50.270836,30.0491076 26.458332,42.3333336 -23.8125,12.284226 47.058036,14.174107 47.058036,14.174107 z

我想得到類似的東西:

M 43.943359 11.123047 C 40.995759 11.900151 38.742188 12.572266 38.742188 12.572266 L 35.236328 14.996094 C 44.091432999999995 21.21816 55.052161 29.822765 57.455078 37.628906 L 66.939453 33.650391 63.632812 30.410156 C 58.77426 27.95814 52.364322 23.85552 52.214844 19.224609 L 43.943359 11.123047 z

這是示例中帶有path的交互式片段(忽略顏色 - 它們是為了清晰起見) - 需要從#path1#path2獲取Intersection

 svg { width: 10em; width: 100vmin; outline: 1px dotted blue; display: none; } input { display: none; } label { width: 10em; float: left; clear: left; cursor: pointer; line-height: 2em; margin: 0 .5em .25em 0; padding: 0 .25em; border: 1px solid; } :checked + * + * + label { background: antiquewhite; color: blue; } :checked + * + * + * + * + * + svg { display: inline-block; }
 <input type=radio name=svg id=in checked> <input type=radio name=svg id=out> <input type=radio name=svg id=cp> <label for=in>Input</label> <label for=out>Intersection</label> <label for=cp>Clip</label> <svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="22 0 76 64"> <path id="path1" style="fill:rgba(255,0,0,.5); stroke:red;stroke-width:0.26458332px;" d="M 24.379464,51.504463 23.434524,23.156249 38.742559,12.572916 c 0,0 29.860118,-9.0714281 17.00893,0.755953 -12.851191,9.82738 13.229166,19.465774 13.229166,19.465774 z" /> <path id="path2" style="fill:rgba(0,255,0,.5);stroke:green;stroke-width:0.26458332px;" d="m 32.883928,0.28869028 c 0,0 -15.686011,1.51190452 -8.504463,7.18154712 7.181546,5.6696426 50.270836,30.0491076 26.458332,42.3333336 -23.8125,12.284226 47.058036,14.174107 47.058036,14.174107 z" /> </svg> <svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" viewBox="22 0 76 64"> <path style="fill:rgba(0,0,255,.5);stroke:blue;stroke-width:0.26458332px;" d="M 43.943359 11.123047 C 40.995759 11.900151 38.742188 12.572266 38.742188 12.572266 L 35.236328 14.996094 C 44.091432999999995 21.21816 55.052161 29.822765 57.455078 37.628906 L 66.939453 33.650391 63.632812 30.410156 C 58.77426 27.95814 52.364322 23.85552 52.214844 19.224609 L 43.943359 11.123047 z" /> </svg> <svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="22 0 76 64"> <clipPath id="clip2"> <use xlink:href="#path2" /> </clipPath> <use xlink:href="#path1" clip-path="url(#clip2)" /> </svg>

Snap.svg 示例:

 var p1 = "M 24.379464,51.504463 23.434524,23.156249 38.742559,12.572916 c 0,0 29.860118,-9.0714281 17.00893,0.755953 -12.851191,9.82738 13.229166,19.465774 13.229166,19.465774 z" var p2 = "m 32.883928,0.28869028 c 0,0 -15.686011,1.51190452 -8.504463,7.18154712 7.181546,5.6696426 50.270836,30.0491076 26.458332,42.3333336 -23.8125,12.284226 47.058036,14.174107 47.058036,14.174107 z" var intersection = Snap.path.intersection(p1, p2) console.log(intersection)
 .as-console-wrapper.as-console-wrapper { max-height: 100vh }
 <script src=//cdnjs.cloudflare.com/ajax/libs/snap.svg/0.5.1/snap.svg-min.js></script>

PS:同樣的問題俄語。

我們可以使用 PaperJS 布爾操作來實現,它可以使用 SVG 路徑進行操作。

PaperJS 有 5 種不同的布爾運算: excludesubtractuniteintersectdivide ,我們將使用它們中的一個,名稱為intersect 此操作也是具有相同名稱的函數,它們返回具有函數exportSVG() item對象。 它返回真正的SVG Path element ,它具有兩條路徑交集的新形狀。

正確解法示例

 paper.install(window); window.onload = function() { paper.setup('canvas'); var p1 = 'M 24.379464,51.504463 23.434524,23.156249 38.742559,12.572916 c 0,0 29.860118,-9.0714281 17.00893,0.755953 -12.851191,9.82738 13.229166,19.465774 13.229166,19.465774 z', p2 = 'm 32.883928,0.28869028 c 0,0 -15.686011,1.51190452 -8.504463,7.18154712 7.181546,5.6696426 50.270836,30.0491076 26.458332,42.3333336 -23.8125,12.284226 47.058036,14.174107 47.058036,14.174107 z', path1 = new Path(p1), path2 = new Path(p2); path1.fillColor = 'rgba(255,0,0,.5)'; path1.position = new Point(25, 25); path2.fillColor = 'rgba(0,255,0,.5)'; path2.position = new Point(40, 25); var result = path2.intersect(path1); result.selected = true; result.fillColor = '#77f'; //exportSVG() docu: http://paperjs.org/reference/item/#exportsvg var svgPathElement = result.exportSVG(), dPath = svgPathElement.getAttribute('d'); document.querySelector('path').setAttribute('d', dPath); var output = document.querySelector('#output'); output.innerHTML = '<pre>' + dPath + '</pre>'; output.innerHTML += '<xmp>' + svgPathElement.outerHTML + '</xmp>'; };
 table { margin-left:14px; padding-left:14px; border-left:1px solid gray; display:inline-block }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/paper.js/0.12.0/paper-full.min.js"></script> <canvas id="canvas" width="75" height="75" resize></canvas> <table><tr><td><b>Our new shape of both paths intersection in separate SVG:</b></td></tr> <tr><td> <svg width="75" height="75" viewBox="0 0 75 75"> <path fill="rgba(0,0,255,.5)" d=""/> </svg> </td></tr></table> <div id="output"></div>

有用的鏈接:

Snap.svg 似乎具有執行此操作所需的基本功能。 他們中的一些人有點尷尬,但這可能是前進的方向。 請將此視為偽代碼,而不是按原樣工作:

// returns something like [ [ "M", 1, 2 ], ["C", 3, 4, 5, 6, 7, 8 ], ... ]
// and has a custom .toString() method
segList1 = Snap.path.toCubic(p1)
segList2 = Snap.path.toCubic(p2)

intersections = Snap.path.intersection(p1, p2)

// handle the subpaths between neighbouring intersections
intersectionPaths = intersections.map((point, id) => {
    from = point
    to = intersections[id + 1 < intersections.length ? id + 1 : 0]
    return pathBetweenIntersections(from, to)
})

// return the two paths between two neighbouring intersection points
function pathBetweenIntersections (from, to) {
    // list the segments between the intersection points on first path
    // TODO: handle cases when from.segment1 >= to.segment1
    subSegList1 = segList1.slice(from.segment1 + 1, to.segment1)

    // first segment has the intersection point
    startSegments = [ from.bez1.slice(0, 2).unshift('M'), from.bez1.slice(2, 8).unshift('C') ]
    startString1 = Snap.path.toCubic(startSegments).toString()
    // construct a path element from the segment
    startPath1 = Paper.path(startString1)
    startPathLength1 = startPath1.getTotalLength()
    // get the relevant subpath from intersection point to end
    startPathString1 = startPath1.getSubpath(from.t1 * startPathLength1, startPathLength1)
    subSegList1 = Snap.path.toCubic(startPathString1).concat(subSegList1)

    // and the same for the last segment
    endSegments = [ to.bez1.slice(0, 2).unshift('M'), to.bez1.slice(2, 8).unshift('C') ]
    endString1 = Snap.path.toCubic(endSegments).toString()
    endPath1 = Paper.path(endString1)
    endPathLength1 = endPath1.getTotalLength()
    endPathString1 = endPath1.getSubpath(0, to.t1 * endPathString1)
    subSegList1.push(Snap.path.toCubic(endPathString1)[1])

    subSegList2 = // do the same for segList2

    return {
        p1: Snap.path.toCubic(subSegList1).toString(),
        p2: Snap.path.toCubic(subSegList2).toString()
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM