Question

I have a kineticjs canvas with image upload and text input, both functions are working fine but I can't get the image resize anchors to show... I need to get the image resize anchors to show "onClick" of the image.

any help is much appreciated :) thanks in advance.

here is the js

var stage = new Kinetic.Stage({
    container: 'container',
    width: 375,
    height: 200
});

var layer = new Kinetic.Layer();

//image loader
var imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', handleImage, false);

function handleImage(e){
    var reader = new FileReader();
    reader.onload = function(event){
        var img = new Image();
        img.onload = function(){
            layer.add(new Kinetic.Image({
                x: 100,
                y: 50,
                image: img,
                width: 200,
                height: 130,
                draggable: true
            }));
            text.moveToTop();
            stage.draw();
        };
        console.log(event);
        img.src = event.target.result;
    };
    reader.readAsDataURL(e.target.files[0]);     
}

// parameters
var resizerRadius = 3;
var rr = resizerRadius * resizerRadius;

// constant
var pi2 = Math.PI * 2;

function draw(img, withAnchors, withBorders) {
    // clear the canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    // draw the image
    var view = img.view;
    ctx.drawImage(img, 0, 0, img.width, img.height, view.left, view.top, view.width, view.height);

    // optionally draw the draggable anchors
    if (withAnchors) {
        drawDragAnchor(view.left, view.top);
        drawDragAnchor(view.left + view.width, view.top);
        drawDragAnchor(view.left + view.width, view.top + view.height);
        drawDragAnchor(view.left, view.top + view.height);
    }

    // optionally draw the connecting anchor lines
    if (withBorders) {
        ctx.beginPath();
        ctx.rect(view.left, view.top, view.width, view.height);
        ctx.stroke();
    }
    drawText();
}

function drawDragAnchor(x, y) {
    ctx.beginPath();
    ctx.arc(x, y, resizerRadius, 0, pi2, false);
    ctx.closePath();
    ctx.fill();
}

function drawText(){
    var x = 40,
        y = 100;
    ctx.font = "bold 20px sans-serif";
    ctx.fillStyle = "black";
    ctx.fillText($("#textBox").val(), x, y);
}

// -------------------------------------------
//        -        Hit Testing        -
// -------------------------------------------

// return 0,1,2, or 3 if (x,y) hits the respective anchor
//   of the given view.
// return -1 if no anchor hit.
function anchorHitTest(view, x, y) {
    var dx, dy;
    x -= view.left;
    y -= view.top;
    // top-left
    dx = x;
    dy = y;
    if (dx * dx + dy * dy <= rr) return (0);
    // top-right
    dx = x - view.width;
    dy = y;
    if (dx * dx + dy * dy <= rr) return (1);
    // bottom-right
    dx = x - view.width;
    dy = y - view.height;
    if (dx * dx + dy * dy <= rr) return (2);
    // bottom-left
    dx = x;
    dy = y - view.height;
    if (dx * dx + dy * dy <= rr) return (3);
    return (-1);
}

// return true if (x,y) lies within the view
function hitImage(view, x, y) {
    x -= view.left;
    y -= view.top;
    return (x > 0 && x < view.width && y > 0 && y < view.height);
}

// -------------------------------------------
//        -        Mouse        -
// -------------------------------------------

var mousePos = {
    x: 0,
    y: 0
};
var draggingImage = false;
var startX, startY;
var isDown = false;

var currentImg = null;

var draggingResizer;

function updateMousePos(e) {
    var canvasOffset = $("#canvas").offset();
    var offsetX = canvasOffset.left;
    var offsetY = canvasOffset.top;
    updateMousePos = function (e) {
        mousePos.x = parseInt(e.clientX - offsetX);
        mousePos.y = parseInt(e.clientY - offsetY);
    };
    return updateMousePos(e);
}


function handleMouseDown(e) {
    updateMousePos(e);
    // here you could make a loop to see which image / anchor was clicked
    draggingResizer = anchorHitTest(img.view, mousePos.x, mousePos.y);
    draggingImage = draggingResizer < 0 && hitImage(img.view, mousePos.x, mousePos.y);
    // 
    if (draggingResizer<0 && !draggingImage) return;
    startX = mousePos.x;
    startY = mousePos.y;
    currentImg = img;
}

function handleMouseUp(e) {
    if (!currentImg) return;
    draggingResizer = -1;
    draggingImage = false;
    draw(currentImg, true, false);
    currentImg = null;
}

