【问题标题】:Is SVG resizing this hard ? What am I missing?SVG 调整大小这么难吗?我错过了什么?
【发布时间】:2017-05-15 22:47:56
【问题描述】:

我正在尝试编写代码来调整图像顶部的 SVG 叠加层的大小。我正在使用的服务器返回图像并通过 API 返回我需要覆盖在图像顶部的多边形点列表。

这就是它的样子(下图是正确对齐的 SVG 图层)。图像尺寸为 1280x720(我已按比例缩小)

我需要在我的应用程序(ionic v1 应用程序)中做的是确保 SVG 覆盖随着浏览器窗口大小的调整而调整,这似乎非常困难。这是我的方法:

我正在捕获一个窗口调整大小事件,当调整图像大小时,我会相对于绘制窗口的大小缩放 SVG 多边形点,因为似乎真的没有办法像浏览器一样“自动”缩放 SVG它与图像有关。

Here is my code pen 如您所见,当我重新缩放时它无法按预期工作(就此而言,当它的全尺寸覆盖不准确时)。叠加层看起来不准确,当我调整大小时,一切都搞砸了。有人可以帮忙吗?

鉴于 SO 需要一个用于 codepen 链接的代码块,但如果你想运行它,查看 codepen 会更容易

CSS:

.imagecontainer{position:relative; margin:0 auto;}

.zonelayer
{
    position:absolute;
    top:0;
    left:0;
    background:none;

}

.zonelayer polygon {
    fill-opacity: 0.25;
    stroke-width: 2px;
}

.Active {
    stroke: #ff0000;
    fill: #ff0000;
}

HTML 代码:

<ion-content>
        image:{{disp}}<br/>
      <small>points: <span ng-repeat="item in zoneArray">{{item}}</span></small>
        <div class="imagecontainer">

            <img id="singlemonitor" style="width:100vw; height:100vh;object-fit:contain" ng-src="http://m9.i.pbase.com/o9/63/103963/1/164771719.2SfdldRy.nphzms.jpeg"  />
            <div class="zonelayer">
                <svg ng-attr-width="{{cw}}" ng-attr-height="{{ch}}" class="zonelayer" ng-attr-viewBox="0 0 {{cw}} {{ch}}">
                    <polygon ng-repeat="item in zoneArray"  ng-attr-points="{{item}}" class="Active"/> </polygon>

                </svg>
            </div>
        </div>

    </ion-content>

JS 控制器:

window.addEventListener('resize', liveloaded);
  liveloaded();
  // credit: http://stackoverflow.com/questions/41411891/most-elegant-way-to-parse-scale-and-re-string-a-string-of-number-co-ordinates?noredirect=1#41411927
    function scaleCoords(string, sx, sy) {
        var f = [sx, sy];
        return string.split(' ').map(function (a) {
            return a.split(',').map(function (b, i) {
                return Math.round(b * f[i]);
            }).join(',');
        }).join(' ');
    }

  function liveloaded()
  {

        $timeout (function () {
                    console.log ("IMAGE LOADED");
                    var img =document.getElementById("singlemonitor");

                    //var offset = img.getBoundingClientRect();
                    $scope.cw = img.clientWidth;
                    $scope.ch = img.clientHeight;
                    $scope.vx = img.offsetWidth;
                    $scope.vy = img.offsetHeight;

                    var rect = img.getBoundingClientRect();
                    //console.log(rect.top, rect.right, rect.bottom, rect.left);
                    $scope.disp = img.clientWidth+ "x"+img.clientHeight + " with offsets:"+$scope.vx+"/"+$scope.vy;

                    $scope.zoneArray = [
                    "598,70 700,101 658,531 516,436",
                    "531,243 687,316 663,593 360,717 191,520",
                    "929,180 1108,248 985,707 847,676",
                    "275,17 422,45 412,312 271,235",
                    ];

                    var ow = 1280;
                    var oh = 720;

                    for (var i=0; i < $scope.zoneArray.length; i++)
                    {
                        var sx = $scope.cw/ow;
                        var sy = $scope.ch/oh;
                        $scope.zoneArray[i] = scaleCoords($scope.zoneArray[i],sx,sy);
                        console.log ("SCALED:"+$scope.zoneArray[i]);
                    }


                });
            }

【问题讨论】:

  • “鉴于 SO 需要一个用于 codepen 链接的代码块,它是” - 不,不要那样做。只需在帖子中包含您的代码,而不是试图欺骗过滤器!
  • 完成 - 我这样做的原因是有多个部分要发布以使其有意义,而 codepen 只是让所有的工作和运行
  • 您是否有理由无法将 SVG 加载到 &lt;img /&gt; 元素中并让浏览器为您调整其大小?
  • 我希望能够做到这一点,但服务器通过在我的应用程序中动态检索的 API 返回点(示例中的硬编码坐标是一种简化) .我该怎么做呢?
  • 你为什么说“真的没有办法像处理图像那样通过浏览器“自动”缩放 SVG”?您很明显可以:只需将 SVG 上的 viewBox 设置为原始大小,然后调整 SVG 的大小。或者,您可以只对 SVG 元素或其任何子元素应用变换。

标签: javascript angularjs svg


【解决方案1】:

您的代码存在几个问题。

主要问题是您不能使用ng-attr-viewBox,因为角度会将属性“规范化”为小写。它将属性转换为viewbox(小写B)(当前)无效。 viewBox 区分大小写。

解决方案是使用 Angular 的特殊技巧来保留驼峰式。如果使用ng-attr-view_box,它将生成viewBox 的正确驼峰式属性名称。

<svg width="100vw" height="100vh" class="zonelayer" ng-attr-view_box="0 0 {{cw}} {{ch}}">

另一件事是您为 viewBox 使用了错误的宽度和高度值。您需要在 viewBox 中使用自然/固有的图像尺寸。

$scope.cw = img.naturalWidth;
$scope.ch = img.naturalHeight;

Link to updated code pen

【讨论】:

  • 谢谢保罗。我做了一个快速检查 - 在 Chrome 上工作,但 SVG 根本没有出现在 Safari 上。正在调试中!
  • 不太确定您的 codepen 出了什么问题,但将您的建议纳入我的 codepen codepen.io/pliablepixels/pen/apoJyj 效果很好!做更多的测试。这个 viewBox 技巧对我来说是不可能的(据我所知)。谢谢!
  • Paul,快速提问,如果我将图像从 object-fit:contain 更改为 object-fit:cover,我需要什么魔法才能正确映射 svg?将其样式更改为相同的对象匹配似乎根本不起作用
  • 将以下内容添加到您的&lt;svg&gt; 标记中即可:preserveAspectRatio="xMidYMid slice"
  • 谢谢 - ng-attr-preserve_aspect_ratio={{ar}} where ar = "none" or "xMidYMid slice" (因为我需要在填充和包含之间切换)似乎不起作用(你的建议有效,我的 ng- attr 方法不是)
猜你喜欢
  • 2012-05-01
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 2010-10-16
  • 1970-01-01
  • 2013-12-27
  • 1970-01-01
  • 2016-11-01
相关资源
最近更新 更多