You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
293 lines
6.6 KiB
293 lines
6.6 KiB
/*globals svgEditor, svgCanvas, $*/ |
|
/*jslint vars: true, eqeq: true*/ |
|
/* |
|
* ext-arrows.js |
|
* |
|
* Licensed under the MIT License |
|
* |
|
* 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, pathdata, |
|
lang_list = { |
|
'en':[ |
|
{'id': 'arrow_none', 'textContent': 'No arrow' } |
|
], |
|
'fr':[ |
|
{'id': 'arrow_none', 'textContent': 'Sans flèche' } |
|
] |
|
}, |
|
arrowprefix, |
|
prefix = 'se_arrow_'; |
|
|
|
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'; |
|
} |
|
|
|
|
|
svgCanvas.bind('setnonce', setArrowNonce); |
|
svgCanvas.bind('unsetnonce', unsetArrowNonce); |
|
|
|
if (randomize_ids) { |
|
arrowprefix = prefix + nonce + '_'; |
|
} else { |
|
arrowprefix = prefix; |
|
} |
|
|
|
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 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 + ')') { |
|
remove = false; |
|
return remove; |
|
} |
|
}); |
|
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); |
|
} |
|
} |
|
}; |
|
});
|
|
|