function handleMouseOut(e) {
    handleMouseUp(e);
}

function handleMouseMove(e) {
    if (!currentImg) return;
    updateMousePos(e);

    var view = currentImg.view;
    if (draggingResizer > -1) {
        var oldView = {
            left: view.left,
            top: view.top,
            width: view.width,
            height: view.height
        };
        // resize the image
        switch (draggingResizer) {
            case 0:
                cl('ttoo');
                //top-left
                view.left = mousePos.x;
                view.top = mousePos.y;
                view.width = oldView.left + oldView.width - mousePos.x;
                view.height = oldView.top + oldView.height - mousePos.y;
                break;
            case 1:
                //top-right
                // view.left  unchanged             
                view.top = mousePos.y;
                view.width = mousePos.x - oldView.left;
                view.height = oldView.top + oldView.height - mousePos.y;
                break;
            case 2:
                //bottom-right
                view.width = mousePos.x - oldView.left;
                view.height = mousePos.y - oldView.top;
                break;
            case 3:
                //bottom-left
                view.left = mousePos.x;
                view.width = oldView.left + oldView.width - mousePos.x;
                view.height = mousePos.y - (oldView.top);
                break;
        }

        if (view.width < 25) view.width = 25;
        if (view.height < 25) view.height = 25;

        // redraw the image with resizing anchors
        draw(currentImg, true, true);

    } else if (draggingImage) {
        imageClick = false;

        // move the image by the amount of the latest drag
        var dx = mousePos.x - startX;
        var dy = mousePos.y - startY;
        view.left += dx;
        view.top += dy;
        // reset the startXY for next time
        startX = mousePos.x;
        startY = mousePos.y;

        // redraw the image with border
        draw(currentImg, false, true);
    }
}



var text = new Kinetic.Text({
    x: 20,
    y: 30,
    text: '',
    fontSize: '30',
    fontFamily: 'Calibri',
    fill: 'black',
    draggable: true
});

stage.add(layer);
layer.add(text);

document.getElementById("textBox").addEventListener("keyup", function () {
    text.setText(this.value);
    layer.draw();
}, true);

document.getElementById("textSize").addEventListener("change", function () {
    var size = this.value;
    text.fontSize(size);
    layer.draw();
}, true);

document.getElementById("fontFamily").addEventListener("change", function () {
    var font = this.value;
    text.fontFamily(font);
    layer.draw();
}, true);

document.getElementById("fontStyle").addEventListener("change", function () {
    var style = this.value;
    text.fontStyle(style);
    layer.draw();
}, true);

document.getElementById("fill").addEventListener("change", function () {
    var colour = this.value;
    text.fill(colour);
    layer.draw();
}, true);



$("#canvas").mousedown(function (e) {
    handleMouseDown(e);
});
$("#canvas").mousemove(function (e) {
    handleMouseMove(e);
});
$("#canvas").mouseup(function (e) {
    handleMouseUp(e);
});
$("#canvas").mouseout(function (e) {
    handleMouseOut(e);
});

// utility
function cl() {
    console.log.apply(console, arguments);
}

can provide jsFiddle if needed :)

Was it helpful?

Solution

You're trying to mix KineticJS with html canvas drawing commands.

That combination doesn't work because KineticJS does its magic by taking over the canvas--leaving no ability to call native canvas commands like context.beginPath.

// these 2 don't play together

... new Kinetic.Image ...

... ctx.beginPath ...

Anyway, Here's the answer to your question (in case you choose KineticJS for your project)

Kinetic.Image can be asked to execute a function when the image is clicked like this:

var image=new Kinetic.Image({
    x: 100,
    y: 50,
    image: img,
    width: 200,
    height: 130,
    draggable: true
}));
image.on("click",function(){

    // The image was clicked
    // Show your anchors now

});
layer.add(image);

[ Addition: Example of Kinetic.Image resizing ]

I don't like the overhead and complexity of maintaining anchors to resize Kinetic.Images.

Here's an example that lets you drag on the right side of the image to scale it proportionally:

http://jsfiddle.net/m1erickson/p8bpC/

You could modify this code to add cosmetic resizing grabbers (the grabbers are not necessary, but if you prefer the "anchor" look, you can add them).

OTHER TIPS

You can refer to this question, the answers are guided and constructive, and contain a jsfiddle with the exact same behavior that you need. Kinetic JS - how do you hide all the anchors for a given group ID

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top