diff --git a/public/svg-edit/editor/svg-editor.css b/public/svg-edit/editor/svg-editor.css index 1e56ed60..709383a1 100644 --- a/public/svg-edit/editor/svg-editor.css +++ b/public/svg-edit/editor/svg-editor.css @@ -1251,7 +1251,7 @@ span.zoom_tool { padding: 5px 0; margin: 0px; display: none; - font: 14px/17px Lucida Sans, Helvetica, Verdana, sans-serif; + font: 12px/15px Lucida Sans, Helvetica, Verdana, sans-serif; border-radius: 5px; -moz-border-radius: 5px; -moz-box-shadow: 2px 5px 10px rgba(0,0,0,.3); @@ -1266,7 +1266,7 @@ span.zoom_tool { } .contextMenu .shortcut { - width: 80px; + width: 115px; text-align:right; float:right; } diff --git a/public/svg-edit/editor/svg-editor.html b/public/svg-edit/editor/svg-editor.html index ef407916..e2599618 100644 --- a/public/svg-edit/editor/svg-editor.html +++ b/public/svg-edit/editor/svg-editor.html @@ -158,8 +158,8 @@ script type="text/javascript" src="locale/locale.min.js">
-
-
+
+
@@ -690,8 +690,10 @@ script type="text/javascript" src="locale/locale.min.js">
  • Delete
  • GroupG
  • UngroupG
  • -
  • Bring ForwardCTRL+]
  • +
  • Bring to FrontSHFT+CTRL+]
  • +
  • Bring ForwardCTRL+]
  • Send BackwardCTRL+[
  • +
  • Send to BackSHFT+CTRL+[
  • diff --git a/public/svg-edit/editor/svg-editor.js b/public/svg-edit/editor/svg-editor.js index 67dce636..41fbc369 100644 --- a/public/svg-edit/editor/svg-editor.js +++ b/public/svg-edit/editor/svg-editor.js @@ -464,6 +464,8 @@ show_save_warning = false, exportWindow = null, tool_scale = 1, + zoomInIcon = 'crosshair', + zoomOutIcon = 'crosshair', ui_context = 'toolbars'; // This sets up alternative dialog boxes. They mostly work the same way as @@ -523,6 +525,7 @@ $('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all} #svgcanvas svg{cursor:default}'); } svgCanvas.setMode('select'); + workarea.css('cursor','auto'); }; var togglePathEditMode = function(editmode, elems) { @@ -703,7 +706,6 @@ res = svgCanvas.getResolution(), w_area = workarea, canvas_pos = $('#svgcanvas').position(); - w_area.css('cursor','auto'); var z_info = svgCanvas.setBBoxZoom(bbox, w_area.width()-scrbar, w_area.height()-scrbar); if(!z_info) return; var zoomlevel = z_info.zoom, @@ -720,6 +722,7 @@ // Go to select if a zoom box was drawn setSelectMode(); } + zoomDone(); } @@ -1565,7 +1568,7 @@ .enableContextMenuItems('#group') .disableContextMenuItems('#ungroup'); } else { - menu_items.disableContextMenuItems('#delete,#cut,#copy,#group,#ungroup,#move_up,#move_down'); + menu_items.disableContextMenuItems('#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back'); } // update history buttons @@ -1589,7 +1592,7 @@ $('#selLayerNames').removeAttr('disabled').val(currentLayer); // Enable regular menu options - canv_menu.enableContextMenuItems('#delete,#cut,#copy,#move_down,#move_up'); + canv_menu.enableContextMenuItems('#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back'); } else { $('#selLayerNames').attr('disabled', 'disabled'); @@ -1858,6 +1861,7 @@ $('.tools_flyout').fadeOut(fadeFlyouts); } $('#styleoverrides').text(''); + workarea.css('cursor','auto'); $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); $(button).addClass('tool_button_current').removeClass('tool_button'); return true; @@ -1897,7 +1901,15 @@ }).bind('keyup', 'space', function(evt) { evt.preventDefault(); svgCanvas.spaceKey = keypan = false; - }); + }).bind('keydown', 'shift', function(evt) { + if(svgCanvas.getMode() === 'zoom') { + workarea.css('cursor', zoomOutIcon); + } + }).bind('keyup', 'shift', function(evt) { + if(svgCanvas.getMode() === 'zoom') { + workarea.css('cursor', zoomInIcon); + } + }) }()); @@ -2263,8 +2275,8 @@ var clickZoom = function(){ if (toolButtonClick('#tool_zoom')) { - workarea.css('cursor','crosshair'); svgCanvas.setMode('zoom'); + workarea.css('cursor', zoomInIcon); } }; @@ -3226,7 +3238,7 @@ // Use this SVG elem to test vectorEffect support var test_el = docElem.firstChild; test_el.setAttribute('style','vector-effect:non-scaling-stroke'); - var supportsNonSS = (test_el.style.vectorEffect == 'non-scaling-stroke'); + var supportsNonSS = (test_el.style.vectorEffect === 'non-scaling-stroke'); test_el.removeAttribute('style'); // Use this to test support for blur element. Seems to work to test support in Webkit @@ -3236,6 +3248,20 @@ } $(blur_test).remove(); + // Test for zoom icon support + (function() { + var pre = '-' + ua_prefix.toLowerCase() + '-zoom-'; + var zoom = pre + 'in'; + workarea.css('cursor', zoom); + if(workarea.css('cursor') === zoom) { + zoomInIcon = zoom; + zoomOutIcon = pre + 'out'; + } + workarea.css('cursor', 'auto'); + }()); + + + // Test for embedImage support (use timeout to not interfere with page load) setTimeout(function() { svgCanvas.embedImage('images/logo.png', function(datauri) { @@ -3656,8 +3682,8 @@ {sel:'#tool_node_delete', fn: deletePathNode, evt: 'click'}, {sel:'#tool_openclose_path', fn: opencloseSubPath, evt: 'click'}, {sel:'#tool_add_subpath', fn: addSubPath, evt: 'click'}, - {sel:'#tool_move_top', fn: moveToTopSelected, evt: 'click', key: 'shift+up'}, - {sel:'#tool_move_bottom', fn: moveToBottomSelected, evt: 'click', key: 'shift+down'}, + {sel:'#tool_move_top', fn: moveToTopSelected, evt: 'click', key: 'ctrl+shift+]'}, + {sel:'#tool_move_bottom', fn: moveToBottomSelected, evt: 'click', key: 'ctrl+shift+['}, {sel:'#tool_topath', fn: convertToPath, evt: 'click'}, {sel:'#tool_undo', fn: clickUndo, evt: 'click', key: ['Z', true]}, {sel:'#tool_redo', fn: clickRedo, evt: 'click', key: ['Y', true]}, @@ -3683,8 +3709,8 @@ {key: 'shift+P', fn: selectNext}, {key: [modKey+'up', true], fn: function(){zoomImage(2);}}, {key: [modKey+'down', true], fn: function(){zoomImage(.5);}}, - {key: [modKey+'[', true], fn: function(){moveUpDownSelected('Down');}}, {key: [modKey+']', true], fn: function(){moveUpDownSelected('Up');}}, + {key: [modKey+'[', true], fn: function(){moveUpDownSelected('Down');}}, {key: ['up', true], fn: function(){moveSelected(0,-1);}}, {key: ['down', true], fn: function(){moveSelected(0,1);}}, {key: ['left', true], fn: function(){moveSelected(-1,0);}}, @@ -3900,11 +3926,17 @@ case 'ungroup': svgCanvas.ungroupSelectedElement(); break; + case 'move_front': + moveToTopSelected(); + break; + case 'move_up': + moveUpDownSelected('Up'); + break; case 'move_down': moveUpDownSelected('Down'); break; - case 'move_up': - moveUpDownSelected('Up'); + case 'move_back': + moveToBottomSelected(); break; } @@ -4085,7 +4117,7 @@ updateCanvas(true); // }); - // var revnums = "svg-editor.js ($Rev: 1758 $) "; + // var revnums = "svg-editor.js ($Rev: 1762 $) "; // revnums += svgCanvas.getVersion(); // $('#copyright')[0].setAttribute("title", revnums); diff --git a/public/svg-edit/editor/svgcanvas.js b/public/svg-edit/editor/svgcanvas.js index 65eb27ef..45c8984e 100644 --- a/public/svg-edit/editor/svgcanvas.js +++ b/public/svg-edit/editor/svgcanvas.js @@ -3705,7 +3705,6 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) { var operation = 0; var N = tlist.numberOfItems; - // Check if it has a gradient with userSpaceOnUse, in which case // adjust it by recalculating the matrix transform. // TODO: Make this work in Webkit using SVGEditTransformList @@ -3714,6 +3713,7 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) { if(fill && fill.indexOf('url(') === 0) { var grad = getElem(getUrlFromAttr(fill).substr(1)); if(grad.getAttribute('gradientUnits') === 'userSpaceOnUse') { + //Update the userSpaceOnUse element var grad = $(grad); m = transformListToTransform(tlist).matrix; @@ -5140,9 +5140,6 @@ var getMouseTarget = this.getMouseTarget = function(evt) { if (selectedElements[0].nodeName == "path" && selectedElements[1] == null) { pathActions.select(t); } // if it was a path - else if (selectedElements[0].nodeName == "text" && selectedElements[1] == null) { - textActions.select(t, x, y); - } // 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) { @@ -5240,7 +5237,7 @@ var getMouseTarget = this.getMouseTarget = function(evt) { break; case "text": keep = true; - addToSelection([element]); + selectOnly([element]); textActions.start(element); break; case "path": @@ -5320,6 +5317,7 @@ var getMouseTarget = this.getMouseTarget = function(evt) { } else if (element != null) { canvas.addedNew = true; + var ani_dur = .2, c_ani; if(opac_ani.beginElement && element.getAttribute('opacity') != cur_shape.opacity) { c_ani = $(opac_ani).clone().attr({ @@ -5366,6 +5364,11 @@ var getMouseTarget = this.getMouseTarget = function(evt) { var mouse_target = getMouseTarget(evt); + if(mouse_target.tagName === 'text' && current_mode !== 'textedit') { + var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ); + textActions.select(mouse_target, pt.x, pt.y); + } + if(getRotationAngle(mouse_target)) { // Don't do for rotated groups for now return; @@ -5438,7 +5441,7 @@ var preventClickDefault = function(img) { // Group: Text edit functions // Functions relating to editing text elements var textActions = canvas.textActions = function() { - var curtext, current_text; + var curtext; var textinput; var cursor; var selblock; @@ -5557,7 +5560,6 @@ var textActions = canvas.textActions = function() { // No content, so return 0 if(chardata.length == 1) return 0; - // Determine if cursor should be on left or right of character var charpos = curtext.getCharNumAtPosition(pt); if(charpos < 0) { @@ -5638,7 +5640,7 @@ var textActions = canvas.textActions = function() { } function selectWord(evt) { - if(!allow_dbl) return; + if(!allow_dbl || !curtext) return; var ept = transformPoint( evt.pageX, evt.pageY, root_sctm ), mouse_x = ept.x * current_zoom, @@ -5662,13 +5664,8 @@ var textActions = canvas.textActions = function() { return { select: function(target, x, y) { - if (current_text == target) { - curtext = target; - textActions.toEditMode(x, y); - } // going into pathedit mode - else { - current_text = target; - } + curtext = target; + textActions.toEditMode(x, y); }, start: function(elem) { curtext = elem; @@ -5712,6 +5709,7 @@ var textActions = canvas.textActions = function() { var sel = selectorManager.requestSelector(curtext).selectorRect; textActions.init(); + $(curtext).css('cursor', 'text'); // if(support.editableText) { @@ -5763,7 +5761,6 @@ var textActions = canvas.textActions = function() { // $(textinput).blur(hideCursor); }, clear: function() { - current_text = null; if(current_mode == "textedit") { textActions.toSelectMode(); } @@ -5821,7 +5818,6 @@ var textActions = canvas.textActions = function() { x: end.x, width: 0 }); - setSelection(textinput.selectionStart, textinput.selectionEnd, true); } } @@ -8121,6 +8117,57 @@ var uniquifyElems = this.uniquifyElems = function(g) { obj_num++; } +// Function convertGradients +// Converts gradients from userSpaceOnUse to objectBoundingBox +var convertGradients = this.convertGradients = function(elem) { + $(elem).find('linearGradient, radialGradient').each(function() { + var grad = this; + if($(grad).attr('gradientUnits') === 'userSpaceOnUse') { + // TODO: Support more than one element with this ref by duplicating parent grad + var elems = $(svgcontent).find('[fill=url(#' + grad.id + ')],[stroke=url(#' + grad.id + ')]'); + if(!elems.length) return; + + // get object's bounding box + var bb = elems[0].getBBox(); + + if(grad.tagName === 'linearGradient') { + var g_coords = $(grad).attr(['x1', 'y1', 'x2', 'y2']); + + $(grad).attr({ + x1: (g_coords.x1 - bb.x) / bb.width, + y1: (g_coords.y1 - bb.y) / bb.height, + x2: (g_coords.x2 - bb.x) / bb.width, + y2: (g_coords.y2 - bb.y) / bb.height + }); + + grad.removeAttribute('gradientUnits'); + } else { + // Note: radialGradient elements cannot be easily converted + // because userSpaceOnUse will keep circular gradients, while + // objectBoundingBox will x/y scale the gradient according to + // its bbox. + + // For now we'll do nothing, though we should probably have + // the gradient be updated as the element is moved, as + // inkscape/illustrator do. + +// var g_coords = $(grad).attr(['cx', 'cy', 'r']); +// +// $(grad).attr({ +// cx: (g_coords.cx - bb.x) / bb.width, +// cy: (g_coords.cy - bb.y) / bb.height, +// r: g_coords.r +// }); +// +// grad.removeAttribute('gradientUnits'); + } + + + } + }); +} + + // Function: convertToGroup // Converts selected/given or child SVG element to a group var convertToGroup = this.convertToGroup = function(elem) { @@ -8194,7 +8241,8 @@ var convertToGroup = this.convertToGroup = function(elem) { } batchCmd.addSubCommand(new InsertElementCommand(g)); } - + convertGradients(g); + // recalculate dimensions on the top-level children so that unnecessary transforms // are removed walkTreePost(g, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); @@ -8304,52 +8352,7 @@ this.setSvgString = function(xmlString) { } }); - // convert gradients with userSpaceOnUse to objectBoundingBox - content.find('linearGradient, radialGradient').each(function() { - var grad = this; - if($(grad).attr('gradientUnits') === 'userSpaceOnUse') { - // TODO: Support more than one element with this ref by duplicating parent grad - var elems = $(svgcontent).find('[fill=url(#' + grad.id + ')],[stroke=url(#' + grad.id + ')]'); - if(!elems.length) return; - - // get object's bounding box - var bb = elems[0].getBBox(); - - if(grad.tagName === 'linearGradient') { - var g_coords = $(grad).attr(['x1', 'y1', 'x2', 'y2']); - - $(grad).attr({ - x1: (g_coords.x1 - bb.x) / bb.width, - y1: (g_coords.y1 - bb.y) / bb.height, - x2: (g_coords.x2 - bb.x) / bb.width, - y2: (g_coords.y1 - bb.y) / bb.height - }); - - grad.removeAttribute('gradientUnits'); - } else { - // Note: radialGradient elements cannot be easily converted - // because userSpaceOnUse will keep circular gradients, while - // objectBoundingBox will x/y scale the gradient according to - // its bbox. - - // For now we'll do nothing, though we should probably have - // the gradient be updated as the element is moved, as - // inkscape/illustrator do. - -// var g_coords = $(grad).attr(['cx', 'cy', 'r']); -// -// $(grad).attr({ -// cx: (g_coords.cx - bb.x) / bb.width, -// cy: (g_coords.cy - bb.y) / bb.height, -// r: g_coords.r -// }); -// -// grad.removeAttribute('gradientUnits'); - } - - - } - }); + convertGradients(content[0]); // recalculate dimensions on the top-level children so that unnecessary transforms // are removed @@ -8501,6 +8504,7 @@ this.importSvgString = function(xmlString) { var use_el = svgdoc.createElementNS(svgns, "use"); setHref(use_el, "#" + symbol.id); findDefs().appendChild(symbol); + (current_group || current_layer).appendChild(use_el); use_el.id = getNextId(); clearSelection(); @@ -9132,7 +9136,7 @@ this.getZoom = function(){return current_zoom;}; // Function: getVersion // Returns a string which describes the revision number of SvgCanvas. this.getVersion = function() { - return "svgcanvas.js ($Rev: 1759 $)"; + return "svgcanvas.js ($Rev: 1764 $)"; }; // Function: setUiStrings @@ -10648,6 +10652,9 @@ this.ungroupSelectedElement = function() { } var chtlist = getTransformList(elem); + + // Don't process gradient transforms + if(~elem.tagName.indexOf('Gradient')) chtlist = null; // Hopefully not a problem to add this. Necessary for elements like if(!chtlist) continue;