@mappedin/mappedin-js 5.34.2 → 5.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ import{b as a}from"./chunk-ZRT45YCM.js";var e,c=a((()=>{e={env:{NODE_ENV:"production",npm_package_version:"5.35.0"}}}));export{c as a,e as b};
@@ -1044,7 +1044,7 @@ declare module '@mappedin/mappedin-js/renderer/internal/Mappedin.BlueDot/Mappedi
1044
1044
  map: MappedinMap | null;
1045
1045
  bearing: any;
1046
1046
  nearestNode: any;
1047
- forceBlueDot: boolean;
1047
+ hasEverReceivedFloorLevel: boolean;
1048
1048
  };
1049
1049
  export interface IBlueDotCore extends IPubSub {
1050
1050
  positionUpdater: IPositionUpdater | null;
@@ -1060,6 +1060,8 @@ declare module '@mappedin/mappedin-js/renderer/internal/Mappedin.BlueDot/Mappedi
1060
1060
  Whether blue dot should be allowed with missing floor level information.
1061
1061
  */
1062
1062
  forceBlueDot: boolean;
1063
+ /** Whether we have received floorLevel data and are on a floorLevel supported device */
1064
+ hasEverReceivedFloorLevel: boolean;
1063
1065
  /**
1064
1066
  The state machine for the current state of the blue dot.
1065
1067
  */
@@ -2357,6 +2359,23 @@ declare module '@mappedin/mappedin-js/renderer/MapView.types' {
2357
2359
  export type { TOutdoorViewOptions, TOutdoorViewOptionsWithHeaders, TOutdoorViewOptionsWithAuthURL };
2358
2360
  export type { default as BlueDotController } from '@mappedin/mappedin-js/renderer/private/controllers/BlueDotController';
2359
2361
  export type { default as Journey } from '@mappedin/mappedin-js/renderer/public/api/Journey';
2362
+ export type TStackedMapsOptions = {
2363
+ /**
2364
+ * The vertical distance between maps in overview, in metres.
2365
+ * @default 50
2366
+ */
2367
+ verticalDistanceBetweenMaps?: number;
2368
+ /**
2369
+ * Whether to show map level labels in overview.
2370
+ * @default true
2371
+ */
2372
+ mapLabels?: boolean;
2373
+ /**
2374
+ * Whether to show only Journey maps in the stack if a Journey is active and the current map is part of the Journey.
2375
+ * @default true
2376
+ */
2377
+ prioritizeJourneyMaps?: boolean;
2378
+ };
2360
2379
  }
2361
2380
 
2362
2381
  declare module '@mappedin/mappedin-js/common/Mappedin.Logger' {
@@ -3420,8 +3439,8 @@ declare module '@mappedin/mappedin-js/renderer/public/api/Paths' {
3420
3439
 
3421
3440
  declare module '@mappedin/mappedin-js/renderer/public/api/StackedMaps' {
3422
3441
  import { MappedinMap } from '@mappedin/mappedin-js/get-venue';
3442
+ import { TStackedMapsOptions } from '@mappedin/mappedin-js/renderer/MapView.types';
3423
3443
  import { STACKED_MAPS_STATE, StackedMapsController, TCameraTransform } from '@mappedin/mappedin-js/renderer/internal';
3424
- import { TStackedMapsOptions } from '@mappedin/mappedin-js/renderer/private/controllers/StackedMapsController';
3425
3444
  /**
3426
3445
  * @experimental
3427
3446
  * API for showing multiple maps involved in a {@link Journey} as a vertical stack.
@@ -3434,7 +3453,8 @@ declare module '@mappedin/mappedin-js/renderer/public/api/StackedMaps' {
3434
3453
  constructor(markersController: StackedMapsController);
3435
3454
  /**
3436
3455
  * @experimental
3437
- * Enable Stacked Maps. A {@link Journey} must be drawn beforehand or this method will fail.
3456
+ * Enable Stacked Maps. If a {@link Journey} is drawn beforehand the default behaviour is to only display the floors that are part of the journey.
3457
+ * {@link TStackedMapsOptions} can be used to enabling display of all maps including those that are not part of the journey.
3438
3458
  * Use {@link showOverview} to expand the maps vertically after enabling.
3439
3459
  *
3440
3460
  * Upon enabling, map state will become {@link STATE.STACKED | STACKED} and Stacked Maps state will become {@link STACKED_MAPS_STATE.ACTIVE | ACTIVE}.
@@ -3472,7 +3492,7 @@ declare module '@mappedin/mappedin-js/renderer/public/api/StackedMaps' {
3472
3492
  /**
3473
3493
  * @experimental
3474
3494
  *
3475
- * Expand the maps in the current {@link Journey} vertically and add vertical paths between connections.
3495
+ * Expand and display all maps in the current {@link MapGroup}. If a {@link Journey} has been drawn, vertical paths between connections are displayed.
3476
3496
  * Stacked Maps must be enabled beforehand and state will become {@link STACKED_MAPS_STATE.OVERVIEW | OVERVIEW}.
3477
3497
  *
3478
3498
  * @example
@@ -3527,7 +3547,8 @@ declare module '@mappedin/mappedin-js/renderer/public/api/StackedMaps' {
3527
3547
  * @experimental
3528
3548
  *
3529
3549
  * Used when in {@link STACKED_MAPS_STATE.OVERVIEW | OVERVIEW} state to replace the maps in the
3530
- * current stack if there is a new Journey or Journey is cleared.
3550
+ * current stack after clearing or creating a {@link Journey}.
3551
+ * Use this to hide maps that are not part of the journey or to display all maps in the {@link MapGroup}.
3531
3552
  *
3532
3553
  * @param options - Options to adjust the overview. Each option defaults to the setting passed in {@link enable}, unless provided.
3533
3554
  *
@@ -4150,21 +4171,64 @@ declare module '@mappedin/mappedin-js/renderer/private/controllers/WatermarkCont
4150
4171
  import { Sprite } from 'three';
4151
4172
  type TPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'center' | 'top' | 'bottom' | 'left' | 'right';
4152
4173
  export type TShowWatermarkOptions = {
4153
- padding?: number;
4154
- position?: TPosition;
4155
- iconOnly?: boolean;
4156
- scale?: number;
4157
- onClick?: () => void;
4174
+ /**
4175
+ * Padding in pixels. Can be a number or an object with top, right, bottom, and left properties.
4176
+ * @default 16
4177
+ * @example
4178
+ * ```ts
4179
+ * // Watermark with 20 pixels of padding on all sides
4180
+ * __showWatermark({
4181
+ * padding: 20,
4182
+ * });
4183
+ * ```
4184
+ * @example
4185
+ * ```ts
4186
+ * // Watermark with unique top, right, bottom, left padding
4187
+ * __showWatermark({
4188
+ * padding: {
4189
+ * top: 10,
4190
+ * right: 20,
4191
+ * bottom: 30,
4192
+ * left: 40,
4193
+ * },
4194
+ * });
4195
+ * ```
4196
+ */
4197
+ padding?: number | {
4198
+ top?: number;
4199
+ right?: number;
4200
+ bottom?: number;
4201
+ left?: number;
4202
+ };
4203
+ /**
4204
+ * Position of the watermark on the screen.
4205
+ * @default 'bottom-left'
4206
+ */
4207
+ position?: TPosition;
4208
+ /**
4209
+ * Show only the Mappedin icon without text.
4210
+ * @default false
4211
+ */
4212
+ iconOnly?: boolean;
4213
+ /**
4214
+ * Scale of the watermark between 0.5 and 1.5.
4215
+ * @default 1
4216
+ */
4217
+ scale?: number;
4218
+ /**
4219
+ * Callback when the watermark is clicked.
4220
+ */
4221
+ onClick?: () => void;
4158
4222
  };
4159
4223
  class WatermarkController {
4160
- #private;
4161
- static ENABLED: boolean;
4162
- static OPTIONS: Required<TShowWatermarkOptions>;
4163
- object?: Sprite;
4164
- constructor(core: ICore);
4165
- show: () => void;
4166
- hide: () => void;
4167
- resize: () => void;
4224
+ #private;
4225
+ static ENABLED: boolean;
4226
+ static OPTIONS: Required<TShowWatermarkOptions>;
4227
+ object?: Sprite;
4228
+ constructor(core: ICore);
4229
+ show: () => void;
4230
+ hide: () => void;
4231
+ resize: () => void;
4168
4232
  }
4169
4233
  export default WatermarkController;
4170
4234
  }
@@ -6186,13 +6250,49 @@ declare module '@mappedin/mappedin-js/renderer/internal/Mappedin.FloatingLabel'
6186
6250
  inactive?: string;
6187
6251
  };
6188
6252
  /**
6189
- * Size of bounding box of SVG icon
6253
+ * Size of bounding box of the icon
6254
+ * @default 10
6190
6255
  */
6191
6256
  iconSize?: number;
6192
6257
  /**
6193
- * SVG of icon to place inside Floating Label
6258
+ * Icon to be placed inside the Floating Label marker. Supports SVG or a URL to png or jpeg.
6259
+ * @example
6260
+ * ```ts
6261
+ * // SVG
6262
+ * mapView.FloatingLabels.add(polygon, "Label", {
6263
+ * appearance: {
6264
+ * marker: {
6265
+ * icon: `<svg>...</svg>`,
6266
+ * },
6267
+ * },
6268
+ * });
6269
+ * ```
6270
+ *
6271
+ * @example
6272
+ * ```ts
6273
+ * // Image URL
6274
+ * mapView.FloatingLabels.add(polygon, "Label", {
6275
+ * appearance: {
6276
+ * marker: {
6277
+ * icon: 'https://example.com/icon.png',
6278
+ * },
6279
+ * },
6280
+ * });
6281
+ * ```
6194
6282
  */
6195
6283
  icon?: string;
6284
+ /**
6285
+ * How the icon should fit inside the marker. By default, this is not set and the icon will be centered inside the marker.
6286
+ * - `fill` will stretch the icon to fill the marker.
6287
+ * - `cover` will maintain aspect ratio and fill the marker.
6288
+ * - `contain` will maintain aspect ratio and fit the icon inside the marker.
6289
+ */
6290
+ iconFit?: 'contain' | 'fill' | 'cover';
6291
+ /**
6292
+ * Padding around the icon, in pixels.
6293
+ * @default 4
6294
+ */
6295
+ iconPadding?: number;
6196
6296
  /**
6197
6297
  * Defines when the icon becomes visible relative to the current zoom level
6198
6298
  * anything below 0 will result in icons never showing up
@@ -6224,6 +6324,8 @@ declare module '@mappedin/mappedin-js/renderer/internal/Mappedin.FloatingLabel'
6224
6324
  };
6225
6325
  iconSize?: number;
6226
6326
  icon?: string;
6327
+ iconFit?: 'fill' | 'cover' | 'contain';
6328
+ iconPadding: number;
6227
6329
  iconVisibilityThreshold?: number;
6228
6330
  };
6229
6331
  };
@@ -6290,6 +6392,12 @@ declare module '@mappedin/mappedin-js/renderer/internal/Mappedin.FloatingLabel'
6290
6392
  static imagePromiseCache: {
6291
6393
  [key in number]?: Promise<HTMLImageElement>;
6292
6394
  };
6395
+ static imageDimensionsCache: {
6396
+ [key in number]: {
6397
+ width: number;
6398
+ height: number;
6399
+ };
6400
+ };
6293
6401
  get pinCanvasSize(): number;
6294
6402
  draw(context: CanvasRenderingContext2D): void;
6295
6403
  }
@@ -6642,150 +6750,6 @@ declare module '@mappedin/mappedin-js/renderer/private/controllers/FlatLabelsCon
6642
6750
  export default FlatLabelsController;
6643
6751
  }
6644
6752
 
6645
- declare module '@mappedin/mappedin-js/renderer/private/controllers/StackedMapsController' {
6646
- import { MappedinDirections, MappedinMap, MappedinNode } from '@mappedin/mappedin-js/get-venue';
6647
- import { STACKED_MAPS_STATE, MapViewScene, MapViewStackScene, CAMERA_EASING_MODE } from '@mappedin/mappedin-js/renderer/internal';
6648
- import type { ICore, TCameraTransform } from '@mappedin/mappedin-js/renderer/internal';
6649
- enum ACTION {
6650
- enable = "enable",
6651
- disable = "disable",
6652
- showOverview = "showOverview",
6653
- zoomInToMap = "zoomInToMap",
6654
- scrollToMap = "scrollToMap",
6655
- restack = "restack"
6656
- }
6657
- type TTargetTransitionFunction = ((options: TParams) => () => Promise<void>) | ((options: TParams) => void);
6658
- type TParams = {
6659
- map: MappedinMap;
6660
- } | {
6661
- directions: MappedinDirections | MappedinDirections[];
6662
- } | {
6663
- stackScene: MapViewStackScene;
6664
- directions: MappedinDirections | MappedinDirections[];
6665
- verticalDistanceBetweenMaps?: number;
6666
- } | {
6667
- stackScene: MapViewStackScene;
6668
- verticalDistanceBetweenMaps?: number;
6669
- map: MappedinMap;
6670
- nodes: MappedinNode[];
6671
- } | {
6672
- stackScene: MapViewStackScene;
6673
- map: MappedinMap;
6674
- nodes: MappedinNode[];
6675
- rotation: number;
6676
- cameraTransform?: TCameraTransform;
6677
- verticalDistanceBetweenMaps?: number;
6678
- };
6679
- type TActionFn = [STACKED_MAPS_STATE, TTargetTransitionFunction[]];
6680
- type TState = {
6681
- [stateName in STACKED_MAPS_STATE]?: {
6682
- actions: {
6683
- [actionName in ACTION]?: TActionFn;
6684
- };
6685
- };
6686
- };
6687
- export type TInternalTransitionOptions = {
6688
- animate?: boolean;
6689
- };
6690
- export type TStackedMapsOptions = {
6691
- /**
6692
- * The vertical distance between maps in overview, in metres.
6693
- * @default 50
6694
- */
6695
- verticalDistanceBetweenMaps?: number;
6696
- /**
6697
- * Whether to show map level labels in overview.
6698
- * @default true
6699
- */
6700
- mapLabels?: boolean;
6701
- /**
6702
- * Whether to show only Journey maps in the stack if a Journey is active and the current map is part of the Journey.
6703
- * @default true
6704
- */
6705
- prioritizeJourneyMaps?: boolean;
6706
- };
6707
- class StackedMapsController {
6708
- #private;
6709
- options: TStackedMapsOptions;
6710
- enabled: boolean;
6711
- stackScene: MapViewStackScene;
6712
- constructor(core: ICore);
6713
- needsUpdate: boolean;
6714
- currentState: STACKED_MAPS_STATE;
6715
- mapsInStack: MappedinMap[];
6716
- getZoomIntoMapOptions: (params: TParams) => (MapViewScene | {
6717
- activeMap: MappedinMap;
6718
- focusOn: {
6719
- targets: {
6720
- nodes: MappedinNode[];
6721
- };
6722
- options: {
6723
- zoom?: number | undefined;
6724
- tilt: number;
6725
- rotation: number;
6726
- position?: MappedinNode | import("../../internal").MappedinCoordinate | undefined;
6727
- easing: CAMERA_EASING_MODE;
6728
- };
6729
- };
6730
- })[] | undefined;
6731
- getDisableOptions: (params: TParams) => (MapViewScene | {
6732
- activeMap: MappedinMap;
6733
- })[] | undefined;
6734
- getShowOverviewOptions: (params: TParams) => (MapViewStackScene | {
6735
- activeMap: MappedinMap;
6736
- focusOn: {
6737
- options: {
6738
- tilt: number;
6739
- duration: number;
6740
- };
6741
- };
6742
- verticalDistanceBetweenMaps: number | undefined;
6743
- })[] | undefined;
6744
- getScrollToMapOptions: (params: TParams) => (MapViewStackScene | {
6745
- focusOn: {
6746
- targets: {
6747
- nodes: MappedinNode[];
6748
- };
6749
- options: {
6750
- tilt: number;
6751
- easing: CAMERA_EASING_MODE;
6752
- };
6753
- };
6754
- activeMap: MappedinMap;
6755
- })[] | undefined;
6756
- getRestackOptions: (params: TParams) => (MapViewStackScene | {
6757
- activeMap: MappedinMap;
6758
- focusOn: {
6759
- options: {
6760
- tilt: number;
6761
- duration: number;
6762
- };
6763
- };
6764
- verticalDistanceBetweenMaps: number | undefined;
6765
- })[] | undefined;
6766
- getEnableOptions: () => void;
6767
- getShowOverviewTransition: (options: any, inTransit?: boolean) => () => Promise<void>;
6768
- getZoomInToMapTransition: (options: any) => () => Promise<void>;
6769
- getScrollToMapTransition: (options: any, inTransit?: boolean) => () => Promise<void>;
6770
- getRestackTransition: (options: any, inTransit?: boolean) => () => Promise<void>;
6771
- getDisableTransition: (options: any) => () => Promise<void>;
6772
- getEnableTransition: () => () => void;
6773
- states: TState;
6774
- get determineMapStack(): MappedinMap[];
6775
- transition(currentState: STACKED_MAPS_STATE, actionName: ACTION): TTargetTransitionFunction[] | void;
6776
- exec(transitions: TTargetTransitionFunction[] | void, params: TParams): Promise<void>;
6777
- disable: () => Promise<void>;
6778
- enable: (opts?: TStackedMapsOptions) => Promise<void>;
6779
- get nodesInJourneyOrMap(): any[];
6780
- showOverview: () => Promise<void>;
6781
- scrollToMap: (map: MappedinMap) => Promise<void>;
6782
- restack: (options?: TStackedMapsOptions) => Promise<void>;
6783
- zoomInToMap: (map: MappedinMap, cameraTransform?: TCameraTransform) => Promise<void>;
6784
- get currentMap(): MappedinMap;
6785
- }
6786
- export default StackedMapsController;
6787
- }
6788
-
6789
6753
  declare module '@mappedin/mappedin-js/renderer/internal/outdoor-context/Mappedin.Tile' {
6790
6754
  import { Texture, Mesh, MeshBasicMaterial } from 'three';
6791
6755
  import type { ICore } from '@mappedin/mappedin-js/renderer/internal';
@@ -8992,6 +8956,134 @@ declare module '@mappedin/mappedin-js/renderer/private/controllers/BillboardMana
8992
8956
  export default BillboardManager;
8993
8957
  }
8994
8958
 
8959
+ declare module '@mappedin/mappedin-js/renderer/private/controllers/StackedMapsController' {
8960
+ import { MappedinDirections, MappedinMap, MappedinNode } from '@mappedin/mappedin-js/get-venue';
8961
+ import { STACKED_MAPS_STATE, MapViewScene, MapViewStackScene, CAMERA_EASING_MODE } from '@mappedin/mappedin-js/renderer/internal';
8962
+ import type { ICore, TCameraTransform } from '@mappedin/mappedin-js/renderer/internal';
8963
+ import { TStackedMapsOptions } from '@mappedin/mappedin-js/renderer/MapView.types';
8964
+ enum ACTION {
8965
+ enable = "enable",
8966
+ disable = "disable",
8967
+ showOverview = "showOverview",
8968
+ zoomInToMap = "zoomInToMap",
8969
+ scrollToMap = "scrollToMap",
8970
+ restack = "restack"
8971
+ }
8972
+ type TTargetTransitionFunction = ((options: TParams) => () => Promise<void>) | ((options: TParams) => void);
8973
+ type TParams = {
8974
+ map: MappedinMap;
8975
+ } | {
8976
+ directions: MappedinDirections | MappedinDirections[];
8977
+ } | {
8978
+ stackScene: MapViewStackScene;
8979
+ directions: MappedinDirections | MappedinDirections[];
8980
+ verticalDistanceBetweenMaps?: number;
8981
+ } | {
8982
+ stackScene: MapViewStackScene;
8983
+ verticalDistanceBetweenMaps?: number;
8984
+ map: MappedinMap;
8985
+ nodes: MappedinNode[];
8986
+ } | {
8987
+ stackScene: MapViewStackScene;
8988
+ map: MappedinMap;
8989
+ nodes: MappedinNode[];
8990
+ rotation: number;
8991
+ cameraTransform?: TCameraTransform;
8992
+ verticalDistanceBetweenMaps?: number;
8993
+ };
8994
+ type TActionFn = [STACKED_MAPS_STATE, TTargetTransitionFunction[]];
8995
+ type TState = {
8996
+ [stateName in STACKED_MAPS_STATE]?: {
8997
+ actions: {
8998
+ [actionName in ACTION]?: TActionFn;
8999
+ };
9000
+ };
9001
+ };
9002
+ export type TInternalTransitionOptions = {
9003
+ animate?: boolean;
9004
+ };
9005
+ class StackedMapsController {
9006
+ #private;
9007
+ options: TStackedMapsOptions;
9008
+ enabled: boolean;
9009
+ stackScene: MapViewStackScene;
9010
+ constructor(core: ICore);
9011
+ needsUpdate: boolean;
9012
+ currentState: STACKED_MAPS_STATE;
9013
+ mapsInStack: MappedinMap[];
9014
+ getZoomIntoMapOptions: (params: TParams) => (MapViewScene | {
9015
+ activeMap: MappedinMap;
9016
+ focusOn: {
9017
+ targets: {
9018
+ nodes: MappedinNode[];
9019
+ };
9020
+ options: {
9021
+ zoom?: number | undefined;
9022
+ tilt: number;
9023
+ rotation: number;
9024
+ position?: MappedinNode | import("../../internal").MappedinCoordinate | undefined;
9025
+ easing: CAMERA_EASING_MODE;
9026
+ };
9027
+ };
9028
+ })[] | undefined;
9029
+ getDisableOptions: (params: TParams) => (MapViewScene | {
9030
+ activeMap: MappedinMap;
9031
+ })[] | undefined;
9032
+ getShowOverviewOptions: (params: TParams) => (MapViewStackScene | {
9033
+ activeMap: MappedinMap;
9034
+ focusOn: {
9035
+ options: {
9036
+ tilt: number;
9037
+ duration: number;
9038
+ };
9039
+ };
9040
+ verticalDistanceBetweenMaps: number | undefined;
9041
+ })[] | undefined;
9042
+ getScrollToMapOptions: (params: TParams) => (MapViewStackScene | {
9043
+ focusOn: {
9044
+ targets: {
9045
+ nodes: MappedinNode[];
9046
+ };
9047
+ options: {
9048
+ tilt: number;
9049
+ easing: CAMERA_EASING_MODE;
9050
+ };
9051
+ };
9052
+ activeMap: MappedinMap;
9053
+ })[] | undefined;
9054
+ getRestackOptions: (params: TParams) => (MapViewStackScene | {
9055
+ activeMap: MappedinMap;
9056
+ focusOn: {
9057
+ options: {
9058
+ tilt: number;
9059
+ duration: number;
9060
+ };
9061
+ };
9062
+ verticalDistanceBetweenMaps: number | undefined;
9063
+ })[] | undefined;
9064
+ getEnableOptions: () => void;
9065
+ getShowOverviewTransition: (options: any, inTransit?: boolean) => () => Promise<void>;
9066
+ getZoomInToMapTransition: (options: any) => () => Promise<void>;
9067
+ getScrollToMapTransition: (options: any, inTransit?: boolean) => () => Promise<void>;
9068
+ getRestackTransition: (options: any, inTransit?: boolean) => () => Promise<void>;
9069
+ getDisableTransition: (options: any) => () => Promise<void>;
9070
+ getEnableTransition: () => () => void;
9071
+ states: TState;
9072
+ get determineMapStack(): MappedinMap[];
9073
+ transition(currentState: STACKED_MAPS_STATE, actionName: ACTION): TTargetTransitionFunction[] | void;
9074
+ exec(transitions: TTargetTransitionFunction[] | void, params: TParams): Promise<void>;
9075
+ disable: () => Promise<void>;
9076
+ enable: (opts?: TStackedMapsOptions) => Promise<void>;
9077
+ get nodesInJourneyOrMap(): any[];
9078
+ showOverview: () => Promise<void>;
9079
+ scrollToMap: (map: MappedinMap) => Promise<void>;
9080
+ restack: (options?: TStackedMapsOptions) => Promise<void>;
9081
+ zoomInToMap: (map: MappedinMap, cameraTransform?: TCameraTransform) => Promise<void>;
9082
+ get currentMap(): MappedinMap;
9083
+ }
9084
+ export default StackedMapsController;
9085
+ }
9086
+
8995
9087
  declare module '@mappedin/mappedin-js/renderer/internal/Mappedin.Renderer' {
8996
9088
  /**
8997
9089
  * A class that controls the rendering resources for a canvas output.