diff options
Diffstat (limited to 'js/lib/geom')
-rwxr-xr-x | js/lib/geom/sub-path.js | 311 |
1 files changed, 156 insertions, 155 deletions
diff --git a/js/lib/geom/sub-path.js b/js/lib/geom/sub-path.js index a9034def..db115655 100755 --- a/js/lib/geom/sub-path.js +++ b/js/lib/geom/sub-path.js | |||
@@ -68,178 +68,179 @@ var GLSubpath = function GLSubpath() { | |||
68 | this._selectedAnchorIndex = -1; | 68 | this._selectedAnchorIndex = -1; |
69 | 69 | ||
70 | this._SAMPLING_EPSILON = 0.5; //epsilon used for sampling the curve | 70 | this._SAMPLING_EPSILON = 0.5; //epsilon used for sampling the curve |
71 | }; //function GLSubpath ...class definition | ||
71 | 72 | ||
72 | // (current GeomObj complains if buildBuffers/render is added to GLSubpath prototype) | 73 | GLSubpath.prototype = Object.create(GeomObj, {}); |
73 | //buildBuffers | ||
74 | // Build the stroke vertices, normals, textures and colors | ||
75 | // Add that array data to the GPU using OpenGL data binding | ||
76 | this.buildBuffers = function () { | ||
77 | // return; //no need to do anything for now | ||
78 | }; | ||
79 | |||
80 | //render | ||
81 | // specify how to render the subpath in Canvas2D | ||
82 | this.render = function () { | ||
83 | // get the world | ||
84 | var world = this.getWorld(); | ||
85 | if (!world) throw( "null world in subpath render" ); | ||
86 | if (!this._canvas){ | ||
87 | //set the canvas by querying the world | ||
88 | this._canvas = this.getWorld().getCanvas(); | ||
89 | } | ||
90 | // get the context | ||
91 | var ctx = world.get2DContext(); | ||
92 | if (!ctx) throw ("null context in subpath render"); | ||
93 | |||
94 | var numAnchors = this.getNumAnchors(); | ||
95 | if (numAnchors === 0) { | ||
96 | return; //nothing to do for empty paths | ||
97 | } | ||
98 | this.createSamples(false); //dirty bit checked in this function...will generate a polyline representation | ||
99 | 74 | ||
100 | var numPoints = this._Samples.length; | 75 | //buildBuffers |
101 | if (numPoints === 0){ | 76 | GLSubpath.prototype.buildBuffers = function () { |
102 | return; //nothing to do for empty paths | 77 | //no need to do anything for now (no WebGL) |
103 | } | 78 | }; |
104 | |||
105 | //figure the size of the area we will draw into | ||
106 | var bboxWidth=0, bboxHeight=0; | ||
107 | bboxWidth = this._BBoxMax[0] - this._BBoxMin[0]; | ||
108 | bboxHeight = this._BBoxMax[1] - this._BBoxMin[1]; | ||
109 | |||
110 | ctx.save(); | ||
111 | ctx.clearRect(0, 0, bboxWidth, bboxHeight); | ||
112 | |||
113 | ctx.lineWidth = this._strokeWidth; | ||
114 | ctx.strokeStyle = "black"; | ||
115 | if (this._strokeColor) { | ||
116 | //ctx.strokeStyle = MathUtils.colorToHex( this._strokeColor ); | ||
117 | var strokeColorStr = "rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+","+this._strokeColor[3]+")"; | ||
118 | ctx.strokeStyle = strokeColorStr; | ||
119 | } | ||
120 | 79 | ||
121 | ctx.fillStyle = "white"; | 80 | //render |
122 | if (this._fillColor){ | 81 | // specify how to render the subpath in Canvas2D |
123 | //ctx.fillStyle = MathUtils.colorToHex( this._fillColor ); | 82 | GLSubpath.prototype.render = function () { |
124 | var fillColorStr = "rgba("+parseInt(255*this._fillColor[0])+","+parseInt(255*this._fillColor[1])+","+parseInt(255*this._fillColor[2])+","+this._fillColor[3]+")"; | 83 | // get the world |
125 | ctx.fillStyle = fillColorStr; | 84 | var world = this.getWorld(); |
126 | } | 85 | if (!world) throw( "null world in subpath render" ); |
127 | var lineCap = ['butt','round','square']; | 86 | if (!this._canvas){ |
128 | ctx.lineCap = lineCap[1]; | 87 | //set the canvas by querying the world |
129 | var lineJoin = ['round','bevel','miter']; | 88 | this._canvas = this.getWorld().getCanvas(); |
130 | ctx.lineJoin = lineJoin[0]; | 89 | } |
131 | 90 | // get the context | |
132 | /* | 91 | var ctx = world.get2DContext(); |
133 | commenting this out for now because of Chrome bug where coincident endpoints of bezier curve cause the curve to not be rendered | 92 | if (!ctx) throw ("null context in subpath render"); |
134 | ctx.beginPath(); | ||
135 | var prevAnchor = this.getAnchor(0); | ||
136 | ctx.moveTo(prevAnchor.getPosX()-bboxMin[0],prevAnchor.getPosY()-bboxMin[1]); | ||
137 | for (var i = 1; i < numAnchors; i++) { | ||
138 | var currAnchor = this.getAnchor(i); | ||
139 | ctx.bezierCurveTo(prevAnchor.getNextX()-bboxMin[0],prevAnchor.getNextY()-bboxMin[1], currAnchor.getPrevX()-bboxMin[0], currAnchor.getPrevY()-bboxMin[1], currAnchor.getPosX()-bboxMin[0], currAnchor.getPosY()-bboxMin[1]); | ||
140 | prevAnchor = currAnchor; | ||
141 | } | ||
142 | if (this._isClosed === true) { | ||
143 | var currAnchor = this.getAnchor(0); | ||
144 | ctx.bezierCurveTo(prevAnchor.getNextX()-bboxMin[0],prevAnchor.getNextY()-bboxMin[1], currAnchor.getPrevX()-bboxMin[0], currAnchor.getPrevY()-bboxMin[1], currAnchor.getPosX()-bboxMin[0], currAnchor.getPosY()-bboxMin[1]); | ||
145 | prevAnchor = currAnchor; | ||
146 | ctx.fill(); | ||
147 | } | ||
148 | */ | ||
149 | 93 | ||
94 | var numAnchors = this.getNumAnchors(); | ||
95 | if (numAnchors === 0) { | ||
96 | return; //nothing to do for empty paths | ||
97 | } | ||
98 | this.createSamples(false); //dirty bit checked in this function...will generate a polyline representation | ||
150 | 99 | ||
151 | ctx.beginPath(); | 100 | var numPoints = this._Samples.length; |
152 | ctx.moveTo(this._Samples[0][0],this._Samples[0][1]); | 101 | if (numPoints === 0){ |
153 | for (var i=0;i<numPoints;i++){ | 102 | return; //nothing to do for empty paths |
154 | ctx.lineTo(this._Samples[i][0],this._Samples[i][1]); | 103 | } |
155 | } | ||
156 | if (this._isClosed === true) { | ||
157 | ctx.lineTo(this._Samples[0][0],this._Samples[0][1]); | ||
158 | } | ||
159 | ctx.fill(); | ||
160 | ctx.stroke(); | ||
161 | ctx.restore(); | ||
162 | }; //render() | ||
163 | |||
164 | this.geomType = function () { | ||
165 | return this.GEOM_TYPE_CUBIC_BEZIER; | ||
166 | }; | ||
167 | |||
168 | this.setWidth = function (newW) { | ||
169 | var strokeWidth = this._strokeWidth; | ||
170 | var halfStrokeWidth = strokeWidth*0.5; | ||
171 | if (newW<1) { | ||
172 | newW=1; //clamp minimum width to 1 | ||
173 | } | ||
174 | 104 | ||
175 | //scale the contents of this subpath to lie within this width | 105 | //figure the size of the area we will draw into |
176 | //determine the scale factor by comparing with the old width | 106 | var bboxWidth=0, bboxHeight=0; |
177 | var oldWidth = this._BBoxMax[0]-this._BBoxMin[0]; | 107 | bboxWidth = this._BBoxMax[0] - this._BBoxMin[0]; |
178 | if (oldWidth<1) { | 108 | bboxHeight = this._BBoxMax[1] - this._BBoxMin[1]; |
179 | oldWidth=1; | ||
180 | } | ||
181 | 109 | ||
182 | var scaleX = newW/oldWidth; | 110 | ctx.save(); |
183 | if (scaleX===1) { | 111 | ctx.clearRect(0, 0, bboxWidth, bboxHeight); |
184 | return; //no need to do anything | ||
185 | } | ||
186 | 112 | ||
187 | //scale the anchor point positions such that the width of the bbox is the newW | 113 | ctx.lineWidth = this._strokeWidth; |
188 | var origX = this._BBoxMin[0]; //this should always be zero since we only deal with local coordinates | 114 | ctx.strokeStyle = "black"; |
189 | var numAnchors = this._Anchors.length; | 115 | if (this._strokeColor) { |
190 | for (var i=0;i<numAnchors;i++){ | 116 | //ctx.strokeStyle = MathUtils.colorToHex( this._strokeColor ); |
191 | //compute the distance from the bboxMin | 117 | var strokeColorStr = "rgba("+parseInt(255*this._strokeColor[0])+","+parseInt(255*this._strokeColor[1])+","+parseInt(255*this._strokeColor[2])+","+this._strokeColor[3]+")"; |
192 | var oldW = this._Anchors[i].getPosX() - origX; | 118 | ctx.strokeStyle = strokeColorStr; |
193 | var prevW = this._Anchors[i].getPrevX() - origX; | 119 | } |
194 | var nextW = this._Anchors[i].getNextX() - origX; | ||
195 | |||
196 | this._Anchors[i].setPos(origX + oldW*scaleX,this._Anchors[i].getPosY(),this._Anchors[i].getPosZ()); | ||
197 | this._Anchors[i].setPrevPos(origX + prevW*scaleX,this._Anchors[i].getPrevY(),this._Anchors[i].getPrevZ()); | ||
198 | this._Anchors[i].setNextPos(origX + nextW*scaleX,this._Anchors[i].getNextY(),this._Anchors[i].getNextZ()); | ||
199 | } | ||
200 | this.makeDirty(); | ||
201 | this.computeBoundingBox(true, false); | ||
202 | }; | ||
203 | 120 | ||
204 | this.setHeight = function (newH) { | 121 | ctx.fillStyle = "white"; |
205 | if (newH<1) { | 122 | if (this._fillColor){ |
206 | newH=1; //clamp minimum width to 1 | 123 | //ctx.fillStyle = MathUtils.colorToHex( this._fillColor ); |
207 | } | 124 | var fillColorStr = "rgba("+parseInt(255*this._fillColor[0])+","+parseInt(255*this._fillColor[1])+","+parseInt(255*this._fillColor[2])+","+this._fillColor[3]+")"; |
208 | //scale the contents of this subpath to lie within this height | 125 | ctx.fillStyle = fillColorStr; |
209 | //determine the scale factor by comparing with the old height | 126 | } |
210 | var oldHeight = this._BBoxMax[1]-this._BBoxMin[1]; | 127 | var lineCap = ['butt','round','square']; |
211 | if (oldHeight<1){ | 128 | ctx.lineCap = lineCap[1]; |
212 | oldHeight=1; | 129 | var lineJoin = ['round','bevel','miter']; |
213 | } | 130 | ctx.lineJoin = lineJoin[0]; |
131 | |||
132 | |||
133 | //commenting this out for now because of Chrome bug where coincident endpoints of bezier curve cause the curve to not be rendered | ||
134 | /* | ||
135 | ctx.beginPath(); | ||
136 | var prevAnchor = this.getAnchor(0); | ||
137 | ctx.moveTo(prevAnchor.getPosX(),prevAnchor.getPosY()); | ||
138 | for (var i = 1; i < numAnchors; i++) { | ||
139 | var currAnchor = this.getAnchor(i); | ||
140 | ctx.bezierCurveTo(prevAnchor.getNextX(),prevAnchor.getNextY(), currAnchor.getPrevX(), currAnchor.getPrevY(), currAnchor.getPosX(), currAnchor.getPosY()); | ||
141 | prevAnchor = currAnchor; | ||
142 | } | ||
143 | if (this._isClosed === true) { | ||
144 | var currAnchor = this.getAnchor(0); | ||
145 | ctx.bezierCurveTo(prevAnchor.getNextX(),prevAnchor.getNextY(), currAnchor.getPrevX(), currAnchor.getPrevY(), currAnchor.getPosX(), currAnchor.getPosY()); | ||
146 | prevAnchor = currAnchor; | ||
147 | } | ||
148 | ctx.fill(); | ||
149 | ctx.stroke(); | ||
150 | */ | ||
214 | 151 | ||
215 | var scaleY = newH/oldHeight; | ||
216 | if (scaleY===1){ | ||
217 | return; //no need to do anything | ||
218 | } | ||
219 | 152 | ||
220 | //scale the anchor point positions such that the height of the bbox is the newH | 153 | ctx.beginPath(); |
221 | var origY = this._BBoxMin[1]; | 154 | ctx.moveTo(this._Samples[0][0],this._Samples[0][1]); |
222 | var numAnchors = this._Anchors.length; | 155 | for (var i=0;i<numPoints;i++){ |
223 | for (var i=0;i<numAnchors;i++){ | 156 | ctx.lineTo(this._Samples[i][0],this._Samples[i][1]); |
224 | //compute the distance from the bboxMin | ||
225 | var oldW = this._Anchors[i].getPosY() - origY; | ||
226 | var prevW = this._Anchors[i].getPrevY() - origY; | ||
227 | var nextW = this._Anchors[i].getNextY() - origY; | ||
228 | |||
229 | this._Anchors[i].setPos(this._Anchors[i].getPosX(), origY + oldW*scaleY,this._Anchors[i].getPosZ()); | ||
230 | this._Anchors[i].setPrevPos(this._Anchors[i].getPrevX(), origY + prevW*scaleY,this._Anchors[i].getPrevZ()); | ||
231 | this._Anchors[i].setNextPos(this._Anchors[i].getNextX(), origY + nextW*scaleY,this._Anchors[i].getNextZ()); | ||
232 | } | ||
233 | this.makeDirty(); | ||
234 | } | 157 | } |
158 | if (this._isClosed === true) { | ||
159 | ctx.lineTo(this._Samples[0][0],this._Samples[0][1]); | ||
160 | } | ||
161 | ctx.fill(); | ||
162 | ctx.stroke(); | ||
235 | 163 | ||
236 | }; //function GLSubpath ...class definition | 164 | ctx.restore(); |
237 | 165 |