Created
February 1, 2015 06:04
-
-
Save nrafter/c3dc961fc2b2602d004e to your computer and use it in GitHub Desktop.
var mouseUp section of event loop in svgcanvas.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var mouseUp = function(evt) { | |
canvas.addClones = false; | |
window.removeEventListener("keyup", canvas.removeClones) | |
selectedElements = selectedElements.filter(Boolean) | |
if(evt.button === 2) { | |
return; | |
} | |
var tempJustSelected = justSelected; | |
justSelected = null; | |
if (!started) { | |
return; | |
} | |
var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), | |
mouse_x = pt.x * current_zoom, | |
mouse_y = pt.y * current_zoom, | |
x = mouse_x / current_zoom, | |
y = mouse_y / current_zoom, | |
element = getElem(getId()); | |
//,NSR issue 123: let's keep elements by default. also, this could break something | |
//keep = false; | |
var real_x = x; | |
var real_y = y; | |
// TODO: Make true when in multi-unit mode | |
var useUnit = false; // (curConfig.baseUnit !== 'px'); | |
started = false; | |
switch (current_mode) { | |
// intentionally fall-through to select here | |
case "bounds": | |
var menu_items = $('#cmenu_canvas li'); | |
var selected = canvas.getSelectedElems(); | |
centerInBounds(canvas.getBoundingBoxElems(selected, rubberBox)); | |
call("changed", selected); | |
if (rubberBox != null) { | |
rubberBox.setAttribute("display", "none"); | |
curBBoxes = []; | |
} | |
keep = true; | |
menu_items.enableContextMenuItems('#create_bounds,#view_bounds,#delete_bounds'); | |
window.prevMode = 'bounds'; | |
canvas.setMode('select'); | |
break; | |
case "resize": | |
if (startedElements) { | |
endedElements = _.map(canvas.getSelectedElems(), function(e){ return _.extend(createObjectNode(e), canvas.getBBox(e), { rotationAngle: canvas.getRotationAngle(e) }); }); | |
logChanged('resize', startedElements, endedElements); | |
startedElements = null; | |
} | |
case "multiselect": | |
if (rubberBox != null) { | |
rubberBox.setAttribute("display", "none"); | |
curBBoxes = []; | |
} | |
current_mode = "select"; | |
case "select": | |
if (selectedElements[0] != null) { | |
// if we only have one selected element | |
if (selectedElements.length == 1) { | |
// set our current stroke/fill properties to the element's | |
var selected = selectedElements[0]; | |
switch ( selected.tagName ) { | |
case "g": | |
case "use": | |
case "image": | |
case "foreignObject": | |
break; | |
default: | |
cur_properties.fill = selected.getAttribute("fill"); | |
cur_properties.fill_opacity = selected.getAttribute("fill-opacity"); | |
cur_properties.stroke = selected.getAttribute("stroke"); | |
cur_properties.stroke_opacity = selected.getAttribute("stroke-opacity"); | |
cur_properties.stroke_width = selected.getAttribute("stroke-width"); | |
cur_properties.stroke_dasharray = selected.getAttribute("stroke-dasharray"); | |
cur_properties.stroke_linejoin = selected.getAttribute("stroke-linejoin"); | |
cur_properties.stroke_linecap = selected.getAttribute("stroke-linecap"); | |
} | |
if (selected.tagName == "text") { | |
cur_text.font_size = selected.getAttribute("font-size"); | |
cur_text.font_family = selected.getAttribute("font-family"); | |
} | |
selectorManager.requestSelector(selected).showGrips(true); | |
// This shouldn't be necessary as it was done on mouseDown... | |
// call("selected", [selected]); | |
} | |
// always recalculate dimensions to strip off stray identity transforms | |
recalculateAllSelectedDimensions(); | |
//NSR alignment: assuming testing will only happen with a single selected element for now, while building | |
console.log("Updating alignmenat from select..."); | |
canvas.updateAlignment(selectedElements[0]); | |
// if it was being dragged/resized | |
var isBotchedZoom = svgedit.browser.isGecko(); | |
r_start_x = isBotchedZoom ? r_start_x * current_zoom : r_start_x; | |
r_start_y = isBotchedZoom ? r_start_y * current_zoom : r_start_y; | |
var difference_x = Math.abs(real_x-r_start_x); | |
var difference_y = Math.abs(real_y-r_start_y); | |
if (difference_y > 1 || difference_y > 1) { | |
var len = selectedElements.length; | |
for (var i = 0; i < len; ++i) { | |
if (selectedElements[i] == null) break; | |
if(!selectedElements[i].firstChild) { | |
// Not needed for groups (incorrectly resizes elems), possibly not needed at all? | |
selectorManager.requestSelector(selectedElements[i]).resize(); | |
} | |
} | |
if(startedElements) { | |
endedElements = _.map(canvas.getSelectedElems(), function(e){ return _.extend(createObjectNode(e), canvas.getBBox(e), { rotationAngle: canvas.getRotationAngle(e) }); }); | |
logChanged('move', startedElements, endedElements); | |
startedElements = null; | |
} | |
} | |
// no change in position/size, so maybe we should move to pathedit | |
else { | |
var t = evt.target; | |
if (selectedElements[0].nodeName === "path" && selectedElements[1] == null) { | |
//NSR: don't need to drop into pathEdit, also fixes clicking too many times tries to replace elements | |
// pathActions.select(selectedElements[0]); | |
} // if it was a path | |
// else, if it was selected and this is a shift-click, remove it from selection | |
else if (evt.shiftKey) { | |
if(tempJustSelected != t) { | |
canvas.removeFromSelection([t]); | |
} | |
} | |
} // no change in mouse position | |
// Remove non-scaling stroke | |
if(svgedit.browser.supportsNonScalingStroke()) { | |
var elem = selectedElements[0]; | |
if (elem) { | |
elem.removeAttribute('style'); | |
svgedit.utilities.walkTree(elem, function(elem) { | |
elem.removeAttribute('style'); | |
}); | |
} | |
} | |
} | |
//return; | |
break; | |
case "zoom": | |
if (rubberBox != null) { | |
rubberBox.setAttribute("display", "none"); | |
} | |
var factor = evt.altKey?.5:2; | |
call("zoomed", { | |
'x': Math.min(r_start_x, real_x), | |
'y': Math.min(r_start_y, real_y), | |
'width': Math.abs(real_x - r_start_x), | |
'height': Math.abs(real_y - r_start_y), | |
'factor': factor | |
}); | |
return; | |
case "fhpath": | |
// Check that the path contains at least 2 points; a degenerate one-point path | |
// causes problems. | |
// Webkit ignores how we set the points attribute with commas and uses space | |
// to separate all coordinates, see https://bugs.webkit.org/show_bug.cgi?id=29870 | |
var coords = element.getAttribute('points'); | |
var commaIndex = coords.indexOf(','); | |
if (commaIndex >= 0) { | |
keep = coords.indexOf(',', commaIndex+1) >= 0; | |
} else { | |
keep = coords.indexOf(' ', coords.indexOf(' ')+1) >= 0; | |
} | |
if (keep) { | |
element = pathActions.smoothPolylineIntoPath(element); | |
} | |
logCreated(element); | |
break; | |
case "line": | |
var attrs = $(element).attr(["x1", "x2", "y1", "y2"]); | |
keep = (attrs.x1 != attrs.x2 || attrs.y1 != attrs.y2); | |
logCreated(element); | |
break; | |
case "foreignObject": | |
case "square": | |
case "rect": | |
case "image": | |
var attrs = $(element).attr(["width", "height"]); | |
// Image should be kept regardless of size (use inherit dimensions later) | |
keep = (attrs.width != 0 || attrs.height != 0) || current_mode === "image"; | |
//NSR alignment | |
canvas.addToAlignment(element); | |
//console.log("Adding initial FSRI element... ", element); | |
logCreated(element); | |
break; | |
case "circle": | |
keep = (element.getAttribute('r') != 0); | |
logCreated(element); | |
//NSR alignment | |
canvas.addToAlignment(element); | |
//console.log("Adding initial circle element... ", element); | |
break; | |
case "ellipse": | |
var attrs = $(element).attr(["rx", "ry"]); | |
keep = (attrs.rx != null || attrs.ry != null); | |
logCreated(element); | |
//NSR alignment | |
canvas.addToAlignment(element); | |
//console.log("Adding initial ellipse element... ", element); | |
break; | |
case "fhellipse": | |
if ((freehand.maxx - freehand.minx) > 0 && | |
(freehand.maxy - freehand.miny) > 0) { | |
element = addSvgElementFromJson({ | |
"element": "ellipse", | |
"curStyles": true, | |
"attr": { | |
"cx": (freehand.minx + freehand.maxx) / 2, | |
"cy": (freehand.miny + freehand.maxy) / 2, | |
"rx": (freehand.maxx - freehand.minx) / 2, | |
"ry": (freehand.maxy - freehand.miny) / 2, | |
"id": getId() | |
} | |
}); | |
call("changed",[element]); | |
keep = true; | |
} | |
logCreated(element); | |
break; | |
case "fhrect": | |
if ((freehand.maxx - freehand.minx) > 0 && | |
(freehand.maxy - freehand.miny) > 0) { | |
element = addSvgElementFromJson({ | |
"element": "rect", | |
"curStyles": true, | |
"attr": { | |
"x": freehand.minx, | |
"y": freehand.miny, | |
"width": (freehand.maxx - freehand.minx), | |
"height": (freehand.maxy - freehand.miny), | |
"id": getId() | |
} | |
}); | |
call("changed",[element]); | |
keep = true; | |
} | |
logCreated(element); | |
break; | |
case "text": | |
keep = true; | |
selectOnly([element]); | |
textActions.start(element); | |
//NSR alignment | |
canvas.addToAlignment(element); | |
//console.log("Adding initial text element... ", element); | |
break; | |
case "path": | |
// set element to null here so that it is not removed nor finalized | |
element = null; | |
// continue to be set to true so that mouseMove happens | |
started = true; | |
var res = pathActions.mouseUp(evt, element, mouse_x, mouse_y); | |
element = res.element; | |
keep = res.keep; | |
logCreated(element); | |
//NSR alignment | |
canvas.addToAlignment(element); | |
//console.log("Adding initial path element... ", element); | |
break; | |
case "pathedit": | |
keep = true; | |
element = null; | |
pathActions.mouseUp(evt); | |
//NSR alignment | |
canvas.addToAlignment(element); | |
//console.log("Adding initial pathedit element... ", element); | |
break; | |
case "textedit": | |
keep = false; | |
element = null; | |
textActions.mouseUp(evt, mouse_x, mouse_y); | |
break; | |
case "rotate": | |
keep = true; | |
element = null; | |
current_mode = "select"; | |
var batchCmd = canvas.undoMgr.finishUndoableChange(); | |
if (!batchCmd.isEmpty()) { | |
addCommandToHistory(batchCmd); | |
} | |
// perform recalculation to weed out any stray identity transforms that might get stuck | |
recalculateAllSelectedDimensions(); | |
call("changed", selectedElements); | |
// TODO: WSL Mark | |
if(startedElements) { | |
endedElements = _.map(canvas.getSelectedElems(), function(e){ return _.extend(createObjectNode(e), canvas.getBBox(e), { rotationAngle: canvas.getRotationAngle(e) }); }); | |
logChanged('rotate', startedElements, endedElements); | |
startedElements = null; | |
} | |
break; | |
default: | |
// This could occur in an extension | |
break; | |
} | |
var ext_result = runExtensions("mouseUp", { | |
event: evt, | |
mouse_x: mouse_x, | |
mouse_y: mouse_y | |
}, true); | |
$.each(ext_result, function(i, r) { | |
if(r) { | |
keep = r.keep || keep; | |
element = r.element; | |
started = r.started || started; | |
} | |
}); | |
if( !keep && element != null && element.parentNode != null ) { | |
// WSL Testing; | |
if( evt == null || evt.target == null) { | |
console.log("t NULL for ", element); | |
} | |
getCurrentDrawing().releaseId(getId()); | |
element.parentNode.removeChild(element); | |
element = null; | |
var t = evt.target; | |
// if this element is in a group, go up until we reach the top-level group | |
// just below the layer groups | |
// TODO: once we implement links, we also would have to check for <a> elements | |
while( t.parentNode.parentNode.tagName == "g" ) { | |
t = t.parentNode; | |
} | |
// if we are not in the middle of creating a path, and we've clicked on some shape, | |
// then go to Select mode. | |
// WebKit returns <div> when the canvas is clicked, Firefox/Opera return <svg> | |
if ( (current_mode != "path" || !drawn_path) && | |
t.parentNode.id != "selectorParentGroup" && | |
t.id != "svgcanvas" && t.id != "svgroot") | |
{ | |
// switch into "select" mode if we've clicked on an element | |
canvas.setMode("select"); | |
selectOnly([t], true); | |
} | |
//NSR issue 123: confirmed it broke stuff, an item that was selected when the canvas is clicked is treated | |
//as a new element and reselected immediately right here | |
} else if (element != null && current_mode !== "select") { | |
canvas.addedNew = true; | |
if(useUnit) svgedit.units.convertAttrs(element); | |
var ani_dur = .2, c_ani; | |
if(opac_ani.beginElement && element.getAttribute('opacity') != cur_shape.opacity) { | |
c_ani = $(opac_ani).clone().attr({ | |
to: cur_shape.opacity, | |
dur: ani_dur | |
}).appendTo(element); | |
try { | |
// Fails in FF4 on foreignObject | |
c_ani[0].beginElement(); | |
} catch(e){} | |
} else { | |
ani_dur = 0; | |
} | |
// Ideally this would be done on the endEvent of the animation, | |
// but that doesn't seem to be supported in Webkit | |
setTimeout(function() { | |
if(c_ani) c_ani.remove(); | |
element.setAttribute("opacity", cur_shape.opacity); | |
element.setAttribute("style", "pointer-events:inherit"); | |
cleanupElement(element); | |
if(current_mode === "path") { | |
pathActions.toEditMode(element); | |
} else { | |
if(curConfig.selectNew) { | |
selectOnly([element], true); | |
} | |
} | |
// we create the insert command that is stored on the stack | |
// undo means to call cmd.unapply(), redo means to call cmd.apply() | |
addCommandToHistory(new InsertElementCommand(element)); | |
call("changed",[element]); | |
}, ani_dur * 1000); | |
} | |
start_transform = null; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment