#angular/google-maps Marker and Cluster Animation - google-maps-markers

I'm using Angular's Google Maps library (#angular/google-maps: 13.3.4) and want to animate clusters the same way as markers just when markers are added. This is my code so far:
<google-map height="400px"
width="750px"
[center]="center"
[zoom]="zoom"
>
<map-marker-clusterer [zoomOnClick]="true" [imagePath]="markerClustererImagePath">
<map-marker *ngFor="let markerPosition of markerPositions"
[options]="markerOptions"
[position]="markerPosition"
></map-marker>
</map-marker-clusterer>
</google-map>
<button (click)="addSingleMarker($event)">Add new Marker</button>
<button (click)="addMarkerToCluster($event)">Add new Cluster</button>
Component.ts:
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
center = { lat: 24, lng: 12 };
zoom = 4;
markerPositions = [
{ lat: 24, lng: 12 },
{ lat: 24, lng: 12 },
{ lat: 15, lng: 6 },
];
markerOptions: google.maps.MarkerOptions = {
animation: google.maps.Animation.DROP
};
markerClustererImagePath =
'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m';
public addMarkerToCluster($event: google.maps.MapMouseEvent) {
if ($event.latLng !== null) {
this.markerPositions.push({ lat: 24, lng: 12 });
}
}
public addSingleMarker($event: google.maps.MapMouseEvent) {
if ($event.latLng !== null) {
this.markerPositions.push({ lat: 21, lng: 2 });
}
}
}
I would be happy if someone can help me.

Not sure if there is proper way to do so but gonna share my solution which works fine in my case:
<map-marker-clusterer
#markerCluster
>
<map-marker
*ngFor="let marker of markers"
[position]="marker.coordinates"
[options]="marker.options"
>
</map-marker>
</map-marker-clusterer>
Add #markerCluster tag for cluster, than assign it to variable as soon as cluster is via ViewChild setter initialized:
#ViewChild('markerCluster') set markerCluster(cluster: MapMarkerClusterer) {
if (!cluster) return;
this.cluster = cluster;
}
Now you have MapMarkerClusterer object on which you can do some animation via reaching on this.cluster.markerClusterer.getClusters() <-- all the clusters on your map.
Each cluster in this.cluster.markerClusterer.getClusters() have div_, so you can add class of css animation on specific clusters div.

Related

#nativescript-community/ui-mapbox - Can't add markers programatically

I am trying add markers dynamically/programatically after map is renderer but nothing is happening. Please see my code below
Service Code:
import { Injectable } from '#angular/core';
import { MapboxMarker, MapboxView, Mapbox } from "#nativescript-community/ui-mapbox";
import { registerElement } from '#nativescript/angular';
import { isIOS } from "#nativescript/core/platform";
#Injectable({
providedIn: 'root'
})
export class MapService {
mapboxView: MapboxView;
mapbox: Mapbox;
/**
* Creates an instance of Mapbox.
* #param config
* #memberof Mapbox
*/
constructor() {
registerElement("Mapbox", () => require("#nativescript-community/ui-mapbox").MapboxView);
}
generateMap(view: any) {
const settings = {
container: view,
accessToken: 'pk.eyJ1IjoiaGV5aXR6c3llZCIsImEiOiJjbDA5aTZlb3gwMGxsM2puejdyeTQyZnNjIn0.aJUDueGHXwKea-kN8lxn2g',
style: 'traffic_day',
margins: {
left: 18,
right: 18,
top: isIOS ? 390 : 454,
bottom: isIOS ? 50 : 8
},
center: {
lat: 52.3702160,
lng: 4.8951680
},
zoomLevel: 18, // 0 (most of the world) to 20, default 0
showUserLocation: false, // default false
hideAttribution: false, // default false
hideLogo: false, // default false
hideCompass: false, // default false
disableRotation: false, // default false
disableScroll: false, // default false
disableZoom: false, // default false
disableTilt: false, // default false
markers: [
{
id: 1,
lat: 52.3732160,
lng: 4.8941680,
title: 'Nice location',
subtitle: 'Really really nice location',
selected: true,
iconPath: '~/assets/Img/map.png',
onTap: () => console.log("'Nice location' marker tapped"),
onCalloutTap: () => console.log("'Nice location' marker callout tapped")
}
]
};
const mapView = new MapboxView();
mapView.setConfig(settings);
view.content = mapView;
}
}
Component.ts code:
import { Component, OnInit } from '#angular/core';
import { MapService } from 'map/map.service';
import { Page } from "#nativescript/core/ui/page";
import { ContentView } from "#nativescript/core/ui/content-view";
#Component({
selector: 'app-map-service-demo',
templateUrl: './map-service-demo.component.html',
styleUrls: ['./map-service-demo.component.css']
})
export class MapServiceDemoComponent implements OnInit {
constructor(public map: MapService, public page: Page) { }
ngOnInit(): void {
const contentView : ContentView = <ContentView>this.page.getViewById( 'mapContainer' );
this.map.generateMap(contentView);
}
}
Component.html code:
<StackLayout>
<ContentView height="100%" width="100%" id="mapContainer">
</ContentView>
</StackLayout>
The above implementation is not displaying markers by default even there is markers: [{}] property available in the settings.
Moreover, In the below code, I dont get what mapbox refers to
mapbox.addMarkers([
firstMarker,
{
// more markers..
}
])
Please guide me on adding markers programatically.

Phaser 3.17 doesn't setect collision between tilemap layer and player sprite

No collisions between map layer and player sprite. But collisions between world bounds work. What is wrong?
I tried different workarounds that could find online and none of them worked.
Game config
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: "#f",
physics: {
default: 'arcade',
arcade: {
gravity: { y: gameState.gravity },
debug: true
}
},
scene: {
preload,
create,
update
}
};
Code in create() regarding the tilemap and its layers and the character
gameState.map = this.add.tilemap('map');
gameState.dungeonTileset = gameState.map.addTilesetImage('dungeon', 'dungeonTiles');
gameState.backgroundLayer = gameState.map.createStaticLayer('Background', gameState.dungeonTileset);
gameState.mapLayer = gameState.map.createStaticLayer('Map', gameState.dungeonTileset);
gameState.miscLayer = gameState.map.createStaticLayer('Misc', gameState.dungeonTileset);
gameState.mapLayer.setCollisionByExclusion([-1]);
this.physics.world.bounds.width = gameState.mapLayer.width;
this.physics.world.bounds.height = gameState.mapLayer.height;
gameState.player = this.physics.add.sprite(73, 398, 'player', 0);
gameState.player.setCollideWorldBounds(true);
this.physics.add.collider(gameState.player, gameState.mapLayer);
No warning and no errors are coming up in the console. I don't know what to do anymore.
Thanks in advance!
I have addited a little bit the original example so you can see how it looks, I think the problem in your code is the line concerning gameState.mapLayer.setCollisionByExclusion([-1]); but am not sure because I can't see how the tilemap is created
var config = {
type: Phaser.WEBGL,
width: 800,
height: 576,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
loader: {
baseURL: 'https://labs.phaser.io',
crossOrigin: 'anonymous'
},
pixelArt: true,
physics: {
default: 'arcade',
arcade: { gravity: { y: 300 } }
},
scene: {
preload: preload,
create: create,
update: update
}
};
var game = new Phaser.Game(config);
var map;
var cursors;
var player;
var groundLayer;
function preload ()
{
this.load.image('ground_1x1', 'assets/tilemaps/tiles/ground_1x1.png');
this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/tile-collision-test.json');
this.load.image('player', 'assets/sprites/phaser-dude.png');
}
function create ()
{
map = this.make.tilemap({ key: 'map' });
var groundTiles = map.addTilesetImage('ground_1x1');
map.createDynamicLayer('Background Layer', groundTiles, 0, 0);
groundLayer = map.createDynamicLayer('Ground Layer', groundTiles, 0, 0);
groundLayer.setCollisionBetween(1, 25);//here
player = this.physics.add.sprite(80, 70, 'player')
.setBounce(0.1);
this.physics.add.collider(player, groundLayer);
cursors = this.input.keyboard.createCursorKeys();
this.cameras.main.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
this.cameras.main.startFollow(player);
}
function update ()
{
player.body.setVelocityX(0);
if (cursors.left.isDown)
{
player.body.setVelocityX(-200);
}
else if (cursors.right.isDown)
{
player.body.setVelocityX(200);
}
if (cursors.up.isDown && player.body.onFloor())
{
player.body.setVelocityY(-300);
}
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.17.0/dist/phaser.min.js"></script>

Getting Position of Marker After Dragging Laravel-VUE based component

I am using
vue-google-maps
They working good so far, I want to achieve that when someone search and select their area a marker appears and then they can drag it to their required position.
I have so far managed to make the marker draggable by editing GoogleMap.vue file
<gmap-marker
:key="index"
v-for="(m, index) in markers"
:position="m.position"
:draggable="true"
#click="center=m.position"
#drag="setCurrent(this)"
></gmap-marker>
Now I am able to drag the marker however the coordinates (lat:long) doesn't change.
I am using Laravel 1.4.1
Vue 3.0.0-beta.6
Please help
rest of the GoogleMap.vue look like this
<script>
export default {
name: "GoogleMap",
data() {
return {
center: { lat: 24.9004057, lng: 67.1926178 },
markers: [],
places: [],
currentPlace: null,
};
},
mounted() {
this.geolocate();
},
methods: {
// receives a place object via the autocomplete component
setPlace(place) {
this.currentPlace = place;
this.addMarker();
},
addMarker() {
if (this.currentPlace) {
const marker = {
lat: this.currentPlace.geometry.location.lat(),
lng: this.currentPlace.geometry.location.lng()
};
this.markers.push({ position: marker, draggable: true });
this.places.push(this.currentPlace);
this.center = marker;
this.currentPlace = null;
}
},
geolocate: function() {
navigator.geolocation.getCurrentPosition(position => {
this.center = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
});
},
checkthis(position){
console.log(navigator.position.getCurrentPosition());
}
}
};
</script>
To get marker position once it is dragged Marker.dragend is better suited then Marker.drag:
This event is fired when the user stops dragging the marker.
In case of vue-google-maps library marker position could be determined like this:
<gmap-marker
:draggable="true"
:key="index"
v-for="(m, index) in markers"
:position="m.position"
#click="center=m.position"
#dragend="showLocation"
></gmap-marker>
showLocation: function(evt){
console.log( evt.latLng.toString());
}
where evt is a MouseEvent object and MouseEvent.latLng property contains the position of dragged marker
The same applies to #drag event.

TypeScript Visual Studio TS1219 Experimental support for decorators is a feature that is subject to change in a future release.

I get the following error: TS1219 Experimental support for decorators is a feature that is subject to change in a future release. Set the 'experimentalDecorators' option to remove this warning.
I know I can suppress this by setting "experimentalDecorators": true in tsconfig.json.
But I would still like to know why I get the error from this code:
import * as React from "react";
import scriptLoader from 'react-async-script-loader'
#scriptLoader(['https://maps.googleapis.com/maps/api/js?key=your-key'])
export default class Maps extends React.Component<any, any> {
constructor(props: any) {
super(props);
this.map = null;
}
refs: {
[string: string]: any;
map: any;
}
map: any;
componentWillReceiveProps({ isScriptLoaded, isScriptLoadSucceed }) {
if (isScriptLoaded && !this.props.isScriptLoaded) { // load finished
if (isScriptLoadSucceed) {
this.map = new google.maps.Map(this.refs.map, {
center: { lat: 10.794234, lng: 106.706541 },
zoom: 20
});
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
const pos = {
lat: position.coords.latitude,
lng: position.coords.longitude
};
this.map.setCenter(pos);
const marker = new google.maps.Marker({
position: pos,
map: this.map,
title: 'Hello World!'
});
}, () => {
console.log('navigator disabled');
});
} else {
// Browser doesn't support Geolocation
console.log('navigator disabled');
}
}
else this.props.onError()
}
}
render() {
return (
<div>
<div ref="map" style={{ height: '80%', width: '100%' }}></div>
{!this.map && <div className="center-md">Loading...</div>}
</div>
)
}
}
But I would still like to know why I get the error from this code:
Because you are using a decorator in #scriptLoader(['https://maps.googleapis.com/maps/api/js?key=your-key']).

