SVG坐标系翻转

88

有没有一种方法可以翻转SVG坐标系,使得[0,0]在左下角而不是左上角?

10个回答

87

我进行了大量实验,唯一合理的方法如下:

<g transform="translate(0,400)">
<g transform="scale(1,-1)">

这里的400是图片的高度。这样做的效果是将所有内容向下移动,以使得图片顶部与页面顶部对齐,然后缩放操作会翻转Y坐标,使得现在位于页面/图片之外的部分被翻转回来填充留下来的空间。


5
你需要第一次翻译的结果吗?我已经通过 viewbox="-200 -200 400 400" 完成了翻译。 - SimplyKnownAsG
9
这些操作可以在一行中组合。 <g transform="translate(0,100) scale(1,-1)">(注:这是SVG语言中的一段代码,表示对该元素进行平移和缩放操作) - Paul Williams
27
但现在文本是倒过来的。 - Chris Sattinger
6
你可以使用单一的“矩阵(matrix)”变换替代独立的“平移(translate)”和“缩放(scale)”变换。要翻转y轴,请尝试使用<g transform="matrix(1 0 0 -1 0 400)">(其中400是图像的高度)。 - r3mainer
3
@felix 你是如何解决倒置文本的问题的? - sourabh dadapure
显示剩余3条评论

44
我发现将坐标系转换为笛卡尔坐标系的最佳组合非常简单: css

svg.cartesian {
  display:flex;
}

/* Flip the vertical axis in <g> to emulate cartesian. */
svg.cartesian > g {
  transform: scaleY(-1);
}

/* Re-flip all <text> element descendants to their original side up. */
svg.cartesian > g text {
  transform: scaleY(-1);
}
<html>
  <head></head>
  <body>

  <svg class="cartesian" viewBox="-100 -100 200 200" preserveAspectRatio="xMidYMid meet">
  <g>
    <!-- SVG Start -->

    <!-- Vertical / Horizontal Axis: Can be removed if you don't want x/y axes. -->
    <path d="M0 -100 V 200" stroke="green" stroke-width="0.5" stroke-opacity="0.5" />
    <path d="M-100 0 H 200" stroke="green" stroke-width="0.5" stroke-opacity="0.5" />
    
    <!-- Plotting: This is an example plotting two points at (20, 20) and (-50, -35), replace it with your data. -->
    <g transform="translate(20, 20)">
      <circle r="1" />
      <text>(20, 20)</text>
    </g>
    <g transform="translate(-50, -35)">
      <circle r="0.5" />
      <text>(-50, -35)</text>
    </g>

    <!-- SVG End -->
  </g>
  </svg>
    </body>
  </html>

这将通过 CSS 的 scaleY(-1) 自动翻转页面上的所有文本元素。

7
在我看来,这个回答有点被低估了。 - jiron
1
谢谢!我很高兴把这个写下来了。每当我需要做这个的时候,我都会回来参考它。我刚刚更新了注释,解释了各个部分的作用,使得使用起来更加容易。 - cchamberlain
1
这个可能需要更多的解释。我已经让它工作了,但并不是很简单。我想加一些说明,但还没有完全理解... - Tony
1
@Tony - 我在注释中添加了更多信息。请告诉我具体哪里令人困惑,我会尽力改进它。 - cchamberlain
1
谢谢更新。我在CSS中添加了一些注释,现在我认为它非常易懂。 - Tony
显示剩余4条评论

14

我知道这已经过时了,但我正在做同样的事情,尝试了@Nippysaurus的版本,但由于所有内容都将被旋转(因此如果您放置图像,则必须将它们旋转回来),这太烦人了。不过有另一种解决方案。

我所做的就是简单地移动svg的viewBox,并在y轴上反转所有坐标(还删除了对象的高度,使其位于左下角),如下:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="300" viewBox="0 -300 200 300">
  <rect x="20" y="-40" width="20" height="20" stroke="black" stroke-width="1px"></rect>
</svg>

这将在svg的左下角距离为20,20处放置一个rect,见http://jsfiddle.net/DUVGz/


乍一看,这似乎是一个临时解决方案,然而,在尝试了所有其他解决方案之后,我不得不同意@Guillaume的观点,即由于对文本等的影响,所有“transform”解决方案都很麻烦,因此这是我采用的SVG输出解决方案。 - Grimxn
但是,转换在嵌套组中如何扩展?即嵌套组... - user3638471

6

4

