2017-09-13 166 views
1

這是Humongous height value for <filter> not preventing cutoff的延續:我仍然試圖在<path>上應用<filter>,但是我遇到了被裁剪的問題。SVG濾波器相對於可能長度爲零的邊界框,calc()的替代方案?

的問題在其他線程使用的<filter>x/y屬性移動過濾器畫布的中心解決,還是一切都以百分比,因此相對於你正在嘗試應用的大小事影響,但問題是,即使在你看到某些東西的情況下,邊長也可以是0,請參閱在以下實施例中的頂線:

.pathWrapper path { 
 
    stroke: grey; 
 
    fill: none; 
 
    stroke-width: 1.5; 
 
    marker-start: url(#circle); 
 
    marker-end: url(#arrow); 
 
} 
 

 
.pathWrapper:hover { 
 
    filter: url(#colorFilter); 
 
}
<svg style="height:400px;width:100%;background-color:LightCyan"> 
 

 
<defs> 
 
    <filter id="colorFilter" x="-300%" y="-300%" width="600%" height="600%"> 
 
    <feGaussianBlur in="SourceAlpha" stdDeviation="1" result="blur"></feGaussianBlur> 
 
    <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 3 0" result="lightenedBlur"></feColorMatrix> 
 
    <feMerge> 
 
     <feMergeNode in="lightenedBlur"></feMergeNode> 
 
     <feMergeNode in="SourceGraphic"></feMergeNode> 
 
    </feMerge> 
 
    </filter> 
 
    <marker id="arrow" viewBox="0 -5 10 10" refX="0" refY="0" markerWidth="8" markerHeight="8" orient="auto" style="fill: grey;"> 
 
    <path d="M0,-5L10,0L0,5"></path> 
 
    </marker> 
 
    <marker id="circle" viewBox="0 -4 8 8" refX="0" refY="0" markerWidth="8" markerHeight="8" orient="auto-start-reverse" style="fill: grey;"><circle r="4" cx="4"></circle></marker> 
 
</defs> 
 

 
<g transform="scale(2)"> 
 

 
    <g class="pathWrapper" transform="translate(70,20)"> 
 
    <path d="M52,10L45,10L-30,10L-37,10"></path> 
 
    </g> 
 
    
 
    <g class="pathWrapper" transform="translate(70,50)"> 
 
    <path d="M42,20L35,20L30,10L-30,10L-37,10"></path> 
 
    </g> 
 

 
    <g class="pathWrapper" transform="translate(200,20)"> 
 
    <path d="M42,140L35,140L-30,70L-30,10L-30,10L-37,10"></path> 
 
    </g> 
 

 
</g> 
 

 
</svg>

光標懸停在線看施加有所述過濾器的效果。 您會看到懸停時頂部線條變得不可見。這是因爲邊框高度爲0,筆劃寬度和標誌小玩意不計:

height zero demo

我可以用絕對單位來代替,如就像下面這個例子:

.pathWrapper path { 
 
    stroke: grey; 
 
    fill: none; 
 
    stroke-width: 1.5; 
 
    marker-start: url(#circle); 
 
    marker-end: url(#arrow); 
 
} 
 

 
.pathWrapper:hover { 
 
    filter: url(#colorFilter); 
 
}
<svg style="height:400px;width:100%;background-color:LightCyan"> 
 

 
<defs> 
 
    <filter id="colorFilter" filterUnits="userSpaceOnUse" x="-125" y="-125" width="250" height="250"> 
 
    <feGaussianBlur in="SourceAlpha" stdDeviation="1" result="blur"></feGaussianBlur> 
 
    <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 3 0" result="lightenedBlur"></feColorMatrix> 
 
    <feMerge> 
 
     <feMergeNode in="lightenedBlur"></feMergeNode> 
 
     <feMergeNode in="SourceGraphic"></feMergeNode> 
 
    </feMerge> 
 
    </filter> 
 
    <marker id="arrow" viewBox="0 -5 10 10" refX="0" refY="0" markerWidth="8" markerHeight="8" orient="auto" style="fill: grey;"> 
 
    <path d="M0,-5L10,0L0,5"></path> 
 
    </marker> 
 
    <marker id="circle" viewBox="0 -4 8 8" refX="0" refY="0" markerWidth="8" markerHeight="8" orient="auto-start-reverse" style="fill: grey;"><circle r="4" cx="4"></circle></marker> 
 
</defs> 
 

 
<g transform="scale(2)"> 
 

 
    <g class="pathWrapper" transform="translate(70,20)"> 
 
    <path d="M52,10L45,10L-30,10L-37,10"></path> 
 
    </g> 
 
    
 
    <g class="pathWrapper" transform="translate(70,50)"> 
 
    <path d="M42,20L35,20L30,10L-30,10L-37,10"></path> 
 
    </g> 
 

 
    <g class="pathWrapper" transform="translate(200,20)"> 
 
    <path d="M42,140L35,140L-30,70L-30,10L-30,10L-37,10"></path> 
 
    </g> 
 

 
</g> 
 

 
</svg>

的問題是,在我的使用情況下,它已應用可以改變相當多的影響元素的大小,所以我將不得不把一個巨大的價值在那裏或者總是有它的變化不夠大(如跨越最大高度的線的例子所示)。

我發現就在使用CSS calc()可能是一個解決辦法:

#colorFilter { 
 
    width: calc(100% + 100); 
 
    height: calc(100% + 100); 
 
    x: calc(-50% - 50); 
 
    y: calc(-50% - 50); 
 
} 
 

 
.pathWrapper path { 
 
    stroke: grey; 
 
    fill: none; 
 
    stroke-width: 1.5; 
 
    marker-start: url(#circle); 
 
    marker-end: url(#arrow); 
 
} 
 

 
.pathWrapper:hover { 
 
    filter: url(#colorFilter); 
 
}
<svg style="height:400px;width:100%;background-color:LightCyan"> 
 

 
<defs> 
 
    <filter id="colorFilter" filterUnits="userSpaceOnUse"> 
 
    <feGaussianBlur in="SourceAlpha" stdDeviation="1" result="blur"></feGaussianBlur> 
 
    <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 3 0" result="lightenedBlur"></feColorMatrix> 
 
    <feMerge> 
 
     <feMergeNode in="lightenedBlur"></feMergeNode> 
 
     <feMergeNode in="SourceGraphic"></feMergeNode> 
 
    </feMerge> 
 
    </filter> 
 
    <marker id="arrow" viewBox="0 -5 10 10" refX="0" refY="0" markerWidth="8" markerHeight="8" orient="auto" style="fill: grey;"> 
 
    <path d="M0,-5L10,0L0,5"></path> 
 
    </marker> 
 
    <marker id="circle" viewBox="0 -4 8 8" refX="0" refY="0" markerWidth="8" markerHeight="8" orient="auto-start-reverse" style="fill: grey;"><circle r="4" cx="4"></circle></marker> 
 
</defs> 
 

 
<g transform="scale(2)"> 
 

 
    <g class="pathWrapper" transform="translate(70,20)"> 
 
    <path d="M52,10L45,10L-30,10L-37,10"></path> 
 
    </g> 
 
    
 
    <g class="pathWrapper" transform="translate(70,50)"> 
 
    <path d="M42,20L35,20L30,10L-30,10L-37,10"></path> 
 
    </g> 
 

 
    <g class="pathWrapper" transform="translate(200,20)"> 
 
    <path d="M42,140L35,140L-30,70L-30,10L-30,10L-37,10"></path> 
 
    </g> 
 

 
</g> 
 

 
</svg>

這個作品在谷歌Chrome和Mozilla Firefox瀏覽器的當前版本,但不會出現在Micosoft邊緣或工作IE11(從一點搜索看起來好像calc()支持即使對於HTML內容已經相當敏感,參見已知問題部分在https://caniuse.com/#search=calc)。

那麼存在一種更好的替代calc()方法嗎?

(也許這是值得注意的是,我與動態d3.js生成的內容合作。)

回答

3

當你正在與D3生成的內容的工作,最好的辦法是插入一個看不見的矩形進g.pathWrapper涵蓋所需的過濾面積。你可能不得不將它適應你的邏輯(也許換ES6等價的ES6結構)。假設你有你從你的生成路徑數據點的列表:

var points = [[52,10], [45,10], [-30,10], [-37,10]]; 

// get the min/max values 
var x1 = d3.min(points,(p) => p[0]), 
    x2 = d3.max(points,(p) => p[0]), 
    y1 = d3.min(points,(p) => p[1]), 
    y2 = d3.max(points,(p) => p[1]); 

// construct the path 
var path = d3.path(); 
path.moveto(...points[0]); 
for (var point of points.slice(1)) { 
    path.lineto(...point); 
} 

// wrapper 
var wrapper = d3.select('svg > g').append('g') 
    .classed('pathWrapper'); 

// invisible rect with +5px in each direction as filter region 
wrapper.append('rect') 
    .attr('fill', 'none') 
    .attr('x', x1 - 5) 
    .attr('y', y1 - 5) 
    .attr('width', x2 - x1 + 10) 
    .attr('height', y2 - y1 + 10); 

// and the path itself 
wrapper.append('path') 
    .attr('d', path); 

之後,濾鏡效果區域的默認值應該工作原樣。

+0

的偉大工程。在你發佈這個答案之前,我正在考慮使用不同的過濾器,但是你的方法更好,並且效果很好。 – phk

1

僅僅因爲您在篩選器中使用的值爲userSpaceOnUse,並不意味着您仍不能使用百分比。只是這些百分比與SVG的寬度和高度有關,而不是元素的寬度和高度。

當然,這確實意味着該過濾器正被應用於多餘的不必要像素的批次。過濾器正在應用於SVG大小的區域,而不是元素大小的區域。但是由於您只是在懸停時篩選了一個元素,因此瀏覽器所做的額外工作導致的任何緩慢都不應該引起注意。

.pathWrapper path { 
 
    stroke: grey; 
 
    fill: none; 
 
    stroke-width: 1.5; 
 
    marker-start: url(#circle); 
 
    marker-end: url(#arrow); 
 
} 
 

 
.pathWrapper:hover { 
 
    filter: url(#colorFilter); 
 
}
<svg style="height:400px;width:100%;background-color:LightCyan"> 
 

 
<defs> 
 
    <filter id="colorFilter" filterUnits="userSpaceOnUse"> 
 
    <feGaussianBlur in="SourceAlpha" stdDeviation="1" result="blur"></feGaussianBlur> 
 
    <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 255 0 0 0 0 0 0 0 0 3 0" result="lightenedBlur"></feColorMatrix> 
 
    <feMerge> 
 
     <feMergeNode in="lightenedBlur"></feMergeNode> 
 
     <feMergeNode in="SourceGraphic"></feMergeNode> 
 
    </feMerge> 
 
    </filter> 
 
    <marker id="arrow" viewBox="0 -5 10 10" refX="0" refY="0" markerWidth="8" markerHeight="8" orient="auto" style="fill: grey;"> 
 
    <path d="M0,-5L10,0L0,5"></path> 
 
    </marker> 
 
    <marker id="circle" viewBox="0 -4 8 8" refX="0" refY="0" markerWidth="8" markerHeight="8" orient="auto-start-reverse" style="fill: grey;"><circle r="4" cx="4"></circle></marker> 
 
</defs> 
 

 
<g transform="scale(2)"> 
 

 
    <g class="pathWrapper" transform="translate(70,20)"> 
 
    <path d="M52,10L45,10L-30,10L-37,10"></path> 
 
    </g> 
 
    
 
    <g class="pathWrapper" transform="translate(70,50)"> 
 
    <path d="M42,20L35,20L30,10L-30,10L-37,10"></path> 
 
    </g> 
 

 
    <g class="pathWrapper" transform="translate(200,20)"> 
 
    <path d="M42,140L35,140L-30,70L-30,10L-30,10L-37,10"></path> 
 
    </g> 
 

 
</g> 
 

 
</svg>

+0

懸停只是爲了演示目的,但如果繪圖空間不是太大,也是一個好主意。在我的情況下,它是相當大的,因爲可見空間只顯示了我的繪圖空間的一部分(用戶可以平移/縮放),而且我還沒有實現某種類型的截錐體剔除等效(還?)。 – phk