Move Selector and SelectorManager into select.js. Start of unit test file for select.js.
git-svn-id: http://svg-edit.googlecode.com/svn/trunk@1873 eee81c28-f429-11dd-99c0-75d572ba1dddmaster
parent
383d52e157
commit
3ef0229180
1
Makefile
1
Makefile
|
@ -30,6 +30,7 @@ build/$(PACKAGE):
|
||||||
--js svgutils.js \
|
--js svgutils.js \
|
||||||
--js sanitize.js \
|
--js sanitize.js \
|
||||||
--js history.js \
|
--js history.js \
|
||||||
|
--js select.js \
|
||||||
--js svgcanvas.js \
|
--js svgcanvas.js \
|
||||||
--js svg-editor.js \
|
--js svg-editor.js \
|
||||||
--js locale/locale.js \
|
--js locale/locale.js \
|
||||||
|
|
|
@ -0,0 +1,531 @@
|
||||||
|
/**
|
||||||
|
* Package: svedit.select
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2
|
||||||
|
*
|
||||||
|
* Copyright(c) 2010 Alexis Deveria
|
||||||
|
* Copyright(c) 2010 Jeff Schiller
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Dependencies:
|
||||||
|
// 1) jQuery
|
||||||
|
// 2) browsersupport.js
|
||||||
|
// 3) math.js
|
||||||
|
// 4) svgutils.js
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
if (!window.svgedit) {
|
||||||
|
window.svgedit = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!svgedit.select) {
|
||||||
|
svgedit.select = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
var svgFactory_;
|
||||||
|
var config_;
|
||||||
|
var selectorManager_; // A Singleton
|
||||||
|
|
||||||
|
// Class: svgedit.select.Selector
|
||||||
|
// Private class for DOM element selection boxes
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// id - integer to internally indentify the selector
|
||||||
|
// elem - DOM element associated with this selector
|
||||||
|
svgedit.select.Selector = function(id, elem) {
|
||||||
|
// this is the selector's unique number
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
|
// this holds a reference to the element for which this selector is being used
|
||||||
|
this.selectedElement = elem;
|
||||||
|
|
||||||
|
// this is a flag used internally to track whether the selector is being used or not
|
||||||
|
this.locked = true;
|
||||||
|
|
||||||
|
// this holds a reference to the <g> element that holds all visual elements of the selector
|
||||||
|
this.selectorGroup = svgFactory_.createSVGElement({
|
||||||
|
'element': 'g',
|
||||||
|
'attr': {'id': ('selectorGroup' + this.id)}
|
||||||
|
});
|
||||||
|
|
||||||
|
// this holds a reference to the path rect
|
||||||
|
this.selectorRect = this.selectorGroup.appendChild(
|
||||||
|
svgFactory_.createSVGElement({
|
||||||
|
'element': 'path',
|
||||||
|
'attr': {
|
||||||
|
'id': ('selectedBox' + this.id),
|
||||||
|
'fill': 'none',
|
||||||
|
'stroke': '#22C',
|
||||||
|
'stroke-width': '1',
|
||||||
|
'stroke-dasharray': '5,5',
|
||||||
|
// need to specify this so that the rect is not selectable
|
||||||
|
'style': 'pointer-events:none'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// this holds a reference to the grip coordinates for this selector
|
||||||
|
this.gripCoords = {
|
||||||
|
'nw': null,
|
||||||
|
'n' : null,
|
||||||
|
'ne': null,
|
||||||
|
'e' : null,
|
||||||
|
'se': null,
|
||||||
|
's' : null,
|
||||||
|
'sw': null,
|
||||||
|
'w' : null
|
||||||
|
};
|
||||||
|
|
||||||
|
this.reset(this.selectedElement);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Function: svgedit.select.Selector.reset
|
||||||
|
// Used to reset the id and element that the selector is attached to
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// e - DOM element associated with this selector
|
||||||
|
svgedit.select.Selector.prototype.reset = function(e) {
|
||||||
|
this.locked = true;
|
||||||
|
this.selectedElement = e;
|
||||||
|
this.resize();
|
||||||
|
this.selectorGroup.setAttribute('display', 'inline');
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function: svgedit.select.Selector.updateGripCursors
|
||||||
|
// Updates cursors for corner grips on rotation so arrows point the right way
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// angle - Float indicating current rotation angle in degrees
|
||||||
|
svgedit.select.Selector.prototype.updateGripCursors = function(angle) {
|
||||||
|
var dir_arr = [];
|
||||||
|
var steps = Math.round(angle / 45);
|
||||||
|
if(steps < 0) steps += 8;
|
||||||
|
for (var dir in selectorManager_.selectorGrips) {
|
||||||
|
dir_arr.push(dir);
|
||||||
|
}
|
||||||
|
while(steps > 0) {
|
||||||
|
dir_arr.push(dir_arr.shift());
|
||||||
|
steps--;
|
||||||
|
}
|
||||||
|
var i = 0;
|
||||||
|
for (var dir in selectorManager_.selectorGrips) {
|
||||||
|
selectorManager_.selectorGrips[dir].setAttribute('style', ('cursor:' + dir_arr[i] + '-resize'));
|
||||||
|
i++;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function: svgedit.select.Selector.showGrips
|
||||||
|
// Show the resize grips of this selector
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// show - boolean indicating whether grips should be shown or not
|
||||||
|
svgedit.select.Selector.prototype.showGrips = function(show) {
|
||||||
|
// TODO: use suspendRedraw() here
|
||||||
|
var bShow = show ? "inline" : "none";
|
||||||
|
selectorManager_.selectorGripsGroup.setAttribute("display", bShow);
|
||||||
|
var elem = this.selectedElement;
|
||||||
|
this.hasGrips = show;
|
||||||
|
if(elem && show) {
|
||||||
|
this.selectorGroup.appendChild(selectorManager_.selectorGripsGroup);
|
||||||
|
this.updateGripCursors(svgedit.utilities.getRotationAngle(elem));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function: svgedit.select.Selector.resize
|
||||||
|
// Updates the selector to match the element's size
|
||||||
|
svgedit.select.Selector.prototype.resize = function() {
|
||||||
|
var selectedBox = this.selectorRect,
|
||||||
|
mgr = selectorManager_,
|
||||||
|
selectedGrips = mgr.selectorGrips,
|
||||||
|
selected = this.selectedElement,
|
||||||
|
sw = selected.getAttribute("stroke-width"),
|
||||||
|
current_zoom = svgFactory_.currentZoom();
|
||||||
|
var offset = 1/current_zoom;
|
||||||
|
if (selected.getAttribute("stroke") !== "none" && !isNaN(sw)) {
|
||||||
|
offset += (sw/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var tagName = selected.tagName;
|
||||||
|
if (tagName === "text") {
|
||||||
|
offset += 2/current_zoom;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop and transform our bounding box until we reach our first rotation
|
||||||
|
var tlist = svgedit.transformlist.getTransformList(selected);
|
||||||
|
var m = svgedit.math.transformListToTransform(tlist).matrix;
|
||||||
|
|
||||||
|
// This should probably be handled somewhere else, but for now
|
||||||
|
// it keeps the selection box correctly positioned when zoomed
|
||||||
|
m.e *= current_zoom;
|
||||||
|
m.f *= current_zoom;
|
||||||
|
|
||||||
|
var bbox = svgedit.utilities.getBBox(selected);
|
||||||
|
if(tagName === 'g' && !$.data(selected, 'gsvg')) {
|
||||||
|
// The bbox for a group does not include stroke vals, so we
|
||||||
|
// get the bbox based on its children.
|
||||||
|
var stroked_bbox = svgFactory_.getStrokedBBox(selected.childNodes);
|
||||||
|
if(stroked_bbox) {
|
||||||
|
bbox = stroked_bbox;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply the transforms
|
||||||
|
var l=bbox.x, t=bbox.y, w=bbox.width, h=bbox.height,
|
||||||
|
bbox = {x:l, y:t, width:w, height:h};
|
||||||
|
|
||||||
|
// we need to handle temporary transforms too
|
||||||
|
// if skewed, get its transformed box, then find its axis-aligned bbox
|
||||||
|
|
||||||
|
//*
|
||||||
|
offset *= current_zoom;
|
||||||
|
|
||||||
|
var nbox = svgedit.math.transformBox(l*current_zoom, t*current_zoom, w*current_zoom, h*current_zoom, m),
|
||||||
|
aabox = nbox.aabox,
|
||||||
|
nbax = aabox.x - offset,
|
||||||
|
nbay = aabox.y - offset,
|
||||||
|
nbaw = aabox.width + (offset * 2),
|
||||||
|
nbah = aabox.height + (offset * 2);
|
||||||
|
|
||||||
|
// now if the shape is rotated, un-rotate it
|
||||||
|
var cx = nbax + nbaw/2,
|
||||||
|
cy = nbay + nbah/2;
|
||||||
|
|
||||||
|
var angle = svgedit.utilities.getRotationAngle(selected);
|
||||||
|
if (angle) {
|
||||||
|
var rot = svgFactory_.svgRoot().createSVGTransform();
|
||||||
|
rot.setRotate(-angle,cx,cy);
|
||||||
|
var rotm = rot.matrix;
|
||||||
|
nbox.tl = svgedit.math.transformPoint(nbox.tl.x,nbox.tl.y,rotm);
|
||||||
|
nbox.tr = svgedit.math.transformPoint(nbox.tr.x,nbox.tr.y,rotm);
|
||||||
|
nbox.bl = svgedit.math.transformPoint(nbox.bl.x,nbox.bl.y,rotm);
|
||||||
|
nbox.br = svgedit.math.transformPoint(nbox.br.x,nbox.br.y,rotm);
|
||||||
|
|
||||||
|
// calculate the axis-aligned bbox
|
||||||
|
var tl = nbox.tl;
|
||||||
|
var minx = tl.x,
|
||||||
|
miny = tl.y,
|
||||||
|
maxx = tl.x,
|
||||||
|
maxy = tl.y;
|
||||||
|
|
||||||
|
var Min = Math.min, Max = Math.max;
|
||||||
|
|
||||||
|
minx = Min(minx, Min(nbox.tr.x, Min(nbox.bl.x, nbox.br.x) ) ) - offset;
|
||||||
|
miny = Min(miny, Min(nbox.tr.y, Min(nbox.bl.y, nbox.br.y) ) ) - offset;
|
||||||
|
maxx = Max(maxx, Max(nbox.tr.x, Max(nbox.bl.x, nbox.br.x) ) ) + offset;
|
||||||
|
maxy = Max(maxy, Max(nbox.tr.y, Max(nbox.bl.y, nbox.br.y) ) ) + offset;
|
||||||
|
|
||||||
|
nbax = minx;
|
||||||
|
nbay = miny;
|
||||||
|
nbaw = (maxx-minx);
|
||||||
|
nbah = (maxy-miny);
|
||||||
|
}
|
||||||
|
var sr_handle = svgFactory_.svgRoot().suspendRedraw(100);
|
||||||
|
|
||||||
|
var dstr = "M" + nbax + "," + nbay
|
||||||
|
+ " L" + (nbax+nbaw) + "," + nbay
|
||||||
|
+ " " + (nbax+nbaw) + "," + (nbay+nbah)
|
||||||
|
+ " " + nbax + "," + (nbay+nbah) + "z";
|
||||||
|
selectedBox.setAttribute('d', dstr);
|
||||||
|
|
||||||
|
var xform = angle ? "rotate(" + [angle,cx,cy].join(",") + ")" : "";
|
||||||
|
this.selectorGroup.setAttribute("transform", xform);
|
||||||
|
|
||||||
|
// TODO(codedread): Is this if needed?
|
||||||
|
// if(selected === selectedElements[0]) {
|
||||||
|
this.gripCoords = {
|
||||||
|
nw: [nbax, nbay],
|
||||||
|
ne: [nbax+nbaw, nbay],
|
||||||
|
sw: [nbax, nbay+nbah],
|
||||||
|
se: [nbax+nbaw, nbay+nbah],
|
||||||
|
n: [nbax + (nbaw)/2, nbay],
|
||||||
|
w: [nbax, nbay + (nbah)/2],
|
||||||
|
e: [nbax + nbaw, nbay + (nbah)/2],
|
||||||
|
s: [nbax + (nbaw)/2, nbay + nbah]
|
||||||
|
};
|
||||||
|
|
||||||
|
for(var dir in this.gripCoords) {
|
||||||
|
var coords = this.gripCoords[dir];
|
||||||
|
selectedGrips[dir].setAttribute('cx', coords[0]);
|
||||||
|
selectedGrips[dir].setAttribute('cy', coords[1]);
|
||||||
|
};
|
||||||
|
|
||||||
|
// we want to go 20 pixels in the negative transformed y direction, ignoring scale
|
||||||
|
mgr.rotateGripConnector.setAttribute('x1', nbax + (nbaw)/2);
|
||||||
|
mgr.rotateGripConnector.setAttribute('y1', nbay);
|
||||||
|
mgr.rotateGripConnector.setAttribute('x2', nbax + (nbaw)/2);
|
||||||
|
mgr.rotateGripConnector.setAttribute('y2', nbay - 20);
|
||||||
|
|
||||||
|
mgr.rotateGrip.setAttribute('cx', nbax + (nbaw)/2);
|
||||||
|
mgr.rotateGrip.setAttribute('cy', nbay - 20);
|
||||||
|
// }
|
||||||
|
|
||||||
|
svgFactory_.svgRoot().unsuspendRedraw(sr_handle);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Class: svgedit.select.SelectorManager
|
||||||
|
svgedit.select.SelectorManager = function() {
|
||||||
|
// this will hold the <g> element that contains all selector rects/grips
|
||||||
|
this.selectorParentGroup = null;
|
||||||
|
|
||||||
|
// this is a special rect that is used for multi-select
|
||||||
|
this.rubberBandBox = null;
|
||||||
|
|
||||||
|
// this will hold objects of type svgedit.select.Selector (see above)
|
||||||
|
this.selectors = [];
|
||||||
|
|
||||||
|
// this holds a map of SVG elements to their Selector object
|
||||||
|
this.selectorMap = {};
|
||||||
|
|
||||||
|
// this holds a reference to the grip elements
|
||||||
|
this.selectorGrips = {
|
||||||
|
'nw': null,
|
||||||
|
'n' : null,
|
||||||
|
'ne': null,
|
||||||
|
'e' : null,
|
||||||
|
'se': null,
|
||||||
|
's' : null,
|
||||||
|
'sw': null,
|
||||||
|
'w' : null
|
||||||
|
};
|
||||||
|
|
||||||
|
this.selectorGripsGroup = null;
|
||||||
|
this.rotateGripConnector = null;
|
||||||
|
this.rotateGrip = null;
|
||||||
|
|
||||||
|
this.initGroup();
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function: svgedit.select.SelectorManager.initGroup
|
||||||
|
// Resets the parent selector group element
|
||||||
|
svgedit.select.SelectorManager.prototype.initGroup = function() {
|
||||||
|
// remove old selector parent group if it existed
|
||||||
|
if (this.selectorParentGroup && this.selectorParentGroup.parentNode) {
|
||||||
|
this.selectorParentGroup.parentNode.removeChild(this.selectorParentGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create parent selector group and add it to svgroot
|
||||||
|
this.selectorParentGroup = svgFactory_.createSVGElement({
|
||||||
|
'element': 'g',
|
||||||
|
'attr': {'id': 'selectorParentGroup'}
|
||||||
|
});
|
||||||
|
this.selectorGripsGroup = svgFactory_.createSVGElement({
|
||||||
|
'element': 'g',
|
||||||
|
'attr': {'display': 'none'}
|
||||||
|
});
|
||||||
|
this.selectorParentGroup.appendChild(this.selectorGripsGroup);
|
||||||
|
svgFactory_.svgRoot().appendChild(this.selectorParentGroup);
|
||||||
|
|
||||||
|
this.selectorMap = {};
|
||||||
|
this.selectors = [];
|
||||||
|
this.rubberBandBox = null;
|
||||||
|
|
||||||
|
// add the corner grips
|
||||||
|
for (var dir in this.selectorGrips) {
|
||||||
|
var grip = svgFactory_.createSVGElement({
|
||||||
|
'element': 'circle',
|
||||||
|
'attr': {
|
||||||
|
'id': ('selectorGrip_resize_' + dir),
|
||||||
|
'fill': '#22C',
|
||||||
|
'r': 4,
|
||||||
|
'style': ('cursor:' + dir + '-resize'),
|
||||||
|
// This expands the mouse-able area of the grips making them
|
||||||
|
// easier to grab with the mouse.
|
||||||
|
// This works in Opera and WebKit, but does not work in Firefox
|
||||||
|
// see https://bugzilla.mozilla.org/show_bug.cgi?id=500174
|
||||||
|
'stroke-width': 2,
|
||||||
|
'pointer-events': 'all'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$.data(grip, 'dir', dir);
|
||||||
|
$.data(grip, 'type', 'resize');
|
||||||
|
this.selectorGrips[dir] = this.selectorGripsGroup.appendChild(grip);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add rotator elems
|
||||||
|
this.rotateGripConnector = this.selectorGripsGroup.appendChild(
|
||||||
|
svgFactory_.createSVGElement({
|
||||||
|
'element': 'line',
|
||||||
|
'attr': {
|
||||||
|
'id': ('selectorGrip_rotateconnector'),
|
||||||
|
'stroke': '#22C',
|
||||||
|
'stroke-width': '1'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
this.rotateGrip = this.selectorGripsGroup.appendChild(
|
||||||
|
svgFactory_.createSVGElement({
|
||||||
|
'element': 'circle',
|
||||||
|
'attr': {
|
||||||
|
'id': 'selectorGrip_rotate',
|
||||||
|
'fill': 'lime',
|
||||||
|
'r': 4,
|
||||||
|
'stroke': '#22C',
|
||||||
|
'stroke-width': 2,
|
||||||
|
'style': 'cursor:url(' + config_.imgPath + 'rotate.png) 12 12, auto;'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
$.data(this.rotateGrip, "type", "rotate");
|
||||||
|
|
||||||
|
if($("#canvasBackground").length) return;
|
||||||
|
|
||||||
|
var dims = config_.dimensions;
|
||||||
|
var canvasbg = svgFactory_.createSVGElement({
|
||||||
|
'element': 'svg',
|
||||||
|
'attr': {
|
||||||
|
'id': 'canvasBackground',
|
||||||
|
'width': dims[0],
|
||||||
|
'height': dims[1],
|
||||||
|
'x': 0,
|
||||||
|
'y': 0,
|
||||||
|
'overflow': (svgedit.browsersupport.isWebkit() ? 'none' : 'visible'), // Chrome 7 has a problem with this when zooming out
|
||||||
|
'style': 'pointer-events:none'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var rect = svgFactory_.createSVGElement({
|
||||||
|
'element': 'rect',
|
||||||
|
'attr': {
|
||||||
|
'width': '100%',
|
||||||
|
'height': '100%',
|
||||||
|
'x': 0,
|
||||||
|
'y': 0,
|
||||||
|
'stroke-width': 1,
|
||||||
|
'stroke': '#000',
|
||||||
|
'fill': '#FFF',
|
||||||
|
'style': 'pointer-events:none'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Both Firefox and WebKit are too slow with this filter region (especially at higher
|
||||||
|
// zoom levels) and Opera has at least one bug
|
||||||
|
// if (!svgedit.browsersupport.isOpera()) rect.setAttribute('filter', 'url(#canvashadow)');
|
||||||
|
canvasbg.appendChild(rect);
|
||||||
|
svgFactory_.svgRoot().insertBefore(canvasbg, svgFactory_.svgContent());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function: svgedit.select.SelectorManager.requestSelector
|
||||||
|
// Returns the selector based on the given element
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// elem - DOM element to get the selector for
|
||||||
|
svgedit.select.SelectorManager.prototype.requestSelector = function(elem) {
|
||||||
|
if (elem == null) return null;
|
||||||
|
var N = this.selectors.length;
|
||||||
|
// If we've already acquired one for this element, return it.
|
||||||
|
if (typeof(this.selectorMap[elem.id]) == 'object') {
|
||||||
|
this.selectorMap[elem.id].locked = true;
|
||||||
|
return this.selectorMap[elem.id];
|
||||||
|
}
|
||||||
|
for (var i = 0; i < N; ++i) {
|
||||||
|
if (this.selectors[i] && !this.selectors[i].locked) {
|
||||||
|
this.selectors[i].locked = true;
|
||||||
|
this.selectors[i].reset(elem);
|
||||||
|
this.selectorMap[elem.id] = this.selectors[i];
|
||||||
|
return this.selectors[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if we reached here, no available selectors were found, we create one
|
||||||
|
this.selectors[N] = new svgedit.select.Selector(N, elem);
|
||||||
|
this.selectorParentGroup.appendChild(this.selectors[N].selectorGroup);
|
||||||
|
this.selectorMap[elem.id] = this.selectors[N];
|
||||||
|
return this.selectors[N];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function: svgedit.select.SelectorManager.releaseSelector
|
||||||
|
// Removes the selector of the given element (hides selection box)
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// elem - DOM element to remove the selector for
|
||||||
|
svgedit.select.SelectorManager.prototype.releaseSelector = function(elem) {
|
||||||
|
if (elem == null) return;
|
||||||
|
var N = this.selectors.length,
|
||||||
|
sel = this.selectorMap[elem.id];
|
||||||
|
for (var i = 0; i < N; ++i) {
|
||||||
|
if (this.selectors[i] && this.selectors[i] == sel) {
|
||||||
|
if (sel.locked == false) {
|
||||||
|
// TODO(codedread): Ensure this exists in this module.
|
||||||
|
console.log("WARNING! selector was released but was already unlocked");
|
||||||
|
}
|
||||||
|
delete this.selectorMap[elem.id];
|
||||||
|
sel.locked = false;
|
||||||
|
sel.selectedElement = null;
|
||||||
|
sel.showGrips(false);
|
||||||
|
|
||||||
|
// remove from DOM and store reference in JS but only if it exists in the DOM
|
||||||
|
try {
|
||||||
|
sel.selectorGroup.setAttribute("display", "none");
|
||||||
|
} catch(e) { }
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function: svgedit.select.SelectorManager.getRubberBandBox
|
||||||
|
// Returns the rubberBandBox DOM element. This is the rectangle drawn by the user for selecting/zooming
|
||||||
|
svgedit.select.SelectorManager.prototype.getRubberBandBox = function() {
|
||||||
|
if (!this.rubberBandBox) {
|
||||||
|
this.rubberBandBox = this.selectorParentGroup.appendChild(
|
||||||
|
svgFactory_.createSVGElement({
|
||||||
|
'element': 'rect',
|
||||||
|
"attr": {
|
||||||
|
"id": "selectorRubberBand",
|
||||||
|
"fill": "#22C",
|
||||||
|
"fill-opacity": 0.15,
|
||||||
|
"stroke": "#22C",
|
||||||
|
"stroke-width": 0.5,
|
||||||
|
"display": "none",
|
||||||
|
"style": "pointer-events:none"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this.rubberBandBox;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface: svgedit.select.SVGFactory
|
||||||
|
* An object that creates SVG elements for the canvas.
|
||||||
|
*
|
||||||
|
* interface svgedit.select.SVGFactory {
|
||||||
|
* SVGElement createSVGElement(jsonMap);
|
||||||
|
* SVGSVGElement svgRoot();
|
||||||
|
* SVGSVGElement svgContent();
|
||||||
|
*
|
||||||
|
* Number: currentZoom();
|
||||||
|
* Object getStrokedBBox(Element[]); // TODO(codedread): Remove when getStrokedBBox() has been put into svgutils.js
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: svgedit.select.init()
|
||||||
|
* Initializes this module.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* config - an object containing configurable parameters (imgPath)
|
||||||
|
* svgFactory - an object implementing the SVGFactory interface (see above).
|
||||||
|
*/
|
||||||
|
svgedit.select.init = function(config, svgFactory) {
|
||||||
|
config_ = config;
|
||||||
|
svgFactory_ = svgFactory;
|
||||||
|
selectorManager_ = new svgedit.select.SelectorManager();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function: svgedit.select.getSelectorManager
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* The SelectorManager instance.
|
||||||
|
*/
|
||||||
|
svgedit.select.getSelectorManager = function() {
|
||||||
|
return selectorManager_;
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
|
@ -25,6 +25,7 @@
|
||||||
<script type="text/javascript" src="svgutils.js"></script>
|
<script type="text/javascript" src="svgutils.js"></script>
|
||||||
<script type="text/javascript" src="sanitize.js"></script>
|
<script type="text/javascript" src="sanitize.js"></script>
|
||||||
<script type="text/javascript" src="history.js"></script>
|
<script type="text/javascript" src="history.js"></script>
|
||||||
|
<script type="text/javascript" src="select.js"></script>
|
||||||
<script type="text/javascript" src="svgcanvas.js"></script>
|
<script type="text/javascript" src="svgcanvas.js"></script>
|
||||||
<script type="text/javascript" src="svg-editor.js"></script>
|
<script type="text/javascript" src="svg-editor.js"></script>
|
||||||
<script type="text/javascript" src="locale/locale.js"></script>
|
<script type="text/javascript" src="locale/locale.js"></script>
|
||||||
|
|
|
@ -119,20 +119,85 @@ if(config) {
|
||||||
$.extend(curConfig, config);
|
$.extend(curConfig, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Array with width/height of canvas
|
||||||
|
var dimensions = curConfig.dimensions;
|
||||||
|
|
||||||
var canvas = this;
|
var canvas = this;
|
||||||
|
|
||||||
// "document" element associated with the container (same as window.document using default svg-editor.js)
|
// "document" element associated with the container (same as window.document using default svg-editor.js)
|
||||||
var svgdoc = container.ownerDocument;
|
var svgdoc = container.ownerDocument;
|
||||||
|
|
||||||
|
// This is a container for the document being edited, not the document itself.
|
||||||
|
var svgroot = svgdoc.importNode(svgedit.utilities.text2xml(
|
||||||
|
'<svg id="svgroot" xmlns="' + svgns + '" xlinkns="' + xlinkns + '" ' +
|
||||||
|
'width="' + dimensions[0] + '" height="' + dimensions[1] + '" x="' + dimensions[0] + '" y="' + dimensions[1] + '" overflow="visible">' +
|
||||||
|
'<defs>' +
|
||||||
|
'<filter id="canvashadow" filterUnits="objectBoundingBox">' +
|
||||||
|
'<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>'+
|
||||||
|
'<feOffset in="blur" dx="5" dy="5" result="offsetBlur"/>'+
|
||||||
|
'<feMerge>'+
|
||||||
|
'<feMergeNode in="offsetBlur"/>'+
|
||||||
|
'<feMergeNode in="SourceGraphic"/>'+
|
||||||
|
'</feMerge>'+
|
||||||
|
'</filter>'+
|
||||||
|
'</defs>'+
|
||||||
|
'</svg>').documentElement, true);
|
||||||
|
container.appendChild(svgroot);
|
||||||
|
|
||||||
// The actual element that represents the final output SVG element
|
// The actual element that represents the final output SVG element
|
||||||
var svgcontent = svgdoc.createElementNS(svgns, "svg");
|
var svgcontent = svgdoc.createElementNS(svgns, "svg");
|
||||||
|
|
||||||
// This is a container for the document being edited, not the document itself. Initialized later.
|
$(svgcontent).attr({
|
||||||
var svgroot = null;
|
id: 'svgcontent',
|
||||||
|
width: dimensions[0],
|
||||||
|
height: dimensions[1],
|
||||||
|
x: dimensions[0],
|
||||||
|
y: dimensions[1],
|
||||||
|
overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden',
|
||||||
|
xmlns: svgns,
|
||||||
|
"xmlns:se": se_ns,
|
||||||
|
"xmlns:xlink": xlinkns
|
||||||
|
}).appendTo(svgroot);
|
||||||
|
|
||||||
|
|
||||||
// Float displaying the current zoom level (1 = 100%, .5 = 50%, etc)
|
// Float displaying the current zoom level (1 = 100%, .5 = 50%, etc)
|
||||||
var current_zoom = 1;
|
var current_zoom = 1;
|
||||||
|
|
||||||
|
// pointer to the current layer <g>
|
||||||
|
var current_layer = null;
|
||||||
|
|
||||||
|
// pointer to current group (for in-group editing)
|
||||||
|
var current_group = null;
|
||||||
|
|
||||||
|
// Object containing data for the currently selected styles
|
||||||
|
var all_properties = {
|
||||||
|
shape: {
|
||||||
|
fill: "#" + curConfig.initFill.color,
|
||||||
|
fill_paint: null,
|
||||||
|
fill_opacity: curConfig.initFill.opacity,
|
||||||
|
stroke: "#" + curConfig.initStroke.color,
|
||||||
|
stroke_paint: null,
|
||||||
|
stroke_opacity: curConfig.initStroke.opacity,
|
||||||
|
stroke_width: curConfig.initStroke.width,
|
||||||
|
stroke_dasharray: 'none',
|
||||||
|
stroke_linejoin: 'miter',
|
||||||
|
stroke_linecap: 'butt',
|
||||||
|
opacity: curConfig.initOpacity
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
all_properties.text = $.extend(true, {}, all_properties.shape);
|
||||||
|
$.extend(all_properties.text, {
|
||||||
|
fill: "#000000",
|
||||||
|
stroke_width: 0,
|
||||||
|
font_size: 24,
|
||||||
|
font_family: 'serif'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Current shape style properties
|
||||||
|
var cur_shape = all_properties.shape;
|
||||||
|
|
||||||
|
|
||||||
// Function: getElem
|
// Function: getElem
|
||||||
// Get a DOM element by ID within the SVG root element.
|
// Get a DOM element by ID within the SVG root element.
|
||||||
//
|
//
|
||||||
|
@ -154,6 +219,112 @@ var getElem = function(id) {
|
||||||
// return svgdoc.getElementById(id);
|
// return svgdoc.getElementById(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Function: assignAttributes
|
||||||
|
// Assigns multiple attributes to an element.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// node - DOM element to apply new attribute values to
|
||||||
|
// attrs - Object with attribute keys/values
|
||||||
|
// suspendLength - Optional integer of milliseconds to suspend redraw
|
||||||
|
// unitCheck - Boolean to indicate the need to use svgedit.units.setUnitAttr
|
||||||
|
var assignAttributes = canvas.assignAttributes = function(node, attrs, suspendLength, unitCheck) {
|
||||||
|
if(!suspendLength) suspendLength = 0;
|
||||||
|
// Opera has a problem with suspendRedraw() apparently
|
||||||
|
var handle = null;
|
||||||
|
if (!svgedit.browsersupport.isOpera()) svgroot.suspendRedraw(suspendLength);
|
||||||
|
|
||||||
|
for (var i in attrs) {
|
||||||
|
var ns = (i.substr(0,4) === "xml:" ? xmlns :
|
||||||
|
i.substr(0,6) === "xlink:" ? xlinkns : null);
|
||||||
|
|
||||||
|
if(ns) {
|
||||||
|
node.setAttributeNS(ns, i, attrs[i]);
|
||||||
|
} else if(!unitCheck) {
|
||||||
|
node.setAttribute(i, attrs[i]);
|
||||||
|
} else {
|
||||||
|
svgedit.units.setUnitAttr(node, i, attrs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!svgedit.browsersupport.isOpera()) svgroot.unsuspendRedraw(handle);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function: cleanupElement
|
||||||
|
// Remove unneeded (default) attributes, makes resulting SVG smaller
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// element - DOM element to clean up
|
||||||
|
var cleanupElement = this.cleanupElement = function(element) {
|
||||||
|
var handle = svgroot.suspendRedraw(60);
|
||||||
|
var defaults = {
|
||||||
|
'fill-opacity':1,
|
||||||
|
'stop-opacity':1,
|
||||||
|
'opacity':1,
|
||||||
|
'stroke':'none',
|
||||||
|
'stroke-dasharray':'none',
|
||||||
|
'stroke-linejoin':'miter',
|
||||||
|
'stroke-linecap':'butt',
|
||||||
|
'stroke-opacity':1,
|
||||||
|
'stroke-width':1,
|
||||||
|
'rx':0,
|
||||||
|
'ry':0
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var attr in defaults) {
|
||||||
|
var val = defaults[attr];
|
||||||
|
if(element.getAttribute(attr) == val) {
|
||||||
|
element.removeAttribute(attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
svgroot.unsuspendRedraw(handle);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function: addSvgElementFromJson
|
||||||
|
// Create a new SVG element based on the given object keys/values and add it to the current layer
|
||||||
|
// The element will be ran through cleanupElement before being returned
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// data - Object with the following keys/values:
|
||||||
|
// * element - tag name of the SVG element to create
|
||||||
|
// * attr - Object with attributes key-values to assign to the new element
|
||||||
|
// * curStyles - Boolean indicating that current style attributes should be applied first
|
||||||
|
//
|
||||||
|
// Returns: The new element
|
||||||
|
var addSvgElementFromJson = this.addSvgElementFromJson = function(data) {
|
||||||
|
var shape = getElem(data.attr.id);
|
||||||
|
// if shape is a path but we need to create a rect/ellipse, then remove the path
|
||||||
|
if (shape && data.element != shape.tagName) {
|
||||||
|
current_layer.removeChild(shape);
|
||||||
|
shape = null;
|
||||||
|
}
|
||||||
|
if (!shape) {
|
||||||
|
shape = svgdoc.createElementNS(svgns, data.element);
|
||||||
|
if (current_layer) {
|
||||||
|
(current_group || current_layer).appendChild(shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(data.curStyles) {
|
||||||
|
assignAttributes(shape, {
|
||||||
|
"fill": cur_shape.fill,
|
||||||
|
"stroke": cur_shape.stroke,
|
||||||
|
"stroke-width": cur_shape.stroke_width,
|
||||||
|
"stroke-dasharray": cur_shape.stroke_dasharray,
|
||||||
|
"stroke-linejoin": cur_shape.stroke_linejoin,
|
||||||
|
"stroke-linecap": cur_shape.stroke_linecap,
|
||||||
|
"stroke-opacity": cur_shape.stroke_opacity,
|
||||||
|
"fill-opacity": cur_shape.fill_opacity,
|
||||||
|
"opacity": cur_shape.opacity / 2,
|
||||||
|
"style": "pointer-events:inherit"
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
assignAttributes(shape, data.attr, 100);
|
||||||
|
cleanupElement(shape);
|
||||||
|
return shape;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// import svgtransformlist.js
|
// import svgtransformlist.js
|
||||||
var getTransformList = canvas.getTransformList = svgedit.transformlist.getTransformList;
|
var getTransformList = canvas.getTransformList = svgedit.transformlist.getTransformList;
|
||||||
|
|
||||||
|
@ -240,6 +411,17 @@ var addCommandToHistory = function(cmd) {
|
||||||
canvas.undoMgr.addCommandToHistory(cmd);
|
canvas.undoMgr.addCommandToHistory(cmd);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// import from select.js
|
||||||
|
svgedit.select.init(curConfig, {
|
||||||
|
createSVGElement: function(jsonMap) { return canvas.addSvgElementFromJson(jsonMap); },
|
||||||
|
svgRoot: function() { return svgroot; },
|
||||||
|
svgContent: function() { return svgcontent; },
|
||||||
|
currentZoom: function() { return current_zoom; },
|
||||||
|
// TODO(codedread): Remove when getStrokedBBox() has been put into svgutils.js.
|
||||||
|
getStrokedBBox: function(elems) { return canvas.getStrokedBBox([elems]); }
|
||||||
|
});
|
||||||
|
// this object manages selectors for us
|
||||||
|
var selectorManager = this.selectorManager = svgedit.select.getSelectorManager();
|
||||||
|
|
||||||
// Function: snapToGrid
|
// Function: snapToGrid
|
||||||
// round value to for snapping
|
// round value to for snapping
|
||||||
|
@ -272,43 +454,10 @@ var ref_attrs = ["clip-path", "fill", "filter", "marker-end", "marker-mid", "mar
|
||||||
var elData = $.data;
|
var elData = $.data;
|
||||||
|
|
||||||
// nonce to uniquify id's
|
// nonce to uniquify id's
|
||||||
var nonce = Math.floor(Math.random()*100001),
|
var nonce = Math.floor(Math.random() * 100001);
|
||||||
|
|
||||||
// Boolean to indicate whether or not IDs given to elements should be random
|
// Boolean to indicate whether or not IDs given to elements should be random
|
||||||
randomize_ids = false,
|
var randomize_ids = false;
|
||||||
|
|
||||||
// Array with width/height of canvas
|
|
||||||
dimensions = curConfig.dimensions;
|
|
||||||
|
|
||||||
// Create Root SVG element. This is a container for the document being edited, not the document itself.
|
|
||||||
svgroot = svgdoc.importNode(svgedit.utilities.text2xml(
|
|
||||||
'<svg id="svgroot" xmlns="' + svgns + '" xlinkns="' + xlinkns + '" ' +
|
|
||||||
'width="' + dimensions[0] + '" height="' + dimensions[1] + '" x="' + dimensions[0] + '" y="' + dimensions[1] + '" overflow="visible">' +
|
|
||||||
'<defs>' +
|
|
||||||
'<filter id="canvashadow" filterUnits="objectBoundingBox">' +
|
|
||||||
'<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>'+
|
|
||||||
'<feOffset in="blur" dx="5" dy="5" result="offsetBlur"/>'+
|
|
||||||
'<feMerge>'+
|
|
||||||
'<feMergeNode in="offsetBlur"/>'+
|
|
||||||
'<feMergeNode in="SourceGraphic"/>'+
|
|
||||||
'</feMerge>'+
|
|
||||||
'</filter>'+
|
|
||||||
'</defs>'+
|
|
||||||
'</svg>').documentElement, true);
|
|
||||||
|
|
||||||
container.appendChild(svgroot);
|
|
||||||
|
|
||||||
$(svgcontent).attr({
|
|
||||||
id: 'svgcontent',
|
|
||||||
width: dimensions[0],
|
|
||||||
height: dimensions[1],
|
|
||||||
x: dimensions[0],
|
|
||||||
y: dimensions[1],
|
|
||||||
overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden',
|
|
||||||
xmlns: svgns,
|
|
||||||
"xmlns:se": se_ns,
|
|
||||||
"xmlns:xlink": xlinkns
|
|
||||||
}).appendTo(svgroot);
|
|
||||||
|
|
||||||
// Set nonce if randomize_ids = true
|
// Set nonce if randomize_ids = true
|
||||||
if (randomize_ids) svgcontent.setAttributeNS(se_ns, 'se:nonce', nonce);
|
if (randomize_ids) svgcontent.setAttributeNS(se_ns, 'se:nonce', nonce);
|
||||||
|
@ -338,557 +487,6 @@ var restoreRefElems = function(elem) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Put SelectorManager in this scope
|
|
||||||
var SelectorManager;
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
// Interface: Selector
|
|
||||||
// Private class for DOM element selection boxes
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// id - integer to internally indentify the selector
|
|
||||||
// elem - DOM element associated with this selector
|
|
||||||
function Selector(id, elem) {
|
|
||||||
// this is the selector's unique number
|
|
||||||
this.id = id;
|
|
||||||
|
|
||||||
// this holds a reference to the element for which this selector is being used
|
|
||||||
this.selectedElement = elem;
|
|
||||||
|
|
||||||
// this is a flag used internally to track whether the selector is being used or not
|
|
||||||
this.locked = true;
|
|
||||||
|
|
||||||
// Function: Selector.reset
|
|
||||||
// Used to reset the id and element that the selector is attached to
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// e - DOM element associated with this selector
|
|
||||||
this.reset = function(e) {
|
|
||||||
this.locked = true;
|
|
||||||
this.selectedElement = e;
|
|
||||||
this.resize();
|
|
||||||
this.selectorGroup.setAttribute("display", "inline");
|
|
||||||
};
|
|
||||||
|
|
||||||
// this holds a reference to the <g> element that holds all visual elements of the selector
|
|
||||||
this.selectorGroup = addSvgElementFromJson({ "element": "g",
|
|
||||||
"attr": {"id": ("selectorGroup"+this.id)}
|
|
||||||
});
|
|
||||||
|
|
||||||
// this holds a reference to the path rect
|
|
||||||
this.selectorRect = this.selectorGroup.appendChild( addSvgElementFromJson({
|
|
||||||
"element": "path",
|
|
||||||
"attr": {
|
|
||||||
"id": ("selectedBox"+this.id),
|
|
||||||
"fill": "none",
|
|
||||||
"stroke": "#22C",
|
|
||||||
"stroke-width": "1",
|
|
||||||
"stroke-dasharray": "5,5",
|
|
||||||
// need to specify this so that the rect is not selectable
|
|
||||||
"style": "pointer-events:none"
|
|
||||||
}
|
|
||||||
}) );
|
|
||||||
|
|
||||||
// this holds a reference to the grip coordinates for this selector
|
|
||||||
this.gripCoords = { "nw":null,
|
|
||||||
"n":null,
|
|
||||||
"ne":null,
|
|
||||||
"e":null,
|
|
||||||
"se":null,
|
|
||||||
"s":null,
|
|
||||||
"sw":null,
|
|
||||||
"w":null
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function: Selector.showGrips
|
|
||||||
// Show the resize grips of this selector
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// show - boolean indicating whether grips should be shown or not
|
|
||||||
this.showGrips = function(show) {
|
|
||||||
// TODO: use suspendRedraw() here
|
|
||||||
var bShow = show ? "inline" : "none";
|
|
||||||
selectorManager.selectorGripsGroup.setAttribute("display", bShow);
|
|
||||||
var elem = this.selectedElement;
|
|
||||||
this.hasGrips = show;
|
|
||||||
if(elem && show) {
|
|
||||||
this.selectorGroup.appendChild(selectorManager.selectorGripsGroup);
|
|
||||||
this.updateGripCursors(svgedit.utilities.getRotationAngle(elem));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function: Selector.updateGripCursors
|
|
||||||
// Updates cursors for corner grips on rotation so arrows point the right way
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// angle - Float indicating current rotation angle in degrees
|
|
||||||
this.updateGripCursors = function(angle) {
|
|
||||||
var dir_arr = [];
|
|
||||||
var steps = Math.round(angle / 45);
|
|
||||||
if(steps < 0) steps += 8;
|
|
||||||
for (var dir in selectorManager.selectorGrips) {
|
|
||||||
dir_arr.push(dir);
|
|
||||||
}
|
|
||||||
while(steps > 0) {
|
|
||||||
dir_arr.push(dir_arr.shift());
|
|
||||||
steps--;
|
|
||||||
}
|
|
||||||
var i = 0;
|
|
||||||
for (var dir in selectorManager.selectorGrips) {
|
|
||||||
selectorManager.selectorGrips[dir].setAttribute('style', ("cursor:" + dir_arr[i] + "-resize"));
|
|
||||||
i++;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function: Selector.resize
|
|
||||||
// Updates the selector to match the element's size
|
|
||||||
this.resize = function() {
|
|
||||||
var selectedBox = this.selectorRect,
|
|
||||||
mgr = selectorManager,
|
|
||||||
selectedGrips = mgr.selectorGrips,
|
|
||||||
selected = this.selectedElement,
|
|
||||||
sw = selected.getAttribute("stroke-width");
|
|
||||||
var offset = 1/current_zoom;
|
|
||||||
if (selected.getAttribute("stroke") !== "none" && !isNaN(sw)) {
|
|
||||||
offset += (sw/2);
|
|
||||||
}
|
|
||||||
|
|
||||||
var tagName = selected.tagName;
|
|
||||||
|
|
||||||
if (tagName === "text") {
|
|
||||||
offset += 2/current_zoom;
|
|
||||||
}
|
|
||||||
|
|
||||||
var bbox = getBBox(selected);
|
|
||||||
|
|
||||||
if(tagName === 'g' && !elData(selected, 'gsvg')) {
|
|
||||||
// The bbox for a group does not include stroke vals, so we
|
|
||||||
// get the bbox based on its children.
|
|
||||||
var stroked_bbox = getStrokedBBox(selected.childNodes);
|
|
||||||
if(stroked_bbox) {
|
|
||||||
bbox = stroked_bbox;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// loop and transform our bounding box until we reach our first rotation
|
|
||||||
var m = getMatrix(selected);
|
|
||||||
|
|
||||||
// This should probably be handled somewhere else, but for now
|
|
||||||
// it keeps the selection box correctly positioned when zoomed
|
|
||||||
m.e *= current_zoom;
|
|
||||||
m.f *= current_zoom;
|
|
||||||
|
|
||||||
// apply the transforms
|
|
||||||
var l=bbox.x, t=bbox.y, w=bbox.width, h=bbox.height,
|
|
||||||
bbox = {x:l, y:t, width:w, height:h};
|
|
||||||
|
|
||||||
|
|
||||||
// we need to handle temporary transforms too
|
|
||||||
// if skewed, get its transformed box, then find its axis-aligned bbox
|
|
||||||
|
|
||||||
//*
|
|
||||||
offset *= current_zoom;
|
|
||||||
|
|
||||||
var nbox = svgedit.math.transformBox(l*current_zoom, t*current_zoom, w*current_zoom, h*current_zoom, m),
|
|
||||||
aabox = nbox.aabox,
|
|
||||||
nbax = aabox.x - offset,
|
|
||||||
nbay = aabox.y - offset,
|
|
||||||
nbaw = aabox.width + (offset * 2),
|
|
||||||
nbah = aabox.height + (offset * 2);
|
|
||||||
|
|
||||||
// now if the shape is rotated, un-rotate it
|
|
||||||
var cx = nbax + nbaw/2,
|
|
||||||
cy = nbay + nbah/2;
|
|
||||||
|
|
||||||
var angle = svgedit.utilities.getRotationAngle(selected);
|
|
||||||
if (angle) {
|
|
||||||
|
|
||||||
var rot = svgroot.createSVGTransform();
|
|
||||||
rot.setRotate(-angle,cx,cy);
|
|
||||||
var rotm = rot.matrix;
|
|
||||||
nbox.tl = transformPoint(nbox.tl.x,nbox.tl.y,rotm);
|
|
||||||
nbox.tr = transformPoint(nbox.tr.x,nbox.tr.y,rotm);
|
|
||||||
nbox.bl = transformPoint(nbox.bl.x,nbox.bl.y,rotm);
|
|
||||||
nbox.br = transformPoint(nbox.br.x,nbox.br.y,rotm);
|
|
||||||
|
|
||||||
// calculate the axis-aligned bbox
|
|
||||||
var tl = nbox.tl;
|
|
||||||
var minx = tl.x,
|
|
||||||
miny = tl.y,
|
|
||||||
maxx = tl.x,
|
|
||||||
maxy = tl.y;
|
|
||||||
|
|
||||||
var Min = Math.min, Max = Math.max;
|
|
||||||
|
|
||||||
minx = Min(minx, Min(nbox.tr.x, Min(nbox.bl.x, nbox.br.x) ) ) - offset;
|
|
||||||
miny = Min(miny, Min(nbox.tr.y, Min(nbox.bl.y, nbox.br.y) ) ) - offset;
|
|
||||||
maxx = Max(maxx, Max(nbox.tr.x, Max(nbox.bl.x, nbox.br.x) ) ) + offset;
|
|
||||||
maxy = Max(maxy, Max(nbox.tr.y, Max(nbox.bl.y, nbox.br.y) ) ) + offset;
|
|
||||||
|
|
||||||
nbax = minx;
|
|
||||||
nbay = miny;
|
|
||||||
nbaw = (maxx-minx);
|
|
||||||
nbah = (maxy-miny);
|
|
||||||
}
|
|
||||||
|
|
||||||
var sr_handle = svgroot.suspendRedraw(100);
|
|
||||||
|
|
||||||
var dstr = "M" + nbax + "," + nbay
|
|
||||||
+ " L" + (nbax+nbaw) + "," + nbay
|
|
||||||
+ " " + (nbax+nbaw) + "," + (nbay+nbah)
|
|
||||||
+ " " + nbax + "," + (nbay+nbah) + "z";
|
|
||||||
selectedBox.setAttribute('d', dstr);
|
|
||||||
|
|
||||||
var xform = angle ? "rotate(" + [angle,cx,cy].join(",") + ")" : "";
|
|
||||||
this.selectorGroup.setAttribute("transform", xform);
|
|
||||||
|
|
||||||
if(selected === selectedElements[0]) {
|
|
||||||
this.gripCoords = {
|
|
||||||
nw: [nbax, nbay],
|
|
||||||
ne: [nbax+nbaw, nbay],
|
|
||||||
sw: [nbax, nbay+nbah],
|
|
||||||
se: [nbax+nbaw, nbay+nbah],
|
|
||||||
n: [nbax + (nbaw)/2, nbay],
|
|
||||||
w: [nbax, nbay + (nbah)/2],
|
|
||||||
e: [nbax + nbaw, nbay + (nbah)/2],
|
|
||||||
s: [nbax + (nbaw)/2, nbay + nbah]
|
|
||||||
};
|
|
||||||
|
|
||||||
for(var dir in this.gripCoords) {
|
|
||||||
var coords = this.gripCoords[dir];
|
|
||||||
assignAttributes(selectedGrips[dir], {
|
|
||||||
cx: coords[0], cy: coords[1]
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// we want to go 20 pixels in the negative transformed y direction, ignoring scale
|
|
||||||
assignAttributes(mgr.rotateGripConnector, { x1: nbax + (nbaw)/2,
|
|
||||||
y1: nbay,
|
|
||||||
x2: nbax + (nbaw)/2,
|
|
||||||
y2: nbay- 20});
|
|
||||||
assignAttributes(mgr.rotateGrip, { cx: nbax + (nbaw)/2,
|
|
||||||
cy: nbay - 20 });
|
|
||||||
}
|
|
||||||
|
|
||||||
svgroot.unsuspendRedraw(sr_handle);
|
|
||||||
};
|
|
||||||
|
|
||||||
// now initialize the selector
|
|
||||||
this.reset(elem);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Interface: SelectorManager
|
|
||||||
// Public class to manage all selector objects (selection boxes)
|
|
||||||
SelectorManager = function() {
|
|
||||||
|
|
||||||
// this will hold the <g> element that contains all selector rects/grips
|
|
||||||
this.selectorParentGroup = null;
|
|
||||||
|
|
||||||
// this is a special rect that is used for multi-select
|
|
||||||
this.rubberBandBox = null;
|
|
||||||
|
|
||||||
// this will hold objects of type Selector (see above)
|
|
||||||
this.selectors = [];
|
|
||||||
|
|
||||||
// this holds a map of SVG elements to their Selector object
|
|
||||||
this.selectorMap = {};
|
|
||||||
|
|
||||||
// local reference to this object
|
|
||||||
var mgr = this;
|
|
||||||
|
|
||||||
// Function: SelectorManager.initGroup
|
|
||||||
// Resets the parent selector group element
|
|
||||||
this.initGroup = function() {
|
|
||||||
// remove old selector parent group if it existed
|
|
||||||
if (mgr.selectorParentGroup && mgr.selectorParentGroup.parentNode) {
|
|
||||||
mgr.selectorParentGroup.parentNode.removeChild(mgr.selectorParentGroup);
|
|
||||||
}
|
|
||||||
// create parent selector group and add it to svgroot
|
|
||||||
mgr.selectorParentGroup = svgdoc.createElementNS(svgns, "g");
|
|
||||||
mgr.selectorParentGroup.setAttribute("id", "selectorParentGroup");
|
|
||||||
mgr.selectorGripsGroup = svgdoc.createElementNS(svgns, "g");
|
|
||||||
mgr.selectorGripsGroup.setAttribute('display','none');
|
|
||||||
svgroot.appendChild(mgr.selectorParentGroup);
|
|
||||||
mgr.selectorParentGroup.appendChild(mgr.selectorGripsGroup);
|
|
||||||
mgr.selectorMap = {};
|
|
||||||
mgr.selectors = [];
|
|
||||||
mgr.rubberBandBox = null;
|
|
||||||
|
|
||||||
// this holds a reference to the grip elements
|
|
||||||
mgr.selectorGrips = { "nw":null,
|
|
||||||
"n":null,
|
|
||||||
"ne":null,
|
|
||||||
"e":null,
|
|
||||||
"se":null,
|
|
||||||
"s":null,
|
|
||||||
"sw":null,
|
|
||||||
"w":null
|
|
||||||
};
|
|
||||||
|
|
||||||
// add the corner grips
|
|
||||||
for (var dir in mgr.selectorGrips) {
|
|
||||||
var grip = addSvgElementFromJson({
|
|
||||||
"element": "circle",
|
|
||||||
"attr": {
|
|
||||||
"id": ("selectorGrip_resize_" + dir),
|
|
||||||
"fill": "#22C",
|
|
||||||
"r": 4,
|
|
||||||
"style": ("cursor:" + dir + "-resize"),
|
|
||||||
// This expands the mouse-able area of the grips making them
|
|
||||||
// easier to grab with the mouse.
|
|
||||||
// This works in Opera and WebKit, but does not work in Firefox
|
|
||||||
// see https://bugzilla.mozilla.org/show_bug.cgi?id=500174
|
|
||||||
"stroke-width": 2,
|
|
||||||
"pointer-events":"all"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
elData(grip, "dir", dir);
|
|
||||||
elData(grip, "type", "resize");
|
|
||||||
this.selectorGrips[dir] = mgr.selectorGripsGroup.appendChild(grip);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add rotator elems
|
|
||||||
this.rotateGripConnector = this.selectorGripsGroup.appendChild( addSvgElementFromJson({
|
|
||||||
"element": "line",
|
|
||||||
"attr": {
|
|
||||||
"id": ("selectorGrip_rotateconnector"),
|
|
||||||
"stroke": "#22C",
|
|
||||||
"stroke-width": "1"
|
|
||||||
}
|
|
||||||
}) );
|
|
||||||
|
|
||||||
this.rotateGrip = this.selectorGripsGroup.appendChild( addSvgElementFromJson({
|
|
||||||
"element": "circle",
|
|
||||||
"attr": {
|
|
||||||
"id": "selectorGrip_rotate",
|
|
||||||
"fill": "lime",
|
|
||||||
"r": 4,
|
|
||||||
"stroke": "#22C",
|
|
||||||
"stroke-width": 2,
|
|
||||||
"style": "cursor:url(" + curConfig.imgPath + "rotate.png) 12 12, auto;"
|
|
||||||
}
|
|
||||||
}) );
|
|
||||||
elData(this.rotateGrip, "type", "rotate");
|
|
||||||
|
|
||||||
if($("#canvasBackground").length) return;
|
|
||||||
|
|
||||||
var canvasbg = svgdoc.createElementNS(svgns, "svg");
|
|
||||||
var dims = curConfig.dimensions;
|
|
||||||
assignAttributes(canvasbg, {
|
|
||||||
'id':'canvasBackground',
|
|
||||||
'width': dims[0],
|
|
||||||
'height': dims[1],
|
|
||||||
'x': 0,
|
|
||||||
'y': 0,
|
|
||||||
'overflow': (svgedit.browsersupport.isWebkit() ? 'none' : 'visible'), // Chrome 7 has a problem with this when zooming out
|
|
||||||
'style': 'pointer-events:none'
|
|
||||||
});
|
|
||||||
|
|
||||||
var rect = svgdoc.createElementNS(svgns, "rect");
|
|
||||||
assignAttributes(rect, {
|
|
||||||
'width': '100%',
|
|
||||||
'height': '100%',
|
|
||||||
'x': 0,
|
|
||||||
'y': 0,
|
|
||||||
'stroke-width': 1,
|
|
||||||
'stroke': '#000',
|
|
||||||
'fill': '#FFF',
|
|
||||||
'style': 'pointer-events:none'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Both Firefox and WebKit are too slow with this filter region (especially at higher
|
|
||||||
// zoom levels) and Opera has at least one bug
|
|
||||||
// if (!window.opera) rect.setAttribute('filter', 'url(#canvashadow)');
|
|
||||||
canvasbg.appendChild(rect);
|
|
||||||
svgroot.insertBefore(canvasbg, svgcontent);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function: SelectorManager.requestSelector
|
|
||||||
// Returns the selector based on the given element
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// elem - DOM element to get the selector for
|
|
||||||
this.requestSelector = function(elem) {
|
|
||||||
if (elem == null) return null;
|
|
||||||
var N = this.selectors.length;
|
|
||||||
// if we've already acquired one for this element, return it
|
|
||||||
if (typeof(this.selectorMap[elem.id]) == "object") {
|
|
||||||
this.selectorMap[elem.id].locked = true;
|
|
||||||
return this.selectorMap[elem.id];
|
|
||||||
}
|
|
||||||
for (var i = 0; i < N; ++i) {
|
|
||||||
if (this.selectors[i] && !this.selectors[i].locked) {
|
|
||||||
this.selectors[i].locked = true;
|
|
||||||
this.selectors[i].reset(elem);
|
|
||||||
this.selectorMap[elem.id] = this.selectors[i];
|
|
||||||
return this.selectors[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// if we reached here, no available selectors were found, we create one
|
|
||||||
this.selectors[N] = new Selector(N, elem);
|
|
||||||
this.selectorParentGroup.appendChild(this.selectors[N].selectorGroup);
|
|
||||||
this.selectorMap[elem.id] = this.selectors[N];
|
|
||||||
return this.selectors[N];
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function: SelectorManager.releaseSelector
|
|
||||||
// Removes the selector of the given element (hides selection box)
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// elem - DOM element to remove the selector for
|
|
||||||
this.releaseSelector = function(elem) {
|
|
||||||
if (elem == null) return;
|
|
||||||
var N = this.selectors.length,
|
|
||||||
sel = this.selectorMap[elem.id];
|
|
||||||
for (var i = 0; i < N; ++i) {
|
|
||||||
if (this.selectors[i] && this.selectors[i] == sel) {
|
|
||||||
if (sel.locked == false) {
|
|
||||||
console.log("WARNING! selector was released but was already unlocked");
|
|
||||||
}
|
|
||||||
delete this.selectorMap[elem.id];
|
|
||||||
sel.locked = false;
|
|
||||||
sel.selectedElement = null;
|
|
||||||
sel.showGrips(false);
|
|
||||||
|
|
||||||
// remove from DOM and store reference in JS but only if it exists in the DOM
|
|
||||||
try {
|
|
||||||
sel.selectorGroup.setAttribute("display", "none");
|
|
||||||
} catch(e) { }
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function: SelectorManager.getRubberBandBox
|
|
||||||
// Returns the rubberBandBox DOM element. This is the rectangle drawn by the user for selecting/zooming
|
|
||||||
this.getRubberBandBox = function() {
|
|
||||||
if (!this.rubberBandBox) {
|
|
||||||
this.rubberBandBox = this.selectorParentGroup.appendChild(
|
|
||||||
addSvgElementFromJson({ "element": "rect",
|
|
||||||
"attr": {
|
|
||||||
"id": "selectorRubberBand",
|
|
||||||
"fill": "#22C",
|
|
||||||
"fill-opacity": 0.15,
|
|
||||||
"stroke": "#22C",
|
|
||||||
"stroke-width": 0.5,
|
|
||||||
"display": "none",
|
|
||||||
"style": "pointer-events:none"
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return this.rubberBandBox;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.initGroup();
|
|
||||||
};
|
|
||||||
}());
|
|
||||||
|
|
||||||
// Function: assignAttributes
|
|
||||||
// Assigns multiple attributes to an element.
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// node - DOM element to apply new attribute values to
|
|
||||||
// attrs - Object with attribute keys/values
|
|
||||||
// suspendLength - Optional integer of milliseconds to suspend redraw
|
|
||||||
// unitCheck - Boolean to indicate the need to use svgedit.units.setUnitAttr
|
|
||||||
var assignAttributes = this.assignAttributes = function(node, attrs, suspendLength, unitCheck) {
|
|
||||||
if(!suspendLength) suspendLength = 0;
|
|
||||||
// Opera has a problem with suspendRedraw() apparently
|
|
||||||
var handle = null;
|
|
||||||
if (!svgedit.browsersupport.isOpera()) svgroot.suspendRedraw(suspendLength);
|
|
||||||
|
|
||||||
for (var i in attrs) {
|
|
||||||
var ns = (i.substr(0,4) === "xml:" ? xmlns :
|
|
||||||
i.substr(0,6) === "xlink:" ? xlinkns : null);
|
|
||||||
|
|
||||||
if(ns) {
|
|
||||||
node.setAttributeNS(ns, i, attrs[i]);
|
|
||||||
} else if(!unitCheck) {
|
|
||||||
node.setAttribute(i, attrs[i]);
|
|
||||||
} else {
|
|
||||||
svgedit.units.setUnitAttr(node, i, attrs[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!svgedit.browsersupport.isOpera()) svgroot.unsuspendRedraw(handle);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function: cleanupElement
|
|
||||||
// Remove unneeded (default) attributes, makes resulting SVG smaller
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// element - DOM element to clean up
|
|
||||||
var cleanupElement = this.cleanupElement = function(element) {
|
|
||||||
var handle = svgroot.suspendRedraw(60);
|
|
||||||
var defaults = {
|
|
||||||
'fill-opacity':1,
|
|
||||||
'stop-opacity':1,
|
|
||||||
'opacity':1,
|
|
||||||
'stroke':'none',
|
|
||||||
'stroke-dasharray':'none',
|
|
||||||
'stroke-linejoin':'miter',
|
|
||||||
'stroke-linecap':'butt',
|
|
||||||
'stroke-opacity':1,
|
|
||||||
'stroke-width':1,
|
|
||||||
'rx':0,
|
|
||||||
'ry':0
|
|
||||||
}
|
|
||||||
|
|
||||||
for(var attr in defaults) {
|
|
||||||
var val = defaults[attr];
|
|
||||||
if(element.getAttribute(attr) == val) {
|
|
||||||
element.removeAttribute(attr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
svgroot.unsuspendRedraw(handle);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Function: addSvgElementFromJson
|
|
||||||
// Create a new SVG element based on the given object keys/values and add it to the current layer
|
|
||||||
// The element will be ran through cleanupElement before being returned
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// data - Object with the following keys/values:
|
|
||||||
// * element - DOM element to create
|
|
||||||
// * attr - Object with attributes/values to assign to the new element
|
|
||||||
// * curStyles - Boolean indicating that current style attributes should be applied first
|
|
||||||
//
|
|
||||||
// Returns: The new element
|
|
||||||
var addSvgElementFromJson = this.addSvgElementFromJson = function(data) {
|
|
||||||
var shape = getElem(data.attr.id);
|
|
||||||
// if shape is a path but we need to create a rect/ellipse, then remove the path
|
|
||||||
if (shape && data.element != shape.tagName) {
|
|
||||||
current_layer.removeChild(shape);
|
|
||||||
shape = null;
|
|
||||||
}
|
|
||||||
if (!shape) {
|
|
||||||
shape = svgdoc.createElementNS(svgns, data.element);
|
|
||||||
if (current_layer) {
|
|
||||||
(current_group || current_layer).appendChild(shape);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(data.curStyles) {
|
|
||||||
assignAttributes(shape, {
|
|
||||||
"fill": cur_shape.fill,
|
|
||||||
"stroke": cur_shape.stroke,
|
|
||||||
"stroke-width": cur_shape.stroke_width,
|
|
||||||
"stroke-dasharray": cur_shape.stroke_dasharray,
|
|
||||||
"stroke-linejoin": cur_shape.stroke_linejoin,
|
|
||||||
"stroke-linecap": cur_shape.stroke_linecap,
|
|
||||||
"stroke-opacity": cur_shape.stroke_opacity,
|
|
||||||
"fill-opacity": cur_shape.fill_opacity,
|
|
||||||
"opacity": cur_shape.opacity / 2,
|
|
||||||
"style": "pointer-events:inherit"
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
assignAttributes(shape, data.attr, 100);
|
|
||||||
cleanupElement(shape);
|
|
||||||
return shape;
|
|
||||||
};
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
// TODO: make this string optional and set by the client
|
// TODO: make this string optional and set by the client
|
||||||
var comment = svgdoc.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ ");
|
var comment = svgdoc.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ ");
|
||||||
|
@ -913,12 +511,6 @@ var all_layers = [],
|
||||||
// String with image URL of last loadable image
|
// String with image URL of last loadable image
|
||||||
last_good_img_url = curConfig.imgPath + 'logo.png',
|
last_good_img_url = curConfig.imgPath + 'logo.png',
|
||||||
|
|
||||||
// pointer to the current layer <g>
|
|
||||||
current_layer = null,
|
|
||||||
|
|
||||||
// pointer to current group (for in-group editing)
|
|
||||||
current_group = null,
|
|
||||||
|
|
||||||
// Array with current disabled elements (for in-group editing)
|
// Array with current disabled elements (for in-group editing)
|
||||||
disabled_elems = [],
|
disabled_elems = [],
|
||||||
|
|
||||||
|
@ -938,38 +530,10 @@ var all_layers = [],
|
||||||
current_mode = "select",
|
current_mode = "select",
|
||||||
|
|
||||||
// String with the current direction in which an element is being resized
|
// String with the current direction in which an element is being resized
|
||||||
current_resize_mode = "none",
|
current_resize_mode = "none";
|
||||||
|
|
||||||
// Object containing data for the currently selected styles
|
// Current text style properties
|
||||||
all_properties = {
|
var cur_text = all_properties.text,
|
||||||
shape: {
|
|
||||||
fill: "#" + curConfig.initFill.color,
|
|
||||||
fill_paint: null,
|
|
||||||
fill_opacity: curConfig.initFill.opacity,
|
|
||||||
stroke: "#" + curConfig.initStroke.color,
|
|
||||||
stroke_paint: null,
|
|
||||||
stroke_opacity: curConfig.initStroke.opacity,
|
|
||||||
stroke_width: curConfig.initStroke.width,
|
|
||||||
stroke_dasharray: 'none',
|
|
||||||
stroke_linejoin: 'miter',
|
|
||||||
stroke_linecap: 'butt',
|
|
||||||
opacity: curConfig.initOpacity
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
all_properties.text = $.extend(true, {}, all_properties.shape);
|
|
||||||
$.extend(all_properties.text, {
|
|
||||||
fill: "#000000",
|
|
||||||
stroke_width: 0,
|
|
||||||
font_size: 24,
|
|
||||||
font_family: 'serif'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Current shape style properties
|
|
||||||
var cur_shape = all_properties.shape,
|
|
||||||
|
|
||||||
// Current text style properties
|
|
||||||
cur_text = all_properties.text,
|
|
||||||
|
|
||||||
// Current general properties
|
// Current general properties
|
||||||
cur_properties = cur_shape,
|
cur_properties = cur_shape,
|
||||||
|
@ -984,9 +548,6 @@ var cur_shape = all_properties.shape,
|
||||||
// The DOM element that was just selected
|
// The DOM element that was just selected
|
||||||
justSelected = null,
|
justSelected = null,
|
||||||
|
|
||||||
// this object manages selectors for us
|
|
||||||
selectorManager = this.selectorManager = new SelectorManager(),
|
|
||||||
|
|
||||||
// DOM element for selection rectangle drawn by the user
|
// DOM element for selection rectangle drawn by the user
|
||||||
rubberBox = null,
|
rubberBox = null,
|
||||||
|
|
||||||
|
@ -1141,7 +702,7 @@ var getIntersectionList = this.getIntersectionList = function(rect) {
|
||||||
//
|
//
|
||||||
// Returns:
|
// Returns:
|
||||||
// A single bounding box object
|
// A single bounding box object
|
||||||
var getStrokedBBox = this.getStrokedBBox = function(elems) {
|
getStrokedBBox = this.getStrokedBBox = function(elems) {
|
||||||
if(!elems) elems = getVisibleElements();
|
if(!elems) elems = getVisibleElements();
|
||||||
if(!elems.length) return false;
|
if(!elems.length) return false;
|
||||||
// Make sure the expected BBox is returned if the element is a group
|
// Make sure the expected BBox is returned if the element is a group
|
||||||
|
@ -1156,7 +717,7 @@ var getStrokedBBox = this.getStrokedBBox = function(elems) {
|
||||||
|
|
||||||
var angle = svgedit.utilities.getRotationAngle(elem);
|
var angle = svgedit.utilities.getRotationAngle(elem);
|
||||||
if ((angle && angle % 90) ||
|
if ((angle && angle % 90) ||
|
||||||
svgedit.math.hasMatrixTransform(getTransformList(elem))) {
|
svgedit.math.hasMatrixTransform(svgedit.transformlist.getTransformList(elem))) {
|
||||||
// Accurate way to get BBox of rotated element in Firefox:
|
// Accurate way to get BBox of rotated element in Firefox:
|
||||||
// Put element in group and get its BBox
|
// Put element in group and get its BBox
|
||||||
|
|
||||||
|
@ -8894,6 +8455,7 @@ this.setSegType = function(new_type) {
|
||||||
pathActions.setSegType(new_type);
|
pathActions.setSegType(new_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(codedread): Remove the getBBox argument and split this function into two.
|
||||||
// Function: convertToPath
|
// Function: convertToPath
|
||||||
// Convert selected element to a path, or get the BBox of an element-as-path
|
// Convert selected element to a path, or get the BBox of an element-as-path
|
||||||
//
|
//
|
||||||
|
@ -10018,7 +9580,6 @@ this.getPrivateMethods = function() {
|
||||||
round: round,
|
round: round,
|
||||||
runExtensions: runExtensions,
|
runExtensions: runExtensions,
|
||||||
sanitizeSvg: sanitizeSvg,
|
sanitizeSvg: sanitizeSvg,
|
||||||
SelectorManager: SelectorManager,
|
|
||||||
shortFloat: shortFloat,
|
shortFloat: shortFloat,
|
||||||
SVGEditTransformList: svgedit.transformlist.SVGTransformList,
|
SVGEditTransformList: svgedit.transformlist.SVGTransformList,
|
||||||
toString: toString,
|
toString: toString,
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
// 1) jQuery
|
// 1) jQuery
|
||||||
// 2) browsersupport.js
|
// 2) browsersupport.js
|
||||||
// 3) svgtransformlist.js
|
// 3) svgtransformlist.js
|
||||||
|
// 4) math.js
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ var typeMap_ = {px: 1};
|
||||||
* Initializes this module.
|
* Initializes this module.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* elementContainer - an object implemnting the ElementContainer interface.
|
* elementContainer - an object implementing the ElementContainer interface.
|
||||||
*/
|
*/
|
||||||
svgedit.units.init = function(elementContainer) {
|
svgedit.units.init = function(elementContainer) {
|
||||||
elementContainer_ = elementContainer;
|
elementContainer_ = elementContainer;
|
||||||
|
|
|
@ -18,6 +18,6 @@ window.setTimeout(function() {
|
||||||
var f = iframes[i];
|
var f = iframes[i];
|
||||||
f.style.height = (f.contentDocument.body.scrollHeight + 20) + 'px';
|
f.style.height = (f.contentDocument.body.scrollHeight + 20) + 'px';
|
||||||
}
|
}
|
||||||
}, 1000);
|
}, 1200);
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
|
@ -7,6 +7,7 @@
|
||||||
<script type='text/javascript' src='qunit/qunit.js'></script>
|
<script type='text/javascript' src='qunit/qunit.js'></script>
|
||||||
<script type='text/javascript'>
|
<script type='text/javascript'>
|
||||||
$(function() {
|
$(function() {
|
||||||
|
// TODO(codedread): Write tests for handling history events.
|
||||||
|
|
||||||
// Mocked out methods.
|
// Mocked out methods.
|
||||||
svgedit.transformlist = {};
|
svgedit.transformlist = {};
|
||||||
|
@ -547,6 +548,8 @@
|
||||||
batch.unapply();
|
batch.unapply();
|
||||||
equals(concatResult, 'cba');
|
equals(concatResult, 'cba');
|
||||||
|
|
||||||
|
MockCommand.prototype.unapply = function() {};
|
||||||
|
|
||||||
tearDown();
|
tearDown();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel='stylesheet' href='qunit/qunit.css' type='text/css'/>
|
||||||
|
<script src='../editor/jquery.js'></script>
|
||||||
|
<script type='text/javascript' src='../editor/select.js'></script>
|
||||||
|
<script type='text/javascript' src='qunit/qunit.js'></script>
|
||||||
|
<script type='text/javascript'>
|
||||||
|
$(function() {
|
||||||
|
// log function
|
||||||
|
QUnit.log = function(result, message) {
|
||||||
|
if (window.console && window.console.log) {
|
||||||
|
window.console.log(result +' :: '+ message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module('svgedit.select');
|
||||||
|
|
||||||
|
test('Test svgedit.select package', function() {
|
||||||
|
expect(10);
|
||||||
|
|
||||||
|
ok(svgedit.select);
|
||||||
|
ok(svgedit.select.Selector);
|
||||||
|
ok(svgedit.select.SelectorManager);
|
||||||
|
ok(svgedit.select.init);
|
||||||
|
ok(svgedit.select.getSelectorManager);
|
||||||
|
equals(typeof svgedit.select, typeof {});
|
||||||
|
equals(typeof svgedit.select.Selector, typeof function(){});
|
||||||
|
equals(typeof svgedit.select.SelectorManager, typeof function(){});
|
||||||
|
equals(typeof svgedit.select.init, typeof function(){});
|
||||||
|
equals(typeof svgedit.select.getSelectorManager, typeof function(){});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 id='qunit-header'>Unit Tests for select.js</h1>
|
||||||
|
<h2 id='qunit-banner'></h2>
|
||||||
|
<h2 id='qunit-userAgent'></h2>
|
||||||
|
<ol id='qunit-tests'>
|
||||||
|
</ol>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -12,6 +12,7 @@
|
||||||
<script type="text/javascript" src="../editor/svgutils.js"></script>
|
<script type="text/javascript" src="../editor/svgutils.js"></script>
|
||||||
<script type="text/javascript" src="../editor/sanitize.js"></script>
|
<script type="text/javascript" src="../editor/sanitize.js"></script>
|
||||||
<script type="text/javascript" src="../editor/history.js"></script>
|
<script type="text/javascript" src="../editor/history.js"></script>
|
||||||
|
<script type="text/javascript" src="../editor/select.js"></script>
|
||||||
<script type="text/javascript" src="../editor/svgcanvas.js"></script>
|
<script type="text/javascript" src="../editor/svgcanvas.js"></script>
|
||||||
<script type="text/javascript" src="qunit/qunit.js"></script>
|
<script type="text/javascript" src="qunit/qunit.js"></script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
Loading…
Reference in New Issue