我正在使用SVG在Javascript中开发一个地图来绘制线条。
我想添加一个可以搜索道路的功能,如果找到了道路,地图上会出现一个圆圈。
我知道我可以在SVG中绘制一个圆圈,但我的问题是,圆的大小不应该根据缩放级别而改变。换句话说,圆圈必须始终具有相同的尺寸。 我地图上的道路都有这个功能,我所要做的就是添加
vector-effect="non-scaling-stroke"
到行属性..
一条线看起来像这样。
<line vector-effect="non-scaling-stroke" stroke-width="3" id = 'line1' x1 = '0' y1 = '0' x2 = '0' y2 = '0' style = 'stroke:rgb(255,215,0);'/>
圆圈看起来像这样。
<circle id = "pointCircle" cx="0" cy="0" r="10" stroke="red" stroke-width="1" fill = "red"/>
是否有可能以某种方式将圆圈定义为“非缩放”?
答案 0 :(得分:7)
我花了一段时间,但我终于把数学弄干净了。这个解决方案需要三件事:
<script xlink:href="SVGPanUnscale.js"></script>
unscaleEach("g.non-scaling > *, circle.non-scaling");
transform="translate(…,…)"
将每个元素放置在图表上,不 cx="…" cy="…"
。 只需使用这些步骤,使用SVGPan进行缩放和平移不会影响标记元素的缩放(或旋转或倾斜)。
// Copyright 2012 © Gavin Kistner, !@phrogz.net
// License: http://phrogz.net/JS/_ReuseLicense.txt
// Undo the scaling to selected elements inside an SVGPan viewport
function unscaleEach(selector){
if (!selector) selector = "g.non-scaling > *";
window.addEventListener('mousewheel', unzoom, false);
window.addEventListener('DOMMouseScroll', unzoom, false);
function unzoom(evt){
// getRoot is a global function exposed by SVGPan
var r = getRoot(evt.target.ownerDocument);
[].forEach.call(r.querySelectorAll(selector), unscale);
}
}
// Counteract all transforms applied above an element.
// Apply a translation to the element to have it remain at a local position
function unscale(el){
var svg = el.ownerSVGElement;
var xf = el.scaleIndependentXForm;
if (!xf){
// Keep a single transform matrix in the stack for fighting transformations
// Be sure to apply this transform after existing transforms (translate)
xf = el.scaleIndependentXForm = svg.createSVGTransform();
el.transform.baseVal.appendItem(xf);
}
var m = svg.getTransformToElement(el.parentNode);
m.e = m.f = 0; // Ignore (preserve) any translations done up to this point
xf.setMatrix(m);
}
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Scale-Independent Elements</title>
<style>
polyline { fill:none; stroke:#000; vector-effect:non-scaling-stroke; }
circle, polygon { fill:#ff9; stroke:#f00; opacity:0.5 }
</style>
<g id="viewport" transform="translate(500,300)">
<polyline points="-100,-50 50,75 100,50" />
<g class="non-scaling">
<circle transform="translate(-100,-50)" r="10" />
<polygon transform="translate(100,50)" points="0,-10 10,0 0,10 -10,0" />
</g>
<circle class="non-scaling" transform="translate(50,75)" r="10" />
</g>
<script xlink:href="SVGPan.js"></script>
<script xlink:href="SVGPanUnscale.js"></script>
<script>
unscaleEach("g.non-scaling > *, circle.non-scaling");
</script>
</svg>
答案 1 :(得分:2)
如果您正在寻找一种完全静态的方法,您可以将非缩放笔划与标记结合使用,因为标记可以相对于笔划宽度。
换句话说,您可以将圆圈包裹在&lt; marker&gt;中。元素然后在你需要的地方使用那些标记。
<svg width="500" height="500" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000">
<marker id="Triangle"
viewBox="0 0 10 10" refX="0" refY="5"
markerUnits="strokeWidth"
markerWidth="4" markerHeight="3"
orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
<path d="M 100 100 l 200 0" vector-effect="non-scaling-stroke"
fill="none" stroke="black" stroke-width="10"
marker-end="url(#Triangle)" />
<path d="M 100 200 l 200 0"
fill="none" stroke="black" stroke-width="10"
marker-end="url(#Triangle)" />
</svg>
同样也可以查看和调整here。 svg规范并未完全明确在这种情况下应该发生什么(因为标记不在SVG Tiny 1.2中,而矢量效应不在SVG 1.1中)。我目前的想法是它可能会影响标记的大小,但目前似乎没有观众这样做(尝试在支持矢量效果的浏览器中,例如Opera或Chrome)。
答案 2 :(得分:0)
看起来有些工作是在webkit中完成的(可能与这个bug有关:320635)并且新的转换不会像简单地附加那样
transform.baseVal.appendItem
这似乎更好。甚至可以在IE 10中使用。
编辑:修复了前面多个翻译转换的更一般情况的代码以及之后可能的其他转换。所有翻译后的第一个矩阵变换必须保留为不定标。
translate(1718.07 839.711) translate(0 0) matrix(0.287175 0 0 0.287175 0 0) rotate(45 100 100)
function unscale()
{
var xf = this.ownerSVGElement.createSVGTransform();
var m = this.ownerSVGElement.getTransformToElement(this.parentNode);
m.e = m.f = 0; // Ignore (preserve) any translations done up to this point
xf.setMatrix(m);
// Keep a single transform matrix in the stack for fighting transformations
// Be sure to apply this transform after existing transforms (translate)
var SVG_TRANSFORM_MATRIX = 1;
var SVG_TRANSFORM_TRANSLATE = 2;
var baseVal = this.transform.baseVal;
if(baseVal.numberOfItems == 0)
baseVal.appendItem(xf);
else
{
for(var i = 0; i < baseVal.numberOfItems; ++i)
{
if(baseVal.getItem(i).type == SVG_TRANSFORM_TRANSLATE && i == baseVal.numberOfItems - 1)
{
baseVal.appendItem(xf);
}
if(baseVal.getItem(i).type != SVG_TRANSFORM_TRANSLATE)
{
if(baseVal.getItem(i).type == SVG_TRANSFORM_MATRIX)
baseVal.replaceItem(xf, i);
else
baseVal.insertItemBefore(xf, i);
break;
}
}
}
}
EDIT2: 由于某种原因,Chrome杀死了getTransformToElement,因此需要手动检索矩阵:
var m = this.parentNode.getScreenCTM().inverse().multiply(this.ownerSVGElement.getScreenCTM());
答案 3 :(得分:0)