【问题标题】:Switch X and Y axis for everything in SVG?为 SVG 中的所有内容切换 X 和 Y 轴?
【发布时间】:2021-09-16 18:48:51
【问题描述】:

我正在使用 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>

【问题讨论】:

    标签: svg svg-transforms


    【解决方案1】:

    可能是这样的:

    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 的内部放在一个组 &lt;g&gt;&lt;/g&gt; 中。下面是一个手动计算变换和通过获取原始 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 中使用具有“stroke”属性的元素,那么您可能还想对它们应用 vector-effect="non-scaling-stroke" 属性。

    【讨论】:

      猜你喜欢
      • 2021-12-12
      • 2011-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-02
      相关资源
      最近更新 更多