@@ -8,6 +8,7 @@ var renderValues = true;
88var renderDnpOutline = false ;
99var renderTracks = true ;
1010var renderZones = true ;
11+ var emptyContext2d = document . createElement ( "canvas" ) . getContext ( "2d" ) ;
1112
1213function deg2rad ( deg ) {
1314 return deg * Math . PI / 180 ;
@@ -122,74 +123,79 @@ function drawedge(ctx, scalefactor, edge, color) {
122123 }
123124}
124125
125- function drawChamferedRect ( ctx , color , size , radius , chamfpos , chamfratio , ctxmethod ) {
126+ function getChamferedRectPath ( size , radius , chamfpos , chamfratio ) {
126127 // chamfpos is a bitmask, left = 1, right = 2, bottom left = 4, bottom right = 8
127- ctx . beginPath ( ) ;
128- ctx . strokeStyle = color ;
128+ var path = new Path2D ( ) ;
129129 var width = size [ 0 ] ;
130130 var height = size [ 1 ] ;
131131 var x = width * - 0.5 ;
132132 var y = height * - 0.5 ;
133133 var chamfOffset = Math . min ( width , height ) * chamfratio ;
134- ctx . moveTo ( x , 0 ) ;
134+ path . moveTo ( x , 0 ) ;
135135 if ( chamfpos & 4 ) {
136- ctx . lineTo ( x , y + height - chamfOffset ) ;
137- ctx . lineTo ( x + chamfOffset , y + height ) ;
138- ctx . lineTo ( 0 , y + height ) ;
136+ path . lineTo ( x , y + height - chamfOffset ) ;
137+ path . lineTo ( x + chamfOffset , y + height ) ;
138+ path . lineTo ( 0 , y + height ) ;
139139 } else {
140- ctx . arcTo ( x , y + height , x + width , y + height , radius ) ;
140+ path . arcTo ( x , y + height , x + width , y + height , radius ) ;
141141 }
142142 if ( chamfpos & 8 ) {
143- ctx . lineTo ( x + width - chamfOffset , y + height ) ;
144- ctx . lineTo ( x + width , y + height - chamfOffset ) ;
145- ctx . lineTo ( x + width , 0 ) ;
143+ path . lineTo ( x + width - chamfOffset , y + height ) ;
144+ path . lineTo ( x + width , y + height - chamfOffset ) ;
145+ path . lineTo ( x + width , 0 ) ;
146146 } else {
147- ctx . arcTo ( x + width , y + height , x + width , y , radius ) ;
147+ path . arcTo ( x + width , y + height , x + width , y , radius ) ;
148148 }
149149 if ( chamfpos & 2 ) {
150- ctx . lineTo ( x + width , y + chamfOffset ) ;
151- ctx . lineTo ( x + width - chamfOffset , y ) ;
152- ctx . lineTo ( 0 , y ) ;
150+ path . lineTo ( x + width , y + chamfOffset ) ;
151+ path . lineTo ( x + width - chamfOffset , y ) ;
152+ path . lineTo ( 0 , y ) ;
153153 } else {
154- ctx . arcTo ( x + width , y , x , y , radius ) ;
154+ path . arcTo ( x + width , y , x , y , radius ) ;
155155 }
156156 if ( chamfpos & 1 ) {
157- ctx . lineTo ( x + chamfOffset , y ) ;
158- ctx . lineTo ( x , y + chamfOffset ) ;
159- ctx . lineTo ( x , 0 ) ;
157+ path . lineTo ( x + chamfOffset , y ) ;
158+ path . lineTo ( x , y + chamfOffset ) ;
159+ path . lineTo ( x , 0 ) ;
160160 } else {
161- ctx . arcTo ( x , y , x , y + height , radius ) ;
161+ path . arcTo ( x , y , x , y + height , radius ) ;
162162 }
163- ctx . closePath ( ) ;
164- ctxmethod ( ) ;
163+ path . closePath ( ) ;
164+ return path ;
165165}
166166
167- function drawOblong ( ctx , color , size , ctxmethod ) {
168- drawChamferedRect ( ctx , color , size , Math . min ( size [ 0 ] , size [ 1 ] ) / 2 , 0 , 0 , ctxmethod ) ;
167+ function getOblongPath ( size ) {
168+ return getChamferedRectPath ( size , Math . min ( size [ 0 ] , size [ 1 ] ) / 2 , 0 , 0 ) ;
169169}
170170
171- function drawPolygons ( ctx , color , polygons , ctxmethod ) {
172- ctx . fillStyle = color ;
171+ function getPolygonsPath ( polygons ) {
172+ var combinedPath = new Path2D ( ) ;
173173 for ( var polygon of polygons ) {
174- ctx . beginPath ( ) ;
174+ var path = new Path2D ( ) ;
175175 for ( var vertex of polygon ) {
176- ctx . lineTo ( ...vertex )
176+ path . lineTo ( ...vertex )
177177 }
178- ctx . closePath ( ) ;
179- ctxmethod ( ) ;
178+ path . closePath ( ) ;
179+ combinedPath . addPath ( path ) ;
180180 }
181+ return combinedPath ;
181182}
182183
183184function drawPolygonShape ( ctx , shape , color ) {
184185 ctx . save ( ) ;
185- if ( shape . svgpath ) {
186- ctx . fillStyle = color ;
187- ctx . fill ( new Path2D ( shape . svgpath ) ) ;
188- } else {
186+ ctx . fillStyle = color ;
187+ if ( ! shape . path2d ) {
188+ if ( shape . svgpath ) {
189+ shape . path2d = new Path2D ( shape . svgpath ) ;
190+ } else {
191+ shape . path2d = getPolygonsPath ( shape . polygons ) ;
192+ }
193+ }
194+ if ( ! shape . svgpath ) {
189195 ctx . translate ( ...shape . pos ) ;
190196 ctx . rotate ( deg2rad ( - shape . angle ) ) ;
191- drawPolygons ( ctx , color , shape . polygons , ctx . fill . bind ( ctx ) ) ;
192197 }
198+ ctx . fill ( shape . path2d ) ;
193199 ctx . restore ( ) ;
194200}
195201
@@ -203,11 +209,32 @@ function drawDrawing(ctx, layer, scalefactor, drawing, color) {
203209 }
204210}
205211
206- function drawCircle ( ctx , radius , ctxmethod ) {
207- ctx . beginPath ( ) ;
208- ctx . arc ( 0 , 0 , radius , 0 , 2 * Math . PI ) ;
209- ctx . closePath ( ) ;
210- ctxmethod ( ) ;
212+ function getCirclePath ( radius ) {
213+ var path = new Path2D ( ) ;
214+ path . arc ( 0 , 0 , radius , 0 , 2 * Math . PI ) ;
215+ path . closePath ( ) ;
216+ return path ;
217+ }
218+
219+ function getCachedPadPath ( pad ) {
220+ if ( ! pad . path2d ) {
221+ // if path2d is not set, build one and cache it on pad object
222+ if ( pad . shape == "rect" ) {
223+ pad . path2d = new Path2D ( ) ;
224+ pad . path2d . rect ( ...pad . size . map ( c => - c * 0.5 ) , ...pad . size ) ;
225+ } else if ( pad . shape == "oval" ) {
226+ pad . path2d = getOblongPath ( pad . size ) ;
227+ } else if ( pad . shape == "circle" ) {
228+ pad . path2d = getCirclePath ( pad . size [ 0 ] / 2 ) ;
229+ } else if ( pad . shape == "roundrect" ) {
230+ pad . path2d = getChamferedRectPath ( pad . size , pad . radius , 0 , 0 ) ;
231+ } else if ( pad . shape == "chamfrect" ) {
232+ pad . path2d = getChamferedRectPath ( pad . size , pad . radius , pad . chamfpos , pad . chamfratio )
233+ } else if ( pad . shape == "custom" ) {
234+ pad . path2d = getPolygonsPath ( pad . polygons ) ;
235+ }
236+ }
237+ return pad . path2d ;
211238}
212239
213240function drawPad ( ctx , pad , color , outline , hole ) {
@@ -219,32 +246,18 @@ function drawPad(ctx, pad, color, outline, hole) {
219246 }
220247 ctx . fillStyle = color ;
221248 ctx . strokeStyle = color ;
222- var ctxmethod = outline ? ctx . stroke . bind ( ctx ) : ctx . fill . bind ( ctx ) ;
223- if ( pad . shape == "rect" ) {
224- var rect = [ ...pad . size . map ( c => - c * 0.5 ) , ...pad . size ] ;
225- if ( outline ) {
226- ctx . strokeRect ( ...rect ) ;
227- } else {
228- ctx . fillRect ( ...rect ) ;
229- }
230- } else if ( pad . shape == "oval" ) {
231- drawOblong ( ctx , color , pad . size , ctxmethod ) ;
232- } else if ( pad . shape == "circle" ) {
233- drawCircle ( ctx , pad . size [ 0 ] / 2 , ctxmethod ) ;
234- } else if ( pad . shape == "roundrect" ) {
235- drawChamferedRect ( ctx , color , pad . size , pad . radius , 0 , 0 , ctxmethod ) ;
236- } else if ( pad . shape == "chamfrect" ) {
237- drawChamferedRect ( ctx , color , pad . size , pad . radius , pad . chamfpos , pad . chamfratio , ctxmethod )
238- } else if ( pad . shape == "custom" ) {
239- drawPolygons ( ctx , color , pad . polygons , ctxmethod ) ;
249+ var path = getCachedPadPath ( pad ) ;
250+ if ( outline ) {
251+ ctx . stroke ( path ) ;
252+ } else {
253+ ctx . fill ( path ) ;
240254 }
241255 if ( pad . type == "th" && hole ) {
242- ctxmethod = ctx . fill . bind ( ctx ) ;
243256 ctx . fillStyle = "#CCCCCC" ;
244257 if ( pad . drillshape == "oblong" ) {
245- drawOblong ( ctx , "#CCCCCC" , pad . drillsize , ctxmethod ) ;
258+ ctx . fill ( getOblongPath ( pad . drillsize ) ) ;
246259 } else {
247- drawCircle ( ctx , pad . drillsize [ 0 ] / 2 , ctxmethod ) ;
260+ ctx . fill ( getCirclePath ( pad . drillsize [ 0 ] / 2 ) ) ;
248261 }
249262 }
250263 ctx . restore ( ) ;
@@ -345,12 +358,16 @@ function drawTracks(canvas, layer, color, highlight) {
345358function drawZones ( canvas , layer , color , highlight ) {
346359 ctx = canvas . getContext ( "2d" ) ;
347360 ctx . strokeStyle = color ;
361+ ctx . fillStyle = color ;
348362 ctx . lineJoin = "round" ;
349363 for ( var zone of pcbdata . zones [ layer ] ) {
364+ if ( ! zone . path2d ) {
365+ zone . path2d = getPolygonsPath ( zone . polygons ) ;
366+ }
350367 if ( highlight && highlightedNet != zone . net ) continue ;
351368 ctx . lineWidth = zone . width ;
352- drawPolygons ( ctx , color , zone . polygons , ctx . stroke . bind ( ctx ) ) ;
353- drawPolygons ( ctx , color , zone . polygons , ctx . fill . bind ( ctx ) ) ;
369+ ctx . fill ( zone . path2d ) ;
370+ ctx . stroke ( zone . path2d ) ;
354371 }
355372}
356373
@@ -563,35 +580,25 @@ function pointWithinPad(x, y, pad) {
563580 v [ 0 ] -= pad . offset [ 0 ] ;
564581 v [ 1 ] -= pad . offset [ 1 ] ;
565582 }
566- if ( [ "rect" , "roundrect" , "chamfrect" ] . includes ( pad . shape ) ) {
567- return - pad . size [ 0 ] / 2 <= v [ 0 ] && v [ 0 ] <= pad . size [ 0 ] / 2 &&
568- - pad . size [ 1 ] / 2 <= v [ 1 ] && v [ 1 ] <= pad . size [ 1 ] / 2 ;
569- } else if ( pad . shape == "oval" ) {
570- var d = ( pad . size [ 0 ] - pad . size [ 1 ] ) / 2 ;
571- if ( d > 0 ) {
572- return pointWithinDistanceToSegment ( v [ 0 ] , v [ 1 ] , d , 0 , - d , 0 , pad . size [ 1 ] / 2 ) ;
573- } else {
574- return pointWithinDistanceToSegment ( v [ 0 ] , v [ 1 ] , 0 , d , 0 , - d , pad . size [ 0 ] / 2 ) ;
575- }
576- } else if ( pad . shape == "circle" ) {
577- return v [ 0 ] * v [ 0 ] + v [ 1 ] * v [ 1 ] <= pad . size [ 0 ] * pad . size [ 0 ] / 4 ;
578- }
583+ return emptyContext2d . isPointInPath ( getCachedPadPath ( pad ) , ...v ) ;
579584}
580585
581586function netHitScan ( layer , x , y ) {
582587 // Check track segments
583- if ( "tracks" in pcbdata ) {
588+ if ( renderTracks && pcbdata . tracks ) {
584589 for ( var track of pcbdata . tracks [ layer ] ) {
585590 if ( pointWithinDistanceToSegment ( x , y , ...track . start , ...track . end , track . width / 2 ) ) {
586591 return track . net ;
587592 }
588593 }
589594 }
590595 // Check pads
591- for ( var mod of pcbdata . modules ) {
592- for ( var pad of mod . pads ) {
593- if ( pad . layers . includes ( layer ) && pointWithinPad ( x , y , pad ) ) {
594- return pad . net ;
596+ if ( renderPads ) {
597+ for ( var mod of pcbdata . modules ) {
598+ for ( var pad of mod . pads ) {
599+ if ( pad . layers . includes ( layer ) && pointWithinPad ( x , y , pad ) ) {
600+ return pad . net ;
601+ }
595602 }
596603 }
597604 }
0 commit comments