align elements (work in progress)
git-svn-id: http://svg-edit.googlecode.com/svn/trunk@397 eee81c28-f429-11dd-99c0-75d572ba1dddmaster
Before Width: | Height: | Size: 291 B After Width: | Height: | Size: 291 B |
Before Width: | Height: | Size: 449 B After Width: | Height: | Size: 449 B |
Before Width: | Height: | Size: 305 B After Width: | Height: | Size: 305 B |
Before Width: | Height: | Size: 459 B After Width: | Height: | Size: 459 B |
Before Width: | Height: | Size: 339 B After Width: | Height: | Size: 339 B |
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 287 B |
After Width: | Height: | Size: 715 B |
|
@ -53,13 +53,15 @@
|
|||
<img class="tool_button tool_button_disabled" id="tool_redo" src="images/redo.png" title="Redo [Y]" alt="Redo"/>
|
||||
</div>
|
||||
|
||||
<!-- Buttons when something a single element is selected -->
|
||||
<!-- Buttons when a single element is selected -->
|
||||
<div id="selected_panel">
|
||||
<img class="tool_sep" src="images/sep.png" alt="|"/>
|
||||
<img class="tool_button" id="tool_clone" src="images/copy.png" title="Clone Element [C]" alt="Copy"/>
|
||||
<img class="tool_button" id="tool_clone" src="images/clone.png" title="Clone Element [C]" alt="Copy"/>
|
||||
<img class="tool_button" id="tool_delete" src="images/delete.png" title="Delete Element [Delete/Backspace]" alt="Delete"/>
|
||||
<img class="tool_sep" src="images/sep.png" alt="|"/>
|
||||
<img class="tool_button" id="tool_move_top" src="images/move_top.png" title="Move to Top [Shift+Up]" alt="Top"/>
|
||||
<img class="tool_button" id="tool_move_bottom" src="images/move_bottom.png" title="Move to Bottom [Shift+Down]" alt="Bottom"/>
|
||||
<img class="tool_sep" src="images/sep.png" alt="|"/>
|
||||
<select id="group_opacity" class="selected_tool" title="Change selected item opacity">
|
||||
<option selected="selected" value="1">100 %</option>
|
||||
<option value="0.9">90 %</option>
|
||||
|
@ -76,11 +78,19 @@
|
|||
<input id="angle" class="selected_tool" title="Change rotation angle" alt="Rotation Angle" size="2" value="0" type="text"/>
|
||||
</div>
|
||||
|
||||
<!-- Buttons when something a single element is selected -->
|
||||
<!-- Buttons when multiple elements are selected -->
|
||||
<div id="multiselected_panel">
|
||||
<img class="tool_sep" src="images/sep.png" alt="|"/>
|
||||
<img class="tool_button" id="tool_clone_multi" src="images/copy.png" title="Clone Elements [C]" alt="Clone"/>
|
||||
<img class="tool_button" id="tool_clone_multi" src="images/clone.png" title="Clone Elements [C]" alt="Clone"/>
|
||||
<img class="tool_button" id="tool_delete_multi" src="images/delete.png" title="Delete Selected Elements [Delete/Backspace]" alt="Delete"/>
|
||||
<img class="tool_sep" src="images/sep.png" alt="|"/>
|
||||
<img class="tool_button" id="tool_alignleft" src="images/align-left.png" title="Align Left" alt="Left"/>
|
||||
<img class="tool_button" id="tool_aligncenter" src="images/align-center.png" title="Align Center" alt="Center"/>
|
||||
<img class="tool_button" id="tool_alignright" src="images/align-right.png" title="Align Right" alt="Right"/>
|
||||
<img class="tool_sep" src="images/sep.png" alt="|"/>
|
||||
<img class="tool_button" id="tool_aligntop" src="images/align-top.png" title="Align Top" alt="Top"/>
|
||||
<img class="tool_button" id="tool_alignmiddle" src="images/align-middle.png" title="Align Middle" alt="Middle"/>
|
||||
<img class="tool_button" id="tool_alignbottom" src="images/align-bottom.png" title="Align Bottom" alt="Bottom"/>
|
||||
</div>
|
||||
|
||||
<div id="rect_panel">
|
||||
|
|
|
@ -475,6 +475,25 @@ function svg_edit_setup() {
|
|||
svgCanvas.cloneSelectedElements();
|
||||
};
|
||||
|
||||
var clickAlignLeft = function(){
|
||||
svgCanvas.alignSelectedElements('l');
|
||||
};
|
||||
var clickAlignCenter = function(){
|
||||
svgCanvas.alignSelectedElements('c');
|
||||
};
|
||||
var clickAlignRight = function(){
|
||||
svgCanvas.alignSelectedElements('r');
|
||||
};
|
||||
var clickAlignTop = function(){
|
||||
svgCanvas.alignSelectedElements('t');
|
||||
};
|
||||
var clickAlignMiddle = function(){
|
||||
svgCanvas.alignSelectedElements('m');
|
||||
};
|
||||
var clickAlignBottom = function(){
|
||||
svgCanvas.alignSelectedElements('b');
|
||||
};
|
||||
|
||||
var showSourceEditor = function(){
|
||||
if (editingsource) return;
|
||||
editingsource = true;
|
||||
|
@ -533,6 +552,12 @@ function svg_edit_setup() {
|
|||
$('#tool_redo').click(clickRedo);
|
||||
$('#tool_clone').click(clickClone);
|
||||
$('#tool_clone_multi').click(clickClone);
|
||||
$('#tool_alignleft').click(clickAlignLeft);
|
||||
$('#tool_aligncenter').click(clickAlignCenter);
|
||||
$('#tool_alignright').click(clickAlignRight);
|
||||
$('#tool_aligntop').click(clickAlignTop);
|
||||
$('#tool_alignmiddle').click(clickAlignMiddle);
|
||||
$('#tool_alignbottom').click(clickAlignBottom);
|
||||
// these two lines are required to make Opera work properly with the flyout mechanism
|
||||
$('#tools_rect_show').click(clickSquare);
|
||||
$('#tools_ellipse_show').click(clickCircle);
|
||||
|
@ -565,12 +590,12 @@ function svg_edit_setup() {
|
|||
$('#tool_paste').mousedown(function(){$('#tool_paste').addClass('tool_button_current');});
|
||||
$('#tool_paste').mouseup(function(){$('#tool_paste').removeClass('tool_button_current');});
|
||||
$('#tool_paste').mouseout(function(){$('#tool_paste').removeClass('tool_button_current');});
|
||||
$('#tool_copy').mousedown(function(){$('#tool_copy').addClass('tool_button_current');});
|
||||
$('#tool_copy').mouseup(function(){$('#tool_copy').removeClass('tool_button_current');});
|
||||
$('#tool_copy').mouseout(function(){$('#tool_copy').removeClass('tool_button_current');});
|
||||
$('#tool_copy_multi').mousedown(function(){$('#tool_copy').addClass('tool_button_current');});
|
||||
$('#tool_copy_multi').mouseup(function(){$('#tool_copy').removeClass('tool_button_current');});
|
||||
$('#tool_copy_multi').mouseout(function(){$('#tool_copy').removeClass('tool_button_current');});
|
||||
$('#tool_clone').mousedown(function(){$('#tool_clone').addClass('tool_button_current');});
|
||||
$('#tool_clone').mouseup(function(){$('#tool_clone').removeClass('tool_button_current');});
|
||||
$('#tool_clone').mouseout(function(){$('#tool_clone').removeClass('tool_button_current');});
|
||||
$('#tool_clone_multi').mousedown(function(){$('#tool_clone').addClass('tool_button_current');});
|
||||
$('#tool_clone_multi').mouseup(function(){$('#tool_clone').removeClass('tool_button_current');});
|
||||
$('#tool_clone_multi').mouseout(function(){$('#tool_clone').removeClass('tool_button_current');});
|
||||
$('#tool_move_top').mousedown(function(){$('#tool_move_top').addClass('tool_button_current');});
|
||||
$('#tool_move_top').mouseup(function(){$('#tool_move_top').removeClass('tool_button_current');});
|
||||
$('#tool_move_top').mouseout(function(){$('#tool_move_top').removeClass('tool_button_current');});
|
||||
|
|
|
@ -7,7 +7,6 @@ if(!window.console) {
|
|||
|
||||
// this defines which elements and attributes that we support
|
||||
// TODO: add <g> elements to this
|
||||
// TODO: add <polygon> elements to this
|
||||
// TODO: add <a> elements to this
|
||||
// TODO: add xmlns:xlink attr to <svg> element
|
||||
var svgWhiteList = {
|
||||
|
@ -24,8 +23,7 @@ var svgWhiteList = {
|
|||
"stop": ["id", "offset", "stop-color", "stop-opacity"],
|
||||
"svg": ["id", "height", "transform", "width", "xmlns"],
|
||||
"text": ["fill", "fill-opacity", "font-family", "font-size", "font-style", "font-weight", "id", "stroke", "stroke-dasharray", "stroke-linecap", "stroke-linejoin", "stroke-opacity", "stroke-width", "transform", "x", "y"],
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// These command objects are used for the Undo/Redo stack
|
||||
// attrs contains the values that the attributes had before the change
|
||||
|
@ -2405,6 +2403,178 @@ function SvgCanvas(c)
|
|||
}
|
||||
};
|
||||
|
||||
// aligns selected elements (type is a char - see switch below for explanation)
|
||||
this.alignSelectedElements = function(type) {
|
||||
var minx = 100000, maxx = -100000, miny = 100000, maxy = -100000;
|
||||
var len = selectedElements.length;
|
||||
if (!len) return;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
if (selectedElements[i] == null) break;
|
||||
var elem = selectedElements[i];
|
||||
switch (elem.tagName) {
|
||||
case 'circle':
|
||||
if (parseInt(elem.getAttribute(('cx'))) - parseInt(elem.getAttribute(('r'))) < minx) minx = parseInt(elem.getAttribute(('cx'))) - parseInt(elem.getAttribute(('r')));
|
||||
if (parseInt(elem.getAttribute(('cx'))) + parseInt(elem.getAttribute(('r'))) > maxx) maxx = parseInt(elem.getAttribute(('cx'))) + parseInt(elem.getAttribute(('r')));
|
||||
if (parseInt(elem.getAttribute(('cy'))) - parseInt(elem.getAttribute(('r'))) < miny) miny = parseInt(elem.getAttribute(('cy'))) - parseInt(elem.getAttribute(('r')));
|
||||
if (parseInt(elem.getAttribute(('cy'))) + parseInt(elem.getAttribute(('r'))) > maxy) maxy = parseInt(elem.getAttribute(('cy'))) + parseInt(elem.getAttribute(('r')));
|
||||
break;
|
||||
case 'ellipse':
|
||||
if (parseInt(elem.getAttribute(('cx'))) - parseInt(elem.getAttribute(('rx'))) < minx) minx = parseInt(elem.getAttribute(('cx'))) - parseInt(elem.getAttribute(('rx')));
|
||||
if (parseInt(elem.getAttribute(('cx'))) + parseInt(elem.getAttribute(('rx'))) > maxx) maxx = parseInt(elem.getAttribute(('cx'))) + parseInt(elem.getAttribute(('rx')));
|
||||
if (parseInt(elem.getAttribute(('cy'))) - parseInt(elem.getAttribute(('ry'))) < miny) miny = parseInt(elem.getAttribute(('cy'))) - parseInt(elem.getAttribute(('ry')));
|
||||
if (parseInt(elem.getAttribute(('cy'))) + parseInt(elem.getAttribute(('ry'))) > maxy) maxy = parseInt(elem.getAttribute(('cy'))) + parseInt(elem.getAttribute(('ry')));
|
||||
break;
|
||||
case 'rect':
|
||||
if (parseInt(elem.getAttribute(('x'))) < minx) minx = parseInt(elem.getAttribute(('x')));
|
||||
if (parseInt(elem.getAttribute(('x'))) + parseInt(elem.getAttribute(('width'))) > maxx) maxx = parseInt(elem.getAttribute(('x'))) + parseInt(elem.getAttribute(('width')));
|
||||
if (parseInt(elem.getAttribute(('y'))) < minx) miny = parseInt(elem.getAttribute(('y')));
|
||||
if (parseInt(elem.getAttribute(('y'))) + parseInt(elem.getAttribute(('height'))) > maxx) maxy = parseInt(elem.getAttribute(('y'))) + parseInt(elem.getAttribute(('height')));
|
||||
break;
|
||||
case 'line':
|
||||
if (parseInt(elem.getAttribute(('x1'))) < minx) minx = parseInt(elem.getAttribute(('x1')));
|
||||
if (parseInt(elem.getAttribute(('x2'))) < minx) minx = parseInt(elem.getAttribute(('x2')));
|
||||
if (parseInt(elem.getAttribute(('x1'))) > maxx) maxx = parseInt(elem.getAttribute(('x1')));
|
||||
if (parseInt(elem.getAttribute(('x2'))) > maxx) maxx = parseInt(elem.getAttribute(('x2')));
|
||||
if (parseInt(elem.getAttribute(('y1'))) < miny) miny = parseInt(elem.getAttribute(('y1')));
|
||||
if (parseInt(elem.getAttribute(('y2'))) < miny) miny = parseInt(elem.getAttribute(('y2')));
|
||||
if (parseInt(elem.getAttribute(('y1'))) > maxy) maxy = parseInt(elem.getAttribute(('y1')));
|
||||
if (parseInt(elem.getAttribute(('y2'))) > maxy) maxy = parseInt(elem.getAttribute(('y2')));
|
||||
break;
|
||||
case 'path':
|
||||
// TODO: implement
|
||||
break;
|
||||
case 'polygon':
|
||||
// TODO: implement
|
||||
break;
|
||||
case 'polyline':
|
||||
// TODO: implement
|
||||
break;
|
||||
case 'text':
|
||||
// TODO: how to handle text?
|
||||
break;
|
||||
}
|
||||
}
|
||||
var len = selectedElements.length;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
if (selectedElements[i] == null) break;
|
||||
var elem = selectedElements[i];
|
||||
switch (elem.tagName) {
|
||||
case 'circle':
|
||||
switch (type) {
|
||||
case 'l': // left (horizontal)
|
||||
elem.setAttribute('cx', minx+parseInt(elem.getAttribute(('r'))));
|
||||
break;
|
||||
case 'c': // center (horizontal)
|
||||
elem.setAttribute('cx', (minx+maxx)/2);
|
||||
break;
|
||||
case 'r': // right (horizontal)
|
||||
elem.setAttribute('cx', maxx-parseInt(elem.getAttribute(('r'))));
|
||||
break;
|
||||
case 't': // top (vertical)
|
||||
elem.setAttribute('cy', miny+parseInt(elem.getAttribute(('r'))));
|
||||
break;
|
||||
case 'm': // middle (vertical)
|
||||
elem.setAttribute('cy', (miny+maxy)/2);
|
||||
break;
|
||||
case 'b': // bottom (vertical)
|
||||
elem.setAttribute('cy', maxy-parseInt(elem.getAttribute(('r'))));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'ellipse':
|
||||
switch (type) {
|
||||
case 'l': // left (horizontal)
|
||||
elem.setAttribute('cx', minx+parseInt(elem.getAttribute(('rx'))));
|
||||
break;
|
||||
case 'c': // center (horizontal)
|
||||
elem.setAttribute('cx', (minx+maxx)/2);
|
||||
break;
|
||||
case 'r': // right (horizontal)
|
||||
elem.setAttribute('cx', maxx-parseInt(elem.getAttribute(('rx'))));
|
||||
break;
|
||||
case 't': // top (vertical)
|
||||
elem.setAttribute('cy', miny+parseInt(elem.getAttribute(('ry'))));
|
||||
break;
|
||||
case 'm': // middle (vertical)
|
||||
elem.setAttribute('cy', (miny+maxy)/2);
|
||||
break;
|
||||
case 'b': // bottom (vertical)
|
||||
elem.setAttribute('cy', maxy-parseInt(elem.getAttribute(('ry'))));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'rect':
|
||||
switch (type) {
|
||||
case 'l': // left (horizontal)
|
||||
elem.setAttribute('x', minx);
|
||||
break;
|
||||
case 'c': // center (horizontal)
|
||||
elem.setAttribute('x', (minx+maxx-parseInt(elem.getAttribute(('width'))))/2);
|
||||
break;
|
||||
case 'r': // right (horizontal)
|
||||
elem.setAttribute('x', maxx-parseInt(elem.getAttribute(('width'))));
|
||||
break;
|
||||
case 't': // top (vertical)
|
||||
elem.setAttribute('y', miny);
|
||||
break;
|
||||
case 'm': // middle (vertical)
|
||||
elem.setAttribute('y', (miny+maxy-parseInt(elem.getAttribute(('width'))))/2);
|
||||
break;
|
||||
case 'b': // bottom (vertical)
|
||||
elem.setAttribute('y', maxx-parseInt(elem.getAttribute(('width'))));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'line':
|
||||
switch (type) {
|
||||
case 'l': // left (horizontal)
|
||||
var d = Math.min(parseInt(elem.getAttribute(('x1'))), parseInt(elem.getAttribute(('x2')))) - minx;
|
||||
elem.setAttribute('x1', parseInt(elem.getAttribute(('x1'))) - d);
|
||||
elem.setAttribute('x2', parseInt(elem.getAttribute(('x2'))) - d);
|
||||
break;
|
||||
case 'c': // center (horizontal)
|
||||
var d = Math.abs(parseInt(elem.getAttribute(('x1'))) - parseInt(elem.getAttribute(('x2'))));
|
||||
elem.setAttribute('x1', (minx+maxx-d)/2 );
|
||||
elem.setAttribute('x2', (minx+maxx+d)/2 );
|
||||
break;
|
||||
case 'r': // right (horizontal)
|
||||
var d = Math.max(parseInt(elem.getAttribute(('x1'))), parseInt(elem.getAttribute(('x2')))) - maxx;
|
||||
elem.setAttribute('x1', parseInt(elem.getAttribute(('x1'))) - d);
|
||||
elem.setAttribute('x2', parseInt(elem.getAttribute(('x2'))) - d);
|
||||
break;
|
||||
case 't': // top (vertical)
|
||||
var d = Math.min(parseInt(elem.getAttribute(('y1'))), parseInt(elem.getAttribute(('y2')))) - miny;
|
||||
elem.setAttribute('y1', parseInt(elem.getAttribute(('y1')))-d);
|
||||
elem.setAttribute('y2', parseInt(elem.getAttribute(('y2')))-d);
|
||||
break;
|
||||
case 'm': // middle (vertical)
|
||||
var d = Math.abs(parseInt(elem.getAttribute(('y1'))) - parseInt(elem.getAttribute(('y2'))));
|
||||
elem.setAttribute('y1', (miny+maxy-d)/2 );
|
||||
elem.setAttribute('y2', (miny+maxy+d)/2 );
|
||||
break;
|
||||
case 'b': // bottom (vertical)
|
||||
var d = Math.max(parseInt(elem.getAttribute(('y1'))), parseInt(elem.getAttribute(('y2')))) - maxy;
|
||||
elem.setAttribute('y1', parseInt(elem.getAttribute(('y1'))) - d);
|
||||
elem.setAttribute('y2', parseInt(elem.getAttribute(('y2'))) - d);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'path':
|
||||
// TODO: implement
|
||||
break;
|
||||
case 'polygon':
|
||||
// TODO: implement
|
||||
break;
|
||||
case 'polyline':
|
||||
// TODO: implement
|
||||
break;
|
||||
case 'text':
|
||||
// TODO: how to handle text?
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Static class for various utility functions
|
||||
|
|