First half of Issue 34 fixed: Can create polygons now. Also change default fill to red and default stroke-width to 5. Moved some functions around for convenience

git-svn-id: http://svg-edit.googlecode.com/svn/trunk@359 eee81c28-f429-11dd-99c0-75d572ba1ddd
master
Jeff Schiller 2009-08-07 05:44:55 +00:00
parent 381e09be87
commit ab3fa8e925
3 changed files with 195 additions and 77 deletions

View File

@ -166,7 +166,7 @@
<img class="tool_button" id="tools_rect_show" src="images/square.png" title="Square/Rect Tool [4/Shift+4]" alt="Square"/><br/> <img class="tool_button" id="tools_rect_show" src="images/square.png" title="Square/Rect Tool [4/Shift+4]" alt="Square"/><br/>
<img class="tool_button" id="tools_ellipse_show" src="images/circle.png" title="Ellipse/Circle Tool [5/Shift+5]" alt="Circle"/><br/> <img class="tool_button" id="tools_ellipse_show" src="images/circle.png" title="Ellipse/Circle Tool [5/Shift+5]" alt="Circle"/><br/>
<img class="tool_button" id="tool_text" src="images/text.png" title="Text Tool [6]" alt="Text"/> <img class="tool_button" id="tool_text" src="images/text.png" title="Text Tool [6]" alt="Text"/>
<img class="tool_button_disabled" id="tool_poly" src="images/polygon.png" title="Poly Tool [7]" alt="Poly"/> <img class="tool_button" id="tool_poly" src="images/polygon.png" title="Poly Tool [7]" alt="Poly"/>
</div> <!-- tools_left --> </div> <!-- tools_left -->
<div id="tools_bottom" class="tools_panel"> <div id="tools_bottom" class="tools_panel">
@ -186,13 +186,13 @@
<tr> <tr>
<td>fill:</td> <td>fill:</td>
<td><div id="fill_color" class="color_block" title="Change fill color"></div></td> <td><div id="fill_color" class="color_block" title="Change fill color"></div></td>
<td><div id="fill_opacity">N/A</div></td> <td><div id="fill_opacity">100%</div></td>
</tr><tr> </tr><tr>
<td>stroke:</td> <td>stroke:</td>
<td><div id="stroke_color" class="color_block" title="Change stroke color"></div></td> <td><div id="stroke_color" class="color_block" title="Change stroke color"></div></td>
<td><div id="stroke_opacity">100 %</div></td> <td><div id="stroke_opacity">100 %</div></td>
<td> <td>
<input id="stroke_width" title="Change stroke width" alt="Stroke Width" size="2" value="1" type="text"/> <input id="stroke_width" title="Change stroke width" alt="Stroke Width" size="2" value="5" type="text"/>
</td> </td>
<td> <td>
<select id="stroke_style" title="Change stroke dash style"> <select id="stroke_style" title="Change stroke dash style">

View File

