简体   繁体   中英

Is SVG resizing this hard ? What am I missing?

I am trying to write code that resizes an SVG overlay on top of an image. The server I am working with returns both the image and via an API, a list of polygon points I need to overlay on top of the image.

This is what it should look like (the image below is a correctly aligned SVG layer). The image size is 1280x720 (I've scaled it down) 在此处输入图片说明

What I need to do in my app (ionic v1 app) is to make sure the SVG overlay resizes as the browser window resizes and it seems to be very hard. Here is my approach:

I am trapping a window resize event and when the image is resized, I scale the SVG polygon points relative to the size of the drawn window as it seems there is really no way to "automatically" scale the SVG by the browser like it does with an image.

Here is my code pen as you see it doesn't work as intended when I rescale (and for that matter in when its full size the overlays are not accurate). The overlays don't look accurate and when I resize it all messed up. Can someone help?

Given SO needs a code block for codepen links here it is, but its just easier to look at the codepen if you want to run it

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 code:

<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 controller:

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]);
                    }


                });
            }

There are a couple of issues with your code.

The main problem is you can't use ng-attr-viewBox , because angular will "normalise" the attribute to lower case. It turns the attribute into viewbox (lower case B) which is (currently) invalid. viewBox is case sensitive.

The solution is to use a special trick of Angular to preserve camel-case. If you use ng-attr-view_box , it will generate the correctly camel-cased attribute name of viewBox .

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

The other thing is that you are using the wrong width and height values for the viewBox. You need to use the natural/intrinsic image dimensions in your viewBox.

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

Link to updated code pen

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM