Gitlab CSE Unil

Commit 123851a3 authored by Julien Furrer's avatar Julien Furrer
Browse files

Added new Arrow

Arrow are now PlacedSymbol, needed to fix some 
getters and setters ; serialization too.

Kept old arrow mode under the name "arrow1"
parent b445d59c
......@@ -151,9 +151,20 @@ define([
fullySelectedAnnot = $.map(selectedAnnot, function(e){ return e.fullySelected ? e : null});
paper.project.deselectAll();
// All arrows annotations, needed to adjust strokeScaling mode for thumbnail exportation
var arrows = [], arr, aIdx;
if (options && options.thumbnailSize) {
// Enable strokeScaling for arrows
arrows = paper.project.getItems({data:{type:'arrow'}});
for (aIdx=0, arr; arr=arrows[aIdx]; aIdx++) {
arr.symbol.definition.strokeScaling = true;
}
paper.view.zoom = options.thumbnailSize / Math.max(ts.width, ts.height);
view.resize(ts.width * paper.view.zoom, ts.height * paper.view.zoom);
} else {
paper.view.zoom = 1;
view.resize(ts.width, ts.height);
......@@ -177,6 +188,11 @@ define([
$.each(selectedAnnot, function(i, e){ e.selected=true; });
$.each(fullySelectedAnnot, function(i, e){ e.fullySelected=true; });
// Reset arrows strokeScaling to false if needed
for (aIdx=0, arr; arr=arrows[aIdx]; aIdx++) {
arr.symbol.definition.strokeScaling = false;
}
// Restore view params
paper.view.viewSize = s;
paper.view.zoom = z;
......
......@@ -79,7 +79,15 @@ define([
* and give it the new id, generated by th DB
*/
io.events.annotationAdded.add(function(data){
// Unserialize item
var itemData = JSON.parse(data.item);
// PlacedSymbol are serialized as an array of two items,
// We want the second one
if ($.isArray(itemData[0])) {
itemData = itemData[1];
}
var tId = itemData[1].data.tId;
if (tId) {
var item = view.getItemByTempId(tId);
......
......@@ -30,7 +30,8 @@ define([
"tools/ellipse",
"tools/rectangle",
"tools/text",
"tools/arrow"
"tools/arrow",
"tools/arrow1"
],
function(Signal){
// ----- Locale variables -----------------------------
......
This diff is collapsed.
define(["paper"], function (paper) {
// ----- Const ----------------------------------------
var TOOL_TYPE = 'arrow1';
// ----- Local variables ------------------------------
// Events
var _events = {
annotationAdded: null,
annotationSelected: null,
annotationChanged: null
};
// Properties
var defaultProperties = {
comment: "",
confidence: 3,
fill: true
};
var confidenceStyle = {
"1": {
dashArray: [10, 10]
},
"2": {
dashArray: [30, 10]
},
"3": {
dashArray: null
}
};
// ----- Serialization ---------------------------------
function exportJSON(param) {
var fromPt = this.segments[7].point;
var toPt = this.segments[3].point;
this.data.from = [fromPt.x, fromPt.y];
this.data.to = [toPt.x, toPt.y];
var json = this.exportJSON({asString:false});
// // There is no apparent reason why we would nullify strokeWidth ?
// // @TODO: remove this part of code when we are sure there are no side effect
// if (!json[1].strokeColor) {
// json[1].strokeWidth = 0;
// }
delete(json[1].fontFamily);
delete(json[1].font);
delete(json[1].fontSize);
delete(json[1].leading);
return (param && param.asString) ? JSON.stringify(json) : json;
}
function importJSON(itemDef, layer, listening) {
var item = itemDef[1];
var curLayer = paper.project.activeLayer;
layer.activate();
var newArrow = createNewArrow({
from: new paper.Point(item.data.from),
to: item.data.to,
arrow: item.data.arrow,
prop: item.data.prop
}, listening);
newArrow.setStyle({
strokeColor: item.strokeColor,
strokeWidth: item.strokeWidth,
fillColor: item.fillColor
});
curLayer.activate();
//var item = layer.importJSON(itemDef);
return newArrow;
}
// ----- Item -----------------------------------------
var arrowParameters = {l1: 10, l2: 30, h: 40};
/**
* Create a new Arrow item.
* If '''eventListening''' is false, won't listen to mouse or keyboard event,
* any other value is considered as true, including undefined
*
* @param {Object} o the parameters of the new Arrow
* @param {Boolean} [eventListening=true]
* @returns {paper.Path}
*/
function createNewArrow(o, eventListening) {
var newArrow = new paper.Path({strokeJoin: 'round'});
o.arrow = o.arrow || arrowParameters;
drawArrow(newArrow, {from: o.from, to: o.to, arrow: o.arrow});
// Extend stria properties with default values
o.prop = (typeof o.prop === 'object') ? o.prop : {};
for (var p in defaultProperties) {
if (!o.prop.hasOwnProperty(p))
o.prop[p] = defaultProperties[p];
}
newArrow.data = {
tId: "a" + newArrow._id,
type: TOOL_TYPE,
prop: o.prop,
from: [o.from.x, o.from.y],
to: [o.to.x, o.to.y],
arrow: o.arrow
};
if (o.prop.confidence) {
newArrow.style = confidenceStyle[o.prop.confidence];
}
if (eventListening !== false) {
newArrow.onMouseDown = itemMouseDown;
//newArrow.onMouseDrag = itemMouseDrag;
newArrow.onMouseUp = itemMouseUp;
/*newArrow.onKeyDown = itemKeyDown;
newArrow.onKeyUp = itemKeyUp;*/
newArrow.onPropertyChange = itemPropertyChange;
}
_events.annotationAdded.dispatch(newArrow);
return newArrow;
}
var DRAG_MODES = {
FULL_DRAG: 0,
DRAG_TO: 1,
DRAG_FROM: 2,
AR_WIDTH: 3,
STRK_WIDTH: 4
};
var _dragMode = "";
var _dragDelta = null;
var _dragModified = false; // this is set to true if a drag event changed the item and need to emmit a change event
function itemMouseDown(event) {
if (!this.selected) return;
_dragMode = DRAG_MODES.FULL_DRAG;
var toPt = this.segments[3].point;
var fromPt = this.segments[7].point;
var arWidthPt1 = this.segments[2].point;
var arWidthPt2 = this.segments[4].point;
var strkWidthPt1 = this.segments[1].point;
var strkWidthPt2 = this.segments[5].point;
_dragDelta = null;
// if a modifier key is hold, act on the shape of the arrow
if (event.modifiers.option || event.modifiers.control || event.modifiers.command) {
if (arWidthPt1.getDistance(event.point) < 10 ||
arWidthPt2.getDistance(event.point) < 10) {
_dragMode = DRAG_MODES.AR_WIDTH;
}
else if (strkWidthPt1.getDistance(event.point) < 10 ||
strkWidthPt2.getDistance(event.point) < 10) {
_dragMode = DRAG_MODES.STRK_WIDTH;
}
}
// No modifier key hold
else {
if (arWidthPt1.getDistance(event.point) < 10 ||
arWidthPt2.getDistance(event.point) < 10) {
_dragMode = DRAG_MODES.AR_WIDTH;
}
else if (strkWidthPt1.getDistance(event.point) < 10 ||
strkWidthPt2.getDistance(event.point) < 10) {
_dragMode = DRAG_MODES.STRK_WIDTH;
}
else if (toPt.getDistance(event.point) < this.data.arrow.h - 20) {
_dragMode = DRAG_MODES.DRAG_TO;
_dragDelta = toPt.subtract(event.point);
}
else if (fromPt.getDistance(event.point) < 30) {
_dragMode = DRAG_MODES.DRAG_FROM;
_dragDelta = fromPt.subtract(event.point);
}
}
this.attach('mousedrag', itemMouseDrag);
}
function itemMouseDrag(event) {
_dragModified = true;
var param = {
from: this.segments[7].point,
to: this.segments[3].point,
arrow: this.data.arrow
};
function getProjectionOnArrow(point, param){
var a = param.to.subtract(point).angle;
var b = param.to.subtract(param.from).angle;
var g_rad = (a - b) / 360 * 2 * Math.PI;
var L = point.getDistance(param.to);
return {l: Math.sin(g_rad) * L, h: Math.cos(g_rad) * L};
}
switch(_dragMode) {
case DRAG_MODES.FULL_DRAG:
this.translate(event.delta);
break;
case DRAG_MODES.DRAG_TO:
param.to = _dragDelta ? event.point.add(_dragDelta) : event.point;
drawArrow(this, param);
break;
case DRAG_MODES.DRAG_FROM:
param.from = _dragDelta ? event.point.add(_dragDelta) : event.point;
drawArrow(this, param);
break;
case DRAG_MODES.AR_WIDTH:
var projecton = getProjectionOnArrow(event.point, param);
if (projecton.l > param.arrow.l1)
param.arrow.l2 = projecton.l;
if (projecton.h > 5)
param.arrow.h = projecton.h;
drawArrow(this, param);
break;
case DRAG_MODES.STRK_WIDTH:
var projecton = getProjectionOnArrow(event.point, param);
if (projecton.l > 2 && projecton.l < param.arrow.l2)
param.arrow.l1 = projecton.l;
if (projecton.h > 5)
param.arrow.h = projecton.h;
drawArrow(this, param);
break;
default:
_dragModified = false;
break;
}
}
function itemMouseUp(event) {
this.detach('mousedrag', itemMouseDrag);
_dragMode = null;
if (_dragModified) {
_events.annotationChanged.dispatch(this);
}
_dragModified = false;
}
function itemPropertyChange(property, value) {
if (property === 'confidence') {
this.style = confidenceStyle[value];
paper.view.draw();
}
}
// ===== Drawing functions
function getArrowVect(param, h) {
var arVect = {
v0 : new paper.Point( param.l1, 0),
v2 : new paper.Point( param.l2 - param.l1, 0),
v3 : new paper.Point(-param.l2, param.h),
v4 : new paper.Point(-param.l2, -param.h),
v5 : new paper.Point( param.l2 - param.l1, 0)
};
if (h !== void(0)) {
var h1 = h - param.h;
arVect.v1 = new paper.Point(0, h1 > 0 ? h1 : 0);
}
return arVect;
}
function drawArrow(path, param) {
var arrowParam = param.arrow || arrowParameters;
var arrowHeight = param.from.getDistance(param.to);
var arVect = getArrowVect(arrowParam, arrowHeight);
path.removeSegments();
path.pivot = param.from;
path.rotation = 0;
path.add(param.from.add(arVect.v0));
path.lineBy(arVect.v1);
path.lineBy(arVect.v2);
path.lineBy(arVect.v3);
path.lineBy(arVect.v4);
path.lineBy(arVect.v5);
path.lineBy(0, -arVect.v1.y);
path.lineBy(arVect.v0);
path.closed = true;
path.rotation = param.from.subtract(param.to).angle + 90;
}
// ----- Utilities ------------------------------------
function _getAnnotationFromItem(item) {
if (item.data && item.data.type === TOOL_TYPE) {
return item;
} else if (item.parent) {
return _getAnnotationFromItem(item.parent);
} else {
return null;
}
}
function _hitOnArrowTest(point) {
var hitResult = paper.project.activeLayer.hitTest(point,{
fill: true,
stroke: true
});
return hitResult && hitResult.item ? _getAnnotationFromItem(hitResult.item) : false;
}
// ----- Tool -----------------------------------------
var _create = false;
var _startPoint = null;
var _createPath = null;
var toolDef = {
onMouseDown: function(event) {
var hitAnnot;
_create = false;
_createPath = null;
paper.project.deselectAll();
_events.annotationSelected.dispatch(null);
if (hitAnnot = _hitOnArrowTest(event.point)) {
// click on existing arrow, modify it (to be implemented)
hitAnnot.selected = true;
} else {
// lets create a new arrow
_create = true;
_startPoint = event.point;
_createPath = new paper.Path({strokeJoin: 'round'});
drawArrow(_createPath, {from: _startPoint, to:event.point});
}
},
onMouseDrag: function(event) {
if (_create && _createPath) {
drawArrow(_createPath, {from: _startPoint, to:event.point});
}
},
onMouseUp: function(event) {
if (_create && _createPath) {
_createPath.remove();
if (_startPoint.subtract(event.point).length > 1) {
var newArrow = createNewArrow({
from: _startPoint,
to: event.point,
arrow: arrowParameters
}, true);
newArrow.selected = true;
}
}
}
};
// ----- Returned Module ------------------------------
return {
name: TOOL_TYPE,
tool: new paper.Tool(toolDef),
registerEvent: function(eventName, evt) { _events[eventName] = evt; },
exportJSON: exportJSON,
importJSON: importJSON,
listeners: {
}
};
});
\ No newline at end of file
......@@ -50,10 +50,11 @@ define([
var _selectedHandle;
var _selectedShape = null;
var _selectedShapeBound = null;
var _selectedArrowBound = null;
function itemMouseDown(item, event) {
var itemHitResult = item.hitTest(event.point, itemHitOptions);
_selectedSegment = _selectedMove = _selectedHandle = _selectedShape = _selectedShapeBound = null;
_selectedSegment = _selectedMove = _selectedHandle = _selectedShape = _selectedShapeBound = _selectedArrowBound = null;
switch (itemHitResult.type) {
case 'handle-in':
case 'handle-out':
......@@ -82,8 +83,8 @@ define([
break;
case 'bounds':
var p = itemHitResult.name.split('-');
if (['shape', 'ellipse', 'rectangle', 'circle'].indexOf(itemHitResult.item.type) > -1) {
var p = itemHitResult.name.split('-');
if (p[0] === 'center' || p[1] === 'center') {
_selectedMove = true;
} else {
......@@ -93,54 +94,66 @@ define([
_selectedShape = itemHitResult.item;
}
}
else if (itemHitResult.item.data.type === 'arrow' && p[1] === 'right') {
try {
itemHitResult.item.data.setDragMode.call(itemHitResult.item, 'DRAG_HANDLE', {
nameStr: itemHitResult.name,
nameParts: p
});
} catch(e) {}
// _selectedArrowBound = itemHitResult.item.bounds;
}
break;
}
}
function itemMouseDrag(item, event) {
function dragHandles(event) {
var dstPoint = event.point.subtract(_selectedSegment.point);
var prevPoint = event.lastPoint.subtract(_selectedSegment.point);
var dA = dstPoint.angle - prevPoint.angle;
var rotateBothHandles = !event.modifiers.option;
if (_selectedHandle === 'in') {
_selectedSegment.handleIn = dstPoint;
if (rotateBothHandles) {
// This is broken if handles are not aligned
//segment.handleOut.angle = 180 + dstPoint.angle;
_selectedSegment.handleOut.angle += dA;
}
} else {
_selectedSegment.handleOut = dstPoint;
if (rotateBothHandles) {
//segment.handleIn.angle = 180 + dstPoint.angle;
_selectedSegment.handleIn.angle += dA;
}
function _dragHandles(event) {
var dstPoint = event.point.subtract(_selectedSegment.point);
var prevPoint = event.lastPoint.subtract(_selectedSegment.point);
var dA = dstPoint.angle - prevPoint.angle;
var rotateBothHandles = !event.modifiers.option;
if (_selectedHandle === 'in') {
_selectedSegment.handleIn = dstPoint;
if (rotateBothHandles) {
// This is broken if handles are not aligned
//segment.handleOut.angle = 180 + dstPoint.angle;
_selectedSegment.handleOut.angle += dA;
}
} else {
_selectedSegment.handleOut = dstPoint;
if (rotateBothHandles) {
//segment.handleIn.angle = 180 + dstPoint.angle;
_selectedSegment.handleIn.angle += dA;
}
}
}
function resizeShape(event) {
var constructorName = _selectedShape.data.type.charAt(0).toUpperCase() + _selectedShape.data.type.slice(1);
var shapeStyle = _selectedShape.style;
var shapeData = _selectedShape.data;
var tmpShape = new paper.Shape[constructorName]({
from: _selectedShapeBound,
to: event.point,
style: shapeStyle,
data: shapeData
}).insertAbove(_selectedShape);
_selectedShape.remove();
_selectedShape = tmpShape;
_selectedShape.selected = true;
}
function _resizeShape(event) {
var constructorName = _selectedShape.data.type.charAt(0).toUpperCase() + _selectedShape.data.type.slice(1);
var shapeStyle = _selectedShape.style;
var shapeData = _selectedShape.data;
var tmpShape = new paper.Shape[constructorName]({
from: _selectedShapeBound,
to: event.point,
style: shapeStyle,
data: shapeData
}).insertAbove(_selectedShape);
_selectedShape.remove();
_selectedShape = tmpShape;
_selectedShape.selected = true;
}
function itemMouseDrag(item, event) {
if (_selectedShape) {
resizeShape(event);
if (item.data && typeof item.data.itemMouseDrag === 'function') {
item.data.itemMouseDrag.call(item, event);
}
else if (_selectedShape) {
_resizeShape(event);
}
else if (_selectedHandle && _selectedSegment.path.id === item.id) {
dragHandles(event);
_dragHandles(event);
}
else if (_selectedSegment && _selectedSegment.path.id === item.id) {
_selectedSegment.point = event.point;
......@@ -158,14 +171,31 @@ define([
// ----- Tool Def -------------------------------------
var selHitOpts = {
tolerance: 7,
fill: true,
stroke: true,
segments: true,
handles: true,
ends: true,
bounds: true,
selected: true
};
var toolDef = {
onMouseDown: function(event) {
_selectedSegment = _selectedMove = _selectedHandle = _selectedShape = _selectedShapeBound = null;
var toolHitResult = !_selectAllLayers
? paper.project.activeLayer.hitTest(event.point, selHitOpts)
: paper.project.hitTest(event.point, toolHitOptions);
if (!toolHitResult) {
toolHitResult = !_selectAllLayers
? paper.project.activeLayer.hitTest(event.point, toolHitOptions)
: paper.project.hitTest(event.point, toolHitOptions);
}