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
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.
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>
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.
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']).
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
}
}
}