Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to not preserve aspect ratio when resizing an image in d3.js

I have the following HTML:

<div id="MainDiv"></div>

and Javascript code:

    var cursor;
    var width, height;
    var testSVG = {
        x: 0,
        y: 0,
        id: 0,
        image: "https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Small_Flag_of_the_United_Nations_ZP.svg/488px-Small_Flag_of_the_United_Nations_ZP.svg.png",
        width: 280,
        height: 140
    };
    var svgContainer = d3.select("#MainDiv").append("svg").attr({
        width: 1920,
        height: 1080,
        version: 1.1,
        xmlns: "http://www.w3.org/2000/svg",
        viewBox: "-40, -40, 2000, 1160",
        "class": "GraphicDesigner"
    });

    createSVG(svgContainer, testSVG);

    function createSVG(container, object) {
        var d = [{
            x: object.x,
            y: object.y,
            moveX: object.x,
            movey: object.y
        }];
        var svgObjectGroup = container.data(d).append("g").attr("transform", function (d) {
            return "translate(" + d.x + "," + d.y + ")";
        }).call(onDragDrop(dragmove, dropHandler))
          .attr("id", object.ID).attr("class", "masterTooltip");
        svgObjectGroup.append("svg").attr({
            width: object.width,
            height: object.height,
            viewBox: "0, 0, " + object.width + ", " + object.height
        }).append("svg:image")
          .attr({
              preserveAspectRatio: "none",
              width: object.width,
              height: object.height,
              "xlink:href": object.image
          });
        var dragSize = 16;
        svgObjectGroup.append("rect").attr({
            x: object.width - dragSize,
            y: object.height - dragSize,
            width: dragSize,
            height: dragSize,
            rx: 0,
            fill: "#FFFFFF",
            stroke: "black",
            "stroke-width": 1,
            cursor: "se-resize",
            "class": "sizers"
        });
    }

    function onDragDrop(dragHandler, dropHandler) {
        var drag = d3.behavior.drag();
        drag.on("drag", dragHandler).on("dragstart", startHandler).on("dragend", dropHandler);
        return drag;
    }

    function startHandler() {
        cursor = "se";
        d3.event.sourceEvent.stopPropagation();
        if (d3.event.sourceEvent.srcElement.attributes.cursor != undefined) cursor = d3.event.sourceEvent.srcElement.attributes.cursor.nodeValue; //Todo. Doesn't work in IE
    }

    function dragmove() {
        if (cursor != null) {
            if (cursor.startsWith("se")) {
                //South-East
                d3.select(this)[0][0].firstChild.height.baseVal.value = d3.select(this)[0][0].firstChild.height.baseVal.value + d3.event.dy;
                d3.select(this)[0][0].firstChild.width.baseVal.value = d3.select(this)[0][0].firstChild.width.baseVal.value + d3.event.dx;
            }
            var sizers = d3.selectAll(".sizers");
            sizers.remove();
            if (d3.select(this)[0][0].firstChild.height.baseVal.value < 1) d3.select(this)[0][0].firstChild.height.baseVal.value = 1;
            if (d3.select(this)[0][0].firstChild.width.baseVal.value < 1) d3.select(this)[0][0].firstChild.width.baseVal.value = 1;
            height = d3.select(this)[0][0].firstChild.height.baseVal.value;
            width = d3.select(this)[0][0].firstChild.width.baseVal.value;
        }
    }

    function dropHandler() {
        d3.selectAll("svg").remove();
        svgContainer = d3.select("#MainDiv").append("svg").attr({
            width: 1920,
            height: 1080,
            version: 1.1,
            xmlns: "http://www.w3.org/2000/svg",
            viewBox: "-40, -40, 2000, 1160",
            "class": "GraphicDesigner"
        });
        d3.select(this).style("cursor", "default");
        testSVG = {
            x: 0,
            y: 0,
            id: 0,
            image: "https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Small_Flag_of_the_United_Nations_ZP.svg/488px-Small_Flag_of_the_United_Nations_ZP.svg.png",
            width: width,
            height: height
        };
        createSVG(svgContainer, testSVG);
    }

I also have a jsfiddle here: http://jsfiddle.net/Family/zvrfp3oL/

NOTE: This code doesn't work in Internet Explorer, it works in Chrome, Edge and Firefox.

If I try to resize the image by clicking and dragging in the lower right box, the image does resize correctly when the mouse button is released. But, is there a way to correctly show the image while it's being dragged. As it is, as it tries to preserve the aspect ratio it look as though the x and y co-ordinates are moving.

like image 245
Family Avatar asked Sep 26 '22 15:09

Family


1 Answers

You can achieve this by changing the 'background-size' property when resizing.

Need to create an absolutely positioned div inside the resizable div, and add a drag behavior to it.

Here's a jsFiddle. Drag the orange rectangle to resize.

Here's the relevant code:

var resizable = d3.select('#resizable');
var resizer = resizable.select('.resizer');

var dragResize = d3.behavior.drag()
 .on('drag', function() {        
    x = d3.mouse(this.parentNode)[0];
    y = d3.mouse(this.parentNode)[1];

    x = Math.max(50, x);
    y = Math.max(50, y);

    resizable
        .style('background-size', x + 'px' + ' ' + y + 'px')
        .style('width', x + 'px')
        .style('height', y + 'px')
    ;

    resizer
        .style('left', x + 'px')
      .style('top', y + 'px')
    ;
})

resizer.call(dragResize);

CSS:

#resizable {
  position: relative;
  width: 200px;    
  height: 200px;
  background-image: url("https://upload.wikimedia.org/wikipedia/commons/thumb/2/2f/Small_Flag_of_the_United_Nations_ZP.svg/488px-Small_Flag_of_the_United_Nations_ZP.svg.png") ;
  background-size:cover;
  background-repeat:no-repeat;
  // background-position:center;
}

#resizable .resizer {
  position: absolute;
  width: 10px;
  height: 10px;
  bottom: 0;
  right: -10px;
  background: orange;
  opacity: .5;
  cursor: pointer;
}

HTML:

<div id="resizable">
  <div class="resizer"></div>
</div>
like image 141
Osman Mazinov Avatar answered Sep 28 '22 07:09

Osman Mazinov