使用动力学js画布保持比例调整图像大小

时间:2012-10-30 13:06:28

标签: javascript image html5 html5-canvas kineticjs

我在我的应用中使用它:

http://www.html5canvastutorials.com/labs/html5-canvas-drag-and-drop-resize-and-invert-images/

使用锚来调整图像大小..

我想要的是调整图像大小并保持其比例。 我不希望它伸展 我能够使用这种代码的和平来实现这一点。:..

  if(width) {
        image.setSize(width);
      }

但这会搞砸锚.. 有人试过这样的事情......

4 个答案:

答案 0 :(得分:10)

我知道这是一个非常古老的帖子,但是我需要实现这个确切的事情并且发现接受的答案是非常有缺陷的 - 左边两个拖动手柄移动整个图像并且与图像编辑程序不同,例如。我发布了我的解决方案,以防有人像我一样从谷歌搜索中绊倒了这个。

// Update the positions of handles during drag.
// This needs to happen so the dimension calculation can use the
// handle positions to determine the new width/height.
switch (activeHandleName) {
    case "topLeft":
        topRight.setY(activeHandle.getY());
        bottomLeft.setX(activeHandle.getX());
        break;
    case "topRight":
        topLeft.setY(activeHandle.getY());
        bottomRight.setX(activeHandle.getX());
        break;
    case "bottomRight":
        bottomLeft.setY(activeHandle.getY());
        topRight.setX(activeHandle.getX());
        break;
    case "bottomLeft":
        bottomRight.setY(activeHandle.getY());
        topLeft.setX(activeHandle.getX());
        break;
}

// Calculate new dimensions. Height is simply the dy of the handles.
// Width is increased/decreased by a factor of how much the height changed.
newHeight = bottomLeft.getY() - topLeft.getY();
newWidth = image.getWidth() * newHeight / image.getHeight();

// Move the image to adjust for the new dimensions.
// The position calculation changes depending on where it is anchored.
// ie. When dragging on the right, it is anchored to the top left,
//     when dragging on the left, it is anchored to the top right.
if(activeHandleName === "topRight" || activeHandleName === "bottomRight") {
    image.setPosition(topLeft.getX(), topLeft.getY());
} else if(activeHandleName === "topLeft" || activeHandleName === "bottomLeft") {
    image.setPosition(topRight.getX() - newWidth, topRight.getY());
}

imageX = image.getX();
imageY = image.getY();

// Update handle positions to reflect new image dimensions
topLeft.setPosition(imageX, imageY);
topRight.setPosition(imageX + newWidth, imageY);
bottomRight.setPosition(imageX + newWidth, imageY + newHeight);
bottomLeft.setPosition(imageX, imageY + newHeight);

// Set the image's size to the newly calculated dimensions
if(newWidth && newHeight) {
     image.setSize(newWidth, newHeight);
}

JSBin中修改的KineticJS示例:http://jsbin.com/iyimuy/1/edit

答案 1 :(得分:1)

更改行:

var width = topRight.attrs.x - topLeft.attrs.x;
var height = bottomLeft.attrs.y - topLeft.attrs.y;
if(width && height) {
    image.setSize(width, height);
}

要:

var height = bottomLeft.attrs.y - topLeft.attrs.y;
var width = image.getWidth()*height/image.getHeight();

topRight.attrs.x = topLeft.attrs.x + width;
topRight.attrs.y = topLeft.attrs.y;
bottomRight.attrs.x = topLeft.attrs.x + width;
bottomRight.attrs.y = topLeft.attrs.y + height;

if(width && height) {
    image.setSize(width, height);
}

Example

答案 2 :(得分:1)

这是:JSFIDDLE

JS:

function update(group, activeHandle) {
        var topLeft = group.get(".topLeft")[0],
            topRight = group.get(".topRight")[0],
            bottomRight = group.get(".bottomRight")[0],
            bottomLeft = group.get(".bottomLeft")[0],
            image = group.get(".image")[0],
            activeHandleName = activeHandle.getName(),
            newWidth,
            newHeight,
            minWidth = 32,
            minHeight = 32,
            oldX,
            oldY,
            imageX,
            imageY;

        // Update the positions of handles during drag.
        // This needs to happen so the dimension calculation can use the
        // handle positions to determine the new width/height.
        switch (activeHandleName) {
            case "topLeft":
                oldY = topRight.getY();
                oldX = bottomLeft.getX();
                topRight.setY(activeHandle.getY());
                bottomLeft.setX(activeHandle.getX());
                break;
            case "topRight":
                oldY = topLeft.getY();
                oldX = bottomRight.getX();
                topLeft.setY(activeHandle.getY());
                bottomRight.setX(activeHandle.getX());
                break;
            case "bottomRight":
                oldY = bottomLeft.getY();
                oldX = topRight.getX();
                bottomLeft.setY(activeHandle.getY());
                topRight.setX(activeHandle.getX());
                break;
            case "bottomLeft":
                oldY = bottomRight.getY();
                oldX = topLeft.getX();
                bottomRight.setY(activeHandle.getY());
                topLeft.setX(activeHandle.getX());
                break;
        }



        // Calculate new dimensions. Height is simply the dy of the handles.
        // Width is increased/decreased by a factor of how much the height changed.
        newHeight = bottomLeft.getY() - topLeft.getY();
        newWidth = image.getWidth() * newHeight / image.getHeight();

        // It's too small: move the active handle back to the old position
        if( newWidth < minWidth || newHeight < minHeight ){
          activeHandle.setY(oldY);
          activeHandle.setX(oldX);
          switch (activeHandleName) {
            case "topLeft":
                topRight.setY(oldY);
                bottomLeft.setX(oldX);
                break;
            case "topRight":
                topLeft.setY(oldY);
                bottomRight.setX(oldX);
                break;
            case "bottomRight":
                bottomLeft.setY(oldY);
                topRight.setX(oldX);
                break;
            case "bottomLeft":
                bottomRight.setY(oldY);
                topLeft.setX(oldX);
                break;
          }
        }


        newHeight = bottomLeft.getY() - topLeft.getY();
        //comment the below line and uncomment the line below tha line to allow free resize of the images because the below line preserves the scale and aspect ratio
        newWidth = image.getWidth() * newHeight / image.getHeight();//for restricted resizing
        //newWidth = topRight.getX() - topLeft.getX();//for free resizing

        // Move the image to adjust for the new dimensions.
        // The position calculation changes depending on where it is anchored.
        // ie. When dragging on the right, it is anchored to the top left,
        //     when dragging on the left, it is anchored to the top right.
        if(activeHandleName === "topRight" || activeHandleName === "bottomRight") {
            image.setPosition(topLeft.getX(), topLeft.getY());
        } else if(activeHandleName === "topLeft" || activeHandleName === "bottomLeft") {
            image.setPosition(topRight.getX() - newWidth, topRight.getY());
        }

        imageX = image.getX();
        imageY = image.getY();

        // Update handle positions to reflect new image dimensions
        topLeft.setPosition(imageX, imageY);
        topRight.setPosition(imageX + newWidth, imageY);
        bottomRight.setPosition(imageX + newWidth, imageY + newHeight);
        bottomLeft.setPosition(imageX, imageY + newHeight);

        // Set the image's size to the newly calculated dimensions
        if(newWidth && newHeight) {
            image.setSize(newWidth, newHeight);
        }
      }
      function addAnchor(group, x, y, name) {
        var stage = group.getStage();
        var layer = group.getLayer();

        var anchor = new Kinetic.Circle({
          x: x,
          y: y,
          stroke: "#666",
          fill: "#ddd",
          strokeWidth: 2,
          radius: 8,
          name: name,
          draggable: true
        });

        anchor.on("dragmove", function() {
          update(group, this);
          layer.draw();
        });
        anchor.on("mousedown touchstart", function() {
          group.setDraggable(false);
          this.moveToTop();
        });
        anchor.on("dragend", function() {
          group.setDraggable(true);
          layer.draw();
        });
        // add hover styling
        anchor.on("mouseover", function() {
          var layer = this.getLayer();
          document.body.style.cursor = "pointer";
          this.setStrokeWidth(4);
          layer.draw();
        });
        anchor.on("mouseout", function() {
          var layer = this.getLayer();
          document.body.style.cursor = "default";
          this.setStrokeWidth(2);
          layer.draw();
        });

        group.add(anchor);
      }
      function loadImages(sources, callback) {
        var images = {};
        var loadedImages = 0;
        var numImages = 0;
        for(var src in sources) {
          numImages++;
        }
        for(var src in sources) {
          images[src] = new Image();
          images[src].onload = function() {
            if(++loadedImages >= numImages) {
              callback(images);
            }
          };
          images[src].src = sources[src];
        }
      }
      function initStage(images) {
        var stage = new Kinetic.Stage({
          container: "container",
          width: 578,
          height: 400
        });
        var darthVaderGroup = new Kinetic.Group({
          x: 270,
          y: 100,
          draggable: true
        });
        var yodaGroup = new Kinetic.Group({
          x: 100,
          y: 110,
          draggable: true
        });
        var layer = new Kinetic.Layer();

        /*
         * go ahead and add the groups
         * to the layer and the layer to the
         * stage so that the groups have knowledge
         * of its layer and stage
         */
        layer.add(darthVaderGroup);
        layer.add(yodaGroup);
        stage.add(layer);

        // darth vader
        var darthVaderImg = new Kinetic.Image({
          x: 0,
          y: 0,
          image: images.darthVader,
          width: 200,
          height: 138,
          name: "image"
        });

        darthVaderGroup.add(darthVaderImg);
        addAnchor(darthVaderGroup, 0, 0, "topLeft");
        addAnchor(darthVaderGroup, 200, 0, "topRight");
        addAnchor(darthVaderGroup, 200, 138, "bottomRight");
        addAnchor(darthVaderGroup, 0, 138, "bottomLeft");

        darthVaderGroup.on("dragstart", function() {
          this.moveToTop();
        });
        // yoda
        var yodaImg = new Kinetic.Image({
          x: 0,
          y: 0,
          image: images.yoda,
          width: 93,
          height: 104,
          name: "image"
        });

        yodaGroup.add(yodaImg);
        addAnchor(yodaGroup, 0, 0, "topLeft");
        addAnchor(yodaGroup, 93, 0, "topRight");
        addAnchor(yodaGroup, 93, 104, "bottomRight");
        addAnchor(yodaGroup, 0, 104, "bottomLeft");

        yodaGroup.on("dragstart", function() {
          this.moveToTop();
        });

        stage.draw();
      }

      var sources = {
        darthVader: 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg',
        yoda: 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg'
      };
      loadImages(sources, initStage);

答案 3 :(得分:0)

我知道这不是问题,但是当锚点超出图像0大小时,我已经失去了大量时间来解决问题,这会引发javasacript错误:

IndexSizeError: Index or size is negative or greater than the allowed amount

我所做的是将Math.abs添加到图像大小计算公式中:

newHeight = Math.abs(bottomLeft.getY() - topLeft.getY()); 
newWidth = Math.abs(image.getWidth() * newHeight / image.getHeight());

它与两个底部锚点都能正常工作,但顶部锚点效果不太好,我只是移除了顶部锚点,这对于我的项目来说已经足够好了....

希望这有助于某人!