【问题标题】:Shifting SVG by fixed number of pixels将 SVG 移动固定像素数
【发布时间】:2022-02-07 17:14:55
【问题描述】:

SVG 示例目前在视觉上看起来很完美,只是我想在没有填充的情况下获得相同的结果。

填充的目的是迫使红/蓝线向右 40px 为轴腾出空间,同时阻止它在图形右侧溢出。

我正在尝试删除填充,但随后我需要找到一种新方法将“行”向右移动 40px,而不使用 x="40px" width="calc(100% - 40px)"因为这种语法也不兼容 Sharp 或旧版浏览器。

有什么方法可以移除填充并将线条向右移动 40 像素,同时将其限制在 SVG 的盒子模型中?

(最后说明:我不想在任何移动线条的逻辑中使用“响应”单元)

JSF 折线图中间:https://jsfiddle.net/Lefsqo3j/14/

<div style="height:148px;width:300px;overflow:hidden;resize:both">
    <svg overflow="visible" style="padding:24px 0px 24px 40px" height="100%" width="100%">
            <svg role="img" viewBox="0 0 300 100" preserveAspectRatio="none">
                <svg viewBox="0 0 300 100" preserveAspectRatio="none">
                    <line y1="0" y2="100" x1="0" x2="0" stroke-width="0.2" stroke="black"></line>
                    <line y1="0" y2="100" x1="75" x2="75" stroke-width="0.2" stroke="black"></line>
                    <line y1="0" y2="100" x1="150" x2="150" stroke-width="0.2" stroke="black"></line>
                    <line y1="0" y2="100" x1="225" x2="225" stroke-width="0.2" stroke="black"></line>
                    <line y1="0" y2="100" x1="300" x2="300" stroke-width="0.2" stroke="black"></line>
                    <line x1="0" x2="300" y1="0" y2="0" stroke-width="0.2" stroke="black"></line>
                    <line x1="0" x2="300" y1="25" y2="25" stroke-width="0.2" stroke="black"></line>
                    <line x1="0" x2="300" y1="50" y2="50" stroke-width="0.2" stroke="black"></line>
                    <line x1="0" x2="300" y1="75" y2="75" stroke-width="0.2" stroke="black"></line>
                    <line x1="0" x2="300" y1="100" y2="100" stroke-width="0.2" stroke="black"></line>
                </svg>
            </svg>
            <svg x="100%" overflow="visible">
                <text text-anchor="end" dy="-8px">
                    <tspan fill="red"> ⬤</tspan>
                    Line A<tspan fill="blue"> ⬤</tspan>
                    Line B
                </text>
            </svg>
            <svg viewBox="0 0 300 100" preserveAspectRatio="none">
                <path
                    d="M 0 75 M 0 75  L 75 50 L 150 15 L 225 67 L 300 67 L 300 67"
                    stroke-width="3"
                    stroke="red"
                    fill="transparent"
                    vector-effect="non-scaling-stroke"
                ></path>
                <path
                    d="M 0 92 M 0 92  L 75 72 L 150 80 L 225 50 L 300 50 L 300 50"
                    stroke-width="3"
                    stroke="blue"
                    fill="transparent"
                ></path>
            </svg>
            <svg overflow="visible">
                <text x="0%" text-anchor="end" y="0%">
                    40
                </text>
                <text x="0%" text-anchor="end" y="25%">
                    30
                </text>
                <text x="0%" text-anchor="end" y="50%">
                    20
                </text>
                <text x="0%" text-anchor="end" y="75%">
                    10
                </text>
                <text x="0%" text-anchor="end" y="100%">
                    0
                </text>
                <g style="transform: translateX(0%);">
                    <text y="100%" dy="16px">
                        5
                    </text>
                </g>
                <g style="transform: translateX(25%);">
                    <text y="100%" dy="16px">
                        10
                    </text>
                </g>
                <g style="transform: translateX(50%); ">
                    <text y="100%" dy="16px">
                        15
                    </text>
                </g>
                <g style="transform: translateX(75%); ">
                    <text y="100%" dy="16px">
                        20
                    </text>
                </g>
                <g text-anchor="end" style="transform: translateX(100%);">
                    <text y="100%" dy="16px">
                        25
                    </text>
                </g>
            </svg>
        </svg>
</div>

【问题讨论】:

  • 是否可以将父svg的所有内容都包裹在g中?
  • 是的,可以对 HTML 结构进行任何结构更改,只要它符合 SVG 规范(即不能将最顶层的父图包装在 div 中)

标签: html svg sharp


【解决方案1】:

我已经修改了 SVG 并将内容带入了内容框。尺寸在保持纵横比的情况下统一缩放。

<div style="height:148px;
    width:300px;
    overflow:hidden;
    resize:both; 
    background-color: wheat;
    ">

  <svg class="chart" overflow="visible">
      <style>
        .chart {
          width: 100%;
          height: 100%;
          font-size: 14px;
          padding-bottom: 24px;
        }

        /* background color for entire chart */
        .chart-background {
          fill: rgb(230, 249, 255);
        }

        /* styling for only the graph part */
        .graph {
          background-color: transparent;
        }

        /* grid lines style  */
        .chart .grid>line {
          stroke-width: 0.5;
          stroke: green;
        }

        .legend {
          background-color: wheat;
        }

        .labels {
          background-color: transparent !important;
        }

        .back {
          background-color: wheat;
        }

      </style>
      <rect class="chart-background" height="100%" width="100%" />
      <svg viewBox="0 0 340 140" x="40" y="24" preserveAspectRatio="none">
        <g class="grid">

          <line y1="0" y2="100" x1="0" x2="0"></line>
          <line y1="0" y2="100" x1="75" x2="75"></line>
          <line y1="0" y2="100" x1="150" x2="150"></line>
          <line y1="0" y2="100" x1="225" x2="225"></line>
          <line y1="0" y2="100" x1="300" x2="300"></line>

          <line x1="0" x2="300" y1="0" y2="0"></line>
          <line x1="0" x2="300" y1="25" y2="25"></line>
          <line x1="0" x2="300" y1="50" y2="50"></line>
          <line x1="0" x2="300" y1="75" y2="75"></line>
          <line x1="0" x2="300" y1="100" y2="100"></line>
        </g>
      </svg>

  <svg>
        <g class="legend">
          <text x="100%" text-anchor="end" dy="16">
            <tspan fill="red"> ⬤</tspan>Line A<tspan fill="blue"> ⬤</tspan>Line B
          </text>
        </g>
      </svg>

  <svg overflow="visible" x="40" y="24" height="70%" width="88%" style="margin-bottom: 24px;">
        <g class="labels" style="font-size: 12px;">
          <text x="0%" text-anchor="end" y="0%">40</text>
          <text x="0%" text-anchor="end" y="25%">30</text>
          <text x="0%" text-anchor="end" y="50%">20</text>
          <text x="0%" text-anchor="end" y="75%">10</text>
          <text x="0%" text-anchor="end" y="100%">0</text>

          <text y="100%" dy="16px">5</text>
          <text y="100%" dy="16px" x="22%">10</text>
          <text y="100%" dy="16px" x="48%">15</text>
          <text y="100%" dy="16px" x="74%">20</text>
          <text y="100%" dy="16px" dx="-20px" x="100%">25</text>
        </g>
      </svg>

  <svg viewBox="0 0 340 140" x="40" y="24" preserveAspectRatio="none">
        <g class="plot">
          <path d="M 0 75 M 0 75  L 75 50 L 150 15 L 225 67 L 300 67 L 300 67" stroke-width="3" stroke="red"
            fill="transparent" vector-effect="non-scaling-stroke"></path>
          <path d="M 0 92 M 0 92  L 75 72 L 150 80 L 225 50 L 300 50 L 300 50" stroke-width="3" stroke="blue"
            fill="transparent"></path>
        </g>
      </svg>
  </svg>
</div>

夏普:

const svgBuffer = Buffer.from(svgImage);

const image = await sharp(svgBuffer, {})
   .resize({ width: 500, fit: sharp.fit.inside, position: 'centre' })
   .toFile('e:/svg-image.png');


旧答案
我们可以将原始 svg 内容包装在一个新的 &lt;svg&gt; 标签中。并且使用自定义样式,可以定位原始 svg,以便溢出可见:

const sharp = require('sharp');

async function svgToImage(svgImage) {
 try {
  const wrapped = `<svg id='wrapper' width="600" height="400">
    <style>
      #wrapper > svg{
       transform: scale(.9) translate(25px, 25px) ;
      }
    </style>
    ${svgImage}
  </svg>`;

  const svgBuffer = Buffer.from(wrapped);
  //const image = await sharp(svgBuffer, {}).resize(500).toFile('e:/svg-image.png');

  const image = await sharp({
   create: {
    width: 600,
    height: 400,
    channels: 4,
    background: { r: 220, g: 255, b: 220, alpha: 1 },
   },
  })
   .composite([{ input: svgBuffer, top: 0, left: 0 }])
   .png()
   .toFile('e:/svg-image.png');
 } catch (error) {
  console.log(error);
 }
}