@ -23,7 +23,7 @@ function svg_edit_setup() {
var multiselected = false; var multiselected = false;
var editingsource = false; var editingsource = false;
var fillPaint = new $.jGraduate.Paint(); // a 'none' paint var fillPaint = new $.jGraduate.Paint({solidColor: "FF0000"}); // solid red
var strokePaint = new $.jGraduate.Paint({solidColor: "000000"}); // solid black var strokePaint = new $.jGraduate.Paint({solidColor: "000000"}); // solid black
// called when we've selected a different element // called when we've selected a different element
@ -691,7 +691,7 @@ function svg_edit_setup() {
// set up gradients to be used for the buttons // set up gradients to be used for the buttons
var svgdocbox = new DOMParser().parseFromString( var svgdocbox = new DOMParser().parseFromString(
'<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="none"/>\ '<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="#FF0000"/>\
<linearGradient id="gradbox_">\ <linearGradient id="gradbox_">\
<stop stop-color="#000" offset="0.0"/>\ <stop stop-color="#000" offset="0.0"/>\
<stop stop-color="#FF0000" offset="1.0"/>\ <stop stop-color="#FF0000" offset="1.0"/>\
@ -702,7 +702,7 @@ function svg_edit_setup() {
$('#fill_color').append( document.importNode(svgdocbox.documentElement,true) ); $('#fill_color').append( document.importNode(svgdocbox.documentElement,true) );
boxgrad.id = 'gradbox_stroke'; boxgrad.id = 'gradbox_stroke';
$(svgdocbox.documentElement.firstChild).attr('fill', '#000'); $(svgdocbox.documentElement.firstChild).attr('fill', '#000000');
$('#stroke_color').append( document.importNode(svgdocbox.documentElement,true) ); $('#stroke_color').append( document.importNode(svgdocbox.documentElement,true) );
$('#fill_color').click(function(){ $('#fill_color').click(function(){

View File

@ -314,10 +314,6 @@ function SvgCanvas(c)
if (elem == null) return null; if (elem == null) return null;
var N = this.selectors.length; var N = this.selectors.length;
if (this.selectorParentGroup == null) {
initGroup();
}
// if we've already acquired one for this element, return it // if we've already acquired one for this element, return it
if (typeof(this.selectorMap[elem.id]) == "object") { if (typeof(this.selectorMap[elem.id]) == "object") {
this.selectorMap[elem.id].locked = true; this.selectorMap[elem.id].locked = true;
@ -364,17 +360,10 @@ function SvgCanvas(c)
// this keeps the selector groups as the last child in the document // this keeps the selector groups as the last child in the document
this.update = function() { this.update = function() {
if (this.selectorParentGroup == null) {
initGroup();
}
this.selectorParentGroup = svgroot.appendChild(this.selectorParentGroup); this.selectorParentGroup = svgroot.appendChild(this.selectorParentGroup);
} };
this.getRubberBandBox = function() { this.getRubberBandBox = function() {
if (this.selectorParentGroup == null) {
initGroup();
}
if (this.rubberBandBox == null) { if (this.rubberBandBox == null) {
this.rubberBandBox = this.selectorParentGroup.appendChild( this.rubberBandBox = this.selectorParentGroup.appendChild(
addSvgElementFromJson({ "element": "rect", addSvgElementFromJson({ "element": "rect",
@ -390,10 +379,63 @@ function SvgCanvas(c)
})); }));
} }
return this.rubberBandBox; return this.rubberBandBox;
} };
initGroup();
} }
// ************************************************************************************** // **************************************************************************************
var addSvgElementFromJson = function(data) {
return canvas.updateElementFromJson(data)
};
var assignAttributes = function(node, attrs) {
var handle = svgroot.suspendRedraw(60);
for (i in attrs) {
node.setAttributeNS(null, i, attrs[i]);
}
svgroot.unsuspendRedraw(handle);
};
// remove unneeded attributes
// makes resulting SVG smaller
var cleanupElement = function(element) {
var handle = svgroot.suspendRedraw(60);
if (element.getAttribute('fill-opacity') == '1')
element.removeAttribute('fill-opacity');
if (element.getAttribute('opacity') == '1')
element.removeAttribute('opacity');
if (element.getAttribute('stroke') == 'none')
element.removeAttribute('stroke');
if (element.getAttribute('stroke-dasharray') == 'none')
element.removeAttribute('stroke-dasharray');
if (element.getAttribute('stroke-opacity') == '1')
element.removeAttribute('stroke-opacity');
if (element.getAttribute('stroke-width') == '1')
element.removeAttribute('stroke-width');
if (element.getAttribute('rx') == '0')
element.removeAttribute('rx')
if (element.getAttribute('ry') == '0')
element.removeAttribute('ry')
svgroot.unsuspendRedraw(handle);
};
this.updateElementFromJson = function(data) {
var shape = svgdoc.getElementById(data.attr.id);
// if shape is a path but we need to create a rect/ellipse, then remove the path
if (shape && data.element != shape.tagName) {
svgroot.removeChild(shape);
shape = null;
}
if (!shape) {
shape = svgdoc.createElementNS(svgns, data.element);
svgroot.appendChild(shape);
}
assignAttributes(shape, data.attr);
cleanupElement(shape);
return shape;
};
var canvas = this; var canvas = this;
var container = c; var container = c;
var svgns = "http://www.w3.org/2000/svg"; var svgns = "http://www.w3.org/2000/svg";
@ -414,11 +456,11 @@ function SvgCanvas(c)
var start_y = null; var start_y = null;
var current_mode = "select"; var current_mode = "select";
var current_resize_mode = "none"; var current_resize_mode = "none";
var current_fill = "none"; var current_fill = "#FF0000";
var current_stroke = "#000000"; var current_stroke = "#000000";
var current_stroke_paint = null; var current_stroke_paint = null;
var current_fill_paint = null; var current_fill_paint = null;
var current_stroke_width = 1; var current_stroke_width = 5;
var current_stroke_style = "none"; var current_stroke_style = "none";
var current_opacity = 1; var current_opacity = 1;
var current_stroke_opacity = 1; var current_stroke_opacity = 1;
@ -429,6 +471,7 @@ function SvgCanvas(c)
var freehand_max_x = null; var freehand_max_x = null;
var freehand_min_y = null; var freehand_min_y = null;
var freehand_max_y = null; var freehand_max_y = null;
var current_poly_pts = [];
// this will hold all the currently selected elements // this will hold all the currently selected elements
// default size of 1 until it needs to grow bigger // default size of 1 until it needs to grow bigger
var selectedElements = new Array(1); var selectedElements = new Array(1);
@ -440,8 +483,6 @@ function SvgCanvas(c)
var events = {}; var events = {};
var undoStackPointer = 0; var undoStackPointer = 0;
var undoStack = []; var undoStack = [];
// this holds all the currently copied elements
var copiedElements = new Array(1);
// This method sends back an array or a NodeList full of elements that // This method sends back an array or a NodeList full of elements that
// intersect the multi-select rubber-band-box. // intersect the multi-select rubber-band-box.
@ -524,41 +565,6 @@ function SvgCanvas(c)
} }
}; };
var assignAttributes = function(node, attrs) {
var handle = svgroot.suspendRedraw(60);
for (i in attrs) {
node.setAttributeNS(null, i, attrs[i]);
}
svgroot.unsuspendRedraw(handle);
};
// remove unneeded attributes
// makes resulting SVG smaller
var cleanupElement = function(element) {
var handle = svgroot.suspendRedraw(60);
if (element.getAttribute('fill-opacity') == '1')
element.removeAttribute('fill-opacity');
if (element.getAttribute('opacity') == '1')
element.removeAttribute('opacity');
if (element.getAttribute('stroke') == 'none')
element.removeAttribute('stroke');
if (element.getAttribute('stroke-dasharray') == 'none')
element.removeAttribute('stroke-dasharray');
if (element.getAttribute('stroke-opacity') == '1')
element.removeAttribute('stroke-opacity');
if (element.getAttribute('stroke-width') == '1')
element.removeAttribute('stroke-width');
if (element.getAttribute('rx') == '0')
element.removeAttribute('rx')
if (element.getAttribute('ry') == '0')
element.removeAttribute('ry')
svgroot.unsuspendRedraw(handle);
};
var addSvgElementFromJson = function(data) {
return canvas.updateElementFromJson(data)
};
// this function sanitizes the input node and its children // this function sanitizes the input node and its children
// this function only keeps what is allowed from our whitelist defined above // this function only keeps what is allowed from our whitelist defined above
var sanitizeSvg = function(node) { var sanitizeSvg = function(node) {
@ -728,6 +734,11 @@ function SvgCanvas(c)
for (var i = 1; i < len; ++i) { for (var i = 1; i < len; ++i) {
var l = segList.getItem(i); var l = segList.getItem(i);
var x = l.x, y = l.y; var x = l.x, y = l.y;
// polys can now be closed, skip Z segments
if (l.pathSegType == 1) {
newd += "z";
continue;
}
// webkit browsers normalize things and this becomes an absolute // webkit browsers normalize things and this becomes an absolute
// line segment! we need to turn this back into a rel line segment // line segment! we need to turn this back into a rel line segment
// see https://bugs.webkit.org/show_bug.cgi?id=26487 // see https://bugs.webkit.org/show_bug.cgi?id=26487
@ -1049,6 +1060,12 @@ function SvgCanvas(c)
}); });
newText.textContent = "text"; newText.textContent = "text";
break; break;
case "poly":
started = true;
break;
default:
console.log("Unknown mode in mousedown: " + current_mode);
break;
} }
}; };
@ -1225,6 +1242,16 @@ function SvgCanvas(c)
d_attr += "l" + dx + "," + dy + " "; d_attr += "l" + dx + "," + dy + " ";
shape.setAttributeNS(null, "d", d_attr); shape.setAttributeNS(null, "d", d_attr);
break; break;
// TODO: update poly stretch line coordinates
case "poly":
var line = document.getElementById("poly_stretch_line");
if (line) {
line.setAttribute("x2", x);
line.setAttribute("y2", y);
}
break;
default:
break;
} }
// TODO: should we fire the change event here? I'm thinking only fire // TODO: should we fire the change event here? I'm thinking only fire
// this event when the user mouses up. That's when the action (create, // this event when the user mouses up. That's when the action (create,
@ -1356,8 +1383,110 @@ function SvgCanvas(c)
canvas.clearSelection(); canvas.clearSelection();
canvas.addToSelection([element]); canvas.addToSelection([element]);
break; break;
case "poly":
var x = evt.pageX - container.parentNode.offsetLeft + container.parentNode.scrollLeft;
var y = evt.pageY - container.parentNode.offsetTop + container.parentNode.scrollTop;
// 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 stretchy = document.getElementById("poly_stretch_line");
if (!stretchy) {
stretchy = document.createElementNS(svgns, "line");
stretchy.id = "poly_stretch_line";
stretchy.setAttribute("stroke-width", "0.5");
stretchy.setAttribute("stroke", "blue");
stretchy = document.getElementById("selectorParentGroup").appendChild(stretchy);
}
stretchy.setAttribute("display", "inline");
// if pts array is empty, create path element with M at current point
if (current_poly_pts.length == 0) {
current_poly_pts.push(x);
current_poly_pts.push(y);
d_attr = "M" + x + "," + y + " ";
addSvgElementFromJson({
"element": "path",
"attr": {
"d": d_attr,
"id": getNextId(),
"fill": current_fill,
"fill-opacity": current_fill_opacity,
"stroke": current_stroke,
"stroke-width": current_stroke_width,
"stroke-dasharray": current_stroke_style,
"stroke-opacity": current_stroke_opacity,
"opacity": current_opacity / 2
}
});
// set stretchy line to first point
stretchy.setAttribute("x1", x);
stretchy.setAttribute("y1", y);
stretchy.setAttribute("x2", x);
stretchy.setAttribute("y2", y);
}
else {
// determine if we clicked on an existing point
var i = current_poly_pts.length;
var FUZZ = 6;
var clickOnPoint = false;
while(i) {
i -= 2;
var px = current_poly_pts[i], py = current_poly_pts[i+1];
// found a matching point
if ( x >= (px-FUZZ) && x <= (px+FUZZ) && y >= (py-FUZZ) && y <= (py+FUZZ) ) {
clickOnPoint = true;
break;
}
}
// get poly element that we are in the process of creating
var poly = svgdoc.getElementById(getId());
// if we clicked on an existing point, then we are done this poly, commit it
// (i,i+1) are the x,y that were clicked on
if (clickOnPoint) {
// if clicked on any other point but the first OR
// the first point was clicked on and there are less than 3 points
// then leave the poly open
// otherwise, close the poly
if (i == 0 && current_poly_pts.length >= 6) {
poly.setAttribute("d", d_attr + "z");
}
// this will signal to commit the poly
element = poly;
current_poly_pts = [];
started = false;
document.getElementById("poly_stretch_line").setAttribute("display", "none");
}
// else, create a new point, append to pts array, update path element
else {
var len = current_poly_pts.length;
var lastx = current_poly_pts[len-2], lasty = current_poly_pts[len-1];
// we store absolute values in our poly points array for easy checking above
current_poly_pts.push(x);
current_poly_pts.push(y);
// but we store relative coordinates in the d string of the poly for easy
// translation around the canvas in move mode
d_attr += "l" + (x-lastx) + "," + (y-lasty) + " ";
poly.setAttribute("d", d_attr);
// set stretchy line to latest point
stretchy.setAttribute("x1", x);
stretchy.setAttribute("y1", y);
stretchy.setAttribute("x2", x);
stretchy.setAttribute("y2", y);
}
keep = true;
}
break;
default:
console.log("Unknown mode in mouseup: " + current_mode);
break;
} }
d_attr = null;
if (!keep && element != null) { if (!keep && element != null) {
element.parentNode.removeChild(element); element.parentNode.removeChild(element);
element = null; element = null;
@ -1455,6 +1584,11 @@ function SvgCanvas(c)
}; };
this.setMode = function(name) { this.setMode = function(name) {
// toss out half-drawn poly
if (current_mode == "poly" && current_poly_pts.length > 0) {
element.parentNode.removeChild(svgdoc.getElementById(getId()));
current_poly_pts = [];
}
current_mode = name; current_mode = name;
}; };
@ -1650,22 +1784,6 @@ function SvgCanvas(c)
this.changeSelectedAttribute("stroke-opacity", val); this.changeSelectedAttribute("stroke-opacity", val);
}; };
this.updateElementFromJson = function(data) {
var shape = svgdoc.getElementById(data.attr.id);
// if shape is a path but we need to create a rect/ellipse, then remove the path
if (shape && data.element != shape.tagName) {
svgroot.removeChild(shape);
shape = null;
}
if (!shape) {
shape = svgdoc.createElementNS(svgns, data.element);
svgroot.appendChild(shape);
}
assignAttributes(shape, data.attr);
cleanupElement(shape);
return shape;
};
this.each = function(cb) { this.each = function(cb) {
$(svgroot).children().each(cb); $(svgroot).children().each(cb);
}; };
@ -1907,7 +2025,7 @@ function SvgCanvas(c)
// this creates deep DOM copies (clones) of all selected elements // this creates deep DOM copies (clones) of all selected elements
this.cloneSelectedElements = function() { this.cloneSelectedElements = function() {
var batchCmd = new BatchCommand("Clone Elements"); var batchCmd = new BatchCommand("Clone Elements");
copiedElements = []; var copiedElements = [];
var len = selectedElements.length; var len = selectedElements.length;
for (var i = 0; i < len; ++i) { for (var i = 0; i < len; ++i) {
if (selectedElements[i] == null) break; if (selectedElements[i] == null) break;