0
votes

I'm using a resize with KineticJS that i've found and finetuned it to fit my needs(http://www.html5canvastutorials.com/labs/html5-canvas-drag-and-drop-resize-and-invert-images/)

One of those needs is that my users can reset the position of their image to a specific X and Y position and make the image fitting to the drawingBox(Which is defined by the script. It's the box that's center/center and is the part being cutout on save). However; When i resize the image in the top left corner the X and Y become a negative number. So if i want my user to be able to reset their image to, let's say, 0, 0. The 0, 0 line is off after they've resized with the topLeft anchor.

Is there a way to workout to 0, 0 line via an other way. Or perhaps use the group or layer the image it's in as a baseline?

The stage init(It draws 4 rectangles around the border to match the drawbox. Everything will be overlayed except for a box in the center/center which will be the cutout off the image on save.

function initStage(image) {
    stage = new Kinetic.Stage({
        container: 'container',
        width: workspaceWidth,
        height: workspaceHeight
    });



    //Get the top, bottom, left and right square sized. used for X/y positioning and the creation of the ovelray
    var top_bottom_sides = (workspaceHeight-drawboxHeight)/2;
    var left_right_sides = (workspaceWidth-drawboxWidth)/2;

    imageGroupX = left_right_sides;
    imageGroupY = Math.ceil(top_bottom_sides);
    imgGroup = new Kinetic.Group({
        /*x: (workspaceWidth/2)-(image.width/2),
        y: (workspaceHeight/2)-(image.height/2),*/
        x: imageGroupX,
        y: imageGroupY,
        draggable: true,
        dragOnTop: false
    })

    layer = new Kinetic.Layer();
    //add the imgGroup to the layer and the layer to the stage.
    imageImg = new Kinetic.Image({
        /*x: left_right_sides-imgGroup.getX(),
        y: Math.ceil(top_bottom_sides)-imgGroup.getY(),*/
        x: 0,
        y: 0,
        image: image,
        width: image.width,
        height: image.height,
        name: 'image',
    });



    imgGroup.add(imageImg);
    layer.add(imgGroup);

    addAnchor(imgGroup, 0, 0, 'topLeft');
    addAnchor(imgGroup, image.width, 0, 'topRight');
    addAnchor(imgGroup, image.width, image.height, 'bottomRight');
    addAnchor(imgGroup, 0, image.height, 'bottomLeft');

    //Create 4 rectangles and place them around the borders to create an overlay which matches the drawing box
    //Ceil the height to avoid 0.5 pixel overlap on some dimensions
    rect1 = new Kinetic.Rect({  //top
        x: 0,
        y: 0, 
        width: workspaceWidth,
        height: Math.ceil(top_bottom_sides),
        fill: '#000000',
        opacity: 1,
        listening: false
    });

    //Floor the height to not have a 0.5 pixel overlap on some dimensions
    rect2 = new Kinetic.Rect({   // bottom
        x: 0,
        y: Math.ceil(workspaceHeight-top_bottom_sides), 
        width: workspaceWidth,
        height: Math.floor(top_bottom_sides),
        fill: '#000000',
        opacity: 1,
        listening: false
    });

    rect3 = new Kinetic.Rect({ //right
        x: rect1.getWidth()-left_right_sides,
        y: rect1.getX()+rect1.getHeight(), 
        width: left_right_sides,
        height: drawboxHeight,
        fill: '#000000',
        opacity: 1,
        listening: false
    });

    rect4 = new Kinetic.Rect({  //left
        x: rect1.getX(),
        y: rect1.getX()+rect1.getHeight(), 
        width: left_right_sides,
        height: drawboxHeight,
        fill: '#000000',
        opacity: 1,
        listening: false
    });


    layer.add(rect1);
    layer.add(rect2);
    layer.add(rect3);
    layer.add(rect4);

    layer.on('mouseover', function() {
        rect1.setOpacity(0.5);
        rect2.setOpacity(0.5);
        rect3.setOpacity(0.5);
        rect4.setOpacity(0.5);
        layer.draw();
    });

    layer.on('mouseout', function() {
        rect1.setOpacity(1);
        rect2.setOpacity(1);
        rect3.setOpacity(1);
        rect4.setOpacity(1);
        layer.draw();
    });

    stage.add(layer);

    stage.draw();
    fitImage();
}

My update which does the anchor-dragging resize:

function update(activeAnchor, optionalX, optionalY) {
    //var group = activeAnchor.getParent();
    var group = imgGroup;
    var topLeft = group.get('.topLeft')[0];
    var topRight = group.get('.topRight')[0];
    var bottomRight = group.get('.bottomRight')[0];
    var bottomLeft = group.get('.bottomLeft')[0];

    var image = group.get('.image')[0];
    if (optionalX && optionalY) {
        var anchorX = optionalX;
        var anchorY = optionalY;
    } else {
        var anchorX = activeAnchor.getX();
        var anchorY = activeAnchor.getY();
    }


    var activeHandleName = activeAnchor.getName();
    // update anchor positions
    switch (activeHandleName) {
        case 'topLeft':
            topRight.setY(anchorY);
            bottomLeft.setX(anchorX);
        break;
        case 'topRight':
            topLeft.setY(anchorY);
            bottomRight.setX(anchorX);
        break;
        case 'bottomRight':
            bottomLeft.setY(anchorY);
            topRight.setX(anchorX);
        break;
        case 'bottomLeft':
            bottomRight.setY(anchorY);
            topLeft.setX(anchorX); 
        break;
    }

    if (jQuery('#keep_ratio:checked').val() != undefined) {
        // 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());
        }

    } else {
        var newWidth = topRight.getX() - topLeft.getX();
        var newHeight = bottomLeft.getY() - topLeft.getY();
        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);

    var width = newWidth;
    var height = newHeight;

    if(width && height) {
        width = Math.round(width);
        height = Math.round(height);

        image.setSize(width, height);
    }
}

The fitImage function and the setSizeManually:

function fitImage() {
if (imageImg) {
    var widthDifference = (imageImg.getWidth() > drawboxWidth) ? imageImg.getWidth()-drawboxWidth : drawboxWidth-imageImg.getWidth();
    var heightDifference = (imageImg.getHeight() > drawboxHeight) ? imageImg.getHeight()-drawboxHeight : drawboxHeight-imageImg.getHeight();

    var ratio = imageImg.getWidth()/imageImg.getHeight();

    if (widthDifference > heightDifference) {
        //Fit the image horizontally and scale it vertically
        var newHeight = Math.ceil(drawboxWidth / ratio);
        var newWidth = drawboxWidth+1;
    } else {
        //Fit the image vertically and scale it horizontally
        var newWidth = Math.round(drawboxHeight * ratio);
        var newHeight = drawboxHeight+1;
    }

    imageImg.setWidth(newWidth);
    imageImg.setHeight(newHeight);
    setSizeManually(newWidth, newHeight);
}
}

function setSizeManually(width, height, isSlider) {
    var stage = imgGroup.getStage();
    update(imgGroup.get('.bottomRight')[0], width, height, isSlider);
    stage.draw();
}
1
while all your code is appreciated, put together a working jsfiddle or jsbin or such, so that people, like me, can play with your code and help you out some more. - SoluableNonagon
also, your explanation is kind of confusing, I can't tell when you mean line or anchor or what you're trying to reset, but I'll try and help you out. See comment below. - SoluableNonagon

1 Answers

1
votes

I can't completely tell what you want to do, but here goes:

If you want to move an object to a position, you can do:

 object.setPosition(0,0);

In your case, your image is contained in a group, so I would take this kind of approach (with notes)

 function resetImage(imageGroup, resetToX, resetToY){ // give the group and the x,y you want it moved to
     var groupChildren = imageGroup.getChildren(); // get image and anchors
     // in your code, the first item added is an image, then four anchor points, from top left clockwise
     var currentImageWidth = groupChildren[0].getWidth(); // will need this to calculate anchor points position
     var currentImageHeight = groupChildren[0].getHeight(); // same as above
     groupChildren[0].setPosition(resetToX, resetToY); // reset the image to this position, you could also do .setAbsolutePosition(resetToX, resetToY);
     groupChildren[1].setPosition(resetToX, resetToY); //reset topLeft anchor
     groupChildren[2].setPosition(resetToX+currentImageWidth, resetToY); //reset topRight anchor
     groupChildren[3].setPosition(resetToX+currentImageWidth, resetToY+currentImageHeight); // reset bottomRight anchor
     groupChildren[4].setPosition(resetToX, resetToY+currentImageHeight); // reset bottomLeft anchor
     imageGroup.getLayer().draw(); //redraw layer once everything resets
 }