Started on Issue 310: Move to Plugin Architecture, as well as Issue 200: flowchart (just connector lines for now)
git-svn-id: http://svg-edit.googlecode.com/svn/trunk@1277 eee81c28-f429-11dd-99c0-75d572ba1dddmaster
parent
6eba334074
commit
75781771be
|
@ -0,0 +1,243 @@
|
||||||
|
$(function() {
|
||||||
|
svgCanvas.addExtension("Connector", function(vars) {
|
||||||
|
|
||||||
|
var svgcontent = vars.content;
|
||||||
|
var getNextId = vars.getNextId;
|
||||||
|
var addElem = vars.addSvgElementFromJson;
|
||||||
|
var selManager = vars.selectorManager;
|
||||||
|
var started = false,
|
||||||
|
start_x,
|
||||||
|
start_y,
|
||||||
|
cur_line,
|
||||||
|
start_elem,
|
||||||
|
end_elem,
|
||||||
|
connections = [],
|
||||||
|
conn_class = "se_connect",
|
||||||
|
connect_str = "-SE_CONNECT-",
|
||||||
|
selElems;
|
||||||
|
|
||||||
|
// Init code
|
||||||
|
// (function() {
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }());
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "Connector",
|
||||||
|
svgicons: "images/conn.svg",
|
||||||
|
buttons: [{
|
||||||
|
id: "mode_connect",
|
||||||
|
type: "mode",
|
||||||
|
icon: "images/cut.png",
|
||||||
|
events: {
|
||||||
|
'click': function() {
|
||||||
|
svgCanvas.setMode("connector");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
mouseDown: function(opts) {
|
||||||
|
var e = opts.event;
|
||||||
|
|
||||||
|
start_x = opts.start_x,
|
||||||
|
start_y = opts.start_y;
|
||||||
|
var mode = svgCanvas.getMode();
|
||||||
|
|
||||||
|
if(mode == "connector") {
|
||||||
|
|
||||||
|
if(started) return;
|
||||||
|
|
||||||
|
if(e.target.parentNode.parentNode == svgcontent) {
|
||||||
|
// Connectable element
|
||||||
|
start_elem = e.target;
|
||||||
|
|
||||||
|
// Get center of source element
|
||||||
|
var bb = svgCanvas.getStrokedBBox([start_elem]);
|
||||||
|
var x = bb.x + bb.width/2;
|
||||||
|
var y = bb.y + bb.height/2;
|
||||||
|
|
||||||
|
started = true;
|
||||||
|
cur_line = addElem({
|
||||||
|
"element": "line",
|
||||||
|
"attr": {
|
||||||
|
"x1": x,
|
||||||
|
"y1": y,
|
||||||
|
"x2": start_x,
|
||||||
|
"y2": start_y,
|
||||||
|
"id": getNextId(),
|
||||||
|
"stroke": '#000',
|
||||||
|
"stroke-width": 1,
|
||||||
|
"fill": "none",
|
||||||
|
"opacity": .5,
|
||||||
|
"style": "pointer-events:none"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
started: true
|
||||||
|
};
|
||||||
|
} else if(mode == "select") {
|
||||||
|
|
||||||
|
// Check if selected elements have connections
|
||||||
|
var elems = opts.selectedElements;
|
||||||
|
var i = elems.length;
|
||||||
|
var connectors = $(svgcontent).find("." + conn_class);
|
||||||
|
if(!connectors.length) return;
|
||||||
|
|
||||||
|
connections = [];
|
||||||
|
|
||||||
|
while(i--) {
|
||||||
|
var elem = elems[i];
|
||||||
|
if(!elem) continue;
|
||||||
|
if(elem.getAttribute('class') == conn_class) continue;
|
||||||
|
var elem_id = elem.id;
|
||||||
|
connectors.each(function() {
|
||||||
|
var con_id = this.id;
|
||||||
|
if(con_id.indexOf(elem_id) != -1) {
|
||||||
|
var is_start = true;
|
||||||
|
if(con_id.indexOf(connect_str + elem_id) != -1) {
|
||||||
|
// Found connector (selected is end elem)
|
||||||
|
is_start = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bb = svgCanvas.getStrokedBBox([elem]);
|
||||||
|
var x = bb.x + bb.width/2;
|
||||||
|
var y = bb.y + bb.height/2;
|
||||||
|
|
||||||
|
connections.push({
|
||||||
|
elem: elem,
|
||||||
|
connector: this,
|
||||||
|
is_start: is_start,
|
||||||
|
start_x: x,
|
||||||
|
start_y: y
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mouseMove: function(opts) {
|
||||||
|
var zoom = svgCanvas.getZoom();
|
||||||
|
var e = opts.event;
|
||||||
|
var x = opts.mouse_x/zoom;
|
||||||
|
var y = opts.mouse_y/zoom;
|
||||||
|
|
||||||
|
var diff_x = x - start_x,
|
||||||
|
diff_y = y - start_y;
|
||||||
|
|
||||||
|
var mode = svgCanvas.getMode();
|
||||||
|
|
||||||
|
if(mode == "connector" && started) {
|
||||||
|
cur_line.setAttributeNS(null, "x2", x);
|
||||||
|
cur_line.setAttributeNS(null, "y2", y);
|
||||||
|
} else if(mode == "select") {
|
||||||
|
var slen = selElems.length;
|
||||||
|
|
||||||
|
while(slen--) {
|
||||||
|
var elem = selElems[slen];
|
||||||
|
// Look for selected connector elements
|
||||||
|
if(elem && elem.getAttribute('class') == conn_class) {
|
||||||
|
// Remove the "translate" transform given to move
|
||||||
|
svgCanvas.getTransformList(elem).clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(connections.length) {
|
||||||
|
// Update line with element
|
||||||
|
var i = connections.length;
|
||||||
|
|
||||||
|
while(i--) {
|
||||||
|
var conn = connections[i];
|
||||||
|
var line = conn.connector;
|
||||||
|
var elem = conn.elem;
|
||||||
|
var n = conn.is_start ? 1 : 2;
|
||||||
|
line.setAttributeNS(null, "x"+n, conn.start_x + diff_x);
|
||||||
|
line.setAttributeNS(null, "y"+n, conn.start_y + diff_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mouseUp: function(opts) {
|
||||||
|
var zoom = svgCanvas.getZoom();
|
||||||
|
var e = opts.event,
|
||||||
|
x = opts.mouse_x/zoom,
|
||||||
|
y = opts.mouse_y/zoom;
|
||||||
|
|
||||||
|
if(svgCanvas.getMode() == "connector") {
|
||||||
|
if(e.target.parentNode.parentNode != svgcontent) {
|
||||||
|
// Not a valid target element, so remove line
|
||||||
|
$(cur_line).remove();
|
||||||
|
started = false;
|
||||||
|
return {
|
||||||
|
keep: false,
|
||||||
|
element: null,
|
||||||
|
started: started
|
||||||
|
}
|
||||||
|
} else if(e.target == start_elem) {
|
||||||
|
// Start line through click
|
||||||
|
started = true;
|
||||||
|
return {
|
||||||
|
keep: true,
|
||||||
|
element: null,
|
||||||
|
started: started
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Valid end element
|
||||||
|
end_elem = e.target;
|
||||||
|
var line_id = start_elem.id + connect_str + end_elem.id;
|
||||||
|
var alt_line_id = end_elem.id + connect_str + start_elem.id;
|
||||||
|
|
||||||
|
// Don't create connector if one already exists
|
||||||
|
if($('#'+line_id + ', #' + alt_line_id).length) {
|
||||||
|
$(cur_line).remove();
|
||||||
|
return {
|
||||||
|
keep: false,
|
||||||
|
element: null,
|
||||||
|
started: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var bb = svgCanvas.getStrokedBBox([end_elem]);
|
||||||
|
var x = bb.x + bb.width/2;
|
||||||
|
var y = bb.y + bb.height/2;
|
||||||
|
cur_line.setAttributeNS(null, "x2", x);
|
||||||
|
cur_line.setAttributeNS(null, "y2", y);
|
||||||
|
cur_line.id = line_id;
|
||||||
|
console.log('cur_line',cur_line.id);
|
||||||
|
cur_line.setAttribute("class", conn_class);
|
||||||
|
svgCanvas.addToSelection([cur_line]);
|
||||||
|
svgCanvas.moveToBottomSelectedElement();
|
||||||
|
|
||||||
|
started = false;
|
||||||
|
return {
|
||||||
|
keep: true,
|
||||||
|
element: cur_line,
|
||||||
|
started: started
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
selectedChanged: function(opts) {
|
||||||
|
|
||||||
|
// Use this to update the current selected elements
|
||||||
|
selElems = opts.elems;
|
||||||
|
|
||||||
|
var i = selElems.length;
|
||||||
|
|
||||||
|
// var to_hide = $('#tool_clone, #tool_topath, div.toolset:has(#angle), #line_panel');
|
||||||
|
|
||||||
|
while(i--) {
|
||||||
|
var elem = selElems[i];
|
||||||
|
if(elem && elem.getAttribute('class') == conn_class) {
|
||||||
|
selManager.requestSelector(elem).showGrips(false);
|
||||||
|
|
||||||
|
if(opts.selectedElement && !opts.multiselected) {
|
||||||
|
// TODO: Set up context tools and hide most regular line tools
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g id="mode_connect">
|
||||||
|
<svg viewBox="0 0 131 156" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<line stroke-dasharray="5,5" transform="rotate(-83.0765, 60.5, 79.0001)" fill="none" stroke-width="5" stroke="#000000" id="svg_1" y2="121.004358" x2="14.899046" y1="36.995687" x1="106.101014"/>
|
||||||
|
<circle stroke-width="5" stroke="#000000" fill="#800000" id="svg_3" r="25" cy="27.5" cx="27.5"/>
|
||||||
|
<rect stroke-width="5" stroke="#000000" fill="#008000" id="svg_6" height="39" width="74" y="114.5" x="54.5"/>
|
||||||
|
</svg>
|
||||||
|
</g>
|
||||||
|
<g id="svg_eof"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 625 B |
|
@ -18,6 +18,7 @@
|
||||||
<script type="text/javascript" src="locale/locale.js"></script>
|
<script type="text/javascript" src="locale/locale.js"></script>
|
||||||
<script type="text/javascript" src="svgcanvas.js"></script>
|
<script type="text/javascript" src="svgcanvas.js"></script>
|
||||||
<script type="text/javascript" src="svg-editor.js"></script>
|
<script type="text/javascript" src="svg-editor.js"></script>
|
||||||
|
<!-- <script type="text/javascript" src="ext-connector.js"></script> -->
|
||||||
|
|
||||||
<!-- Release version of script tags: >
|
<!-- Release version of script tags: >
|
||||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
|
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
|
||||||
|
|
|
@ -202,9 +202,12 @@ function svg_edit_setup() {
|
||||||
|
|
||||||
// Deal with pathedit mode
|
// Deal with pathedit mode
|
||||||
togglePathEditMode(is_node, elems);
|
togglePathEditMode(is_node, elems);
|
||||||
|
|
||||||
|
|
||||||
updateContextPanel();
|
updateContextPanel();
|
||||||
|
svgCanvas.runExtensions("selectedChanged", {
|
||||||
|
elems: elems,
|
||||||
|
selectedElement: selectedElement,
|
||||||
|
multiselected: multiselected
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// called when any element has changed
|
// called when any element has changed
|
||||||
|
@ -259,6 +262,83 @@ function svg_edit_setup() {
|
||||||
zoomDone();
|
zoomDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var extAdded = function(window, ext) {
|
||||||
|
if("buttons" in ext) {
|
||||||
|
var fallback_obj = {},
|
||||||
|
placement_obj = {},
|
||||||
|
svgicons = ext.svgicons;
|
||||||
|
|
||||||
|
// Add buttons given by extension
|
||||||
|
$.each(ext.buttons, function(i, btn) {
|
||||||
|
var icon;
|
||||||
|
var id = btn.id;
|
||||||
|
var num = i;
|
||||||
|
|
||||||
|
// Give button a unique ID
|
||||||
|
while($('#'+id).length) {
|
||||||
|
id = btn.id + '_' + (++num);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!svgicons) {
|
||||||
|
icon = $('<img src="' + btn.icon + '">');
|
||||||
|
} else {
|
||||||
|
fallback_obj[id] = btn.iocn;
|
||||||
|
placement_obj['#' + id] = btn.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cls, parent;
|
||||||
|
|
||||||
|
// Set button up according to its type
|
||||||
|
switch ( btn.type ) {
|
||||||
|
case 'mode':
|
||||||
|
cls = 'tool_button';
|
||||||
|
parent = "#tools_left";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var button = $('<div/>')
|
||||||
|
.attr("id", id)
|
||||||
|
.addClass(cls)
|
||||||
|
.appendTo(parent);
|
||||||
|
if(!svgicons) {
|
||||||
|
button.append(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add given events to button
|
||||||
|
$.each(btn.events, function(name, func) {
|
||||||
|
button.bind(name, function() {
|
||||||
|
if(name == "click" && btn.type == 'mode') {
|
||||||
|
if (toolButtonClick('#' + id)) {
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
$.svgIcons(svgicons, {
|
||||||
|
w:24, h:24,
|
||||||
|
id_match: false,
|
||||||
|
no_img: true,
|
||||||
|
fallback: fallback_obj,
|
||||||
|
placement: placement_obj,
|
||||||
|
callback: function() {
|
||||||
|
// Bad hack to make the icon match the current size
|
||||||
|
// TODO: Write better hack!
|
||||||
|
var old = curPrefs.iconsize;
|
||||||
|
if(curPrefs.iconsize != 'm') {
|
||||||
|
setIconSize('m');
|
||||||
|
setIconSize(old);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// updates the toolbar (colors, opacity, etc) based on the selected element
|
// updates the toolbar (colors, opacity, etc) based on the selected element
|
||||||
var updateToolbar = function() {
|
var updateToolbar = function() {
|
||||||
if (selectedElement != null &&
|
if (selectedElement != null &&
|
||||||
|
@ -507,6 +587,7 @@ function svg_edit_setup() {
|
||||||
svgCanvas.bind("changed", elementChanged);
|
svgCanvas.bind("changed", elementChanged);
|
||||||
svgCanvas.bind("saved", saveHandler);
|
svgCanvas.bind("saved", saveHandler);
|
||||||
svgCanvas.bind("zoomed", zoomChanged);
|
svgCanvas.bind("zoomed", zoomChanged);
|
||||||
|
svgCanvas.bind("extension_added", extAdded);
|
||||||
|
|
||||||
var str = '<div class="palette_item" data-rgb="none"></div>'
|
var str = '<div class="palette_item" data-rgb="none"></div>'
|
||||||
$.each(palette, function(i,item){
|
$.each(palette, function(i,item){
|
||||||
|
|
|
@ -959,7 +959,34 @@ function BatchCommand(text) {
|
||||||
events = {},
|
events = {},
|
||||||
undoStackPointer = 0,
|
undoStackPointer = 0,
|
||||||
undoStack = [],
|
undoStack = [],
|
||||||
curBBoxes = [];
|
curBBoxes = [],
|
||||||
|
extensions = {};
|
||||||
|
|
||||||
|
var runExtensions = this.runExtensions = function(action, vars) {
|
||||||
|
var result = false;
|
||||||
|
$.each(extensions, function(name, opts) {
|
||||||
|
if(action in opts) {
|
||||||
|
result = opts[action](vars);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.addExtension = function(name, ext_func) {
|
||||||
|
if(!(name in extensions)) {
|
||||||
|
// Provide constants here (or should these be accessed through getSomething()?
|
||||||
|
var ext = ext_func({
|
||||||
|
content: svgcontent,
|
||||||
|
getNextId: getNextId,
|
||||||
|
addSvgElementFromJson: addSvgElementFromJson,
|
||||||
|
selectorManager: selectorManager
|
||||||
|
});
|
||||||
|
extensions[name] = ext;
|
||||||
|
call("extension_added", ext);
|
||||||
|
} else {
|
||||||
|
console.log('Cannot add extension "' + name + '", an extension by that name already exists"');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// This method rounds the incoming value to the nearest value based on the current_zoom
|
// This method rounds the incoming value to the nearest value based on the current_zoom
|
||||||
var round = function(val){
|
var round = function(val){
|
||||||
|
@ -2131,7 +2158,6 @@ function BatchCommand(text) {
|
||||||
|
|
||||||
// Make sure first elements are not null
|
// Make sure first elements are not null
|
||||||
while(selectedElements[0] == null) selectedElements.shift(0);
|
while(selectedElements[0] == null) selectedElements.shift(0);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: could use slice here to make this faster?
|
// TODO: could use slice here to make this faster?
|
||||||
|
@ -2659,6 +2685,17 @@ function BatchCommand(text) {
|
||||||
console.log("Unknown mode in mousedown: " + current_mode);
|
console.log("Unknown mode in mousedown: " + current_mode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ext_result = runExtensions("mouseDown", {
|
||||||
|
event: evt,
|
||||||
|
start_x: start_x,
|
||||||
|
start_y: start_y,
|
||||||
|
selectedElements: selectedElements
|
||||||
|
});
|
||||||
|
|
||||||
|
if(ext_result) {
|
||||||
|
started = ext_result.started;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// in this function we do not record any state changes yet (but we do update
|
// in this function we do not record any state changes yet (but we do update
|
||||||
|
@ -2952,6 +2989,14 @@ function BatchCommand(text) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
runExtensions("mouseMove", {
|
||||||
|
event: evt,
|
||||||
|
mouse_x: mouse_x,
|
||||||
|
mouse_y: mouse_y,
|
||||||
|
selected: selected
|
||||||
|
});
|
||||||
|
|
||||||
}; // mouseMove()
|
}; // mouseMove()
|
||||||
|
|
||||||
var mouseUp = function(evt)
|
var mouseUp = function(evt)
|
||||||
|
@ -3161,6 +3206,19 @@ function BatchCommand(text) {
|
||||||
console.log("Unknown mode in mouseup: " + current_mode);
|
console.log("Unknown mode in mouseup: " + current_mode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ext_result = runExtensions("mouseUp", {
|
||||||
|
event: evt,
|
||||||
|
mouse_x: mouse_x,
|
||||||
|
mouse_y: mouse_y
|
||||||
|
});
|
||||||
|
|
||||||
|
if(ext_result) {
|
||||||
|
keep = ext_result.keep;
|
||||||
|
element = ext_result.element;
|
||||||
|
started = ext_result.started;
|
||||||
|
}
|
||||||
|
|
||||||
if (!keep && element != null) {
|
if (!keep && element != null) {
|
||||||
element.parentNode.removeChild(element);
|
element.parentNode.removeChild(element);
|
||||||
element = null;
|
element = null;
|
||||||
|
|
Loading…
Reference in New Issue