diff options
author | Pushkar Joshi | 2012-04-16 14:04:04 -0700 |
---|---|---|
committer | Pushkar Joshi | 2012-04-16 14:04:04 -0700 |
commit | 348ea7dfba12055e15e069a7c2b8bc527531e534 (patch) | |
tree | 710b85cfb062d086310f70472bff422317344054 /js | |
parent | 04d7f7ec211d7fee47aa353309eca36864c50d53 (diff) | |
download | ninja-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
Diffstat (limited to 'js')
-rwxr-xr-x | js/lib/geom/sub-path.js | 173 | ||||
-rwxr-xr-x | js/tools/PenTool.js | 19 |
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 | ||
652 | GLSubpath.prototype.setCanvasLeft = function(cl){ | ||
653 | this._canvasLeft = cl; | ||
654 | }; | ||
655 | GLSubpath.prototype.setCanvasTop = function(ct){ | ||
656 | this._canvasTop = ct; | ||
657 | }; | ||
658 | GLSubpath.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); | 651 | GLSubpath.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 | ||
680 | GLSubpath.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 | ||
698 | GLSubpath.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 | ||
721 | GLSubpath.prototype.getStrokeColor = function () { | 746 | GLSubpath.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 |
869 | GLSubpath.prototype.createSamples = function () { | 894 | GLSubpath.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]); |