Skip to content

Commit

Permalink
Add custom marker example
Browse files Browse the repository at this point in the history
  • Loading branch information
OttyLab committed Feb 22, 2021
1 parent 5d5a144 commit d1373f4
Show file tree
Hide file tree
Showing 2 changed files with 269 additions and 0 deletions.
267 changes: 267 additions & 0 deletions example/lib/custom_marker.dart
@@ -0,0 +1,267 @@
import 'dart:io';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:mapbox_gl/mapbox_gl.dart';

import 'main.dart';
import 'page.dart';

const RANDOM_MARKER_NUM = 100;

class CustomMarker extends ExamplePage {
CustomMarker() : super(const Icon(Icons.place), 'Custom marker');

@override
Widget build(BuildContext context) {
return FullMap();
}
}

class FullMap extends StatefulWidget {
const FullMap();

@override
State createState() => FullMapState();
}

abstract class PositionChangeListener {
LatLng onPositionWillChange();
void onPositionChanged(Point point);
}

class FullMapState extends State<FullMap> {
final Random _rnd = new Random();

MapboxMapController _mapController;
List<Marker> _markers = [];
List<PositionChangeListener> _positionChangeListeners = [];

void _addPositionChangeListener(PositionChangeListener listener) {
_positionChangeListeners.add(listener);
}

void _onMapCreated(MapboxMapController controller) {
_mapController = controller;
controller.addListener(() {
if (controller.isCameraMoving) {
_updateMarkerPosition();
}
});
}

void _onStyleLoadedCallback() {
print('onStyleLoadedCallback');
}

void _onMapLongClickCallback(Point<double> point, LatLng coordinates) {
_addMarker(point, coordinates);
}

void _onCameraIdleCallback() {
_updateMarkerPosition();
}

void _updateMarkerPosition() {
var param = <LatLng>[];

for (final listner in _positionChangeListeners) {
param.add(listner.onPositionWillChange());
}

_mapController.toScreenLocationBatch(param).then((points){
for (final listner in _positionChangeListeners) {
param.add(listner.onPositionWillChange());
}

_positionChangeListeners.asMap().forEach((i, value){
final point = Point(points[i].x, points[i].y);
_positionChangeListeners[i].onPositionChanged(point);
});
});
}

void _addMarker(Point<double> point, LatLng coordinates) {
setState(() {
_markers.add(Marker(_rnd.nextInt(100000).toString(), coordinates, point, _addPositionChangeListener));
});
}

@override
Widget build(BuildContext context) {
return new Scaffold(
body: Stack(
children: [
MapboxMap(
accessToken: MapsDemo.ACCESS_TOKEN,
trackCameraPosition: true,
onMapCreated: _onMapCreated,
onMapLongClick: _onMapLongClickCallback,
onCameraIdle: _onCameraIdleCallback,
onStyleLoadedCallback: _onStyleLoadedCallback,
initialCameraPosition: const CameraPosition(target: LatLng(35.0, 135.0), zoom: 5),
),
IgnorePointer(
ignoring: true,
child:
Stack(
children: _markers,
)
)
]
),
floatingActionButton: FloatingActionButton(
onPressed: (){
//_measurePerformance();

// Generate random markers
var param = <LatLng>[];
for (var i = 0; i < RANDOM_MARKER_NUM; i++) {
final lat = _rnd.nextDouble() * 20 + 30;
final lng = _rnd.nextDouble() * 20 + 125;
param.add(LatLng(lat, lng));
}

_mapController.toScreenLocationBatch(param).then((value) {
for (var i = 0; i < RANDOM_MARKER_NUM; i++) {
var point = Point<double>(value[i].x, value[i].y);
_addMarker(point, param[i]);
}
});
},
child: Icon(Icons.add),
),
);
}

// ignore: unused_element
void _measurePerformance() {
final trial = 10;
final batches = [500, 1000, 1500, 2000, 2500, 3000];
var results = Map<int, List<double>>();
for (final batch in batches) {
results[batch] = [0.0, 0.0];
}

_mapController.toScreenLocation(LatLng(0, 0));
Stopwatch sw = Stopwatch();

for (final batch in batches) {
//
// primitive
//
for (var i = 0; i < trial; i++) {
sw.start();
var list = <Future<Point<num>>>[];
for (var j = 0; j < batch; j++) {
var p = _mapController.toScreenLocation(LatLng(j.toDouble() % 80, j.toDouble() % 300));
list.add(p);
}
Future.wait(list);
sw.stop();
results[batch][0] += sw.elapsedMilliseconds;
sw.reset();
}

//
// batch
//
for (var i = 0; i < trial; i++) {
sw.start();
var param = <LatLng>[];
for (var j = 0; j < batch; j++) {
param.add(LatLng(j.toDouble() % 80, j.toDouble() % 300));
}
Future.wait([_mapController.toScreenLocationBatch(param)]);
sw.stop();
results[batch][1] += sw.elapsedMilliseconds;
sw.reset();
}

print('batch=$batch,primitive=${results[batch][0] / trial}ms, batch=${results[batch][1] / trial}ms');
}

}
}

class Marker extends StatefulWidget {
final Point _initialPosition;
final LatLng _coordinate;
final void Function(PositionChangeListener) _addPositionChangeListener;

Marker(String key, this._coordinate, this._initialPosition, this._addPositionChangeListener) : super(key: Key(key));

@override
State<StatefulWidget> createState() {
final state = _MarkerState(_coordinate, _initialPosition);
_addPositionChangeListener(state);
return state;
}
}

class _MarkerState extends State with TickerProviderStateMixin, PositionChangeListener {
final _iconSize = 20.0;

final LatLng _coordinate;
Point _position;

AnimationController _controller;
Animation<double> _animation;

_MarkerState(this._coordinate, this._position);

@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(seconds: 2),
vsync: this,
)..repeat(reverse: true);
_animation = CurvedAnimation(
parent: _controller,
curve: Curves.elasticOut,
);
}

@override
void dispose() {
_controller.dispose();
super.dispose();
}

@override
Widget build(BuildContext context) {
var ratio = 1.0;

try {
ratio = Platform.isIOS ? 1.0 : MediaQuery.of(context).devicePixelRatio; //TODO: iOS returns lp
} catch (UnsupportedError) {
//web does not support Platform._operatingSystem
}; // ignore: empty_statements

return
Positioned(
left: _position.x / ratio - _iconSize / 2,
top: _position.y / ratio - _iconSize / 2,
child:
RotationTransition(
turns: _animation,
child:
Image.asset('assets/symbols/2.0x/custom-icon.png', height: _iconSize))
);
}

@override
void onPositionChanged(Point<num> point) {
setState(() {
_position = point;
});
}

@override
LatLng onPositionWillChange() {
return _coordinate;
}
}

2 changes: 2 additions & 0 deletions example/lib/main.dart
Expand Up @@ -5,6 +5,7 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:location/location.dart';
import 'package:mapbox_gl_example/custom_marker.dart';
import 'package:mapbox_gl_example/full_map.dart';
import 'package:mapbox_gl_example/offline_regions.dart';

Expand Down Expand Up @@ -36,6 +37,7 @@ final List<ExamplePage> _allPages = <ExamplePage>[
ScrollingMapPage(),
OfflineRegionsPage(),
AnnotationOrderPage(),
CustomMarker(),
];

class MapsDemo extends StatelessWidget {
Expand Down

0 comments on commit d1373f4

Please sign in to comment.