A marker can only be added to a layer of type "group" error even though type "group" is defined

I am having trouble with an error that seems obvious but I've tried everything. I must be missing something. I'm running a rails app with Angularjs and angular-leaflet-directives. I am trying to add markers to a specific group. No matter what I do, I keep getting this error:
[AngularJS - Leaflet] A marker can only be added to a layer of type "group"
I know that this error comes up when the overlays type isn't group. The issue is that in my case, it is!
EDIT: here is a plunkr where I recreated the bug: http://plnkr.co/edit/DLCN5RYVr0BheYzTuqkQ?p=preview
Here is my code:
assets/javascript/angular/services/service.js
app.factory('Markers', ["$http", "$q", function($http, $q) {
var Markers = []
var events_markers = []
var stories_markers = []
var defaultIcon = L.icon({
iconUrl: 'assets/dot-grey.png',
iconSize: [15, 15],
iconAnchor: [15, 15],
popupAnchor: [-7, -20]
})
// Getting events + stories from rails API
var event_data = $http.get("/api/v1/events.json"),
story_data = $http.get("/api/v1/stories.json")
// Setting event markers and stories markers
$q.all([event_data, story_data]).then(function(results) {
var data_stories = results[1].data.stories
var data_events = results[0].data.event
for (i=0 ; i < data_stories.length; i++){
for (j=0; j < data_stories[i].locations.length; j++){
var lat = data_stories[i].locations[j].latitude
var lng = data_stories[i].locations[j].longitude
var title = data_stories[i].title
var layer = "stories"
Markers.push({layer: layer, lat:lat, lng:lng, message: title, icon: defaultIcon})
}
}
for (e=0 ; e < data_events.length; e++){
if (data_events[e].latitude != null){
var lat = data_events[e].latitude
var lng = data_events[e].longitude
var title = data_events[e].name
var layer = "events"
Markers.push({layer: layer, lat:lat, lng: lng, message: title, icon: defaultIcon})
}
}
return Markers
});
return {
markers: Markers
}
}]);
assets/javascript/angular/controllers/MapCtrl.js
app.controller("MapCtrl", ['$scope', "$timeout", "leafletData", "Markers", function($scope,
$timeout, leafletData, Markers ){
$scope.isVisible = true;
$scope.markers = Markers.markers;
var bounds = {
northEast:{
lat: 37.86862005954327,
lng: -122.12230682373048
},
southWest:{
lat: 37.68436373334184,
lng: -122.55901336669923
}
}
function setMap($scope, markers, bounds) {
angular.extend($scope, {
maxbounds: bounds,
defaults: {
scrollWheelZoom: false,
maxZoom: 14,
minZoom: 10
},
layers: {
baselayers: {
mapbox:{
name: 'Mapbox Litography',
url: 'http://api.tiles.mapbox.com/v4/{mapid}/{z}/{x}/{y}.png?access_token={apikey}',
type: 'xyz',
layerParams: {
apikey: 'pk.eyJ1IjoibGF1cmVuYmVuaWNob3UiLCJhIjoiQ1BlZGczRSJ9.EVMieITn7lHNi6Ato9wFwg',
mapid: 'laurenbenichou.jm96meb6'
}
}
}
},
overlays: {
stories: {
type: 'group', //Note here that the type is indeed 'group'
name: 'stories',
visible: true
},
events: {
type: 'group',
name: 'events',
visible: false
}
},
markers: markers
});
}
setMap($scope, $scope.markers, bounds)
angular.element(document).ready(function () {
function toggle(){$scope.isVisible = !$scope.isVisible;}
$timeout(toggle, 1000);
});
}])
assets/javascript/templates/map.html
<leaflet ng-hide="isVisible" defaults="defaults" markers="markers" layers="layers" height="100%" width="100%" maxbounds="maxbounds" ></leaflet>
assets/javascript/angular/app.js
var app = angular.module("litography", ['ngAnimate','ui.router','ngResource', 'templates', 'leaflet-directive', 'cn.offCanvas', 'ui.bootstrap', 'angular-flexslider'])
.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function($stateProvider, $urlRouterProvider, $locationProvider) {
/**
* Routes and States
*/
$stateProvider
.state('home', {
url: "/",
views:{
"splash": {
templateUrl: "splash.html",
controller: "SplashCtrl"
},
"map":{
templateUrl: "map.html",
controller: "MapCtrl",
resolve:{
Markers: function(Markers){
return Markers
}
}
},
"menu":{
templateUrl: "menu.html",
controller: "MenuCtrl"
}
}
})
// default fall back route
$urlRouterProvider.otherwise('/');
// enable HTML5 Mode for SEO
$locationProvider.html5Mode(true);
}]);
It can happen if you forgot to add the file: leaflet.markercluster.js
Ok, from the reduced plunker it was easier to play around and find the bug.
You need to put overlays inside (i.e. as a property of) layers:
layers: {
baselayers: {
mapbox: {
name: 'mapbox',
url: 'http://api.tiles.mapbox.com/v4/{mapid}/{z}/{x}/{y}.png?access_token={apikey}',
type: 'xyz',
layerParams: {
apikey: 'pk.eyJ1IjoibGF1cmVuYmVuaWNob3UiLCJhIjoiQ1BlZGczRSJ9.EVMieITn7lHNi6Ato9wFwg',
mapid: 'laurenbenichou.jm96meb6',
name: "stories"
}
}
},
overlays: {
stories: {
type: 'group',
name: 'stories',
visible: true,
},
events: {
type: 'group',
name: 'events',
visible: false
}
}
}

Resources