【问题标题】:SVG dynamic positioning and dimensionsSVG 动态定位和尺寸
【发布时间】:2022-11-28 00:37:36
【问题描述】:

我有一个网络应用程序,它从来自数据库的笛卡尔点(线、路径等)呈现 svg 元素。

我要求最终用户可以上传 svg 文件(图标)并拖动图标以适应应用程序中已定义和呈现的点的特定范围。

例如(参见 sn-p),用户可以上传“x”图标并将其拖到由两点定义的绿线附近,这应该会导致图标被捕捉并调整到线的大小 - 左上角捕捉到线的起点,以及延伸到线终点的图标的宽度。与红线对齐的文件图标也是如此。这是在用js拖动的过程中动态完成的。为了简单起见,我从 sn-p 中省略了 js,因为我相信答案在于我可以使用 js 设置的 svg 属性和/或样式,但 svg 属性/值是我无法确定的。

我尝试过的——一切,我想。鉴于我正在嵌套 svg 元素,我将 BBox 值作为偏移量以使用 icon svg 元素上的 x 和 y 属性,并移动它,但不是移动到起点。我也尝试过翻译但没有成功。我可以移动和调整大小,但不能移动到我需要的坐标。如果可能的话,我根本不想更改图标 svg,所以我宁愿按原样保留它的 viewBox。

<svg height="700" width="700" fill="#e6e6e6" xmlns="http://www.w3.org/2000/svg">

<svg viewBox="0 0 512 512">
  <path d="M443.6,387.1L312.4,255.4l131.5-130c5.4-5.4,5.4-14.2,0-19.6l-37.4-37.6c-2.6-2.6-6.1-4-9.8-4c-3.7,0-7.2,1.5-9.8,4  L256,197.8L124.9,68.3c-2.6-2.6-6.1-4-9.8-4c-3.7,0-7.2,1.5-9.8,4L68,105.9c-5.4,5.4-5.4,14.2,0,19.6l131.5,130L68.4,387.1  c-2.6,2.6-4.1,6.1-4.1,9.8c0,3.7,1.4,7.2,4.1,9.8l37.4,37.6c2.7,2.7,6.2,4.1,9.8,4.1c3.5,0,7.1-1.3,9.8-4.1L256,313.1l130.7,131.1  c2.7,2.7,6.2,4.1,9.8,4.1c3.5,0,7.1-1.3,9.8-4.1l37.4-37.6c2.6-2.6,4.1-6.1,4.1-9.8C447.7,393.2,446.2,389.7,443.6,387.1z"/>
</svg>

<svg viewBox="0 0 380 511.7">
  <path fill-rule="nonzero" d="M26.18 0h221.14c3.1 0 5.85 1.51 7.56 3.84l122.88 145.08a9.27 9.27 0 0 1 2.21 6.05l.03 330.55c0 7.13-2.98 13.68-7.72 18.42l-.03.04c-4.75 4.74-11.29 7.72-18.43 7.72H26.18c-7.13 0-13.69-2.96-18.45-7.71l-.03-.04C2.97 499.22 0 492.69 0 485.52V26.18C0 19 2.95 12.46 7.68 7.72l.04-.04C12.46 2.95 19 0 26.18 0zm335.06 164.7c-134.78-5.58-134.35-17.38-129.82-134.02l.45-11.92H26.18c-2.05 0-3.91.83-5.26 2.16a7.482 7.482 0 0 0-2.16 5.26v459.34c0 2.02.84 3.88 2.18 5.23 1.36 1.35 3.22 2.19 5.24 2.19h327.64c2.01 0 3.86-.85 5.22-2.2 1.35-1.36 2.2-3.21 2.2-5.22V164.7zM250.25 27.32l-.15 4.01c-3.73 96.04-4.22 109.01 100.23 114.16L250.25 27.32z"/>
</svg>

<line x1="100" y1="20" x2="200" y2="20" stroke="green" />
<line x1="300" y1="20" x2="350" y2="20" stroke="red" />
</svg>

强文本

【问题讨论】:

  • 1. 主 svg 需要一个 viewBox 属性。 2. 嵌套的 svg 都需要宽度和高度 3. 计算第二个 svg 元素的中心 4. 确定 X svg 所需的大小。 4. 给 x svg 中心的 x 和 y。 5. 向后平移x width/2 height/2

标签: javascript css svg


【解决方案1】:

虽然可能有几种方法可以实现这一点,但我想出了一种方法,我将继续前进。与此混淆主要是由于我缺乏对 svg viewBox 以及坐标系如何工作的理解。

