I am using leaflet to display a map with center view on America, I would like to display all the markers I am also wondering is it because of the huge amount of data I have that it is not displaying or is that not a problem? I have around 12000 units. I am unable to display the markers. I have a JSON file and I have a problem with getting the latitude and longitude parameters for creating markers array on my map.
Json File
{
"PlantID": 1,
"PlantState": "AK",
"PlantName": "7-Mile Ridge Wind Project",
"UtilityName": "Alaska Power and Telephone Co",
"UtilityID": 219,
"Latitude": 63.210689,
"Longitude": -143.247156,
"NetGeneration": 0
},
{
"PlantID": 2,
"PlantState": "AK",
"PlantName": "Agrium Kenai Nitrogen Operations",
"UtilityName": "Agrium US Inc",
"UtilityID": 179,
"Latitude": 60.6732,
"Longitude": -151.3784,
"NetGeneration": 0
},
map.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import * as L from 'leaflet';
#Injectable({
providedIn: 'root',
})
export class MarkerService {
baseUrl: string = 'http://localhost:3000/PLNT20' //json file
constructor(private http: HttpClient) {}
makesMarkers(map: L.Map): void {
this.http.get(this.baseUrl).subscribe((res : any) => {
for(const c of res){
const lat = c.latitude;
const long = c.longtitude;
const marker = L.marker([long,lat]).addTo(map);
/*marker.bindPopup( `<center>
<p>
<strong>'${c.PlantID}'</strong>
</p>
</center>`
).openPopup() */
}
});
}
}
map.component.ts
import { Component, OnInit } from '#angular/core';
import * as L from 'leaflet';
import { MarkerService } from 'src/app/map.service';
#Component({
selector: 'app-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.scss']
})
export class MapComponent implements OnInit {
private map: any;
private initMap(): void {
this.map = L.map('map').setView([40,-100],5)
const tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '© OpenStreetMap'
});
tiles.addTo(this.map);
}
constructor(private markerService : MarkerService) { }
ngAfterViewInit():void{
this.initMap();
this.markerService.makesMarkers(this.map);
}
ngOnInit(): void {
this.initMap();
}
}
12k points is indeed a big number for Leaflet. Consider clustering, or canvas rendering.
See Large dataset of markers or dots in Leaflet
Also, Leaflet expects the coordinates order to be [latitude, longitude]
Looks like you also have some typos:
// In your data:
{
"Latitude": 63.210689,
"Longitude": -143.247156,
},
But:
// In your code:
const lat = c.latitude;
const long = c.longtitude;
// ...should have been:
const lat = c.Latitude;
const long = c.Longitude;
Related
I've developed a website in Angular 14 that treat about cryptocurrencies using the CoinGecko API.
I wanted to display a chart for every cryptocurrency on a specific page using chart.js and ng2-charts.
I've parsed the data sent by the API and used it in my chart but it is not showing the line chart expected.
Here is a service that is getting the data from the API and parse it:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import {map, Observable, Subscription } from 'rxjs';
#Injectable({
providedIn: 'root',
})
export class SingleCryptoGraphService {
subscription: Subscription;
doubletab: any = {
date : Array<string>(),
price: Array<number>(),
};
constructor(private httpClient: HttpClient) {
this.subscription = Subscription.EMPTY;
}
HistoricalChart(id: string, currency: string, days: number): Observable<any> {
return this.httpClient
.get<any[]>(
'https://api.coingecko.com/api/v3/coins/'+id+'/market_chart?vs_currency='+currency+'&days='+days+'&interval=daily').pipe(
map( (obj: any) => obj['prices']),
map((tab: any[]) => {
const res = [];
for (let i = 0; i < tab.length; i++) {
this.doubletab.date.push(this.getDate(tab[i][0]));
this.doubletab.price.push(this.convertToNumber(tab[i][1]));
}
console.log(this.doubletab);
return this.doubletab;
}
)
);
}
getDate = (date: number) : string => {
let d = new Date(date)
let day = d.getDate()
let month = d.getMonth() + 1
let year = d.getFullYear()
return day + "/" + month + "/" + year
}
convertToNumber = (str: string) : number => {
return Number(str)
}
}
Here is the chart component TypeScript:
import { Component, OnDestroy, OnInit, Input, ViewChild } from '#angular/core';
import { SingleCryptoGraphService } from '../single-crypto-graph.service';
import { Subscription } from 'rxjs';
import { Chart, ChartConfiguration, ChartEvent, ChartType } from 'chart.js';
import { BaseChartDirective } from 'ng2-charts';
#Component({
selector: 'app-crypto-graph',
templateUrl: './crypto-graph.component.html',
styleUrls: ['./crypto-graph.component.css']
})
export class CryptoGraphComponent implements OnInit, OnDestroy {
subscription3: Subscription
chartInfoTabs: any = {
date: Array<string>(),
price: Array<number>(),
}
#Input() id = ''
constructor(private SingleCryptoGraphService:SingleCryptoGraphService) {
this.subscription3 = Subscription.EMPTY;
this.id = "none";
}
ngOnInit(): void {
this.subscription3.unsubscribe()
this.subscription3 = this.SingleCryptoGraphService.HistoricalChart(this.id,"eur",30).subscribe(
(data) => {
this.chartInfoTabs.date = data.date;
this.chartInfoTabs.price = data.price;
}
);
}
ngOnDestroy() {
this.subscription3.unsubscribe()
}
public lineChartData: ChartConfiguration['data'] = {
datasets: [{
data: this.chartInfoTabs.price,
label: this.id,
backgroundColor: 'rgba(148,159,177,0.2)',
borderColor: 'rgba(148,159,177,1)',
pointBackgroundColor: 'rgba(148,159,177,1)',
pointBorderColor: '#fff',
pointHoverBackgroundColor: '#fff',
pointHoverBorderColor: 'rgba(148,159,177,0.8)',
fill: 'origin',
}],
labels: this.chartInfoTabs.date,
}
public lineChartOptions: ChartConfiguration['options'] = {
elements: {
line: {
tension: 0.5
}
},
scales: {
y:
{
position: 'left',
},
},
};
public lineChartType: ChartType = 'line';
#ViewChild(BaseChartDirective) chart?: BaseChartDirective;
}
And here is the canvas used to display the chart and the result I got:
<canvas baseChart class="chart"
[data]="lineChartData"
[options]="lineChartOptions"
[type]="lineChartType"
(chartHover)="chartHovered($event)">
</canvas>
What's actually shown by my code
I suspect my tables of data implement the wrong type but I can't figure out why because they seem to be right.
I would really appreciate help with this problem because I really don't understand why it is not working.
I have the following code where I am creating a leaflet map on initial load of the page. I have about four jsons with lat/lon data that I would like to populate the map. What I'm looking for is four buttons that when clicked will add the json data as markers to the map.
What I'm getting is an error indicating the following:
Cannot read properties of undefined (reading 'addLayer').
Map Component:
import { Component, AfterViewInit, OnInit } from '#angular/core';
import { MapPointsService } from './map-points.service';
import * as L from 'leaflet';
#Component({
selector: 'app-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.css'],
})
export class MapComponent implements AfterViewInit {
private map: L.Map | L.LayerGroup<any> | undefined;
area: any;
markersLayer = new L.LayerGroup();
private initMap(): void {
this.map = L.map('map', {
center: [4.5709, -74.2973],
zoom: 3,
});
this.area = this.map;
const tiles = L.tileLayer(
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
{
maxZoom: 18,
minZoom: 3,
attribution:
'© OpenStreetMap',
}
);
tiles.addTo(this.map);
}
constructor(private mapService: MapPointsService) {}
ngAfterViewInit(): void {
this.initMap();
// this.mapService.jsonMarkers(this.area);
}
addMarkers(): void {
this.mapService.jsonMarkers(this.area);
}
}
MapService
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
// import { MapComponent } from './map.component';
import * as L from 'leaflet';
#Injectable({
providedIn: 'root',
})
export class MapPointsService {
constructor(private http: HttpClient) {}
jsonMarkers(map: L.Map): void {
this.http
.get('/assets/data/<my_json>.json')
.subscribe((res: any) => {
for (const area of res.<json_item>) {
const lon = are.Longitude;
const lat = are.Latitude;
const marker = L.marker([lat, lon]);
/*if (map.hasLayer(marker)) {
map.removeLayer(marker);
}*/
marker.addTo(map);
// console.log(markers);
}
});
}
}
Info Component that calls function
import { Component, OnInit } from '#angular/core';
import { MapPointsService } from '../map/map-points.service';
import { MapComponent } from '../map/map.component';
import { MatSnackBar } from '#angular/material/snack-bar';
#Component({
selector: 'app-information',
templateUrl: './information.component.html',
styleUrls: ['./information.component.css'],
})
export class InformationComponent implements OnInit {
/**
* showSpinner boolean
*/
showSpinner = false;
constructor(
private _snackBar: MatSnackBar,
private mapService: MapPointsService
) {}
ngOnInit(): void {}
run(msg: string): void {
const snackBarRef = this._snackBar.open('Running ' + msg, 'Close', {
duration: 3000,
});
snackBarRef.afterDismissed().subscribe(() => {
this.showSpinner = false;
});
this.showSpinner = true;
}
mapData() {
let data = new MapComponent(this.mapService);
data.addMarkers();
}
}
Info Html
<button type="button" (click)='mapData()'></button>
If you manually instantiate an Angular component with just the new keyword (let data = new MapComponent(this.mapService)), it will not be mounted anywhere, and in particular its lifecycle methods, like ngAfterViewInit, will not be called.
Then in your case, this.map and this.area remain undefined, leading to your error message.
Since you do not show your templates, it is hard to tell how your components are supposed to be related.
In case your <app-information> (InformationComponent) contains the <app-map> (MapComponent), you can use #ViewChild in InformationComponent to get a reference to the child MapComponent, and from there you can call its addMarkers method.
In case they are in the opposite situation, IIRC you can just request a MapComponent type in InformationComponent constructor, and Angular will inject it from its ancestors tree.
And if they are somehow siblings, then you could manage from a common ancestor:
get a ref to the MapComponent as described first
add an #Output event emitter on InformationComponent that fires when your button is clicked, and in the ancestor you listen to that event, and call the MapComponent.addMarkers method.
I am building an angular web app that should display data from an endpoint . I have created the service class and I got chart.js installed but the graph is showing a blank linechart even though the console is displaying the data .
could it be a bug issue or am i doing something wrong ?
this is the component.ts class
import { Component, OnInit } from '#angular/core';
import {ApiService} from '../api.service';
import {Chart} from 'chart.js';
//import { map } from 'rxjs/operators';
#Component({
selector: 'app-transactions',
templateUrl: './transactions.component.html',
styleUrls: ['./transactions.component.scss']
})
export class TransactionsComponent implements OnInit {
Linechart;
data ;
market_price_usd ;
time_date ;
constructor(private apiService : ApiService) { }
ngOnInit() {
this.apiService.dailychart()
.subscribe((data: any) => {
this.data = data;
console.log(data);
this.market_price_usd = data.market_price_usd;
this.time_date = data.timestamp;
})
this.Linechart = new Chart ('canvas', {
type : 'line',
data : {
labels : this.time_date,
datasets :[
{
data : this.market_price_usd,
borderColor: '#3cb371',
backgroundColor: "#0000FF",
fill : false
},
]
},
options : {
legend: {
display: false
},
scales : {
xAxes: [{
display: true
}],
yAxes:[{
display: true
}],
}
}
});
};
}
this is the service class : could the issues be from the endpoint that I am consuming ?
mport { Injectable } from '#angular/core';
import {HttpClient, HttpHeaders} from '#angular/common/http';
import {Observable} from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private httpclient : HttpClient ) { }
public dailychart(){
return this.httpclient.get('https://api.blockchain.info/stats') as Observable <Array<any>>
}
}
This is the component.transaction.html code :
<div class="chart-container" style="position: relative; height:40vh; width:70vw">
<canvas id="canvas">{{ Linechart }}</canvas>
</div>
I can't add pictures right now but the chart displays but without data...Just random numbers showed in the Yaxis . This is the result of the endpoint on the console :
timestamp: 1580991534000
market_price_usd: 9669.3
hash_rate: 114554768282.53265
total_fees_btc: 2465817153
.......
Thanks in advance
Im getting cordova notification on the console when I try to see my current country name on the browser.
There's something method or alternative to show me that on my tests.html, like in an input field (in the browser)?
On the other hand, if exist another alternative to show actual country name, please tell me.
tests.ts
import { Component, ViewChild, ElementRef } from "#angular/core";
import { NavController, IonicPage, NavParams } from "ionic-angular";
import {
NativeGeocoder,
NativeGeocoderReverseResult
} from "#ionic-native/native-geocoder";
import { Geolocation } from "#ionic-native/geolocation";
declare var google;
#IonicPage()
#Component({
selector: "page-tests",
templateUrl: "tests.html"
})
export class TestsPage {
#ViewChild("mapSmall") mapElement: ElementRef;
map: any;
message: any;
location: any;
gmLocation: { lat: number; lng: number } = { lat: 0, lng: 0 };
constructor(
public navCtrl: NavController,
private geolocation: Geolocation,
private nativeGeocoder: NativeGeocoder,
public navParams: NavParams,
) {
this.onLocateUser();
}
onLocateUser() {
this.geolocation
.getCurrentPosition()
.then(location => {
console.log(
"position gotten: long:",
location.coords.longitude,
" lat:",
location.coords.latitude
);
this.location = location;
this.gmLocation.lat = location.coords.latitude;
this.gmLocation.lng = location.coords.longitude;
this.nativeGeocoder.reverseGeocode(location.coords.latitude,location.coords.longitude)
.then((result: NativeGeocoderReverseResult) => console.log(JSON.stringify(result.countryName)))
.catch((error: any) => console.log(error));
})
.catch(error => {
console.log("Error getting location", error);
});
}
ionViewDidLoad() {
let latlng = new google.maps.LatLng(
this.gmLocation.lat,
this.gmLocation.lat
);
setTimeout(() => {
this.loadMap(latlng);
this.addMarker(this.gmLocation.lat, this.gmLocation.lng);
}, 100);
}
...
}
Hi all I am using the googles maps nodejs client web api and would like to display a map on my HTMLviews through AngularJS 2.
I have this server export that returns an object to my AngularJS2 client service
const googleMapsClient = require('#google/maps').createClient({
key: 'AIzaSyCYcyd0vCGRY6Pq5E0u_ECTFi4I9VmUE4o'
});
module.exports = (req, res) => {
googleMapsClient.geocode({
address: 'Cosmo City, Roodepoort USA street'
}, function(err,response) {
if(err) {
console.log("There was an error geocoding the address", err)
} else {
console.log("Here is the maps response", response.json.results)
var obj = {
name: "Thabo",
age: 23,
maps: response.json.results
};
res.json({obj});
}
});
}
The Angular2 services looks like this
#Injectable()
export class MyService {
constructor(private http: Http) { }
getMessage(): Promise<mma> {
return this.http.get('/map-moving-agents')
.toPromise()
.then((res)=> {
console.dir(res.json().maps);
return res.json().obj;
})
.catch(this.handleError);
}
Everything seems to be fine, I get the expected response from the server, now i would like to use this response to draw a map on my component template.
And then here is my AngularJS2 component
#Component({
moduleId:module.id,
selector: 'map-moving-agents',
templateUrl: 'moving-agents.html',
styleUrls: ['moving-agents.css'],
providers: [ MyService ]
})
export class MapMovingAgents implements OnInit{
msg : mma;
constructor(private myService: MyService ){}
getMessage(): void {
this.myService.getMessage().then((res) => {
this.msg = res;
console.log(this.msg.name);
})
}
ngOnInit(): void {
this.getMessage();
}
}
I have used the angular2-google-maps package, i now have this In my component class
export class MapMovingAgents implements OnInit{
map: any;
lat: number;
lng: number;
zoom: number = 18;
constructor(private myService: MyService ){}
getMessage(): void {
this.myService.getMessage().then((res) => {
this.map = res;
this.lat = this.map.maps[0].geometry.location.lat;
this.lng = this.map.maps[0].geometry.location.lng;
console.log(this.lat,this.lng);
})
}
And have this in my tempate
<sebm-google-map [latitude]="lat" [longitude]="lng" [zoom]="zoom">
<sebm-google-map-marker [latitude]="lat" [longitude]="lng"></sebm-google- map-marker>
</sebm-google-map>
I have also updated my app module by importing the module and passed it the api key
import { AgmCoreModule } from 'angular2-google-maps/core';
imports: [... AgmCoreModule.forRoot({
apiKey: 'AIzMSNPY'
})...]
You can read through the angular2-google-maps here