/* * ext-arrows.js * * Licensed under the Apache License, Version 2 * * Copyright(c) 2010 Alexis Deveria * */ svgEditor.addExtension("Arrows", function(S) { var svgcontent = S.svgcontent, addElem = S.addSvgElementFromJson, nonce = S.nonce, randomize_ids = S.randomize_ids, selElems; svgCanvas.bind('setnonce', setArrowNonce); svgCanvas.bind('unsetnonce', unsetArrowNonce); var lang_list = { "en":[ {"id": "arrow_none", "textContent": "No arrow" } ], "fr":[ {"id": "arrow_none", "textContent": "Sans flèche" } ] }; var prefix = 'se_arrow_'; if (randomize_ids) { var arrowprefix = prefix + nonce + '_'; } else { var arrowprefix = prefix; } var pathdata = { fw: {d:"m0,0l10,5l-10,5l5,-5l-5,-5z", refx:8, id: arrowprefix + 'fw'}, bk: {d:"m10,0l-10,5l10,5l-5,-5l5,-5z", refx:2, id: arrowprefix + 'bk'} } function setArrowNonce(window, n) { randomize_ids = true; arrowprefix = prefix + n + '_'; pathdata.fw.id = arrowprefix + 'fw'; pathdata.bk.id = arrowprefix + 'bk'; } function unsetArrowNonce(window) { randomize_ids = false; arrowprefix = prefix; pathdata.fw.id = arrowprefix + 'fw'; pathdata.bk.id = arrowprefix + 'bk'; } function getLinked(elem, attr) { var str = elem.getAttribute(attr); if(!str) return null; var m = str.match(/\(\#(.*)\)/); if(!m || m.length !== 2) { return null; } return S.getElem(m[1]); } function showPanel(on) { $('#arrow_panel').toggle(on); if(on) { var el = selElems[0]; var end = el.getAttribute("marker-end"); var start = el.getAttribute("marker-start"); var mid = el.getAttribute("marker-mid"); var val; if(end && start) { val = "both"; } else if(end) { val = "end"; } else if(start) { val = "start"; } else if(mid) { val = "mid"; if(mid.indexOf("bk") != -1) { val = "mid_bk"; } } if(!start && !mid && !end) { val = "none"; } $("#arrow_list").val(val); } } function resetMarker() { var el = selElems[0]; el.removeAttribute("marker-start"); el.removeAttribute("marker-mid"); el.removeAttribute("marker-end"); } function addMarker(dir, type, id) { // TODO: Make marker (or use?) per arrow type, since refX can be different id = id || arrowprefix + dir; var marker = S.getElem(id); var data = pathdata[dir]; if(type == "mid") { data.refx = 5; } if(!marker) { marker = addElem({ "element": "marker", "attr": { "viewBox": "0 0 10 10", "id": id, "refY": 5, "markerUnits": "strokeWidth", "markerWidth": 5, "markerHeight": 5, "orient": "auto", "style": "pointer-events:none" // Currently needed for Opera } }); var arrow = addElem({ "element": "path", "attr": { "d": data.d, "fill": "#000000" } }); marker.appendChild(arrow); S.findDefs().appendChild(marker); } marker.setAttribute('refX', data.refx); return marker; } function setArrow() { var type = this.value; resetMarker(); if(type == "none") { return; } // Set marker on element var dir = "fw"; if(type == "mid_bk") { type = "mid"; dir = "bk"; } else if(type == "both") { addMarker("bk", type); svgCanvas.changeSelectedAttribute("marker-start", "url(#" + pathdata.bk.id + ")"); type = "end"; dir = "fw"; } else if (type == "start") { dir = "bk"; } addMarker(dir, type); svgCanvas.changeSelectedAttribute("marker-"+type, "url(#" + pathdata[dir].id + ")"); S.call("changed", selElems); } function colorChanged(elem) { var color = elem.getAttribute('stroke'); var mtypes = ['start','mid','end']; var defs = S.findDefs(); $.each(mtypes, function(i, type) { var marker = getLinked(elem, 'marker-'+type); if(!marker) return; var cur_color = $(marker).children().attr('fill'); var cur_d = $(marker).children().attr('d'); var new_marker = null; if(cur_color === color) return; var all_markers = $(defs).find('marker'); // Different color, check if already made all_markers.each(function() { var attrs = $(this).children().attr(['fill', 'd']); if(attrs.fill === color && attrs.d === cur_d) { // Found another marker with this color and this path new_marker = this; } }); if(!new_marker) { // Create a new marker with this color var last_id = marker.id; var dir = last_id.indexOf('_fw') !== -1?'fw':'bk'; new_marker = addMarker(dir, type, arrowprefix + dir + all_markers.length); $(new_marker).children().attr('fill', color); } $(elem).attr('marker-'+type, "url(#" + new_marker.id + ")"); // Check if last marker can be removed var remove = true; $(S.svgcontent).find('line, polyline, path, polygon').each(function() { var elem = this; $.each(mtypes, function(j, mtype) { if($(elem).attr('marker-' + mtype) === "url(#" + marker.id + ")") { return remove = false; } }); if(!remove) return false; }); // Not found, so can safely remove if(remove) { $(marker).remove(); } }); } return { name: "Arrows", context_tools: [{ type: "select", panel: "arrow_panel", title: "Select arrow type", id: "arrow_list", options: { none: "No arrow", end: "---->", start: "<----", both: "<--->", mid: "-->--", mid_bk: "--<--" }, defval: "none", events: { change: setArrow } }], callback: function() { $('#arrow_panel').hide(); // Set ID so it can be translated in locale file $('#arrow_list option')[0].id = 'connector_no_arrow'; }, addLangData: function(lang) { return { data: lang_list[lang] }; }, selectedChanged: function(opts) { // Use this to update the current selected elements selElems = opts.elems; var i = selElems.length; var marker_elems = ['line','path','polyline','polygon']; while(i--) { var elem = selElems[i]; if(elem && $.inArray(elem.tagName, marker_elems) != -1) { if(opts.selectedElement && !opts.multiselected) { showPanel(true); } else { showPanel(false); } } else { showPanel(false); } } }, elementChanged: function(opts) { var elem = opts.elems[0]; if(elem && ( elem.getAttribute("marker-start") || elem.getAttribute("marker-mid") || elem.getAttribute("marker-end") )) { // var start = elem.getAttribute("marker-start"); // var mid = elem.getAttribute("marker-mid"); // var end = elem.getAttribute("marker-end"); // Has marker, so see if it should match color colorChanged(elem); } } }; });