aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPushkar Joshi2012-04-16 14:04:04 -0700
committerPushkar Joshi2012-04-16 14:04:04 -0700
commit348ea7dfba12055e15e069a7c2b8bc527531e534 (patch)
tree710b85cfb062d086310f70472bff422317344054
parent04d7f7ec211d7fee47aa353309eca36864c50d53 (diff)
downloadninja-348ea7dfba12055e15e069a7c2b8bc527531e534.tar.gz
Allow the path stroke width to be changed without causing a drift in the canvas position
AND some code cleanup (remove canvas left and top tracking for each subpath) AND add flags for the specifying in what coordinate space we're sampling the subpath
-rwxr-xr-xjs/lib/geom/sub-path.js173
-rwxr-xr-xjs/tools/PenTool.js19
2 files changed, 110 insertions, 82 deletions
diff --git a/js/lib/geom/sub-path.js b/js/lib/geom/sub-path.js
index 761391b7..31bf4632 100755
--- a/js/lib/geom/sub-path.js
+++ b/js/lib/geom/sub-path.js
@@ -43,10 +43,6 @@ var GLSubpath = function GLSubpath() {
43 //initially set the _dirty bit so we will re-construct _Anchors and _Samples 43 //initially set the _dirty bit so we will re-construct _Anchors and _Samples
44 this._dirty = true; 44 this._dirty = true;
45 45
46 //the top left location of this subpath's canvas in screen space (used to identify cases when location changes)
47 this._canvasLeft = 0;
48 this._canvasTop = 0;
49
50 //stroke information 46 //stroke information
51 this._strokeWidth = 1.0; 47 this._strokeWidth = 1.0;
52 this._strokeColor = [0.4, 0.4, 0.4, 1.0]; 48 this._strokeColor = [0.4, 0.4, 0.4, 1.0];
@@ -97,7 +93,7 @@ var GLSubpath = function GLSubpath() {
97 if (numAnchors === 0) { 93 if (numAnchors === 0) {
98 return; //nothing to do for empty paths 94 return; //nothing to do for empty paths
99 } 95 }
100 this.createSamples(); //dirty bit checked in this function...will generate a polyline representation 96 this.createSamples(false); //dirty bit checked in this function...will generate a polyline representation
101 97
102 //figure the size of the area we will draw into 98 //figure the size of the area we will draw into
103 var bboxWidth=0, bboxHeight=0; 99 var bboxWidth=0, bboxHeight=0;
@@ -123,6 +119,8 @@ var GLSubpath = function GLSubpath() {
123 } 119 }
124 var lineCap = ['butt','round','square']; 120 var lineCap = ['butt','round','square'];
125 ctx.lineCap = lineCap[1]; 121 ctx.lineCap = lineCap[1];
122 var lineJoin = ['round','bevel','miter'];
123 ctx.lineJoin = lineJoin[0];
126 124
127 /* 125 /*
128 commenting this out for now because of Chrome bug where coincident endpoints of bezier curve cause the curve to not be rendered 126 commenting this out for now because of Chrome bug where coincident endpoints of bezier curve cause the curve to not be rendered
@@ -649,73 +647,100 @@ GLSubpath.prototype.getStrokeWidth = function () {
649 return this._strokeWidth; 647 return this._strokeWidth;
650}; 648};
651 649
652GLSubpath.prototype.setCanvasLeft = function(cl){
653 this._canvasLeft = cl;
654};
655GLSubpath.prototype.setCanvasTop = function(ct){
656 this._canvasTop = ct;
657};
658GLSubpath.prototype.setCanvasLeftTopPerElementMediator = function(elemMediator){
659 if (!this._canvas){
660 if (!this.getWorld())
661 return; //cannot do anything if there is no world
662 //set the canvas by querying the world
663 this._canvas = this.getWorld().getCanvas();
664 }
665 //check if the canvas was translated
666 var penCanvasCurrentLeft = parseInt(elemMediator.getProperty(this._canvas, "left"));//parseFloat(DocumentControllerModule.DocumentController.GetElementStyle(this._penCanvas, "left"));
667 var penCanvasCurrentTop = parseInt(elemMediator.getProperty(this._canvas, "top"));//parseFloat(DocumentControllerModule.DocumentController.GetElementStyle(this._penCanvas, "top"));
668 650
669 var translateCanvasX = Math.round(penCanvasCurrentLeft - this._canvasLeft); 651GLSubpath.prototype.setStrokeWidth = function (w) {
670 var translateCanvasY = Math.round(penCanvasCurrentTop - this._canvasTop); 652 var diffStrokeWidth = w-this._strokeWidth;//if positive, then stroke width grew, else shrunk
653 if (diffStrokeWidth === 0){
654 return;//nothing to do
655 }
671 656
672 //update the left and top parameters for this subpath and also translate the subpath points (since they're stored in stage world space) 657 //only allow to increase the stroke width with even increments (this avoids floating point round-off problems)
673 if (Math.abs(translateCanvasX)>=1 || Math.abs(translateCanvasY)>=1){ 658 diffStrokeWidth = Math.round(diffStrokeWidth);
674 this.setCanvasLeft(penCanvasCurrentLeft); 659 if (diffStrokeWidth%2){
675 this.setCanvasTop(penCanvasCurrentTop); 660 diffStrokeWidth+=1;
676 } 661 }
677 this._dirty=true;
678};
679 662
680GLSubpath.prototype.computeLeftTopWidthHeight = function() { 663 //update the stroke width by the delta
681 //build the width and height of this canvas by looking at local coordinates 664 this._strokeWidth += diffStrokeWidth;
682 var bboxMin = this.getLocalBBoxMin();
683 var bboxMax = this.getLocalBBoxMax();
684 var bboxWidth = bboxMax[0] - bboxMin[0];
685 var bboxHeight = bboxMax[1] - bboxMin[1];
686 665
687 //build the 3D position of the plane center of this canvas by looking at midpoint of the bounding box in stage world coords 666 //if we have no path yet, return
688 bboxMin = this.getBBoxMin(); 667 if (this.getNumAnchors()<2 || this._canvas===null){
689 bboxMax = this.getBBoxMax(); 668 return;
690 //var bboxMid = [0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0.5 * (bboxMax[2] + bboxMin[2])]; 669 }
691 //var left = Math.round(bboxMid[0] - 0.5 * bboxWidth);
692 //var top = Math.round(bboxMid[1] - 0.5 * bboxHeight);
693 var left = this._canvasLeft;
694 var top = this._canvasTop;
695 return [left, top, bboxWidth, bboxHeight];
696};
697 670
698GLSubpath.prototype.setStrokeWidth = function (w) { 671 if (this._dirty){
699 var diffStrokeWidth = w-Math.floor(this._strokeWidth);//if positive, then stroke width grew, else shrunk 672 this.createSamples(false); //this will also update the bounding box
700 if (diffStrokeWidth === 0) 673 } else{
701 return;//nothing to do 674 this.computeBoundingBox(false);
675 }
676 this.offsetPerBBoxMin(); //this will shift the local coordinates such that the bbox min point is at (0,0)
702 677
703 this._strokeWidth = w; 678 //figure out the adjustment to the canvas position and size
704 this._dirty=true; 679 var delta = Math.round(diffStrokeWidth*0.5);
705 680
681 //update the width, height, left and top
706 var ElementMediator = require("js/mediators/element-mediator").ElementMediator; 682 var ElementMediator = require("js/mediators/element-mediator").ElementMediator;
683 var penCanvasCurrentWidth = parseInt(ElementMediator.getProperty(this._canvas, "width"));
684 var penCanvasNewWidth = penCanvasCurrentWidth + diffStrokeWidth;
685 var penCanvasCurrentHeight = parseInt(ElementMediator.getProperty(this._canvas, "height"));
686 var penCanvasNewHeight = penCanvasCurrentHeight + diffStrokeWidth;
687 var penCanvasCurrentLeft = parseInt(ElementMediator.getProperty(this._canvas, "left"));
688 var penCanvasNewLeft = penCanvasCurrentLeft - delta;
689 var penCanvasCurrentTop = parseInt(ElementMediator.getProperty(this._canvas, "top"));
690 var penCanvasNewTop = penCanvasCurrentTop - delta;
691 var canvasArray=[this._canvas];
692 ElementMediator.setProperty(canvasArray, "width", [penCanvasNewWidth+"px"], "Changing", "penTool");
693 ElementMediator.setProperty(canvasArray, "height", [penCanvasNewHeight+"px"], "Changing", "penTool");
694 ElementMediator.setProperty(canvasArray, "left", [penCanvasNewLeft+"px"],"Changing", "penTool");
695 ElementMediator.setProperty(canvasArray, "top", [penCanvasNewTop+ "px"],"Changing", "penTool");
696
697 /*
698 //compute the current location of the canvas for this subpath
699 this.createSamples(); //this will also update the bounding box
700 var bboxMin = this.getBBoxMin();
701 var bboxMax = this.getBBoxMax();
702 var bboxMid = [0.5 * (bboxMax[0] + bboxMin[0]), 0.5 * (bboxMax[1] + bboxMin[1]), 0]; //ignore the Z coord. for local coordinates
703
704 //go from local coordinates to stage world
705 var ViewUtils = require("js/helper-classes/3D/view-utils").ViewUtils;
706 var SnapManager = require("js/helper-classes/3D/snap-manager").SnapManager;
707 var localToStageWorldMat = ViewUtils.getLocalToStageWorldMatrix(this._canvas, true, true);
708 var bboxMidSW = MathUtils.transformAndDivideHomogeneousPoint(bboxMid, localToStageWorldMat);
709 bboxMidSW[0]+=SnapManager.getStageWidth()*0.5;
710 bboxMidSW[1]+=SnapManager.getStageHeight()*0.5;
711
712 this._strokeWidth = Math.round(w);
713 this._dirty=true;
714
715 // **** adjust the local coordinates to account for the change in stroke width ****
716 this.computeBoundingBox(); //this will take the new strokewidth into account
717 this.offsetPerBBoxMin(); //this will shift the local coordinates such that the bbox min point is at (0,0)
707 718
708 //translate the subpath in case the actual canvas location does not match where subpath thinks the canvas should be 719 // **** adjust the canvas position to account for the change in stroke width
709 this.setCanvasLeftTopPerElementMediator(ElementMediator); 720 var ElementMediator = require("js/mediators/element-mediator").ElementMediator;
721 //build the width and height of this canvas by looking at local coordinates
722 bboxMin = this.getBBoxMin();
723 bboxMax = this.getBBoxMax();
724 var width = Math.round(bboxMax[0] - bboxMin[0]);
725 var height = Math.round(bboxMax[1] - bboxMin[1]);
726 var left = Math.round(bboxMidSW[0] - 0.5 * width);
727 var top = Math.round(bboxMidSW[1] - 0.5 * height);
710 728
711 // **** adjust the left, top, width, and height to adjust for the change in stroke width ****
712 this.createSamples(); //dirty bit is checked here
713 var ltwh = this.computeLeftTopWidthHeight();
714 var canvasArray=[this._canvas]; 729 var canvasArray=[this._canvas];
715 ElementMediator.setProperty(canvasArray, "width", [ltwh[2]+"px"], "Changing", "penTool");//canvas.width = w; 730 ElementMediator.setProperty(canvasArray, "width", [width+"px"], "Changing", "penTool");
716 ElementMediator.setProperty(canvasArray, "height", [ltwh[3]+"px"], "Changing", "penTool");//canvas.height = h; 731 ElementMediator.setProperty(canvasArray, "height", [height+"px"], "Changing", "penTool");
717 ElementMediator.setProperty(canvasArray, "left", [ltwh[0]+"px"],"Changing", "penTool");//DocumentControllerModule.DocumentController.SetElementStyle(canvas, "left", parseInt(left) + "px"); 732
718 ElementMediator.setProperty(canvasArray, "top", [ltwh[1]+ "px"],"Changing", "penTool");//DocumentControllerModule.DocumentController.SetElementStyle(canvas, "top", parseInt(top) + "px"); 733 //check if the canvas was translated
734 var penCanvasCurrentLeft = parseInt(ElementMediator.getProperty(this._canvas, "left"));
735 var penCanvasCurrentTop = parseInt(ElementMediator.getProperty(this._canvas, "top"));
736 left = Math.round(penCanvasCurrentLeft - diffStrokeWidth*0.5);
737 top = Math.round(penCanvasCurrentTop - diffStrokeWidth*0.5);
738
739 //left = Math.round(bboxMidSW[0] - 0.5 * width);
740 //top = Math.round(bboxMidSW[1] - 0.5 * height);
741 ElementMediator.setProperty(canvasArray, "left", [left+"px"],"Changing", "penTool");
742 ElementMediator.setProperty(canvasArray, "top", [top+ "px"],"Changing", "penTool");
743 */
719}; 744};
720 745
721GLSubpath.prototype.getStrokeColor = function () { 746GLSubpath.prototype.getStrokeColor = function () {
@@ -866,7 +891,7 @@ GLSubpath.prototype._unprojectPt = function(pt, pespectiveDist) {
866 891
867// createSamples 892// createSamples
868// stores samples of the subpath in _samples 893// stores samples of the subpath in _samples
869GLSubpath.prototype.createSamples = function () { 894GLSubpath.prototype.createSamples = function (isStageWorldCoord) {
870 if (this._dirty) { 895 if (this._dirty) {
871 //clear any previously computed samples 896 //clear any previously computed samples
872 this._Samples = []; 897 this._Samples = [];
@@ -928,7 +953,7 @@ GLSubpath.prototype.createSamples = function () {
928 } //if (numAnchors >== 2) { 953 } //if (numAnchors >== 2) {
929 954
930 //re-compute the bounding box (this also accounts for stroke width, so assume the stroke width is set) 955 //re-compute the bounding box (this also accounts for stroke width, so assume the stroke width is set)
931 this.computeBoundingBox(true); 956 this.computeBoundingBox(true, isStageWorldCoord);
932 } //if (this._dirty) 957 } //if (this._dirty)
933 this._dirty = false; 958 this._dirty = false;
934}; 959};
@@ -938,13 +963,14 @@ GLSubpath.prototype.offsetPerBBoxMin = function()
938 //offset the anchor and sample coordinates such that the min point of the bbox is at [0,0,0] 963 //offset the anchor and sample coordinates such that the min point of the bbox is at [0,0,0]
939 this.translateAnchors(-this._BBoxMin[0], -this._BBoxMin[1], -this._BBoxMin[2]); 964 this.translateAnchors(-this._BBoxMin[0], -this._BBoxMin[1], -this._BBoxMin[2]);
940 this.translateSamples(-this._BBoxMin[0], -this._BBoxMin[1], -this._BBoxMin[2]); 965 this.translateSamples(-this._BBoxMin[0], -this._BBoxMin[1], -this._BBoxMin[2]);
966
941 this._BBoxMax[0]-= this._BBoxMin[0];