你能控制SVG的笔画宽度是如何绘制的吗?

Ste*_*eve 188 svg rect offset

目前正在构建基于浏览器的SVG应用程序.在这个应用程序中,用户可以设置和定位各种形状,包括矩形.

当我将一个stroke-widthSVG rect元素应用于某个SVG 元素时1px,rect不同浏览器会以不同的方式将笔划应用于偏移和插入.这被证明是麻烦的,特别是当我尝试计算矩形的外部宽度和视觉位置并将其放置在其他元素旁边时.

例如:

  • Firefox增加1px插入(底部和左侧)和1px偏移(顶部和右侧)
  • Chrome增加了1px插页(顶部和左侧)和1px偏移(底部和右侧)

到目前为止,我唯一的解决方案是自己绘制实际边界(可能使用path工具)并将边框定位在描边元素后面.但是这个解决方案是一个令人不快的解决方案,如果可能的话,我宁愿不走这条路.

所以我的问题是,你能控制如何stroke-width在元素上绘制SVG 吗?

Phr*_*ogz 349

不,您无法指定是在元素内部还是外部绘制笔划.我在2003年向SVG工作组提出了此功能的建议,但没有得到任何支持(或讨论).

SVG提出了来自phrogz.net/SVG/stroke-location.svg的笔画位置示例

正如我在提案中所指出的,

  • 通过将笔划宽度加倍,然后使用剪切路径将对象剪切为自身,可以获得与"内部"相同的视觉效果,以及
  • 通过将笔划宽度加倍,然后将对象的无笔划副本叠加在自身上,您可以获得与"外部"相同的视觉效果.

编辑:这个答案将来可能是错的.应当可以使用实现这些结果SVG矢量效果,通过组合veStrokePath使用veIntersect(用于"内部"),或与veExclude(关于"外).但是,Vector Effects仍然是一个工作草案模块,没有我能找到的实现.

编辑2:SVG 2草案规范包括stroke-alignment属性(具有中心|外部可能值).该属性最终可能会成为UA.

编辑3:有趣且令人失望的是,SVG工作组已从stroke-alignmentSVG 2中删除.您可以在此处看到散文后描述的一些问题.

  • 我只是喜欢看工作中的官僚机构. (23认同)
  • @Phrogz也许我们会在10年过去之前看到它.https://svgwg.org/svg2-draft/painting.html#SpecifyingStrokePaint注释 (6认同)
  • 可能是这样的想法.为了解决这个问题,我为getBBox()编写了一个名为getStrokedBBox()的包装函数.此包装器根据浏览器如何将笔划应用于形状的插入和偏移来返回BBox.它不是完美的(需要不断检查最新的浏览器版本),但它确实提供了现在的形状外部宽度. (2认同)
  • 是否有任何我可以为该提案提供投票的页面?谢谢.似乎很荒谬,它不受支持. (2认同)

mns*_*sth 57

更新:stroke-alignment属性于4月1日转移到一个名为SVG Strokes的全新规范.

截至2015年2月26日的SVG 2.0编辑草案(可能自2月13日起),stroke-alignment物业存在使用值inner,center (默认)outer.

它的工作方式与stroke-location@Phrogz提出的属性和后来的stroke-position建议相同.这个属性至少从2011年开始计划,但除了注释之外

SVG 2应包括指定行程位置的方法

,它从未被详细说明,因为它被推迟 - 直到现在,似乎.

没有浏览器支持这个属性,或者据我所知,任何新的SVG 2功能,但希望它们会很快成熟.这是我个人一直敦促拥有的财产,我很高兴它终于出现在规范中.

关于属性应该如何在开放路径和循环上表现,似乎存在一些问题.这些问题很可能会延长浏览器的实现时间.但是,随着浏览器开始支持此属性,我将使用新信息更新此答案.


小智 40

我找到了一个简单的方法,它有一些限制,但对我有用:

  • 用defs定义形状
  • 定义引用形状的剪辑路径
  • 使用它并在外部被剪裁时使笔划加倍

这是一个工作示例:

<svg width="240" height="240" viewBox="0 0 1024 1024">
<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>
</svg>
Run Code Online (Sandbox Code Playgroud)

  • 为什么是顶级`&lt;use&gt;`?为什么不直接把路径和剪辑路径放进去呢?这工作得很好: `&lt;svg width="240" height="240" viewBox="0 0 1024 1024"&gt; &lt;path id="ld" d="M256,0 L0,512 L384,512 L128,1024 L1024 ,384 L640,384 L896,0 L256,0 Z"clip-path="url(#clip)" 笔划="#0081C6" 笔画宽度="160" 填充="#00d2b8"/&gt; &lt;clipPath id="剪辑"&gt; &lt;use xlink:href="#ld"/&gt; &lt;/clipPath&gt; &lt;/svg&gt;`。(是的,这是完全合理且正确的 SVG,并且将在任何地方正确渲染。不用担心递归。) (4认同)
  • 我找到的最佳答案 (2认同)
  • 聪明的解决方案。谢谢 (2认同)

Xav*_* Ho 17

您可以使用CSS来设置笔触和填充的顺序.也就是说,先击打然后再填充第二个,然后获得所需的效果.

MDN paint-order:https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/paint-order

CSS代码:

paint-order: stroke;
Run Code Online (Sandbox Code Playgroud)

  • 笔划像往常一样居中,但如果您有实心填充,则将绘制顺序调整为首先绘制笔划的效果是笔划的内半部分被绘制,这与绘制一个相同的效果外侧的笔划厚度为一半。 (3认同)
  • 只要填充物是固体,这就是一个很好的解决方法。如果它是透明的,则笔划的内半部分将变得可见,就像标准顺序一样。 (2认同)

Ste*_*eve 7

这是一个函数,它将根据浏览器计算需要添加的像素数(使用给定的笔划)到顶部,右侧,底部和左侧:

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
            };

        }

    };
Run Code Online (Sandbox Code Playgroud)


小智 6

正如上面的人已经注意到你要么必须重新计算笔划的路径坐标的偏移量或加倍其宽度然后屏蔽一侧或另一侧,因为SVG不仅本身不支持Illustrator的笔划对齐,而且PostScript也不是.

在Adobe的的PostScript手册第二版笔划说明书指出:" 4.5.1抚摸: 所述行程操作者绘制一条线沿着电流路径一定厚度的对于路径中的每个直的或弯曲段.冲程绘制是一条线为中心上两边平行于该段的段." (强调他们的)

规范的其余部分没有用于抵消线的位置的属性.当Illustrator允许您在内部或外部对齐时,它会重新计算实际路径的偏移量(因为它的计算成本仍然比叠印然后屏蔽更便宜)..ai文档中的路径坐标是参考,而不是被栅格化或导出为最终格式的路径.

因为Inkscape的原生格式是spec SVG,所以它无法提供规范所缺乏的功能.