@@ -4,7 +4,7 @@ import { ImageManager } from './image-manager';
44import { Layer , LayerHitTestContext , LayerPreloadContext , LayerRenderContext } from './layer' ;
55import { TyriaMapOptions } from './options' ;
66import { RenderQueue , RenderQueuePriority , RenderReason } from './render-queue' ;
7- import { Bounds , Point , View , ViewOptions } from './types' ;
7+ import { Bounds , Padding , Point , View , ViewOptions } from './types' ;
88import { add , clamp , easeInOutCubic , getPadding , multiply , subtract } from './util' ;
99
1010export class Tyria extends TyriaEventTarget {
@@ -13,7 +13,8 @@ export class Tyria extends TyriaEventTarget {
1313
1414 view : Readonly < View > = {
1515 center : [ 0 , 0 ] ,
16- zoom : 1
16+ zoom : 1 ,
17+ padding : { top : 0 , right : 0 , bottom : 0 , left : 0 } ,
1718 }
1819 layers : { id : number , layer : Layer } [ ] = [ ] ;
1920 debug = false
@@ -116,9 +117,11 @@ export class Tyria extends TyriaEventTarget {
116117 const dpr = window . devicePixelRatio || 1 ;
117118 const width = this . canvas . width / dpr ;
118119 const height = this . canvas . height / dpr ;
120+ const padding = this . view . padding ;
121+
119122 const translate = this . project ( this . view . center ) ;
120- const translateX = - translate [ 0 ] + ( width / 2 ) ;
121- const translateY = - translate [ 1 ] + ( height / 2 ) ;
123+ const translateX = - translate [ 0 ] + ( padding . left - padding . right + width ) / 2 ;
124+ const translateY = - translate [ 1 ] + ( padding . top - padding . bottom + height ) / 2 ;
122125
123126 const transform = new DOMMatrix ( [ dpr , 0 , 0 , dpr , translateX * dpr , translateY * dpr ] ) ;
124127
@@ -131,6 +134,7 @@ export class Tyria extends TyriaEventTarget {
131134 zoom : this . view . zoom ,
132135 width,
133136 height,
137+ padding,
134138 area : this . #getViewportArea( this . view ) ,
135139 dpr,
136140 debug : this . debug ,
@@ -197,35 +201,35 @@ export class Tyria extends TyriaEventTarget {
197201 ctx . resetTransform ( ) ;
198202
199203 // render padding
200- if ( this . options . padding && this . debugLastViewOptions ?. contain ) {
201- ctx . fillStyle = '#673AB788' ;
202- ctx . strokeStyle = '#673AB7' ;
203- ctx . lineWidth = 2 * dpr ;
204-
205- const padding = getPadding ( this . options . padding ) ;
204+ ctx . fillStyle = '#673AB788' ;
205+ ctx . strokeStyle = '#673AB7' ;
206+ ctx . lineWidth = 2 * dpr ;
206207
207- if ( padding . top ) {
208- ctx . fillRect ( padding . left * dpr , 0 , ( width - padding . left - padding . right ) * dpr , padding . top * dpr ) ;
209- }
210- if ( padding . bottom ) {
211- ctx . fillRect ( padding . left * dpr , ( height - padding . bottom ) * dpr , ( width - padding . left - padding . right ) * dpr , height * dpr ) ;
212- }
213- if ( padding . left ) {
214- ctx . fillRect ( 0 , 0 , padding . left * dpr , height * dpr ) ;
215- }
216- if ( padding . right ) {
217- ctx . fillRect ( ( width - padding . right ) * dpr , 0 , padding . right * dpr , height * dpr ) ;
218- }
219- ctx . strokeRect ( padding . left * dpr , padding . top * dpr , ( width - padding . left - padding . right ) * dpr , ( height - padding . top - padding . bottom ) * dpr ) ;
208+ if ( padding . top ) {
209+ ctx . fillRect ( padding . left * dpr , 0 , ( width - padding . left - padding . right ) * dpr , padding . top * dpr ) ;
210+ }
211+ if ( padding . bottom ) {
212+ ctx . fillRect ( padding . left * dpr , ( height - padding . bottom ) * dpr , ( width - padding . left - padding . right ) * dpr , height * dpr ) ;
213+ }
214+ if ( padding . left ) {
215+ ctx . fillRect ( 0 , 0 , padding . left * dpr , height * dpr ) ;
220216 }
217+ if ( padding . right ) {
218+ ctx . fillRect ( ( width - padding . right ) * dpr , 0 , padding . right * dpr , height * dpr ) ;
219+ }
220+ ctx . strokeRect ( padding . left * dpr , padding . top * dpr , ( width - padding . left - padding . right ) * dpr , ( height - padding . top - padding . bottom ) * dpr ) ;
221221
222222 // render map center
223- ctx . setTransform ( dpr , 0 , 0 , dpr , dpr * width / 2 , dpr * height / 2 ) ;
223+ ctx . setTransform ( dpr , 0 , 0 , dpr , dpr * ( padding . left - padding . right + width ) / 2 , dpr * ( padding . top - padding . bottom + height ) / 2 ) ;
224224 ctx . fillStyle = 'lime' ;
225225 ctx . fillRect ( - 4 , - 4 , 8 , 8 ) ;
226226 ctx . font = '12px monospace' ;
227227 ctx . textAlign = 'left' ;
228228 ctx . textBaseline = 'top' ;
229+ ctx . fillStyle = '#000' ;
230+ ctx . fillText ( `px ${ translate [ 0 ] } , ${ translate [ 1 ] } ` , 8 + 1 , 0 + 1 ) ;
231+ ctx . fillText ( `map ${ this . view . center [ 0 ] } , ${ this . view . center [ 1 ] } ` , 8 + 1 , 16 + 1 ) ;
232+ ctx . fillText ( `zoom ${ this . view . zoom } ` , 8 + 1 , 32 + 1 ) ;
229233 ctx . fillStyle = '#fff' ;
230234 ctx . fillText ( `px ${ translate [ 0 ] } , ${ translate [ 1 ] } ` , 8 , 0 ) ;
231235 ctx . fillText ( `map ${ this . view . center [ 0 ] } , ${ this . view . center [ 1 ] } ` , 8 , 16 ) ;
@@ -264,6 +268,9 @@ export class Tyria extends TyriaEventTarget {
264268 // get dpr to correctly calculate viewport size
265269 const dpr = window . devicePixelRatio ?? 1 ;
266270
271+ // get padding
272+ const padding = getPadding ( view . padding ?? this . options . padding ) ;
273+
267274 // make sure the area is completely visible in the viewport
268275 // TODO: handle passing contain + center?
269276 if ( view . contain ) {
@@ -272,7 +279,6 @@ export class Tyria extends TyriaEventTarget {
272279 const aspectRatio = size [ 0 ] / size [ 1 ] ;
273280
274281 // get size and aspect ratio of the viewport
275- const padding = getPadding ( this . options . padding ) ;
276282 const viewportSizePx = [
277283 ( this . canvas . width / dpr ) - padding . left - padding . right ,
278284 ( this . canvas . height / dpr ) - padding . top - padding . bottom ,
@@ -293,7 +299,6 @@ export class Tyria extends TyriaEventTarget {
293299 }
294300
295301 // set center to the middle of the area
296- // TODO: adjust for asymmetric padding
297302 center = add ( view . contain [ 0 ] , multiply ( size , 0.5 ) ) ;
298303
299304 // make sure we are zooming out when zoom snapping
@@ -353,17 +358,21 @@ export class Tyria extends TyriaEventTarget {
353358 center = this . unproject ( centerPx , zoom ) ;
354359 }
355360
356- return { center, zoom } ;
361+ return { center, zoom, padding } ;
357362 }
358363
359364 /** Gets the area visible in the viewport */
360- #getViewportArea( view : View ) : Bounds {
365+ #getViewportArea( view : Readonly < View > ) : Bounds {
361366 const dpr = window . devicePixelRatio ?? 1 ;
362- const viewportHalfSizePx : Point = [ this . canvas . width / dpr / 2 , this . canvas . height / dpr / 2 ] ;
367+ const padding = view . padding ;
368+ const viewportHalfSizePx : Point = [
369+ ( padding . left - padding . right + this . canvas . width / dpr ) / 2 ,
370+ ( padding . top - padding . bottom + this . canvas . height / dpr ) / 2
371+ ] ;
363372 const centerPx = this . project ( view . center ) ;
364373
365- const topLeft = this . unproject ( subtract ( centerPx , viewportHalfSizePx ) ) ;
366- const bottomRight = this . unproject ( add ( centerPx , viewportHalfSizePx ) ) ;
374+ const topLeft = this . unproject ( subtract ( subtract ( centerPx , viewportHalfSizePx ) , 0 ) ) ;
375+ const bottomRight = this . unproject ( add ( add ( centerPx , viewportHalfSizePx ) , [ padding . right - padding . left , padding . bottom - padding . top ] ) ) ;
367376
368377 return [ topLeft , bottomRight ] ;
369378 }
@@ -399,7 +408,7 @@ export class Tyria extends TyriaEventTarget {
399408 const target = this . resolveView ( view ) ;
400409
401410 // if we are not moving, don't move
402- if ( target . zoom === start . zoom && target . center [ 0 ] === start . center [ 0 ] && target . center [ 1 ] === start . center [ 1 ] ) {
411+ if ( target . zoom === start . zoom && target . center [ 0 ] === start . center [ 0 ] && target . center [ 1 ] === start . center [ 1 ] && target . padding . top === start . padding . top && target . padding . right === start . padding . right && target . padding . bottom === start . padding . bottom && target . padding . left === start . padding . left ) {
403412 return ;
404413 }
405414
@@ -409,10 +418,10 @@ export class Tyria extends TyriaEventTarget {
409418 const startArea = this . #getViewportArea( start ) ;
410419 const targetArea = this . #getViewportArea( target ) ;
411420 const combinedArea : Bounds = [
412- [ Math . min ( startArea [ 0 ] [ 0 ] , targetArea [ 0 ] [ 0 ] ) , Math . min ( startArea [ 0 ] [ 1 ] , targetArea [ 0 ] [ 1 ] ) ] as Point ,
413- [ Math . max ( startArea [ 1 ] [ 0 ] , targetArea [ 1 ] [ 0 ] ) , Math . max ( startArea [ 1 ] [ 1 ] , targetArea [ 1 ] [ 1 ] ) ] as Point
421+ [ Math . min ( startArea [ 0 ] [ 0 ] , targetArea [ 0 ] [ 0 ] ) , Math . min ( startArea [ 0 ] [ 1 ] , targetArea [ 0 ] [ 1 ] ) ] ,
422+ [ Math . max ( startArea [ 1 ] [ 0 ] , targetArea [ 1 ] [ 0 ] ) , Math . max ( startArea [ 1 ] [ 1 ] , targetArea [ 1 ] [ 1 ] ) ]
414423 ] ;
415- this . preload ( this . resolveView ( { contain : combinedArea } ) ) ;
424+ this . preload ( { contain : combinedArea , padding : 0 } ) ;
416425
417426 // calculate delta
418427 const deltaZoom = target . zoom - start . zoom ;
@@ -439,8 +448,16 @@ export class Tyria extends TyriaEventTarget {
439448 // calculate center
440449 const center = add ( start . center , multiply ( deltaCenter , easedProgress * speedup ) ) ;
441450
451+ // calculate padding
452+ const padding : Padding = {
453+ top : start . padding . top + ( target . padding . top - start . padding . top ) * easedProgress ,
454+ right : start . padding . right + ( target . padding . right - start . padding . right ) * easedProgress ,
455+ bottom : start . padding . bottom + ( target . padding . bottom - start . padding . bottom ) * easedProgress ,
456+ left : start . padding . left + ( target . padding . left - start . padding . left ) * easedProgress ,
457+ }
458+
442459 // set view to the calculated center and zoom
443- this . view = { center, zoom } ;
460+ this . view = { center, zoom, padding } ;
444461
445462 if ( progress === 1 ) {
446463 performance . mark ( 'easeTo-end' ) ;
@@ -452,6 +469,7 @@ export class Tyria extends TyriaEventTarget {
452469
453470 if ( duration === 0 ) {
454471 // if the duration of the transition is 0 we just call the end frame
472+ // TODO: why not just call `jumpTo(view)` at the start?
455473 frame ( 1 ) ;
456474 } else {
457475 // store current ease and queue frame
@@ -498,22 +516,26 @@ export class Tyria extends TyriaEventTarget {
498516 /** Convert a pixel in the canvas (for example offsetX/offsetY from an event) to the corresponding map coordinates at that point */
499517 canvasPixelToMapCoordinate ( [ x , y ] : Point ) {
500518 const dpr = window . devicePixelRatio || 1 ;
519+ const padding = this . view . padding ;
501520
502- const halfWidth = this . canvas . width / dpr / 2 ;
503- const halfHeight = this . canvas . height / dpr / 2 ;
521+ const viewportHalfSizePx : Point = [
522+ ( padding . left - padding . right + this . canvas . width ) / dpr / 2 ,
523+ ( padding . top - padding . bottom + this . canvas . height ) / dpr / 2
524+ ] ;
504525
505- const offset : Point = this . unproject ( [ - x + halfWidth , - y + halfHeight ] ) ;
526+ const offset : Point = this . unproject ( [ - x + viewportHalfSizePx [ 0 ] , - y + viewportHalfSizePx [ 1 ] ] ) ;
506527
507528 return subtract ( this . view . center , offset ) ;
508529 }
509530
510531 /** Convert a map coordinate to canvas px */
511532 mapCoordinateToCanvasPixel ( coordinate : Point ) {
512533 const dpr = window . devicePixelRatio || 1 ;
534+ const padding = this . view . padding ;
513535
514536 const viewportHalfSizePx : Point = [
515- this . canvas . width / dpr / 2 ,
516- this . canvas . height / dpr / 2
537+ ( padding . left - padding . right + this . canvas . width ) / dpr / 2 ,
538+ ( padding . top - padding . bottom + this . canvas . height ) / dpr / 2
517539 ] ;
518540
519541 const pointPx = this . project ( coordinate ) ;
@@ -543,6 +565,7 @@ export class Tyria extends TyriaEventTarget {
543565 zoom : target . zoom ,
544566 width : this . canvas . width / dpr ,
545567 height : this . canvas . height / dpr ,
568+ padding : target . padding ,
546569 area : this . #getViewportArea( target ) ,
547570 dpr : dpr ,
548571 debug : this . debug ,
@@ -612,6 +635,7 @@ export class Tyria extends TyriaEventTarget {
612635 zoom : this . view . zoom ,
613636 width,
614637 height,
638+ padding : this . view . padding ,
615639 area : this . #getViewportArea( this . view ) ,
616640 dpr,
617641 debug : this . debug ,
0 commit comments