|  |  | 
 |  |  |  | 
 |  |  | svgedit.path.init = function(editorContext) { | 
 |  |  |   editorContext_ = editorContext; | 
 |  |  |    | 
 |  |  |  | 
 |  |  |   pathFuncs = [0,'ClosePath']; | 
 |  |  |   var pathFuncsStrs = ['Moveto', 'Lineto', 'CurvetoCubic', 'CurvetoQuadratic', 'Arc', | 
 |  |  |     'LinetoHorizontal', 'LinetoVertical','CurvetoCubicSmooth','CurvetoQuadraticSmooth']; | 
 |  |  | 
 |  |  | svgedit.path.addCtrlGrip = function(id) { | 
 |  |  |   var pointGrip = svgedit.utilities.getElem("ctrlpointgrip_"+id); | 
 |  |  |   if(pointGrip) return pointGrip; | 
 |  |  |      | 
 |  |  |  | 
 |  |  |   pointGrip = document.createElementNS(svgns, "circle"); | 
 |  |  |   svgedit.utilities.assignAttributes(pointGrip, { | 
 |  |  |     'id': "ctrlpointgrip_" + id, | 
 |  |  | 
 |  |  |   var item = seg.item; | 
 |  |  |   var index = seg.index; | 
 |  |  |   if(!item || !("x1" in item) || !("x2" in item)) return null; | 
 |  |  |   var cpt = {};      | 
 |  |  |   var cpt = {}; | 
 |  |  |   var pointGripContainer = svgedit.path.getGripContainer(); | 
 |  |  |  | 
 |  |  |   // Note that this is intentionally not seg.prev.item | 
 |  |  | 
 |  |  |       'd': 'M0,0 0,0' | 
 |  |  |     }); | 
 |  |  |     pointGripContainer.appendChild(segLine); | 
 |  |  |   }  | 
 |  |  |   } | 
 |  |  |  | 
 |  |  |   if(update) { | 
 |  |  |     var prev = seg.prev; | 
 |  |  | 
 |  |  |  | 
 |  |  | // Function: smoothControlPoints | 
 |  |  | // Takes three points and creates a smoother line based on them | 
 |  |  | //  | 
 |  |  | // Parameters:  | 
 |  |  | // | 
 |  |  | // Parameters: | 
 |  |  | // ct1 - Object with x and y values (first control point) | 
 |  |  | // ct2 - Object with x and y values (second control point) | 
 |  |  | // pt - Object with x and y values (third point) | 
 |  |  | // | 
 |  |  | // Returns:  | 
 |  |  | // Returns: | 
 |  |  | // Array of two "smoothed" point objects | 
 |  |  | svgedit.path.smoothControlPoints = this.smoothControlPoints = function(ct1, ct2, pt) { | 
 |  |  |   // each point must not be the origin | 
 |  |  | 
 |  |  |     y1 = ct1.y - pt.y, | 
 |  |  |     x2 = ct2.x - pt.x, | 
 |  |  |     y2 = ct2.y - pt.y; | 
 |  |  |      | 
 |  |  |  | 
 |  |  |   if ( (x1 != 0 || y1 != 0) && (x2 != 0 || y2 != 0) ) { | 
 |  |  |     var anglea = Math.atan2(y1,x1), | 
 |  |  |       angleb = Math.atan2(y2,x2), | 
 |  |  |       r1 = Math.sqrt(x1*x1+y1*y1), | 
 |  |  |       r2 = Math.sqrt(x2*x2+y2*y2), | 
 |  |  |       nct1 = editorContext_.getSVGRoot().createSVGPoint(), | 
 |  |  |       nct2 = editorContext_.getSVGRoot().createSVGPoint();         | 
 |  |  |       nct2 = editorContext_.getSVGRoot().createSVGPoint(); | 
 |  |  |     if (anglea < 0) { anglea += 2*Math.PI; } | 
 |  |  |     if (angleb < 0) { angleb += 2*Math.PI; } | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     var angleBetween = Math.abs(anglea - angleb), | 
 |  |  |       angleDiff = Math.abs(Math.PI - angleBetween)/2; | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     var new_anglea, new_angleb; | 
 |  |  |     if (anglea - angleb > 0) { | 
 |  |  |       new_anglea = angleBetween < Math.PI ? (anglea + angleDiff) : (anglea - angleDiff); | 
 |  |  | 
 |  |  |       new_anglea = angleBetween < Math.PI ? (anglea - angleDiff) : (anglea + angleDiff); | 
 |  |  |       new_angleb = angleBetween < Math.PI ? (angleb + angleDiff) : (angleb - angleDiff); | 
 |  |  |     } | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     // rotate the points | 
 |  |  |     nct1.x = r1 * Math.cos(new_anglea) + pt.x; | 
 |  |  |     nct1.y = r1 * Math.sin(new_anglea) + pt.y; | 
 |  |  |     nct2.x = r2 * Math.cos(new_angleb) + pt.x; | 
 |  |  |     nct2.y = r2 * Math.sin(new_angleb) + pt.y; | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     return [nct1, nct2]; | 
 |  |  |   } | 
 |  |  |   return undefined; | 
 |  |  | 
 |  |  |   this.index = index; | 
 |  |  |   this.item = item; | 
 |  |  |   this.type = item.pathSegType; | 
 |  |  |    | 
 |  |  |  | 
 |  |  |   this.ctrlpts = []; | 
 |  |  |   this.ptgrip = null; | 
 |  |  |   this.segsel = null; | 
 |  |  | 
 |  |  |         this.type = this.item.pathSegType; | 
 |  |  |       } | 
 |  |  |       svgedit.path.getControlPoints(this); | 
 |  |  |     }  | 
 |  |  |     } | 
 |  |  |     // this.segsel.setAttribute("display", y?"inline":"none"); | 
 |  |  |   } | 
 |  |  | }; | 
 |  |  | 
 |  |  |   var item = this.item; | 
 |  |  |   // fix for path tool dom breakage, amending item does bad things now, so we take a copy and use that. Can probably improve to just take a shallow copy of object | 
 |  |  |   var cloneItem = $.extend({}, item); | 
 |  |  |   var cur_pts = (this.ctrlpts)  | 
 |  |  |     ? [cloneItem.x += dx,  cloneItem.y += dy,  | 
 |  |  |        cloneItem.x1,       cloneItem.y1,  | 
 |  |  |   var cur_pts = (this.ctrlpts) | 
 |  |  |     ? [cloneItem.x += dx,  cloneItem.y += dy, | 
 |  |  |        cloneItem.x1,       cloneItem.y1, | 
 |  |  |        cloneItem.x2 += dx, cloneItem.y2 += dy] | 
 |  |  |     : [cloneItem.x += dx, cloneItem.y += dy]; | 
 |  |  |    | 
 |  |  |  | 
 |  |  |   svgedit.path.replacePathSeg(this.type, this.index, cur_pts); | 
 |  |  |  | 
 |  |  |   if(this.next && this.next.ctrlpts) { | 
 |  |  |     var next = this.next.item; | 
 |  |  |     var next_pts = [next.x, next.y,  | 
 |  |  |     var next_pts = [next.x, next.y, | 
 |  |  |       next.x1 += dx, next.y1 += dy, next.x2, next.y2]; | 
 |  |  |     svgedit.path.replacePathSeg(this.next.type, this.next.index, next_pts); | 
 |  |  |   } | 
 |  |  | 
 |  |  |   cloneItem['x' + anum ] = pt.x + (pt.x - this.item['x' + num]); | 
 |  |  |   cloneItem['y' + anum ] = pt.y + (pt.y - this.item['y' + num]); | 
 |  |  |  | 
 |  |  |   var pts = [  | 
 |  |  |   var pts = [ | 
 |  |  |               cloneItem.x, cloneItem.y, | 
 |  |  |               cloneItem.x1, cloneItem.y1, | 
 |  |  |               cloneItem.x2, cloneItem.y2 | 
 |  |  | 
 |  |  |  | 
 |  |  |   var pts = [item.x,item.y, | 
 |  |  |     item.x1,item.y1, item.x2,item.y2]; | 
 |  |  |      | 
 |  |  |  | 
 |  |  |   svgedit.path.replacePathSeg(this.type, this.index, pts); | 
 |  |  |   this.update(true); | 
 |  |  | }; | 
 |  |  | 
 |  |  |   this.segs = []; | 
 |  |  |   this.selected_pts = []; | 
 |  |  |   this.first_seg = null; | 
 |  |  |    | 
 |  |  |  | 
 |  |  |   // Set up segs array | 
 |  |  |   for(var i=0; i < len; i++) { | 
 |  |  |     var item = segList.getItem(i); | 
 |  |  |     var segment = new svgedit.path.Segment(i, item); | 
 |  |  |     segment.path = this; | 
 |  |  |     this.segs.push(segment); | 
 |  |  |   }  | 
 |  |  |    | 
 |  |  |   } | 
 |  |  |  | 
 |  |  |   var segs = this.segs; | 
 |  |  |   var start_i = null; | 
 |  |  |  | 
 |  |  |   for(var i=0; i < len; i++) { | 
 |  |  |     var seg = segs[i];  | 
 |  |  |     var seg = segs[i]; | 
 |  |  |     var next_seg = (i+1) >= len ? null : segs[i+1]; | 
 |  |  |     var prev_seg = (i-1) < 0 ? null : segs[i-1]; | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     if(seg.type === 2) { | 
 |  |  |       if(prev_seg && prev_seg.type !== 1) { | 
 |  |  |         // New sub-path, last one is open, | 
 |  |  | 
 |  |  |       // This is the last real segment of a closed sub-path | 
 |  |  |       // Next is first seg after "M" | 
 |  |  |       seg.next = segs[start_i+1]; | 
 |  |  |        | 
 |  |  |  | 
 |  |  |       // First seg after "M"'s prev is this | 
 |  |  |       seg.next.prev = seg; | 
 |  |  |       seg.mate = segs[start_i]; | 
 |  |  | 
 |  |  |     } else if(seg.type !== 1){ | 
 |  |  |       // Regular segment, so add grip and its "next" | 
 |  |  |       seg.addGrip(); | 
 |  |  |        | 
 |  |  |  | 
 |  |  |       // Don't set its "next" if it's an "M" | 
 |  |  |       if(next_seg && next_seg.type !== 2) { | 
 |  |  |         seg.next = next_seg; | 
 |  |  | 
 |  |  | svgedit.path.Path.prototype.deleteSeg = function(index) { | 
 |  |  |   var seg = this.segs[index]; | 
 |  |  |   var list = this.elem.pathSegList; | 
 |  |  |    | 
 |  |  |  | 
 |  |  |   seg.show(false); | 
 |  |  |   var next = seg.next; | 
 |  |  |   if(seg.mate) { | 
 |  |  |     // Make the next point be the "M" point | 
 |  |  |     var pt = [next.item.x, next.item.y]; | 
 |  |  |     svgedit.path.replacePathSeg(2, next.index, pt); | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     // Reposition last node | 
 |  |  |     svgedit.path.replacePathSeg(4, seg.index, pt); | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     list.removeItem(seg.mate.index); | 
 |  |  |   } else if(!seg.prev) { | 
 |  |  |     // First node of open path, make next point the M | 
 |  |  | 
 |  |  |     var pt = [next.item.x, next.item.y]; | 
 |  |  |     svgedit.path.replacePathSeg(2, seg.next.index, pt); | 
 |  |  |     list.removeItem(index); | 
 |  |  |      | 
 |  |  |  | 
 |  |  |   } else { | 
 |  |  |     list.removeItem(index); | 
 |  |  |   } | 
 |  |  | 
 |  |  |       return false; | 
 |  |  |     } | 
 |  |  |   }); | 
 |  |  |    | 
 |  |  |  | 
 |  |  |   return closed; | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | 
 |  |  |   var pos = this.selected_pts.indexOf(index); | 
 |  |  |   if(pos == -1) { | 
 |  |  |     return; | 
 |  |  |   }  | 
 |  |  |   } | 
 |  |  |   this.segs[index].select(false); | 
 |  |  |   this.selected_pts.splice(pos, 1); | 
 |  |  | }; | 
 |  |  | 
 |  |  |   return this; | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // Move selected points  | 
 |  |  | // Move selected points | 
 |  |  | svgedit.path.Path.prototype.movePts = function(d_x, d_y) { | 
 |  |  |   var i = this.selected_pts.length; | 
 |  |  |   while(i--) { | 
 |  |  | 
 |  |  |   var text; | 
 |  |  |   while(i--) { | 
 |  |  |     var sel_pt = this.selected_pts[i]; | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     // Selected seg | 
 |  |  |     var cur = this.segs[sel_pt]; | 
 |  |  |     var prev = cur.prev; | 
 |  |  |     if(!prev) continue; | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     if(!new_type) { // double-click, so just toggle | 
 |  |  |       text = "Toggle Path Segment Type"; | 
 |  |  |  | 
 |  |  |       // Toggle segment to curve/straight line | 
 |  |  |       var old_type = cur.type; | 
 |  |  |        | 
 |  |  |  | 
 |  |  |       new_type = (old_type == 6) ? 4 : 6; | 
 |  |  |     }  | 
 |  |  |      | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     new_type = new_type-0; | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     var cur_x = cur.item.x; | 
 |  |  |     var cur_y = cur.item.y; | 
 |  |  |     var prev_x = prev.item.x; | 
 |  |  | 
 |  |  |       break; | 
 |  |  |     case 4: | 
 |  |  |       points = [cur_x,cur_y]; | 
 |  |  |        | 
 |  |  |  | 
 |  |  |       // Store original prevve segment nums | 
 |  |  |       cur.olditem = cur.item; | 
 |  |  |       break; | 
 |  |  |     } | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     cur.setType(new_type, points); | 
 |  |  |   } | 
 |  |  |   svgedit.path.path.endChanges(text); | 
 |  |  | 
 |  |  |   this.addPtsToSelection(pt); | 
 |  |  |   if(ctrl_num) { | 
 |  |  |     this.dragctrl = ctrl_num; | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     if(link_control_pts) { | 
 |  |  |       this.segs[pt].setLinked(ctrl_num); | 
 |  |  |     } | 
 |  |  | 
 |  |  | var getRotVals = function(x, y, oldcx, oldcy, newcx, newcy, angle) { | 
 |  |  |   dx = x - oldcx; | 
 |  |  |   dy = y - oldcy; | 
 |  |  |    | 
 |  |  |  | 
 |  |  |   // rotate the point around the old center | 
 |  |  |   r = Math.sqrt(dx*dx + dy*dy); | 
 |  |  |   theta = Math.atan2(dy,dx) + angle; | 
 |  |  |   dx = r * Math.cos(theta) + oldcx; | 
 |  |  |   dy = r * Math.sin(theta) + oldcy; | 
 |  |  |    | 
 |  |  |  | 
 |  |  |   // dx,dy should now hold the actual coordinates of each | 
 |  |  |   // point after being rotated | 
 |  |  |  | 
 |  |  |   // now we want to rotate them around the new center in the reverse direction | 
 |  |  |   dx -= newcx; | 
 |  |  |   dy -= newcy; | 
 |  |  |    | 
 |  |  |  | 
 |  |  |   r = Math.sqrt(dx*dx + dy*dy); | 
 |  |  |   theta = Math.atan2(dy,dx) - angle; | 
 |  |  |   return {'x':(r * Math.cos(theta) + newcx)/1, | 
 |  |  | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // If the path was rotated, we must now pay the piper: | 
 |  |  | // Every path point must be rotated into the rotated coordinate system of  | 
 |  |  | // Every path point must be rotated into the rotated coordinate system of | 
 |  |  | // its old center, then determine the new center, then rotate it back | 
 |  |  | // This is because we want the path to remember its rotation | 
 |  |  |  | 
 |  |  | 
 |  |  |     oldcy = oldbox.y + oldbox.height/2, | 
 |  |  |     newcx = box.x + box.width/2, | 
 |  |  |     newcy = box.y + box.height/2, | 
 |  |  |      | 
 |  |  |  | 
 |  |  |   // un-rotate the new center to the proper position | 
 |  |  |     dx = newcx - oldcx, | 
 |  |  |     dy = newcy - oldcy, | 
 |  |  |     r = Math.sqrt(dx*dx + dy*dy), | 
 |  |  |     theta = Math.atan2(dy,dx) + angle; | 
 |  |  |      | 
 |  |  |  | 
 |  |  |   newcx = r * Math.cos(theta) + oldcx; | 
 |  |  |   newcy = r * Math.sin(theta) + oldcy; | 
 |  |  |    | 
 |  |  |  | 
 |  |  |   var list = current_path.pathSegList, | 
 |  |  |     i = list.numberOfItems; | 
 |  |  |   while (i) { | 
 |  |  | 
 |  |  |     var seg = list.getItem(i), | 
 |  |  |       type = seg.pathSegType; | 
 |  |  |     if(type == 1) continue; | 
 |  |  |      | 
 |  |  |  | 
 |  |  |     var rvals = getRotVals(seg.x,seg.y, oldcx, oldcy, newcx, newcy, angle), | 
 |  |  |       points = [rvals.x, rvals.y]; | 
 |  |  |     if(seg.x1 != null && seg.x2 != null) { | 
 |  |  | 
 |  |  |     svgedit.path.replacePathSeg(type, i, points); | 
 |  |  |   } // loop for each point | 
 |  |  |  | 
 |  |  |   box = svgedit.utilities.getBBox(current_path);             | 
 |  |  |   box = svgedit.utilities.getBBox(current_path); | 
 |  |  | //  selectedBBoxes[0].x = box.x; selectedBBoxes[0].y = box.y; | 
 |  |  | //  selectedBBoxes[0].width = box.width; selectedBBoxes[0].height = box.height; | 
 |  |  |    | 
 |  |  |  | 
 |  |  |   // now we must set the new transform to be rotated around the new center | 
 |  |  |   var R_nc = svgroot.createSVGTransform(), | 
 |  |  |     tlist = svgedit.transformlist.getTransformList(current_path); |