为 SVG 中的所有内容切换 X 轴和 Y 轴?
Switch X and Y axis for everything in SVG?
我正在使用 SVG 创建条形图,默认情况下条形是垂直的。但在某些情况下,如果条是水平的,看起来会更好,比如只有 2 个条。
如何重复使用相同的 SVG 代码并仅切换 X 轴和 Y 轴来实现?它实际上不仅仅是 X 和 Y,还有矩形的高度和宽度。
这可能吗?我想避免两次编写非常相似的代码。
示例:我分别构建了两个图表,理想情况下,第二个图表应该通过重用第一个图表中的代码生成。
<style>
svg { height: 20px; width: 100px; border: 1px solid #ccc;}
</style>
<svg>
<rect x="5%" y="60%" width="40%" height="40%" fill="black"/>
<rect x="55%" y="40%" width="40%" height="60%" fill="black"/>
</svg>
<svg>
<rect y="5%" x="0%" height="40%" width="40%" fill="black"/>
<rect y="55%" x="0%" height="40%" width="60%" fill="black"/>
</svg>
也许是这样的:
function cloneWithTransformedAttributes(obj1, mapping) {
// returns copy of obj1 with child node attributes transformed according to mapping.
const obj2 = obj1.cloneNode(true);
[...obj1.children].forEach((child, idx)=>{
Object.keys(mapping).forEach((attribute) => {
const replacementVal = mapping[attribute].default ?
mapping[attribute].default :
child.getAttribute(mapping[attribute]);
obj2.children[idx].setAttribute(attribute, replacementVal);
})
})
return obj2;
}
mapping = {
x: {
default: 0
},
y: "x",
width: "height",
height: "width"
}
const verticalSvg = document.getElementsByTagName("svg")[0];
const horizontalSvg = cloneWithTransformedAttributes(verticalSvg, mapping);
const graphs = document.getElementById("graphs");
graphs.appendChild(horizontalSvg);
<style>
svg { height: 20px; width: 100px; border: 1px solid #ccc;}
</style>
<div id="graphs">
<svg>
<rect x="5%" y="60%" width="40%" height="40%" fill="black"/>
<rect x="55%" y="40%" width="40%" height="60%" fill="black"/>
</svg>
</div>
编辑:您也可以使用 svg 转换来完成,但您需要将 SVG 的内部放在一个组中 <g></g>
。这是一个包含手动计算的变换和通过获取原始 svg 宽度和高度自行计算变换的 JS 解决方案的示例:
const verticalSvg = document.getElementsByTagName("svg")[0];
const svgStyle = window.getComputedStyle(verticalSvg, null);
const width = parseInt(svgStyle.getPropertyValue("width"));
const height = parseInt(svgStyle.getPropertyValue("height"));
const whRatio = width / height;
const transform = `rotate(90) scale(${1 / whRatio} ${whRatio}) translate(0 -${height})`
const horizontalSvg = verticalSvg.cloneNode(true);
horizontalSvg.children[0].setAttribute("transform", transform);
const graphs = document.getElementById("graphs");
graphs.appendChild(horizontalSvg);
<style>
svg { height: 20px; width: 100px; border: 1px solid #ccc; overflow: visible}
</style>
<div id="graphs">
<svg>
<g>
<rect x="5%" y="60%" width="40%" height="40%" fill="black"/>
<rect x="55%" y="40%" width="40%" height="60%" fill="black"/>
</g>
</svg>
<svg>
<!-- Manually calculated and applied transform -->
<g transform="rotate(90)
scale(0.20 5)
translate(0 -20)
">
<rect x="5%" y="60%" width="40%" height="40%" fill="black"/>
<rect x="55%" y="40%" width="40%" height="60%" fill="black"/>
</g>
</svg>
<!-- JS generated SVG will get inserted here -->
</div>
在您的情况下,您需要将转换应用于包含 SVG 内容的组。
如果将变换应用于 SVG 本身,它也会根据缩放变换缩放边框。
vector-effect="non-scaling-stroke"
不能应用于不属于 SVG 本身的 SVG 边框。但是,如果您在 SVG 中使用带有“笔划”属性 的元素,那么您可能还想对它们应用 vector-effect="non-scaling-stroke"
属性。
我正在使用 SVG 创建条形图,默认情况下条形是垂直的。但在某些情况下,如果条是水平的,看起来会更好,比如只有 2 个条。
如何重复使用相同的 SVG 代码并仅切换 X 轴和 Y 轴来实现?它实际上不仅仅是 X 和 Y,还有矩形的高度和宽度。
这可能吗?我想避免两次编写非常相似的代码。
示例:我分别构建了两个图表,理想情况下,第二个图表应该通过重用第一个图表中的代码生成。
<style>
svg { height: 20px; width: 100px; border: 1px solid #ccc;}
</style>
<svg>
<rect x="5%" y="60%" width="40%" height="40%" fill="black"/>
<rect x="55%" y="40%" width="40%" height="60%" fill="black"/>
</svg>
<svg>
<rect y="5%" x="0%" height="40%" width="40%" fill="black"/>
<rect y="55%" x="0%" height="40%" width="60%" fill="black"/>
</svg>
也许是这样的:
function cloneWithTransformedAttributes(obj1, mapping) {
// returns copy of obj1 with child node attributes transformed according to mapping.
const obj2 = obj1.cloneNode(true);
[...obj1.children].forEach((child, idx)=>{
Object.keys(mapping).forEach((attribute) => {
const replacementVal = mapping[attribute].default ?
mapping[attribute].default :
child.getAttribute(mapping[attribute]);
obj2.children[idx].setAttribute(attribute, replacementVal);
})
})
return obj2;
}
mapping = {
x: {
default: 0
},
y: "x",
width: "height",
height: "width"
}
const verticalSvg = document.getElementsByTagName("svg")[0];
const horizontalSvg = cloneWithTransformedAttributes(verticalSvg, mapping);
const graphs = document.getElementById("graphs");
graphs.appendChild(horizontalSvg);
<style>
svg { height: 20px; width: 100px; border: 1px solid #ccc;}
</style>
<div id="graphs">
<svg>
<rect x="5%" y="60%" width="40%" height="40%" fill="black"/>
<rect x="55%" y="40%" width="40%" height="60%" fill="black"/>
</svg>
</div>
编辑:您也可以使用 svg 转换来完成,但您需要将 SVG 的内部放在一个组中 <g></g>
。这是一个包含手动计算的变换和通过获取原始 svg 宽度和高度自行计算变换的 JS 解决方案的示例:
const verticalSvg = document.getElementsByTagName("svg")[0];
const svgStyle = window.getComputedStyle(verticalSvg, null);
const width = parseInt(svgStyle.getPropertyValue("width"));
const height = parseInt(svgStyle.getPropertyValue("height"));
const whRatio = width / height;
const transform = `rotate(90) scale(${1 / whRatio} ${whRatio}) translate(0 -${height})`
const horizontalSvg = verticalSvg.cloneNode(true);
horizontalSvg.children[0].setAttribute("transform", transform);
const graphs = document.getElementById("graphs");
graphs.appendChild(horizontalSvg);
<style>
svg { height: 20px; width: 100px; border: 1px solid #ccc; overflow: visible}
</style>
<div id="graphs">
<svg>
<g>
<rect x="5%" y="60%" width="40%" height="40%" fill="black"/>
<rect x="55%" y="40%" width="40%" height="60%" fill="black"/>
</g>
</svg>
<svg>
<!-- Manually calculated and applied transform -->
<g transform="rotate(90)
scale(0.20 5)
translate(0 -20)
">
<rect x="5%" y="60%" width="40%" height="40%" fill="black"/>
<rect x="55%" y="40%" width="40%" height="60%" fill="black"/>
</g>
</svg>
<!-- JS generated SVG will get inserted here -->
</div>
在您的情况下,您需要将转换应用于包含 SVG 内容的组。 如果将变换应用于 SVG 本身,它也会根据缩放变换缩放边框。
vector-effect="non-scaling-stroke"
不能应用于不属于 SVG 本身的 SVG 边框。但是,如果您在 SVG 中使用带有“笔划”属性 的元素,那么您可能还想对它们应用 vector-effect="non-scaling-stroke"
属性。