2013-09-10 2 views
0

Я уже использую плагин jQuery под названием j Crop, но недавно я обнаружил KinectJs, и он действительно решает многие проблемы для меня. Потом я наткнулся на этот пример:Kinect JS обрезной прямоугольник

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 horizontaly 
     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'; 

Он работает почти идеально. Проблема в том, что когда вы изменяете размер с помощью привязок круга и после нескольких попыток (просто дайте несколько снимков), когда вы пытаетесь перетащить весь прямоугольник, он позволяет вытащить его за пределы!

Illustration of the problem

С моей отладки это, кажется, как вопрос с библиотекой, но если сб. видит проблему в моем коде или видит способ ее оптимизации, пожалуйста, поделитесь своими мыслями.

В результате моих усилий можно увидеть здесь:

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

+0

Разве это конкретный браузер?? или с Chrome/Firefox это будет делать !? – MarmiK

ответ

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); 

Fiddle: http://jsfiddle.net/BMy7b/1/

В качестве альтернативы код от readjust() могут быть включены в update(), как было предложено MarmiK. Это приведет к большему количеству операций при каждом перетаскивании, поэтому может быть медленнее (но я не уверен, мнения?). Fiddle: http://jsfiddle.net/vUPeQ/1/

Проблема заключалась в том, что промахнулись и анкеры движущимся относительно cropperGroup, но функция ограничивающая cropperGroup сопротивление не принимает его во внимание.

Удачи!

+1

Я думаю, что это также должно пойти с этим anchor.on ('dragmove', function() { update (this); layer.draw(); }); – MarmiK

+0

Я предполагаю, что логика 'update()' и 'readjust()' может быть объединена. Однако предложенное изменение минимально инвазивно к исходному коду. –

+0

Я просто делал то же самое, что и вы, так что нам просто нужно добавить вашу функцию в часть «dragmove» исходной функции, перетаскивание также является одной из причин, которая также может изменить холст. – MarmiK

1

Одно быстрое обновление: я был за чем-то вроде этого (красивый прямоугольник для обрезки), но когда я пробую этот код с последним KineticJS 5.0.1, ну, он делает пару неприятных вещей. Вы можете увидеть здесь: [http://jsfiddle.net/vUPeQ/2/]:http://jsfiddle.нетто/vUPeQ/2/

Мой дикий думаю, что это потому, что некоторые изменения API, но я не могу найти какой ...

Может кто-нибудь дать руку здесь?

Большое спасибо!

+0

Да, API изменился. Чтобы заставить его работать, вы должны признать, что из версии 5.0.0 «все многомерные входы и выходы должны быть объектными литералами по соображениям производительности. т. е. shape.setScale (1) больше не будет работать. Вам нужно использовать shape.setScale ({x: 1, y: 1}); '. В нашем примере это означает, что вы должны изменить все 'setPosition (xCoord, yCoord)' и 'setAbsolutePosition (xCoord, yCoord)' на 'setPosition ({x: xCoord, y: yCoord})' и 'setAbsolutePosition ({x: xCoord, y: yCoord}) '.После изменения является' setSize (newWidth, newHeight) ', который необходимо изменить на 'setSize ({width: newWidth, height: newHeight))'. – Tobiasz

Смежные вопросы