html 如何在SVG上实现逆透视变换

qf9go6mv  于 2022-11-27  发布在  其他
关注(0)|答案(2)|浏览(260)

假设我有一个div,其中有两个SVG元素:svgPlan***和***svgIcon(这是一个SVG图像元素)。

服务计划

svgIcon

一组转换(透视rotateX缩放***和***平移)应用于父元素**(svgPlan)**:

  1. svg.style('transform', 'perspective(30em) rotateX(33deg) scale(1.7) translate(0%, -6%)');

转换后的svgPlan

我要在***svgPlan***内显示***svgIcon***。

问题:转换同时应用于父元素svgPlan和子元素***svgIcon***。子元素似乎自动继承了应用于父元素的样式,但这不是我所希望的。我希望图标显示时没有任何效果。

问题:我如何取消继承父元素的样式(我认为目前在SVG上是不可能的),或者应用***逆变换***使图标显示时没有任何透视或样式?


指令集

最小可重现示例

  1. <div>
  2. <svg id="svgPlan" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 2118.5 624.2" enable-background="new 0 0 2118.5 624.2" xml:space="preserve"
  3. style="transform:perspective(30em) rotateX(30deg) scale(1.17)">
  4. <rect width="1200" height="400" style="fill:rgb(224,224,224);stroke-width:3;stroke:rgb(0,0,0)" />
  5. <g id="svgIcon">
  6. <image x="550" y="120" width="120" height="120" xlink:href="https://svgshare.com/i/npz.svg">
  7. </image>
  8. </g>
  9. </svg>
  10. </div>

谢谢你的帮助。

lo8azlld

lo8azlld1#

这个答案提出的解决方案与SVG没有太大关系,相反,它使用了更通用的方法,将CSS的透视转换专门应用于HTML元素-其中一些元素可能是SVG图像,也可能包含SVG图像。
先说些琐事:

  • SVG没有第三个维度(“z轴”),因此维度转换或透视在那里是不可能的,unless you do all the maths yourself。它甚至没有z-index,层只是由源(DOM)的外观顺序表示。SVG在本质上实际上只是一个“平面”二维矢量图形。
  • SVG将许多CSS样式属性Map到其表示属性,但由于SVG中没有rotate3dtranslate3drotatex()等,因此它们没有任何效果。
  • HTML中的CSS有这些。
  • 在您的代码片段中,您正在对一个HTML节点应用CSS转换,该节点根据定义只是一个平面上的矩形(就像页面中的所有内容一样)。在您的示例中,该节点是一个SVG元素,但它可以是一个带有背景图像的<div>,也可以只是HTML <img>-在所有情况下,这些都只是“视口”矩形,在无限(可能经过转换)平面内显示(SVG)内容。
  • 所以你不能“从里面弹出东西”;您只能操作由HTML元素组成的“平面”。

据我所知,您的用例是在某个倾斜的图像上方显示标记图标(如“精灵”),这些图标始终面向摄像头(说一个“Map”)。从你的问题中不清楚遥远的图标是否(离摄像头较远的)应较小,并与较近的重叠(什么感觉更自然,但与“非继承”的立场相矛盾)或者每个都是相同的大小,具有未定义的重叠策略。
在“HTML”世界中,您可以嵌套转换后的元素,并让子元素与父元素一起移动(借助transform-style: preserve-3d;),以使它们到达所需的位置,然后将否定转换应用于它们的子元素,使这些子元素再次面向相机。
让我们从基本的纯SVG平面图像开始-带有两个“标记”的“Map”概览,没有转换:

  1. <svg xmlns='http://www.w3.org/2000/svg' viewBox="0 0 800 400"
  2. stroke-width="10" stroke="black" fill="none">
  3. <g transform="translate(100 100)">
  4. <rect width="500" height="200" fill="silver"></rect>
  5. <path d="M 0 200 L 250 100 L 310 30 L 500 200" stroke="white"></path>
  6. <g transform="translate(250 100)">
  7. <circle r="20" fill="darkturquoise"></circle>
  8. <image width="80" height="100" transform="translate(-40 -100)" preserveAspectRatio="none" href="data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-200 -200 400 516' stroke='black' stroke-width='20'%3E%3Cpath fill='red' d='M187-14c-15-232-359-232-374 0l-1 23c0 131 77 244 188 297A329 329 0 0 0 187-14z'/%3E%3Ccircle fill='darkturquoise' r='127'/%3E%3Ctext font-size='150' text-anchor='middle' stroke='none' %3Ea%3C/text%3E%3C/svg%3E"
  9. ></image>
  10. </g>
  11. <g transform="translate(310 30)">
  12. <circle r="20" fill="red"></circle>
  13. <image width="80" height="100" transform="translate(-40 -100)" preserveAspectRatio="none" href="data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-200 -200 400 516' stroke='black' stroke-width='20'%3E%3Cpath fill='darkturquoise' d='M187-14c-15-232-359-232-374 0l-1 23c0 131 77 244 188 297A329 329 0 0 0 187-14z'/%3E%3Ccircle fill='red' r='127'/%3E%3Ctext font-size='150' text-anchor='middle' stroke='none' %3Eb%3C/text%3E%3C/svg%3E"
  14. ></image>
  15. </g>
  16. </g>
  17. </svg>

