2011-08-30 51 views
147

目前正在構建基於瀏覽器的SVG應用程序。在這個應用程序中,用戶可以對各種形狀進行樣式化和定位,包括矩形。你可以控制如何繪製一個SVG的筆畫寬度?

當我施加stroke-width到的SVG rect元件說1px,衝程被施加到rect的偏移和插圖中通過不同的瀏覽器不同的方式。這很麻煩,尤其是當我嘗試計算一個矩形的外部寬度和視覺位置並將其放置在其他元素旁邊時。

例如:

  • 火狐添加1px的邊界(下和左),和1px的偏移(頂部和右)
  • 鉻添加1px的邊界(頂部和左),和1px的偏移(底部和右)

我唯一的解決辦法爲止。將繪製實際邊界自己(可能與path工具)和邊界定位描邊元素後面。但是這個解決方案是一個令人不快的解決方法,如果可能的話,我寧願不要走這條路。

所以我的問題是,你可以控制SVG的stroke-width如何繪製元素?

+0

有過濾器黑客可以用來實現這一點 - 但它不是一個很好的解決方案 –

+1

有'paint-order'參數,您可以指定,填充應該被繪製在筆畫頂部,所以你將獲得「外部對齊」,請參閱https://jsfiddle.net/hne0kyLg/1/ –

回答

272

不,您不能指定描邊是在元素內部還是外部繪製。我在2003年向SVG工作組提供了a proposal的這一功能,但它沒有得到任何支持(或討論)。

SVG proposed stroke-location example, from phrogz.net/SVG/stroke-location.svg

正如我在提案中指出,

  • 您可以通過使用剪切路徑對象夾在翻了幾番,中風的寬度,然後實現相同的視覺結果爲「內」 ,並且
  • 您可以通過將筆畫寬度加倍然後在其自身頂部覆蓋該對象的無筆畫副本來實現與「外部」相同的視覺效果。

編輯:這個答案在將來可能是錯誤的。應該可以使用SVG Vector EffectsveStrokePathveIntersect(用於「內部」)或與veExclude(用於「外部」)來實現這些結果。然而,Vector Effects仍然是一個工作草案模塊,沒有我可以找到的實現。

編輯2:SVG 2草案規範包含stroke-alignment屬性(具有中間|外部可能值)。該屬性最終可能會使其成爲UA。

編輯3:有趣的是和dissapointingly,SVG工作組已經從SVG 2.刪除stroke-alignment你可以看到一些散文here之後描述的擔憂。

+2

認爲可能是這種情況。爲了解決這個問題,我爲getBBox()寫了一個叫做getStrokedBBox()的包裝函數。這個包裝根據瀏覽器如何將筆劃應用到形狀的插入和偏移來返回BBox。這並不完美(需要繼續檢查最新的瀏覽器版本),但它現在可以準確地提供一個形狀外部寬度。 – Steve

+6

@Phrogz也許我們會在10年過去之前看到它。 https://svgwg.org/svg2-draft/painting.html#SpecifyingStrokePaint批註 – frenchone

+1

