@@ -23,16 +23,58 @@ function DisplayCanvas() {
2323 _ext = extent ;
2424 } ;
2525
26+ /*
27+ // Original function, not optimized
2628 _self.drawPathShapes = function(shapes, arcs, style) {
27- var start = getPathStart ( style , _ext ) ,
28- draw = getShapePencil ( arcs , _ext ) ,
29- end = getPathEnd ( style ) ;
29+ var startPath = getPathStart(_ext),
30+ drawPath = getShapePencil(arcs, _ext),
31+ styler = style.styler || null ;
3032 for (var i=0, n=shapes.length; i<n; i++) {
31- start ( _ctx , i ) ;
32- draw ( shapes [ i ] , _ctx ) ;
33- end ( _ctx ) ;
33+ if (styler) styler(style, i);
34+ startPath(_ctx, style);
35+ drawPath(shapes[i], _ctx);
36+ endPath(_ctx, style);
3437 }
3538 };
39+ */
40+
41+ // Optimized to draw paths in same-style batches (faster Canvas drawing)
42+ _self . drawPathShapes = function ( shapes , arcs , style ) {
43+ var styleIndex = { } ;
44+ var batchSize = 1500 ;
45+ var startPath = getPathStart ( _ext ) ;
46+ var drawPath = getShapePencil ( arcs , _ext ) ;
47+ var key , item ;
48+ var styler = style . styler || null ;
49+ for ( var i = 0 ; i < shapes . length ; i ++ ) {
50+ if ( styler ) styler ( style , i ) ;
51+ key = getStyleKey ( style ) ;
52+ if ( key in styleIndex === false ) {
53+ styleIndex [ key ] = {
54+ style : utils . defaults ( { } , style ) ,
55+ shapes : [ ]
56+ } ;
57+ }
58+ item = styleIndex [ key ] ;
59+ item . shapes . push ( shapes [ i ] ) ;
60+ if ( item . shapes . length >= batchSize ) {
61+ drawPaths ( item . shapes , startPath , drawPath , item . style ) ;
62+ item . shapes = [ ] ;
63+ }
64+ }
65+ Object . keys ( styleIndex ) . forEach ( function ( key ) {
66+ var item = styleIndex [ key ] ;
67+ drawPaths ( item . shapes , startPath , drawPath , item . style ) ;
68+ } ) ;
69+ } ;
70+
71+ function drawPaths ( shapes , startPath , drawPath , style ) {
72+ startPath ( _ctx , style ) ;
73+ for ( var i = 0 , n = shapes . length ; i < n ; i ++ ) {
74+ drawPath ( shapes [ i ] , _ctx ) ;
75+ }
76+ endPath ( _ctx , style ) ;
77+ }
3678
3779 _self . drawSquareDots = function ( shapes , style ) {
3880 var t = getScaledTransform ( _ext ) ,
@@ -59,69 +101,50 @@ function DisplayCanvas() {
59101 }
60102 } ;
61103
104+ // TODO: consider using drawPathShapes(), which draws paths in batches
105+ // for faster Canvas rendering. Downside: changes stacking order, which
106+ // is bad if circles are graduated.
62107 _self . drawPoints = function ( shapes , style ) {
63108 var t = getScaledTransform ( _ext ) ,
64109 pixRatio = gui . getPixelRatio ( ) ,
65- start = getPathStart ( style , _ext ) ,
66- end = getPathEnd ( style ) ,
110+ startPath = getPathStart ( _ext ) ,
111+ styler = style . styler || null ,
67112 shp , p ;
68113
69114 for ( var i = 0 , n = shapes . length ; i < n ; i ++ ) {
70115 shp = shapes [ i ] ;
71- start ( _ctx , i ) ;
116+ if ( styler ) styler ( style , i ) ;
117+ startPath ( _ctx , style ) ;
72118 if ( ! shp || style . radius > 0 === false ) continue ;
73119 for ( var j = 0 , m = shp ? shp . length : 0 ; j < m ; j ++ ) {
74120 p = shp [ j ] ;
75121 drawCircle ( p [ 0 ] * t . mx + t . bx , p [ 1 ] * t . my + t . by , style . radius * pixRatio , _ctx ) ;
76122 }
77- end ( _ctx ) ;
123+ endPath ( _ctx , style ) ;
78124 }
79125 } ;
80126
81- _self . drawArcs = function ( arcs , flags , style ) {
82- var darkStyle = { strokeWidth : style . strokeWidth , strokeColor : style . strokeColors [ 1 ] } ,
83- lightStyle = { strokeWidth : style . strokeWidth , strokeColor : style . strokeColors [ 0 ] } ;
84- setArcVisibility ( flags , arcs ) ;
85- // TODO: don't show light arcs if reference layer is visible
86- if ( lightStyle . strokeColor ) {
87- drawFlaggedArcs ( 2 , flags , lightStyle , arcs ) ;
88- }
89- drawFlaggedArcs ( 3 , flags , darkStyle , arcs ) ;
90- } ;
91-
92- function setArcVisibility ( flags , arcs ) {
93- var minPathLen = 0.5 * _ext . getPixelSize ( ) ,
94- geoBounds = _ext . getBounds ( ) ,
95- geoBBox = geoBounds . toArray ( ) ,
96- allIn = geoBounds . contains ( arcs . getBounds ( ) ) ,
97- visible ;
98- // don't continue dropping paths if user zooms out farther than full extent
99- if ( _ext . scale ( ) < 1 ) minPathLen *= _ext . scale ( ) ;
100- for ( var i = 0 , n = arcs . size ( ) ; i < n ; i ++ ) {
101- visible = ! arcs . arcIsSmaller ( i , minPathLen ) && ( allIn ||
102- arcs . arcIntersectsBBox ( i , geoBBox ) ) ;
103- // mark visible arcs by setting second flag bit to 1
104- flags [ i ] = ( flags [ i ] & 1 ) | ( visible ? 2 : 0 ) ;
105- }
106- }
107-
108- function drawFlaggedArcs ( flag , flags , style , arcs ) {
109- var start = getPathStart ( style , _ext ) ,
110- end = getPathEnd ( style ) ,
127+ _self . drawArcs = function ( arcs , style , filter ) {
128+ var startPath = getPathStart ( _ext ) ,
111129 t = getScaledTransform ( _ext ) ,
112130 ctx = _ctx ,
113131 n = 25 , // render paths in batches of this size (an optimization)
114132 count = 0 ;
115- start ( ctx ) ;
133+ startPath ( ctx , style ) ;
116134 for ( i = 0 , n = arcs . size ( ) ; i < n ; i ++ ) {
117- if ( flags [ i ] != flag ) continue ;
135+ if ( filter && ! filter ( i ) ) continue ;
118136 if ( ++ count % n === 0 ) {
119- end ( ctx ) ;
120- start ( ctx ) ;
137+ endPath ( ctx , style ) ;
138+ startPath ( ctx , style ) ;
121139 }
122- drawPath ( arcs . getArcIter ( i ) , t , ctx ) ;
140+ drawPath ( arcs . getArcIter ( i ) , t , ctx , 0.6 ) ;
123141 }
124- end ( ctx ) ;
142+ endPath ( ctx , style ) ;
143+ } ;
144+
145+ function getStyleKey ( style ) {
146+ return ( style . strokeWidth > 0 ? style . strokeColor + '~' + style . strokeWidth +
147+ '~' : '' ) + ( style . fillColor || '' ) + ( style . opacity < 1 ? '~' + style . opacity : '' ) ;
125148 }
126149
127150 return _self ;
@@ -147,10 +170,10 @@ function drawSquare(x, y, size, ctx) {
147170 }
148171}
149172
150- function drawPath ( vec , t , ctx ) {
151- var minLen = gui . getPixelRatio ( ) > 1 ? 1 : 0.6 ,
152- x , y , xp , yp ;
173+ function drawPath ( vec , t , ctx , minLen ) {
174+ var x , y , xp , yp ;
153175 if ( ! vec . hasNext ( ) ) return ;
176+ minLen = minLen >= 0 ? minLen : 0.4 ;
154177 x = xp = vec . x * t . mx + t . bx ;
155178 y = yp = vec . y * t . my + t . by ;
156179 ctx . moveTo ( x , y ) ;
@@ -163,19 +186,16 @@ function drawPath(vec, t, ctx) {
163186 yp = y ;
164187 }
165188 }
166- if ( x != xp || y != yp ) {
167- ctx . lineTo ( x , y ) ;
168- }
169189}
170190
171191function getShapePencil ( arcs , ext ) {
172192 var t = getScaledTransform ( ext ) ;
193+ var iter = new internal . ShapeIter ( arcs ) ;
173194 return function ( shp , ctx ) {
174- var iter = new internal . ShapeIter ( arcs ) ;
175- if ( ! shp ) return ;
176- for ( var i = 0 ; i < shp . length ; i ++ ) {
195+ for ( var i = 0 , n = shp ? shp . length : 0 ; i < n ; i ++ ) {
177196 iter . init ( shp [ i ] ) ;
178- drawPath ( iter , t , ctx ) ;
197+ // 0.2 trades visible seams for performance
198+ drawPath ( iter , t , ctx , 0.2 ) ;
179199 }
180200 } ;
181201}
@@ -198,17 +218,13 @@ function getDotScale(ext) {
198218 return Math . pow ( getLineScale ( ext ) , 0.6 ) ;
199219}
200220
201- function getPathStart ( style , ext ) {
202- var styler = style . styler || null ,
203- pixRatio = gui . getPixelRatio ( ) ,
221+ function getPathStart ( ext ) {
222+ var pixRatio = gui . getPixelRatio ( ) ,
204223 lineScale = getLineScale ( ext ) ;
205224
206- return function ( ctx , i ) {
225+ return function ( ctx , style ) {
207226 var strokeWidth ;
208227 ctx . beginPath ( ) ;
209- if ( styler ) {
210- styler ( style , i ) ;
211- }
212228 if ( style . opacity >= 0 ) {
213229 ctx . globalAlpha = style . opacity ;
214230 }
@@ -229,11 +245,9 @@ function getPathStart(style, ext) {
229245 } ;
230246}
231247
232- function getPathEnd ( style ) {
233- return function ( ctx ) {
234- if ( style . fillColor ) ctx . fill ( ) ;
235- if ( style . strokeWidth > 0 ) ctx . stroke ( ) ;
236- if ( style . opacity >= 0 ) ctx . globalAlpha = 1 ;
237- ctx . closePath ( ) ;
238- } ;
248+ function endPath ( ctx , style ) {
249+ if ( style . fillColor ) ctx . fill ( ) ;
250+ if ( style . strokeWidth > 0 ) ctx . stroke ( ) ;
251+ if ( style . opacity >= 0 ) ctx . globalAlpha = 1 ;
252+ ctx . closePath ( ) ;
239253}
0 commit comments