(我已经将图像图标提取为简化的dataURI,并将位置更改为分组转换,以提高可重用性和独立性。)

现在让我们来介绍一下斜坡和图标“sprites”。

  • SVG现在没有图标,图标是分开的<img>
  • 每个<img>都被定位并转换到Map上的相应位置。这里的自定义属性有助于重用性,但静态值也可以硬编码。
  • 自定义属性--slopecalc也简化了“自动化”,并允许从范围输入启动更改。

第一次
应该呈现如下内容:

对于单个3D变换,这是合适的;对于多个同时的转换,应该包含更多的数学运算或者嵌套更多的转换 Package 器。2请参阅pen中的example of nested transform layers producing sprite-like "dots" in 3d space使用此技术。

展开查看全部
n3h0vuf2

n3h0vuf22#

通过取消rotateX,让图标(放在单独的覆盖svg上)在相同的透视投影下面向viewpoint,可以实现该画面。
例如:

  1. <div>
  2. <svg id="svgPlan" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" x="0px" y="0px" viewBox="0 0 2118.5 624.2" enable-background="new 0 0 2118.5 624.2" preserveAspectRatio="none" style="position: absolute; transform: perspective(30em) rotateX(30deg) scale(1.17) scaleZ(1.17);">
  3. <rect width="1200" height="400" style="fill:rgb(224,224,224);stroke-width:3;stroke:rgb(0,0,0)" />
  4. <rect width="610" height="160" y="240" fill="none" stroke="blue"/>
  5. </svg>
  6. <svg id="svgIcon" xmlns="http://www.w3.org/2000/svg" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" viewBox="0 0 2118.5 624.2" preserveAspectRatio="none"
  7. style="position: absolute;
  8. transform: perspective(30em) rotateX(30deg) scale3d(1.17, 1.17, 1.17)
  9. translate3d(calc(100% * 610 / 2118.5 - 50%), calc(100% * 240 / 624.2 - 50%), 0)
  10. rotateX(-30deg)
  11. translate3d(calc(-100% * 610 / 2118.5 + 50%), calc(-100% * 240 / 624.2 + 50%),0)">
  12. <image x="550" y="120" width="120" height="120" xlink:href="https://i.stack.imgur.com/KZVZ0.png" preserveAspectRatio="xMidYMin slice"></image>
  13. </svg>
  14. </div>

但是,由于透视投影,图标上的缩放效果将保持不变。

应用于图标的转换的简要说明
  • perspective(30em) rotateX(30deg) scale3d(1.17, 1.17, 1.17):套用至svgPlan的转换复本
  • translate3d(calc(100% * 610 / 2118.5 - 50%), calc(100% * 240 / 624.2 - 50%), 0):从css转换原点(50%,50%)转译回原始位置(610,240)
  • rotateX(-30deg):转换以取消旋转
  • translate3d(calc(-100% * 610 / 2118.5 + 50%), calc(-100% * 240 / 624.2 + 50%),0):从图标的底部中心(610,240)到css转换原点(50%,50%)的转换
展开查看全部

相关问题