const svgImage = `
  <svg overflow="visible" style="padding:24px 0px 24px 40px">
  <svg role="img" viewBox="0 0 300 100" preserveAspectRatio="none">
      <svg viewBox="0 0 300 100" preserveAspectRatio="none">
          <line y1="0" y2="100" x1="0" x2="0" stroke-width="0.2" stroke="black"></line>
          <line y1="0" y2="100" x1="75" x2="75" stroke-width="0.2" stroke="black"></line>
          <line y1="0" y2="100" x1="150" x2="150" stroke-width="0.2" stroke="black"></line>
          <line y1="0" y2="100" x1="225" x2="225" stroke-width="0.2" stroke="black"></line>
          <line y1="0" y2="100" x1="300" x2="300" stroke-width="0.2" stroke="black"></line>
          <line x1="0" x2="300" y1="0" y2="0" stroke-width="0.2" stroke="black"></line>
          <line x1="0" x2="300" y1="25" y2="25" stroke-width="0.2" stroke="black"></line>
          <line x1="0" x2="300" y1="50" y2="50" stroke-width="0.2" stroke="black"></line>
          <line x1="0" x2="300" y1="75" y2="75" stroke-width="0.2" stroke="black"></line>
          <line x1="0" x2="300" y1="100" y2="100" stroke-width="0.2" stroke="black"></line>
      </svg>
  </svg>
  <svg x="100%" overflow="visible">
      <text text-anchor="end" dy="-8px">
          <tspan fill="red"> ⬤</tspan>
          Line A<tspan fill="blue"> ⬤</tspan>
          Line B
      </text>
  </svg>
  <svg viewBox="0 0 300 100" preserveAspectRatio="none">
      <path
          d="M 0 75 M 0 75  L 75 50 L 150 15 L 225 67 L 300 67 L 300 67"
          stroke-width="3"
          stroke="red"
          fill="transparent"
          vector-effect="non-scaling-stroke"
      ></path>
      <path
          d="M 0 92 M 0 92  L 75 72 L 150 80 L 225 50 L 300 50 L 300 50"
          stroke-width="3"
          stroke="blue"
          fill="transparent"
      ></path>
  </svg>
  <svg overflow="visible">
      <text x="0%" text-anchor="end" y="0%">40</text>
      <text x="0%" text-anchor="end" y="25%">30</text>
      <text x="0%" text-anchor="end" y="50%">20</text>
      <text x="0%" text-anchor="end" y="75%">10</text>
      <text x="0%" text-anchor="end" y="100%">0</text>
      
      <text y="100%" dy="16px">5</text>
      <text y="100%" dy="16px" x="25%">10</text>
      <text y="100%" dy="16px" x="50%">15</text>
      <text y="100%" dy="16px" x="75%">20</text>
      <text y="100%" dy="16px" x="100%">25</text>
  </svg>
</svg>`;

svgToImage(svgImage);

输出:



在 x 轴上,由于 bugbug 与变换相关,标签无法正常工作。所以我不得不修改x标签标签。

【讨论】:

  • 在查看了这里的所有内容后,这不太对,抱歉。 “scale(0.9)”是一个响应单元。这些图表需要在左侧总是分配 40px 的空间时完美响应,不多不少。此外,我真的很想避免任何形式的溢出,因为这些图表也被渲染到网页中,我不想突破盒子模型的边界。
  • 您是自己生成这些图表(svgs)吗?我以为他们是第三方,你无法控制。您需要删除图例上的dy="-8px" 负位置和y 轴上的text-anchor="end"。绘制组件,使它们不会超出边界。需要更多关于这些图表来自何处以及如何生成的信息。
  • 图表是我们自己的内部库,因此我们可以完全控制更改任何和所有 HTML
  • 他们为什么不首先构建没有溢出的 Svg?
  • 不太明白你的意思,但它目前没有“溢出”并且看起来很完美我们只是想在不使用填充的情况下达到相同的结果。即填充强制“行(红色/ blue)" 向右 40px 这是我们想要的,我们只是不想使用 padding 来实现它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-09
  • 2016-07-28
  • 2012-09-28
  • 2013-09-29
  • 1970-01-01
  • 1970-01-01
  • 2013-06-19
相关资源
最近更新 更多