| | |
| | | * Copyright(c) 2010 Alexis Deveria |
| | | * |
| | | */ |
| | | |
| | | |
| | | methodDraw.addExtension("Connector", function(S) { |
| | | var svgcontent = S.svgcontent, |
| | | svgroot = S.svgroot, |
| | |
| | | se_ns, |
| | | // connect_str = "-SE_CONNECT-", |
| | | selElems = []; |
| | | |
| | | |
| | | elData = $.data; |
| | | |
| | | |
| | | var lang_list = { |
| | | "en":[ |
| | | {"id": "mode_connect", "title": "Connect two objects" } |
| | |
| | | {"id": "mode_connect", "title": "Connecter deux objets"} |
| | | ] |
| | | }; |
| | | |
| | | |
| | | function getOffset(side, line) { |
| | | var give_offset = !!line.getAttribute('marker-' + side); |
| | | // var give_offset = $(line).data(side+'_off'); |
| | |
| | | var size = line.getAttribute('stroke-width') * 5; |
| | | return give_offset ? size : 0; |
| | | } |
| | | |
| | | |
| | | function showPanel(on) { |
| | | var conn_rules = $('#connector_rules'); |
| | | if(!conn_rules.length) { |
| | | conn_rules = $('<style id="connector_rules"><\/style>').appendTo('head'); |
| | | } |
| | | } |
| | | conn_rules.text(!on?"":"#tool_clone, #tool_topath, #tool_angle, #xy_panel { display: none !important; }"); |
| | | $('#connector_panel').toggle(on); |
| | | } |
| | | |
| | | |
| | | function setPoint(elem, pos, x, y, setMid) { |
| | | var pts = elem.points; |
| | | var pt = svgroot.createSVGPoint(); |
| | |
| | | pt_arr[i] = x + ',' + y; |
| | | } |
| | | } |
| | | elem.setAttribute("points",pt_arr.join(" ")); |
| | | elem.setAttribute("points",pt_arr.join(" ")); |
| | | } |
| | | |
| | | |
| | | if(setMid) { |
| | | // Add center point |
| | | var pt_start = pts.getItem(0); |
| | |
| | | setPoint(elem, 1, (pt_end.x + pt_start.x)/2, (pt_end.y + pt_start.y)/2); |
| | | } |
| | | } |
| | | |
| | | |
| | | function updateLine(diff_x, diff_y) { |
| | | // Update line with element |
| | | var i = connections.length; |
| | |
| | | var conn = connections[i]; |
| | | var line = conn.connector; |
| | | var elem = conn.elem; |
| | | |
| | | |
| | | var pre = conn.is_start?'start':'end'; |
| | | // var sw = line.getAttribute('stroke-width') * 5; |
| | | |
| | | |
| | | // Update bbox for this element |
| | | var bb = elData(line, pre+'_bb'); |
| | | bb.x = conn.start_x + diff_x; |
| | | bb.y = conn.start_y + diff_y; |
| | | elData(line, pre+'_bb', bb); |
| | | |
| | | |
| | | var alt_pre = conn.is_start?'end':'start'; |
| | | |
| | | |
| | | // Get center pt of connected element |
| | | var bb2 = elData(line, alt_pre+'_bb'); |
| | | var src_x = bb2.x + bb2.width/2; |
| | | var src_y = bb2.y + bb2.height/2; |
| | | |
| | | |
| | | // Set point of element being moved |
| | | var pt = getBBintersect(src_x, src_y, bb, getOffset(pre, line)); // $(line).data(pre+'_off')?sw:0 |
| | | setPoint(line, conn.is_start?0:'end', pt.x, pt.y, true); |
| | | |
| | | |
| | | // Set point of connected element |
| | | var pt2 = getBBintersect(pt.x, pt.y, elData(line, alt_pre + '_bb'), getOffset(alt_pre, line)); |
| | | setPoint(line, conn.is_start?'end':0, pt2.x, pt2.y, true); |
| | | |
| | | } |
| | | } |
| | | |
| | | |
| | | function findConnectors(elems) { |
| | | if(!elems) elems = selElems; |
| | | var connectors = $(svgcontent).find(conn_sel); |
| | |
| | | connectors.each(function() { |
| | | var start = elData(this, "c_start"); |
| | | var end = elData(this, "c_end"); |
| | | |
| | | |
| | | var parts = [getElem(start), getElem(end)]; |
| | | for(var i=0; i<2; i++) { |
| | | var c_elem = parts[i]; |
| | |
| | | add_this = true; |
| | | } |
| | | }); |
| | | |
| | | |
| | | if(!c_elem || !c_elem.parentNode) { |
| | | $(this).remove(); |
| | | continue; |
| | |
| | | is_start: (i === 0), |
| | | start_x: bb.x, |
| | | start_y: bb.y |
| | | }); |
| | | }); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | |
| | | function updateConnectors(elems) { |
| | | // Updates connector lines based on selected elements |
| | | // Is not used on mousemove, as it runs getStrokedBBox every time, |
| | |
| | | |
| | | var sw = line.getAttribute('stroke-width') * 5; |
| | | var pre = conn.is_start?'start':'end'; |
| | | |
| | | |
| | | // Update bbox for this element |
| | | var bb = svgCanvas.getStrokedBBox([elem]); |
| | | bb.x = conn.start_x; |
| | | bb.y = conn.start_y; |
| | | elData(line, pre+'_bb', bb); |
| | | var add_offset = elData(line, pre+'_off'); |
| | | |
| | | |
| | | var alt_pre = conn.is_start?'end':'start'; |
| | | |
| | | |
| | | // Get center pt of connected element |
| | | var bb2 = elData(line, alt_pre+'_bb'); |
| | | var src_x = bb2.x + bb2.width/2; |
| | | var src_y = bb2.y + bb2.height/2; |
| | | |
| | | |
| | | // Set point of element being moved |
| | | var pt = getBBintersect(src_x, src_y, bb, getOffset(pre, line)); |
| | | setPoint(line, conn.is_start?0:'end', pt.x, pt.y, true); |
| | | |
| | | |
| | | // Set point of connected element |
| | | var pt2 = getBBintersect(pt.x, pt.y, elData(line, alt_pre + '_bb'), getOffset(alt_pre, line)); |
| | | setPoint(line, conn.is_start?'end':0, pt2.x, pt2.y, true); |
| | | |
| | | |
| | | // Update points attribute manually for webkit |
| | | if(navigator.userAgent.indexOf('AppleWebKit') != -1) { |
| | | var pts = line.points; |
| | |
| | | for(var j=0; j< len; j++) { |
| | | var pt = pts.getItem(j); |
| | | pt_arr[j] = pt.x + ',' + pt.y; |
| | | } |
| | | line.setAttribute("points",pt_arr.join(" ")); |
| | | } |
| | | line.setAttribute("points",pt_arr.join(" ")); |
| | | } |
| | | |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | function getBBintersect(x, y, bb, offset) { |
| | | if(offset) { |
| | | offset -= 0; |
| | |
| | | bb.x -= offset/2; |
| | | bb.y -= offset/2; |
| | | } |
| | | |
| | | |
| | | var mid_x = bb.x + bb.width/2; |
| | | var mid_y = bb.y + bb.height/2; |
| | | var len_x = x - mid_x; |
| | | var len_y = y - mid_y; |
| | | |
| | | |
| | | var slope = Math.abs(len_y/len_x); |
| | | |
| | | |
| | | var ratio; |
| | | |
| | | |
| | | if(slope < bb.height/bb.width) { |
| | | ratio = (bb.width/2) / Math.abs(len_x); |
| | | } else { |
| | | ratio = (bb.height/2) / Math.abs(len_y); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | return { |
| | | x: mid_x + len_x * ratio, |
| | | y: mid_y + len_y * ratio |
| | | } |
| | | } |
| | | |
| | | |
| | | // Do once |
| | | (function() { |
| | | var gse = svgCanvas.groupSelectedElements; |
| | | |
| | | |
| | | svgCanvas.groupSelectedElements = function() { |
| | | svgCanvas.removeFromSelection($(conn_sel).toArray()); |
| | | return gse.apply(this, arguments); |
| | | } |
| | | |
| | | |
| | | var mse = svgCanvas.moveSelectedElements; |
| | | |
| | | |
| | | svgCanvas.moveSelectedElements = function() { |
| | | svgCanvas.removeFromSelection($(conn_sel).toArray()); |
| | | var cmd = mse.apply(this, arguments); |
| | | updateConnectors(); |
| | | return cmd; |
| | | } |
| | | |
| | | |
| | | se_ns = svgCanvas.getEditorNS(); |
| | | }()); |
| | | |
| | | |
| | | // Do on reset |
| | | function init() { |
| | | // Make sure all connectors have data set |
| | | $(svgcontent).find('*').each(function() { |
| | | $(svgcontent).find('*').each(function() { |
| | | var conn = this.getAttributeNS(se_ns, "connector"); |
| | | if(conn) { |
| | | this.setAttribute('class', conn_sel.substr(1)); |
| | |
| | | }); |
| | | // updateConnectors(); |
| | | } |
| | | |
| | | |
| | | // $(svgroot).parent().mousemove(function(e) { |
| | | // // if(started |
| | | // // if(started |
| | | // // || svgCanvas.getMode() != "connector" |
| | | // // || e.target.parentNode.parentNode != svgcontent) return; |
| | | // |
| | | // |
| | | // console.log('y') |
| | | // // if(e.target.parentNode.parentNode === svgcontent) { |
| | | // // |
| | | // // |
| | | // // } |
| | | // }); |
| | | |
| | | |
| | | return { |
| | | name: "Connector", |
| | | svgicons: "images/conn.svg", |
| | |
| | | start_x = opts.start_x, |
| | | start_y = opts.start_y; |
| | | var mode = svgCanvas.getMode(); |
| | | |
| | | |
| | | if(mode == "connector") { |
| | | |
| | | |
| | | if(started) return; |
| | | |
| | | |
| | | var mouse_target = e.target; |
| | | |
| | | |
| | | var parents = $(mouse_target).parents(); |
| | | |
| | | |
| | | if($.inArray(svgcontent, parents) != -1) { |
| | | // Connectable element |
| | | |
| | | |
| | | // If child of foreignObject, use parent |
| | | var fo = $(mouse_target).closest("foreignObject"); |
| | | start_elem = fo.length ? fo[0] : mouse_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": "polyline", |
| | |
| | | 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) { |
| | | |
| | | |
| | | var sw = cur_line.getAttribute('stroke-width') * 3; |
| | | // Set start point (adjusts based on bb) |
| | | var pt = getBBintersect(x, y, elData(cur_line, 'start_bb'), getOffset('start', cur_line)); |
| | | start_x = pt.x; |
| | | start_y = pt.y; |
| | | |
| | | |
| | | setPoint(cur_line, 0, pt.x, pt.y, true); |
| | | |
| | | |
| | | // Set end point |
| | | setPoint(cur_line, 'end', x, y, true); |
| | | } else if(mode == "select") { |
| | | var slen = selElems.length; |
| | | |
| | | |
| | | while(slen--) { |
| | | var elem = selElems[slen]; |
| | | // Look for selected connector elements |
| | |
| | | if(connections.length) { |
| | | updateLine(diff_x, diff_y); |
| | | |
| | | |
| | | |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | mouseUp: function(opts) { |
| | | var zoom = svgCanvas.getZoom(); |
| | |
| | | x = opts.mouse_x/zoom, |
| | | y = opts.mouse_y/zoom, |
| | | mouse_target = e.target; |
| | | |
| | | |
| | | if(svgCanvas.getMode() == "connector") { |
| | | var fo = $(mouse_target).closest("foreignObject"); |
| | | if(fo.length) mouse_target = fo[0]; |
| | | |
| | | |
| | | var parents = $(mouse_target).parents(); |
| | | |
| | | if(mouse_target == start_elem) { |
| | |
| | | keep: true, |
| | | element: null, |
| | | started: started |
| | | } |
| | | } |
| | | } else if($.inArray(svgcontent, parents) === -1) { |
| | | // Not a valid target element, so remove line |
| | | $(cur_line).remove(); |
| | |
| | | } else { |
| | | // Valid end element |
| | | end_elem = mouse_target; |
| | | |
| | | |
| | | var start_id = start_elem.id, end_id = end_elem.id; |
| | | var conn_str = start_id + " " + end_id; |
| | | var alt_str = end_id + " " + start_id; |
| | |
| | | started: false |
| | | } |
| | | } |
| | | |
| | | |
| | | var bb = svgCanvas.getStrokedBBox([end_elem]); |
| | | |
| | | |
| | | var pt = getBBintersect(start_x, start_y, bb, getOffset('start', cur_line)); |
| | | setPoint(cur_line, 'end', pt.x, pt.y, true); |
| | | $(cur_line) |
| | |
| | | selectedChanged: function(opts) { |
| | | // TODO: Find better way to skip operations if no connectors are in use |
| | | if(!$(svgcontent).find(conn_sel).length) return; |
| | | |
| | | |
| | | if(svgCanvas.getMode() == 'connector') { |
| | | svgCanvas.setMode('select'); |
| | | } |
| | | |
| | | |
| | | // Use this to update the current selected elements |
| | | selElems = opts.elems; |
| | | |
| | | |
| | | var i = selElems.length; |
| | | |
| | | |
| | | while(i--) { |
| | | var elem = selElems[i]; |
| | | if(elem && elData(elem, 'c_start')) { |
| | |
| | | svgcontent = elem; |
| | | init(); |
| | | } |
| | | |
| | | |
| | | // Has marker, so change offset |
| | | if(elem && ( |
| | | elem.getAttribute("marker-start") || |
| | |
| | | $(elem) |
| | | .data("start_off", !!start) |
| | | .data("end_off", !!end); |
| | | |
| | | |
| | | if(elem.tagName == "line" && mid) { |
| | | // Convert to polyline to accept mid-arrow |
| | | |
| | | |
| | | var x1 = elem.getAttribute('x1')-0; |
| | | var x2 = elem.getAttribute('x2')-0; |
| | | var y1 = elem.getAttribute('y1')-0; |
| | | var y2 = elem.getAttribute('y2')-0; |
| | | var id = elem.id; |
| | | |
| | | |
| | | var mid_pt = (' '+((x1+x2)/2)+','+((y1+y2)/2) + ' '); |
| | | var pline = addElem({ |
| | | "element": "polyline", |