Fix #769: Implement Item#selection flags to separate selection from item and bounds.

This commit is contained in:
Jürg Lehni 2016-03-17 13:02:26 +01:00
parent bb19fade56
commit f0edcd31b0
10 changed files with 170 additions and 146 deletions

View file

@ -904,18 +904,13 @@ new function() {
* @default false * @default false
*/ */
isSelected: function() { isSelected: function() {
return this._owner._boundsSelected; return !!(this._owner._selection & /*#=*/ItemSelection.BOUNDS);
}, },
setSelected: function(selected) { setSelected: function(selected) {
var owner = this._owner; var owner = this._owner;
if (owner.setSelected) { if (owner.changeSelection) {
owner._boundsSelected = selected; owner.changeSelection(/*#=*/ItemSelection.BOUNDS, selected);
// Update the owner's selected state too, so the bounds
// actually get drawn. When deselecting, take a path's
// _segmentSelection into account too, since it will
// have to remain selected even when bounds are deselected
owner.setSelected(selected || owner._segmentSelection > 0);
} }
} }
}) })

View file

@ -12,4 +12,5 @@
/*#*/ include('util/Numerical.js'); /*#*/ include('util/Numerical.js');
/*#*/ include('item/ChangeFlag.js'); /*#*/ include('item/ChangeFlag.js');
/*#*/ include('item/ItemSelection.js');
/*#*/ include('path/SegmentSelection.js'); /*#*/ include('path/SegmentSelection.js');

View file

