0

我已经在使用jQuery名为 j 的插件,Crop但最近我发现KinectJs它确实为我解决了很多问题。然后我偶然发现了这个例子:

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

我决定根据KinectJs上面的例子编写我自己的裁剪矩形。

    function update(activeAnchor) {
var group = activeAnchor.getParent();

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 cropper = group.get('.cropper')[0];

var leftMask = group.getParent().get('.leftMask')[0];
var rightMask = group.getParent().get('.rightMask')[0];
var topMask = group.getParent().get('.topMask')[0];
var bottomMask = group.getParent().get('.bottomMask')[0];

var anchorX = activeAnchor.getX();
var anchorY = activeAnchor.getY();

// update anchor positions
switch (activeAnchor.getName()) {
    case 'topLeft':
        topRight.setY(anchorY);
        bottomLeft.setX(anchorX);
        updateLeftMaskWidth(leftMask,activeAnchor);
        updateTopMaskHeight(topMask,cropper,activeAnchor);
        break;
    case 'topRight':
        topLeft.setY(anchorY);
        bottomRight.setX(anchorX);
        updateRightMaskWidthAndPos(rightMask,activeAnchor);
        updateTopMaskHeight(topMask,cropper,activeAnchor);
        break;
    case 'bottomRight':
        bottomLeft.setY(anchorY);
        topRight.setX(anchorX);
        updateRightMaskWidthAndPos(rightMask,activeAnchor);
        updateBottomMaskHeightAndPos(bottomMask,cropper,activeAnchor);
        break;
    case 'bottomLeft':
        bottomRight.setY(anchorY);
        topLeft.setX(anchorX);
        updateLeftMaskWidth(leftMask,activeAnchor);
        updateBottomMaskHeightAndPos(bottomMask,cropper,activeAnchor);
        break;
    }

    cropper.setPosition(topLeft.getPosition().x,topLeft.getPosition().y);

    var width = topRight.getX() - topLeft.getX();
    var height = bottomLeft.getY() - topLeft.getY();
    if(width && height) {
        cropper.setSize(width, height);
    }
}

function updateLeftMaskWidth(mask,leftAnchor) {
    mask.setWidth(leftAnchor.getAbsolutePosition().x - 100);
}

function updateRightMaskWidthAndPos(mask,rightAnchor) {
    mask.setAbsolutePosition(rightAnchor.getAbsolutePosition().x,mask.getAbsolutePosition().y);
    mask.setWidth(213 - (rightAnchor.getAbsolutePosition().x - 100));
}

function updateTopMaskHeight(mask,cropper,topAnchor) {
    mask.setAbsolutePosition(topAnchor.getAbsolutePosition().x,mask.getAbsolutePosition().y);
    mask.setHeight(topAnchor.getAbsolutePosition().y - 110);
    mask.setWidth(cropper.getWidth());
}

function updateBottomMaskHeightAndPos(mask,cropper,bottomAnchor) {
    mask.setAbsolutePosition(bottomAnchor.getAbsolutePosition().x, bottomAnchor.getAbsolutePosition().y);
    mask.setHeight(236 - (bottomAnchor.getAbsolutePosition().y - 110));
    mask.setWidth(cropper.getWidth());
}

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: 1,
    radius: 5,
    name: name,
    draggable: true,
    dragBoundFunc: function(pos) {
        var newX = pos.x;
        var newY = pos.y;
        var image = this.getParent().getParent().get('.image')[0];
        var cropper = this.getParent();

        // Bound horizontally
        if(newX < 100) {
            newX = 100;
        }
        else if(newX > image.getWidth() + 100 - cropper.getWidth()) {
            newX = image.getWidth() + 100 - cropper.getWidth();
        }

        if(newY < 110) {
            newY = 110;
        }
        else if(newY > image.getHeight() + 110 - cropper.getHeight()) {
            newY = image.getHeight() + 110 - cropper.getHeight();
        }

        return {
            x: newX,
            y: newY
        }
    }
});

anchor.on('dragmove', function() {
    update(this);
    layer.draw();
});
// add hover styling
anchor.on('mouseover', function() {
    var layer = this.getLayer();
    document.body.style.cursor = 'pointer';
    this.setStrokeWidth(2);
    layer.draw();
});
anchor.on('mouseout', function() {
    var layer = this.getLayer();
    document.body.style.cursor = 'default';
    this.setStrokeWidth(2);
    layer.draw();
});

group.add(anchor);
}