是的,先进行一个-90度的坐标旋转,然后再进行一个+新图形高度的平移即可。在W3C有一个示例。


我认为你想要的是先旋转180度,然后再进行-w和-h的平移。但这样做是不行的,因为[0,0]仍然在左上角。 - Nippysaurus
我怀疑你的SVG实现不符合规范,这并不令人感到惊讶,因为它是一个(可能)很少被使用的功能。-90度的仿射旋转将笛卡尔象限IV(+x、-y)移动到象限I(+x、+y)。180度的旋转会将你的参考框架置于象限II中,并将原点放在左下角。你自己的答案之所以有效是因为它与我的原始答案相似,但可能使用了更好测试的SVG解释器的位元。就个人而言,我只会在用户空间的代码中计算仿射变换,并对SVG的能力持悲观态度。 - msw
你可能是对的。我正在使用OS X 10.6上的Safari,所以明天会在Windows机器上测试它。 - Nippysaurus

3
<g transform="translate(0,400) scale(1,-1)">

这也等同于以下内容:

<g transform="scale(1,-1) translate(0,-400) ">

0
你可以使用matrix()

<g transform="matrix(1 0 0 -1 0 svgHeight)">

因为

matrix(a b c d e f)如下所示。

| a c e |
| b d f |
| 0 0 1 |

(x,y)
| x |
| y |
| 1 |

matrix(a b c d e f) . (x,y)
| a c e |    |x|    | ax+cy+e |
| b d f ||y|  = | bx+dy+f | 
| 0 0 1 |    |1|    | 0x+0y+1 |

什么时候

a, b, c,  d, e, f          
1, 0, 0, -1, 0, heght
=>
| ax+cy+e |    | x           |
| bx+dy+f |  = | -y + height |
| 0x+0y+1 |    | 1           |

示例

<style>
  svg {
    border: 1px solid
  }
</style>
<table>
  <tr>
    <th>org</th>
    <th>svg</th>
  </tr>
  <tr>
    <td>top left</td>
    <td>
      <svg width="100" height="100" stroke="black">
        <path d="
      M 50 70
      L 80 30
      "/>
        <circle fill='#ff0000' cx="50" cy="70" r="2"></circle>
        <text x=55 y=75 style="font-size: 10px;" fill="blue">(50, 70)</text>
        
        <!-- x -->
        <!-- https://bennettfeely.com/clippy/ -->
        <polygon points="30 7 10 15 10 0" fill="gray" />
        <!-- y -->
        <polygon points="15,20 0,20 7 40" fill="gray" />
      </svg>
    </td>
  </tr>

  <tr>
    <td>bottom left</td>
    <td>
      <svg width="100" height="100" stroke="black">
        <g transform="matrix(1 0 0 -1 0 100)"> <!--  -->
          <path d="
      M 50 70
      L 80 30
      "/>
          <circle fill='#ff0000' cx="50" cy="70" r="2"></circle>

          <!-- x -->
          <polygon points="30 7 10 15 10 0" fill="gray" />
          <!-- y -->
          <polygon points="15,20 0,20 7 40" fill="gray" />
        </g>
        <!-- y=-75+100=25 -->
        <text x=55 y=25 style="font-size: 10px;" fill="blue">(50, 70)</text>
      </svg>
    </td>
  </tr>
</table>


-1

另一种选择是使用 D3 v4 scaleLinear ,创建一个能够为您执行交换的函数。

import * as d3 from "d3";

...

// Set the height to the actual value to where you want to shift the coords.
// Most likely based on the size of the element it is contained within
let height = 1; 
let y = d3.scaleLinear()
  .domain([0,1])
  .range([height,0]);

console.log("0 = " + y(0));       // = 1
console.log("0.5 = " + y(0.5));   // = 0.5
console.log("1 = " + y(1));       // = 0
console.log("100 = " + y(100));   // = -99
console.log("-100 = " + y(-100)); // = 101

请查看通过tonic运行的可执行代码


-2
通常我所做的是在笛卡尔平面上将坐标绘制/放置在y轴负值处。然后通过将y轴负值替换为正值来转移坐标。

-7

我认为将元素旋转180度的最简单方法是将其旋转180.1度;

transform="translate(180.1,0,0)"


翻译函数只需要两个参数,即x和y坐标。我认为它不接受3D坐标(x,y,z)。如果您打算使用3D坐标,则必须使用translate3d(),该函数需要3个坐标。请查看文档:https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/translate - ShellZero

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接