You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4112 lines
151 KiB
Plaintext

/**Diagramo namespace. We must place as much "global application" variables in here to avoid
* conflict and to achieve better management*/
var DIAGRAMO = {
/**Set it on true if you want visual debug clues.
* Note: See to set the Connector's visualDebug (Connector.visualDebug) to false too
**/
debug: false,
/**Keeps temporary connector solution.
* TODO: move to CONNECTOR_MANAGER?!*/
debugSolutions: [],
/** enables/disables rendering of currentCloud
* TODO: in further can be used for option like "Show Cloud" or "Highlight about to connect points" */
visualMagnet: true,
/** enables/disables rendering fill color as gradient*/
gradientFill: true,
/**On canvas fit action this will be the distance between canvas work area and it's border*/
CANVAS_FIT_PADDING: 10
};
/**Switch on/off debug
* @param {Boolean} value optional value
* */
DIAGRAMO.switchDebug = function (value) {
if (value == undefined) {
DIAGRAMO.debug = !DIAGRAMO.debug;
}
else {
DIAGRAMO.debug = value;
}
var iconDebug = document.getElementById('iconDebug');
if (DIAGRAMO.debug) {
iconDebug.src = './assets/images/icon_debug_true.gif';
}
else {
iconDebug.src = './assets/images/icon_debug_false.gif';
}
draw();
};
/*Activate the bellow block of code if anything else fails
*Helped me a lot on a remote iPad (https://bitbucket.org/scriptoid/diagramo/issue/118)
*with no available OSX around.
*TODO: Could be added as normal lister into a future verbosity option
**/
if (false) {
/**@see http://stackoverflow.com/questions/10197895/ipad-javascript-error-not-helpful*/
window.onerror = function (desc, page, line, chr) {
alert('Description: ' + desc
+ ' Page: ' + page
+ ' Line: ' + line
+ ' Position: ' + chr
);
};
}
/**Describe the file version of the file
* This will make easier to make upgrades in the future.
* Any time change in file format will be appear this number
* must be increased and also update the importer.js
* library
* */
DIAGRAMO.fileVersion = 4;
/**Activate or deactivate the undo feature
*@deprecated
***/
var doUndo = true;
/**Usually an instance of a Command (see /lib/commands/*.js)*/
var currentMoveUndo = null;
var CONNECTOR_MANAGER = new ConnectorManager();
var CONTAINER_MANAGER = new ContainerFigureManager();
/**An currentCloud - {Array} of 2 {ConnectionPoint} ids.
* Cloud highlights 2 {ConnectionPoint}s whose are able to connect. */
var currentCloud = [];
/**The width of grid cell.
*Must be an odd number.
*Must coincide with the size of the image used as canvas tile
**/
var GRIDWIDTH = 30;
/**The distance (from a snap line) that will trigger a snap*/
var SNAP_DISTANCE = 5;
/**The half of light distance between upper and lower border for gradient filling*/
var gradientLightStep = 0.06;
var fillColor = null;
var strokeColor = '#000000';
var currentText = null;
/** Instance of Browser Class for defining browser */
var Browser = new Browser();
/**Default top&bottom padding of Text editor's textarea*/
var defaultEditorPadding = 6;
/**Default border width of Text editor's textarea*/
var defaultEditorBorderWidth = 1;
/**
*Scrollbar width
*19px is the width added to a scrollable area (Zack discovered this into Chrome)
*We might compute this dimension too but for now it's fine
*even if we are wrong by a pixel or two
**/
var scrollBarWidth = 19;
var FIGURE_ESCAPE_DISTANCE = 30; /**the distance by which the connectors will escape Figure's bounds*/
/**the distance by which the connectors will be able to connect with Figure*/
var FIGURE_CLOUD_DISTANCE = 4;
/*It will store a reference to the function that will create a figure( ex: figureForKids:buildFigure3()) will be stored into this
*variable so upon click on canvas this function will create the object*/
var createFigureFunction = null;
var createFigureName = null;
/**A variable that tells us if CTRL is pressed*/
var CNTRL_PRESSED = false;
/**A variable that tells us if SHIFT is pressed*/
var SHIFT_PRESSED = false;
/**Current connector. It is null if no connector selected
* @deprecated
* TODO: we should base ONLY on selectedConnectorId
**/
var connector = null;
/**Connector type
* TODO: this should not be present here but retrieved from Connector object
**/
var connectorType = '';
/**It contains all the figure sets. Each figure set upon loading it will add a new
* entry to this array*/
var figureSets = [];
/**Used to generate nice formatted SVG files */
var INDENTATION = 0;
/**Export the Canvas as SVG. It will descend to whole graph of objects and ask
*each one to convert to SVG (and use the proper indentation)
*Note: Placed out of editor.php so we can safelly add '<?...' string
*@author Alex
*@deprecated
**/
function toSVG() {
return '';
/* Note: Support for SVG is suspended
*
var canvas = getCanvas();
//@see http://www.w3schools.com/svg/svg_example.asp
var v2 = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
v2 += "\n" + '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="'
+ canvas.width +'" height="' + canvas.height
+ '" viewBox="0 0 ' + canvas.width + ' ' + canvas.height + '" version="1.1">';
INDENTATION++;
v2 += STACK.toSVG();
v2 += CONNECTOR_MANAGER.toSVG();
INDENTATION--;
v2 += "\n" + '</svg>';
return v2;
*/
}
/**
*Supposelly stop any selection from happening
*/
function stopselection(ev) {
/*If we are selecting text within anything with the className text, we allow it
* This gives us the option of using textareas, inputs and any other item we
* want to allow text selection in.
**/
if (ev.target.className == "text") {
return true;
}
return false;
}
var STACK = new Stack();
/**keeps track if the MLB is pressed*/
var mousePressed = false;
/**the default application state*/
var STATE_NONE = 'none';
/**we have figure to be created**/
var STATE_FIGURE_CREATE = 'figure_create';
/**we selected a figure (for further editing for example)*/
var STATE_FIGURE_SELECTED = 'figure_selected';
/**we are selecting the start of a connector*/
var STATE_CONNECTOR_PICK_FIRST = 'connector_pick_first';
/**we are selecting the end of a connector*/
var STATE_CONNECTOR_PICK_SECOND = 'connector_pick_second';
/**we selected a connector (for further editing for example)*/
var STATE_CONNECTOR_SELECTED = 'connector_selected';
/**move a connection point of a connector*/
var STATE_CONNECTOR_MOVE_POINT = 'connector_move_point';
/**we are dragging the mouse over a group of figures.*/
var STATE_SELECTING_MULTIPLE = 'selecting_multiple';
/**we have a group selected (either temporary or permanent)*/
var STATE_GROUP_SELECTED = 'group_selected';
/**we have a container selected*/
var STATE_CONTAINER_SELECTED = 'container_selected';
/**we have a text editing*/
var STATE_TEXT_EDITING = 'text_editing';
/**connector continue create*/
var STATE_CONNECTOR_CREATE = 'connector_create';
/** 当前选择的是创建线状态 */
var STATE_FORM_CREATE_LINE = false;
/** formId **/
var CCForm_FK_MapData = null;
/**节点编号**/
var CCForm_NodeID = null;
/**Begin - Form Controls***************/
var CCForm_Controls = {
Line: 'Line',
Label: 'Label',
Button: 'Button',
HyperLink: 'HyperLink',
Image: 'Image',
Fieldset: 'Fieldset',
TextBox: 'TextBox',
TextBoxInt: 'TextBoxInt',
TextBoxMoney: 'TextBoxMoney',
TextBoxFloat: 'TextBoxFloat',
Date: 'Date',
DateTime: 'DateTime',
RadioButton: 'RadioButton',
RadioButtList: 'RadioButtonList',
CheckBox: 'CheckBox',
DropDownListEnum: 'DropDownListEnum',
DropDownListTable: 'DropDownListTable',
CheckBoxList: 'CheckBoxList',
Dtl: 'Dtl',
AthMulti: 'AthMulti',
AthSingle: 'AthSingle',
AthImg: 'AthImg',
Chart: 'Chart',
FrmCheck: 'FrmCheck',
SubFlowDtl: 'SubFlowDtl',
ThreadDtl: 'ThreadDtl',
FrmTransferCustom: 'FrmTransferCustom'
};
/**End - FormControl***********/
/**Keeps current state*/
var state = STATE_NONE;
/**The (current) selection area*/
var selectionArea = new Polygon();
selectionArea.points.push(new Point(0, 0));
selectionArea.points.push(new Point(0, 0));
selectionArea.points.push(new Point(0, 0));
selectionArea.points.push(new Point(0, 0));
selectionArea.style.strokeStyle = 'grey';
selectionArea.style.gradientBounds = [];
selectionArea.style.lineWidth = '1';
/**Toggle grid visible or not*/
var gridVisible = false;
/**Makes figure snap to grid*/
var snapTo = false;
/*show propertyWin show or hide*/
var propertyWinVisible = false;
/**Keeps last coodinates while dragging*/
var lastClick = [];
/**Default line width*/
var defaultLineWidth = 2;
/**Default handle line width*/
var defaultThinLineWidth = 1;
/**Current instance of TextEditorPopup*/
var currentTextEditor = null;
/**Current selected figure id ( -1 if none selected)*/
var selectedFigureId = -1;
/**Currently selected figure thumbnail (for D&D)*/
var selectedFigureThumb = null
/**Current selected group (-1 if none selected)*/
var selectedGroupId = -1;
/**Current selecte connector (-1 if none selected)*/
var selectedConnectorId = -1;
/**Current selectet container (-1 if none selected)*/
var selectedContainerId = -1;
/**Currently selected ConnectionPoint (if -1 none is selected)*/
var selectedConnectionPointId = -1;
/**Set on true while we drag*/
var dragging = false;
/**Currently inserted image filename*/
var insertedImageFileName = null;
/**Holds a wrapper around canvas object*/
var canvasProps = null;
/**Currently holds two elements the type: figure|group and the id*/
var clipboardBuffer = [];
/**Return current canvas.
* Current canvas will ALWAYS have the 'a' as DOM id
* @return {HTMLCanvasElement} the DOM element of <canvas> tag
* @author Alex Gheorghiu <alex@scriptoid.com>
**/
function getCanvas() {
var canvas = document.getElementById("a");
if (canvas.getAttribute("Height") != "8000") {
canvas.setAttribute('Height', '8000');
}
return canvas;
}
/**Return work area container.
* Work area container will ALWAYS have the 'container' as DOM id
* @return {HTMLElement} the DOM element of work area container
* @author Artyom Pokatilov <artyom.pokatilov@gmail.com>
**/
function getWorkAreaContainer() {
/**Id of work area HTML element, which includes canvas*/
var workAreaContainer = document.getElementById("container");
return workAreaContainer;
}
/**Return the 2D context of current canvas
* @author Alex Gheorghiu <alex@scriptoid.com>
**/
function getContext() {
var canvas = getCanvas();
if (canvas.getContext) {
return canvas.getContext("2d");
}
else {
alert('You need a HTML5 web browser. Any Safari,Firefox, Chrome or Explorer supports this.');
}
}
/**Keeps current figure set id*/
var currentSetId = 'basic';
/**
* Reveals the figure set named by 'name' and hide previously displayed set
* @param {String} id - the (div) id value of the set
* @author Alex
**/
function setFigureSet(id) {
Log.info("main.js id = " + id);
//alert(name);
var div = document.getElementById(id);
if (div != null) {
if (currentSetId != null) {
Log.info("main.js currentSetId = " + currentSetId);
var currentFigureSet = document.getElementById(currentSetId);
currentFigureSet.style.display = 'none';
}
div.style.display = 'block';
currentSetId = id;
}
}
/**Update an object (Figure or Connector)
*@param {Number} shapeId - the id of the updating object
*@param {String} property - (or an {Array} of {String}s). The 'id' under which the property is stored
*TODO: is there any case where we are using property as an array ?
*@param {String} newValue - the new value of the property
*@param {Boolean} [skipCommand = false] - if true than current {Command} won't be added to the {History}
*@param {String} [previousValue] - the previous value of the property
*@author Zack, Alex, Artyom
**/
function updateShape(shapeId, property, newValue, skipCommand, previousValue) {
// set default values of optional params
skipCommand = skipCommand || false;
var obj = STACK.figureGetById(shapeId); //try to find it inside {Figure}s
//TODO: this horror must dissapear
if (!obj) {
obj = CONNECTOR_MANAGER.connectorGetById(shapeId);
}
//container?
if (!obj) {
obj = STACK.containerGetById(shapeId);
}
var objSave = obj; //keep a reference to initial shape
/*Example of property 'primitives.1.str' */
var props = property.split(".");
/*Going down the object's hierarchy down to the property's parent
*Example:
* for props = ['primitives','1','str']
* figure
* |_primitives
* |_1 (it's a Text)
* |_str
*/
//Log.info("Object before descend: " + obj.oType);
var figure = obj; //TODO: Why this variable when we already have objSave?
for (var i = 0; i < props.length - 1; i++) {
obj = obj[props[i]];
}
//the property name
var propName = props[props.length - 1];
/*Now we are located at Figure level or somewhere in a primitive or another object.
*Here we will search for setXXX (where XXX is the property name) method first and if we find one we will use it
*if not we will simply update the property directly.
**/
/**Compute setXXX and getXXX*/
var propSet = "set" + Util.capitaliseFirstLetter(propName);
var propGet = "get" + Util.capitaliseFirstLetter(propName);
if (propSet in obj) { //@see https://developer.mozilla.org/en/JavaScript/Reference/Operators/Special_Operators/in_Operator
/*If something is complicated enough to need a function,
* likelyhood is it will need access to its parent figure.
*So we will let the parent to do the update as it likes, if it has
* a method of form set<property_name> in place
*/
if ((typeof (previousValue) !== 'undefined' && previousValue != obj[propGet])
|| (typeof (previousValue) === 'undefined' && newValue != obj[propGet]())) { //update ONLY if new value differ from the old one
var undo = new ShapeChangePropertyCommand(shapeId, property, newValue, previousValue);
undo.execute();
if (!skipCommand) {
History.addUndo(undo);
}
}
//TODO: Do we really need this anymore?
obj[propSet](newValue);
}
else {
if ((typeof (previousValue) !== 'undefined' && obj[propName] != previousValue)
|| (typeof (previousValue) === 'undefined' && obj[propName] != newValue)) { //try to change it ONLY if new value is different than the last one
var undo = new ShapeChangePropertyCommand(shapeId, property, newValue, previousValue);
undo.execute();
if (!skipCommand) {
History.addUndo(undo);
}
obj[propName] = newValue;
}
}
//connector's text special case
if (objSave instanceof Connector && propName == 'str') {
//Log.info("updateShape(): it's a connector 2");
objSave.updateMiddleText();
}
//Log.groupEnd();
draw();
}
/**Setup the editor panel for a special shape.
*@param shape - can be either Connector or Figure. If null is provided the
*editor panel will be disabled
**/
function setUpEditPanel(shape) {
//var propertiesPanel = canvas.edit; //access the edit div
var propertiesPanel = document.getElementById("edit");
propertiesPanel.innerHTML = "";
if (shape == null) {
//do nothing
}
else {
switch (shape.oType) {
case 'Group':
//do nothing. We do not want to offer this to groups
break;
case 'Container':
Builder.constructPropertiesPanel(propertiesPanel, shape);
break;
case 'CanvasProps':
Builder.constructCanvasPropertiesPanel(propertiesPanel, shape);
break;
default: //both Figure and Connector
Builder.constructPropertiesPanel(propertiesPanel, shape);
}
}
}
/**Setup edit mode for Text primitive.
*@param shape - parent of Text primitive. Can be either {Connector} or {Figure}.
*@param {Number} textPrimitiveId - the id value of Text primitive (from {Stack}
*@author Artyom
**/
function setUpTextEditorPopup(shape, textPrimitiveId) {
// get elements of Text Editor and it's tools
var textEditor = document.getElementById('text-editor'); //a <div> inside editor page
var textEditorTools = document.getElementById('text-editor-tools'); //a <div> inside editor page
// set current Text editor to use it further in code
currentTextEditor = Builder.constructTextPropertiesPanel(textEditor, textEditorTools, shape, textPrimitiveId);
}
/**Setup the creation function (that -later, upon calling - will create the actual {Figure}
* Note: It will also set the current state to STATE_FIGURE_CREATE
* @param {Function} fFunction - the function used to create the figure
* @param {String} thumbURL - the URL to the thumb of the image
**/
function createFigure(fFunction, thumbURL, fName) {
//Log.info('createFigure (' + fFunction + ',' + thumbURL + ')');
createFigureFunction = fFunction;
createFigureName = fName;
selectedFigureThumb = thumbURL;
selectedFigureId = -1;
selectedConnectorId = -1;
selectedConnectionPointId = -1;
if (state == STATE_TEXT_EDITING) {
currentTextEditor.destroy();
currentTextEditor = null;
}
state = STATE_FIGURE_CREATE;
draw();
}
/*
* Resets any state to STATE_NONE
*/
function resetToNoneState() {
// clear text editing mode
if (state == STATE_TEXT_EDITING) {
currentTextEditor.destroy();
currentTextEditor = null;
}
// deselect everything
selectedFigureId = -1;
selectedConnectionPointId = -1;
selectedConnectorId = -1;
selectedContainerId = -1;
// if group selected
if (state == STATE_GROUP_SELECTED) {
var selectedGroup = STACK.groupGetById(selectedGroupId);
// if group is temporary then destroy it
if (!selectedGroup.permanent) {
STACK.groupDestroy(selectedGroupId);
}
//deselect current group
selectedGroupId = -1;
}
state = STATE_NONE;
}
// Id of the DOM object for errors of image upload
var uploadImageErrorDivId = 'upload-image-error';
/** Show "Insert image" dialog
* Insert image dialog can be triggered in 1 case:
* 1 - from quick toolbar
* Description:
* Call popup to get image from url or upload target image from local
* @author Artyom Pokatilov <artyom.pokatilov@gmail.com>
**/
function showInsertImageDialog() {
resetToNoneState();
draw();
//setUploadedImagesList();
var dialogContent = document.getElementById('insert-image-dialog');
$.modal(dialogContent, { minWidth: '380px', containerId: 'upload-image-dialog', overlayClose: true });
// update dialog's position
$.modal.setPosition();
}
/** Show filenames of uploaded images in "Insert image" dialog
* Get filenames from server and insert them into dialog
* @author Artyom Pokatilov <artyom.pokatilov@gmail.com>
**/
function setUploadedImagesList() {
//see: http://api.jquery.com/jQuery.get/
$.post("./common/controller.php",
{ action: 'getUploadedImageFileNames' },
function (data) {
var list = document.getElementById('insert-image-reuse');
var reuseGroup = document.getElementById('insert-image-reuse-group');
data = JSON.parse(data);
if (data != null && data.length) {
var i,
length = data.length,
option;
// add options with filenames to select
for (i = 0; i < length; i++) {
option = document.createElement('option');
option.value = data[i];
option.textContent = data[i];
list.appendChild(option);
}
// enable reuse select and group button
list.disabled = false;
reuseGroup.disabled = false;
} else {
// disable reuse select and group button
list.disabled = true;
reuseGroup.disabled = true;
}
}
);
}
/** Insert image into current diagram
* Insert image can be triggered in 1 case:
* 1 - from insert image dialog
*
* @param {String} imageFileName - filename of uploaded image
* @param {String} errorMessage - error message
*
* Description:
* 1) Call popup to get image from url or upload target image from local
* 2) Save image to backend
* 3) Close popup
* 4) If there were errors - go to 5 else - go to 6
* 5) Alert error message
* 6) Create figure with target image and text caption
*
* @author Artyom Pokatilov <artyom.pokatilov@gmail.com>
**/
function insertImage(imageFileName, errorMessage) {
if (errorMessage) {
// set upload errors to dialog
var errorDiv = document.getElementById(uploadImageErrorDivId);
errorDiv.innerHTML = errorMessage;
// update dialog's position
$.modal.setPosition();
} else {
// close current insert image dialog
$.modal.close();
insertedImageFileName = imageFileName;
action('insertImage');
}
}
/**Activate snapToGrip option*/
function snapToGrid() {
Log.info("snapToGrid called;");
snapTo = !snapTo;
if (snapTo) {
if (!gridVisible) {
gridVisible = true;
backgroundImage = null; // reset cached background image of canvas
document.getElementById("gridCheckbox").checked = true;
//trigger a repaint;
draw();
}
}
}
/**是否显示属性窗口*/
function propertyForm() {
Log.info("propertyForm show or hidden;");
propertyWinVisible = !propertyWinVisible;
if (propertyWinVisible) {
$('#right').show();
document.getElementById("propertyCheckbox").checked = true;
$('#container').css('right', '247px');
} else {
$('#right').hide();
document.getElementById("propertyCheckbox").checked = false;
$('#container').css('right', '0px');
}
}
/**Makes grid visible or invisible, depedinding of previous value
*If the "snap to" was active and grid made invisible the "snap to"
*will be disabled
**/
function ShowGrid() {
/**If grid was visible and snap to was check we need to take measures*/
if (gridVisible) {
if (snapTo) {
snapTo = false;
document.getElementById("snapCheckbox").checked = false;
}
}
gridVisible = !gridVisible;
backgroundImage = null; // reset cached background image of canvas
//trigger a repaint;
draw();
}
/**Click is disabled because we need to handle mouse down and mouse up....etc etc etc*/
function onClick(ev) {
var coords = getCanvasXY(ev);
var x = coords[0];
var y = coords[1];
//here is the problem....how do we know we clicked on canvas
/*var fig=STACK.figures[STACK.figureGetMouseOver(x,y,null)];
if(CNTRL_PRESSED && fig!=null){
TEMPORARY_GROUP.addPrimitive();
STACK.figureRemove(fig);
STACK.figureAdd(TEMPORARY_GROUP);
}
else if(STACK.figureGetMouseOver(x,y,null)!=null){
TEMPORARY_GROUP.primitives=[];
TEMPORARY_GROUP.addPrimitive(fig);
STACK.figureRemove(fig);
}*/
//draw();
}
/**
* @deprecated Does not seem to be used
* */
function onDoubleClick(ev) {
var coords = getCanvasXY(ev);
var HTMLCanvas = getCanvas();
var x = coords[0];
var y = coords[1];
lastClick = [x, y];
// Log.info("onMouseDown at (" + x + "," + y + ")");
//alert('lastClick: ' + lastClick + ' state: ' + state);
//mousePressed = true;
alert("Double click triggered");
}
/**Receives the ASCII character code but not the keyboard code
*@param {Event} ev - the event generated when kay is pressed
*@see <a href="http://www.quirksmode.org/js/keys.html">http://www.quirksmode.org/js/keys.html</a>
**/
function onKeyPress(ev) {
//ignore texts
if (ev.target.className == "text") {
return true;
}
draw();
return false;
}
/**
*Receives the key code of keyboard but not the ASCII
*Treats the key pressed event
*@param {Event} ev - the event generated when key is down
*@see <a href="http://www.quirksmode.org/jskey/keys.html">http://www.quirksmode.org/js/keys.html</a>
**/
function onKeyDown(ev) {
//1 - avoid text elements (if you are on a text area and you press the arrow you do not want the figures to move on canvas)
if (ev.target.className == "text") {
return true;
}
//2 - "enhance" event TODO: I'm not sure this is really necessary
ev.KEY = ev.keyCode;
switch (ev.KEY) {
case KEY.ESCAPE: //Esc
//alert('So do you want to escape me');
//cancel any figure creation
createFigureFunction = null;
if (selectedFigureId != -1 || selectedConnectionPointId != -1 || selectedConnectorId != -1) {
redraw = true;
}
//deselect any figure
selectedFigureId = -1;
selectedConnectionPointId = -1;
selectedConnectorId = -1;
// clear current text editor
if (state == STATE_TEXT_EDITING) {
currentTextEditor.destroy();
currentTextEditor = null;
}
state = STATE_NONE;
break;
case KEY.DELETE: //Delete
//delete any Figure or Group
// alert('Delete pressed' + this);
switch (state) {
case STATE_FIGURE_SELECTED: //delete a figure ONLY when the figure is selected
if (selectedFigureId != -1) {
var cmdDelFig = new FigureDeleteCommand(selectedFigureId);
cmdDelFig.execute();
History.addUndo(cmdDelFig);
}
break;
case STATE_GROUP_SELECTED:
if (selectedGroupId != -1) {
var cmdDelGrp = new GroupDeleteCommand(selectedGroupId);
cmdDelGrp.execute();
History.addUndo(cmdDelGrp);
}
break;
case STATE_CONNECTOR_SELECTED:
Log.group("Delete connector");
if (selectedConnectorId != -1) {
var cmdDelCon = new ConnectorDeleteCommand(selectedConnectorId);
cmdDelCon.execute();
History.addUndo(cmdDelCon);
}
Log.groupEnd();
break;
case STATE_CONTAINER_SELECTED:
Log.group("Delete container");
if (selectedContainerId != -1) {
var cmdDelContainer = new ContainerDeleteCommand(selectedContainerId);
cmdDelContainer.execute();
History.addUndo(cmdDelContainer);
}
Log.groupEnd();
break;
}
break;
case KEY.SHIFT: //Shift
SHIFT_PRESSED = true;
break;
case KEY.CTRL: //Ctrl
case KEY.COMMAND_LEFT:
case KEY.COMMAND_FIREFOX:
CNTRL_PRESSED = true;
break;
case KEY.LEFT: //Arrow Left
case KEY.A:
action("left");
return false;
break;
case KEY.UP: //Arrow Up
case KEY.W:
// alert('up');
action("up");
return false;
break;
case KEY.RIGHT: //Arrow Right
case KEY.D:
action("right");
return false;
break;
case KEY.DOWN: //Arrow Down
case KEY.S:
if (CNTRL_PRESSED) {
//Log.info("CTRL-S pressed ");
save(true);
ev.preventDefault();
} else {
action("down");
}
break;
case KEY.Z:
if (CNTRL_PRESSED) {
//action('undo');
}
break;
// case KEY.Y:
// if(CNTRL_PRESSED){
// action('redo');
// }
// break;
case KEY.G:
if (CNTRL_PRESSED) {
//action('group');
}
break;
case KEY.U:
if (CNTRL_PRESSED) {
//action('ungroup');
}
break;
case KEY.D:
if (CNTRL_PRESSED) {
if (ev.preventDefault) {
ev.preventDefault();
}
else {
ev.returnValue = false;
}
//action('duplicate');
}
break;
case KEY.C:
if (CNTRL_PRESSED) {
if (selectedFigureId != -1) {
clipboardBuffer[0] = "figure";
clipboardBuffer[1] = selectedFigureId;
} else if (selectedGroupId != -1) {
clipboardBuffer[0] = "group";
clipboardBuffer[1] = selectedGroupId;
} else if (selectedConnectorId != -1) {
clipboardBuffer[0] = "connector";
clipboardBuffer[1] = selectedConnectorId;
} else {
clipboardBuffer[0] = "";
clipboardBuffer[1] = -1;
}
}
break;
case KEY.V:
if (CNTRL_PRESSED) {
/*Description:
* If figure or group copied here is what can happen:
* - if no selection -> STATE_NONE:
* - if figure copied then duplicate it
* - if group copied then check if it`s not permanent, becase then we have lost it, and if not, then duplicate it
* - if figure selected (ONLY if figure copied):
* - if it is same figure as copied, then duplicate it
* also because the duplicate will become selected, add it to the clipboard thus allowing another paste
* - if it is another figure, then apply style to it
* - if group selected:
* //TODO: for Janis see comments/description on GroupCloneCommands
* - if it is same group as copied, then duplicate it, in this case we can also duplicate permanent group
* also because the duplicate will become selected, add it to the clipboard thus allowing another paste
* - if it is another group, and if we have COPIED THE FIGURE, then apply its style to all group
*
*/
if (clipboardBuffer[0]) {// if something was copied
switch (state) {
case STATE_NONE:
if (clipboardBuffer[0] == "figure") {
selectedFigureId = clipboardBuffer[1];
action('duplicate');
} else if (clipboardBuffer[0] == "group") {
selectedGroupId = clipboardBuffer[1];
if (STACK.groupGetById(selectedGroupId)) { //if this is true, then the group isn`t permanent
action('duplicate');
}
}
break;
case STATE_FIGURE_SELECTED:
if (clipboardBuffer[0] == "figure") {
if (clipboardBuffer[1] == selectedFigureId) {
action('duplicate');
//this means we add the copied to the clipboard, thus allowing another paste (it is ok, since the style is same)
clipboardBuffer[1] = selectedFigureId;
} else { //apply style
//TODO: I do think style should be applied by users directly.
var copiedFigure = STACK.figureGetById(clipboardBuffer[1]);
var selectedFigure = STACK.figureGetById(selectedFigureId);
selectedFigure.applyAnotherFigureStyle(copiedFigure);
}
}
break;
case STATE_GROUP_SELECTED:
if (clipboardBuffer[1] == selectedGroupId) {
action('duplicate');
//this means we add the copied to the clipboard, thus allowing another paste (it is ok, since the style is same)
clipboardBuffer[1] = selectedGroupId;
} else {
//TODO: I do think style should be applied by users directly, even less to spread a figure's style to a whole group
if (clipboardBuffer[0] == "figure") { //if we have copied the figure, apply style to group
var copiedFigure = STACK.figureGetById(clipboardBuffer[1]);
var groupFigures = STACK.figureGetByGroupId(selectedGroupId);
for (var i = 0; i < groupFigures.length; i++) {
groupFigures[i].applyAnotherFigureStyle(copiedFigure);
}
}
}
break;
case STATE_CONNECTOR_SELECTED:
if (clipboardBuffer[1] == selectedConnectorId) {
action('duplicate');
clipboardBuffer[1] = selectedConnectorId;
} else {
if (clipboardBuffer[0] == "connector") { //if we have copied the connector
var copiedCon = CONNECTOR_MANAGER.connectorGetById(clipboardBuffer[1]);
var selectedCon = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId);
selectedCon.applyAnotherConnectorStyle(copiedCon);
}
}
break;
}
}
}
break;
case KEY.S:
if (CNTRL_PRESSED) {
//Log.info("CTRL-S pressed ");
save();
ev.preventDefault();
}
break;
case KEY.P:
if (currentDiagramId !== null) {
if (CNTRL_PRESSED) {
Log.info("CTRL-P pressed ");
print_diagram();
ev.preventDefault();
}
}
break;
}
draw();
return false;
}
/**
*Treats the key up event
*@param {Event} ev - the event generated when key is up
**/
function onKeyUp(ev) {
switch (ev.keyCode) {
case KEY.SHIFT: //Shift
SHIFT_PRESSED = false;
break;
case KEY.ALT: //Alt
CNTRL_PRESSED = false;
break;
case KEY.CTRL: //Ctrl
CNTRL_PRESSED = false;
break;
}
return false;
}
/**
*Treats the mouse down event
*@param {Event} ev - the event generated when button is pressed
**/
function onMouseDown(ev) {
var coords = getCanvasXY(ev);
var HTMLCanvas = getCanvas();
var x = coords[0];
var y = coords[1];
lastClick = [x, y];
// Log.info("onMouseDown at (" + x + "," + y + ")");
//alert('lastClick: ' + lastClick + ' state: ' + state);
mousePressed = true;
//alert("onMouseDown() + state " + state + " none state is " + STATE_NONE);
switch (state) {
case STATE_TEXT_EDITING:
/*Description:
* If we have active text editor in popup and we click mouse. Here is what can happen:
* - if we clicked inside current text editor that nothing is happening
* - if we clicked canvas:
* - we trigger onblur of text editor for IE and FF manually
* - we will remove text editor
* - we will switch to STATE_NONE
* - we will run STATE_NONE case next (without break;)
*/
if (currentTextEditor.mouseClickedInside(ev)) {
break;
} else {
// IE and Firefox doesn't trigger blur event when mouse clicked canvas
// that is why we trigger this event manually
if (Browser.msie || Browser.mozilla) {
currentTextEditor.blurTextArea();
}
currentTextEditor.destroy();
currentTextEditor = null;
state = STATE_NONE;
}
// TODO: Further needs to be the same behaviour as for the STATE_NONE case
// to avoid repeating of the code next "break" statement commented to let execution flow down
// break;
case STATE_NONE:
//alert("onMouseDown() - STATE_NONE");
snapMonitor = [0, 0];
/*Description:
* We are in None state when no action was done....yet. Here is what can happen:
* - if we clicked a Connector than that Connector should be selected
* (Connectors are more important than Figures :p)
* - if we clicked a Group:
* - select the Group
* - if we clicked a Figure:
* - select the Figure
* - if we clicked a Container (Figures more important than Container)
* - select the Container
* - if we did not clicked anything....
* - we will stay in STATE_NONE
* - allow to edit canvas
*
*/
var selectedObject = Util.getObjectByXY(x, y); // get object under cursor
switch (selectedObject.type) {
case 'Connector':
selectedConnectorId = selectedObject.id;
state = STATE_CONNECTOR_SELECTED;
setUpEditPanel(CONNECTOR_MANAGER.connectorGetById(selectedConnectorId));
Log.info('onMouseDown() + STATE_NONE - change to STATE_CONNECTOR_SELECTED');
redraw = true;
break;
case 'Group':
selectedGroupId = selectedObject.id;
state = STATE_GROUP_SELECTED;
setUpEditPanel(null);
Log.info('onMouseDown() + STATE_NONE + group selected => change to STATE_GROUP_SELECTED');
break;
case 'Figure':
selectedFigureId = selectedObject.id;
state = STATE_FIGURE_SELECTED;
setUpEditPanel(STACK.figureGetById(selectedFigureId));
Log.info('onMouseDown() + STATE_NONE + lonely figure => change to STATE_FIGURE_SELECTED');
redraw = true;
break;
case 'Container':
selectedContainerId = selectedObject.id;
state = STATE_CONTAINER_SELECTED;
setUpEditPanel(STACK.containerGetById(selectedContainerId));
Log.info('onMouseDown() + STATE_NONE - change to STATE_CONTAINER_SELECTED');
redraw = true;
break;
default:
if (STATE_FORM_CREATE_LINE == true) {
var canvas = getCanvas();
canvas.style.cursor = 'crosshair';
state = STATE_CONNECTOR_CREATE;
onMouseDown(ev);
}
break;
}
break;
case STATE_FIGURE_CREATE:
// selectedConnectorId = -1;
// createFigureFunction = null;
//
// mousePressed = false;
// redraw = true;
throw "canvas> onMouseDown> STATE_FIGURE_CREATE> : this should not happen";
break;
case STATE_FIGURE_SELECTED:
snapMonitor = [0, 0];
//CONNECTOR
if (HandleManager.handleGet(x, y) != null) { //Clicked a handler (of a Figure or Connector)
Log.info("onMouseDown() + STATE_FIGURE_SELECTED - handle selected");
/*Nothing important (??) should happen here. We just clicked the handler of the figure*/
HandleManager.handleSelectXY(x, y);
}
else { //We did not clicked a handler
var selectedObject = Util.getObjectByXY(x, y); // get object under cursor
switch (selectedObject.type) {
case 'Connector':
state = STATE_CONNECTOR_SELECTED;
selectedConnectorId = selectedObject.id;
selectedFigureId = -1;
var con = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId);
HandleManager.shapeSet(con);
setUpEditPanel(con);
Log.info('onMouseDown() + STATE_FIGURE_SELECTED - change to STATE_CONNECTOR_SELECTED');
redraw = true;
break;
case 'Group':
if (SHIFT_PRESSED) {
var figuresToAdd = [];
/* TODO: for what reason we have this condition in STATE_FIGURE_SELECTED?
* Seems like escaping of bigger problem */
if (selectedFigureId != -1) { //add already selected figure
figuresToAdd.push(selectedFigureId);
}
var groupFigures = STACK.figureGetByGroupId(selectedObject.id);
for (var i = 0; i < groupFigures.length; i++) {
figuresToAdd.push(groupFigures[i].id);
}
// create group for current figure joined with clicked group
selectedGroupId = STACK.groupCreate(figuresToAdd);
Log.info('onMouseDown() + STATE_FIGURE_SELECTED + SHIFT + another group => STATE_GROUP_SELECTED');
} else {
selectedGroupId = selectedObject.id;
Log.info('onMouseDown() + STATE_FIGURE_SELECTED + group figure => change to STATE_GROUP_SELECTED');
}
selectedFigureId = -1;
state = STATE_GROUP_SELECTED;
setUpEditPanel(null);
redraw = true;
break;
case 'Figure': //lonely figure
if (SHIFT_PRESSED) {
var figuresToAdd = [];
/* TODO: for what reason we have this condition in STATE_FIGURE_SELECTED?
* Seems like escaping of bigger problem */
if (selectedFigureId != -1) { //add already selected figure
figuresToAdd.push(selectedFigureId);
}
figuresToAdd.push(selectedObject.id); //add ONLY clicked selected figure
selectedFigureId = -1;
// we have two figures, create a group
selectedGroupId = STACK.groupCreate(figuresToAdd);
state = STATE_GROUP_SELECTED;
setUpEditPanel(null);
Log.info('onMouseDown() + STATE_FIGURE_SELECTED + SHIFT + min. 2 figures => STATE_GROUP_SELECTED');
} else {
selectedFigureId = selectedObject.id;
HandleManager.clear();
setUpEditPanel(STACK.figureGetById(selectedFigureId));
Log.info('onMouseDown() + STATE_FIGURE_SELECTED + single figure => change to STATE_FIGURE_SELECTED (different figure)');
}
redraw = true;
break;
case 'Container':
selectedFigureId = -1;
selectedContainerId = selectedObject.id;
state = STATE_CONTAINER_SELECTED;
Log.info('onMouseDown() + STATE_FIGURE_SELECTED + single container - change to STATE_CONTAINER_SELECTED');
setUpEditPanel(STACK.containerGetById(selectedContainerId));
redraw = true;
break;
default: //mouse down on empty space
if (!SHIFT_PRESSED) { //if Shift isn`t pressed
selectedFigureId = -1;
state = STATE_NONE;
setUpEditPanel(canvasProps);
Log.info('onMouseDown() + STATE_FIGURE_SELECTED - change to STATE_NONE');
}
redraw = true;
break;
}
}
break;
case STATE_GROUP_SELECTED:
//GROUPS
//if selected group is temporary and we pressed outside of it's border we will destroy it
var selectedGroup = STACK.groupGetById(selectedGroupId);
if (HandleManager.handleGet(x, y) != null) { //handle ?
HandleManager.handleSelectXY(x, y);
redraw = true;
Log.info('onMouseDown() + STATE_GROUP_SELECTED + handle selected => STATE_GROUP_SELECTED');
}
else {
// get object under cursor
var selectedObject = Util.getObjectByXY(x, y);
switch (selectedObject.type) {
case 'Connector':
//destroy current group (if temporary)
if (!selectedGroup.permanent) {
STACK.groupDestroy(selectedGroupId);
}
//deselect current group
selectedGroupId = -1;
selectedConnectorId = selectedObject.id;
state = STATE_CONNECTOR_SELECTED;
redraw = true;
Log.info('onMouseDown() + STATE_GROUP_SELECTED + handle selected => STATE_CONNECTOR_SELECTED');
break;
case 'Group':
if (selectedObject.id != selectedGroupId) {
if (SHIFT_PRESSED) {
var figuresToAdd = [];
//add figures from current group
var groupFigures = STACK.figureGetByGroupId(selectedGroupId);
for (var i = 0; i < groupFigures.length; i++) {
figuresToAdd.push(groupFigures[i].id);
}
//add figures from clicked group
groupFigures = STACK.figureGetByGroupId(selectedObject.id);
for (var i = 0; i < groupFigures.length; i++) {
figuresToAdd.push(groupFigures[i].id);
}
//destroy current group (if temporary)
if (!selectedGroup.permanent) {
STACK.groupDestroy(selectedGroupId);
}
selectedGroupId = STACK.groupCreate(figuresToAdd);
} else {
//destroy current group (if temporary)
if (!selectedGroup.permanent) {
STACK.groupDestroy(selectedGroupId);
}
selectedGroupId = selectedObject.id;
}
redraw = true;
Log.info('onMouseDown() + STATE_GROUP_SELECTED + (different) group figure => STATE_GROUP_SELECTED');
}
else { //figure from same group
//do nothing
}
break;
case 'Figure': //lonely figure
if (SHIFT_PRESSED) {
var figuresToAdd = [];
var groupFigures = STACK.figureGetByGroupId(selectedGroupId);
for (var i = 0; i < groupFigures.length; i++) {
figuresToAdd.push(groupFigures[i].id);
}
figuresToAdd.push(selectedObject.id);
//destroy current group (if temporary)
if (!selectedGroup.permanent) {
STACK.groupDestroy(selectedGroupId);
}
selectedGroupId = STACK.groupCreate(figuresToAdd);
Log.info('onMouseDown() + STATE_GROUP_SELECTED + SHIFT + add lonely figure to other');
} else {
//destroy current group (if temporary)
if (!selectedGroup.permanent) {
STACK.groupDestroy(selectedGroupId);
}
//deselect current group
selectedGroupId = -1;
state = STATE_FIGURE_SELECTED;
selectedFigureId = selectedObject.id;
Log.info('onMouseDown() + STATE_GROUP_SELECTED + lonely figure => STATE_FIGURE_SELECTED');
setUpEditPanel(STACK.figureGetById(selectedFigureId));
redraw = true;
}
break;
case 'Container':
//destroy current group (if temporary)
if (!selectedGroup.permanent) {
STACK.groupDestroy(selectedGroupId);
}
//deselect current group
selectedGroupId = -1;
state = STATE_CONTAINER_SELECTED;
selectedContainerId = selectedObject.id;
Log.info('onMouseDown() + STATE_GROUP_SELECTED + container => STATE_CONTAINER_SELECTED');
setUpEditPanel(STACK.containerGetById(selectedContainerId));
redraw = true;
break;
default: //mouse down on empty space
if (!SHIFT_PRESSED) { //if Shift isn`t pressed
if (!selectedGroup.permanent) {
STACK.groupDestroy(selectedGroupId);
}
selectedGroupId = -1;
state = STATE_NONE;
setUpEditPanel(canvasProps);
redraw = true;
Log.info('onMouseDown() + STATE_GROUP_SELECTED + mouse on empty => STATE_NONE');
}
break;
}
}
break;
case STATE_CONNECTOR_PICK_FIRST:
//moved so it can be called from undo action
//connectorPickFirst(x, y, ev);
break;
case STATE_CONNECTOR_PICK_SECOND:
state = STATE_NONE;
break;
case STATE_CONNECTOR_SELECTED:
var cps = CONNECTOR_MANAGER.connectionPointGetAllByParent(selectedConnectorId);
var start = cps[0];
var end = cps[1];
var figureConnectionPointId;
//did we click any of the connection points?
if (start.point.near(x, y, 3)) {
Log.info("Picked the start point");
selectedConnectionPointId = start.id;
state = STATE_CONNECTOR_MOVE_POINT;
HTMLCanvas.style.cursor = 'default';
//this acts like clone of the connector
var undoCmd = new ConnectorAlterCommand(selectedConnectorId);
History.addUndo(undoCmd);
// check if current cloud for connection point
figureConnectionPointId = CONNECTOR_MANAGER.connectionPointGetByXYRadius(x, y, FIGURE_CLOUD_DISTANCE, ConnectionPoint.TYPE_FIGURE, end);
if (figureConnectionPointId !== -1) {
currentCloud = [selectedConnectionPointId, figureConnectionPointId];
}
}
else if (end.point.near(x, y, 3)) {
Log.info("Picked the end point");
selectedConnectionPointId = end.id;
state = STATE_CONNECTOR_MOVE_POINT;
HTMLCanvas.style.cursor = 'default';
//this acts like clone of the connector
var undoCmd = new ConnectorAlterCommand(selectedConnectorId);
History.addUndo(undoCmd);
// check if current cloud for connection point
figureConnectionPointId = CONNECTOR_MANAGER.connectionPointGetByXYRadius(x, y, FIGURE_CLOUD_DISTANCE, ConnectionPoint.TYPE_FIGURE, start);
if (figureConnectionPointId !== -1) {
currentCloud = [selectedConnectionPointId, figureConnectionPointId];
}
}
else { //no connection point selected
//see if handler selected
if (HandleManager.handleGet(x, y) != null) {
Log.info("onMouseDown() + STATE_CONNECTOR_SELECTED - handle selected");
HandleManager.handleSelectXY(x, y);
//TODO: just copy/paste code ....this acts like clone of the connector
var undoCmd = new ConnectorAlterCommand(selectedConnectorId);
History.addUndo(undoCmd);
}
else {
// get object under cursor
var selectedObject = Util.getObjectByXY(x, y);
switch (selectedObject.type) {
case 'Connector':
selectedConnectorId = selectedObject.id;
selectedFigureId = -1;
var con = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId);
HandleManager.shapeSet(con);
setUpEditPanel(con);
redraw = true;
break;
case 'Group':
selectedConnectorId = -1;
selectedGroupId = selectedObject.id; // set Group as active element
state = STATE_GROUP_SELECTED;
setUpEditPanel(null);
redraw = true;
break;
case 'Figure':
selectedConnectorId = -1;
selectedFigureId = selectedObject.id; // set Figure as active element
state = STATE_FIGURE_SELECTED;
setUpEditPanel(STACK.figureGetById(selectedFigureId));
redraw = true;
break;
case 'Container':
selectedConnectorId = -1;
selectedContainerId = selectedObject.id; // set Container as active element
state = STATE_CONTAINER_SELECTED;
setUpEditPanel(STACK.containerGetById(selectedContainerId));
redraw = true;
break;
default: // nothing else selected
selectedConnectorId = -1;
state = STATE_NONE;
setUpEditPanel(canvasProps); // set canvas as active element
redraw = true;
break;
}
}
}
break; //end case STATE_CONNECTOR_SELECTED
case STATE_CONTAINER_SELECTED:
/*Description:
* If we have a Container selected and we do click here is what can happen:
* - if we clicked a handle of current selected shape (it should be Container) then just select that Handle
* - if we clicked a Connector, Group or than it should be selected (Connectors, Groups and Figures are more important than Containers :p)
* - if we clicked a Container:
* - did we clicked another Container?
* - select that Container
* - did we click same Container?
* - do nothing
*/
if (HandleManager.handleGet(x, y) != null) { //Clicked a handler (of a Figure or Connector)
Log.info("onMouseDown() + STATE_CONTAINER_SELECTED - handle selected");
/*Nothing important (??) should happen here. We just clicked the handler of the figure*/
HandleManager.handleSelectXY(x, y);
}
else {
// get object under cursor
var selectedObject = Util.getObjectByXY(x, y);
switch (selectedObject.type) {
case 'Connector':
selectedContainerId = -1;
selectedConnectorId = selectedObject.id;
state = STATE_CONNECTOR_SELECTED;
Log.info('onMouseDown() + STATE_CONTAINER_SELECTED - change to STATE_CONNECTOR_SELECTED');
setUpEditPanel(CONNECTOR_MANAGER.connectorGetById(selectedConnectorId));
redraw = true;
break;
case 'Group':
selectedContainerId = -1;
selectedGroupId = selectedObject.id;
state = STATE_GROUP_SELECTED;
Log.info('onMouseDown() + STATE_CONTAINER_SELECTED + group selected => change to STATE_GROUP_SELECTED');
setUpEditPanel(null);
redraw = true;
break;
case 'Figure':
selectedContainerId = -1;
selectedFigureId = selectedObject.id;
state = STATE_FIGURE_SELECTED;
Log.info('onMouseDown() + STATE_CONTAINER_SELECTED + lonely figure => change to STATE_FIGURE_SELECTED');
setUpEditPanel(STACK.figureGetById(selectedFigureId));
redraw = true;
break;
case 'Container':
if (selectedObject.id != selectedContainerId) { //a different one
selectedContainerId = selectedObject.id;
Log.info('onMouseDown() + STATE_NONE - change to STATE_CONTAINER_SELECTED');
setUpEditPanel(STACK.containerGetById(selectedContainerId));
redraw = true;
}
break;
default: // nothing else selected
selectedContainerId = -1;
state = STATE_NONE;
setUpEditPanel(canvasProps);
HandleManager.clear();
Log.info('onMouseDown() + STATE_CONTAINER_SELECTED + click on nothing - change to STATE_NONE');
redraw = true;
break;
}
}
break; //end STATE_CONTAINER_SELECTED
case STATE_CONNECTOR_CREATE:
selectedFigureId = -1;
state = STATE_CONNECTOR_PICK_FIRST;
connectorType = Connector.TYPE_STRAIGHT;
redraw = true;
break;
default:
//alert("onMouseDown() - switch default - state is " + state);
}
draw();
return false;
}
/**
*Treats the mouse up event
*@param {Event} ev - the event generated when key is up
**/
function onMouseUp(ev) {
Log.info("main.js>onMouseUp()");
var coords = getCanvasXY(ev);
var x = coords[0];
var y = coords[1];
lastClick = [];
mousePressed = true;
switch (state) {
case STATE_NONE:
/*Description:
* TODO: Nothing should happen here
*/
if (HandleManager.handleGetSelected()) {
HandleManager.clear();
}
break;
case STATE_FIGURE_SELECTED:
/*Description:
* This means that we have a figure selected and just released the mouse:
* - if we were altering (rotate/resize) the Figure that will stop (Handler will be deselected)
* - if we were moving the figure .... that will stop (but figure remains selected)
*/
mousePressed = false;
HandleManager.handleSelectedIndex = -1; //reset only the handler....the Figure is still selected
break;
case STATE_CONTAINER_SELECTED:
/*Description:
* This means that we have a Container selected and just released the mouse:
* - if we were altering (rotate/resize) the Container that will stop (Handler will be deselected)
* - if we were moving the Container .... that will stop (but figure remains selected)
*/
mousePressed = false;
HandleManager.handleSelectedIndex = -1; //reset only the handler....the Figure is still selected
break;
case STATE_GROUP_SELECTED:
Log.info('onMouseUp() + STATE_GROUP_SELECTED ...');
mousePressed = false;
HandleManager.handleSelectedIndex = -1; //reset only the handler....the Group is still selected
break;
case STATE_SELECTING_MULTIPLE:
/*Description
*From figures select only those that do not belong to any group
**/
Log.info('onMouseUp() + STATE_SELECTING_MULTIPLE => STATE_NONE');
Log.info('onMouseUp() selection area: ' + selectionArea);
state = STATE_NONE;
var figuresToAdd = [];
/*
* If SHIFT pressed add the new selection to the already selected figures,
* so here add to array already selected ones
*/
if (SHIFT_PRESSED) {
//if one figure already selected add it
if (selectedFigureId != -1) {
figuresToAdd.push(selectedFigureId);
}
//if group already selected add it
if (selectedGroupId != -1) {
var selectedGroup = STACK.groupGetById(selectedGroupId);
var groupFigures = STACK.figureGetByGroupId(selectedGroupId);
for (var i = 0; i < groupFigures.length; i++) {
figuresToAdd.push(groupFigures[i].id);
}
}
}
//add free figures (not belonging to any group) that overlaps with selection region
/*TODO:
* From Janis to Alex: Why we are selecting only figures that
* doesn`t belong to any group, I think we must also add grouped
* figures
* From Alex to Janis: We do not support groups in groups neither
* figures that belong to more than one group
*/
for (var i = 0; i < STACK.figures.length; i++) {
if (STACK.figures[i].groupId == -1) { //we only want ungrouped items
var points = STACK.figures[i].getPoints();
if (points.length == 0) { //if no point at least to add bounds TODO: lame 'catch all' condition
points.push(new Point(STACK.figures[i].getBounds()[0], STACK.figures[i].getBounds()[1])); //top left
points.push(new Point(STACK.figures[i].getBounds()[2], STACK.figures[i].getBounds()[3])); //bottom right
points.push(new Point(STACK.figures[i].getBounds()[0], STACK.figures[i].getBounds()[3])); //bottom left
points.push(new Point(STACK.figures[i].getBounds()[2], STACK.figures[i].getBounds()[1])); //top right
}
// flag shows if figure added to figuresToAdd array
var figureAddFlag = false;
/**Idea: We want to select both figures completely encompassed by
* selection (case 1) and those that are intersected by selection (case 2)*/
//1 - test if any figure point inside selection
for (var a = 0; a < points.length; a++) {
if (Util.isPointInside(points[a], selectionArea.getPoints())) {
figuresToAdd.push(STACK.figures[i].id);
// set flag not to add figure twice
figureAddFlag = true;
break;
}
}
//2 - test if any figure intersected by selection
if (!figureAddFlag) { //run this ONLY if is not already proposed for addition
figureAddFlag = Util.polylineIntersectsRectangle(points, selectionArea.getBounds(), true);
}
//select figures whose line intersects selectionArea
if (figureAddFlag) {
figuresToAdd.push(STACK.figures[i].id);
}
} //end if
} //end for
if (selectedGroupId != -1) {
var selectedGroup = STACK.groupGetById(selectedGroupId);
//destroy current group (if temporary)
if (!selectedGroup.permanent) {
STACK.groupDestroy(selectedGroupId);
}
}
//See what to do with collected figures
if (figuresToAdd.length >= 2) { //if we selected at least 2 figures then we can create a group
selectedGroupId = STACK.groupCreate(figuresToAdd);
state = STATE_GROUP_SELECTED;
setUpEditPanel(null); //because of shift in this case we also need to reset the edit panel
Log.info('onMouseUp() + STATE_SELECTING_MULTIPLE + min. 2 figures => STATE_GROUP_SELECTED');
}
else if (figuresToAdd.length == 1) { // if we only select one figure, then it is not a group, it's a simple selection
selectedFigureId = figuresToAdd[0];
selectedGroupId = -1;
state = STATE_FIGURE_SELECTED;
Log.info('onMouseUp() + STATE_SELECTING_MULTIPLE + 1 figure => STATE_FIGURE_SELECTED');
}
break;
case STATE_CONNECTOR_PICK_SECOND:
//store undo command
var cmdCreateCon = new ConnectorCreateCommand(selectedConnectorId);
History.addUndo(cmdCreateCon);
//reset all {ConnectionPoint}s' color
CONNECTOR_MANAGER.connectionPointsResetColor();
//reset current connection cloud
currentCloud = [];
//select the current connector
state = STATE_CONNECTOR_SELECTED;
var con = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId);
setUpEditPanel(con);
redraw = true;
break;
case STATE_CONNECTOR_MOVE_POINT:
/**
*Description:
*Simply alter the connector until mouse will be released
**/
//reset all {ConnectionPoint}s' color
CONNECTOR_MANAGER.connectionPointsResetColor();
//reset current connection cloud
currentCloud = [];
state = STATE_CONNECTOR_SELECTED; //back to selected connector
selectedConnectionPointId = -1; //but deselect the connection point
redraw = true;
break;
case STATE_CONNECTOR_SELECTED:
if (currentMoveUndo) {
var turns = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId).turningPoints;
var newTurns = [turns.length];
for (var i = 0; i < turns.length; i++) {
newTurns[i] = turns[i].clone();
}
currentMoveUndo.currentValue = newTurns;
History.addUndo(currentMoveUndo);
state = STATE_NONE;
selectedConnectorId = -1;
HandleManager.clear(); //clear current selection
}
break;
}
currentMoveUndo = null;
mousePressed = false;
draw();
}
/**Remembers last move. Initially it's null but once set it's a [x,y] array*/
var lastMove = null;
/**It will accumulate the changes on either X or Y coordinates for snap effect.
*As we need to escape the "gravity/attraction" of the grid system we need to "accumulate" more changes
*and if those changes become greater than a certain threshold we will initiate a snap action
*Zack : "Because of the snap to grid function we need to move more than a certain amount of pixels
*so we will not be snapped back to the old location"
*Initially it's [0,0] but once more and more changes got added a snap effect will be triggered
*and some of it's elements will be reset to 0.
*So snapMonitor = [sumOfChagesOnX, sumOfChangesOnY]
**/
var snapMonitor = [0, 0];
/**Treats the mouse move event
*@param {Event} ev - the event generated when key is up
**/
function onMouseMove(ev) {
// //resize canvas.
// if(lastMousePosition != null){
// resize(ev);
// }
var redraw = false;
var coords = getCanvasXY(ev);
if (coords == null) {
Log.error("main.js onMouseMove() null coordinates");
return;
}
var x = coords[0];
var y = coords[1];
var canvas = getCanvas();
/*change cursor
*More here: http://www.javascriptkit.com/dhtmltutors/csscursors.shtml
*/
switch (state) {
case STATE_NONE:
/*Description:
* We are in None state when no action was done....yet. Here is what can happen:
* - if the mouse is pressed, through onMouseDown(), then it's the begining of a multiple selection
* - if mouse is not pressed then change the cursor type to:
* - "move" if over a figure or connector
* - "default" if over "over a connector "empty" space
*/
if (mousePressed) {
state = STATE_SELECTING_MULTIPLE;
selectionArea.points[0] = new Point(x, y);
selectionArea.points[1] = new Point(x, y);
selectionArea.points[2] = new Point(x, y);
selectionArea.points[3] = new Point(x, y); //the selectionArea has no size until we start dragging the mouse
Log.debug('onMouseMove() - STATE_NONE + mousePressed = STATE_SELECTING_MULTIPLE');
}
else {
if (STACK.figureIsOver(x, y)) { //over a figure
canvas.style.cursor = 'move';
Log.debug('onMouseMove() - STATE_NONE - mouse cursor = move (over figure)');
}
else if (CONNECTOR_MANAGER.connectorGetByXY(x, y) != -1) { //over a connector
canvas.style.cursor = 'move';
Log.debug('onMouseMove() - STATE_NONE - mouse cursor = move (over connector)');
}
else if (STACK.containerGetByXY(x, y) != -1) { //container has a lower priority than figure
canvas.style.cursor = 'move';
Log.debug("onMouseMove() - STATE_NONE - mouse cursor = move (over container)");
}
else { //default cursor
canvas.style.cursor = 'default';
Log.debug('onMouseMove() - STATE_NONE - mouse cursor = default');
}
}
break;
case STATE_SELECTING_MULTIPLE:
selectionArea.points[1].x = x; //top right
selectionArea.points[2].x = x; //bottom right
selectionArea.points[2].y = y;
selectionArea.points[3].y = y; //bottom left
redraw = true;
break;
case STATE_FIGURE_CREATE:
if (createFigureFunction) { //creating a new figure
canvas.style.cursor = 'crosshair';
}
break;
case STATE_FIGURE_SELECTED:
/*Description:
* We have a figure selected. Here is what can happen:
* - if the mouse is pressed
* - if over a Figure's Handler then execute Handler's action
* - else (it is over the Figure)
* if SHIFT _NOT_ pressed
* then move figure
* else (SHIFT pressed)
* enter STATE_SELECTING_MULTIPLE state
* - if mouse is not pressed then change the cursor type to :
* - "move" if over a figure or connector
* - "handle" if over current figure's handle
* - "default" if over "nothing"
*/
if (mousePressed) { // mouse is (at least was) pressed
if (lastMove != null) { //we are in dragging mode
/*We need to use handleGetSelected() as if we are using handleGet(x,y) then
*as we move the mouse....it can move faster/slower than the figure and we
*will lose the Handle selection.
**/
var handle = HandleManager.handleGetSelected();
if (handle != null) { //We are over a Handle of selected Figure
canvas.style.cursor = handle.getCursor();
handle.action(lastMove, x, y);
redraw = true;
}
else { /*no handle is selected*/
if (!SHIFT_PRESSED) {//just translate the figure
canvas.style.cursor = 'move';
var translateMatrix = generateMoveMatrix(STACK.figureGetById(selectedFigureId), x, y);
Log.info("onMouseMove() + STATE_FIGURE_SELECTED : translation matrix" + translateMatrix);
var cmdTranslateFigure = new FigureTranslateCommand(selectedFigureId, translateMatrix);
History.addUndo(cmdTranslateFigure);
cmdTranslateFigure.execute();
/*Algorithm described:
if figure belong to an existing container:
if we moved it outside of current container (even partially?!)
unglue it from container
if figure dropped inside a container
add it to the (new) container
*/
var figure = STACK.figureGetById(selectedFigureId);
var figBounds = figure.getBounds();
var containerId = CONTAINER_MANAGER.getContainerForFigure(selectedFigureId);
if (containerId !== -1) { //we are glued to a container
var container = STACK.containerGetById(containerId);
var contBounds = container.getBounds();
//Test if figure' bounds are inside container's bounds?
if (Util.areBoundsInBounds(figBounds, contBounds)) {
//do nothing we are still in same container
}
else {
//TODO: CONTAINER_MANAGER.removeFigure(containerId, selectedFigureId);
//throw "main->onMouseMove->FigureSelected: removed from a container";
CONTAINER_MANAGER.removeFigure(containerId, selectedFigureId);
}
}
else { //not in any container
var newContainerId = -1;
for (var c = 0; c < STACK.containers.length; c++) {
var tempCont = STACK.containers[c];
if (Util.areBoundsInBounds(figBounds, tempCont.getBounds())) {
newContainerId = STACK.containers[c].id;
break;
}
}
if (newContainerId !== -1) {
//TODO: add figure to container
//throw "main->onMouseMove->FigureSelected: add figure to container";
CONTAINER_MANAGER.addFigure(newContainerId, selectedFigureId);
}
}
redraw = true;
} else { //we are entering a figures selection sesssion
state = STATE_SELECTING_MULTIPLE;
selectionArea.points[0] = new Point(x, y);
selectionArea.points[1] = new Point(x, y);
selectionArea.points[2] = new Point(x, y);
selectionArea.points[3] = new Point(x, y); //the selectionArea has no size until we start dragging the mouse
redraw = true;
}
}
}
}
else { //no mouse press (only change cursor)
var handle = HandleManager.handleGet(x, y); //TODO: we should be able to replace it with .getSelectedHandle()
if (handle != null) { //We are over a Handle of selected Figure
canvas.style.cursor = handle.getCursor();
}
else {
/*move figure only if no handle is selected*/
var tmpFigId = STACK.figureGetByXY(x, y); //pick first figure from (x, y)
if (tmpFigId != -1) {
canvas.style.cursor = 'move';
}
else {
canvas.style.cursor = 'default';
}
}
}
break;
case STATE_TEXT_EDITING:
/*Description:
* We have a text editor. Here is what can happen:
* - if the mouse is pressed
* - this should never happen
* - if mouse is not pressed then change the cursor type to :
* - "move" if over a figure or connector
* - "handle" if over current figure's handle
* - "default" if over "nothing"
*/
if (!mousePressed) {
var handle = HandleManager.handleGet(x, y); //TODO: we should be able to replace it with .getSelectedHandle()
if (handle != null) { //We are over a Handle of selected Figure
canvas.style.cursor = handle.getCursor();
Log.info('onMouseMove() - STATE_TEXT_EDITING + over a Handler = change cursor to: ' + canvas.style.cursor);
}
else {
/*move figure only if no handle is selected*/
var tmpFigId = STACK.figureGetByXY(x, y); //pick first figure from (x, y)
if (tmpFigId != -1) {
canvas.style.cursor = 'move';
Log.info("onMouseMove() + STATE_TEXT_EDITING + over a figure = change cursor");
}
else {
canvas.style.cursor = 'default';
Log.info("onMouseMove() + STATE_TEXT_EDITING + over nothin = change cursor to default");
}
}
} else {
throw "main:onMouseMove() - this should never happen";
}
break;
case STATE_CONTAINER_SELECTED:
//BRUTE COPY FROM FIGURE
if (mousePressed) { // mouse is (at least was) pressed
if (lastMove != null) { //we are in dragging mode
/*We need to use handleGetSelected() as if we are using handleGet(x,y) then
*as we move the mouse....it can move faster/slower than the figure and we
*will lose the Handle selection.
**/
var handle = HandleManager.handleGetSelected();
if (handle != null) { //We are over a Handle of selected Container
canvas.style.cursor = handle.getCursor();
handle.action(lastMove, x, y);
redraw = true;
Log.info('onMouseMove() - STATE_CONTAINER_SELECTED + drag - mouse cursor = ' + canvas.style.cursor);
}
else { /*no handle is selected*/
// if (!SHIFT_PRESSED){//just translate the figure
canvas.style.cursor = 'move';
var translateMatrix = generateMoveMatrix(STACK.containerGetById(selectedContainerId), x, y);
Log.info("onMouseMove() + STATE_CONTAINER_SELECTED : translation matrix" + translateMatrix);
var cmdTranslateContainer = new ContainerTranslateCommand(selectedContainerId, translateMatrix);
History.addUndo(cmdTranslateContainer);
cmdTranslateContainer.execute();
redraw = true;
}
}
}
else { //no mouse press (only change cursor)
var handle = HandleManager.handleGet(x, y); //TODO: we should be able to replace it with .getSelectedHandle()
if (handle != null) { //We are over a Handle of selected Figure
canvas.style.cursor = handle.getCursor();
Log.info('onMouseMove() - STATE_CONTAINER_SELECTED + over a Handler = change cursor to: ' + canvas.style.cursor);
}
else {
/*move figure only if no handle is selected*/
if (STACK.containerGetByXY(x, y) !== -1) {//pick first container from (x, y)
canvas.style.cursor = 'move';
Log.info("onMouseMove() + STATE_CONTAINER_SELECTED + over a container's edge = change cursor");
}
else {
canvas.style.cursor = 'default';
}
}
}
//END BRUTE COPY FROM FIGURE
break;
case STATE_GROUP_SELECTED:
//Log.info('onMouseMove() - STATE_GROUP_SELECTED ...');
/*Description:
*TODO: implement
* We have a group selected. Here is what can happen:
* - if the mouse is pressed
* - if over a Group's Handler then execute Handler's action
* - else (it is over one of Group's Figures):
* if SHIFT _NOT_ pressed:
* then move whole group
* else (SHIFT pressed)
* enter STATE_SELECTING_MULTIPLE state
* - if mouse is not pressed then change the cursor type to :
* - drag group?
* - cursor ?
* - "move" if over a figure or connector or group
* - "handle" if over current group's handle
* - "default" if over "nothing"
*/
if (mousePressed) {
if (lastMove != null) {
//Log.debug('onMouseMove() - STATE_GROUP_SELECTED + mouse pressed');
/*We need to use handleGetSelected() as if we are using handleGet(x,y) then
*as we move the mouse....it can move faster/slower than the figure and we
*will lose the Handle selection.
**/
var handle = HandleManager.handleGetSelected();
if (handle != null) { //over a handle
Log.info('onMouseMove() - STATE_GROUP_SELECTED + mouse pressed + over a Handle');
//HandleManager.handleSelectXY(x, y);
canvas.style.cursor = handle.getCursor();
handle.action(lastMove, x, y);
redraw = true;
}
else { //not over any handle -so it must be translating
if (!SHIFT_PRESSED) {
Log.info('onMouseMove() - STATE_GROUP_SELECTED + mouse pressed + NOT over a Handle');
canvas.style.cursor = 'move';
var mTranslate = generateMoveMatrix(STACK.groupGetById(selectedGroupId), x, y);
var cmdTranslateGroup = new GroupTranslateCommand(selectedGroupId, mTranslate);
cmdTranslateGroup.execute();
History.addUndo(cmdTranslateGroup);
redraw = true;
} else {
state = STATE_SELECTING_MULTIPLE;
selectionArea.points[0] = new Point(x, y);
selectionArea.points[1] = new Point(x, y);
selectionArea.points[2] = new Point(x, y);
selectionArea.points[3] = new Point(x, y); //the selectionArea has no size until we start dragging the mouse
redraw = true;
Log.info('onMouseMove() - STATE_GROUP_SELECTED + mousePressed + SHIFT => STATE_SELECTING_MULTIPLE');
}
}
}
}
else { //mouse not pressed (only change cursor)
Log.debug('onMouseMove() - STATE_GROUP_SELECTED + mouse NOT pressed');
if (HandleManager.handleGet(x, y) != null) {
canvas.style.cursor = HandleManager.handleGet(x, y).getCursor();
}
else if (CONNECTOR_MANAGER.connectorGetByXY(x, y) != -1) {
//nothing for now
}
else if (STACK.figureIsOver(x, y)) {
canvas.style.cursor = 'move';
}
else {
canvas.style.cursor = 'default';
}
}
break;
case STATE_CONNECTOR_PICK_FIRST:
if (mousePressed) {
connectorPickFirst(x, y, ev);
//change FCP (figure connection points) color
var fCpId = CONNECTOR_MANAGER.connectionPointGetByXY(x, y, ConnectionPoint.TYPE_FIGURE); //find figure's CP
if (fCpId != -1) { //we are over a figure's CP
var fCp = CONNECTOR_MANAGER.connectionPointGetById(fCpId);
fCp.color = ConnectionPoint.OVER_COLOR;
selectedConnectionPointId = fCpId;
}
else { //change back old connection point to normal color
if (selectedConnectionPointId != -1) {
var oldCp = CONNECTOR_MANAGER.connectionPointGetById(selectedConnectionPointId);
oldCp.color = ConnectionPoint.NORMAL_COLOR;
// canvas.style.cursor = 'normal';
selectedConnectionPointId = -1;
}
}
canvas.style.cursor = 'crosshair';
redraw = true;
} else {
state = STATE_NONE;
}
break;
case STATE_CONNECTOR_PICK_SECOND:
//moved to allow undo to access it
connectorPickSecond(x, y, ev);
redraw = true;
break;
case STATE_CONNECTOR_SELECTED:
/*Description:
*In case you move the mouse and you have the connector selected:
* - if adjusting the endpoints
* - alter the shape of connector in real time (gluing and unglued it, etc)
* (EXTRA option: do as little changes as possible to existing shape
* - if adjusting the handlers
* - alter the shape of connector in real time
**/
//alert('Move but we have a connector');
//change cursor to move if over a connector's CP
//var connector = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId);
var cps = CONNECTOR_MANAGER.connectionPointGetAllByParent(selectedConnectorId);
var start = cps[0];
var end = cps[1];
if (start.point.near(x, y, 3) || end.point.near(x, y, 3)) {
canvas.style.cursor = 'move';
}
else if (HandleManager.handleGet(x, y) != null) { //over a handle?. Handles should appear only for selected figures
canvas.style.cursor = HandleManager.handleGet(x, y).getCursor();
}
else {
canvas.style.cursor = 'default';
}
/*if we have a handle action*/
if (mousePressed == true && lastMove != null && HandleManager.handleGetSelected() != null) {
Log.info("onMouseMove() + STATE_CONNECTOR_SELECTED - trigger a handler action");
var handle = HandleManager.handleGetSelected();
// alert('Handle action');
/*We need completely new copies of the turningPoints in order to restore them,
*this is simpler than keeping track of the handle used, the direction in which the handle edits
*and the turningPoints it edits*/
//store old turning points
var turns = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId).turningPoints;
var oldTurns = [turns.length];
for (var i = 0; i < turns.length; i++) {
oldTurns[i] = turns[i].clone();
}
//DO the handle action
handle.action(lastMove, x, y);
//store new turning points
turns = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId).turningPoints;
var newTurns = [turns.length];
for (var i = 0; i < turns.length; i++) {
newTurns[i] = turns[i].clone();
}
//see if old turning points are the same as the new turning points
var difference = false;
for (var k = 0; k < newTurns.length; k++) {
if (!newTurns[k].equals(oldTurns[k])) {
difference = true;
}
}
redraw = true;
} else if (mousePressed == true && lastMove != null) {
canvas.style.cursor = 'move';
var con = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId);
var deltaX = x - lastMove[0];
var deltaY = y - lastMove[1];
start.point.x = start.point.x + deltaX;
end.point.x = end.point.x + deltaX;
start.point.y = start.point.y + deltaY;
end.point.y = end.point.y + deltaY;
con.turningPoints[0] = start.point;
con.turningPoints[1] = end.point;
redraw = true;
}
break;
case STATE_CONNECTOR_MOVE_POINT:
/**
*Description:
*Adjust on real time - WYSIWYG
*-compute the solution
*-update connector shape
*-update glues
*TODO: add description*/
Log.info("Easy easy easy....it's fragile");
if (mousePressed) { //only if we are dragging
/*update connector - but not unglue/glue it (Unglue and glue is handle in onMouseUp)
*as we want the glue-unglue to produce only when mouse is released*/
connectorMovePoint(selectedConnectionPointId, x, y, ev);
redraw = true;
}
break;
}
lastMove = [x, y];
if (redraw) {
draw();
}
return false;
}
/**Treats the mouse double click event
*@param {Event} ev - the event generated when key is clicked twice
*@author Artyom, Alex
**/
function onDblClick(ev) {
var coords = getCanvasXY(ev);
var x = coords[0];
var y = coords[1];
lastClick = [x, y];
//user cancel
return false;
// store clicked figure or connector
var shape = null;
// store id value (from Stack) of clicked text primitive
var textPrimitiveId = -1;
//find Connector at (x,y)
var cId = CONNECTOR_MANAGER.connectorGetByXY(x, y);
var connector = null;
// check if we clicked a connector
if (cId != -1) {
connector = CONNECTOR_MANAGER.connectorGetById(cId);
shape = connector;
textPrimitiveId = -1; // (0 by default)
} else {
cId = CONNECTOR_MANAGER.connectorGetByTextXY(x, y);
// check if we clicked a text of connector
if (cId != -1) {
connector = CONNECTOR_MANAGER.connectorGetById(cId);
shape = connector;
textPrimitiveId = -1; // (0 by default)
} else {
//find Figure at (x,y)
var fId = STACK.figureGetByXY(x, y);
// check if we clicked a figure
if (fId != -1) {
var figure = STACK.figureGetById(fId);
var tId = STACK.textGetByFigureXY(fId, x, y);
// if we clicked text primitive inside of figure
if (tId !== -1) {
shape = figure;
textPrimitiveId = tId;
}
} else {
//find Container at (x,y)
var contId = STACK.containerGetByXY(x, y);
// check if we clicked a container
if (contId !== -1) {
var container = STACK.containerGetById(contId);
var tId = STACK.textGetByContainerXY(contId, x, y);
// if we clicked text primitive inside of figure
if (tId !== -1) {
shape = container;
textPrimitiveId = tId;
}
}
}
}
}
// check if we clicked a text primitive inside of shape
if (textPrimitiveId != -1) {
// if group selected
if (state == STATE_GROUP_SELECTED) {
var selectedGroup = STACK.groupGetById(selectedGroupId);
// if group is temporary then destroy it
if (!selectedGroup.permanent) {
STACK.groupDestroy(selectedGroupId);
}
//deselect current group
selectedGroupId = -1;
}
// deselect current figure
selectedFigureId = -1;
// deselect current container
selectedContainerId = -1;
// deselect current connector
selectedConnectorId = -1;
// set current state
state = STATE_TEXT_EDITING;
// set up text editor
setUpTextEditorPopup(shape, textPrimitiveId);
redraw = true;
}
draw();
return false;
}
/**Pick the first connector we can get at (x,y) position
*@param {Number} x - the x position
*@param {Number} y - the y position
*@param {Event} ev - the event triggered
*@author Alex, Artyom
**/
function connectorPickFirst(x, y, ev) {
Log.group("connectorPickFirst");
//create connector
var conId = CONNECTOR_MANAGER.connectorCreate(new Point(x, y), new Point(x + 10, y + 10) /*fake cp*/, connectorType);
selectedConnectorId = conId;
var con = CONNECTOR_MANAGER.connectorGetById(conId);
//TRY TO GLUE IT
//1.get CP of the connector
var conCps = CONNECTOR_MANAGER.connectionPointGetAllByParent(conId);
//get Figure's id if over it
var fOverId = STACK.figureGetByXY(x, y);
//get the ConnectionPoint's id if we are over it (and belonging to a figure)
var fCpOverId = CONNECTOR_MANAGER.connectionPointGetByXY(x, y, ConnectionPoint.TYPE_FIGURE); //find figure's CP
//see if we can snap to a figure
if (fCpOverId != -1) { //Are we over a ConnectionPoint from a Figure?
var fCp = CONNECTOR_MANAGER.connectionPointGetById(fCpOverId);
//update connector' cp
conCps[0].point.x = fCp.point.x;
conCps[0].point.y = fCp.point.y;
//update connector's turning point
con.turningPoints[0].x = fCp.point.x;
con.turningPoints[0].y = fCp.point.y;
var g = CONNECTOR_MANAGER.glueCreate(fCp.id, conCps[0].id, false);
Log.info("First glue created : " + g);
//alert('First glue ' + g);
} else if (fOverId !== -1) { //Are we, at least, over the {Figure}?
/*As we are over a {Figure} but not over a {ConnectionPoint} we will switch
* to automatic connection*/
var point = new Point(x, y);
var candidate = CONNECTOR_MANAGER.getClosestPointsOfConnection(
true, // automatic start
true, // automatic end
fOverId, //start figure's id
point, //start point
fOverId, //end figure's id
point //end point
);
var connectionPoint = candidate[0];
//update connector' cp
conCps[0].point.x = conCps[1].point.x = connectionPoint.x;
conCps[0].point.y = conCps[1].point.y = connectionPoint.y;
//update connector's turning point
con.turningPoints[0].x = con.turningPoints[1].x = connectionPoint.x;
con.turningPoints[0].y = con.turningPoints[1].y = connectionPoint.y;
var g = CONNECTOR_MANAGER.glueCreate(candidate[2], conCps[0].id, true);
Log.info("First glue created : " + g);
}
state = STATE_CONNECTOR_PICK_SECOND;
Log.groupEnd();
}
/**Pick the second {ConnectorPoint} we can get at (x,y) position
*@param {Number} x - the x position
*@param {Number} y - the y position
*@param {Event} ev - the event triggered
**/
function connectorPickSecond(x, y, ev) {
Log.group("main: connectorPickSecond");
//current connector
var con = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId); //it should be the last one
var cps = CONNECTOR_MANAGER.connectionPointGetAllByParent(con.id);
//get the ConnectionPoint's id if we are over it (and belonging to a figure)
var fCpOverId = CONNECTOR_MANAGER.connectionPointGetByXY(x, y, ConnectionPoint.TYPE_FIGURE); //find figure's CP
//get Figure's id if over it
var fOverId = STACK.figureGetByXY(x, y);
//TODO: remove
//play with algorithm
{
//We will try to find the startFigure, endFigure, startPoint, endPoint, etc
//start point
var rStartPoint = con.turningPoints[0].clone();
var rStartGlues = CONNECTOR_MANAGER.glueGetBySecondConnectionPointId(cps[0].id);
var rStartFigure = STACK.figureGetAsFirstFigureForConnector(con.id);
if (rStartFigure) {
Log.info(":) WE HAVE A START FIGURE id = " + rStartFigure.id);
}
else {
Log.info(":( WE DO NOT HAVE A START FIGURE");
}
//end point
var rEndPoint = new Point(x, y);
var rEndFigure = null;
if (fCpOverId != -1) { //Are we over a ConnectionPoint from a Figure?
var r_figureConnectionPoint = CONNECTOR_MANAGER.connectionPointGetById(fCpOverId);
Log.info("End Figure's ConnectionPoint present id = " + fCpOverId);
//As we found the connection point by a vicinity (so not exactly x,y match) we will adjust the end point too
rEndPoint = r_figureConnectionPoint.point.clone();
rEndFigure = STACK.figureGetById(r_figureConnectionPoint.parentId);
Log.info(":) WE HAVE AN END FIGURE id = " + rEndFigure.id);
} else if (fOverId != -1) { //Are we, at least, over a Figure?
Log.info("End Figure connected as automatic");
rEndPoint = new Point(x, y);
rEndFigure = STACK.figureGetById(fOverId);
Log.info(":) WE HAVE AN END FIGURE id = " + rEndFigure.id);
} else {
Log.info(":( WE DO NOT HAVE AN END FIGURE ");
}
var rStartBounds = rStartFigure ? rStartFigure.getBounds() : null;
var rEndBounds = rEndFigure ? rEndFigure.getBounds() : null;
// if start point has automatic glue => connection has automatic start
var automaticStart = rStartGlues.length > 0 && rStartGlues[0].automatic;
// if end point is over a {Figure}'s {ConnectionPoint} => connection is not automatic
// else if end point is over a {Figure} -> connection has automatic end
// else -> connection has no automatic end
var automaticEnd = fCpOverId != -1 ? false : fOverId != -1;
var xSpan = rStartPoint.x - rEndPoint.x;
var ySpan = rStartPoint.y - rEndPoint.y;
if (Math.abs(xSpan) > Math.abs(ySpan)) {
rEndPoint.y = rStartPoint.y;
} else { //竖线
rEndPoint.x = rStartPoint.x;
}
var candidate = CONNECTOR_MANAGER.getClosestPointsOfConnection(
automaticStart, //start automatic
automaticEnd, //end automatic
rStartFigure ? rStartFigure.id : -1, //start figure's id
rStartPoint, //start figure's point
rEndFigure ? rEndFigure.id : -1, //end figure's id
rEndPoint //end figure's point
);
DIAGRAMO.debugSolutions = CONNECTOR_MANAGER.connector2Points(
con.type,
candidate[0], /*Start point*/
candidate[1], /*End point*/
rStartBounds,
rEndBounds
);
}
//end remove block
//COLOR MANAGEMENT FOR {ConnectionPoint}
//Find any {ConnectionPoint} from a figure at (x,y). Change FCP (figure connection points) color
if (fCpOverId != -1 || fOverId != -1) { //Are we over a ConnectionPoint from a Figure or over a Figure?
cps[1].color = ConnectionPoint.OVER_COLOR;
} else {
cps[1].color = ConnectionPoint.NORMAL_COLOR;
}
var firstConPoint = CONNECTOR_MANAGER.connectionPointGetFirstForConnector(selectedConnectorId);
var secConPoint = CONNECTOR_MANAGER.connectionPointGetSecondForConnector(selectedConnectorId);
//adjust connector
Log.info("connectorPickSecond() -> Solution: " + DIAGRAMO.debugSolutions[0][2]);
con.turningPoints = Point.cloneArray(DIAGRAMO.debugSolutions[0][2]);
//CONNECTOR_MANAGER.connectionPointGetFirstForConnector(selectedConnectorId).point = con.turningPoints[0].clone();
firstConPoint.point = con.turningPoints[0].clone();
secConPoint.point = con.turningPoints[con.turningPoints.length - 1].clone();
// MANAGE TEXT
// update position of connector's text
con.updateMiddleText();
// before defining of {ConnectionPoint}'s position we reset currentCloud
currentCloud = [];
Log.groupEnd();
}
/**
*Alter the {Connector} in real time
*@param {Number} connectionPointId - the id of the current dragged {ConnectionPoint}
*@param {Number} x - the x position
*@param {Number} y - the y position
*@param {Event} ev - the event triggered
**/
function connectorMovePoint(connectionPointId, x, y, ev) {
//current connector
var con = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId);
var cps = CONNECTOR_MANAGER.connectionPointGetAllByParent(con.id);
// MANAGE TEXT
// update position of connector's text
con.updateMiddleText();
//MANAGE COLOR
//canvas.style.cursor = 'move';
if (cps[0].id == selectedConnectionPointId) {
cps[0].color = ConnectionPoint.OVER_COLOR;
}
else {
cps[1].color = ConnectionPoint.NORMAL_COLOR;
}
/*Variables used in finding solution. As we only know the ConnectionPoint's id
* (connectionPointId) and the location of event (x,y) we need to find
* who is the start Figure, end Figure, starting Glue, ending Glue, etc*/
var rStartPoint = con.turningPoints[0].clone();
var rStartFigure = null; //starting figure (it can be null - as no Figure)
var rEndPoint = con.turningPoints[con.turningPoints.length - 1].clone();
var rEndFigure = null; //ending figure (it can be null - as no Figure)
var rStartGlues = CONNECTOR_MANAGER.glueGetBySecondConnectionPointId(cps[0].id);
var rEndGlues = CONNECTOR_MANAGER.glueGetBySecondConnectionPointId(cps[1].id);
// before solution we reset currentCloud
currentCloud = [];
if (cps[0].id == connectionPointId) { //FIRST POINT
rStartPoint = new Point(x, y);
//end figure
rEndFigure = STACK.figureGetAsSecondFigureForConnector(con.id);
var rStartBounds = rStartFigure ? rStartFigure.getBounds() : null;
var rEndBounds = rEndFigure ? rEndFigure.getBounds() : null;
/** define connection type **/
// if end point has automatic glue -> connection has automatic end
var automaticEnd = rEndGlues.length && rEndGlues[0].automatic;
// if start point is over figure's connection point -> connection has no automatic start
// else if start point is over figure -> connection has automatic start
// else -> connection has no automatic start
var automaticStart = false;
var xSpan = rStartPoint.x - rEndPoint.x;
var ySpan = rStartPoint.y - rEndPoint.y;
if (Math.abs(xSpan) > Math.abs(ySpan)) {
rStartPoint.y = rEndPoint.y;
} else { //竖线
rStartPoint.x = rEndPoint.x;
}
var candidate = CONNECTOR_MANAGER.getClosestPointsOfConnection(
automaticStart, //start automatic
automaticEnd, //end automatic
rStartFigure ? rStartFigure.id : -1, //start figure's id
rStartPoint, //start figure's point
rEndFigure ? rEndFigure.id : -1, //end figure's id
rEndPoint //end figure's point
);
//solutions
DIAGRAMO.debugSolutions = CONNECTOR_MANAGER.connector2Points(con.type, candidate[0], candidate[1], rStartBounds, rEndBounds);
//UPDATE CONNECTOR
var firstConPoint = CONNECTOR_MANAGER.connectionPointGetFirstForConnector(selectedConnectorId);
var secondConPoint = CONNECTOR_MANAGER.connectionPointGetSecondForConnector(selectedConnectorId);
//adjust connector
Log.info("connectorMovePoint() -> Solution: " + DIAGRAMO.debugSolutions[0][2]);
con.turningPoints = Point.cloneArray(DIAGRAMO.debugSolutions[0][2]);
firstConPoint.point = con.turningPoints[0].clone();
secondConPoint.point = con.turningPoints[con.turningPoints.length - 1].clone();
}
else if (cps[1].id == connectionPointId) { //SECOND POINT
rEndPoint = new Point(x, y);
//start figure
rStartFigure = STACK.figureGetAsFirstFigureForConnector(con.id);
var rStartBounds = rStartFigure ? rStartFigure.getBounds() : null;
var rEndBounds = rEndFigure ? rEndFigure.getBounds() : null;
/** define connection type **/
// if start point has automatic glue -> connection has automatic start
var automaticStart = rStartGlues.length && rStartGlues[0].automatic;
// if end point is over figure's connection point -> connection has no automatic end
// else if end point is over figure -> connection has automatic end
// else -> connection has no automatic end
var automaticEnd = false;
var xSpan = rStartPoint.x - rEndPoint.x;
var ySpan = rStartPoint.y - rEndPoint.y;
if (Math.abs(xSpan) > Math.abs(ySpan)) {
rEndPoint.y = rStartPoint.y;
} else { //竖线
rEndPoint.x = rStartPoint.x;
}
var candidate = CONNECTOR_MANAGER.getClosestPointsOfConnection(
automaticStart, //start automatic
automaticEnd, //end automatic
rStartFigure ? rStartFigure.id : -1, //start figure's id
rStartPoint, //start figure's point
rEndFigure ? rEndFigure.id : -1, //end figure's id
rEndPoint //end figure point
);
//solutions
DIAGRAMO.debugSolutions = CONNECTOR_MANAGER.connector2Points(con.type, candidate[0], candidate[1], rStartBounds, rEndBounds);
//UPDATE CONNECTOR
var firstConPoint = CONNECTOR_MANAGER.connectionPointGetFirstForConnector(selectedConnectorId);
var secondConPoint = CONNECTOR_MANAGER.connectionPointGetSecondForConnector(selectedConnectorId);
//adjust connector
con.turningPoints = Point.cloneArray(DIAGRAMO.debugSolutions[0][2]);
firstConPoint.point = con.turningPoints[0].clone();
secondConPoint.point = con.turningPoints[con.turningPoints.length - 1].clone();
} else {
throw "main:connectorMovePoint() - this should never happen";
}
Log.groupEnd();
}
/** Creates a moving matrix taking into consideration the snapTo option
* The strange stuff is that Dia (http://projects.gnome.org/dia/) is using a top/left align
* but OpenOffice's Draw is using something similar to Diagramo
* @return {Matrix} - translation matrix
* @param {Object} fig - could be a figure, or a Connector
* @param {Number} x - mouse position
* @param {Number} y - mouse position
* @author Zack Newsham
* @author Alex Gheorghiu
*/
function generateMoveMatrix(fig, x, y) {
// Log.group("generateMoveMatrix");
if (typeof x === 'undefined') {
throw "Exception in generateMoveMatrix, x is undefined";
}
if (typeof y === 'undefined') {
throw "Exception in generateMoveMatrix, is undefined";
}
Log.info("main.js --> generateMoveMatrix x:" + x + ' y:' + y + ' lastMove=[' + lastMove + ']');
var dx = x - lastMove[0];
var dy = y - lastMove[1];
// Log.info("generateMoveMatrix() - delta " + dx + ', ' + dy);
var moveMatrix = null;
if (snapTo) { //snap effect
moveMatrix = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]
];
snapMonitor[0] += dx;
snapMonitor[1] += dy;
var jump = GRIDWIDTH / 2; //the figure will jump half of grid cell width
//HORIZONTAL
if (dx != 0) { //dragged to right
/*Idea:
*As you move the shape to right it might snap to next snap line
*regarding figure's start bounds (startNextGridX)
*or snap to the snap line regarding figure's end bounds (endNextGridX)
*We just need to see to which snap line will actually snap (the one that is closer)
**/
var startGridX = (Math.floor((fig.getBounds()[0] + snapMonitor[0]) / jump) + 1) * jump;
var deltaStart = startGridX - fig.getBounds()[0];
var endGridX = (Math.floor((fig.getBounds()[2] + snapMonitor[0]) / jump) + 1) * jump;
var deltaEnd = endGridX - fig.getBounds()[2];
if (deltaStart < deltaEnd) {
if (fig.getBounds()[0] + snapMonitor[0] >= startGridX - SNAP_DISTANCE) {
moveMatrix[0][2] = deltaStart;
snapMonitor[0] -= deltaStart;
}
else if (fig.getBounds()[2] + snapMonitor[0] >= endGridX - SNAP_DISTANCE) {
moveMatrix[0][2] = deltaEnd;
snapMonitor[0] -= deltaEnd;
}
}
else {
if (fig.getBounds()[2] + snapMonitor[0] >= endGridX - SNAP_DISTANCE) {
moveMatrix[0][2] = deltaEnd;
snapMonitor[0] -= deltaEnd;
}
else if (fig.getBounds()[0] + snapMonitor[0] >= startGridX - SNAP_DISTANCE) {
moveMatrix[0][2] = deltaStart;
snapMonitor[0] -= deltaStart;
}
}
}
//VERTICAL
if (dy != 0) { //dragged to bottom
var upperGridY = (Math.floor((fig.getBounds()[1] + snapMonitor[1]) / jump) + 1) * jump;
var deltaUpper = upperGridY - fig.getBounds()[1];
var lowerGridY = (Math.floor((fig.getBounds()[3] + snapMonitor[1]) / jump) + 1) * jump;
var deltaLower = lowerGridY - fig.getBounds()[3];
if (deltaUpper < deltaLower) {
if (fig.getBounds()[1] + snapMonitor[1] >= upperGridY - SNAP_DISTANCE) {
moveMatrix[1][2] = deltaUpper;
snapMonitor[1] -= deltaUpper;
}
else if (fig.getBounds()[3] + snapMonitor[1] >= lowerGridY - SNAP_DISTANCE) {
moveMatrix[1][2] = deltaLower;
snapMonitor[1] -= deltaLower;
}
}
else {
if (fig.getBounds()[3] + snapMonitor[1] >= lowerGridY - SNAP_DISTANCE) {
moveMatrix[1][2] = deltaLower;
snapMonitor[1] -= deltaLower;
}
else if (fig.getBounds()[1] + snapMonitor[1] >= upperGridY - SNAP_DISTANCE) {
moveMatrix[1][2] = deltaUpper;
snapMonitor[1] -= deltaUpper;
}
}
}
} else { //normal move
moveMatrix = [
[1, 0, dx],
[0, 1, dy],
[0, 0, 1]
];
}
Log.groupEnd();
return moveMatrix;
}
/**Computes the bounds of the canvas
**@return {Array} of {Integer} - [xStart, yStart, xEnd, yEnd]
**/
function getCanvasBounds() {
var canvasMinX = $("#a").offset().left;
var canvasMaxX = canvasMinX + $("#a").width();
var canvasMinY = $("#a").offset().top;
var canvasMaxY = canvasMinY + $("#a").height();
return [canvasMinX, canvasMinY, canvasMaxX, canvasMaxY];
}
/**Computes the (x,y) coordinates of an event in page
*@param {Event} ev - the event
**/
function getBodyXY(ev) {
return [ev.pageX, ev.pageY]; //TODO: add scroll
}
/**
*Extracts the X and Y from an event (for canvas)
*@param {Event} ev - the event
*@return {Array} of {Integer} - or null if event not inside the canvas
**/
function getCanvasXY(ev) {
var position = null;
var canvasBounds = getCanvasBounds();
// Log.group("main.js->getCanvasXY()");
Log.debug("Canvas bounds: [" + canvasBounds + ']');
var tempPageX = null;
var tempPageY = null;
if (ev.touches) { //iPad
if (ev.touches.length > 0) {
tempPageX = ev.touches[0].pageX;
tempPageY = ev.touches[0].pageY;
}
}
else { //normal Desktop
tempPageX = ev.pageX; //Retrieves the x-coordinate of the mouse pointer relative to the top-left corner of the document.
tempPageY = ev.pageY; //Retrieves the y-coordinate of the mouse pointer relative to the top-left corner of the document.
Log.debug("ev.pageX:" + ev.pageX + " ev.pageY:" + ev.pageY);
}
if (canvasBounds[0] <= tempPageX && tempPageX <= canvasBounds[2]
&& canvasBounds[1] <= tempPageY && tempPageY <= canvasBounds[3]) {
// Log.info('Inside canvas');
position = [tempPageX - $("#a").offset().left, tempPageY - $("#a").offset().top];
//alert("getXT : " + position);
}
// Log.groupEnd();
return position;
}
/**Buffered image for background of canvas
* It is set to null in CanvasProps::sync() method*/
var backgroundImage = null;
/**Adds a background to a canvas
* @param {HTMLCanvasElement} canvasElement the <canvas> DOM element
* */
function addBackground(canvasElement) {
Log.info("addBackground: called");
var ctx = canvasElement.getContext('2d');
// set background image if backgroundImage is null
if (!backgroundImage) {
// fill canvas with fill color
ctx.rect(0, 0, canvasElement.width, canvasElement.height);
ctx.fillStyle = canvasProps.getFillColor();
ctx.fill();
// draw grid if it's visible
if (gridVisible) {
var columns = Math.floor(canvasElement.width / GRIDWIDTH) + 1;
//console.info("Columns: " + columns );
var rows = Math.floor(canvasElement.height / GRIDWIDTH) + 1;
//console.info("Rows: " + rows );
for (var i = 0; i < rows; i++) {
for (var j = 0; j < columns; j++) {
ctx.beginPath();
ctx.strokeStyle = '#C0C0C0';
//big cross
ctx.moveTo(j * GRIDWIDTH - 1, i * GRIDWIDTH);
ctx.lineTo(j * GRIDWIDTH + 1, i * GRIDWIDTH);
ctx.moveTo(j * GRIDWIDTH, i * GRIDWIDTH - 1);
ctx.lineTo(j * GRIDWIDTH, i * GRIDWIDTH + 1);
//small dot
//ctx.moveTo(j * GRIDWIDTH + GRIDWIDTH/2 - 1, i * GRIDWIDTH + GRIDWIDTH/2);
//ctx.lineTo(j * GRIDWIDTH + GRIDWIDTH/2 + 1, i * GRIDWIDTH + GRIDWIDTH/2);
ctx.stroke();
}
}
}
// set new buffered background image
backgroundImage = new Image();
backgroundImage.src = canvasElement.toDataURL();
} else {
// backgroundImage.onload = function(e){
// ctx.drawImage(this, 0, 0);
// } //end onload
// draw buffered background image on canvas
ctx.drawImage(backgroundImage, 0, 0);
}
} //end function
/**Cleans up the canvas. It also add a white background to avoid "transparent"
*background issue in PNG
*@param {HTMLCanvasElement} canvas - the canvas to reset
*@author Alex
**/
function reset(canvas) {
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
/**Draws all the stuff on the canvas*/
function draw() {
var ctx = getContext();
// Log.group("A draw started");
//alert('Paint 1')
reset(getCanvas());
//if grid visible paint it
// if(gridVisible){ //paint grid
addBackground(getCanvas());
// }
//alert('Paint 2')
STACK.paint(ctx);
minimap.updateMinimap();
// Log.groupEnd();
//alert('Paint 3')
}
/**
*Returns the canvas data but without the selections and grid.
*@return {DOMString} - the result of a toDataURL() call on the temporary canvas
*@author Alex
*@author Artyom
**/
function renderedCanvas() {
var canvas = getCanvas();
//render the canvas without the selection and stuff
var tempCanvas = document.getElementById('tempCanvas');
if (tempCanvas === null) {
tempCanvas = document.createElement('canvas');
tempCanvas.setAttribute('id', 'tempCanvas');
tempCanvas.style.display = 'none';
//it seems that there is no need to actually add it to the dom tree to be able to render (tested: IE9, FF9, Chrome 19)
//canvas.parentNode.appendChild(tempCanvas);
}
//adjust temp canvas size to main canvas (as it migh have been changed)
tempCanvas.setAttribute('width', canvas.width);
tempCanvas.setAttribute('height', canvas.height);
reset(tempCanvas);
addBackground(tempCanvas);
STACK.paint(tempCanvas.getContext('2d'), true);
//end render
return tempCanvas.toDataURL();
}
/*Returns a text containing all the URL in a diagram */
function linkMap() {
var csvBounds = '';
var first = true;
for (f in STACK.figures) {
var figure = STACK.figures[f];
if (figure.url != '') {
var bounds = figure.getBounds();
if (first) {
first = false;
}
else {
csvBounds += "\n";
}
csvBounds += bounds[0] + ',' + bounds[1] + ',' + bounds[2] + ',' + bounds[3] + ',' + figure.url;
}
}
Log.info("editor.php->linkMap()->csv bounds: " + csvBounds);
return csvBounds;
}
/** Save current diagram
* Save can be triggered in 3 cases:
* 1 - from menu
* 2 - from quick toolbar
* 3 - from shortcut Ctrl-S (onKeyDown)
**/
function Save(showInfo) {
if (state == STATE_TEXT_EDITING) {
currentTextEditor.destroy();
currentTextEditor = null;
state = STATE_NONE;
}
var dataURL = null;
try {
dataURL = renderedCanvas();
}
catch (e) {
if (e.name === 'SecurityError' && e.code === 18) {
/*This is usually happening as we load an image from another host than the one Diagramo is hosted*/
alert("A figure contains an image loaded from another host. \
\n\nHint: \
\nPlease make sure that the browser's URL (current location) is the same as the one saved in the DB.");
}
}
var diagram = { c: canvasProps, s: STACK, m: CONNECTOR_MANAGER, p: CONTAINER_MANAGER, v: DIAGRAMO.fileVersion };
//var serializedDiagram = JSON.stringify(diagram, Util.operaReplacer);
var serializedDiagram = JSON.stringify(diagram);
//var svgDiagram = toSVG();
//save the URLs of figures as a CSV
var lMap = linkMap();
var handler = new HttpHandler("BP.WF.HttpHandler.WF_Admin_CCFormDesigner");
handler.AddPara("diagram", serializedDiagram);
handler.AddPara("png", dataURL);
handler.AddPara("linkMap", lMap);
handler.AddPara("svg", "");
handler.AddPara("FK_MapData", CCForm_FK_MapData);
var data = handler.DoMethodReturnString("SaveForm");
// $.post( Handler, {
// action: 'SaveForm',
// diagram: serializedDiagram,
// png: dataURL,
// linkMap: lMap,
// svg: "",
// FK_MapData: CCForm_FK_MapData
// }, function (data) {
if (data.indexOf('err@') != -1) {
alert(data);
return;
}
Designer_ShowMsg(data);
// });
}
/** Print current diagram
* Print can be triggered in 3 cases only after diagram was saved:
* 1 - from menu
* 2 - from quick toolbar
* 3 - from Ctrl + P shortcut
*
* Copy link to saved diagram's png file to src of image,
* add it to iframe and call print of last.
*
* @author Artyom Pokatilov <artyom.pokatilov@gmail.com>
**/
function print_diagram() {
var printFrameId = "printFrame";
var iframe = document.getElementById(printFrameId);
// if iframe isn't created
if (iframe == null) {
iframe = document.createElement("IFRAME");
iframe.id = printFrameId;
document.body.appendChild(iframe);
}
// get DOM of iframe
var frameDoc = iframe.contentDocument;
var diagramImages = frameDoc.getElementsByTagName('img');
var diagramImage;
if (diagramImages.length > 0) { // if image is already added
diagramImage = diagramImages[0];
// set source of image to png of saved diagram
diagramImage.setAttribute('src', "data/diagrams/" + currentDiagramId + ".png");
} else { // if image isn't created yet
diagramImage = frameDoc.createElement('img');
// set source of image to png of saved diagram
diagramImage.setAttribute('src', "data/diagrams/" + currentDiagramId + ".png");
if (frameDoc.body !== null) {
frameDoc.body.appendChild(diagramImage);
} else {
// IE case for more details
// @see http://stackoverflow.com/questions/8298320/correct-access-of-dynamic-iframe-in-ie
// create body of iframe
frameDoc.src = "javascript:'<body></body>'";
// append image through html of <img>
frameDoc.write(diagramImage.outerHTML);
frameDoc.close();
}
}
// adjust iframe size to main canvas (as it might have been changed)
iframe.setAttribute('width', canvasProps.getWidth());
iframe.setAttribute('height', canvasProps.getHeight());
// print iframe
iframe.contentWindow.print();
}
/**Exports current canvas as SVG*/
function exportCanvas() {
//export canvas as SVG
var v = '<svg width="300" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1">\
<rect x="0" y="0" height="200" width="300" style="stroke:#000000; fill: #FFFFFF"/>\
<path d="M100,100 C200,200 100,50 300,100" style="stroke:#FFAAFF;fill:none;stroke-width:3;" />\
<rect x="50" y="50" height="50" width="50"\
style="stroke:#ff0000; fill: #ccccdf" />\
</svg>';
//get svg
var canvas = getCanvas();
var v2 = '<svg width="' + canvas.width + '" height="' + canvas.height + '" xmlns="http://www.w3.org/2000/svg" version="1.1">';
v2 += STACK.toSVG();
v2 += CONNECTOR_MANAGER.toSVG();
v2 += '</svg>';
alert(v2);
//save SVG into session
//see: http://api.jquery.com/jQuery.post/
$.post("../common/controller.php", { action: 'saveSvg', svg: escape(v2) },
function (data) {
if (data == 'svg_ok') {
//alert('SVG was save into session');
}
else if (data == 'svg_failed') {
Log.info('SVG was NOT save into session');
}
}
);
//open a new window that will display the SVG
window.open('./svg.php', 'SVG', 'left=20,top=20,width=500,height=500,toolbar=1,resizable=0');
}
/**Loads a saved diagram
*@param {String} tempDiagramName - the name of temporary diagram
**/
function LoadTempDiagram(frmID) {
//将v1版本表单元素转换为v2 杨玉慧 silverlight 自由表单转化为H5表单
Conver_CCForm_V1ToV2();
/*
$.post(Handler, { action: 'FormDesigner_Loadform', FK_MapData: frmID },
function (data) {
if (data.indexOf('err@') != -1) {
alert(data);
return;
}
try {
// 装载表单入口.
if (data == "" || data == "" || data == null) {
return;
}
action(data);
var obj = cceval('(' + data + ')');
//alert(obj);
//console.log(obj);
if (!('v' in obj) || obj.v != DIAGRAMO.fileVersion) {
Importer.importDiagram(obj); //import 1st version of Diagramo files
}
STACK = Stack.load(obj['s']);
canvasProps = CanvasProps.load(obj['c']);
canvasProps.sync();
setUpEditPanel(canvasProps);
CONNECTOR_MANAGER = ConnectorManager.load(obj['m']);
CONTAINER_MANAGER = ContainerFigureManager.load(obj['p']);
draw();
//alert("loaded");
} catch (error) {
alert("main.js:load() 装载表单异常 Exception: " + error);
}
}
);
*/
}
/**Saves a diagram. Actually send the serialized version of diagram
*for saving
**/
function saveAs() {
var dataURL = renderedCanvas();
// var $diagram = {c:canvas.save(), s:STACK, m:CONNECTOR_MANAGER};
var $diagram = { c: canvasProps, s: STACK, m: CONNECTOR_MANAGER, p: CONTAINER_MANAGER, v: DIAGRAMO.fileVersion };
var $serializedDiagram = JSON.stringify($diagram);
// $serializedDiagram = JSON.stringify($diagram, Util.operaReplacer);
var svgDiagram = toSVG();
//save the URLs of figures as a CSV
var lMap = linkMap();
//alert($serializedDiagram);
//see: http://api.jquery.com/jQuery.post/
$.post("./common/controller.php", { action: 'saveAs', diagram: $serializedDiagram, png: dataURL, linkMap: lMap, svg: svgDiagram },
function (data) {
if (data == 'noaccount') {
Log.info('You must have an account to use that feature');
//window.location = '../register.php';
}
else if (data == 'step1Ok') {
Log.info('Save as...');
window.location = './saveDiagram.php';
}
}
);
}
/**Add listeners to elements on the page*/
// TODO: set dblclick handler for mobile (touches)
function addListeners() {
var canvas = getCanvas();
//add event handlers for Document
document.addEventListener("keypress", onKeyPress, false);
document.addEventListener("keydown", onKeyDown, false);
document.addEventListener("keyup", onKeyUp, false);
document.addEventListener("selectstart", stopselection, false);
//add event handlers for Canvas
canvas.addEventListener("mousemove", onMouseMove, false);
canvas.addEventListener("mousedown", onMouseDown, false);
canvas.addEventListener("mouseup", onMouseUp, false);
canvas.addEventListener("dblclick", onDblClick, false);
if (false) {
//add listeners for iPad/iPhone
//As this was only an experiment (for now) it is not well supported nor optimized
ontouchstart = "touchStart(event);"
ontouchmove = "touchMove(event);"
ontouchend = "touchEnd(event);"
ontouchcancel = "touchCancel(event);"
}
}
/**Minimap section*/
var minimap; //stores a refence to minimap object (see minimap.js)
//TODO: remove reference to JQuery and add a normal listener (for "onmouseup" event)
$(document).mouseup(
function () {
minimap.selected = false;
}
);
//TODO: convert to a normal listener (for "onresize" event)
window.onresize = function () {
minimap.initMinimap()
};
var currentDiagramId = null;
/**Initialize the page
* @param {Integer} diagramId (optional) the diagram Id to load
* */
function Init_Panel(diagramId) {
var canvas = getCanvas();
minimap = new Minimap(canvas, document.getElementById("minimap"), 115);
minimap.updateMinimap();
//Canvas properties (width and height)
if (canvasProps == null) {//only create a new one if we have not already loaded one
canvasProps = new CanvasProps(CanvasProps.DEFAULT_WIDTH, CanvasProps.DEFAULT_HEIGHT, CanvasProps.DEFAULT_FILL_COLOR);
}
//lets make sure that our canvas is set to the correct values
canvasProps.setWidth(canvasProps.getWidth());
// canvasProps.setHeight(canvasProps.getHeight());
// alert( canvasProps.getHeight() );
canvasProps.setHeight(2000);
//Browser support and warnings
if (isBrowserReady() == 0) { //no support at all
modal();
}
//Edit panel
setUpEditPanel(canvasProps);
// loads diagram
LoadTempDiagram(diagramId);
// close layer when click-out
addListeners();
window.addEventListener("mousedown", documentOnMouseDown, false);
window.addEventListener("mousemove", documentOnMouseMove, false);
window.addEventListener("mouseup", documentOnMouseUp, false);
}
/**Flag to inform if to drew or not the diagram. Similar to "Dirty pattern" */
var redraw = false;
/**
*Dispatch actions. Detect the action needed and trigger it.
*@param {String} action - the action name
**/
function action(action) {
redraw = false;
switch (action) {
case 'undo':
Log.info("main.js->action()->Undo. Nr of actions in the STACK: " + History.COMMANDS.length);
History.undo();
redraw = true;
break;
// case 'redo':
// Log.info("main.js->action()->Redo. Nr of actions in the STACK: " + History.COMMANDS.length);
// History.redo();
// redraw = true;
// break;
case 'group':
/*After we pressed Ctrl-G any temporary group will became permanent*/
if (selectedGroupId != -1) {
var group = STACK.groupGetById(selectedGroupId);
if (!group.permanent) { //group only temporary groups
var cmdGroup = new GroupCreateCommand(selectedGroupId);
cmdGroup.execute();
History.addUndo(cmdGroup);
Log.info("main.js->action()->Group. New group made permanent. Group id = " + selectedGroupId);
}
else {
Log.info("main.js->action()->Group. Group ALREADY permanent. Group id = " + selectedGroupId);
}
}
redraw = true;
break;
case 'container':
Log.info("main.js->action()->container. Nr of actions in the STACK: " + History.COMMANDS.length);
if (state == STATE_TEXT_EDITING) {
currentTextEditor.destroy();
currentTextEditor = null;
}
//creates a container
var cmdContainerCreate = new ContainerCreateCommand(300, 300);
cmdContainerCreate.execute();
History.addUndo(cmdContainerCreate);
redraw = true;
break;
case 'insertImage':
Log.info("main.js->action()->insertImage. Nr of actions in the STACK: " + History.COMMANDS.length);
if (state == STATE_TEXT_EDITING) {
currentTextEditor.destroy();
currentTextEditor = null;
}
//creates a container
var cmdFigureCreate = new InsertedImageFigureCreateCommand(insertedImageFileName, 100, 100);
cmdFigureCreate.execute();
History.addUndo(cmdFigureCreate);
redraw = true;
break;
case 'ungroup':
if (selectedGroupId != -1) {
var group = STACK.groupGetById(selectedGroupId);
if (group.permanent) { //split only permanent groups
var cmdUngroup = new GroupDestroyCommand(selectedGroupId);
cmdUngroup.execute();
History.addUndo(cmdUngroup);
Log.info("main.js->action()->Ungroup. New group made permanent. Group id = " + selectedGroupId);
}
else {
Log.info("main.js->action()->Ungroup. Ignore. Group is not permanent. Group id = " + selectedGroupId);
}
redraw = true;
}
break;
case 'connector-jagged':
if (state == STATE_TEXT_EDITING) {
currentTextEditor.destroy();
currentTextEditor = null;
}
selectedFigureId = -1;
state = STATE_CONNECTOR_PICK_FIRST;
connectorType = Connector.TYPE_JAGGED;
redraw = true;
break;
case 'connector-straight':
if (state == STATE_TEXT_EDITING) {
currentTextEditor.destroy();
currentTextEditor = null;
}
selectedFigureId = -1;
state = STATE_CONNECTOR_PICK_FIRST;
connectorType = Connector.TYPE_STRAIGHT;
redraw = true;
break;
case 'connector-organic':
if (state == STATE_TEXT_EDITING) {
currentTextEditor.destroy();
currentTextEditor = null;
}
selectedFigureId = -1;
state = STATE_CONNECTOR_PICK_FIRST;
connectorType = Connector.TYPE_ORGANIC;
redraw = true;
break;
case 'rotate90':
case 'rotate90A':
if (selectedFigureId) {
//alert("Selected figure index: " + STACK.figureSelectedIndex);
var figure = STACK.figureGetById(selectedFigureId);
var bounds = figure.getBounds();
var dx = bounds[0] + (bounds[2] - bounds[0]) / 2
var dy = bounds[1] + (bounds[3] - bounds[1]) / 2
//alert(dx + ' ' + dy);
//alert("Selected figure is: " + figure);
var TRANSLATE = [
[1, 0, dx * -1],
[0, 1, dy * -1],
[0, 0, 1]
]
/*
var dx = bounds[0] + (bounds[3] - bounds[1]) / 2
var dy = bounds[1] + (bounds[2] - bounds[0]) / 2
*/
//TODO: figure out why we have to -1 off the dx, we have to do this regardless of rotation angle
var TRANSLATEBACK = [
[1, 0, dx],
[0, 1, dy],
[0, 0, 1]
]
figure.transform(TRANSLATE);
if (action == "rotate90") {
figure.transform(R90);
}
else {
figure.transform(R90A);
}
figure.transform(TRANSLATEBACK);
redraw = true;
}
break;
case 'up': //decrease Y
switch (state) {
case STATE_FIGURE_SELECTED:
var cmdFigUp = new FigureTranslateCommand(selectedFigureId, Matrix.UP);
History.addUndo(cmdFigUp);
cmdFigUp.execute();
redraw = true;
break;
case STATE_GROUP_SELECTED:
var cmdGrpUp = new GroupTranslateCommand(selectedGroupId, Matrix.UP);
History.addUndo(cmdGrpUp);
cmdGrpUp.execute();
redraw = true;
break;
case STATE_CONTAINER_SELECTED:
var cmdContUp = new ContainerTranslateCommand(selectedContainerId, Matrix.UP);
History.addUndo(cmdContUp);
cmdContUp.execute();
redraw = true;
break;
case STATE_CONNECTOR_SELECTED:
var con = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId);
con.transform(Matrix.UP);
redraw = true;
break;
}
break;
case 'down': //increase Y
switch (state) {
case STATE_FIGURE_SELECTED:
var cmdFigDown = new FigureTranslateCommand(selectedFigureId, Matrix.DOWN);
History.addUndo(cmdFigDown);
cmdFigDown.execute();
redraw = true;
break;
case STATE_GROUP_SELECTED:
var cmdGrpDown = new GroupTranslateCommand(selectedGroupId, Matrix.DOWN);
History.addUndo(cmdGrpDown);
cmdGrpDown.execute();
redraw = true;
break;
case STATE_CONTAINER_SELECTED:
var cmdContDown = new ContainerTranslateCommand(selectedContainerId, Matrix.DOWN);
History.addUndo(cmdContDown);
cmdContDown.execute();
redraw = true;
break;
case STATE_CONNECTOR_SELECTED:
var con = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId);
con.transform(Matrix.DOWN);
redraw = true;
break;
}
break;
case 'right': //increase X
switch (state) {
case STATE_FIGURE_SELECTED:
var cmdFigRight = new FigureTranslateCommand(selectedFigureId, Matrix.RIGHT);
History.addUndo(cmdFigRight);
cmdFigRight.execute();
redraw = true;
break;
case STATE_GROUP_SELECTED:
var cmdGrpRight = new GroupTranslateCommand(selectedGroupId, Matrix.RIGHT);
History.addUndo(cmdGrpRight);
cmdGrpRight.execute();
redraw = true;
break;
case STATE_CONTAINER_SELECTED:
var cmdContRight = new ContainerTranslateCommand(selectedContainerId, Matrix.RIGHT);
History.addUndo(cmdContRight);
cmdContRight.execute();
redraw = true;
break;
case STATE_CONNECTOR_SELECTED:
var con = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId);
con.transform(Matrix.RIGHT);
redraw = true;
break;
}
break;
case 'left': //decrease X
switch (state) {
case STATE_FIGURE_SELECTED:
var cmdFigLeft = new FigureTranslateCommand(selectedFigureId, Matrix.LEFT);
History.addUndo(cmdFigLeft);
cmdFigLeft.execute();
redraw = true;
break;
case STATE_GROUP_SELECTED:
var cmdGrpLeft = new GroupTranslateCommand(selectedGroupId, Matrix.LEFT);
History.addUndo(cmdGrpLeft);
cmdGrpLeft.execute();
redraw = true;
break;
case STATE_CONTAINER_SELECTED:
var cmdContLeft = new ContainerTranslateCommand(selectedContainerId, Matrix.LEFT);
History.addUndo(cmdContLeft);
cmdContLeft.execute();
redraw = true;
break;
case STATE_CONNECTOR_SELECTED:
var con = CONNECTOR_MANAGER.connectorGetById(selectedConnectorId);
con.transform(Matrix.LEFT);
redraw = true;
break;
}
break;
case 'grow':
if (selectedFigureId != -1) {
//alert("Selected figure index: " + STACK.figureSelectedIndex);
var figure = STACK.figureGetById(selectedFigureId);
var bounds = figure.getBounds();
var dx = bounds[0] + (bounds[2] - bounds[0]) / 2
var dy = bounds[1] + (bounds[3] - bounds[1]) / 2
//alert(dx + ' ' + dy);
//alert("Selected figure is: " + figure);
var TRANSLATE = [
[1, 0, dx * -1],
[0, 1, dy * -1],
[0, 0, 1]
]
/*
var dx = bounds[0] + (bounds[3] - bounds[1]) / 2
var dy = bounds[1] + (bounds[2] - bounds[0]) / 2
*/
var TRANSLATEBACK = [
[1, 0, dx],
[0, 1, dy],
[0, 0, 1]
]
var GROW = [
[1 + 0.2, 0, 0],
[0, 1 + 0.2, 0],
[0, 0, 1]
]
figure.transform(TRANSLATE);
figure.transform(GROW);
figure.transform(TRANSLATEBACK);
redraw = true;
}
break;
case 'shrink':
if (selectedFigureId != -1) {
//alert("Selected figure index: " + STACK.figureSelectedIndex);
var figure = STACK.figureGetById(selectedFigureId);
var bounds = figure.getBounds();
var dx = bounds[0] + (bounds[2] - bounds[0]) / 2
var dy = bounds[1] + (bounds[3] - bounds[1]) / 2
//alert(dx + ' ' + dy);
//alert("Selected figure is: " + figure);
var TRANSLATE = [
[1, 0, dx * -1],
[0, 1, dy * -1],
[0, 0, 1]
]
/*
var dx = bounds[0] + (bounds[3] - bounds[1]) / 2
var dy = bounds[1] + (bounds[2] - bounds[0]) / 2
*/
var TRANSLATEBACK = [
[1, 0, dx],
[0, 1, dy],
[0, 0, 1]
]
var SHRINK = [
[1 - 0.2, 0, 0],
[0, 1 - 0.2, 0],
[0, 0, 1]
]
figure.transform(TRANSLATE);
figure.transform(SHRINK);
figure.transform(TRANSLATEBACK);
redraw = true;
}
break;
case 'duplicate':
//TODO: From Janis: Connectors are not cloned
if (selectedFigureId != -1) { //duplicate one figure
var cmdDupl = new FigureCloneCommand(selectedFigureId);
cmdDupl.execute();
History.addUndo(cmdDupl);
}
if (selectedGroupId != -1) { //copies a group or multiple figures
var cmdDupl = new GroupCloneCommand(selectedGroupId);
cmdDupl.execute();
History.addUndo(cmdDupl);
}
if (selectedConnectorId != -1) {
var cmdConn = new ConnectorCloneCommand(selectedConnectorId);
cmdConn.execute();
History.addUndo(cmdConn);
}
getCanvas().style.cursor = "default";
redraw = true;
break;
case 'back':
if (selectedFigureId != -1) {
var cmdBack = new FigureZOrderCommand(selectedFigureId, 0);
cmdBack.execute();
History.addUndo(cmdBack);
//STACK.setPosition(selectedFigureId, 0);
redraw = true;
}
break;
case 'front':
if (selectedFigureId != -1) {
var cmdFront = new FigureZOrderCommand(selectedFigureId, STACK.figures.length - 1);
cmdFront.execute();
History.addUndo(cmdFront);
redraw = true;
}
break;
case 'moveback':
if (selectedFigureId != -1) {
var cmdMoveBack = new FigureZOrderCommand(selectedFigureId, STACK.idToIndex[selectedFigureId] - 1);
cmdMoveBack.execute();
History.addUndo(cmdMoveBack);
redraw = true;
}
break;
case 'moveforward':
if (selectedFigureId != -1) {
var cmdMoveForward = new FigureZOrderCommand(selectedFigureId, STACK.idToIndex[selectedFigureId] + 1);
cmdMoveForward.execute();
History.addUndo(cmdMoveForward);
redraw = true;
}
break;
} //end switch
if (redraw) {
draw();
}
}
/**Stores last mouse position. Null initially.*/
var lastMousePosition = null;
function documentOnMouseDown(evt) {
//Log.info("documentOnMouseDown");
//evt.preventDefault();
}
var draggingFigure = null;
function documentOnMouseMove(evt) {
//Log.info("documentOnMouseMove");
switch (state) {
case STATE_FIGURE_CREATE:
//Log.info("documentOnMouseMove: trying to draw the D'n'D figure");
if (!draggingFigure) {
draggingFigure = document.createElement('img');
draggingFigure.setAttribute('id', 'draggingThumb');
draggingFigure.style.position = 'absolute';
draggingFigure.style.zIndex = 3; // set it in front of editor
body.appendChild(draggingFigure);
}
//Log.info("editor.php>documentOnMouseMove>STATE_FIGURE_CREATE: selectedFigureThumb=" + selectedFigureThumb);
draggingFigure.setAttribute('src', selectedFigureThumb);
draggingFigure.style.width = '100px';
draggingFigure.style.height = '25px';
draggingFigure.style.left = (evt.pageX - 20) + 'px';
draggingFigure.style.top = (evt.pageY - 15) + 'px';
//draggingFigure.style.backgroundColor = 'red';
draggingFigure.style.display = 'block';
draggingFigure.addEventListener('mousedown', function (event) {
//Log.info("documentOnMouseMove: How stupid. Mouse down on dragging figure");
}, false);
draggingFigure.addEventListener('mouseup', function (ev) {
var coords = getCanvasXY(ev);
if (coords == null) {
return;
}
var x = coords[0];
var y = coords[1];
switch (state) {
case STATE_FIGURE_CREATE:
Log.info("draggingFigure>onMouseUp() + STATE_FIGURE_CREATE");
snapMonitor = [0, 0];
//treat new figure
//do we need to create a figure on the canvas?
if (window.createFigureFunction) {
//Log.info("draggingFigure>onMouseUp() + STATE_FIGURE_CREATE--> new state STATE_FIGURE_SELECTED + createFigureFunction = " + window.createFigureFunction);
var cmdCreateFig = new FigureCreateCommand(window.createFigureFunction, x, y);
cmdCreateFig.execute();
History.addUndo(cmdCreateFig);
//HTMLCanvas.style.cursor = 'default';
selectedConnectorId = -1;
createFigureFunction = null;
mousePressed = false;
redraw = true;
draw();
//TODO: a way around to hide this dragging DIV
document.getElementById('draggingThumb').style.display = 'none';
//TODO: the horror
//body.removeChild(document.getElementById('draggingThumb'));
}
else {
Log.info("draggingFigure>onMouseUp() + STATE_FIGURE_CREATE--> but no 'createFigureFunction'");
}
break;
}
//stop canvas from gettting this event
evt.stopPropagation();
}, false);
break;
case STATE_NONE:
//document.removeChild(document.getElementById('draggingThumb'));
break;
}
}
function documentOnMouseUp(evt) {
Log.info("documentOnMouseUp");
switch (state) {
case STATE_FIGURE_CREATE:
var eClicked = document.elementFromPoint(evt.clientX, evt.clientY);
if (eClicked.id != 'a') {
if (draggingFigure) {
//draggingFigure.style.display = 'none';
draggingFigure.parentNode.removeChild(draggingFigure);
state = STATE_NONE;
draggingFigure = null;
//evt.stopPropagation();
}
}
break;
}
}
/*Returns a text containing all the URL in a diagram */
function linkMap() {
var csvBounds = '';
var first = true;
for (var f in STACK.figures) {
var figure = STACK.figures[f];
if (figure.url != '') {
var bounds = figure.getBounds();
if (first) {
first = false;
}
else {
csvBounds += "\n";
}
csvBounds += bounds[0] + ',' + bounds[1] + ',' + bounds[2] + ',' + bounds[3] + ',' + figure.url;
}
}
Log.info("editor.php->linkMap()->csv bounds: " + csvBounds);
return csvBounds;
}
/*======================APPLE=====================================*/
/**Triggered when an touch is initiated (iPad/iPhone).
*Simply forward to onMouseDown
*@param {Event} event - the event triggered
**/
function touchStart(event) {
event.preventDefault();
onMouseDown(event);
}
/**Triggered while touching and moving is in progress (iPad/iPhone).
*Simply forward to onMouseMove
*@param {Event} event - the event triggered
**/
function touchMove(event) {
event.preventDefault();
onMouseMove(event);
}
/**Triggered when touch ends (iPad/iPhone).
*Simply forward to onMouseUp
*@param {Event} event - the event triggered
**/
function touchEnd(event) {
onMouseUp(event);
}
/**Triggered when touch is canceled (iPad/iPhone).
*@param {Event} event - the event triggered
**/
function touchCancel(event) {
//nothing
}
/*======================END APPLE=================================*/