function initStage(img) {
    var stage = new Kinetic.Stage({
        container: 'container',
        width: 578,
        height: 400
    });
    var imageGroup = new Kinetic.Group({
        x: 100,
        y: 110
    });
var leftMaskGroup = new Kinetic.Group({
    x: 100,
    y: 110
});

var rightMaskGroup = new Kinetic.Group({
    x: 270,
    y: 110
});

var topMaskGroup = new Kinetic.Group({
    x: 169.9,
    y: 110
});

var bottomMaskGroup = new Kinetic.Group({
    x: 169.9,
    y: 150+138
});

var cropperGroup = new Kinetic.Group({
    x: 170,
    y: 150,
    draggable: true,
    dragBoundFunc: function(pos) {
        var newX = pos.x;
        var newY = pos.y;
        var image = this.getParent().get('.image')[0];
        var cropper = this.get('.cropper')[0];

        // Bound horizontally
        if(newX < 100) {
            newX = 100;
        }
        else if(newX > image.getWidth() + 100 - cropper.getWidth()) {
            newX = image.getWidth() + 100 - cropper.getWidth();
        }

        // Bound vertically
        if(newY < 110) {
            newY = 110;
        }
        else if(newY > image.getHeight() + 110 - cropper.getHeight()) {
            newY = image.getHeight() + 110 - cropper.getHeight();
        }

        return {
            x: newX,
            y: newY
        }
    }
});
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(imageGroup);
layer.add(leftMaskGroup);
layer.add(rightMaskGroup);
layer.add(topMaskGroup);
layer.add(bottomMaskGroup);
layer.add(cropperGroup);
stage.add(layer);

// cropping rectangle
var cropperRect = new Kinetic.Rect({
    x: 0,
    y: 0,
    width: 100,
    height: 138,
    stroke: 'black',
    name: 'cropper',
    strokeWidth: 1
});

cropperGroup.add(cropperRect);
addAnchor(cropperGroup, 0, 0, 'topLeft');
addAnchor(cropperGroup, 100, 0, 'topRight');
addAnchor(cropperGroup, 100, 138, 'bottomRight');
addAnchor(cropperGroup, 0, 138, 'bottomLeft');

cropperGroup.on('dragstart', function() {
    this.moveToTop();
});

cropperGroup.on('dragmove', function() {
    var layer = this.getLayer();
    var topLeft = this.get('.topLeft')[0];
    var bottomLeft = this.get('.bottomLeft')[0];
    var topRight = this.get('.topRight')[0];
    var leftMask = this.getParent().get('.leftMask')[0];
    var rightMask = this.getParent().get('.rightMask')[0];
    var topMask = this.getParent().get('.topMask')[0];
    var bottomMask = this.getParent().get('.bottomMask')[0];
    updateLeftMaskWidth(leftMask,topLeft);
    updateRightMaskWidthAndPos(rightMask,topRight);
    updateTopMaskHeight(topMask,this.get('.cropper')[0],topLeft);
    updateBottomMaskHeightAndPos(bottomMask,this.get('.cropper')[0],bottomLeft);
    layer.draw();
});

// left mask
var leftMaskRect = new Kinetic.Rect({
    x: 0,
    y: 0,
    width: 70,
    height: 236,
    fill: 'black',
    name: 'leftMask',
    strokeWidth: 0,
    opacity: 0.5
});

leftMaskGroup.add(leftMaskRect);

// right mask
var rightMaskRect = new Kinetic.Rect({
    x: 0,
    y: 0,
    width: 213-170,
    height: 236,
    fill: 'black',
    name: 'rightMask',
    strokeWidth: 0,
    opacity: 0.5
});

rightMaskGroup.add(rightMaskRect);

// top mask
var topMaskRect = new Kinetic.Rect({
    x: 0,
    y: 0,
    width: 100.2,
    height: 150-110,
    fill: 'black',
    name: 'topMask',
    strokeWidth: 0,
    opacity: 0.5
});

topMaskGroup.add(topMaskRect);

// bottom mask
var bottomMaskRect = new Kinetic.Rect({
    x: 0,
    y: 0,
    width: 100.2,
    height: 236-138-(150-110),
    fill: 'black',
    name: 'bottomMask',
    strokeWidth: 0,
    opacity: 0.5
});

bottomMaskGroup.add(bottomMaskRect);

// image
var srcImg = new Kinetic.Image({
    x: 0,
    y: 0,
    image: img,
    name: 'image'
});

imageGroup.add(srcImg);

stage.draw();
}
var img = new Image();
img.onload = function() {
    initStage(this);
}
img.src = 'http://www.html5canvastutorials.com/demos/assets/yoda.jpg';

它工作得几乎完美。问题是,当您使用圆形锚点调整大小时,经过几次尝试(只是给它一些镜头),当您尝试拖动整个矩形时,它允许您将其拖出边界!

问题说明

从我的调试来看,这似乎是库的问题,但如果 sb. 在我的代码中看到问题或看到优化它的方法,请分享您的想法。

我的努力的结果可以在这里看到:

http://jsfiddle.net/wanderer/WLpXF/

4

2 回答 2

1

A)重现错误:

  1. 向上拖动一个顶部锚点(比如说它被拖动了 N 个像素)
  2. 向上拖动整个裁剪器;它可以离开图像边界 N 个像素

其他锚点和方向的类似行为。

B) 解决方案:

将此函数添加到脚本中:

function readjust() {
    var group = this.getParent();

    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 cropper = group.get('.cropper')[0];

    var tlx = cropper.getX(),
        tly = cropper.getY(),
        w = cropper.getWidth(),
        h = cropper.getHeight();

    group.setX(group.getX() + tlx);
    group.setY(group.getY() + tly);

    topLeft.setPosition(0,0);
    topRight.setPosition(w,0);
    bottomLeft.setPosition(0,h);
    bottomRight.setPosition(w,h);
    cropper.setPosition(0,0);
}

以及以下处理程序addAnchor()

anchor.on('dragend', readjust);

小提琴:http: //jsfiddle.net/BMy7b/1/

或者,如 MarmiK 所建议的,来自的代码readjust()可以包含在 中。update()这将在每次拖动时运行更多操作,因此可能会更慢(但我不确定;意见?)。小提琴:http: //jsfiddle.net/vUPeQ/1/

问题是裁剪器和锚点相对于 移动cropperGroup,但cropperGroup拖动边界功能没有考虑到它。

玩得开心!

于 2013-09-13T11:39:28.283 回答
1

一个快速更新:我在追求这样的东西(看起来不错的裁剪矩形),但是当我用最新的 KineticJS 5.0.1 尝试这段代码时,它做了一些令人讨厌的事情。您可以在这里自行查看:[http://jsfiddle.net/vUPeQ/2/]:http://jsfiddle.net/vUPeQ/2/

我的猜测是,这是因为一些 api 发生了变化,但我找不到哪一个......

有人可以在这里帮忙吗?

非常感谢!!!

于 2014-02-10T10:39:57.047 回答