diff --git a/example/canvas_source/index.dart b/example/canvas_source/index.dart new file mode 100644 index 0000000..093b884 --- /dev/null +++ b/example/canvas_source/index.dart @@ -0,0 +1,44 @@ +import 'package:mapbox_gl_dart/mapbox_gl_dart.dart'; + +void main() { + bool isPlaying = true; + Mapbox.accessToken = + 'pk.eyJ1IjoiYW5kcmVhNjg5IiwiYSI6ImNrNGlsYjhyZDBuYXoza213aWphOGNjZmoifQ.maw_5NsXejG1DoOeOi6hlQ'; + + var map = MapboxMap( + MapOptions( + container: 'map', + style: 'mapbox://styles/mapbox/light-v10', + zoom: 5, + minZoom: 4, + center: LngLat(95.8991, 18.0887), + ), + ); + + map.on('load', (_) { + map.addSource( + 'canvas-source', + CanvasSource( + canvas: "canvasID", + coordinates: [ + [91.4461, 21.5006], + [100.3541, 21.5006], + [100.3541, 13.9706], + [91.4461, 13.9706] + ], + animate: true, + )); + + map.addLayer( + {'id': 'canvas-layer', 'type': 'raster', 'source': 'canvas-source'}); + }); + map.on('click', (_) { + final source = map.getSource('canvas-source') as CanvasSource?; + if (isPlaying) { + source?.pause(); + } else { + source?.play(); + } + isPlaying = !isPlaying; + }); +} diff --git a/example/canvas_source/index.html b/example/canvas_source/index.html new file mode 100644 index 0000000..0040a70 --- /dev/null +++ b/example/canvas_source/index.html @@ -0,0 +1,114 @@ + + + + Display a canvas source + + + + + + + +
+
+ Canvas not supported +
+

+ Example of the + mapbox-gl-dart +