[終​​於來了!](// stackoverflow.com/questions/7241393/can-you-control-how-an-svgs-stroke- width-is-drawn/28787545#answer-28787545)其中之一,我真的一直在敦促這個財產到達。 – mnsth

6

這裏是一個將計算出你需要多少像素增加一個功能 - 使用給定的行程 - 到頂部,右,下,左,所有基於瀏覽器上:

var getStrokeOffsets = function(stroke){ 

     var strokeFloor =  Math.floor(stroke/2),                 // max offset 
      strokeCeil =  Math.ceil(stroke/2);                 // min offset 

     if($.browser.mozilla){                       // Mozilla offsets 

      return { 
       bottom:  strokeFloor, 
       left:  strokeFloor, 
       top:  strokeCeil, 
       right:  strokeCeil 
      }; 

     }else if($.browser.webkit){                      // WebKit offsets 

      return { 
       bottom:  strokeCeil, 
       left:  strokeFloor, 
       top:  strokeFloor, 
       right:  strokeCeil 
      }; 

     }else{                           // default offsets 

      return { 
       bottom:  strokeCeil, 
       left:  strokeCeil, 
       top:  strokeCeil, 
       right:  strokeCeil 
      }; 

     } 

    }; 
4

如上人注意你要麼必須重新計算筆劃路徑座標的偏移量,要麼重新計算其寬度,然後屏蔽一側或另一側,這是因爲SVG不僅本身不支持Illustrator的筆劃對齊,而且PostScript也不會。

在Adobe的的PostScript手冊第二版狀態中風規格: 「4.5.1撫摸:衝程操作者繪製一條線沿着電流路徑一些厚度對於在每個直的或彎曲段路徑,筆劃繪製一條線,即居中在邊上並行到段。 (強調他們的)

規範的其餘部分沒有抵消線的位置的屬性。當Illustrator允許您在內部或外部對齊時,它將重新計算實際路徑的偏移量(因爲它仍然比套印和遮罩在計算上便宜)。 .ai文檔中的路徑座標是引用,而不是被分類或導出爲最終格式的路徑。

因爲Inkscape的原生格式是spec SVG,所以它不能提供spec所缺少的功能。

43

更新:stroke-alignment屬性was on April 1st moved to a completely new spec called SVG Strokes

由於SVG 2.0編輯的2015年2月26日(也可能是因爲February 13th)的草案,the stroke-alignment property is present的價值觀innercenter(默認)outer

它似乎與@Phrogz和後來的stroke-position suggestion提出的stroke-location屬性的工作方式相同。自2011年至少這家酒店已經計劃,但除了一個註解,說

SVG 2應包括一種指定行程位置

,它從來沒有在規範中,因爲它詳細被推遲 - 直到現在看來。

沒有瀏覽器支持這個屬性,或者,據我所知,任何新的SVG 2功能,但希望他們會盡快規範成熟。這是我個人一直敦促擁有的財產,我真的很高興它終於在規範中出現。

似乎有一些問題,如何該屬性應該在開放路徑以及循環行爲。這些問題很可能會延長瀏覽器的實現時間。但是,當瀏覽器開始支持這個屬性時,我會用新的信息更新這個答案。

+1

筆劃對齊是在W3C工作草案的SVG Strokes中指定的。同時,SVG 2 W3C編輯草案指出,中風定位屬性應在SVG規範中的https://svgwg.org/svg2-draft/painting.html#SpecifyingStrokePaint中,但該規範已達到W3C候選推薦標準,並且除了與「中風位置」提案的聯繫之外,沒有這樣的財產存在,這使得看起來情況並非如此。 –

0

A(髒)可能的解決方案是通過使用圖案,

這裏是帶有內撫摸三角形的示例:

https://jsfiddle.net/qr3p7php/5/

<style> 
#triangle1{ 
    fill: #0F0; 
    fill-opacity: 0.3; 
    stroke: #000; 
    stroke-opacity: 0.5; 
    stroke-width: 20; 
} 
#triangle2{ 
    stroke: #f00; 
    stroke-opacity: 1; 
    stroke-width: 1; 
}  
</style> 

<svg height="210" width="400" > 
    <pattern id="fagl" patternUnits="objectBoundingBox" width="2" height="1" x="-50%"> 
     <path id="triangle1" d="M150 0 L75 200 L225 200 Z"> 
    </pattern>  
    <path id="triangle2" d="M150 0 L75 200 L225 200 Z" fill="url(#fagl)"/> 
</svg> 
2

這裏是內周圍的工作加上rect使用symboluse

https://jsbin.com/yopemiwame/edit?html,output

SVG

<svg> 
    <symbol id="inner-border-rect"> 
    <rect class="inner-border" width="100%" height="100%" style="fill:rgb(0,255,255);stroke-width:10;stroke:rgb(0,0,0)"> 
    </symbol> 
    ... 
    <use xlink:href="#inner-border-rect" x="?" y="?" width="?" height="?"> 
</svg> 

注:確保用實際值替換?use

背景:之所以這個作品是因爲標誌用svg更換symbol並創造陰影DOM元素建立一個新的視窗。這個影子DOM的svg然後鏈接到您當前的SVG元素中。請注意,svg s可以嵌套,並且每個svg都會創建一個新視口,該視口將剪切重疊的所有內容(包括重疊的邊框)。有關Sara Soueidan閱讀this fantastic article的更多詳細信息,請參閱。

17

我發現一個簡單的方法,它有一些限制,但爲我工作:

  • 定義DEFS形狀
  • 定義剪輯路徑引用形狀
  • 使用它和雙中風與作爲外部被夾

這裏的工作示例:

<defs> 
    <path id="ld" d="M256,0 L0,512 L384,512 L128,1024 L1024,384 L640,384 L896,0 L256,0 Z"/> 
    <clipPath id="clip"> 
     <use xlink:href="#ld"/> 
    </clipPath> 
</defs> 
<g> 
    <use xlink:href="#ld" stroke="#0081C6" stroke-width="160" fill="#00D2B8" clip-path="url(#clip)"/> 
</g> 
+0

我找到了最佳答案 –

+0

聰明的解決方案。謝謝 –

+0

這應該被接受爲答案。使用是當前可用的最優雅的解決方案。 – Nyerguds

0

我不知道這會有多大的幫助,但在我的情況下,我只是創建了另一個只有邊框的圓,並將其放置在另一個形狀的「內部」。