@ -51,22 +51,30 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
_applyMatrix: true, _applyMatrix: true,
_canApplyMatrix: true, _canApplyMatrix: true,
_canScaleStroke: false, _canScaleStroke: false,
_pivot: null,
_visible: true,
_blendMode: 'normal',
_opacity: 1,
_locked: false,
_guide: false,
_clipMask: false,
_selection: 0,
_boundsSelected: false, _boundsSelected: false,
_selectChildren: false, _selectChildren: false,
// Provide information about fields to be serialized, with their defaults // Provide information about fields to be serialized, with their defaults
// that can be ommited. // that can be omitted.
_serializeFields: { _serializeFields: {
name: null, name: null,
applyMatrix: null, applyMatrix: null,
matrix: new Matrix(), matrix: new Matrix(),
pivot: null, pivot: null,
locked: false,
visible: true, visible: true,
blendMode: 'normal', blendMode: 'normal',
opacity: 1, opacity: 1,
locked: false,
guide: false, guide: false,
selected: false,
clipMask: false, clipMask: false,
selected: false,
data: {} data: {}
} }
}, },
@ -425,7 +433,6 @@ new function() { // Injection scope for various item event handlers
* @default false * @default false
* @ignore * @ignore
*/ */
_locked: false,
/** /**
* Specifies whether the item is visible. When set to `false`, the item * Specifies whether the item is visible. When set to `false`, the item
@ -446,7 +453,6 @@ new function() { // Injection scope for various item event handlers
* // Hide the path: * // Hide the path:
* path.visible = false; * path.visible = false;
*/ */
_visible: true,
/** /**
* The blend mode with which the item is composited onto the canvas. Both * The blend mode with which the item is composited onto the canvas. Both
@ -488,7 +494,6 @@ new function() { // Injection scope for various item event handlers
* // Set the blend mode of circle2: * // Set the blend mode of circle2:
* circle2.blendMode = 'multiply'; * circle2.blendMode = 'multiply';
*/ */
_blendMode: 'normal',
/** /**
* The opacity of the item as a value between `0` and `1`. * The opacity of the item as a value between `0` and `1`.
@ -516,7 +521,6 @@ new function() { // Injection scope for various item event handlers
* // Make circle2 50% transparent: * // Make circle2 50% transparent:
* circle2.opacity = 0.5; * circle2.opacity = 0.5;
*/ */
_opacity: 1,
// TODO: Implement guides // TODO: Implement guides
/** /**
@ -528,7 +532,26 @@ new function() { // Injection scope for various item event handlers
* @default true * @default true
* @ignore * @ignore
*/ */
_guide: false,
getSelection: function() {
return this._selection;
},
setSelection: function(selection) {
if (selection !== this._selection) {
this._selection = selection;
var project = this._project;
if (project) {
project._updateSelection(this);
this._changed(/*#=*/Change.ATTRIBUTE);
}
}
},
changeSelection: function(flag, selected) {
var selection = this._selection;
this.setSelection(selected ? selection | flag : selection & ~flag);
},
/** /**
* Specifies whether the item is selected. This will also return `true` for * Specifies whether the item is selected. This will also return `true` for
@ -563,39 +586,29 @@ new function() { // Injection scope for various item event handlers
if (children[i].isSelected()) if (children[i].isSelected())
return true; return true;
} }
return this._selected; return !!(this._selection & /*#=*/ItemSelection.ITEM);
}, },
setSelected: function(selected, noChildren) { setSelected: function(selected) {
// Don't recursively call #setSelected() if it was called with if (this._selectChildren) {
// noChildren set to true, see #setFullySelected().
if (!noChildren && this._selectChildren) {
var children = this._children; var children = this._children;
for (var i = 0, l = children.length; i < l; i++) for (var i = 0, l = children.length; i < l; i++)
children[i].setSelected(selected); children[i].setSelected(selected);
} }
if ((selected = !!selected) ^ this._selected) { this.changeSelection(/*#=*/ItemSelection.ITEM, selected);
this._selected = selected;
var project = this._project;
if (project) {
project._updateSelection(this);
this._changed(/*#=*/Change.ATTRIBUTE);
}
}
}, },
_selected: false,
isFullySelected: function() { isFullySelected: function() {
var children = this._children; var children = this._children,
if (children && this._selected) { selected = !!(this._selection & /*#=*/ItemSelection.ITEM);
if (children && selected) {
for (var i = 0, l = children.length; i < l; i++) for (var i = 0, l = children.length; i < l; i++)
if (!children[i].isFullySelected()) if (!children[i].isFullySelected())
return false; return false;
return true; return true;
} }
// If there are no children, this is the same as #selected // If there are no children, this is the same as #selected
return this._selected; return selected;
}, },
setFullySelected: function(selected) { setFullySelected: function(selected) {
@ -604,8 +617,7 @@ new function() { // Injection scope for various item event handlers
for (var i = 0, l = children.length; i < l; i++) for (var i = 0, l = children.length; i < l; i++)
children[i].setFullySelected(selected); children[i].setFullySelected(selected);
} }
// Pass true for hidden noChildren argument this.changeSelection(/*#=*/ItemSelection.ITEM, selected);
this.setSelected(selected, true);
}, },
/** /**
@ -636,8 +648,6 @@ new function() { // Injection scope for various item event handlers
} }
}, },
_clipMask: false,
// TODO: get/setIsolated (print specific feature) // TODO: get/setIsolated (print specific feature)
// TODO: get/setKnockout (print specific feature) // TODO: get/setKnockout (print specific feature)
// TODO: get/setAlphaIsShape // TODO: get/setAlphaIsShape
@ -778,9 +788,7 @@ new function() { // Injection scope for various item event handlers
this._pivot = Point.read(arguments, 0, { clone: true, readNull: true }); this._pivot = Point.read(arguments, 0, { clone: true, readNull: true });
// No need for _changed() since the only thing this affects is _position // No need for _changed() since the only thing this affects is _position
this._position = undefined; this._position = undefined;
}, }
_pivot: null,
}, Base.each({ // Produce getters for bounds properties: }, Base.each({ // Produce getters for bounds properties:
getStrokeBounds: { stroke: true }, getStrokeBounds: { stroke: true },
getHandleBounds: { handle: true }, getHandleBounds: { handle: true },
@ -1565,9 +1573,9 @@ new function() { // Injection scope for various item event handlers
// in case #applyMatrix is true. // in case #applyMatrix is true.
this.setApplyMatrix(source._applyMatrix); this.setApplyMatrix(source._applyMatrix);
this.setPivot(source._pivot); this.setPivot(source._pivot);
// Copy over the selection state, use setSelected so the item // Copy over the selection state, use setSelection so the item
// is also added to Project#selectedItems if it is selected. // is also added to Project#_selectionItems if it is selected.
this.setSelected(source._selected); this.setSelection(source._selection);
// Copy over data and name as well. // Copy over data and name as well.
var data = source._data, var data = source._data,
name = source._name; name = source._name;
@ -1876,7 +1884,7 @@ new function() { // Injection scope for hit-test functions shared with project
// See if we should check self (own content), by filtering for type, // See if we should check self (own content), by filtering for type,
// guides and selected items if that's required. // guides and selected items if that's required.
var checkSelf = !(options.guides && !this._guide var checkSelf = !(options.guides && !this._guide
|| options.selected && !this._selected || options.selected && !this.isSelected(true)
// Support legacy Item#type property to match hyphenated // Support legacy Item#type property to match hyphenated
// class-names. // class-names.
|| options.type && options.type !== Base.hyphenate(this._class) || options.type && options.type !== Base.hyphenate(this._class)
@ -4240,23 +4248,27 @@ new function() { // Injection scope for hit-test functions shared with project
return updated; return updated;
}, },
_drawSelection: function(ctx, matrix, size, selectedItems, updateVersion) { _drawSelection: function(ctx, matrix, size, selectionItems, updateVersion) {
if ((this._drawSelected || this._boundsSelected) var selection = this._selection,
&& this._isUpdated(updateVersion)) { itemSelected = selection & /*#=*/ItemSelection.ITEM,
boundsSelected = selection & /*#=*/ItemSelection.BOUNDS
|| itemSelected && this._boundsSelected;
if (!this._drawSelected)
itemSelected = false;
if ((itemSelected || boundsSelected) && this._isUpdated(updateVersion)) {
// Allow definition of selected color on a per item and per // Allow definition of selected color on a per item and per
// layer level, with a fallback to #009dec // layer level, with a fallback to #009dec
var layer, var layer,
color = this.getSelectedColor(true) color = this.getSelectedColor(true) || (layer = this.getLayer())
|| (layer = this.getLayer()) && layer.getSelectedColor(true), && layer.getSelectedColor(true),
mx = matrix.appended(this.getGlobalMatrix(true)); mx = matrix.appended(this.getGlobalMatrix(true));
ctx.strokeStyle = ctx.fillStyle = color ctx.strokeStyle = ctx.fillStyle = color
? color.toCanvasStyle(ctx) : '#009dec'; ? color.toCanvasStyle(ctx) : '#009dec';
if (this._drawSelected) if (itemSelected)
this._drawSelected(ctx, mx, selectedItems); this._drawSelected(ctx, mx, selectionItems);
if (this._boundsSelected) { if (boundsSelected) {
var half = size / 2, var half = size / 2,
coords = mx._transformCorners( coords = mx._transformCorners(this.getInternalBounds());
this.getInternalBounds());
// Now draw a rectangle that connects the transformed // Now draw a rectangle that connects the transformed
// bounds corners, and draw the corners. // bounds corners, and draw the corners.
ctx.beginPath(); ctx.beginPath();

17
src/item/ItemSelection.js Normal file
View file

@ -0,0 +1,17 @@
/*
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
* http://paperjs.org/
*
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
* http://scratchdisk.com/ & http://jonathanpuckey.com/
*
* Distributed under the MIT license. See LICENSE file for details.
*
* All rights reserved.
*/
var ItemSelection = {
ITEM: 1,
BOUNDS: 2,
PIVOT: 4
};

View file

@ -62,8 +62,8 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
// (e.g. PointText#_getBounds) // (e.g. PointText#_getBounds)
this._view = View.create(this, this._view = View.create(this,
element || CanvasProvider.getCanvas(1, 1)); element || CanvasProvider.getCanvas(1, 1));
this._selectedItems = {}; this._selectionItems = {};
this._selectedItemCount = 0; this._selectionCount = 0;
// See Item#draw() for an explanation of _updateVersion // See Item#draw() for an explanation of _updateVersion
this._updateVersion = 0; this._updateVersion = 0;
// Change tracking, not in use for now. Activate once required: // Change tracking, not in use for now. Activate once required:
@ -282,15 +282,15 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
// TODO: Return groups if their children are all selected, and filter // TODO: Return groups if their children are all selected, and filter
// out their children from the list. // out their children from the list.
// TODO: The order of these items should be that of their drawing order. // TODO: The order of these items should be that of their drawing order.
var selectedItems = this._selectedItems, var selectionItems = this._selectionItems,
items = []; items = [];
for (var id in selectedItems) { for (var id in selectionItems) {
var item = selectedItems[id]; var item = selectionItems[id],
if (item.isInserted()) { selection = item._selection;
if (selection & /*#=*/ItemSelection.ITEM && item.isInserted()) {
items.push(item); items.push(item);
} else { } else if (!selection) {
this._selectedItemCount--; this._updateSelection(item);
delete selectedItems[id];
} }
} }
return items; return items;
@ -299,15 +299,15 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
_updateSelection: function(item) { _updateSelection: function(item) {
var id = item._id, var id = item._id,
selectedItems = this._selectedItems; selectionItems = this._selectionItems;
if (item._selected) { if (item._selection) {
if (selectedItems[id] !== item) { if (selectionItems[id] !== item) {
this._selectedItemCount++; this._selectionCount++;
selectedItems[id] = item; selectionItems[id] = item;
} }
} else if (selectedItems[id] === item) { } else if (selectionItems[id] === item) {
this._selectedItemCount--; this._selectionCount--;
delete selectedItems[id]; delete selectionItems[id];
} }
}, },
@ -324,9 +324,9 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
* Deselects all selected items in the project. * Deselects all selected items in the project.
*/ */
deselectAll: function() { deselectAll: function() {
var selectedItems = this._selectedItems; var selectionItems = this._selectionItems;
for (var i in selectedItems) for (var i in selectionItems)
selectedItems[i].setFullySelected(false); selectionItems[i].setFullySelected(false);
}, },
/** /**
@ -866,10 +866,10 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
ctx.restore(); ctx.restore();
// Draw the selection of the selected items in the project: // Draw the selection of the selected items in the project:
if (this._selectedItemCount > 0) { if (this._selectionCount > 0) {
ctx.save(); ctx.save();
ctx.strokeWidth = 1; ctx.strokeWidth = 1;
var items = this._selectedItems, var items = this._selectionItems,
size = this._scope.settings.handleSize, size = this._scope.settings.handleSize,
version = this._updateVersion; version = this._updateVersion;
for (var id in items) { for (var id in items) {

View file

@ -293,14 +293,14 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{
} }
}, },
_drawSelected: function(ctx, matrix, selectedItems) { _drawSelected: function(ctx, matrix, selectionItems) {
var children = this._children; var children = this._children;
for (var i = 0, l = children.length; i < l; i++) { for (var i = 0, l = children.length; i < l; i++) {
var child = children[i], var child = children[i],
mx = child._matrix; mx = child._matrix;
// Do not draw this child now if it's separately marked as selected, // Do not draw this child now if it's separately marked as selected,
// as it would be drawn twice otherwise. // as it would be drawn twice otherwise.
if (!selectedItems[child._id]) { if (!selectionItems[child._id]) {
child._drawSelected(ctx, mx.isIdentity() ? matrix child._drawSelected(ctx, mx.isIdentity() ? matrix
: matrix.appended(mx)); : matrix.appended(mx));
} }

View file

@ -935,8 +935,8 @@ var Path = PathItem.extend(/** @lends Path# */{
*/ */
isFullySelected: function() { isFullySelected: function() {
var length = this._segments.length; var length = this._segments.length;
return this._selected && length > 0 && this._segmentSelection return this.isSelected(true) && length > 0 && this._segmentSelection
=== length * /*#=*/SegmentSelection.SEGMENT; === length * /*#=*/SegmentSelection.ALL;
}, },
setFullySelected: function(selected) { setFullySelected: function(selected) {
@ -947,22 +947,20 @@ var Path = PathItem.extend(/** @lends Path# */{
this.setSelected(selected); this.setSelected(selected);
}, },
setSelected: function setSelected(selected) { setSelection: function setSelection(selection) {
// Deselect all segments when path is marked as not selected // Deselect all segments when path is marked as not selected
if (!selected) if (!(selection & /*#=*/ItemSelection.ITEM))
this._selectSegments(false); this._selectSegments(false);
// No need to pass true for noChildren since Path has none anyway. setSelection.base.call(this, selection);
setSelected.base.call(this, selected);
}, },
_selectSegments: function(selected) { _selectSegments: function(selected) {
var length = this._segments.length; var segments = this._segments,
this._segmentSelection = selected length = segments.length,
? length * /*#=*/SegmentSelection.SEGMENT : 0; selection = selected ? /*#=*/SegmentSelection.ALL : 0;
for (var i = 0; i < length; i++) { this._segmentSelection = selection * length;
this._segments[i]._selection = selected for (var i = 0; i < length; i++)
? /*#=*/SegmentSelection.SEGMENT : 0; segments[i]._selection = selection;
}
}, },
_updateSelection: function(segment, oldSelection, newSelection) { _updateSelection: function(segment, oldSelection, newSelection) {

View file

@ -115,7 +115,8 @@ var Segment = Base.extend(/** @lends Segment# */{
*/ */
initialize: function Segment(arg0, arg1, arg2, arg3, arg4, arg5) { initialize: function Segment(arg0, arg1, arg2, arg3, arg4, arg5) {
var count = arguments.length, var count = arguments.length,
point, handleIn, handleOut; point, handleIn, handleOut,
selection;
// TODO: Use Point.read or Point.readNamed to read these? // TODO: Use Point.read or Point.readNamed to read these?
if (count === 0) { if (count === 0) {
// Nothing // Nothing
@ -125,17 +126,17 @@ var Segment = Base.extend(/** @lends Segment# */{
point = arg0.point; point = arg0.point;
handleIn = arg0.handleIn; handleIn = arg0.handleIn;
handleOut = arg0.handleOut; handleOut = arg0.handleOut;
selection = arg0.selection;
} else { } else {
point = arg0; point = arg0;
} }
} else if (count === 2 && typeof arg0 === 'number') { } else if (typeof arg0 === 'object') {
point = arguments; // It doesn't matter if all of these arguments exist.
} else if (count <= 3) { // new SegmentPoint() produces creates points with (0, 0) otherwise.
point = arg0; point = arg0;
// Doesn't matter if these arguments exist, SegmentPointcreate
// produces creates points with (0, 0) otherwise
handleIn = arg1; handleIn = arg1;
handleOut = arg2; handleOut = arg2;
selection = arg3;
} else { // Read points from the arguments list as a row of numbers } else { // Read points from the arguments list as a row of numbers
point = arg0 !== undefined ? [ arg0, arg1 ] : null; point = arg0 !== undefined ? [ arg0, arg1 ] : null;
handleIn = arg2 !== undefined ? [ arg2, arg3 ] : null; handleIn = arg2 !== undefined ? [ arg2, arg3 ] : null;
@ -144,14 +145,20 @@ var Segment = Base.extend(/** @lends Segment# */{
new SegmentPoint(point, this, '_point'); new SegmentPoint(point, this, '_point');
new SegmentPoint(handleIn, this, '_handleIn'); new SegmentPoint(handleIn, this, '_handleIn');
new SegmentPoint(handleOut, this, '_handleOut'); new SegmentPoint(handleOut, this, '_handleOut');
if (selection)
this.setSelection(selection);
}, },
_serialize: function(options) { _serialize: function(options) {
// If it is has no handles, only serialize point, otherwise handles too. // If it is has no handles, only serialize point, otherwise handles too.
return Base.serialize(this.hasHandles() var point = this._point,
? [this._point, this._handleIn, this._handleOut] selection = this._selection,
: this._point, obj = selection || this.hasHandles()
options, true); ? [point, this._handleIn, this._handleOut]
: point;
if (selection)
obj.push(selection);
return Base.serialize(obj, options, true);
}, },
_changed: function(point) { _changed: function(point) {
@ -253,8 +260,30 @@ var Segment = Base.extend(/** @lends Segment# */{
this._handleOut.set(0, 0); this._handleOut.set(0, 0);
}, },
_getSelectionFlag: function(point) { getSelection: function() {
return !point ? /*#=*/SegmentSelection.SEGMENT return this._selection;
},
setSelection: function(selection) {
var oldSelection = this._selection,
path = this._path;
// Set the selection state even if path is not defined yet, to allow
// selected segments to be inserted into paths and make JSON
// deserialization work.
this._selection = selection = selection || 0;
// If the selection state of the segment has changed, we need to let
// it's path know and possibly add or remove it from
// project._selectionItems
if (path && selection !== oldSelection) {
path._updateSelection(this, oldSelection, selection);
// Let path know that we changed something and the view should be
// redrawn
path._changed(/*#=*/Change.ATTRIBUTE);
}
},
_getSelection: function(point) {
return !point ? /*#=*/SegmentSelection.ALL
: point === this._point ? /*#=*/SegmentSelection.POINT : point === this._point ? /*#=*/SegmentSelection.POINT
: point === this._handleIn ? /*#=*/SegmentSelection.HANDLE_IN : point === this._handleIn ? /*#=*/SegmentSelection.HANDLE_IN
: point === this._handleOut ? /*#=*/SegmentSelection.HANDLE_OUT : point === this._handleOut ? /*#=*/SegmentSelection.HANDLE_OUT
@ -277,33 +306,13 @@ var Segment = Base.extend(/** @lends Segment# */{
* path.segments[2].selected = true; * path.segments[2].selected = true;
*/ */
isSelected: function(_point) { isSelected: function(_point) {
return !!(this._selection & this._getSelectionFlag(_point)); return !!(this._selection & this._getSelection(_point));
}, },
setSelected: function(selected, _point) { setSelected: function(selected, _point) {
var path = this._path, var selection = this._selection,
selected = !!selected, // convert to boolean flag = this._getSelection(_point);
selection = this._selection, this.setSelection(selected ? selection | flag : selection & ~flag);
oldSelection = selection,
flag = this._getSelectionFlag(_point);
if (selected) {
selection |= flag;
} else {
selection &= ~flag;
}
// Set the selection state even if path is not defined yet, to allow
// selected segments to be inserted into paths and make JSON
// deserialization work.
this._selection = selection;
// If the selection state of the segment has changed, we need to let
// it's path know and possibly add or remove it from
// project._selectedItems
if (path && selection !== oldSelection) {
path._updateSelection(this, oldSelection, selection);
// Let path know that we changed something and the view should be
// redrawn
path._changed(/*#=*/Change.ATTRIBUTE);
}
}, },
/** /**

View file

@ -18,13 +18,14 @@
*/ */
var SegmentPoint = Point.extend({ var SegmentPoint = Point.extend({
initialize: function SegmentPoint(point, owner, key) { initialize: function SegmentPoint(point, owner, key) {
var x, y, selected; var x, y,
selected;
if (!point) { if (!point) {
x = y = 0; x = y = 0;
} else if ((x = point[0]) !== undefined) { // Array-like } else if ((x = point[0]) !== undefined) { // Array-like
y = point[1]; y = point[1];
} else { } else {
// So we don't have to modify the point argument which causes // So we don't have to modify the point argument which would cause
// deoptimization: // deoptimization:
var pt = point; var pt = point;
// If not Point-like already, read Point from arguments // If not Point-like already, read Point from arguments
@ -38,9 +39,9 @@ var SegmentPoint = Point.extend({
this._x = x; this._x = x;
this._y = y; this._y = y;
this._owner = owner; this._owner = owner;
// We have to set the owner's property that points to this point already
// now, so #setSelected(true) can work.
owner[key] = this; owner[key] = this;
// We need to call #setSelected(true) after setting property on the
// owner that references this point.
if (selected) if (selected)
this.setSelected(true); this.setSelected(true);
}, },
@ -52,15 +53,6 @@ var SegmentPoint = Point.extend({
return this; return this;
}, },
_serialize: function(options) {
var f = options.formatter,
x = f.number(this._x),
y = f.number(this._y);
return this.isSelected()
? { x: x, y: y, selected: true }
: [x, y];
},
getX: function() { getX: function() {
return this._x; return this._x;
}, },

View file

@ -11,11 +11,11 @@
*/ */
// Path#_segmentSelection is the addition of all segment's states, and is // Path#_segmentSelection is the addition of all segment's states, and is
// compared with SegmentSelection.SEGMENT, the combination of all // compared with SegmentSelection.ALL, the combination of all
// SegmentSelection values to see if all segments are fully selected. // SegmentSelection values to see if all segments are fully selected.
var SegmentSelection = { var SegmentSelection = {
HANDLE_IN: 1, POINT: 1,
HANDLE_OUT: 2, HANDLE_IN: 2,
POINT: 4, HANDLE_OUT: 4,
SEGMENT: 7 // HANDLE_IN | HANDLE_OUT | POINT ALL: 1 | 2 | 4 // POINT | HANDLE_IN | HANDLE_OUT
}; };