+
+
+ + + diff --git a/example/examples.json b/example/examples.json index a55d70f..35e6fc2 100644 --- a/example/examples.json +++ b/example/examples.json @@ -18,5 +18,13 @@ { "title": "Display a popup on hover", "folder": "popup_on_hover" + }, + { + "title": "Display a canvas source", + "folder": "canvas_source" + }, + { + "title": "Display a video source", + "folder": "video_source" } ] \ No newline at end of file diff --git a/example/video_source/index.dart b/example/video_source/index.dart new file mode 100644 index 0000000..f78b22b --- /dev/null +++ b/example/video_source/index.dart @@ -0,0 +1,45 @@ +import 'package:mapbox_gl_dart/mapbox_gl_dart.dart'; + +void main() { + bool isPlaying = true; + Mapbox.accessToken = + 'pk.eyJ1IjoiYW5kcmVhNjg5IiwiYSI6ImNrNGlsYjhyZDBuYXoza213aWphOGNjZmoifQ.maw_5NsXejG1DoOeOi6hlQ'; + + var map = MapboxMap( + MapOptions( + container: 'map', + style: 'mapbox://styles/mapbox/light-v10', + zoom: 16, + minZoom: 14, + center: LngLat(-122.514426, 37.562984), + bearing: -96, + ), + ); + + map.on('load', (_) { + map.addSource( + 'video', + VideoSource( + urls: [ + 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4' + ], + coordinates: [ + [-122.51596391201019, 37.56238816766053], + [-122.51467645168304, 37.56410183312965], + [-122.51309394836426, 37.563391708549425], + [-122.51423120498657, 37.56161849366671] + ], + )); + + map.addLayer({'id': 'video', 'type': 'raster', 'source': 'video'}); + }); + map.on('click', (_) { + final source = map.getSource('video') as VideoSource?; + if (isPlaying) { + source?.pause(); + } else { + source?.play(); + } + isPlaying = !isPlaying; + }); +} diff --git a/example/video_source/index.html b/example/video_source/index.html new file mode 100644 index 0000000..802d447 --- /dev/null +++ b/example/video_source/index.html @@ -0,0 +1,47 @@ + + + + Display a video source + + + + + + + +
+
+
+

+ Example of the + mapbox-gl-dart +

+
+
+ + diff --git a/lib/mapbox_gl_dart.dart b/lib/mapbox_gl_dart.dart index 955c951..001460c 100644 --- a/lib/mapbox_gl_dart.dart +++ b/lib/mapbox_gl_dart.dart @@ -4,6 +4,7 @@ library mapboxgl; export 'src/geo/geojson.dart'; +export 'src/geo/image_options.dart'; export 'src/geo/lng_lat.dart'; export 'src/geo/lng_lat_bounds.dart'; export 'src/geo/point.dart'; @@ -13,9 +14,12 @@ export 'src/style/layers/circle_layer.dart'; export 'src/style/layers/layer.dart'; export 'src/style/layers/line_layer.dart'; export 'src/style/layers/symbol_layer.dart'; +export 'src/style/sources/canvas_source.dart'; export 'src/style/sources/geojson_source.dart'; +export 'src/style/sources/image_source.dart'; export 'src/style/sources/source.dart'; export 'src/style/sources/vector_source.dart'; +export 'src/style/sources/video_source.dart'; export 'src/style/style.dart'; export 'src/style/style_image.dart'; export 'src/ui/camera.dart'; diff --git a/lib/src/geo/image_options.dart b/lib/src/geo/image_options.dart new file mode 100644 index 0000000..6b27058 --- /dev/null +++ b/lib/src/geo/image_options.dart @@ -0,0 +1,27 @@ +library mapboxgl.geo.image_options; + +import 'package:mapbox_gl_dart/src/interop/interop.dart'; + +class ImageOptions extends JsObjectWrapper { + String get url => jsObject.url; + dynamic get coordinates => jsObject.coordinates; + + factory ImageOptions({ + String? url, + dynamic coordinates, + }) { + if (coordinates != null && + (coordinates is! List || coordinates.length != 4)) { + throw Exception( + 'Image coordinates must be an array of four longitude latitude pairs'); + } + return ImageOptions.fromJsObject(ImageOptionsJsImpl( + url: url, + coordinates: coordinates, + )); + } + + /// Creates a new ImageOptions from a [jsObject]. + ImageOptions.fromJsObject(ImageOptionsJsImpl jsObject) + : super.fromJsObject(jsObject); +} diff --git a/lib/src/interop/geo/image_options_interop.dart b/lib/src/interop/geo/image_options_interop.dart new file mode 100644 index 0000000..1c59531 --- /dev/null +++ b/lib/src/interop/geo/image_options_interop.dart @@ -0,0 +1,15 @@ +@JS('mapboxgl') +library mapboxgl.interop.geo.image_options; + +import 'package:js/js.dart'; + +@JS() +@anonymous +class ImageOptionsJsImpl { + external String get url; + external dynamic get coordinates; + external factory ImageOptionsJsImpl({ + String? url, + dynamic coordinates, + }); +} diff --git a/lib/src/interop/interop.dart b/lib/src/interop/interop.dart index 59f8cf0..3a15312 100644 --- a/lib/src/interop/interop.dart +++ b/lib/src/interop/interop.dart @@ -1,6 +1,7 @@ library mapboxgl.interop; export 'geo/geojson_interop.dart'; +export 'geo/image_options_interop.dart'; export 'geo/lng_lat_bounds_interop.dart'; export 'geo/lng_lat_interop.dart'; export 'geo/point_interop.dart'; @@ -9,8 +10,12 @@ export 'style/evaluation_parameters_interop.dart'; export 'style/layers/circle_layer_interop.dart'; export 'style/layers/line_layer_interop.dart'; export 'style/layers/symbol_layer_interop.dart'; +export 'style/sources/canvas_source_interop.dart'; export 'style/sources/geojson_source_interop.dart'; +export 'style/sources/image_source_interop.dart'; +export 'style/sources/image_source_interop.dart'; export 'style/sources/vector_source_interop.dart'; +export 'style/sources/video_source_interop.dart'; export 'style/style_image_interop.dart'; export 'style/style_interop.dart'; export 'ui/camera_interop.dart'; diff --git a/lib/src/interop/style/sources/canvas_source_interop.dart b/lib/src/interop/style/sources/canvas_source_interop.dart new file mode 100644 index 0000000..303e035 --- /dev/null +++ b/lib/src/interop/style/sources/canvas_source_interop.dart @@ -0,0 +1,22 @@ +@JS('mapboxgl') +library mapboxgl.style.interop.sources.canvas_source; + +import 'package:js/js.dart'; + +@JS() +@anonymous +class CanvasSourceJsImpl { + external bool get animate; + external String get canvas; + external dynamic get coordinates; + external factory CanvasSourceJsImpl({ + String? type, + bool? animate = false, + String canvas, + dynamic coordinates, + }); + + external CanvasSourceJsImpl play(); + external CanvasSourceJsImpl pause(); + external CanvasSourceJsImpl setCoordinates(dynamic coordinates); +} diff --git a/lib/src/interop/style/sources/image_source_interop.dart b/lib/src/interop/style/sources/image_source_interop.dart new file mode 100644 index 0000000..775550e --- /dev/null +++ b/lib/src/interop/style/sources/image_source_interop.dart @@ -0,0 +1,20 @@ +@JS('mapboxgl') +library mapboxgl.style.interop.sources.image_source; + +import 'package:js/js.dart'; +import 'package:mapbox_gl_dart/src/interop/interop.dart'; + +@JS() +@anonymous +class ImageSourceJsImpl { + external String get url; + external dynamic get coordinates; + external factory ImageSourceJsImpl({ + String? type, + String url, + dynamic coordinates, + }); + + external ImageSourceJsImpl updateImage(ImageOptionsJsImpl imageOptions); + external ImageSourceJsImpl setCoordinates(dynamic coordinates); +} diff --git a/lib/src/interop/style/sources/video_source_interop.dart b/lib/src/interop/style/sources/video_source_interop.dart new file mode 100644 index 0000000..43f1f03 --- /dev/null +++ b/lib/src/interop/style/sources/video_source_interop.dart @@ -0,0 +1,20 @@ +@JS('mapboxgl') +library mapboxgl.style.interop.sources.video_source; + +import 'package:js/js.dart'; + +@JS() +@anonymous +class VideoSourceJsImpl { + external List get urls; + external dynamic get coordinates; + external factory VideoSourceJsImpl({ + String? type, + List urls, + dynamic coordinates, + }); + + external VideoSourceJsImpl play(); + external VideoSourceJsImpl pause(); + external VideoSourceJsImpl setCoordinates(dynamic coordinates); +} diff --git a/lib/src/style/sources/canvas_source.dart b/lib/src/style/sources/canvas_source.dart new file mode 100644 index 0000000..2d4c5d2 --- /dev/null +++ b/lib/src/style/sources/canvas_source.dart @@ -0,0 +1,49 @@ +library mapboxgl.style.sources.canvas_source; + +import 'package:mapbox_gl_dart/mapbox_gl_dart.dart'; +import 'package:mapbox_gl_dart/src/interop/interop.dart'; + +class CanvasSource extends Source { + static const type = 'canvas'; + bool get animate => jsObject.animate; + String get canvas => jsObject.canvas; + dynamic get coordinates => jsObject.coordinates; + + factory CanvasSource({ + required String canvas, + bool? animate, + required dynamic coordinates, + }) { + if (coordinates == null) { + throw Exception('Specify coordinates'); + } + if ((coordinates as List?)?.length != 4) { + throw Exception( + 'Coordinates must be an array of four longitude latitude pairs'); + } + return CanvasSource.fromJsObject(CanvasSourceJsImpl( + type: type, + animate: animate, + canvas: canvas, + coordinates: coordinates, + )); + } + + CanvasSource play() => CanvasSource.fromJsObject(jsObject.play()); + + CanvasSource pause() => CanvasSource.fromJsObject(jsObject.pause()); + + CanvasSource setCoordinates(dynamic coordinates) => + CanvasSource.fromJsObject(jsObject.setCoordinates(coordinates)); + + CanvasSource.fromJsObject(CanvasSourceJsImpl jsObject) + : super.fromJsObject(jsObject); + + @override + get dict => { + 'type': type, + 'canvas': canvas, + 'coordinates': coordinates, + 'animate': animate + }; +} diff --git a/lib/src/style/sources/geojson_source.dart b/lib/src/style/sources/geojson_source.dart index 8725b3b..1273b61 100644 --- a/lib/src/style/sources/geojson_source.dart +++ b/lib/src/style/sources/geojson_source.dart @@ -4,6 +4,7 @@ import 'package:mapbox_gl_dart/mapbox_gl_dart.dart'; import 'package:mapbox_gl_dart/src/interop/interop.dart'; class GeoJsonSource extends Source { + static const type = 'geojson'; FeatureCollection get data => FeatureCollection.fromJsObject(jsObject.data); String? get promoteId => jsObject.promoteId; @@ -12,7 +13,7 @@ class GeoJsonSource extends Source { String? promoteId, }) => GeoJsonSource.fromJsObject(GeoJsonSourceJsImpl( - type: 'geojson', + type: type, promoteId: promoteId, data: data.jsObject, )); @@ -26,7 +27,7 @@ class GeoJsonSource extends Source { @override get dict => { - 'type': 'geojson', + 'type': type, 'promoteId': promoteId, 'data': data.jsObject, }; diff --git a/lib/src/style/sources/image_source.dart b/lib/src/style/sources/image_source.dart new file mode 100644 index 0000000..b0e1005 --- /dev/null +++ b/lib/src/style/sources/image_source.dart @@ -0,0 +1,51 @@ +library mapboxgl.style.sources.image_source; + +import 'package:mapbox_gl_dart/mapbox_gl_dart.dart'; +import 'package:mapbox_gl_dart/src/interop/interop.dart'; + +class ImageSource extends Source { + static const type = 'image'; + String? get url => jsObject.url; + dynamic get coordinates => jsObject.coordinates; + + factory ImageSource({ + required String url, + dynamic coordinates, + }) { + if (coordinates == null) { + throw Exception('Specify coordinates'); + } + if ((coordinates as List?)?.length != 4) { + throw Exception( + 'Image coordinates must be an array of four longitude latitude pairs'); + } + return ImageSource.fromJsObject(ImageSourceJsImpl( + type: type, + url: url, + coordinates: coordinates, + )); + } + + ImageSource updateImage(ImageOptions imageOptions) => + ImageSource.fromJsObject(jsObject.updateImage(imageOptions.jsObject)); + + ImageSource setCoordinates(dynamic coordinates) => + ImageSource.fromJsObject(jsObject.setCoordinates(coordinates)); + + ImageSource.fromJsObject(ImageSourceJsImpl jsObject) + : super.fromJsObject(jsObject); + + @override + get dict { + Map dict = { + 'type': type, + }; + if (url != null) { + dict['url'] = url; + } + if (coordinates != null) { + dict['coordinates'] = coordinates; + } + return dict; + } +} diff --git a/lib/src/style/sources/vector_source.dart b/lib/src/style/sources/vector_source.dart index bf84eec..8523576 100644 --- a/lib/src/style/sources/vector_source.dart +++ b/lib/src/style/sources/vector_source.dart @@ -4,6 +4,7 @@ import 'package:mapbox_gl_dart/mapbox_gl_dart.dart'; import 'package:mapbox_gl_dart/src/interop/interop.dart'; class VectorSource extends Source { + static const type = 'vector'; String? get url => jsObject.url; List? get tiles => jsObject.tiles; @@ -21,7 +22,7 @@ class VectorSource extends Source { )); } return VectorSource.fromJsObject(VectorSourceJsImpl( - type: 'vector', + type: type, tiles: tiles, )); } @@ -33,7 +34,7 @@ class VectorSource extends Source { @override get dict { Map dict = { - 'type': 'vector', + 'type': type, }; if (url != null) { dict['url'] = url; diff --git a/lib/src/style/sources/video_source.dart b/lib/src/style/sources/video_source.dart new file mode 100644 index 0000000..7cb2955 --- /dev/null +++ b/lib/src/style/sources/video_source.dart @@ -0,0 +1,48 @@ +library mapboxgl.style.sources.image_source; + +import 'package:mapbox_gl_dart/mapbox_gl_dart.dart'; +import 'package:mapbox_gl_dart/src/interop/interop.dart'; + +class VideoSource extends Source { + static const type = 'video'; + List get urls => jsObject.urls; + dynamic get coordinates => jsObject.coordinates; + + factory VideoSource({ + required List urls, + required dynamic coordinates, + }) { + if (coordinates == null) { + throw Exception('Specify coordinates'); + } + if ((coordinates as List?)?.length != 4) { + throw Exception( + 'Video coordinates must be an array of four longitude latitude pairs'); + } + if (urls.isEmpty) { + throw Exception('Specify at least 1 url'); + } + return VideoSource.fromJsObject(VideoSourceJsImpl( + type: type, + urls: urls, + coordinates: coordinates, + )); + } + + VideoSource play() => VideoSource.fromJsObject(jsObject.play()); + + VideoSource pause() => VideoSource.fromJsObject(jsObject.pause()); + + VideoSource setCoordinates(dynamic coordinates) => + VideoSource.fromJsObject(jsObject.setCoordinates(coordinates)); + + VideoSource.fromJsObject(VideoSourceJsImpl jsObject) + : super.fromJsObject(jsObject); + + @override + get dict => { + 'type': type, + 'urls': urls, + 'coordinates': coordinates, + }; +} diff --git a/lib/src/ui/map.dart b/lib/src/ui/map.dart index ee9f65b..5619a57 100644 --- a/lib/src/ui/map.dart +++ b/lib/src/ui/map.dart @@ -584,13 +584,19 @@ class MapboxMap extends Camera { /// @see [Add live realtime data](https://www.mapbox.com/mapbox-gl-js/example/live-geojson/) dynamic getSource(String id) { var source = jsObject.getSource(id); - if (source is GeoJsonSourceJsImpl) { - return GeoJsonSource.fromJsObject(source); + switch (source?.type) { + case ImageSource.type: + if (source?.canvas != null) { + return CanvasSource.fromJsObject(source); + } + return ImageSource.fromJsObject(source); + case VectorSource.type: + return VectorSource.fromJsObject(source); + case VideoSource.type: + return VideoSource.fromJsObject(source); + default: + return GeoJsonSource.fromJsObject(source); } - if (source is VectorSourceJsImpl) { - return VectorSource.fromJsObject(source); - } - return source; } /// Add an image to the style. This image can be displayed on the map like any other icon in the style's diff --git a/pubspec.yaml b/pubspec.yaml index 3b9c471..133d229 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: mapbox_gl_dart -version: 0.2.1 +version: 0.2.2 description: Mapbox-gl wrapper for Dart. Library to use Mapbox GL JS in your web Dart projects. homepage: https://github.com/andrea689/mapbox-gl-dart/ environment: