2016-08-23 4 views
0

Я пытаюсь разработать способ выбора объектов, которые расположены ниже и (полностью) покрыты другими объектами. Одна идея состоит в том, чтобы выбрать верхний объект, а затем через doubleclick пройти вниз по слоям. Это то, что я в данный момент:Как выбрать покрытые объекты с помощью мыши в fabricJS?

var canvas = new fabric.Canvas("c"); 
 

 
fabric.util.addListener(canvas.upperCanvasEl, "dblclick", function (e) { 
 
    var _canvas = canvas; 
 
    var _mouse = _canvas.getPointer(e); 
 
    var _active = _canvas.getActiveObject(); 
 
    
 
    if (e.target) { 
 
    var _targets = _canvas.getObjects().filter(function (_obj) { 
 
     return _obj.containsPoint(_mouse); 
 
    }); 
 
     
 
    //console.warn(_targets); 
 
     
 
    for (var _i=0, _max=_targets.length; _i<_max; _i+=1) { 
 
     //check if target is currently active 
 
     if (_targets[_i] == _active) { 
 
     \t //then select the one on the layer below 
 
     \t _targets[_i-1] && _canvas.setActiveObject(_targets[_i-1]); 
 
     break; 
 
     } 
 
     } 
 
    } 
 
}); 
 

 
canvas 
 
    .add(new fabric.Rect({ 
 
    top: 25, 
 
    left: 25, 
 
    width: 100, 
 
    height: 100, 
 
    fill: "red" 
 
    })) 
 
    .add(new fabric.Rect({ 
 
    top: 50, 
 
    left: 50, 
 
    width: 100, 
 
    height: 100, 
 
    fill: "green" 
 
    })) 
 
    .add(new fabric.Rect({ 
 
    top: 75, 
 
    left: 75, 
 
    width: 100, 
 
    height: 100, 
 
    fill: "blue" 
 
    })) 
 
    .renderAll();
canvas { 
 
border: 1px solid; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.min.js"></script> 
 
<canvas id="c" width="300" height="200"></canvas>

Как вы можете видеть, пытаясь выбрать red прямоугольник внутри blue один не работает. Я могу только выбрать green или blue. Я предполагаю, что после того, как первый doubleclick работал (green), щелчок снова просто выбирает blue, поэтому следующий двойной клик сможет снова получить green.

Есть ли способ обойти это? Любые другие идеи?

+0

** «Любые другие идеи?» ** Конечно, если FabricJS ударил тест с множественными слоистыми прямоугольниками не легко доступен, просто перебирать прямоугольники и математически тест, если mouseX , mouseY находится внутри любого прямоугольника. См. Этот Html5-Canvas [Пример документации] (http://stackoverflow.com/documentation/html5-canvas/5017/collisions-and-intersections/17716/is-an-xy-point-inside-a-rectangle#t= 201608240434175724158). Таким образом, вам не нужно пытаться координировать клики, двойные клики и тройные символы и т. Д. ;-) – markE

+0

@markE: Это не касается моей проблемы. Я уже знаю, какие объекты попадают в указатель мыши (это мои «_targets» в коде выше). Мне нужен механизм для 'select' объектов, которые покрываются другими. И тот, внизу, и так далее. – Fidel90

+0

Я не гуру FabricJS, но вы не можете выбрать группу объектов с 'fabric.Group'? 'var group = new fabric.Group(); group.addWithUpdate (TargetObject); canvas.setActiveObject (группа); canvas.add (группа); ' – markE

ответ

1

Через некоторое время я, наконец, смог решить это самостоятельно. Нажатие на объект приводит его к вершине. При двойном щелчке я пытаюсь получить объект за один слой за текущим объектом. На другом dblclick я получаю тот за и так далее. Отлично подходит для меня, а также позволяет выбирать полностью закрытые объекты без необходимости перемещать других.

var canvas = new fabric.Canvas("c"); 
 

 
canvas.on("object:selected", function (e) { 
 
    if (e.target) { 
 
    e.target.bringToFront(); 
 
    this.renderAll(); 
 
    } 
 
}); 
 

 
var _prevActive = 0; 
 
var _layer = 0; 
 

 
// 
 
fabric.util.addListener(canvas.upperCanvasEl, "dblclick", function (e) { 
 
    var _canvas = canvas; 
 
    //current mouse position 
 
    var _mouse = _canvas.getPointer(e); 
 
    //active object (that has been selected on click) 
 
    var _active = _canvas.getActiveObject(); 
 
    //possible dblclick targets (objects that share mousepointer) 
 
    var _targets = _canvas.getObjects().filter(function (_obj) { 
 
     return _obj.containsPoint(_mouse) && !_canvas.isTargetTransparent(_obj, _mouse.x, _mouse.y); 
 
    }); 
 
    
 
    _canvas.deactivateAll(); 
 
     
 
    //new top layer target 
 
    if (_prevActive !== _active) { 
 
     //try to go one layer below current target 
 
     _layer = Math.max(_targets.length-2, 0); 
 
    } 
 
    //top layer target is same as before 
 
    else { 
 
     //try to go one more layer down 
 
     _layer = --_layer < 0 ? Math.max(_targets.length-2, 0) : _layer; 
 
    } 
 

 
    //get obj on current layer 
 
    var _obj = _targets[_layer]; 
 

 
    if (_obj) { 
 
    \t _prevActive = _obj; 
 
    \t _obj.bringToFront(); 
 
    \t _canvas.setActiveObject(_obj).renderAll(); 
 
    } 
 
}); 
 

 
//create something to play with 
 
canvas 
 
    //fully covered rect is selectable with dblclicks 
 
    .add(new fabric.Rect({ 
 
    top: 75, 
 
    left: 75, 
 
    width: 50, 
 
    height: 50, 
 
    fill: "black", 
 
    stroke: "black", 
 
    globalCompositeOperation: "xor", 
 
    perPixelTargetFind: true 
 
    })) 
 
    .add(new fabric.Circle({ 
 
    top: 25, 
 
    left: 25, 
 
    radius: 50, 
 
    fill: "rgba(255,0,0,.5)", 
 
    stroke: "black", 
 
    perPixelTargetFind: true 
 
    })) 
 
    .add(new fabric.Circle({ 
 
    top: 50, 
 
    left: 50, 
 
    radius: 50, 
 
    fill: "rgba(0,255,0,.5)", 
 
    stroke: "black", 
 
    perPixelTargetFind: true 
 
    })) 
 
    .add(new fabric.Circle({ 
 
    top: 75, 
 
    left: 75, 
 
    radius: 50, 
 
    fill: "rgba(0,0,255,.5)", 
 
    stroke: "black", 
 
    perPixelTargetFind: true 
 
    })) 
 
    .renderAll();
canvas { 
 
border: 1px solid; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script> 
 
<canvas id="c" width="300" height="200"></canvas>