mirror of
https://github.com/scratchfoundation/scratchjr.git
synced 2024-11-25 08:38:30 -05:00
Consolidation of PathBkg, PathEdit, PathMgmt, PathTools
This commit is contained in:
parent
1479db4633
commit
01973b5dae
5 changed files with 2070 additions and 2054 deletions
2070
src/painteditor/Path.js
Normal file
2070
src/painteditor/Path.js
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1,504 +0,0 @@
|
|||
///////////////////////////////////////////////////
|
||||
// Background Cropping with Path
|
||||
///////////////////////////////////////////////////
|
||||
|
||||
Path.checkBackgroundCrop = function (shape) {
|
||||
var ocmds = Path.getPointsAndCmds(shape);
|
||||
var list = Layer.findUnderMe(shape);
|
||||
var iscropped = (list.length == 0) ? Path.createFromBkg(shape) : Path.someOverlaps(shape, list);
|
||||
if (iscropped) {
|
||||
shape.parentNode.removeChild(shape, list);
|
||||
Layer.bringElementsToFront();
|
||||
} else {
|
||||
var d = Path.getDattribute(ocmds);
|
||||
shape.setAttribute('d', d);
|
||||
}
|
||||
};
|
||||
|
||||
Path.someOverlaps = function (shape, list) {
|
||||
var cropped = false;
|
||||
Path.strechEdges(shape);
|
||||
var box = SVGTools.getBox(shape);
|
||||
var box2 = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 480,
|
||||
height: 360
|
||||
};
|
||||
if (Path.withinBounds(box, box2)) {
|
||||
return cropped;
|
||||
}
|
||||
if (!Path.isClockWise(shape.getAttribute('d'))) {
|
||||
shape.setAttribute('d', Path.flip(shape));
|
||||
}
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var node = list[i];
|
||||
if (node.tagName.toLowerCase() == 'image') {
|
||||
continue;
|
||||
}
|
||||
if (node.tagName == 'clipPath') {
|
||||
continue;
|
||||
}
|
||||
var contatctPoints = Path.getContactPoints(shape, node);
|
||||
if (contatctPoints.length < 2) {
|
||||
continue;
|
||||
}
|
||||
var cantcrop = (node.id.indexOf('staticbkg') < 0) && (node.getAttribute('stencil') != 'yes');
|
||||
if (cantcrop) {
|
||||
continue;
|
||||
}
|
||||
if (!Path.withinBounds(box, box2)) {
|
||||
continue;
|
||||
}
|
||||
if (Path.endsSameSide(shape)) {
|
||||
continue;
|
||||
}
|
||||
if (Path.isClockWise(node.getAttribute('d'))) {
|
||||
node.setAttribute('d', Path.flip(node));
|
||||
}
|
||||
if (Path.createStencil(shape, node)) {
|
||||
cropped = true;
|
||||
}
|
||||
}
|
||||
return cropped;
|
||||
};
|
||||
|
||||
Path.createStencil = function (shape, mt) {
|
||||
var isimage = SVGImage.getImage(mt) != null;
|
||||
var list = Path.getPointsAndCmds(shape);
|
||||
var other = Path.getPointsAndCmds(mt);
|
||||
var index = Layer.groupStartsAt(gn('layer1'), mt);
|
||||
var group = Layer.onTopOf(gn('layer1'), index);
|
||||
//Layer.onTopOfBy(gn("layer1"), mt, 0.1, index, [mt]);
|
||||
var p = mt.parentNode;
|
||||
for (var i = 0; i < group.length; i++) {
|
||||
p.appendChild(group[i]);
|
||||
}
|
||||
var contatctPoints = Path.getContactPoints(shape, mt);
|
||||
// console.log ("createStencil", contatctPoints, "shape", shape.id, "mt", mt.id);
|
||||
if (contatctPoints.length < 2) {
|
||||
return false;
|
||||
}
|
||||
var attr = Path.getStylingFrom(mt);
|
||||
if (isimage) {
|
||||
attr.fill = 'none';
|
||||
}
|
||||
var path = Path.makeAcut(shape, list, other, contatctPoints[0], contatctPoints[1], attr);
|
||||
path.setAttribute('stencil', 'yes');
|
||||
gn('layer1').appendChild(path);
|
||||
var attr2 = Path.getStylingFrom(shape);
|
||||
attr2.fill = isimage ? 'none' : mt.getAttribute('fill');
|
||||
attr2['stroke-width'] = isimage ? 0 : Paint.strokewidth;
|
||||
for (var val in attr2) {
|
||||
mt.setAttribute(val, attr2[val]);
|
||||
}
|
||||
attr2.id = getIdFor('path');
|
||||
attr2.d = mt.getAttribute('d');
|
||||
if (isimage) {
|
||||
mt = SVGTools.addChild(gn('layer1'), 'path', attr2);
|
||||
}
|
||||
mt.setAttribute('d', Path.getComplement(shape, mt, contatctPoints[0], contatctPoints[1]));
|
||||
mt.setAttribute('d', Path.flip(mt));
|
||||
mt.setAttribute('stencil', 'yes');
|
||||
for (var j = 0; j < group.length; j++) {
|
||||
p.appendChild(group[j]);
|
||||
} // make sure to bring to front the old stuff
|
||||
if (contatctPoints.length > 2) {
|
||||
Path.cutBoard(gn('layer1'), contatctPoints, shape, path, 2);
|
||||
}
|
||||
return !isimage;
|
||||
};
|
||||
|
||||
Path.cutBoard = function (p, ptsincontact, shape, mt, n) {
|
||||
if (n > ptsincontact.length - 2) {
|
||||
return;
|
||||
}
|
||||
if (Path.isClockWise(mt.getAttribute('d'))) {
|
||||
mt.setAttribute('d', Path.flip(mt));
|
||||
}
|
||||
var list = Path.getPointsAndCmds(shape);
|
||||
var other = Path.getPointsAndCmds(mt);
|
||||
var seam1 = ptsincontact[n];
|
||||
var seam2 = ptsincontact[n + 1];
|
||||
var attr = Path.getStylingFrom(mt);
|
||||
var hitpoints = Path.updateContactPoints(seam1, seam2, list, other);
|
||||
if (Path.isValidSegment(hitpoints)) {
|
||||
var path = Path.makeAcut(shape, list, other, hitpoints[0], hitpoints[1], attr);
|
||||
p.appendChild(path);
|
||||
path.setAttribute('stencil', 'yes');
|
||||
gn('layer1').appendChild(path);
|
||||
var attr2 = Path.getStylingFrom(shape);
|
||||
attr2.fill = mt.getAttribute('fill');
|
||||
attr2['stroke-width'] = Paint.strokewidth;
|
||||
for (var val in attr2) {
|
||||
mt.setAttribute(val, attr2[val]);
|
||||
}
|
||||
mt.setAttribute('d', Path.getComplement(shape, mt, hitpoints[0], hitpoints[1]));
|
||||
mt.setAttribute('d', Path.flip(mt));
|
||||
mt.setAttribute('stencil', 'yes');
|
||||
Path.cutBoard(p, ptsincontact, shape, path, n + 2);
|
||||
}
|
||||
};
|
||||
|
||||
Path.moveToEdge = function (last) {
|
||||
if (last.x <= -10) {
|
||||
return null;
|
||||
}
|
||||
if (last.x >= 490) {
|
||||
return null;
|
||||
}
|
||||
if (last.y >= 370) {
|
||||
return null;
|
||||
}
|
||||
if (last.y <= -10) {
|
||||
return null;
|
||||
}
|
||||
if (last.x <= 0) {
|
||||
return {
|
||||
x: -10,
|
||||
y: last.y
|
||||
};
|
||||
}
|
||||
if (last.y <= 0) {
|
||||
return {
|
||||
x: last.x,
|
||||
y: -10
|
||||
};
|
||||
}
|
||||
if (last.x >= 480) {
|
||||
return {
|
||||
x: 490,
|
||||
y: last.y
|
||||
};
|
||||
}
|
||||
if (last.y >= 360) {
|
||||
return {
|
||||
x: last.x,
|
||||
y: 370
|
||||
};
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Path.atEdge = function (pt) {
|
||||
if (pt.x <= -10) {
|
||||
return true;
|
||||
}
|
||||
if (pt.x >= 490) {
|
||||
return true;
|
||||
}
|
||||
if (pt.y >= 370) {
|
||||
return true;
|
||||
}
|
||||
if (pt.y <= -10) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Path.endsSameSide = function (shape) {
|
||||
var cmds = Path.getPointsAndCmds(shape);
|
||||
var last = cmds[cmds.length - 1].pt;
|
||||
var first = cmds[0].pt;
|
||||
return Path.findEdge(first) == Path.findEdge(last);
|
||||
};
|
||||
|
||||
Path.findEdge = function (pt) {
|
||||
if (pt.x <= 0) {
|
||||
return 'W';
|
||||
}
|
||||
if (pt.x >= 480) {
|
||||
return 'E';
|
||||
}
|
||||
if (pt.y >= 360) {
|
||||
return 'S';
|
||||
}
|
||||
return 'N';
|
||||
};
|
||||
|
||||
Path.createFromBkg = function (shape) {
|
||||
//console.log ("createFromBkg");
|
||||
Path.strechEdges(shape);
|
||||
var box = SVGTools.getBox(shape);
|
||||
var box2 = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 480,
|
||||
height: 360
|
||||
};
|
||||
if (Path.withinBounds(box, box2)) {
|
||||
return false;
|
||||
}
|
||||
if (Path.endsSameSide(shape)) {
|
||||
return false;
|
||||
}
|
||||
// get a duplicate of the background
|
||||
var attr2 = {
|
||||
'id': getIdFor('path'),
|
||||
'opacity': 1,
|
||||
fill: 'white'
|
||||
};
|
||||
var cmds = [['M', -10, -10], ['L', 490, -10], ['L', 490, 370], ['L', -10, 370], ['L', -10, -10]];
|
||||
attr2.d = SVG2Canvas.arrayToString(cmds);
|
||||
var mt = SVGTools.addChild(gn('layer1'), 'path', attr2);
|
||||
mt.setAttribute('stencil', 'yes');
|
||||
if (!Path.isClockWise(shape.getAttribute('d'))) {
|
||||
shape.setAttribute('d', Path.flip(shape));
|
||||
}
|
||||
if (Path.isClockWise(mt.getAttribute('d'))) {
|
||||
mt.setAttribute('d', Path.flip(mt));
|
||||
}
|
||||
var attr = Path.getStylingFrom(gn('staticbkg'));
|
||||
for (var val in attr) {
|
||||
mt.setAttribute(val, attr[val]);
|
||||
}
|
||||
return Path.createStencil(shape, mt);
|
||||
};
|
||||
|
||||
Path.withinBounds = function (box, box2) {
|
||||
if ((box.x <= box2.x) && ((box.width + box.x) >= box2.width)) {
|
||||
return false;
|
||||
}
|
||||
if (box.y > box2.y) {
|
||||
return true;
|
||||
}
|
||||
if ((box.height + box.y) < box2.height) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Path.strechEdges = function (shape) {
|
||||
var cmds = Path.getPointsAndCmds(shape);
|
||||
var last = cmds[cmds.length - 1].pt;
|
||||
var newpt;
|
||||
if (!Path.atEdge(last)) {
|
||||
var addtoend = Path.moveToEdge(last);
|
||||
if (addtoend) {
|
||||
cmds.push({
|
||||
cmd: 'C',
|
||||
pt: addtoend
|
||||
});
|
||||
} else {
|
||||
newpt = Vector.sum(last, Vector.diff(last, cmds[cmds.length - 2].pt));
|
||||
cmds.push({
|
||||
cmd: 'C',
|
||||
pt: newpt
|
||||
});
|
||||
}
|
||||
}
|
||||
var first = cmds[0].pt;
|
||||
if (!Path.atEdge(first)) {
|
||||
cmds[0].cmd = 'L';
|
||||
var addtostart = Path.moveToEdge(first);
|
||||
if (addtostart) {
|
||||
cmds.unshift({
|
||||
cmd: 'M',
|
||||
pt: addtostart
|
||||
});
|
||||
} else { // add fudge factor
|
||||
newpt = Vector.sum(first, Vector.diff(first, cmds[1].pt));
|
||||
cmds.unshift({
|
||||
cmd: 'M',
|
||||
pt: newpt
|
||||
});
|
||||
}
|
||||
}
|
||||
var d = Path.getDattribute(cmds);
|
||||
shape.setAttribute('d', d);
|
||||
};
|
||||
|
||||
///////////////////////
|
||||
// path management
|
||||
///////////////////////
|
||||
|
||||
Path.getContactPoints = function (eraser, hitobj) {
|
||||
// console.log ("getContactPoints", eraser.id, hitobj.id);
|
||||
var list = Path.getPointsAndCmds(eraser);
|
||||
var other = Path.getPointsAndCmds(hitobj);
|
||||
var res = [];
|
||||
for (var i = 1; i < list.length; i++) {
|
||||
var v1 = list[i - 1].pt;
|
||||
var v2 = list[i].pt;
|
||||
for (var j = 1; j < other.length; j++) {
|
||||
var v3 = other[j - 1].pt;
|
||||
var v4 = other[j].pt;
|
||||
var pt = Vector.lineIntersect(v1, v2, v3, v4);
|
||||
if (pt) {
|
||||
res.push([i, j, pt]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
Path.makeAcut = function (eraser, list, other, goin, goout, attr) {
|
||||
var epathdata = SVG2Canvas.getSVGcommands(eraser);
|
||||
attr.d = Path.chopSection(list, epathdata, other, goin, goout);
|
||||
attr.id = getIdFor('path');
|
||||
var newpath = SVGTools.addChild(gn('layer1'), 'path', attr);
|
||||
newpath.setAttribute('d', Path.flip(newpath));
|
||||
return newpath;
|
||||
};
|
||||
|
||||
Path.chopSection = function (list, edata, other, goin, goout) {
|
||||
var d = 'M' + goin[2].x + ',' + goin[2].y;
|
||||
d += SVG2Canvas.arrayToString(edata.slice(goin[0], goout[0]));
|
||||
d += Path.lineSeg(goout[2]);
|
||||
var joinIn = goin[1];
|
||||
var joinOut = goout[1];
|
||||
var plist = Path.getShapeFromPoints(joinIn, joinOut, goin[2], other);
|
||||
return Path.fromPointsToPath(d, plist);
|
||||
};
|
||||
|
||||
Path.getShapeFromPoints = function (joinIn, joinOut, pt, other) {
|
||||
var plist = [];
|
||||
if (joinOut > joinIn) {
|
||||
var indx = other.length;
|
||||
//Vector.len (Vector.diff(other[0].pt, other[other.length - 1].pt)) == 0 ? other.length - 1 : other.length;
|
||||
plist = other.slice(joinOut, indx);
|
||||
plist = plist.concat(other.slice(0, joinIn));
|
||||
|
||||
} else if (joinOut != joinIn) {
|
||||
plist = other.slice(joinOut, joinIn);
|
||||
}
|
||||
plist.push({
|
||||
cmd: 'L',
|
||||
pt: pt
|
||||
});
|
||||
return plist;
|
||||
};
|
||||
|
||||
Path.fromPointsToPath = function (d, plist) {
|
||||
var prev = plist[0];
|
||||
d += Path.lineSeg(prev.pt);
|
||||
for (var i = 1; i < plist.length - 1; i++) {
|
||||
d += Path.getNextCmd(i, prev, plist);
|
||||
prev = plist[i];
|
||||
}
|
||||
d += Path.lineSeg(plist[plist.length - 1].pt);
|
||||
return d;
|
||||
};
|
||||
|
||||
Path.getNextCmd = function (i, prev, plist, endpt) {
|
||||
var next = '';
|
||||
switch (plist[i].cmd.toUpperCase()) {
|
||||
case 'M':
|
||||
if (prev.cmd == 'C') {
|
||||
var ptafter = endpt ? endpt : plist[i + 1].pt;
|
||||
next = Path.curveSeg(prev.pt, plist[i].pt, ptafter);
|
||||
} else {
|
||||
next = Path.lineSeg(plist[i].pt);
|
||||
}
|
||||
break;
|
||||
case 'C':
|
||||
case 'S':
|
||||
next = Path.curveSeg(prev.pt, plist[i].pt, endpt ? endpt : plist[i + 1].pt);
|
||||
break;
|
||||
default:
|
||||
next = Path.lineSeg(plist[i].pt);
|
||||
break;
|
||||
}
|
||||
return next;
|
||||
};
|
||||
|
||||
Path.getComplement = function (eraser, hitobj, goin, goout) {
|
||||
var edata = SVG2Canvas.getSVGcommands(eraser);
|
||||
var other = Path.getPointsAndCmds(hitobj);
|
||||
var d = 'M' + goin[2].x + ',' + goin[2].y;
|
||||
d += SVG2Canvas.arrayToString(edata.slice(goin[0], goout[0]));
|
||||
d += Path.lineSeg(goout[2]);
|
||||
var joinIn = goin[1];
|
||||
var joinOut = goout[1];
|
||||
var plist = Path.getFromPoints(joinIn, joinOut, goin[2], other);
|
||||
return Path.fromPointsToPath(d, plist);
|
||||
};
|
||||
|
||||
Path.getFromPoints = function (joinIn, joinOut, pt, other) {
|
||||
var plist = [];
|
||||
if (joinIn >= joinOut) {
|
||||
var indx = other.length;
|
||||
plist = other.slice(joinIn, indx);
|
||||
plist = plist.concat(other.slice(0, joinOut));
|
||||
} else {
|
||||
plist = other.slice(joinIn, joinOut);
|
||||
}
|
||||
if (plist.length > 0) {
|
||||
plist.reverse();
|
||||
}
|
||||
plist.push({
|
||||
cmd: 'L',
|
||||
pt: pt
|
||||
});
|
||||
return plist;
|
||||
};
|
||||
|
||||
Path.updateContactPoints = function (myseamin, myseamout, elist, newlist) {
|
||||
// in logic
|
||||
var hitout, hitin;
|
||||
var seamin1 = Path.updateContact(myseamin[0], elist, newlist);
|
||||
if (seamin1 == null) {
|
||||
var res1 = Path.extendSearch(myseamin[0], (myseamout[0]) - 1, elist, newlist);
|
||||
if (res1 != null) {
|
||||
hitin = [res1[0], res1[1], res1[2]];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
hitin = [myseamin[0], seamin1, myseamin[2]];
|
||||
}
|
||||
|
||||
// out logic
|
||||
var seamout1 = Path.updateContact(myseamout[0], elist, newlist);
|
||||
if (seamout1 == null) {
|
||||
var res2 = Path.extendSearch((myseamin[0]) + 1, (myseamout[0]) + 1, elist, newlist);
|
||||
if (res2 != null) {
|
||||
hitout = [res2[0], res2[1], res2[2]];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
hitout = [myseamout[0], seamout1, myseamout[2]];
|
||||
}
|
||||
return [hitin, hitout];
|
||||
};
|
||||
|
||||
Path.extendSearch = function (start, end, list, other) {
|
||||
for (var i = start; i < list.length; i++) {
|
||||
var v1 = list[i - 1].pt;
|
||||
var v2 = list[i].pt;
|
||||
for (var j = 1; j < other.length; j++) {
|
||||
var v3 = other[j - 1].pt;
|
||||
var v4 = other[j].pt;
|
||||
var pt = Vector.lineIntersect(v1, v2, v3, v4);
|
||||
if (pt) {
|
||||
return [i, j, pt];
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Path.updateContact = function (n, elist, newlist) {
|
||||
var v1 = elist[n - 1].pt;
|
||||
var v2 = elist[n].pt;
|
||||
for (var j = 1; j < newlist.length; j++) {
|
||||
var v3 = newlist[j - 1].pt;
|
||||
var v4 = newlist[j].pt;
|
||||
var pt = Vector.lineIntersect(v1, v2, v3, v4);
|
||||
if (pt) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Path.isValidSegment = function (hp) {
|
||||
if (hp == null) {
|
||||
return false;
|
||||
}
|
||||
if ((hp[0][1] == hp[1][1]) || (hp[0][2] == hp[1][1])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
|
@ -1,618 +0,0 @@
|
|||
Path.lineDotColor = 'white';
|
||||
Path.curveDotColor = '#009eff'; // "#0b72b5"
|
||||
Path.endDotColor = '#ffaa00';
|
||||
Path.selectedDotColor = 'lime';
|
||||
Path.selector = undefined;
|
||||
Path.dotsize = 6;
|
||||
Path.idotsize = 10;
|
||||
|
||||
Path.maxDistance = function () {
|
||||
return 20 / Paint.currentZoom;
|
||||
};
|
||||
|
||||
Path.importPath = function (elem) {
|
||||
var d = elem.getAttribute('d');
|
||||
var list = SVG2Canvas.getCommandList(d);
|
||||
var imported = Path.adaptPath(list);
|
||||
var path = SVG2Canvas.arrayToString(imported);
|
||||
elem.setAttribute('d', path);
|
||||
};
|
||||
|
||||
Path.adaptPath = function (list) {
|
||||
var res = [];
|
||||
var lastpt = {
|
||||
x: list[0][1],
|
||||
y: list[0][2]
|
||||
};
|
||||
var l;
|
||||
res.push(list[0]);
|
||||
for (var i = 1; i < list.length; i++) {
|
||||
var pts = list[i].concat();
|
||||
var cmd = pts.shift();
|
||||
switch (cmd.toLowerCase()) {
|
||||
case 'h':
|
||||
lastpt = {
|
||||
x: pts[0],
|
||||
y: lastpt.y
|
||||
};
|
||||
res.push(['L', lastpt.x, lastpt.y]);
|
||||
break;
|
||||
case 'v':
|
||||
lastpt = {
|
||||
x: lastpt.x,
|
||||
y: pts[0]
|
||||
};
|
||||
res.push(['L', lastpt.x, lastpt.y]);
|
||||
break;
|
||||
case 'l':
|
||||
lastpt = {
|
||||
x: pts[0],
|
||||
y: pts[1]
|
||||
};
|
||||
res.push(['L', lastpt.x, lastpt.y]);
|
||||
break;
|
||||
case 'c':
|
||||
l = pts.length;
|
||||
var nextpt = {
|
||||
x: pts[l - 2],
|
||||
y: pts[l - 1]
|
||||
};
|
||||
var thisPt = {
|
||||
x: pts[0],
|
||||
y: pts[1]
|
||||
};
|
||||
var diff = Math.floor(Vector.len(Vector.diff(lastpt, thisPt)));
|
||||
if (diff == 0) {
|
||||
res.push(['L', lastpt.x, lastpt.y]);
|
||||
}
|
||||
// if (diff == 0) console.log (i, "added at beginging");
|
||||
res.push(list[i]);
|
||||
var startAt = {
|
||||
x: pts[l - 4],
|
||||
y: pts[l - 3]
|
||||
};
|
||||
var diffend = Math.floor(Vector.len(Vector.diff(startAt, nextpt)));
|
||||
if (diffend == 0) {
|
||||
res.push(['L', nextpt.x, nextpt.y]);
|
||||
}
|
||||
// if (diffend == 0) console.log (i, "added at end");
|
||||
lastpt = nextpt;
|
||||
break;
|
||||
case 'z':
|
||||
res.push(list[i]);
|
||||
break;
|
||||
default:
|
||||
l = pts.length;
|
||||
lastpt = {
|
||||
x: pts[l - 2],
|
||||
y: pts[l - 1]
|
||||
};
|
||||
res.push(list[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// UI Management
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Path.showDots = function (shape) {
|
||||
Transform.applyToCmds(shape, Transform.combineAll(shape));
|
||||
Transform.eliminateAll(shape);
|
||||
var list = Path.getPointsForFirst(shape);
|
||||
// if (Vector.len (Vector.diff (list[0].pt, list[list.length -1].pt)) == 0) list[list.length -1].cmd = "Z";
|
||||
var g = gn('pathdots');
|
||||
if (g != null) {
|
||||
g.parentNode.removeChild(g);
|
||||
}
|
||||
g = document.createElementNS(Paint.xmlns, 'g');
|
||||
g.setAttribute('style', 'pointer-events:none');
|
||||
g.setAttribute('id', 'pathdots');
|
||||
var p = document.getElementById('layer1').parentNode;
|
||||
p.appendChild(g);
|
||||
var plist = Path.getPathDotsElem(g, list);
|
||||
for (var k = 0; k < plist.length; k++) {
|
||||
plist[k].setAttribute('parentid', shape.id);
|
||||
}
|
||||
shape.setAttribute('style', 'pointer-events:visibleStroke;');
|
||||
var lastdot = plist[plist.length - 1];
|
||||
var iscurve = SVG2Canvas.curveoptions.indexOf(lastdot.getAttribute('cmd')) > -1;
|
||||
lastdot.setAttribute('fill', iscurve ? Path.curveDotColor : Path.lineDotColor);
|
||||
lastdot.setAttribute('opacity', 0.6);
|
||||
var first = Path.getDotPoint(plist[0]);
|
||||
var lastpoint = Path.getDotPoint(lastdot);
|
||||
var farilyclose = (Vector.len(Vector.diff(lastpoint, first)) < 10) && (lastdot.getAttribute('cmd') != 'Z');
|
||||
if (farilyclose) {
|
||||
lastdot.setAttribute('fill', Path.endDotColor);
|
||||
}
|
||||
};
|
||||
|
||||
Path.getPathDotsElem = function (g, list) {
|
||||
var res = [];
|
||||
var first;
|
||||
var cp;
|
||||
for (var j = 0; j < list.length - 1; j++) {
|
||||
var pt = list[j].pt;
|
||||
var cmd = list[j].cmd;
|
||||
if (cmd == 'M') {
|
||||
first = pt;
|
||||
}
|
||||
cp = Path.getDot(g, cmd, pt);
|
||||
res.push(cp);
|
||||
cp.onmouseover = function (evt) {
|
||||
Path.highlightDot(evt);
|
||||
};
|
||||
cp.onmouseout = function (evt) {
|
||||
Path.unhighlightDot(evt);
|
||||
};
|
||||
}
|
||||
var last = list[list.length - 1];
|
||||
pt = last.pt;
|
||||
cmd = last.cmd;
|
||||
var prev = list[list.length - 2];
|
||||
if ((cmd.toLowerCase() != 'z') && (Vector.len(Vector.diff(first, pt)) == 0)) {
|
||||
cmd = 'x';
|
||||
cp = Path.getDot(g, cmd, pt);
|
||||
cp.style.visibility = 'hidden';
|
||||
} else {
|
||||
if ((Vector.len(Vector.diff(first, pt)) == 0) &&
|
||||
(cmd.toLowerCase() == 'z') &&
|
||||
(Vector.len(Vector.diff(first, prev.pt)) == 0)) {
|
||||
cp.setAttribute('cmd', 'x');
|
||||
cp.style.visibility = 'hidden';
|
||||
} else {
|
||||
if (cmd.toLowerCase() == 'z') {
|
||||
cmd = (prev.cmd == 'C') ? 'C' : 'L';
|
||||
}
|
||||
cp = Path.getDot(g, cmd, pt);
|
||||
}
|
||||
}
|
||||
res.push(cp);
|
||||
cp.onmouseover = function (evt) {
|
||||
Path.highlightDot(evt);
|
||||
};
|
||||
cp.onmouseout = function (evt) {
|
||||
Path.unhighlightDot(evt);
|
||||
};
|
||||
return res;
|
||||
};
|
||||
|
||||
Path.reshape = function (shape) {
|
||||
var list = Path.getDotsCoodinates(shape);
|
||||
// console.log (list.length, list[0]);
|
||||
var cmds = Path.getPointsForFirst(shape);
|
||||
var dist = Vector.len(Vector.diff(list[0].pt, list[list.length - 1].pt));
|
||||
var valid = list[list.length - 1].cmd.toLowerCase() != 'x';
|
||||
var res = [];
|
||||
for (var i = 0; i < cmds.length; i++) {
|
||||
if (list.length == 0) {
|
||||
res.push(cmds[i]);
|
||||
} else {
|
||||
if (list[0].cmd.toLowerCase() == 'x') { // elipse and rect have force close to keep joint
|
||||
list[0].cmd = cmds[i].cmd;
|
||||
list[0].pt = res[0].pt;
|
||||
}
|
||||
res.push(list[0]);
|
||||
list.shift();
|
||||
}
|
||||
}
|
||||
if (valid) {
|
||||
if ((dist < 10) && (res.length > 3)) {
|
||||
res[res.length - 1].cmd = 'z';
|
||||
res[0].pt = {
|
||||
x: res[res.length - 1].pt.x,
|
||||
y: res[res.length - 1].pt.y
|
||||
};
|
||||
} else {
|
||||
res[res.length - 1].cmd = (res[1].cmd == 'L') ? 'L' : 'C';
|
||||
}
|
||||
}
|
||||
var d = Path.getDattribute(res);
|
||||
if (SVG2Canvas.isCompoundPath(shape)) {
|
||||
var paths = shape.getAttribute('d').match(/[M][^M]*/g);
|
||||
for (var j = 1; j < paths.length; j++) {
|
||||
d += paths[j];
|
||||
}
|
||||
}
|
||||
shape.setAttributeNS(null, 'd', d);
|
||||
if (SVGImage.getImage(shape)) {
|
||||
SVGImage.rotatePointsOf(shape);
|
||||
}
|
||||
};
|
||||
|
||||
Path.getDotColor = function (shape, dot) {
|
||||
var cmds = Path.getPointsForFirst(shape);
|
||||
var indx = Path.getDotPos(dot);
|
||||
if (indx < 0) {
|
||||
return Path.curveDotColor;
|
||||
}
|
||||
if (indx >= (cmds.length - 1)) {
|
||||
return Path.endDotColor;
|
||||
}
|
||||
var cmd = cmds[indx].cmd;
|
||||
var iscurve = SVG2Canvas.curveoptions.indexOf(cmd) > -1;
|
||||
return iscurve ? Path.curveDotColor : Path.lineDotColor;
|
||||
};
|
||||
|
||||
Path.getDotPos = function (dot) {
|
||||
var arr = dot.id.split(' ');
|
||||
if (arr.length < 2) {
|
||||
return -1;
|
||||
}
|
||||
if (arr[0] != 'grab') {
|
||||
return -1;
|
||||
}
|
||||
return Number(arr[1]) - 1;
|
||||
};
|
||||
|
||||
Path.getDotPoint = function (dot) {
|
||||
var rot = Transform.extract(gn(dot.getAttribute('parentid')), 4);
|
||||
var mtx = Transform.getCombinedMatrices(gn(dot.getAttribute('parentid'))); // skips rotation matrices
|
||||
var pt = Transform.point(Number(dot.getAttribute('cx')), Number(dot.getAttribute('cy')), mtx.inverse());
|
||||
pt = Transform.point(pt.x, pt.y, rot.matrix.inverse());
|
||||
return pt;
|
||||
};
|
||||
|
||||
Path.isTip = function (grab) {
|
||||
var indx = Path.getDotPos(grab);
|
||||
if (indx < 0) {
|
||||
return false;
|
||||
}
|
||||
if (indx == 0) {
|
||||
return true;
|
||||
}
|
||||
return indx == (gn('pathdots').childElementCount - 1);
|
||||
};
|
||||
|
||||
Path.getDot = function (g, cmd, pt) {
|
||||
cmd = cmd.toUpperCase();
|
||||
var iscurve = SVG2Canvas.curveoptions.indexOf(cmd) > -1;
|
||||
var radius = Math.floor((isTablet ? Path.idotsize : Path.dotsize) / Paint.currentZoom) + 1;
|
||||
var skip = (cmd == 'Z');
|
||||
var cp = SVGTools.addChild(g, 'circle', {
|
||||
'id': getIdFor('grab'),
|
||||
'fill': iscurve ? Path.curveDotColor : Path.lineDotColor,
|
||||
'r': radius,
|
||||
'stroke': skip ? 'none' : '#064268',
|
||||
'stroke-width': 1,
|
||||
'pointer-events': skip ? 'none' : 'all',
|
||||
opacity: skip ? 0 : 0.8
|
||||
});
|
||||
cp.setAttributeNS(null, 'cx', pt.x);
|
||||
cp.setAttributeNS(null, 'cy', pt.y);
|
||||
cp.setAttribute('cmd', cmd);
|
||||
return cp;
|
||||
};
|
||||
|
||||
Path.highlightDot = function (e) {
|
||||
var shape = e.target;
|
||||
shape.setAttribute('fill', '#00ffff');
|
||||
shape.setAttribute('opacity', 1);
|
||||
};
|
||||
|
||||
Path.unhighlightDot = function (e) {
|
||||
var shape = e.target;
|
||||
if (!shape) {
|
||||
return;
|
||||
}
|
||||
var isbez = SVG2Canvas.curveoptions.indexOf(shape.getAttribute('cmd')) > -1;
|
||||
shape.setAttribute('fill', isbez ? Path.curveDotColor : Path.lineDotColor);
|
||||
shape.setAttribute('opacity', 0.6);
|
||||
};
|
||||
|
||||
Path.hideDots = function (shape) {
|
||||
if (shape) {
|
||||
shape.setAttribute('style', 'pointer-events:visiblePainted;');
|
||||
}
|
||||
var g = gn('pathdots');
|
||||
if (!g) {
|
||||
return;
|
||||
}
|
||||
g.parentNode.removeChild(g);
|
||||
};
|
||||
|
||||
Path.getDotsCoodinates = function () {
|
||||
var pointslist = [];
|
||||
for (var i = 0; i < gn('pathdots').childElementCount; i++) {
|
||||
var dot = gn('pathdots').childNodes[i];
|
||||
pointslist.push({
|
||||
cmd: dot.getAttribute('cmd'),
|
||||
pt: Path.getDotPoint(dot)
|
||||
});
|
||||
}
|
||||
return pointslist;
|
||||
};
|
||||
|
||||
Path.getDots = function () {
|
||||
var pointslist = [];
|
||||
for (var i = 0; i < gn('pathdots').childElementCount; i++) {
|
||||
pointslist.push(gn('pathdots').childNodes[i]);
|
||||
}
|
||||
return pointslist;
|
||||
};
|
||||
|
||||
Path.addDot = function (shape) {
|
||||
var g = gn('pathdots');
|
||||
g.parentNode.removeChild(g);
|
||||
var rot = Transform.extract(shape, 4);
|
||||
var newpt = Transform.point(Paint.initialPoint.x, Paint.initialPoint.y, rot.matrix.inverse());
|
||||
setCanvasSize(
|
||||
ScratchJr.workingCanvas,
|
||||
Paint.root.getAttribute('width') * Paint.currentZoom,
|
||||
Paint.root.getAttribute('height') * Paint.currentZoom
|
||||
);
|
||||
var ctx = ScratchJr.workingCanvas.getContext('2d');
|
||||
// uncomment for testing offscreen rendering for hit test
|
||||
// Paint.root.parentNode.appendChild(ScratchJr.workingCanvas);
|
||||
// setProps(ScratchJr.workingCanvas.style, {position: "absolute", left: "0px", top: "0px"});
|
||||
ctx.clearRect(0, 0, ScratchJr.workingCanvas.width, ScratchJr.workingCanvas.height);
|
||||
ctx.fillStyle = 'rgba(0,0,0,0)';
|
||||
ctx.lineWidth = Ghost.linemask;
|
||||
ctx.strokeStyle = '#ff00FF';
|
||||
shape.setAttribute('d', Path.addPoint(shape, ctx, newpt));
|
||||
Path.showDots(shape);
|
||||
PaintUndo.record();
|
||||
};
|
||||
|
||||
Path.getHitIndex = function (ctx, commands, pt) {
|
||||
ctx.save();
|
||||
ctx.beginPath();
|
||||
for (var i = 0; i < commands.length; i++) {
|
||||
SVG2Canvas.drawCommand(ctx, commands[i]);
|
||||
ctx.stroke();
|
||||
pt = Vector.floor(pt);
|
||||
var pixel = ctx.getImageData(pt.x, pt.y, 1, 1).data;
|
||||
if (pixel[3] != 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
return -1;
|
||||
};
|
||||
|
||||
Path.getHitPointIndex = function (list, pt) {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (Vector.len(Vector.diff(list[i].pt, pt)) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
Path.addPoint = function (shape, ctx, newpt) {
|
||||
var mycmds = SVG2Canvas.getSVGcommands(shape);
|
||||
var list = Path.getPointsAndCmds(shape);
|
||||
var newCmd;
|
||||
var indx = Path.getHitIndex(ctx, mycmds, Vector.floor(newpt));
|
||||
if (indx > -1) {
|
||||
var prevcmd = list[indx].cmd;
|
||||
if ((SVG2Canvas.curveoptions.indexOf(prevcmd) > -1) || (prevcmd.toLowerCase() == 'z')) {
|
||||
newCmd = {
|
||||
cmd: 'C',
|
||||
pt: newpt
|
||||
};
|
||||
} else {
|
||||
newCmd = {
|
||||
cmd: 'L',
|
||||
pt: Path.inLine(newpt, indx, list)
|
||||
};
|
||||
}
|
||||
list.splice(indx, 0, newCmd);
|
||||
}
|
||||
return Path.getDattribute(list);
|
||||
};
|
||||
|
||||
Path.inLine = function (C, indx, list) {
|
||||
var A = list[indx - 1].pt;
|
||||
var B = list[indx].pt;
|
||||
var norm = Vector.norm(Vector.diff(B, A));
|
||||
var K = Vector.dot(norm, Vector.diff(C, A));
|
||||
var pt = Vector.sum(A, Vector.scale(norm, K));
|
||||
return pt;
|
||||
};
|
||||
|
||||
Path.deleteDot = function (dot, shape) {
|
||||
var list1 = Path.getPointsForFirst(shape);
|
||||
var list = Path.getPointsAndCmds(shape);
|
||||
var mustdelteboth = (gn('pathdots').childNodes[gn('pathdots').childElementCount - 1]).getAttribute('cmd') == 'x';
|
||||
if ((list.length != list1.length) && (list1.length < 5)) {
|
||||
return;
|
||||
} else if (list.length < (mustdelteboth ? 6 : 3)) {
|
||||
return;
|
||||
} // polygons have M,L,Z to represent first and last point
|
||||
var pt = Path.getDotPoint(dot);
|
||||
var indx = Path.getHitPointIndex(list, pt);
|
||||
if (indx > 0) {
|
||||
list.splice(indx, 1);
|
||||
}
|
||||
if (indx == 0) {
|
||||
var pt1 = list[0].pt;
|
||||
var pt2 = list[list.length - 1].pt;
|
||||
if (Vector.len(Vector.diff(pt1, pt2)) == 0) {
|
||||
list.splice(indx, 1);
|
||||
if (mustdelteboth) {
|
||||
list.splice(list.length - 1, 1);
|
||||
list[0].cmd = 'M';
|
||||
var lastpt = {
|
||||
x: list[0].pt.x,
|
||||
y: list[0].pt.y
|
||||
};
|
||||
list[list.length - 1].pt = lastpt;
|
||||
var np = {
|
||||
cmd: 'z',
|
||||
pt: lastpt
|
||||
};
|
||||
list.push(np);
|
||||
}
|
||||
list[list.length - 1].pt = list[0].pt;
|
||||
} else {
|
||||
list.splice(indx, 1);
|
||||
if (list.length == 2) {
|
||||
list[0].cmd = 'M';
|
||||
list[list.length - 1].cmd = 'L';
|
||||
}
|
||||
}
|
||||
}
|
||||
var d = Path.getDattribute(list);
|
||||
var img = SVGImage.getImage(shape);
|
||||
if (d == null) {
|
||||
Path.hideDots(shape);
|
||||
shape.parentNode.removeChild(shape);
|
||||
if (img) {
|
||||
SVGImage.removeClip(img);
|
||||
}
|
||||
} else {
|
||||
shape.setAttribute('d', d);
|
||||
Path.showDots(shape);
|
||||
if (img) {
|
||||
SVGImage.rotatePointsOf(shape);
|
||||
}
|
||||
}
|
||||
PaintUndo.record();
|
||||
};
|
||||
|
||||
////////////////////////////////////////
|
||||
// Enter modes
|
||||
///////////////////////////////////////
|
||||
|
||||
Path.enterEditMode = function (mt) {
|
||||
Path.selector = SVGImage.getPathBorder(mt);
|
||||
Path.showDots(Path.selector);
|
||||
};
|
||||
|
||||
Path.quitEditMode = function () {
|
||||
Path.hideDots(Path.selector);
|
||||
Path.selector = undefined;
|
||||
};
|
||||
|
||||
Path.hitDot = function (evt) {
|
||||
if (!Path.selector) {
|
||||
return false;
|
||||
}
|
||||
var pt = PaintAction.getScreenPt(evt);
|
||||
var closestdot = Path.getClosestDotTo(pt,
|
||||
Math.floor((isTablet ? Path.idotsize + 4 : Path.dotsize) / Paint.currentZoom) * 2);
|
||||
if (closestdot) {
|
||||
PaintAction.target = closestdot;
|
||||
}
|
||||
return closestdot != null;
|
||||
};
|
||||
|
||||
Path.getClosestDotTo = function (pt, range) {
|
||||
var list = Path.getDotsCoodinates(Path.selector);
|
||||
var min = 99999;
|
||||
var dot = null;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var pt2 = list[i].pt;
|
||||
var dist = Vector.len(Vector.diff(pt2, pt));
|
||||
if (dist < min) {
|
||||
min = dist;
|
||||
dot = i + 1;
|
||||
}
|
||||
}
|
||||
if (min <= range) {
|
||||
return gn('grab ' + dot);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Path.hitLine = function (shape, pt) {
|
||||
return Path.getPointIndex(shape, pt) > -1;
|
||||
};
|
||||
|
||||
Path.getPointIndex = function (shape, pt) {
|
||||
var rot = Transform.extract(shape, 4);
|
||||
var newpt = Transform.point(pt.x, pt.y, rot.matrix.inverse());
|
||||
setCanvasSize(ScratchJr.workingCanvas, Paint.root.getAttribute('width'), Paint.root.getAttribute('height'));
|
||||
var ctx = ScratchJr.workingCanvas.getContext('2d');
|
||||
ctx.clearRect(0, 0, ScratchJr.workingCanvas.width, ScratchJr.workingCanvas.height);
|
||||
ctx.fillStyle = 'rgba(0,0,0,0)';
|
||||
ctx.lineWidth = Ghost.linemask;
|
||||
ctx.strokeStyle = '#ff00FF';
|
||||
return Path.getHitIndex(ctx, SVG2Canvas.getSVGcommands(shape), Vector.floor(newpt));
|
||||
};
|
||||
|
||||
Path.getClosestPath = function (pt, current, layer, mindist) {
|
||||
var min = 999999;
|
||||
var kid;
|
||||
for (var i = 0; i < layer.childElementCount; i++) {
|
||||
var elem = layer.childNodes[i];
|
||||
if (elem.id == current.id) {
|
||||
continue;
|
||||
}
|
||||
if (SVG2Canvas.isCloseDPath(elem)) {
|
||||
continue;
|
||||
}
|
||||
var pt2 = Path.getStartPoint(elem);
|
||||
var dist = Events.distance(pt2.x - pt.x, pt2.y - pt.y);
|
||||
if (dist < min) {
|
||||
min = dist;
|
||||
kid = elem;
|
||||
}
|
||||
}
|
||||
return (min <= mindist) ? kid : null;
|
||||
};
|
||||
|
||||
///////////////////////////////
|
||||
// Join Path algorithm
|
||||
///////////////////////////////
|
||||
|
||||
Path.getStartPoint = function (elem) {
|
||||
var d = elem.getAttribute('d');
|
||||
var list = Path.getAnchorpoints(d);
|
||||
return list[0];
|
||||
};
|
||||
|
||||
Path.getLastPoint = function (elem) {
|
||||
var d = elem.getAttribute('d');
|
||||
var list = Path.getAnchorpoints(d);
|
||||
return list[list.length - 1];
|
||||
};
|
||||
|
||||
Path.join = function (cs, mt, pt) {
|
||||
Transform.applyToCmds(mt, Transform.combineAll(mt));
|
||||
Transform.applyToCmds(cs, Transform.combineAll(cs));
|
||||
var cslist = Path.getCommands(cs.getAttribute('d'));
|
||||
var diffstart = Vector.len(Vector.diff(pt, cslist[0].pt));
|
||||
var diffend = Vector.len(Vector.diff(pt, cslist[cslist.length - 1].pt));
|
||||
var isEnd = diffstart > diffend;
|
||||
var mtlist = Path.getCommands(mt.getAttribute('d'));
|
||||
var res;
|
||||
if (isEnd) {
|
||||
if (diffend < diffstart) {
|
||||
cslist[0].cmd = 'C';
|
||||
res = mtlist.concat(cslist.reverse());
|
||||
} else {
|
||||
mtlist.shift();
|
||||
res = cslist.concat(mtlist);
|
||||
}
|
||||
} else {
|
||||
if (diffstart < diffend) {
|
||||
mtlist[0].cmd = 'L';
|
||||
cslist[0].cmd = 'C';
|
||||
res = (cslist.reverse()).concat(mtlist);
|
||||
} else {
|
||||
cslist[0].cmd = 'L';
|
||||
res = mtlist.concat(cslist);
|
||||
}
|
||||
}
|
||||
var d = Path.getDattribute(res);
|
||||
if (Vector.len(Vector.diff(res[0].pt, res[res.length - 1].pt)) < 10) {
|
||||
var char = d.charAt(d.length - 1);
|
||||
if (char != 'z') {
|
||||
d += 'z';
|
||||
}
|
||||
}
|
||||
cs.setAttributeNS(null, 'd', d);
|
||||
var attr = Path.getStylingFrom(mt);
|
||||
for (var val in attr) {
|
||||
cs.setAttribute(val, attr[val]);
|
||||
}
|
||||
if (mt.parentNode) {
|
||||
mt.parentNode.removeChild(mt);
|
||||
}
|
||||
return cs;
|
||||
};
|
|
@ -1,454 +0,0 @@
|
|||
var Path = function () {};
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Path management
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
Path.process = function (shape) {
|
||||
var plist = Path.getPolyPoints(shape);
|
||||
var firstpoint = plist[0];
|
||||
plist = Path.addPoints(plist); // make sure points are evenly spaced
|
||||
plist = Path.smoothPoints(plist);
|
||||
plist.unshift(firstpoint);
|
||||
plist = Path.addPoints(plist); // make sure points are evenly spaced
|
||||
plist = Path.deletePoints(plist);
|
||||
var bezier = Path.drawBezier(plist);
|
||||
shape.parentNode.removeChild(shape);
|
||||
return bezier;
|
||||
};
|
||||
|
||||
Path.getPolyPoints = function (shape) {
|
||||
var points = shape.points;
|
||||
var pp = [];
|
||||
for (var i = 0; i < points.numberOfItems; i++) {
|
||||
pp.push(points.getItem(i));
|
||||
}
|
||||
return pp;
|
||||
};
|
||||
|
||||
Path.smoothPoints = function (points) {
|
||||
var n = points.length;
|
||||
var plist = [];
|
||||
var interval = 3;
|
||||
var i;
|
||||
for (i = 0; i < (n - 1); i++) {
|
||||
var ax = 0;
|
||||
var ay = 0;
|
||||
for (var j = -interval; j <= interval; j++) {
|
||||
var nj = Math.max(0, i + j);
|
||||
nj = Math.min(nj, n - 1);
|
||||
ax += points[nj].x;
|
||||
ay += points[nj].y;
|
||||
}
|
||||
ax /= ((interval * 2) + 1);
|
||||
ay /= ((interval * 2) + 1);
|
||||
plist.push({
|
||||
x: ax,
|
||||
y: ay
|
||||
});
|
||||
}
|
||||
plist.push(points[n - 1]);
|
||||
return plist;
|
||||
};
|
||||
|
||||
Path.addPoints = function (points) {
|
||||
var it = 0;
|
||||
var b = true;
|
||||
while (b) {
|
||||
var result = Path.fillWithPoints(points);
|
||||
b = result[0];
|
||||
it++;
|
||||
if (it > 10) {
|
||||
return result[1];
|
||||
}
|
||||
}
|
||||
return result[1];
|
||||
};
|
||||
|
||||
Path.fillWithPoints = function (points) {
|
||||
var n = points.length;
|
||||
var i = 1;
|
||||
var res = false;
|
||||
var plist = [points[0]];
|
||||
while (i < n - 1) {
|
||||
var here = points[i];
|
||||
var after = points[i + 1];
|
||||
var l2 = Vector.len(Vector.diff(after, here));
|
||||
plist.push(points[i]);
|
||||
if (l2 > 5) {
|
||||
var mp = Vector.mid(here, after);
|
||||
plist.push({
|
||||
x: mp.x,
|
||||
y: mp.y
|
||||
});
|
||||
res = true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
plist.push(points[n - 1]);
|
||||
return [res, plist];
|
||||
};
|
||||
|
||||
Path.deletePoints = function (points) {
|
||||
var n = points.length;
|
||||
var i = 1;
|
||||
var j = 0;
|
||||
var plist = [];
|
||||
plist.push(points[0]);
|
||||
var dist = isTablet ? 40 : 30;
|
||||
var before, here, after;
|
||||
while (i < n - 1) {
|
||||
before = points[j];
|
||||
here = points[i];
|
||||
after = points[i + 1];
|
||||
var l1 = Vector.diff(before, here);
|
||||
var l2 = Vector.diff(after, here);
|
||||
var div = Vector.len(l1) * Vector.len(l2);
|
||||
if (div == 0) {
|
||||
div = 0.01;
|
||||
}
|
||||
var factor = Vector.dot(l1, l2) / div;
|
||||
if ((factor > -0.9) || (Vector.len(l2) > dist) || (Vector.len(l1) > dist)) {
|
||||
plist.push(points[i]);
|
||||
j = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
before = points[n - 2];
|
||||
here = points[n - 1];
|
||||
if ((plist.length > 2) && (Vector.len(Vector.diff(before, here)) < 3)) {
|
||||
plist.pop();
|
||||
}
|
||||
plist.push(points[n - 1]);
|
||||
return plist;
|
||||
};
|
||||
|
||||
Path.drawBezier = function (pointslist) {
|
||||
var first = pointslist[0];
|
||||
var shape = SVGTools.addPath(gn('layer1'), first.x, first.y);
|
||||
if (pointslist.length < 2) {
|
||||
return shape;
|
||||
}
|
||||
var d = Path.getBezier(pointslist);
|
||||
// var farilyclose = Vector.len(Vector.diff(lastpoint,first)) < 20;
|
||||
//s if (farilyclose) d+="z";
|
||||
shape.setAttributeNS(null, 'd', d);
|
||||
return shape;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// Make a Bezier
|
||||
////////////////////////////////////////////
|
||||
|
||||
Path.getBezier = function (plist) {
|
||||
SVG2Canvas.lastcxy = plist[0];
|
||||
var lastpoint = plist[plist.length - 1];
|
||||
var d = 'M' + SVG2Canvas.lastcxy.x + ',' + SVG2Canvas.lastcxy.y;
|
||||
var str = '';
|
||||
if (plist.length < 3) {
|
||||
str = Path.lineSeg(plist[1]);
|
||||
} else {
|
||||
var dist = Vector.len(Vector.diff(plist[0], lastpoint));
|
||||
// calculate the curves
|
||||
var startpt = Path.curveSeg(plist[0], plist[1], plist[2]);
|
||||
for (var i = 2; i < plist.length - 1; i++) {
|
||||
str += Path.curveSeg(plist[i - 1], plist[i], plist[i + 1]);
|
||||
}
|
||||
// calculate the last point whether it closes or not
|
||||
if (dist == 0) {
|
||||
str += Path.curveSeg(plist[plist.length - 2], lastpoint, plist[1]);
|
||||
// recalculate first point same command but the SVG2Canvas.lastcxy have changed
|
||||
startpt = Path.curveSeg(plist[0], plist[1], plist[2]);
|
||||
} else {
|
||||
str += Path.curveSeg(plist[plist.length - 2], lastpoint, lastpoint);
|
||||
}
|
||||
// (dist < 10) ? Path.curveSeg(plist[plist.length-2], lastpoint, plist[0]):
|
||||
d += startpt;
|
||||
}
|
||||
d += str;
|
||||
return d;
|
||||
};
|
||||
|
||||
Path.getControlPoint = function (before, here, after) {
|
||||
// needs more work on the fudge factor
|
||||
var l1 = Vector.len(Vector.diff(before, here));
|
||||
var l2 = Vector.len(Vector.diff(here, after));
|
||||
var l3 = Vector.len(Vector.diff(before, after));
|
||||
var l;
|
||||
if ((l1 + l2) == 0) {
|
||||
l = 0;
|
||||
} else {
|
||||
l = l3 / (l1 + l2);
|
||||
}
|
||||
var min = Math.min(l1, l2);
|
||||
//if ((l1 + l2) > 3 * l3) l = 0;
|
||||
var beforev = Vector.diff(before, here);
|
||||
var afterv = Vector.diff(after, here);
|
||||
var bisect = Vector.sum(Vector.norm(beforev), Vector.norm(afterv));
|
||||
var perp = Vector.perp(bisect);
|
||||
if (Vector.dot(perp, afterv) < 0) {
|
||||
perp = Vector.neg(perp);
|
||||
}
|
||||
if ((bisect.x == 0) || (bisect.y == 0)) {
|
||||
var kappa = (Math.sqrt(2) - 1) / 3 * 4;
|
||||
perp = Vector.norm(perp);
|
||||
var lx = Vector.dot(Vector.diff(here, before), perp);
|
||||
return Vector.diff(here, Vector.scale(perp, lx * kappa));
|
||||
}
|
||||
return Vector.diff(here, Vector.scale(perp, l * l * min * 0.666));
|
||||
};
|
||||
|
||||
Path.curveSeg = function (before, here, after) {
|
||||
// var endpoint = Vector.diff(here, before);
|
||||
var c2 = Path.getControlPoint(before, here, after);
|
||||
var c1 = Vector.sum(before, Vector.diff(before, SVG2Canvas.lastcxy));
|
||||
SVG2Canvas.lastcxy = c2;
|
||||
var pt = 'C' + c1.x + ',' + c1.y + ',' + c2.x + ',' + c2.y + ',' + here.x + ',' + here.y;
|
||||
return pt;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Making a Rect
|
||||
////////////////////////////////////////////
|
||||
|
||||
Path.makeRectangle = function (p, pointslist) {
|
||||
var first = pointslist[0];
|
||||
var shape = SVGTools.addPath(p, first.x, first.y);
|
||||
var d = Path.getRectangularD(pointslist);
|
||||
shape.setAttributeNS(null, 'd', d);
|
||||
shape.setAttribute('fill', 'none');
|
||||
return shape;
|
||||
};
|
||||
|
||||
Path.getRectangularD = function (plist) {
|
||||
var first = plist[0];
|
||||
var d = 'M' + first.x + ',' + first.y;
|
||||
for (var i = 1; i < plist.length; i++) {
|
||||
d += Path.lineSeg(plist[i]);
|
||||
}
|
||||
d += Path.lineSeg(plist[0]);
|
||||
d += 'z';
|
||||
return d;
|
||||
};
|
||||
|
||||
Path.lineSeg = function (pt) {
|
||||
SVG2Canvas.lastcxy = pt;
|
||||
return 'L' + pt.x + ',' + pt.y;
|
||||
};
|
||||
|
||||
Path.moveToCmd = function (pt) {
|
||||
SVG2Canvas.lastcxy = pt;
|
||||
return 'M' + pt.x + ',' + pt.y;
|
||||
};
|
||||
|
||||
/////////////////////////
|
||||
// Polygon / Polyline
|
||||
/////////////////////////
|
||||
|
||||
Path.convertPoints = function (shape) {
|
||||
var plist = Path.getPolyPoints(shape);
|
||||
var d = 'M' + plist[0].x + ',' + plist[0].y;
|
||||
for (var i = 1; i < plist.length; i++) {
|
||||
d += Path.lineSeg(plist[i]);
|
||||
}
|
||||
d += 'z';
|
||||
var attr = Path.getStylingFrom(shape);
|
||||
attr.d = d;
|
||||
attr.id = getIdFor('path');
|
||||
attr['stroke-miterlimit'] = shape.getAttribute('stroke-miterlimit');
|
||||
var path = SVGTools.addChild(gn('layer1'), 'path', attr);
|
||||
shape.parentNode.removeChild(shape);
|
||||
return path;
|
||||
};
|
||||
|
||||
Path.getStylingFrom = function (elem) {
|
||||
var c = elem.getAttribute('fill');
|
||||
var s = elem.getAttribute('stroke');
|
||||
var sw = elem.getAttribute('stroke-width');
|
||||
var attr = {
|
||||
'opacity': 1,
|
||||
'fill': c,
|
||||
'stroke': s,
|
||||
'stroke-width': sw
|
||||
};
|
||||
return attr;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Ellipse convertion to Path
|
||||
////////////////////////////////////////////
|
||||
|
||||
Path.makeEllipse = function (shape) {
|
||||
var rx = Number(shape.getAttribute('rx'));
|
||||
var ry = Number(shape.getAttribute('ry'));
|
||||
var cx = Number(shape.getAttribute('cx'));
|
||||
var cy = Number(shape.getAttribute('cy'));
|
||||
var kappa = (Math.sqrt(2) - 1) / 3 * 4;
|
||||
var d = [['M', cx - rx, cy],
|
||||
['C', cx - rx, cy - ry * kappa, cx - rx * kappa, cy - ry, cx, cy - ry],
|
||||
['C', cx + rx * kappa, cy - ry, cx + rx, cy - ry * kappa, cx + rx, cy],
|
||||
['C', cx + rx, cy + ry * kappa, cx + rx * kappa, cy + ry, cx, cy + ry],
|
||||
['C', cx - rx * kappa, cy + ry, cx - rx, cy + ry * kappa, cx - rx, cy]];
|
||||
var attr = Path.getStylingFrom(shape);
|
||||
attr.d = SVG2Canvas.arrayToString(d);
|
||||
attr.id = getIdFor('path');
|
||||
attr['stroke-miterlimit'] = shape.getAttribute('stroke-miterlimit');
|
||||
var elem = SVGTools.addChild(gn('layer1'), 'path', attr);
|
||||
return elem;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// From D to point list with CMD type
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
Path.getAnchorpoints = function (d) {
|
||||
var list = SVG2Canvas.getCommandList(d);
|
||||
var res = [];
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var cmd = SVG2Canvas.getAbsoluteCommand(list[i]);
|
||||
if (cmd[0] != 'z') {
|
||||
res.push(SVG2Canvas.endp);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
Path.getPointsAndCmds = function (shape) {
|
||||
return Path.getCommands(shape.getAttribute('d'));
|
||||
};
|
||||
|
||||
Path.getCommands = function (path) {
|
||||
var list = SVG2Canvas.getCommandList(path);
|
||||
var res = [];
|
||||
var first;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var cmd = SVG2Canvas.getAbsoluteCommand(list[i]);
|
||||
if (cmd[0].toLowerCase() == 'm') {
|
||||
first = SVG2Canvas.endp;
|
||||
}
|
||||
if (cmd[0].toLowerCase() != 'z') {
|
||||
res.push({
|
||||
cmd: cmd[0],
|
||||
pt: SVG2Canvas.endp
|
||||
});
|
||||
} else {
|
||||
res.push({
|
||||
cmd: cmd[0],
|
||||
pt: first
|
||||
});
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
Path.getPointsForFirst = function (elem) {
|
||||
var paths = elem.getAttribute('d').match(/[M][^M]*/g);
|
||||
var d;
|
||||
if (!paths) {
|
||||
d = elem.getAttribute('d');
|
||||
} else {
|
||||
d = paths[0];
|
||||
}
|
||||
return Path.getCommands(d);
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
// From CMD points to Path D attribute
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
Path.getDattribute = function (ptlist) {
|
||||
// plist data structure is
|
||||
// CMD - pt;
|
||||
SVG2Canvas.lastcxy = ptlist[0].pt;
|
||||
var d = 'M' + SVG2Canvas.lastcxy.x + ',' + SVG2Canvas.lastcxy.y;
|
||||
//paths always start with "M"
|
||||
// first CMD after M and last CMDS are calculated at the end of the loop
|
||||
var str = '';
|
||||
// two points line;
|
||||
if (ptlist.length < 3) {
|
||||
return (ptlist[1].cmd.toLowerCase() == 'z') ? null : d + Path.lineSeg(ptlist[1].pt);
|
||||
}
|
||||
Paint.skipNext = false;
|
||||
// any other shape;
|
||||
var startpt = Path.thisCommand(ptlist, 1);
|
||||
var first = ptlist[1];
|
||||
var last = ptlist[ptlist.length - 1];
|
||||
var dist = Vector.len(Vector.diff(ptlist[0].pt, last.pt));
|
||||
var shapetype = ((first.cmd == 'C') && (last.cmd == 'C') && (dist == 0)) ? 'ellipse' :
|
||||
((first.cmd == 'C') &&
|
||||
(ptlist[ptlist.length - 2].cmd == 'C') && (last.cmd.toLowerCase() == 'z')) ? 'closecurve' :
|
||||
((first.cmd == 'L') && (ptlist[ptlist.length - 2].cmd == 'L') && (dist == 0)) ? 'polygon' :
|
||||
((first.cmd == 'C') && (last.cmd == 'C')) ? 'curve' : 'line';
|
||||
for (var i = 2; i < ptlist.length - 1; i++) {
|
||||
str += Path.thisCommand(ptlist, i);
|
||||
}
|
||||
switch (shapetype) {
|
||||
case 'ellipse':
|
||||
str += Path.curveSeg(ptlist[ptlist.length - 2].pt, last.pt, first.pt);
|
||||
// recalculate first point same command because the SVG2Canvas.lastcxy have changed
|
||||
startpt = Path.curveSeg(ptlist[0].pt, first.pt, ptlist[2].pt);
|
||||
break;
|
||||
case 'closecurve':
|
||||
// str+= Path.curveSeg(ptlist[ptlist.length-2].pt, last.pt, first.pt);
|
||||
str += 'z';
|
||||
break;
|
||||
case 'polygon':
|
||||
str += 'z';
|
||||
break;
|
||||
|
||||
case 'curve':
|
||||
str += Path.curveSeg(ptlist[ptlist.length - 2].pt, last.pt, last.pt);
|
||||
break;
|
||||
case 'line':
|
||||
str += (last.cmd.toLowerCase() == 'z') ? 'z' : Path.lineSeg(last.pt);
|
||||
break;
|
||||
default:
|
||||
str += Path.lineSeg(last.pt);
|
||||
break;
|
||||
}
|
||||
return d + startpt + str;
|
||||
};
|
||||
|
||||
Path.thisCommand = function (ptlist, i) {
|
||||
var str;
|
||||
var kind = ptlist[i].cmd;
|
||||
var pt = ptlist[i].pt;
|
||||
if (Paint.skipNext) {
|
||||
Paint.skipNext = false;
|
||||
return '';
|
||||
}
|
||||
if (Path.skipCmd(ptlist, i)) {
|
||||
return '';
|
||||
}
|
||||
switch (kind.toUpperCase()) {
|
||||
case 'C':
|
||||
case 'S':
|
||||
var ptbefore = ptlist[i - 1].pt;
|
||||
var ptafter = ptlist[i + 1].pt;
|
||||
str = Path.curveSeg(ptbefore, pt, ptafter);
|
||||
break;
|
||||
case 'Z':
|
||||
str = 'Z';
|
||||
break;
|
||||
case 'M':
|
||||
str = Path.moveToCmd(pt);
|
||||
break;
|
||||
default:
|
||||
str = Path.lineSeg(pt);
|
||||
break;
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
Path.skipCmd = function (ptlist, i) {
|
||||
var cmd1 = ptlist[i].cmd.toLowerCase();
|
||||
var cmd2 = ptlist[i + 1].cmd.toLowerCase();
|
||||
if ((cmd1 == 'm') && (cmd2 == 'm')) {
|
||||
return true;
|
||||
}
|
||||
if ((cmd1 == 'm') && (cmd2 == 'z')) {
|
||||
Paint.skipNext = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
|
@ -1,478 +0,0 @@
|
|||
/////////////////////////////////////////////
|
||||
// Path direction
|
||||
////////////////////////////////////////////
|
||||
|
||||
Path.isClockWise = function (d) {
|
||||
return Path.getTurnType(Path.getAnchorpoints(d)) == 'clockwise';
|
||||
};
|
||||
|
||||
Path.getTurnType = function (list) {
|
||||
if (list.length < 3) {
|
||||
return 'colinear';
|
||||
}
|
||||
var limitpoints = Path.getMinMaxPoints(list);
|
||||
var a = Path.findGreaterThanIndex(limitpoints, -1);
|
||||
if (!a) {
|
||||
return 'colinear';
|
||||
}
|
||||
var b = Path.findGreaterThanIndex(limitpoints, a.index);
|
||||
if (!b) {
|
||||
return 'colinear';
|
||||
}
|
||||
var c = Path.findGreaterThanIndex(limitpoints, b.index);
|
||||
if (!c) {
|
||||
return 'colinear';
|
||||
}
|
||||
return Path.triangleAreaDir(a, b, c);
|
||||
};
|
||||
|
||||
Path.findGreaterThanIndex = function (list, min) {
|
||||
var lastmin = 99999999;
|
||||
var pos;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if ((list[i].index > min) && (list[i].index < lastmin)) {
|
||||
lastmin = list[i].index;
|
||||
pos = list[i];
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
|
||||
Path.triangleAreaDir = function (a, b, c) {
|
||||
var area = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
|
||||
if (area > 0) {
|
||||
return 'clockwise';
|
||||
}
|
||||
if (area < 0) {
|
||||
return 'counterclockwise';
|
||||
}
|
||||
return 'colinear';
|
||||
};
|
||||
|
||||
Path.getMinMaxPoints = function (list) {
|
||||
var res = [0, 0, 0, 0];
|
||||
if (list.length < 1) {
|
||||
return res;
|
||||
}
|
||||
var minx = 9999999;
|
||||
var miny = 9999999;
|
||||
var maxx = -9999999;
|
||||
var maxy = -9999999;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (list[i].x < minx) {
|
||||
minx = list[i].x;
|
||||
res[0] = {
|
||||
type: 'minx',
|
||||
x: list[i].x,
|
||||
y: list[i].y,
|
||||
index: i
|
||||
};
|
||||
}
|
||||
if (list[i].x > maxx) {
|
||||
maxx = list[i].x;
|
||||
res[2] = {
|
||||
type: 'maxx',
|
||||
x: list[i].x,
|
||||
y: list[i].y,
|
||||
index: i
|
||||
};
|
||||
}
|
||||
|
||||
if (list[i].y < miny) {
|
||||
miny = list[i].y;
|
||||
res[1] = {
|
||||
type: 'miny',
|
||||
x: list[i].x,
|
||||
y: list[i].y,
|
||||
index: i
|
||||
};
|
||||
}
|
||||
if (list[i].y > maxy) {
|
||||
maxy = list[i].y;
|
||||
res[3] = {
|
||||
type: 'maxy',
|
||||
x: list[i].x,
|
||||
y: list[i].y,
|
||||
index: i
|
||||
};
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////
|
||||
// Flip Element
|
||||
////////////////////////////////////////////
|
||||
|
||||
Path.flip = function (elem) {
|
||||
var paths = elem.getAttribute('d').match(/[M][^M]*/g);
|
||||
var d = '';
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
d += Path.reverse(paths[i]);
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
Path.reverse = function (d) {
|
||||
var list = Path.getCommands(d);
|
||||
if (list.length < 2) {
|
||||
return '';
|
||||
}
|
||||
var lastcmd = list[list.length - 1].cmd.toLowerCase();
|
||||
if (lastcmd == 'z') {
|
||||
list[0].cmd = 'z';
|
||||
} else {
|
||||
list[0].cmd = lastcmd.toUpperCase();
|
||||
}
|
||||
list[list.length - 1].cmd = 'M';
|
||||
list = list.reverse();
|
||||
return Path.getDattribute(list);
|
||||
};
|
||||
|
||||
Path.setData = function (mt) {
|
||||
if (mt.getAttribute('relatedto')) {
|
||||
Path.breakRelationship(mt, mt.getAttribute('relatedto'));
|
||||
} else {
|
||||
Path.makeCompoundPath(mt);
|
||||
}
|
||||
};
|
||||
|
||||
Path.breakRelationship = function (mt, family) {
|
||||
var elem = gn(family);
|
||||
if (!elem) {
|
||||
return;
|
||||
}
|
||||
var paths = elem.getAttribute('d').match(/[M][^M]*/g);
|
||||
var findPlace = Path.getMatchPathIndex(mt, paths);
|
||||
if (findPlace < 0) {
|
||||
return;
|
||||
}
|
||||
paths.splice(findPlace, 1);
|
||||
var d = '';
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
d += paths[i];
|
||||
}
|
||||
elem.setAttribute('d', d);
|
||||
mt.setAttribute('d', Path.flip(mt));
|
||||
mt.removeAttribute('relatedto');
|
||||
};
|
||||
|
||||
Path.getMatchPathIndex = function (mt, paths) {
|
||||
var mypoints = Path.getPointsAndCmds(mt);
|
||||
for (var i = 0; i < paths.length; i++) {
|
||||
var path = paths[i];
|
||||
var yourpoints = Path.getCommands(path);
|
||||
var count = Path.countMatchingPoints(mypoints, yourpoints);
|
||||
if (count >= mypoints.length) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
Path.countMatchingPoints = function (list, other) {
|
||||
var count = 0;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var v1 = list[i].pt;
|
||||
for (var j = 0; j < other.length; j++) {
|
||||
var v2 = other[j].pt;
|
||||
if (Vector.len(Vector.diff(v1, v2)) == 0) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
};
|
||||
|
||||
Path.makeCompoundPath = function (mt) {
|
||||
var list = Path.findIntersecting(mt);
|
||||
if ((list.length == 0) || Path.containsImage(list) || (Path.anyCrossing(list, mt))) {
|
||||
mt.setAttribute('fill', Paint.fillcolor);
|
||||
} else {
|
||||
var filled = false;
|
||||
list.sort(function (l1, l2) {
|
||||
var a = SVGTools.getArea(l1);
|
||||
var b = SVGTools.getArea(l2);
|
||||
return a > b ? -1 : (a < b ? 1 : 0);
|
||||
});
|
||||
var res = [];
|
||||
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (list[i].getAttribute('fill') != 'none') {
|
||||
filled = true;
|
||||
}
|
||||
if (list[i].nodeName == 'image') {
|
||||
filled = true;
|
||||
}
|
||||
if ((list[i].tagName == 'path') && !SVG2Canvas.isCloseDPath(list[i])) {
|
||||
filled = true;
|
||||
}
|
||||
if (i == 0) {
|
||||
res.push(list[i]);
|
||||
}
|
||||
if (i > 0) {
|
||||
if (!Layer.insideMe(list[i], list[i - 1])) {
|
||||
res.push(list[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filled) {
|
||||
mt.setAttribute('fill', Paint.fillcolor);
|
||||
} else {
|
||||
Path.processCompoundPath(mt, res);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Path.findIntersecting = function (mt) {
|
||||
var rpos = Paint.root.createSVGRect();
|
||||
var box = SVGTools.getBox(mt);
|
||||
rpos.x = box.x;
|
||||
rpos.y = box.y;
|
||||
rpos.width = box.width;
|
||||
rpos.height = box.height;
|
||||
var list = Paint.root.getIntersectionList(rpos, null);
|
||||
var res = [];
|
||||
if (list != null) {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (list[i].parentNode.id == 'ghostlayer') {
|
||||
continue;
|
||||
}
|
||||
if (list[i].id == mt.id) {
|
||||
continue;
|
||||
}
|
||||
if (Layer.includesBox(mt, list[i])) {
|
||||
res.push(list[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
Path.containsImage = function (objlist) {
|
||||
for (var i = 0; i < objlist.length; i++) {
|
||||
if (objlist[i].nodeName == 'image') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Path.anyCrossing = function (objlist, mt) {
|
||||
for (var i = 0; i < objlist.length; i++) {
|
||||
if (mt == objlist[i]) {
|
||||
continue;
|
||||
}
|
||||
if (objlist[i].nodeName == 'g') {
|
||||
continue;
|
||||
}
|
||||
var contatctPoints = Path.getPathCrossing(objlist[i], mt);
|
||||
if (contatctPoints.length > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Path.getPathCrossing = function (obj, mt) {
|
||||
var list = Path.getAllPoints(obj.getAttribute('d'));
|
||||
var other = Path.getAllPoints(mt.getAttribute('d'));
|
||||
var res = [];
|
||||
for (var i = 1; i < list.length; i++) {
|
||||
var v1 = list[i - 1];
|
||||
var v2 = list[i];
|
||||
for (var j = 1; j < other.length; j++) {
|
||||
var v3 = other[j - 1];
|
||||
var v4 = other[j];
|
||||
var pt = Vector.lineIntersect(v1, v2, v3, v4);
|
||||
if (pt) {
|
||||
res.push([i, j, pt]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
Path.getAllPoints = function (d) {
|
||||
var list = SVG2Canvas.getCommandList(d);
|
||||
if (list.length == 0) {
|
||||
return [];
|
||||
}
|
||||
var res = [];
|
||||
var lastpt = {
|
||||
x: list[0][1],
|
||||
y: list[0][2]
|
||||
};
|
||||
res.push(lastpt);
|
||||
for (var i = 1; i < list.length; i++) {
|
||||
var pts = list[i];
|
||||
var cmd = pts.shift();
|
||||
switch (cmd.toLowerCase()) {
|
||||
case 'l':
|
||||
lastpt = {
|
||||
x: pts[0],
|
||||
y: pts[1]
|
||||
};
|
||||
res.push(lastpt);
|
||||
break;
|
||||
case 'c':
|
||||
pts.unshift(lastpt.y); // add last point y;
|
||||
pts.unshift(lastpt.x); // add last point y;
|
||||
var l = pts.length;
|
||||
lastpt = {
|
||||
x: pts[l - 2],
|
||||
y: pts[l - 1]
|
||||
};
|
||||
var seg = Path.getBezierPoints(pts);
|
||||
res = res.concat(seg);
|
||||
break;
|
||||
case 'z':
|
||||
lastpt = {
|
||||
x: res[0].x,
|
||||
y: res[0].y
|
||||
};
|
||||
res.push(lastpt);
|
||||
break;
|
||||
}
|
||||
}
|
||||
l = Path.cleanBezier(res, 5);
|
||||
return (l.length < 5) ? res : l;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// from C to bezier points
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
Path.getBezierPoints = function (points) {
|
||||
if (points.length < 8) {
|
||||
return [];
|
||||
}
|
||||
var p1x, p2x, p3x, p4x, p1y, p2y, p3y, p4y;
|
||||
p1x = points[0];
|
||||
p1y = points[1];
|
||||
p2x = points[2];
|
||||
p2y = points[3];
|
||||
p3x = points[4];
|
||||
p3y = points[5];
|
||||
p4x = points[6];
|
||||
p4y = points[7];
|
||||
|
||||
var x, y, t;
|
||||
|
||||
var xl = p1x - 1;
|
||||
var yl = p1y - 1;
|
||||
t = 0;
|
||||
var f = 1;
|
||||
|
||||
var k = 1.1;
|
||||
//Array to hold all points on the bezier curve
|
||||
var curvePoints = new Array();
|
||||
|
||||
var n = 0;
|
||||
while ((t <= 1) && (t >= 0)) { // t goes from 0 to 1
|
||||
n++;
|
||||
x = 0;
|
||||
y = 0;
|
||||
x = (1 - t) * (1 - t) * (1 - t) * p1x + 3 * (1 - t) * (1 - t) *
|
||||
t * p2x + 3 * (1 - t) * t * t * p3x + t * t * t * p4x;
|
||||
y = (1 - t) * (1 - t) * (1 - t) * p1y + 3 * (1 - t) * (1 - t) *
|
||||
t * p2y + 3 * (1 - t) * t * t * p3y + t * t * t * p4y;
|
||||
x = Math.round(x);
|
||||
y = Math.round(y);
|
||||
if (x != xl || y != yl) {
|
||||
if (t == 0) {
|
||||
xl = x;
|
||||
yl = y;
|
||||
}
|
||||
if (x - xl > 1 || y - yl > 1 || xl - x > 1 || yl - y > 1) {
|
||||
t -= f;
|
||||
f = f / k;
|
||||
} else {
|
||||
curvePoints[curvePoints.length] = {
|
||||
x: x,
|
||||
y: y
|
||||
};
|
||||
xl = x;
|
||||
yl = y;
|
||||
}
|
||||
} else {
|
||||
t -= f;
|
||||
f = f * k;
|
||||
}
|
||||
t += f;
|
||||
}
|
||||
return curvePoints;
|
||||
};
|
||||
|
||||
// for debugging
|
||||
Path.placePoint = function (p, pt, c) {
|
||||
var el = SVGTools.addEllipse(p, pt.x, pt.y);
|
||||
el.setAttributeNS(null, 'stroke-width', 0.5);
|
||||
|
||||
el.setAttributeNS(null, 'rx', 4);
|
||||
el.setAttributeNS(null, 'ry', 4);
|
||||
el.setAttributeNS(null, 'fill', c);
|
||||
};
|
||||
// Path.placePoint(gn("testlayer"), pt, c ? c : "#0093ff");
|
||||
|
||||
|
||||
Path.cleanBezier = function (points, dist) {
|
||||
var n = points.length;
|
||||
var i = 1;
|
||||
var j = 0;
|
||||
var plist = [];
|
||||
plist.push(points[0]);
|
||||
while (i < n - 1) {
|
||||
var before = points[j];
|
||||
var here = points[i];
|
||||
var after = points[i + 1];
|
||||
var l1 = Vector.diff(before, here);
|
||||
var l2 = Vector.diff(after, here);
|
||||
if ((Vector.len(l2) > dist) || (Vector.len(l1) > dist)) {
|
||||
plist.push(points[i]);
|
||||
j = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return plist;
|
||||
};
|
||||
|
||||
Path.processCompoundPath = function (mt, list) {
|
||||
var dir = Path.isClockWise(mt.getAttribute('d'));
|
||||
// take out all matrices out of original shape
|
||||
Transform.applyToCmds(mt, Transform.combineAll(mt));
|
||||
Transform.eliminateAll(mt);
|
||||
var d = mt.getAttribute('d');
|
||||
var yourdir;
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
if (list[i] == mt) {
|
||||
continue;
|
||||
}
|
||||
if (list[i].getAttribute('fill') != 'none') {
|
||||
list[i].parentNode.appendChild(list[i]);
|
||||
continue;
|
||||
}
|
||||
list[i].setAttribute('relatedto', mt.id);
|
||||
if (SVG2Canvas.isCompoundPath(list[i])) {
|
||||
Transform.applyToCmds(list[i], Transform.combineAll(list[i]));
|
||||
Transform.eliminateAll(list[i]);
|
||||
var paths = list[i].getAttribute('d').match(/[M][^M]*/g);
|
||||
yourdir = Path.isClockWise(paths[0]);
|
||||
if (dir == yourdir) {
|
||||
d += Path.reverse(paths[0]);
|
||||
} else {
|
||||
d += paths[0];
|
||||
}
|
||||
} else {
|
||||
yourdir = Path.isClockWise(list[i].getAttribute('d'));
|
||||
if (dir == yourdir) {
|
||||
list[i].setAttribute('d', Path.flip(list[i]));
|
||||
// take out matrices
|
||||
}
|
||||
Transform.applyToCmds(list[i], Transform.combineAll(list[i]));
|
||||
Transform.eliminateAll(list[i]);
|
||||
d += list[i].getAttribute('d');
|
||||
}
|
||||
}
|
||||
mt.setAttribute('d', d);
|
||||
};
|
Loading…
Reference in a new issue