这样做的关键是根据其 BBox 坐标为每个嵌套的 svg 定义一个新的 viewBox 值。这样做的目的是在没有“空白”的情况下框起绘图,以使其能够放置在所需的坐标处。一旦你有了 BBox 数据,你就可以设置 viewBox 并做一些简单的数学运算来正确设置所需的高度和宽度(这两者都必须为嵌套的 svg 定义)。更新 viewBox、宽度和高度后,您可以将 svg 移动到新位置。

$( document ).ready(function() {
        const svg = document.querySelectorAll('svg.a');
        svg.forEach(x => {
          setSvg(x);
        });
    });

    function setSvg(svg){
      const { xMin, xMax, yMin, yMax } = [...svg.children].reduce((acc, el) => {
            const { x, y, width, height } = el.getBBox();
            if (!acc.xMin || x < acc.xMin) acc.xMin = x;
            if (!acc.xMax || x + width > acc.xMax) acc.xMax = x + width;
            if (!acc.yMin || y < acc.yMin) acc.yMin = y;
            if (!acc.yMax || y + height > acc.yMax) acc.yMax = y + height;
            return acc;
        }, {});
        const viewbox = `${xMin} ${yMin} ${xMax - xMin} ${yMax - yMin}`;

        let newWidth = $(svg).attr('data-new-width');
        let newPosition = $(svg).attr('data-new-position');
        let newHeight = newWidth*(yMax - yMin)/(xMax - xMin);

        svg.setAttribute('width', newWidth);
        svg.setAttribute('height', newHeight);
        svg.setAttribute('x', newPosition.split(",")[0]);
        svg.setAttribute('y', newPosition.split(",")[1]);
        svg.setAttribute('viewBox', viewbox);
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<svg height="700" width="700" fill="#e6e6e6" xmlns="http://www.w3.org/2000/svg">

    <svg class="a" data-new-width="100" data-new-position="100,20" viewBox="0 0 512 512">
      <path d="M443.6,387.1L312.4,255.4l131.5-130c5.4-5.4,5.4-14.2,0-19.6l-37.4-37.6c-2.6-2.6-6.1-4-9.8-4c-3.7,0-7.2,1.5-9.8,4  L256,197.8L124.9,68.3c-2.6-2.6-6.1-4-9.8-4c-3.7,0-7.2,1.5-9.8,4L68,105.9c-5.4,5.4-5.4,14.2,0,19.6l131.5,130L68.4,387.1  c-2.6,2.6-4.1,6.1-4.1,9.8c0,3.7,1.4,7.2,4.1,9.8l37.4,37.6c2.7,2.7,6.2,4.1,9.8,4.1c3.5,0,7.1-1.3,9.8-4.1L256,313.1l130.7,131.1  c2.7,2.7,6.2,4.1,9.8,4.1c3.5,0,7.1-1.3,9.8-4.1l37.4-37.6c2.6-2.6,4.1-6.1,4.1-9.8C447.7,393.2,446.2,389.7,443.6,387.1z"/>
    </svg>

    <svg class="a" data-new-width="50" data-new-position="300,20" viewBox="0 0 380 511.7">
      <path fill-rule="nonzero" d="M26.18 0h221.14c3.1 0 5.85 1.51 7.56 3.84l122.88 145.08a9.27 9.27 0 0 1 2.21 6.05l.03 330.55c0 7.13-2.98 13.68-7.72 18.42l-.03.04c-4.75 4.74-11.29 7.72-18.43 7.72H26.18c-7.13 0-13.69-2.96-18.45-7.71l-.03-.04C2.97 499.22 0 492.69 0 485.52V26.18C0 19 2.95 12.46 7.68 7.72l.04-.04C12.46 2.95 19 0 26.18 0zm335.06 164.7c-134.78-5.58-134.35-17.38-129.82-134.02l.45-11.92H26.18c-2.05 0-3.91.83-5.26 2.16a7.482 7.482 0 0 0-2.16 5.26v459.34c0 2.02.84 3.88 2.18 5.23 1.36 1.35 3.22 2.19 5.24 2.19h327.64c2.01 0 3.86-.85 5.22-2.2 1.35-1.36 2.2-3.21 2.2-5.22V164.7zM250.25 27.32l-.15 4.01c-3.73 96.04-4.22 109.01 100.23 114.16L250.25 27.32z"/>
    </svg>

    <line x1="100" y1="20" x2="200" y2="20" stroke="green" />
    <line x1="300" y1="20" x2="350" y2="20" stroke="red" />
  </svg>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-30
    • 1970-01-01
    • 2016-10-27
    • 2011-11-02
    • 2012-02-29
    • 1970-01-01
    • 1970-01-01
    • 2018-10-21
    相关资源
    最近更新 更多