Feature #2044 upload svg-edit 2.5.1
@ -0,0 +1,287 @@ |
||||
/** |
||||
* A class to parse color values |
||||
* @author Stoyan Stefanov <sstoo@gmail.com> |
||||
* @link http://www.phpied.com/rgb-color-parser-in-javascript/
|
||||
* @license Use it if you like it |
||||
*/ |
||||
function RGBColor(color_string) |
||||
{ |
||||
this.ok = false; |
||||
|
||||
// strip any leading #
|
||||
if (color_string.charAt(0) == '#') { // remove # if any
|
||||
color_string = color_string.substr(1,6); |
||||
} |
||||
|
||||
color_string = color_string.replace(/ /g,''); |
||||
color_string = color_string.toLowerCase(); |
||||
|
||||
// before getting into regexps, try simple matches
|
||||
// and overwrite the input
|
||||
var simple_colors = { |
||||
aliceblue: 'f0f8ff', |
||||
antiquewhite: 'faebd7', |
||||
aqua: '00ffff', |
||||
aquamarine: '7fffd4', |
||||
azure: 'f0ffff', |
||||
beige: 'f5f5dc', |
||||
bisque: 'ffe4c4', |
||||
black: '000000', |
||||
blanchedalmond: 'ffebcd', |
||||
blue: '0000ff', |
||||
blueviolet: '8a2be2', |
||||
brown: 'a52a2a', |
||||
burlywood: 'deb887', |
||||
cadetblue: '5f9ea0', |
||||
chartreuse: '7fff00', |
||||
chocolate: 'd2691e', |
||||
coral: 'ff7f50', |
||||
cornflowerblue: '6495ed', |
||||
cornsilk: 'fff8dc', |
||||
crimson: 'dc143c', |
||||
cyan: '00ffff', |
||||
darkblue: '00008b', |
||||
darkcyan: '008b8b', |
||||
darkgoldenrod: 'b8860b', |
||||
darkgray: 'a9a9a9', |
||||
darkgreen: '006400', |
||||
darkkhaki: 'bdb76b', |
||||
darkmagenta: '8b008b', |
||||
darkolivegreen: '556b2f', |
||||
darkorange: 'ff8c00', |
||||
darkorchid: '9932cc', |
||||
darkred: '8b0000', |
||||
darksalmon: 'e9967a', |
||||
darkseagreen: '8fbc8f', |
||||
darkslateblue: '483d8b', |
||||
darkslategray: '2f4f4f', |
||||
darkturquoise: '00ced1', |
||||
darkviolet: '9400d3', |
||||
deeppink: 'ff1493', |
||||
deepskyblue: '00bfff', |
||||
dimgray: '696969', |
||||
dodgerblue: '1e90ff', |
||||
feldspar: 'd19275', |
||||
firebrick: 'b22222', |
||||
floralwhite: 'fffaf0', |
||||
forestgreen: '228b22', |
||||
fuchsia: 'ff00ff', |
||||
gainsboro: 'dcdcdc', |
||||
ghostwhite: 'f8f8ff', |
||||
gold: 'ffd700', |
||||
goldenrod: 'daa520', |
||||
gray: '808080', |
||||
green: '008000', |
||||
greenyellow: 'adff2f', |
||||
honeydew: 'f0fff0', |
||||
hotpink: 'ff69b4', |
||||
indianred : 'cd5c5c', |
||||
indigo : '4b0082', |
||||
ivory: 'fffff0', |
||||
khaki: 'f0e68c', |
||||
lavender: 'e6e6fa', |
||||
lavenderblush: 'fff0f5', |
||||
lawngreen: '7cfc00', |
||||
lemonchiffon: 'fffacd', |
||||
lightblue: 'add8e6', |
||||
lightcoral: 'f08080', |
||||
lightcyan: 'e0ffff', |
||||
lightgoldenrodyellow: 'fafad2', |
||||
lightgrey: 'd3d3d3', |
||||
lightgreen: '90ee90', |
||||
lightpink: 'ffb6c1', |
||||
lightsalmon: 'ffa07a', |
||||
lightseagreen: '20b2aa', |
||||
lightskyblue: '87cefa', |
||||
lightslateblue: '8470ff', |
||||
lightslategray: '778899', |
||||
lightsteelblue: 'b0c4de', |
||||
lightyellow: 'ffffe0', |
||||
lime: '00ff00', |
||||
limegreen: '32cd32', |
||||
linen: 'faf0e6', |
||||
magenta: 'ff00ff', |
||||
maroon: '800000', |
||||
mediumaquamarine: '66cdaa', |
||||
mediumblue: '0000cd', |
||||
mediumorchid: 'ba55d3', |
||||
mediumpurple: '9370d8', |
||||
mediumseagreen: '3cb371', |
||||
mediumslateblue: '7b68ee', |
||||
mediumspringgreen: '00fa9a', |
||||
mediumturquoise: '48d1cc', |
||||
mediumvioletred: 'c71585', |
||||
midnightblue: '191970', |
||||
mintcream: 'f5fffa', |
||||
mistyrose: 'ffe4e1', |
||||
moccasin: 'ffe4b5', |
||||
navajowhite: 'ffdead', |
||||
navy: '000080', |
||||
oldlace: 'fdf5e6', |
||||
olive: '808000', |
||||
olivedrab: '6b8e23', |
||||
orange: 'ffa500', |
||||
orangered: 'ff4500', |
||||
orchid: 'da70d6', |
||||
palegoldenrod: 'eee8aa', |
||||
palegreen: '98fb98', |
||||
paleturquoise: 'afeeee', |
||||
palevioletred: 'd87093', |
||||
papayawhip: 'ffefd5', |
||||
peachpuff: 'ffdab9', |
||||
peru: 'cd853f', |
||||
pink: 'ffc0cb', |
||||
plum: 'dda0dd', |
||||
powderblue: 'b0e0e6', |
||||
purple: '800080', |
||||
red: 'ff0000', |
||||
rosybrown: 'bc8f8f', |
||||
royalblue: '4169e1', |
||||
saddlebrown: '8b4513', |
||||
salmon: 'fa8072', |
||||
sandybrown: 'f4a460', |
||||
seagreen: '2e8b57', |
||||
seashell: 'fff5ee', |
||||
sienna: 'a0522d', |
||||
silver: 'c0c0c0', |
||||
skyblue: '87ceeb', |
||||
slateblue: '6a5acd', |
||||
slategray: '708090', |
||||
snow: 'fffafa', |
||||
springgreen: '00ff7f', |
||||
steelblue: '4682b4', |
||||
tan: 'd2b48c', |
||||
teal: '008080', |
||||
thistle: 'd8bfd8', |
||||
tomato: 'ff6347', |
||||
turquoise: '40e0d0', |
||||
violet: 'ee82ee', |
||||
violetred: 'd02090', |
||||
wheat: 'f5deb3', |
||||
white: 'ffffff', |
||||
whitesmoke: 'f5f5f5', |
||||
yellow: 'ffff00', |
||||
yellowgreen: '9acd32' |
||||
}; |
||||
for (var key in simple_colors) { |
||||
if (color_string == key) { |
||||
color_string = simple_colors[key]; |
||||
} |
||||
} |
||||
// emd of simple type-in colors
|
||||
|
||||
// array of color definition objects
|
||||
var color_defs = [ |
||||
{ |
||||
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, |
||||
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], |
||||
process: function (bits){ |
||||
return [ |
||||
parseInt(bits[1]), |
||||
parseInt(bits[2]), |
||||
parseInt(bits[3]) |
||||
]; |
||||
} |
||||
}, |
||||
{ |
||||
re: /^(\w{2})(\w{2})(\w{2})$/, |
||||
example: ['#00ff00', '336699'], |
||||
process: function (bits){ |
||||
return [ |
||||
parseInt(bits[1], 16), |
||||
parseInt(bits[2], 16), |
||||
parseInt(bits[3], 16) |
||||
]; |
||||
} |
||||
}, |
||||
{ |
||||
re: /^(\w{1})(\w{1})(\w{1})$/, |
||||
example: ['#fb0', 'f0f'], |
||||
process: function (bits){ |
||||
return [ |
||||
parseInt(bits[1] + bits[1], 16), |
||||
parseInt(bits[2] + bits[2], 16), |
||||
parseInt(bits[3] + bits[3], 16) |
||||
]; |
||||
} |
||||
} |
||||
]; |
||||
|
||||
// search through the definitions to find a match
|
||||
for (var i = 0; i < color_defs.length; i++) { |
||||
var re = color_defs[i].re; |
||||
var processor = color_defs[i].process; |
||||
var bits = re.exec(color_string); |
||||
if (bits) { |
||||
channels = processor(bits); |
||||
this.r = channels[0]; |
||||
this.g = channels[1]; |
||||
this.b = channels[2]; |
||||
this.ok = true; |
||||
} |
||||
|
||||
} |
||||
|
||||
// validate/cleanup values
|
||||
this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r); |
||||
this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g); |
||||
this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b); |
||||
|
||||
// some getters
|
||||
this.toRGB = function () { |
||||
return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; |
||||
} |
||||
this.toHex = function () { |
||||
var r = this.r.toString(16); |
||||
var g = this.g.toString(16); |
||||
var b = this.b.toString(16); |
||||
if (r.length == 1) r = '0' + r; |
||||
if (g.length == 1) g = '0' + g; |
||||
if (b.length == 1) b = '0' + b; |
||||
return '#' + r + g + b; |
||||
} |
||||
|
||||
// help
|
||||
this.getHelpXML = function () { |
||||
|
||||
var examples = new Array(); |
||||
// add regexps
|
||||
for (var i = 0; i < color_defs.length; i++) { |
||||
var example = color_defs[i].example; |
||||
for (var j = 0; j < example.length; j++) { |
||||
examples[examples.length] = example[j]; |
||||
} |
||||
} |
||||
// add type-in colors
|
||||
for (var sc in simple_colors) { |
||||
examples[examples.length] = sc; |
||||
} |
||||
|
||||
var xml = document.createElement('ul'); |
||||
xml.setAttribute('id', 'rgbcolor-examples'); |
||||
for (var i = 0; i < examples.length; i++) { |
||||
try { |
||||
var list_item = document.createElement('li'); |
||||
var list_color = new RGBColor(examples[i]); |
||||
var example_div = document.createElement('div'); |
||||
example_div.style.cssText = |
||||
'margin: 3px; ' |
||||
+ 'border: 1px solid black; ' |
||||
+ 'background:' + list_color.toHex() + '; ' |
||||
+ 'color:' + list_color.toHex() |
||||
; |
||||
example_div.appendChild(document.createTextNode('test')); |
||||
var list_item_value = document.createTextNode( |
||||
' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex() |
||||
); |
||||
list_item.appendChild(example_div); |
||||
list_item.appendChild(list_item_value); |
||||
xml.appendChild(list_item); |
||||
|
||||
} catch(e){} |
||||
} |
||||
return xml; |
||||
|
||||
} |
||||
|
||||
} |
||||
|
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,298 @@ |
||||
/* |
||||
* 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('setarrownonce', setArrowNonce); |
||||
svgCanvas.bind('unsetsetarrownonce', 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); |
||||
} |
||||
|
||||
} |
||||
}; |
||||
}); |
||||
@ -0,0 +1,92 @@ |
||||
/* |
||||
* ext-closepath.js |
||||
* |
||||
* Licensed under the Apache License, Version 2 |
||||
* |
||||
* Copyright(c) 2010 Jeff Schiller |
||||
* |
||||
*/ |
||||
|
||||
// This extension adds a simple button to the contextual panel for paths
|
||||
// The button toggles whether the path is open or closed
|
||||
svgEditor.addExtension("ClosePath", function(S) { |
||||
var selElems, |
||||
updateButton = function(path) { |
||||
var seglist = path.pathSegList, |
||||
closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType==1, |
||||
showbutton = closed ? '#tool_openpath' : '#tool_closepath', |
||||
hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; |
||||
$(hidebutton).hide(); |
||||
$(showbutton).show(); |
||||
}, |
||||
showPanel = function(on) { |
||||
$('#closepath_panel').toggle(on); |
||||
if (on) { |
||||
var path = selElems[0]; |
||||
if (path) updateButton(path); |
||||
} |
||||
}, |
||||
|
||||
toggleClosed = function() { |
||||
var path = selElems[0]; |
||||
if (path) { |
||||
var seglist = path.pathSegList, |
||||
last = seglist.numberOfItems - 1;
|
||||
// is closed
|
||||
if(seglist.getItem(last).pathSegType == 1) { |
||||
seglist.removeItem(last); |
||||
} |
||||
else { |
||||
seglist.appendItem(path.createSVGPathSegClosePath()); |
||||
} |
||||
updateButton(path); |
||||
} |
||||
}; |
||||
|
||||
return { |
||||
name: "ClosePath", |
||||
svgicons: "extensions/closepath_icons.svg", |
||||
buttons: [{ |
||||
id: "tool_openpath", |
||||
type: "context", |
||||
panel: "closepath_panel", |
||||
title: "Open path", |
||||
events: { |
||||
'click': function() { |
||||
toggleClosed(); |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
id: "tool_closepath", |
||||
type: "context", |
||||
panel: "closepath_panel", |
||||
title: "Close path", |
||||
events: { |
||||
'click': function() { |
||||
toggleClosed(); |
||||
} |
||||
} |
||||
}], |
||||
callback: function() { |
||||
$('#closepath_panel').hide(); |
||||
}, |
||||
selectedChanged: function(opts) { |
||||
selElems = opts.elems; |
||||
var i = selElems.length; |
||||
|
||||
while(i--) { |
||||
var elem = selElems[i]; |
||||
if(elem && elem.tagName == 'path') { |
||||
if(opts.selectedElement && !opts.multiselected) { |
||||
showPanel(true); |
||||
} else { |
||||
showPanel(false); |
||||
} |
||||
} else { |
||||
showPanel(false); |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
}); |
||||
@ -0,0 +1,579 @@ |
||||
/* |
||||
* ext-connector.js |
||||
* |
||||
* Licensed under the Apache License, Version 2 |
||||
* |
||||
* Copyright(c) 2010 Alexis Deveria |
||||
* |
||||
*/ |
||||
|
||||
svgEditor.addExtension("Connector", function(S) { |
||||
var svgcontent = S.svgcontent, |
||||
svgroot = S.svgroot, |
||||
getNextId = S.getNextId, |
||||
getElem = S.getElem, |
||||
addElem = S.addSvgElementFromJson, |
||||
selManager = S.selectorManager, |
||||
curConfig = svgEditor.curConfig, |
||||
started = false, |
||||
start_x, |
||||
start_y, |
||||
cur_line, |
||||
start_elem, |
||||
end_elem, |
||||
connections = [], |
||||
conn_sel = ".se_connector", |
||||
se_ns, |
||||
// connect_str = "-SE_CONNECT-",
|
||||
selElems = []; |
||||
|
||||
var lang_list = { |
||||
"en":[ |
||||
{"id": "mode_connect", "title": "Connect two objects" } |
||||
], |
||||
"fr":[ |
||||
{"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');
|
||||
|
||||
// TODO: Make this number (5) be based on marker width/height
|
||||
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.x = x; |
||||
pt.y = y; |
||||
if(pos === 'end') pos = pts.numberOfItems-1; |
||||
// TODO: Test for this on init, then use alt only if needed
|
||||
try { |
||||
pts.replaceItem(pt, pos); |
||||
} catch(err) { |
||||
// Should only occur in FF which formats points attr as "n,n n,n", so just split
|
||||
var pt_arr = elem.getAttribute("points").split(" "); |
||||
for(var i=0; i< pt_arr.length; i++) { |
||||
if(i == pos) { |
||||
pt_arr[i] = x + ',' + y; |
||||
} |
||||
} |
||||
elem.setAttribute("points",pt_arr.join(" "));
|
||||
} |
||||
|
||||
if(setMid) { |
||||
// Add center point
|
||||
var pt_start = pts.getItem(0); |
||||
var pt_end = pts.getItem(pts.numberOfItems-1); |
||||
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; |
||||
while(i--) { |
||||
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 = $(line).data(pre+'_bb'); |
||||
bb.x = conn.start_x + diff_x; |
||||
bb.y = conn.start_y + diff_y; |
||||
$(line).data(pre+'_bb', bb); |
||||
|
||||
var alt_pre = conn.is_start?'end':'start'; |
||||
|
||||
// Get center pt of connected element
|
||||
var bb2 = $(line).data(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, $(line).data(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); |
||||
connections = []; |
||||
|
||||
// Loop through connectors to see if one is connected to the element
|
||||
connectors.each(function() { |
||||
var start = $(this).data("c_start"); |
||||
var end = $(this).data("c_end"); |
||||
|
||||
var parts = [getElem(start), getElem(end)]; |
||||
for(var i=0; i<2; i++) { |
||||
var c_elem = parts[i]; |
||||
var add_this = false; |
||||
// The connected element might be part of a selected group
|
||||
$(c_elem).parents().each(function() { |
||||
if($.inArray(this, elems) !== -1) { |
||||
// Pretend this element is selected
|
||||
add_this = true; |
||||
} |
||||
}); |
||||
|
||||
if(!c_elem || !c_elem.parentNode) { |
||||
$(this).remove(); |
||||
continue; |
||||
} |
||||
if($.inArray(c_elem, elems) !== -1 || add_this) { |
||||
var bb = svgCanvas.getStrokedBBox([c_elem]); |
||||
connections.push({ |
||||
elem: c_elem, |
||||
connector: this, |
||||
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,
|
||||
// which isn't necessary there.
|
||||
findConnectors(elems); |
||||
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 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; |
||||
$(line).data(pre+'_bb', bb); |
||||
var add_offset = $(line).data(pre+'_off'); |
||||
|
||||
var alt_pre = conn.is_start?'end':'start'; |
||||
|
||||
// Get center pt of connected element
|
||||
var bb2 = $(line).data(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, $(line).data(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; |
||||
var len = pts.numberOfItems; |
||||
var pt_arr = Array(len); |
||||
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(" "));
|
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
||||
|
||||
function getBBintersect(x, y, bb, offset) { |
||||
if(offset) { |
||||
offset -= 0; |
||||
bb = $.extend({}, bb); |
||||
bb.width += offset; |
||||
bb.height += offset; |
||||
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()); |
||||
gse(); |
||||
} |
||||
|
||||
var mse = svgCanvas.moveSelectedElements; |
||||
|
||||
svgCanvas.moveSelectedElements = function() { |
||||
svgCanvas.removeFromSelection($(conn_sel).toArray()); |
||||
mse.apply(this, arguments); |
||||
updateConnectors(); |
||||
} |
||||
|
||||
se_ns = svgCanvas.getEditorNS(); |
||||
}()); |
||||
|
||||
// Do on reset
|
||||
function init() { |
||||
// Make sure all connectors have data set
|
||||
$(svgcontent).find('*').each(function() {
|
||||
var conn = this.getAttributeNS(se_ns, "connector"); |
||||
if(conn) { |
||||
this.setAttribute('class', conn_sel.substr(1)); |
||||
var conn_data = conn.split(' '); |
||||
var sbb = svgCanvas.getStrokedBBox([getElem(conn_data[0])]); |
||||
var ebb = svgCanvas.getStrokedBBox([getElem(conn_data[1])]); |
||||
$(this).data('c_start',conn_data[0]) |
||||
.data('c_end',conn_data[1]) |
||||
.data('start_bb', sbb) |
||||
.data('end_bb', ebb); |
||||
svgCanvas.getEditorNS(true); |
||||
} |
||||
}); |
||||
// updateConnectors();
|
||||
} |
||||
|
||||
// $(svgroot).parent().mousemove(function(e) {
|
||||
// // 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", |
||||
buttons: [{ |
||||
id: "mode_connect", |
||||
type: "mode", |
||||
icon: "images/cut.png", |
||||
title: "Connect two objects", |
||||
key: "Shift+3", |
||||
includeWith: { |
||||
button: '#tool_line', |
||||
isDefault: false, |
||||
position: 1 |
||||
}, |
||||
events: { |
||||
'click': function() { |
||||
svgCanvas.setMode("connector"); |
||||
} |
||||
} |
||||
}], |
||||
addLangData: function(lang) { |
||||
return { |
||||
data: lang_list[lang] |
||||
}; |
||||
}, |
||||
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; |
||||
|
||||
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", |
||||
"attr": { |
||||
"id": getNextId(), |
||||
"points": (x+','+y+' '+x+','+y+' '+start_x+','+start_y), |
||||
"stroke": '#' + curConfig.initStroke.color, |
||||
"stroke-width": (!start_elem.stroke_width || start_elem.stroke_width == 0) ? curConfig.initStroke.width : start_elem.stroke_width, |
||||
"fill": "none", |
||||
"opacity": curConfig.initStroke.opacity, |
||||
"style": "pointer-events:none" |
||||
} |
||||
}); |
||||
$(cur_line).data('start_bb', bb); |
||||
} |
||||
return { |
||||
started: true |
||||
}; |
||||
} else if(mode == "select") { |
||||
findConnectors(); |
||||
} |
||||
}, |
||||
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) { |
||||
|
||||
var sw = cur_line.getAttribute('stroke-width') * 3; |
||||
// Set start point (adjusts based on bb)
|
||||
var pt = getBBintersect(x, y, $(cur_line).data('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(elem && $(elem).data('c_start')) { |
||||
// Remove the "translate" transform given to move
|
||||
svgCanvas.removeFromSelection([elem]); |
||||
svgCanvas.getTransformList(elem).clear(); |
||||
|
||||
} |
||||
} |
||||
if(connections.length) { |
||||
updateLine(diff_x, diff_y); |
||||
|
||||
|
||||
} |
||||
}
|
||||
}, |
||||
mouseUp: function(opts) { |
||||
var zoom = svgCanvas.getZoom(); |
||||
var e = opts.event, |
||||
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) { |
||||
// Start line through click
|
||||
started = true; |
||||
return { |
||||
keep: true, |
||||
element: null, |
||||
started: started |
||||
}
|
||||
} else if($.inArray(svgcontent, parents) === -1) { |
||||
// Not a valid target element, so remove line
|
||||
$(cur_line).remove(); |
||||
started = false; |
||||
return { |
||||
keep: false, |
||||
element: null, |
||||
started: started |
||||
} |
||||
} 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; |
||||
// Don't create connector if one already exists
|
||||
var dupe = $(svgcontent).find(conn_sel).filter(function() { |
||||
var conn = this.getAttributeNS(se_ns, "connector"); |
||||
if(conn == conn_str || conn == alt_str) return true; |
||||
}); |
||||
if(dupe.length) { |
||||
$(cur_line).remove(); |
||||
return { |
||||
keep: false, |
||||
element: null, |
||||
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) |
||||
.data("c_start", start_id) |
||||
.data("c_end", end_id) |
||||
.data("end_bb", bb); |
||||
se_ns = svgCanvas.getEditorNS(true); |
||||
cur_line.setAttributeNS(se_ns, "se:connector", conn_str); |
||||
cur_line.setAttribute('class', conn_sel.substr(1)); |
||||
cur_line.setAttribute('opacity', 1); |
||||
svgCanvas.addToSelection([cur_line]); |
||||
svgCanvas.moveToBottomSelectedElement(); |
||||
selManager.requestSelector(cur_line).showGrips(false); |
||||
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; |
||||
|
||||
while(i--) { |
||||
var elem = selElems[i]; |
||||
if(elem && $(elem).data('c_start')) { |
||||
selManager.requestSelector(elem).showGrips(false); |
||||
if(opts.selectedElement && !opts.multiselected) { |
||||
// TODO: Set up context tools and hide most regular line tools
|
||||
showPanel(true); |
||||
} else { |
||||
showPanel(false); |
||||
} |
||||
} else { |
||||
showPanel(false); |
||||
} |
||||
} |
||||
updateConnectors(); |
||||
}, |
||||
elementChanged: function(opts) { |
||||
var elem = opts.elems[0]; |
||||
if (elem && elem.tagName == 'svg' && elem.id == "svgcontent") { |
||||
// Update svgcontent (can change on import)
|
||||
svgcontent = elem; |
||||
init(); |
||||
} |
||||
|
||||
// Has marker, so change offset
|
||||
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"); |
||||
cur_line = elem; |
||||
$(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", |
||||
"attr": { |
||||
"points": (x1+','+y1+ mid_pt +x2+','+y2), |
||||
"stroke": elem.getAttribute('stroke'), |
||||
"stroke-width": elem.getAttribute('stroke-width'), |
||||
"marker-mid": mid, |
||||
"fill": "none", |
||||
"opacity": elem.getAttribute('opacity') || 1 |
||||
} |
||||
}); |
||||
$(elem).after(pline).remove(); |
||||
svgCanvas.clearSelection(); |
||||
pline.id = id; |
||||
svgCanvas.addToSelection([pline]); |
||||
elem = pline; |
||||
} |
||||
} |
||||
// Update line if it's a connector
|
||||
if(elem.getAttribute('class') == conn_sel.substr(1)) { |
||||
var start = getElem($(elem).data('c_start')); |
||||
updateConnectors([start]); |
||||
} else { |
||||
updateConnectors(); |
||||
} |
||||
}, |
||||
toolButtonStateUpdate: function(opts) { |
||||
if(opts.nostroke) { |
||||
if ($('#mode_connect').hasClass('tool_button_current')) { |
||||
clickSelect(); |
||||
} |
||||
} |
||||
$('#mode_connect') |
||||
.toggleClass('disabled',opts.nostroke); |
||||
} |
||||
}; |
||||
}); |
||||
@ -0,0 +1,101 @@ |
||||
/* |
||||
* ext-eyedropper.js |
||||
* |
||||
* Licensed under the Apache License, Version 2 |
||||
* |
||||
* Copyright(c) 2010 Jeff Schiller |
||||
* |
||||
*/ |
||||
|
||||
svgEditor.addExtension("eyedropper", function(S) { |
||||
var svgcontent = S.svgcontent, |
||||
svgns = "http://www.w3.org/2000/svg", |
||||
svgdoc = S.svgroot.parentNode.ownerDocument, |
||||
ChangeElementCommand = svgCanvas.getPrivateMethods().ChangeElementCommand, |
||||
addToHistory = svgCanvas.getPrivateMethods().addCommandToHistory, |
||||
currentStyle = {fillPaint: "red", fillOpacity: 1.0, |
||||
strokePaint: "black", strokeOpacity: 1.0,
|
||||
strokeWidth: 5, strokeDashArray: null, |
||||
opacity: 1.0, |
||||
strokeLinecap: 'butt', |
||||
strokeLinejoin: 'miter', |
||||
}; |
||||
|
||||
function getStyle(opts) { |
||||
// if we are in eyedropper mode, we don't want to disable the eye-dropper tool
|
||||
var mode = svgCanvas.getMode(); |
||||
if (mode == "eyedropper") return; |
||||
|
||||
var elem = null; |
||||
var tool = $('#tool_eyedropper'); |
||||
// enable-eye-dropper if one element is selected
|
||||
if (opts.elems.length == 1 && opts.elems[0] &&
|
||||
$.inArray(opts.elems[0].nodeName, ['svg', 'g', 'use']) == -1)
|
||||
{ |
||||
elem = opts.elems[0]; |
||||
tool.removeClass('disabled'); |
||||
// grab the current style
|
||||
currentStyle.fillPaint = elem.getAttribute("fill") || "black"; |
||||
currentStyle.fillOpacity = elem.getAttribute("fill-opacity") || 1.0; |
||||
currentStyle.strokePaint = elem.getAttribute("stroke"); |
||||
currentStyle.strokeOpacity = elem.getAttribute("stroke-opacity") || 1.0; |
||||
currentStyle.strokeWidth = elem.getAttribute("stroke-width"); |
||||
currentStyle.strokeDashArray = elem.getAttribute("stroke-dasharray"); |
||||
currentStyle.strokeLinecap = elem.getAttribute("stroke-linecap"); |
||||
currentStyle.strokeLinejoin = elem.getAttribute("stroke-linejoin"); |
||||
currentStyle.opacity = elem.getAttribute("opacity") || 1.0; |
||||
} |
||||
// disable eye-dropper tool
|
||||
else { |
||||
tool.addClass('disabled'); |
||||
} |
||||
|
||||
} |
||||
|
||||
return { |
||||
name: "eyedropper", |
||||
svgicons: "extensions/eyedropper-icon.xml", |
||||
buttons: [{ |
||||
id: "tool_eyedropper", |
||||
type: "mode", |
||||
title: "Eye Dropper Tool", |
||||
events: { |
||||
"click": function() { |
||||
svgCanvas.setMode("eyedropper"); |
||||
} |
||||
} |
||||
}], |
||||
|
||||
// if we have selected an element, grab its paint and enable the eye dropper button
|
||||
selectedChanged: getStyle, |
||||
elementChanged: getStyle, |
||||
|
||||
mouseDown: function(opts) { |
||||
var mode = svgCanvas.getMode(); |
||||
if (mode == "eyedropper") { |
||||
var e = opts.event; |
||||
var target = e.target; |
||||
if ($.inArray(target.nodeName, ['svg', 'g', 'use']) == -1) { |
||||
var changes = {}; |
||||
|
||||
var change = function(elem, attrname, newvalue) { |
||||
changes[attrname] = elem.getAttribute(attrname); |
||||
elem.setAttribute(attrname, newvalue); |
||||
}; |
||||
|
||||
if (currentStyle.fillPaint) change(target, "fill", currentStyle.fillPaint); |
||||
if (currentStyle.fillOpacity) change(target, "fill-opacity", currentStyle.fillOpacity); |
||||
if (currentStyle.strokePaint) change(target, "stroke", currentStyle.strokePaint); |
||||
if (currentStyle.strokeOpacity) change(target, "stroke-opacity", currentStyle.strokeOpacity); |
||||
if (currentStyle.strokeWidth) change(target, "stroke-width", currentStyle.strokeWidth); |
||||
if (currentStyle.strokeDashArray) change(target, "stroke-dasharray", currentStyle.strokeDashArray); |
||||
if (currentStyle.opacity) change(target, "opacity", currentStyle.opacity); |
||||
if (currentStyle.strokeLinecap) change(target, "stroke-linecap", currentStyle.strokeLinecap); |
||||
if (currentStyle.strokeLinejoin) change(target, "stroke-linejoin", currentStyle.strokeLinejoin); |
||||
|
||||
addToHistory(new ChangeElementCommand(target, changes)); |
||||
} |
||||
} |
||||
}, |
||||
}; |
||||
}); |
||||
@ -0,0 +1,277 @@ |
||||
/* |
||||
* ext-foreignobject.js |
||||
* |
||||
* Licensed under the Apache License, Version 2 |
||||
* |
||||
* Copyright(c) 2010 Jacques Distler
|
||||
* Copyright(c) 2010 Alexis Deveria
|
||||
* |
||||
*/ |
||||
|
||||
svgEditor.addExtension("foreignObject", function(S) { |
||||
var svgcontent = S.svgcontent, |
||||
addElem = S.addSvgElementFromJson, |
||||
selElems, |
||||
svgns = "http://www.w3.org/2000/svg", |
||||
xlinkns = "http://www.w3.org/1999/xlink", |
||||
xmlns = "http://www.w3.org/XML/1998/namespace", |
||||
xmlnsns = "http://www.w3.org/2000/xmlns/", |
||||
se_ns = "http://svg-edit.googlecode.com", |
||||
htmlns = "http://www.w3.org/1999/xhtml", |
||||
mathns = "http://www.w3.org/1998/Math/MathML", |
||||
editingforeign = false, |
||||
svgdoc = S.svgroot.parentNode.ownerDocument, |
||||
started, |
||||
newFO; |
||||
|
||||
|
||||
var properlySourceSizeTextArea = function(){ |
||||
// TODO: remove magic numbers here and get values from CSS
|
||||
var height = $('#svg_source_container').height() - 80; |
||||
$('#svg_source_textarea').css('height', height); |
||||
}; |
||||
|
||||
function showPanel(on) { |
||||
var fc_rules = $('#fc_rules'); |
||||
if(!fc_rules.length) { |
||||
fc_rules = $('<style id="fc_rules"><\/style>').appendTo('head'); |
||||
}
|
||||
fc_rules.text(!on?"":" #tool_topath { display: none !important; }"); |
||||
$('#foreignObject_panel').toggle(on); |
||||
} |
||||
|
||||
function toggleSourceButtons(on) { |
||||
$('#tool_source_save, #tool_source_cancel').toggle(!on); |
||||
$('#foreign_save, #foreign_cancel').toggle(on); |
||||
} |
||||
|
||||
|
||||
// Function: setForeignString(xmlString, elt)
|
||||
// This function sets the content of element elt to the input XML.
|
||||
//
|
||||
// Parameters:
|
||||
// xmlString - The XML text.
|
||||
// elt - the parent element to append to
|
||||
//
|
||||
// Returns:
|
||||
// This function returns false if the set was unsuccessful, true otherwise.
|
||||
function setForeignString(xmlString) { |
||||
var elt = selElems[0]; |
||||
try { |
||||
// convert string into XML document
|
||||
var newDoc = Utils.text2xml('<svg xmlns="'+svgns+'" xmlns:xlink="'+xlinkns+'">'+xmlString+'</svg>'); |
||||
// run it through our sanitizer to remove anything we do not support
|
||||
S.sanitizeSvg(newDoc.documentElement); |
||||
elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt); |
||||
S.call("changed", [elt]); |
||||
svgCanvas.clearSelection(); |
||||
} catch(e) { |
||||
console.log(e); |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
}; |
||||
|
||||
function showForeignEditor() { |
||||
var elt = selElems[0]; |
||||
if (!elt || editingforeign) return; |
||||
editingforeign = true; |
||||
toggleSourceButtons(true); |
||||
elt.removeAttribute('fill'); |
||||
|
||||
var str = S.svgToString(elt, 0); |
||||
$('#svg_source_textarea').val(str); |
||||
$('#svg_source_editor').fadeIn(); |
||||
properlySourceSizeTextArea(); |
||||
$('#svg_source_textarea').focus(); |
||||
} |
||||
|
||||
function setAttr(attr, val) { |
||||
svgCanvas.changeSelectedAttribute(attr, val); |
||||
S.call("changed", selElems); |
||||
} |
||||
|
||||
|
||||
return { |
||||
name: "foreignObject", |
||||
svgicons: "extensions/foreignobject-icons.xml", |
||||
buttons: [{ |
||||
id: "tool_foreign", |
||||
type: "mode", |
||||
title: "Foreign Object Tool", |
||||
events: { |
||||
'click': function() { |
||||
svgCanvas.setMode('foreign') |
||||
} |
||||
} |
||||
},{ |
||||
id: "edit_foreign", |
||||
type: "context", |
||||
panel: "foreignObject_panel", |
||||
title: "Edit ForeignObject Content", |
||||
events: { |
||||
'click': function() { |
||||
showForeignEditor(); |
||||
} |
||||
} |
||||
}], |
||||
|
||||
context_tools: [{ |
||||
type: "input", |
||||
panel: "foreignObject_panel", |
||||
title: "Change foreignObject's width", |
||||
id: "foreign_width", |
||||
label: "w", |
||||
size: 3, |
||||
events: { |
||||
change: function() { |
||||
setAttr('width', this.value); |
||||
} |
||||
} |
||||
},{ |
||||
type: "input", |
||||
panel: "foreignObject_panel", |
||||
title: "Change foreignObject's height", |
||||
id: "foreign_height", |
||||
label: "h", |
||||
events: { |
||||
change: function() { |
||||
setAttr('height', this.value); |
||||
} |
||||
} |
||||
}, { |
||||
type: "input", |
||||
panel: "foreignObject_panel", |
||||
title: "Change foreignObject's font size", |
||||
id: "foreign_font_size", |
||||
label: "font-size", |
||||
size: 2, |
||||
defval: 16, |
||||
events: { |
||||
change: function() { |
||||
setAttr('font-size', this.value); |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
], |
||||
callback: function() { |
||||
$('#foreignObject_panel').hide(); |
||||
|
||||
var endChanges = function() { |
||||
$('#svg_source_editor').hide(); |
||||
editingforeign = false; |
||||
$('#svg_source_textarea').blur(); |
||||
toggleSourceButtons(false); |
||||
} |
||||
|
||||
// TODO: Needs to be done after orig icon loads
|
||||
setTimeout(function() {
|
||||
// Create source save/cancel buttons
|
||||
var save = $('#tool_source_save').clone() |
||||
.hide().attr('id', 'foreign_save').unbind() |
||||
.appendTo("#tool_source_back").click(function() { |
||||
|
||||
if (!editingforeign) return; |
||||
|
||||
if (!setForeignString($('#svg_source_textarea').val())) { |
||||
$.confirm("Errors found. Revert to original?", function(ok) { |
||||
if(!ok) return false; |
||||
endChanges(); |
||||
}); |
||||
} else { |
||||
endChanges(); |
||||
} |
||||
// setSelectMode();
|
||||
}); |
||||
|
||||
var cancel = $('#tool_source_cancel').clone() |
||||
.hide().attr('id', 'foreign_cancel').unbind() |
||||
.appendTo("#tool_source_back").click(function() { |
||||
endChanges(); |
||||
}); |
||||
|
||||
}, 3000); |
||||
}, |
||||
mouseDown: function(opts) { |
||||
var e = opts.event; |
||||
|
||||
if(svgCanvas.getMode() == "foreign") { |
||||
|
||||
started = true; |
||||
newFO = S.addSvgElementFromJson({ |
||||
"element": "foreignObject", |
||||
"attr": { |
||||
"x": opts.start_x, |
||||
"y": opts.start_y, |
||||
"id": S.getNextId(), |
||||
"font-size": 16, //cur_text.font_size,
|
||||
"width": "48", |
||||
"height": "20", |
||||
"style": "pointer-events:inherit" |
||||
} |
||||
}); |
||||
var m = svgdoc.createElementNS(mathns, 'math'); |
||||
m.setAttributeNS(xmlnsns, 'xmlns', mathns); |
||||
m.setAttribute('display', 'inline'); |
||||
var mi = svgdoc.createElementNS(mathns, 'mi'); |
||||
mi.setAttribute('mathvariant', 'normal'); |
||||
mi.textContent = "\u03A6"; |
||||
var mo = svgdoc.createElementNS(mathns, 'mo'); |
||||
mo.textContent = "\u222A"; |
||||
var mi2 = svgdoc.createElementNS(mathns, 'mi'); |
||||
mi2.textContent = "\u2133"; |
||||
m.appendChild(mi); |
||||
m.appendChild(mo); |
||||
m.appendChild(mi2); |
||||
newFO.appendChild(m); |
||||
return { |
||||
started: true |
||||
} |
||||
} |
||||
}, |
||||
mouseUp: function(opts) { |
||||
var e = opts.event; |
||||
if(svgCanvas.getMode() == "foreign" && started) { |
||||
var attrs = $(newFO).attr(["width", "height"]); |
||||
keep = (attrs.width != 0 || attrs.height != 0); |
||||
svgCanvas.addToSelection([newFO], true); |
||||
|
||||
return { |
||||
keep: keep, |
||||
element: newFO |
||||
} |
||||
|
||||
} |
||||
|
||||
}, |
||||
selectedChanged: function(opts) { |
||||
// Use this to update the current selected elements
|
||||
selElems = opts.elems; |
||||
|
||||
var i = selElems.length; |
||||
|
||||
while(i--) { |
||||
var elem = selElems[i]; |
||||
if(elem && elem.tagName == "foreignObject") { |
||||
if(opts.selectedElement && !opts.multiselected) { |
||||
$('#foreign_font_size').val(elem.getAttribute("font-size")); |
||||
$('#foreign_width').val(elem.getAttribute("width")); |
||||
$('#foreign_height').val(elem.getAttribute("height")); |
||||
|
||||
showPanel(true); |
||||
} else { |
||||
showPanel(false); |
||||
} |
||||
} else { |
||||
showPanel(false); |
||||
} |
||||
} |
||||
}, |
||||
elementChanged: function(opts) { |
||||
var elem = opts.elems[0]; |
||||
} |
||||
}; |
||||
}); |
||||
@ -0,0 +1,78 @@ |
||||
/* |
||||
* ext-helloworld.js |
||||
* |
||||
* Licensed under the Apache License, Version 2 |
||||
* |
||||
* Copyright(c) 2010 Alexis Deveria |
||||
* |
||||
*/ |
||||
|
||||
/* |
||||
This is a very basic SVG-Edit extension. It adds a "Hello World" button in |
||||
the left panel. Clicking on the button, and then the canvas will show the |
||||
user the point on the canvas that was clicked on. |
||||
*/ |
||||
|
||||
svgEditor.addExtension("Hello World", function() { |
||||
|
||||
return { |
||||
name: "Hello World", |
||||
// For more notes on how to make an icon file, see the source of
|
||||
// the hellorworld-icon.xml
|
||||
svgicons: "extensions/helloworld-icon.xml", |
||||
|
||||
// Multiple buttons can be added in this array
|
||||
buttons: [{ |
||||
// Must match the icon ID in helloworld-icon.xml
|
||||
id: "hello_world",
|
||||
|
||||
// This indicates that the button will be added to the "mode"
|
||||
// button panel on the left side
|
||||
type: "mode",
|
||||
|
||||
// Tooltip text
|
||||
title: "Say 'Hello World'",
|
||||
|
||||
// Events
|
||||
events: { |
||||
'click': function() { |
||||
// The action taken when the button is clicked on.
|
||||
// For "mode" buttons, any other button will
|
||||
// automatically be de-pressed.
|
||||
svgCanvas.setMode("hello_world"); |
||||
} |
||||
} |
||||
}], |
||||
// This is triggered when the main mouse button is pressed down
|
||||
// on the editor canvas (not the tool panels)
|
||||
mouseDown: function() { |
||||
// Check the mode on mousedown
|
||||
if(svgCanvas.getMode() == "hello_world") { |
||||
|
||||
// The returned object must include "started" with
|
||||
// a value of true in order for mouseUp to be triggered
|
||||
return {started: true}; |
||||
} |
||||
}, |
||||
|
||||
// This is triggered from anywhere, but "started" must have been set
|
||||
// to true (see above). Note that "opts" is an object with event info
|
||||
mouseUp: function(opts) { |
||||
// Check the mode on mouseup
|
||||
if(svgCanvas.getMode() == "hello_world") { |
||||
var zoom = svgCanvas.getZoom(); |
||||
|
||||
// Get the actual coordinate by dividing by the zoom value
|
||||
var x = opts.mouse_x / zoom; |
||||
var y = opts.mouse_y / zoom; |
||||
|
||||
var text = "Hello World!\n\nYou clicked here: "
|
||||
+ x + ", " + y; |
||||
|
||||
// Show the text using the custom alert function
|
||||
$.alert(text); |
||||
} |
||||
} |
||||
}; |
||||
}); |
||||
|
||||
@ -0,0 +1,572 @@ |
||||
/* |
||||
* ext-markers.js |
||||
* |
||||
* Licensed under the Apache License, Version 2 |
||||
* |
||||
* Copyright(c) 2010 Will Schleter
|
||||
* based on ext-arrows.js by Copyright(c) 2010 Alexis Deveria |
||||
* |
||||
* This extension provides for the addition of markers to the either end |
||||
* or the middle of a line, polyline, path, polygon.
|
||||
*
|
||||
* Markers may be either a graphic or arbitary text |
||||
*
|
||||
* to simplify the coding and make the implementation as robust as possible, |
||||
* markers are not shared - every object has its own set of markers. |
||||
* this relationship is maintained by a naming convention between the |
||||
* ids of the markers and the ids of the object |
||||
*
|
||||
* The following restrictions exist for simplicty of use and programming |
||||
* objects and their markers to have the same color |
||||
* marker size is fixed |
||||
* text marker font, size, and attributes are fixed |
||||
* an application specific attribute - se_type - is added to each marker element |
||||
* to store the type of marker |
||||
*
|
||||
* TODO: |
||||
* remove some of the restrictions above |
||||
* add option for keeping text aligned to horizontal |
||||
* add support for dimension extension lines |
||||
* |
||||
*/ |
||||
|
||||
svgEditor.addExtension("Markers", function(S) { |
||||
var svgcontent = S.svgcontent, |
||||
addElem = S.addSvgElementFromJson, |
||||
selElems; |
||||
|
||||
var mtypes = ['start','mid','end']; |
||||
|
||||
var marker_prefix = 'se_marker_'; |
||||
var id_prefix = 'mkr_'; |
||||
|
||||
// note - to add additional marker types add them below with a unique id
|
||||
// and add the associated icon(s) to marker-icons.svg
|
||||
// the geometry is normallized to a 100x100 box with the origin at lower left
|
||||
// Safari did not like negative values for low left of viewBox
|
||||
// remember that the coordinate system has +y downward
|
||||
var marker_types = { |
||||
nomarker: {},
|
||||
leftarrow:
|
||||
{element:'path', attr:{d:'M0,50 L100,90 L70,50 L100,10 Z'}}, |
||||
rightarrow: |
||||
{element:'path', attr:{d:'M100,50 L0,90 L30,50 L0,10 Z'}}, |
||||
textmarker: |
||||
{element:'text', attr: {x:0, y:0,'stroke-width':0,'stroke':'none','font-size':75,'font-family':'serif','text-anchor':'left', |
||||
'xml:space': 'preserve'}}, |
||||
forwardslash: |
||||
{element:'path', attr:{d:'M30,100 L70,0'}}, |
||||
reverseslash: |
||||
{element:'path', attr:{d:'M30,0 L70,100'}}, |
||||
verticalslash: |
||||
{element:'path', attr:{d:'M50,0 L50,100'}}, |
||||
box: |
||||
{element:'path', attr:{d:'M20,20 L20,80 L80,80 L80,20 Z'}}, |
||||
star: |
||||
{element:'path', attr:{d:'M10,30 L90,30 L20,90 L50,10 L80,90 Z'}}, |
||||
xmark: |
||||
{element:'path', attr:{d:'M20,80 L80,20 M80,80 L20,20'}}, |
||||
triangle: |
||||
{element:'path', attr:{d:'M10,80 L50,20 L80,80 Z'}}, |
||||
mcircle: |
||||
{element:'circle', attr:{r:30, cx:50, cy:50}},
|
||||
} |
||||
|
||||
|
||||
var lang_list = { |
||||
"en":[ |
||||
{id: "start_marker_list", title: "Select start marker type" }, |
||||
{id: "mid_marker_list", title: "Select mid marker type" }, |
||||
{id: "end_marker_list", title: "Select end marker type" }, |
||||
{id: "nomarker", title: "No Marker" }, |
||||
{id: "leftarrow", title: "Left Arrow" }, |
||||
{id: "rightarrow", title: "Right Arrow" }, |
||||
{id: "textmarker", title: "Text Marker" }, |
||||
{id: "forwardslash", title: "Forward Slash" }, |
||||
{id: "reverseslash", title: "Reverse Slash" }, |
||||
{id: "verticalslash", title: "Vertical Slash" }, |
||||
{id: "box", title: "Box" }, |
||||
{id: "star", title: "Star" }, |
||||
{id: "xmark", title: "X" }, |
||||
{id: "triangle", title: "Triangle" }, |
||||
{id: "mcircle", title: "Circle" }, |
||||
{id: "leftarrow_o", title: "Open Left Arrow" }, |
||||
{id: "rightarrow_o", title: "Open Right Arrow" }, |
||||
{id: "box_o", title: "Open Box" }, |
||||
{id: "star_o", title: "Open Star" }, |
||||
{id: "triangle_o", title: "Open Triangle" }, |
||||
{id: "mcircle_o", title: "Open Circle" }, |
||||
] |
||||
}; |
||||
|
||||
|
||||
// duplicate shapes to support unfilled (open) marker types with an _o suffix
|
||||
$.each(['leftarrow','rightarrow','box','star','mcircle','triangle'],function(i,v) { |
||||
marker_types[v+'_o'] = marker_types[v]; |
||||
}); |
||||
|
||||
// elem = a graphic element will have an attribute like marker-start
|
||||
// attr - marker-start, marker-mid, or marker-end
|
||||
// returns the marker element that is linked to the graphic element
|
||||
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]); |
||||
} |
||||
|
||||
//toggles context tool panel off/on
|
||||
//sets the controls with the selected element's settings
|
||||
function showPanel(on) { |
||||
$('#marker_panel').toggle(on); |
||||
|
||||
if(on) { |
||||
var el = selElems[0]; |
||||
var val; |
||||
var ci; |
||||
|
||||
$.each(mtypes, function(i, pos) { |
||||
var m=getLinked(el,"marker-"+pos); |
||||
var txtbox = $('#'+pos+'_marker'); |
||||
if (!m) { |
||||
val='\\nomarker'; |
||||
ci=val; |
||||
txtbox.hide() // hide text box
|
||||
} else { |
||||
if (!m.attributes.se_type) return; // not created by this extension
|
||||
val='\\'+m.attributes.se_type.textContent; |
||||
ci=val; |
||||
if (val=='\\textmarker') { |
||||
val=m.lastChild.textContent; |
||||
//txtbox.show(); // show text box
|
||||
} else { |
||||
txtbox.hide() // hide text box
|
||||
} |
||||
} |
||||
txtbox.val(val);
|
||||
setIcon(pos,ci); |
||||
}) |
||||
} |
||||
}
|
||||
|
||||
function addMarker(id, val) { |
||||
var txt_box_bg = '#ffffff'; |
||||
var txt_box_border = 'none'; |
||||
var txt_box_stroke_width = 0; |
||||
|
||||
var marker = S.getElem(id); |
||||
|
||||
if (marker) return; |
||||
|
||||
if (val=='' || val=='\\nomarker') return; |
||||
|
||||
var el = selElems[0];
|
||||
var color = el.getAttribute('stroke'); |
||||
//NOTE: Safari didn't like a negative value in viewBox
|
||||
//so we use a standardized 0 0 100 100
|
||||
//with 50 50 being mapped to the marker position
|
||||
var refX = 50; |
||||
var refY = 50; |
||||
var viewBox = "0 0 100 100"; |
||||
var markerWidth = 5; |
||||
var markerHeight = 5; |
||||
var strokeWidth = 10; |
||||
if (val.substr(0,1)=='\\') se_type=val.substr(1); |
||||
else se_type='textmarker'; |
||||
|
||||
if (!marker_types[se_type]) return; // an unknown type!
|
||||
|
||||
// create a generic marker
|
||||
marker = addElem({ |
||||
"element": "marker", |
||||
"attr": { |
||||
"id": id, |
||||
"markerUnits": "strokeWidth", |
||||
"orient": "auto", |
||||
"style": "pointer-events:none", |
||||
"se_type": se_type |
||||
} |
||||
}); |
||||
|
||||
if (se_type!='textmarker') { |
||||
var mel = addElem(marker_types[se_type]); |
||||
var fillcolor = color; |
||||
if (se_type.substr(-2)=='_o') fillcolor='none'; |
||||
mel.setAttribute('fill',fillcolor); |
||||
mel.setAttribute('stroke',color); |
||||
mel.setAttribute('stroke-width',strokeWidth); |
||||
marker.appendChild(mel); |
||||
} else { |
||||
var text = addElem(marker_types[se_type]); |
||||
// have to add text to get bounding box
|
||||
text.textContent = val; |
||||
var tb=text.getBBox(); |
||||
//alert( tb.x + " " + tb.y + " " + tb.width + " " + tb.height);
|
||||
var pad=1; |
||||
var bb = tb; |
||||
bb.x = 0; |
||||
bb.y = 0; |
||||
bb.width += pad*2; |
||||
bb.height += pad*2; |
||||
// shift text according to its size
|
||||
text.setAttribute('x', pad); |
||||
text.setAttribute('y', bb.height - pad - tb.height/4); // kludge?
|
||||
text.setAttribute('fill',color); |
||||
refX = bb.width/2+pad; |
||||
refY = bb.height/2+pad; |
||||
viewBox = bb.x + " " + bb.y + " " + bb.width + " " + bb.height; |
||||
markerWidth =bb.width/10; |
||||
markerHeight = bb.height/10; |
||||
|
||||
var box = addElem({ |
||||
"element": "rect", |
||||
"attr": { |
||||
"x": bb.x, |
||||
"y": bb.y, |
||||
"width": bb.width, |
||||
"height": bb.height, |
||||
"fill": txt_box_bg, |
||||
"stroke": txt_box_border, |
||||
"stroke-width": txt_box_stroke_width |
||||
} |
||||
}); |
||||
marker.setAttribute("orient",0); |
||||
marker.appendChild(box); |
||||
marker.appendChild(text); |
||||
}
|
||||
|
||||
marker.setAttribute("viewBox",viewBox); |
||||
marker.setAttribute("markerWidth", markerWidth); |
||||
marker.setAttribute("markerHeight", markerHeight); |
||||
marker.setAttribute("refX", refX); |
||||
marker.setAttribute("refY", refY); |
||||
S.findDefs().appendChild(marker); |
||||
|
||||
return marker; |
||||
} |
||||
|
||||
|
||||
function setMarker() { |
||||
var poslist={'start_marker':'start','mid_marker':'mid','end_marker':'end'}; |
||||
var pos = poslist[this.id]; |
||||
var marker_name = 'marker-'+pos; |
||||
var val = this.value; |
||||
var el = selElems[0]; |
||||
var marker = getLinked(el, marker_name); |
||||
if (marker) $(marker).remove(); |
||||
el.removeAttribute(marker_name); |
||||
if (val=='') val='\\nomarker'; |
||||
if (val=='\\nomarker') { |
||||
setIcon(pos,val); |
||||
S.call("changed", selElems); |
||||
return; |
||||
} |
||||
// Set marker on element
|
||||
var id = marker_prefix + pos + '_' + el.id; |
||||
addMarker(id, val); |
||||
svgCanvas.changeSelectedAttribute(marker_name, "url(#" + id + ")"); |
||||
if (el.tagName == "line" && pos=='mid') el=convertline(el); |
||||
S.call("changed", selElems); |
||||
setIcon(pos,val); |
||||
} |
||||
|
||||
function convertline(elem) { |
||||
// this routine came from the connectors extension
|
||||
// it is needed because midpoint markers don't work with line elements
|
||||
if (!(elem.tagName == "line")) return elem; |
||||
|
||||
// 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", |
||||
"attr": { |
||||
"points": (x1+','+y1+ mid_pt +x2+','+y2), |
||||
"stroke": elem.getAttribute('stroke'), |
||||
"stroke-width": elem.getAttribute('stroke-width'), |
||||
"fill": "none", |
||||
"opacity": elem.getAttribute('opacity') || 1 |
||||
} |
||||
}); |
||||
$.each(mtypes, function(i, pos) { // get any existing marker definitions
|
||||
var nam = 'marker-'+pos; |
||||
var m = elem.getAttribute(nam); |
||||
if (m) pline.setAttribute(nam,elem.getAttribute(nam)); |
||||
}); |
||||
|
||||
var batchCmd = new S.BatchCommand(); |
||||
batchCmd.addSubCommand(new S.RemoveElementCommand(elem, elem.parentNode)); |
||||
batchCmd.addSubCommand(new S.InsertElementCommand(pline)); |
||||
|
||||
$(elem).after(pline).remove(); |
||||
svgCanvas.clearSelection(); |
||||
pline.id = id; |
||||
svgCanvas.addToSelection([pline]); |
||||
S.addCommandToHistory(batchCmd); |
||||
return pline; |
||||
} |
||||
|
||||
// called when the main system modifies an object
|
||||
// this routine changes the associated markers to be the same color
|
||||
function colorChanged(elem) { |
||||
var color = elem.getAttribute('stroke'); |
||||
|
||||
$.each(mtypes, function(i, pos) { |
||||
var marker = getLinked(elem, 'marker-'+pos); |
||||
if (!marker) return; |
||||
if (!marker.attributes.se_type) return; //not created by this extension
|
||||
var ch = marker.lastElementChild; |
||||
if (!ch) return; |
||||
var curfill = ch.getAttribute("fill"); |
||||
var curstroke = ch.getAttribute("stroke") |
||||
if (curfill && curfill!='none') ch.setAttribute("fill",color); |
||||
if (curstroke && curstroke!='none') ch.setAttribute("stroke",color); |
||||
}); |
||||
} |
||||
|
||||
// called when the main system creates or modifies an object
|
||||
// primary purpose is create new markers for cloned objects
|
||||
function updateReferences(el) { |
||||
$.each(mtypes, function (i,pos) { |
||||
var id = marker_prefix + pos + '_' + el.id; |
||||
var marker_name = 'marker-'+pos; |
||||
var marker = getLinked(el, marker_name); |
||||
if (!marker || !marker.attributes.se_type) return; //not created by this extension
|
||||
var url = el.getAttribute(marker_name); |
||||
if (url) { |
||||
var len = el.id.length; |
||||
var linkid = url.substr(-len-1,len); |
||||
if (el.id != linkid) { |
||||
var val = $('#'+pos+'_marker').attr('value'); |
||||
addMarker(id, val); |
||||
svgCanvas.changeSelectedAttribute(marker_name, "url(#" + id + ")"); |
||||
if (el.tagName == "line" && pos=='mid') el=convertline(el); |
||||
S.call("changed", selElems); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
// simulate a change event a text box that stores the current element's marker type
|
||||
function triggerTextEntry(pos,val) { |
||||
$('#'+pos+'_marker').val(val); |
||||
$('#'+pos+'_marker').change(); |
||||
var txtbox = $('#'+pos+'_marker'); |
||||
//if (val.substr(0,1)=='\\') txtbox.hide();
|
||||
//else txtbox.show();
|
||||
} |
||||
|
||||
function setIcon(pos,id) { |
||||
if (id.substr(0,1)!='\\') id='\\textmarker' |
||||
var ci = '#'+id_prefix+pos+'_'+id.substr(1); |
||||
svgEditor.setIcon('#cur_' + pos +'_marker_list', $(ci).children()); |
||||
$(ci).addClass('current').siblings().removeClass('current'); |
||||
} |
||||
|
||||
function setMarkerSet(obj) { |
||||
var parts = this.id.split('_'); |
||||
var set = parts[2]; |
||||
switch (set) { |
||||
case 'off': |
||||
triggerTextEntry('start','\\nomarker'); |
||||
triggerTextEntry('mid','\\nomarker'); |
||||
triggerTextEntry('end','\\nomarker'); |
||||
break; |
||||
case 'dimension': |
||||
triggerTextEntry('start','\\leftarrow'); |
||||
triggerTextEntry('end','\\rightarrow'); |
||||
showTextPrompt('mid'); |
||||
break; |
||||
case 'label': |
||||
triggerTextEntry('mid','\\nomarker'); |
||||
triggerTextEntry('end','\\rightarrow'); |
||||
showTextPrompt('start'); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
function showTextPrompt(pos) { |
||||
var def = $('#'+pos+'_marker').val(); |
||||
if (def.substr(0,1)=='\\') def=''; |
||||
$.prompt('Enter text for ' + pos + ' marker', def , function(txt) { if (txt) triggerTextEntry(pos,txt); }); |
||||
} |
||||
|
||||
// callback function for a toolbar button click
|
||||
function setArrowFromButton(obj) { |
||||
|
||||
var parts = this.id.split('_'); |
||||
var pos = parts[1]; |
||||
var val = parts[2]; |
||||
if (parts[3]) val+='_'+parts[3]; |
||||
|
||||
if (val!='textmarker') { |
||||
triggerTextEntry(pos,'\\'+val); |
||||
} else { |
||||
showTextPrompt(pos); |
||||
} |
||||
} |
||||
|
||||
function getTitle(lang,id) { |
||||
var list = lang_list[lang]; |
||||
for (var i in list) { |
||||
if (list[i].id==id) return list[i].title; |
||||
} |
||||
return id; |
||||
} |
||||
|
||||
|
||||
// build the toolbar button array from the marker definitions
|
||||
// TODO: need to incorporate language specific titles
|
||||
function buildButtonList() { |
||||
var buttons=[]; |
||||
var i=0; |
||||
/* |
||||
buttons.push({ |
||||
id:id_prefix + 'markers_off', |
||||
title:'Turn off all markers', |
||||
type:'context', |
||||
events: { 'click': setMarkerSet }, |
||||
panel: 'marker_panel' |
||||
}); |
||||
buttons.push({ |
||||
id:id_prefix + 'markers_dimension', |
||||
title:'Dimension', |
||||
type:'context', |
||||
events: { 'click': setMarkerSet }, |
||||
panel: 'marker_panel' |
||||
}); |
||||
buttons.push({ |
||||
id:id_prefix + 'markers_label', |
||||
title:'Label', |
||||
type:'context', |
||||
events: { 'click': setMarkerSet }, |
||||
panel: 'marker_panel' |
||||
}); |
||||
*/ |
||||
$.each(mtypes,function(k,pos) { |
||||
var listname = pos + "_marker_list"; |
||||
var def = true; |
||||
$.each(marker_types,function(id,v) { |
||||
var title = getTitle('en',id); |
||||
buttons.push({ |
||||
id:id_prefix + pos + "_" + id, |
||||
svgicon:id, |
||||
title:title, |
||||
type:'context', |
||||
events: { 'click': setArrowFromButton }, |
||||
panel:'marker_panel', |
||||
list: listname, |
||||
isDefault: def |
||||
}); |
||||
def = false; |
||||
}); |
||||
}); |
||||
return buttons; |
||||
} |
||||
|
||||
return { |
||||
name: "Markers", |
||||
svgicons: "extensions/markers-icons.xml", |
||||
buttons: buildButtonList(), |
||||
context_tools: [ |
||||
{ |
||||
type: "input", |
||||
panel: "marker_panel", |
||||
title: "Start marker", |
||||
id: "start_marker", |
||||
label: "s", |
||||
size: 3, |
||||
events: { change: setMarker } |
||||
},{ |
||||
type: "button-select", |
||||
panel: "marker_panel", |
||||
title: getTitle('en','start_marker_list'), |
||||
id: "start_marker_list", |
||||
colnum: 3, |
||||
events: { change: setArrowFromButton } |
||||
},{ |
||||
type: "input", |
||||
panel: "marker_panel", |
||||
title: "Middle marker", |
||||
id: "mid_marker", |
||||
label: "m", |
||||
defval: "", |
||||
size: 3, |
||||
events: { change: setMarker } |
||||
},{ |
||||
type: "button-select", |
||||
panel: "marker_panel", |
||||
title: getTitle('en','mid_marker_list'), |
||||
id: "mid_marker_list", |
||||
colnum: 3, |
||||
events: { change: setArrowFromButton } |
||||
},{ |
||||
type: "input", |
||||
panel: "marker_panel", |
||||
title: "End marker", |
||||
id: "end_marker", |
||||
label: "e", |
||||
size: 3, |
||||
events: { change: setMarker } |
||||
},{ |
||||
type: "button-select", |
||||
panel: "marker_panel", |
||||
title: getTitle('en','end_marker_list'), |
||||
id: "end_marker_list", |
||||
colnum: 3, |
||||
events: { change: setArrowFromButton } |
||||
} ], |
||||
callback: function() { |
||||
$('#marker_panel').addClass('toolset').hide(); |
||||
|
||||
}, |
||||
addLangData: function(lang) { |
||||
return { data: lang_list[lang] }; |
||||
}, |
||||
|
||||
selectedChanged: function(opts) { |
||||
// Use this to update the current selected elements
|
||||
//console.log('selectChanged',opts);
|
||||
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) {
|
||||
//console.log('elementChanged',opts);
|
||||
var elem = opts.elems[0]; |
||||
if(elem && ( |
||||
elem.getAttribute("marker-start") || |
||||
elem.getAttribute("marker-mid") || |
||||
elem.getAttribute("marker-end") |
||||
)) { |
||||
colorChanged(elem); |
||||
updateReferences(elem); |
||||
} |
||||
changing_flag = false; |
||||
} |
||||
}; |
||||
}); |
||||
@ -0,0 +1,179 @@ |
||||
/* |
||||
* ext-server_opensave.js |
||||
* |
||||
* Licensed under the Apache License, Version 2 |
||||
* |
||||
* Copyright(c) 2010 Alexis Deveria |
||||
* |
||||
*/ |
||||
|
||||
svgEditor.addExtension("server_opensave", { |
||||
callback: function() { |
||||
|
||||
var save_svg_action = 'extensions/filesave.php'; |
||||
var save_png_action = 'extensions/filesave.php'; |
||||
|
||||
// Create upload target (hidden iframe)
|
||||
var target = $('<iframe name="output_frame" src="#"/>').hide().appendTo('body'); |
||||
|
||||
svgEditor.setCustomHandlers({ |
||||
save: function(win, data) { |
||||
var svg = '<?xml version="1.0"?>' + data; |
||||
|
||||
var title = svgCanvas.getDocumentTitle(); |
||||
var filename = title.replace(/[^a-z0-9\.\_\-]+/gi, '_'); |
||||
|
||||
var form = $('<form>').attr({ |
||||
method: 'post', |
||||
action: save_svg_action, |
||||
target: 'output_frame' |
||||
}) .append('<input type="hidden" name="output_svg" value="' + encodeURI(svg) + '">') |
||||
.append('<input type="hidden" name="filename" value="' + filename + '">') |
||||
.appendTo('body') |
||||
.submit().remove(); |
||||
}, |
||||
pngsave: function(win, data) { |
||||
var issues = data.issues; |
||||
|
||||
if(!$('#export_canvas').length) { |
||||
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body'); |
||||
} |
||||
var c = $('#export_canvas')[0]; |
||||
|
||||
c.width = svgCanvas.contentW; |
||||
c.height = svgCanvas.contentH; |
||||
canvg(c, data.svg); |
||||
var datauri = c.toDataURL('image/png'); |
||||
|
||||
var uiStrings = svgEditor.uiStrings; |
||||
var note = ''; |
||||
|
||||
// Check if there's issues
|
||||
if(issues.length) { |
||||
var pre = "\n \u2022 "; |
||||
note += ("\n\n" + pre + issues.join(pre)); |
||||
}
|
||||
|
||||
if(note.length) { |
||||
alert(note); |
||||
} |
||||
|
||||
var title = svgCanvas.getDocumentTitle(); |
||||
var filename = title.replace(/[^a-z0-9\.\_\-]+/gi, '_'); |
||||
|
||||
var form = $('<form>').attr({ |
||||
method: 'post', |
||||
action: save_png_action, |
||||
target: 'output_frame' |
||||
}) .append('<input type="hidden" name="output_png" value="' + datauri + '">') |
||||
.append('<input type="hidden" name="filename" value="' + filename + '">') |
||||
.appendTo('body') |
||||
.submit().remove(); |
||||
|
||||
|
||||
} |
||||
}); |
||||
|
||||
// Do nothing if client support is found
|
||||
if(window.FileReader) return; |
||||
|
||||
var cancelled = false; |
||||
|
||||
// Change these to appropriate script file
|
||||
var open_svg_action = 'extensions/fileopen.php?type=load_svg'; |
||||
var import_svg_action = 'extensions/fileopen.php?type=import_svg'; |
||||
var import_img_action = 'extensions/fileopen.php?type=import_img'; |
||||
|
||||
// Set up function for PHP uploader to use
|
||||
svgEditor.processFile = function(str64, type) { |
||||
if(cancelled) { |
||||
cancelled = false; |
||||
return; |
||||
} |
||||
|
||||
$('#dialog_box').hide(); |
||||
|
||||
if(type != 'import_img') { |
||||
var xmlstr = svgCanvas.Utils.decode64(str64); |
||||
} |
||||
|
||||
switch ( type ) { |
||||
case 'load_svg': |
||||
svgCanvas.clear(); |
||||
svgCanvas.setSvgString(xmlstr); |
||||
svgEditor.updateCanvas(); |
||||
break; |
||||
case 'import_svg': |
||||
svgCanvas.importSvgString(xmlstr); |
||||
svgEditor.updateCanvas();
|
||||
break; |
||||
case 'import_img': |
||||
svgCanvas.setGoodImage(str64); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
// Create upload form
|
||||
var open_svg_form = $('<form>'); |
||||
open_svg_form.attr({ |
||||
enctype: 'multipart/form-data', |
||||
method: 'post', |
||||
action: open_svg_action, |
||||
target: 'output_frame' |
||||
}); |
||||
|
||||
// Create import form
|
||||
var import_svg_form = open_svg_form.clone().attr('action', import_svg_action); |
||||
|
||||
// Create image form
|
||||
var import_img_form = open_svg_form.clone().attr('action', import_img_action); |
||||
|
||||
// It appears necessory to rebuild this input every time a file is
|
||||
// selected so the same file can be picked and the change event can fire.
|
||||
function rebuildInput(form) { |
||||
form.empty(); |
||||
var inp = $('<input type="file" name="svg_file">').appendTo(form); |
||||
|
||||
|
||||
function submit() { |
||||
// This submits the form, which returns the file data using svgEditor.uploadSVG
|
||||
form.submit(); |
||||
|
||||
rebuildInput(form); |
||||
$.process_cancel("Uploading...", function() { |
||||
cancelled = true; |
||||
$('#dialog_box').hide(); |
||||
}); |
||||
} |
||||
|
||||
if(form[0] == open_svg_form[0]) { |
||||
inp.change(function() { |
||||
// This takes care of the "are you sure" dialog box
|
||||
svgEditor.openPrep(function(ok) { |
||||
if(!ok) { |
||||
rebuildInput(form); |
||||
return; |
||||
} |
||||
submit(); |
||||
}); |
||||
}); |
||||
} else { |
||||
inp.change(function() { |
||||
// This submits the form, which returns the file data using svgEditor.uploadSVG
|
||||
submit(); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
// Create the input elements
|
||||
rebuildInput(open_svg_form); |
||||
rebuildInput(import_svg_form); |
||||
rebuildInput(import_img_form); |
||||
|
||||
// Add forms to buttons
|
||||
$("#tool_open").show().prepend(open_svg_form); |
||||
$("#tool_import").show().prepend(import_svg_form); |
||||
$("#tool_image").prepend(import_img_form); |
||||
} |
||||
}); |
||||
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 718 B |
@ -0,0 +1,31 @@ |
||||
<!doctype html> |
||||
<?php |
||||
/* |
||||
* fileopen.php |
||||
* To be used with ext-server_opensave.js for SVG-edit |
||||
* |
||||
* Licensed under the Apache License, Version 2 |
||||
* |
||||
* Copyright(c) 2010 Alexis Deveria |
||||
* |
||||
*/ |
||||
// Very minimal PHP file, all we do is Base64 encode the uploaded file and |
||||
// return it to the editor |
||||
|
||||
$file = $_FILES['svg_file']['tmp_name']; |
||||
|
||||
$output = file_get_contents($file); |
||||
|
||||
$type = $_REQUEST['type']; |
||||
|
||||
$prefix = ''; |
||||
|
||||
// Make Data URL prefix for import image |
||||
if($type == 'import_img') { |
||||
$info = getimagesize($file); |
||||
$prefix = 'data:' . $info['mime'] . ';base64,'; |
||||
} |
||||
?> |
||||
<script> |
||||
window.top.window.svgEditor.processFile("<?php echo $prefix . base64_encode($output); ?>", "<?php echo $type ?>");
|
||||
</script> |
||||
@ -0,0 +1,44 @@ |
||||
<?php |
||||
/* |
||||
* filesave.php |
||||
* To be used with ext-server_opensave.js for SVG-edit |
||||
* |
||||
* Licensed under the Apache License, Version 2 |
||||
* |
||||
* Copyright(c) 2010 Alexis Deveria |
||||
* |
||||
*/ |
||||
|
||||
if(!isset($_POST['output_svg']) && !isset($_POST['output_png'])) { |
||||
die('post fail'); |
||||
} |
||||
|
||||
$file = ''; |
||||
|
||||
$suffix = isset($_POST['output_svg'])?'.svg':'.png'; |
||||
|
||||
if(isset($_POST['filename']) && strlen($_POST['filename']) > 0) { |
||||
$file = $_POST['filename'] . $suffix; |
||||
} else { |
||||
$file = 'image' . $suffix; |
||||
} |
||||
|
||||
if($suffix == '.svg') { |
||||
$mime = 'image/svg+xml'; |
||||
$contents = rawurldecode($_POST['output_svg']); |
||||
} else { |
||||
$mime = 'image/png'; |
||||
$contents = $_POST['output_png']; |
||||
$pos = (strpos($contents, 'base64,') + 7); |
||||
$contents = base64_decode(substr($contents, $pos)); |
||||
} |
||||
|
||||
header("Cache-Control: public"); |
||||
header("Content-Description: File Transfer"); |
||||
header("Content-Disposition: attachment; filename=" . $file); |
||||
header("Content-Type: " . $mime); |
||||
header("Content-Transfer-Encoding: binary"); |
||||
|
||||
echo $contents; |
||||
|
||||
?> |
||||
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
@ -0,0 +1,61 @@ |
||||
filename origin |
||||
|
||||
align-bottom.png http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/actions/align-vertical-bottom.png |
||||
align-bottom.svg http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/actions/align-vertical-bottom.svg |
||||
align-center.png http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/actions/align-horizontal-center.png |
||||
align-center.svg http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/actions/align-horizontal-center.svg |
||||
align-left.png http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/actions/align-horizontal-left.png |
||||
align-left.svg http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/actions/align-horizontal-left.svg |
||||
align-middle.png http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/actions/align-vertical-center.png |
||||
align-middle.svg http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/actions/align-vertical-center.svg |
||||
align-right.png http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/actions/align-horizontal-right.png |
||||
align-right.svg http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/actions/align-horizontal-right.svg |
||||
align-top.png http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/actions/align-vertical-top.png |
||||
align-top.svg http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/actions/align-vertical-top.svg |
||||
bold.png |
||||
cancel.png |
||||
circle.png |
||||
clear.png |
||||
clone.png |
||||
copy.png |
||||
cut.png |
||||
delete.png |
||||
document-properties.png |
||||
dropdown.gif |
||||
ellipse.png |
||||
eye.png |
||||
flyouth.png |
||||
flyup.gif |
||||
freehand-circle.png |
||||
freehand-square.png |
||||
go-down.png |
||||
go-up.png |
||||
image.png |
||||
italic.png |
||||
line.png |
||||
logo.png |
||||
logo.svg |
||||
move_bottom.png |
||||
move_top.png |
||||
none.png |
||||
open.png |
||||
paste.png |
||||
path.png |
||||
polygon.png http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/tools/draw-polygon.png |
||||
polygon.svg http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/tools/draw-polygon.svg |
||||
rect.png |
||||
redo.png |
||||
rotate.png |
||||
save.png |
||||
select.png |
||||
sep.png |
||||
shape_group.png |
||||
shape_ungroup.png |
||||
source.png |
||||
square.png |
||||
text.png http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/tools/draw-text.png |
||||
text.svg http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/tools/draw-text.svg |
||||
undo.png |
||||
view-refresh.png |
||||
wave.png |
||||
zoom.png http://tango.freedesktop.org/static/cvs/tango-art-libre/22x22/tools/page-magnifier.png |
||||
|
After Width: | Height: | Size: 291 B |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 449 B |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 305 B |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 459 B |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 339 B |
|
After Width: | Height: | Size: 8.4 KiB |
|
After Width: | Height: | Size: 287 B |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 812 B |
|
After Width: | Height: | Size: 715 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 852 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 663 B |
|
After Width: | Height: | Size: 688 B |
|
After Width: | Height: | Size: 49 B |
|
After Width: | Height: | Size: 811 B |
|
After Width: | Height: | Size: 750 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 109 B |
|
After Width: | Height: | Size: 48 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 903 B |
|
After Width: | Height: | Size: 683 B |
|
After Width: | Height: | Size: 652 B |
|
After Width: | Height: | Size: 900 B |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 919 B |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 737 B |
|
After Width: | Height: | Size: 663 B |
|
After Width: | Height: | Size: 571 B |
|
After Width: | Height: | Size: 589 B |
|
After Width: | Height: | Size: 136 B |
|
After Width: | Height: | Size: 919 B |
|
After Width: | Height: | Size: 906 B |
|
After Width: | Height: | Size: 854 B |
|
After Width: | Height: | Size: 881 B |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 404 B |
|
After Width: | Height: | Size: 921 B |
|
After Width: | Height: | Size: 980 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 712 B |
|
After Width: | Height: | Size: 828 B |
|
After Width: | Height: | Size: 93 B |
|
After Width: | Height: | Size: 553 B |
|
After Width: | Height: | Size: 666 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 422 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 912 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 466 B |
|
After Width: | Height: | Size: 1.2 KiB |
@ -0,0 +1,202 @@ |
||||
|
||||
Apache License |
||||
Version 2.0, January 2004 |
||||
http://www.apache.org/licenses/ |
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
||||
|
||||
1. Definitions. |
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, |
||||
and distribution as defined by Sections 1 through 9 of this document. |
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by |
||||
the copyright owner that is granting the License. |
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all |
||||
other entities that control, are controlled by, or are under common |
||||
control with that entity. For the purposes of this definition, |
||||
"control" means (i) the power, direct or indirect, to cause the |
||||
direction or management of such entity, whether by contract or |
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
||||
outstanding shares, or (iii) beneficial ownership of such entity. |
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity |
||||
exercising permissions granted by this License. |
||||
|
||||
"Source" form shall mean the preferred form for making modifications, |
||||
including but not limited to software source code, documentation |
||||
source, and configuration files. |
||||
|
||||
"Object" form shall mean any form resulting from mechanical |
||||
transformation or translation of a Source form, including but |
||||
not limited to compiled object code, generated documentation, |
||||
and conversions to other media types. |
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or |
||||
Object form, made available under the License, as indicated by a |
||||
copyright notice that is included in or attached to the work |
||||
(an example is provided in the Appendix below). |
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object |
||||
form, that is based on (or derived from) the Work and for which the |
||||
editorial revisions, annotations, elaborations, or other modifications |
||||
represent, as a whole, an original work of authorship. For the purposes |
||||
of this License, Derivative Works shall not include works that remain |
||||
separable from, or merely link (or bind by name) to the interfaces of, |
||||
the Work and Derivative Works thereof. |
||||
|
||||
"Contribution" shall mean any work of authorship, including |
||||
the original version of the Work and any modifications or additions |
||||
to that Work or Derivative Works thereof, that is intentionally |
||||
submitted to Licensor for inclusion in the Work by the copyright owner |
||||
or by an individual or Legal Entity authorized to submit on behalf of |
||||
the copyright owner. For the purposes of this definition, "submitted" |
||||
means any form of electronic, verbal, or written communication sent |
||||
to the Licensor or its representatives, including but not limited to |
||||
communication on electronic mailing lists, source code control systems, |
||||
and issue tracking systems that are managed by, or on behalf of, the |
||||
Licensor for the purpose of discussing and improving the Work, but |
||||
excluding communication that is conspicuously marked or otherwise |
||||
designated in writing by the copyright owner as "Not a Contribution." |
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity |
||||
on behalf of whom a Contribution has been received by Licensor and |
||||
subsequently incorporated within the Work. |
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of |
||||
this License, each Contributor hereby grants to You a perpetual, |
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
copyright license to reproduce, prepare Derivative Works of, |
||||
publicly display, publicly perform, sublicense, and distribute the |
||||
Work and such Derivative Works in Source or Object form. |
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of |
||||
this License, each Contributor hereby grants to You a perpetual, |
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
||||
(except as stated in this section) patent license to make, have made, |
||||
use, offer to sell, sell, import, and otherwise transfer the Work, |
||||
where such license applies only to those patent claims licensable |
||||
by such Contributor that are necessarily infringed by their |
||||
Contribution(s) alone or by combination of their Contribution(s) |
||||
with the Work to which such Contribution(s) was submitted. If You |
||||
institute patent litigation against any entity (including a |
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work |
||||
or a Contribution incorporated within the Work constitutes direct |
||||
or contributory patent infringement, then any patent licenses |
||||
granted to You under this License for that Work shall terminate |
||||
as of the date such litigation is filed. |
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the |
||||
Work or Derivative Works thereof in any medium, with or without |
||||
modifications, and in Source or Object form, provided that You |
||||
meet the following conditions: |
||||
|
||||
(a) You must give any other recipients of the Work or |
||||
Derivative Works a copy of this License; and |
||||
|
||||
(b) You must cause any modified files to carry prominent notices |
||||
stating that You changed the files; and |
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works |
||||
that You distribute, all copyright, patent, trademark, and |
||||
attribution notices from the Source form of the Work, |
||||
excluding those notices that do not pertain to any part of |
||||
the Derivative Works; and |
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its |
||||
distribution, then any Derivative Works that You distribute must |
||||
include a readable copy of the attribution notices contained |
||||
within such NOTICE file, excluding those notices that do not |
||||
pertain to any part of the Derivative Works, in at least one |
||||
of the following places: within a NOTICE text file distributed |
||||
as part of the Derivative Works; within the Source form or |
||||
documentation, if provided along with the Derivative Works; or, |
||||
within a display generated by the Derivative Works, if and |
||||
wherever such third-party notices normally appear. The contents |
||||
of the NOTICE file are for informational purposes only and |
||||
do not modify the License. You may add Your own attribution |
||||
notices within Derivative Works that You distribute, alongside |
||||
or as an addendum to the NOTICE text from the Work, provided |
||||
that such additional attribution notices cannot be construed |
||||
as modifying the License. |
||||
|
||||
You may add Your own copyright statement to Your modifications and |
||||
may provide additional or different license terms and conditions |
||||
for use, reproduction, or distribution of Your modifications, or |
||||
for any such Derivative Works as a whole, provided Your use, |
||||
reproduction, and distribution of the Work otherwise complies with |
||||
the conditions stated in this License. |
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise, |
||||
any Contribution intentionally submitted for inclusion in the Work |
||||
by You to the Licensor shall be under the terms and conditions of |
||||
this License, without any additional terms or conditions. |
||||
Notwithstanding the above, nothing herein shall supersede or modify |
||||
the terms of any separate license agreement you may have executed |
||||
with Licensor regarding such Contributions. |
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade |
||||
names, trademarks, service marks, or product names of the Licensor, |
||||
except as required for reasonable and customary use in describing the |
||||
origin of the Work and reproducing the content of the NOTICE file. |
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or |
||||
agreed to in writing, Licensor provides the Work (and each |
||||
Contributor provides its Contributions) on an "AS IS" BASIS, |
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
||||
implied, including, without limitation, any warranties or conditions |
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
||||
PARTICULAR PURPOSE. You are solely responsible for determining the |
||||
appropriateness of using or redistributing the Work and assume any |
||||
risks associated with Your exercise of permissions under this License. |
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory, |
||||
whether in tort (including negligence), contract, or otherwise, |
||||
unless required by applicable law (such as deliberate and grossly |
||||
negligent acts) or agreed to in writing, shall any Contributor be |
||||
liable to You for damages, including any direct, indirect, special, |
||||
incidental, or consequential damages of any character arising as a |
||||
result of this License or out of the use or inability to use the |
||||
Work (including but not limited to damages for loss of goodwill, |
||||
work stoppage, computer failure or malfunction, or any and all |
||||
other commercial damages or losses), even if such Contributor |
||||
has been advised of the possibility of such damages. |
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing |
||||
the Work or Derivative Works thereof, You may choose to offer, |
||||
and charge a fee for, acceptance of support, warranty, indemnity, |
||||
or other liability obligations and/or rights consistent with this |
||||
License. However, in accepting such obligations, You may act only |
||||
on Your own behalf and on Your sole responsibility, not on behalf |
||||
of any other Contributor, and only if You agree to indemnify, |
||||
defend, and hold each Contributor harmless for any liability |
||||
incurred by, or claims asserted against, such Contributor by reason |
||||
of your accepting any such warranty or additional liability. |
||||
|
||||
END OF TERMS AND CONDITIONS |
||||
|
||||
APPENDIX: How to apply the Apache License to your work. |
||||
|
||||
To apply the Apache License to your work, attach the following |
||||
boilerplate notice, with the fields enclosed by brackets "[]" |
||||
replaced with your own identifying information. (Don't include |
||||
the brackets!) The text should be enclosed in the appropriate |
||||
comment syntax for the file format. We also recommend that a |
||||
file or class name and description of purpose be included on the |
||||
same "printed page" as the copyright notice for easier |
||||
identification within third-party archives. |
||||
|
||||
Copyright [yyyy] [name of copyright owner] |
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
you may not use this file except in compliance with the License. |
||||
You may obtain a copy of the License at |
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
||||
Unless required by applicable law or agreed to in writing, software |
||||
distributed under the License is distributed on an "AS IS" BASIS, |
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
See the License for the specific language governing permissions and |
||||
limitations under the License. |
||||
@ -0,0 +1,3 @@ |
||||
jGraduate - A jQuery plugin for picking gradients |
||||
|
||||
Licensed under the Apache License 2. See LICENSE for more information. |
||||
@ -0,0 +1,270 @@ |
||||
/* |
||||
* jGraduate Default CSS |
||||
* |
||||
* Copyright (c) 2009 Jeff Schiller |
||||
* |
||||
* Licensed under the Apache License Version 2 |
||||
*/ |
||||
|
||||
h2.jGraduate_Title { |
||||
font-family: Arial, Helvetica, Sans-Serif; |
||||
font-size: 11px !important; |
||||
font-weight: bold; |
||||
margin: -13px 0px 0px 0px; |
||||
padding: 0px; |
||||
text-align: center; |
||||
} |
||||
|
||||
.jGraduate_Picker { |
||||
font-family: Arial, Helvetica, Sans-Serif; |
||||
font-size: 12px; |
||||
border-style: solid; |
||||
border-color: lightgrey black black lightgrey; |
||||
border-width: 1px; |
||||
background-color: #EFEFEF; |
||||
position: absolute; |
||||
padding: 10px; |
||||
} |
||||
|
||||
.jGraduate_tabs li { |
||||
background-color: #ccc; |
||||
display: inline; |
||||
border: solid 1px grey; |
||||
padding: 3px; |
||||
margin: 2px; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
li.jGraduate_tab_current { |
||||
background-color: #EFEFEF; |
||||
display: inline; |
||||
padding: 3px; |
||||
margin: 2px; |
||||
border: solid 1px black; |
||||
cursor: pointer; |
||||
} |
||||
|
||||
.jGraduate_colPick { |
||||
display: none; |
||||
} |
||||
|
||||
.jGraduate_lgPick { |
||||
display: none; |
||||
border: outset 1px #666; |
||||
padding: 10px 7px 5px 5px; |
||||
overflow: auto; |
||||
} |
||||
|
||||
.jGraduate_rgPick { |
||||
display: none; |
||||
border: outset 1px #666; |
||||
padding: 10px 7px 5px 5px; |
||||
overflow: auto; |
||||
/* position: relative;*/ |
||||
} |
||||
|
||||
.jGraduate_tabs { |
||||
position: relative; |
||||
background-color: #EFEFEF; |
||||
padding: 0px; |
||||
margin: 0px; |
||||
margin-bottom: 5px; |
||||
} |
||||
|
||||
div.jGraduate_Swatch { |
||||
float: left; |
||||
margin: 8px; |
||||
} |
||||
div.jGraduate_GradContainer { |
||||
border: 2px inset #EEE; |
||||
background-image: url(../images/map-opacity.png); |
||||
background-position: 0px 0px; |
||||
height: 256px; |
||||
} |
||||
|
||||
.jGraduate_AlphaArrows { |
||||
position: absolute; |
||||
margin-top: -10px; |
||||
margin-left: 250.5px; |
||||
} |
||||
|
||||
div.jGraduate_Opacity { |
||||
border: 2px inset #eee; |
||||
margin-top: 14px; |
||||
background-color: black; |
||||
background-image: url(../images/Maps.png); |
||||
background-position: 0px -2816px; |
||||
height: 20px; |
||||
cursor: ew-resize; |
||||
} |
||||
|
||||
div.lg_jGraduate_OpacityField { |
||||
position: absolute; |
||||
bottom: 25px; |
||||
left: 292px; |
||||
} |
||||
|
||||
div.jGraduate_Form { |
||||
float: left; |
||||
width: 140px; |
||||
margin: -3px 3px 0px 4px; |
||||
} |
||||
|
||||
div.jGraduate_StopSection { |
||||
width: 120px; |
||||
text-align: center; |
||||
} |
||||
|
||||
div.jGraduate_RadiusField { |
||||
|
||||
text-align: center; |
||||
float: left; |
||||
} |
||||
|
||||
div.jGraduate_RadiusField input { |
||||
margin-top: 10px; |
||||
} |
||||
|
||||
.jGraduate_RadiusField .jGraduate_Form_Section { |
||||
width: 250px; |
||||
padding: 2px; |
||||
height: 80px; |
||||
overflow: visible; |
||||
} |
||||
|
||||
.jGraduate_Form_Section input[type=text] { |
||||
width: 38px; |
||||
} |
||||
|
||||
.jGraduate_Radius { |
||||
border:1px solid #BBB; |
||||
cursor:ew-resize; |
||||
height:20px; |
||||
margin-top:14px; |
||||
position: relative; |
||||
} |
||||
|
||||
|
||||
.jGraduate_RadiusArrows { |
||||
top: 0; |
||||
left: 0; |
||||
position: absolute; |
||||
margin-top: -10px; |
||||
margin-left: 250.5px; |
||||
} |
||||
|
||||
|
||||
div.jGraduate_OkCancel { |
||||
float: left; |
||||
width: 113px; |
||||
} |
||||
|
||||
input.jGraduate_Ok, input.jGraduate_Cancel { |
||||
display: block; |
||||
width: 100px; |
||||
margin-left: -4px; |
||||
margin-right: -4px; |
||||
} |
||||
input.jGraduate_Ok { |
||||
margin: 9px -4px 5px -4px; |
||||
} |
||||
|
||||
.colorBox { |
||||
float: left; |
||||
height: 16px; |
||||
width: 16px; |
||||
border: 1px solid #808080; |
||||
cursor: pointer; |
||||
margin: 4px 4px 4px 30px; |
||||
} |
||||
|
||||
.colorBox + label { |
||||
float: left; |
||||
margin-top: 7px; |
||||
} |
||||
|
||||
label.jGraduate_Form_Heading { |
||||
position: relative; |
||||
top: 10px; |
||||
background-color: #EFEFEF; |
||||
padding: 2px; |
||||
font-weight: bold; |
||||
font-size: 13px; |
||||
} |
||||
|
||||
div.jGraduate_Form_Section { |
||||
border-style: solid; |
||||
border-width: 1px; |
||||
border-color: grey; |
||||
-moz-border-radius: 5px; |
||||
-webkit-border-radius: 5px; |
||||
padding: 15px 5px 5px 5px; |
||||
margin: 2px; |
||||
width: 110px; |
||||
text-align: center; |
||||
overflow: auto; |
||||
} |
||||
|
||||
div.jGraduate_LightBox { |
||||
position: fixed; |
||||
top: 0px; |
||||
left: 0px; |
||||
right: 0px; |
||||
bottom: 0px; |
||||
background-color: #000; |
||||
opacity: 0.5; |
||||
display: none; |
||||
} |
||||
|
||||
div.jGraduate_stopPicker { |
||||
position: absolute; |
||||
display: none; |
||||
background: #E8E8E8; |
||||
} |
||||
|
||||
|
||||
.jGraduate_rgPick { |
||||
width: 530px; |
||||
} |
||||
|
||||
.jGraduate_rgPick div.jGraduate_Form { |
||||
width: 270px; |
||||
position: absolute; |
||||
left: 284px; |
||||
width: 266px; |
||||
top: 130px; |
||||
margin: -3px 3px 0px 4px; |
||||
} |
||||
|
||||
.jGraduate_Colorblocks { |
||||
display: table; |
||||
border-spacing: 0 5px; |
||||
} |
||||
|
||||
.jGraduate_colorblock { |
||||
display: table-row; |
||||
} |
||||
|
||||
.jGraduate_Colorblocks .jGraduate_colorblock > * { |
||||
display: table-cell; |
||||
vertical-align: middle; |
||||
margin: 0; |
||||
float: none; |
||||
} |
||||
|
||||
.jGraduate_rgPick div.jGraduate_StopSection { |
||||
float: left; |
||||
width: 133px; |
||||
margin: 0; |
||||
} |
||||
|
||||
.jGraduate_rgPick .jGraduate_OkCancel { |
||||
position: absolute; |
||||
right: 0; |
||||
} |
||||
|
||||
.rg_jGraduate_OpacityField { |
||||
position: absolute; |
||||
left: 288px; |
||||
bottom: 24px; |
||||
} |
||||
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 349 B |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 268 B |
|
After Width: | Height: | Size: 134 B |