Generate Heat-map with lat-lng in angularjs - angularjs

I am using angularjs with mongodb.
I have table which contains user coordinates.
{ "mac" : "aa:22:01:d2:e6:f9","lat" : 33.53625,"lng" : -111.92674, "time" : 2017-07-12T04:44:13.707Z}
{ "mac" : "aa:22:01:d2:e6:f9","lat" : 33.53625,"lng" : -111.92674, "time" : 2017-07-12 04:44:13.707Z}
{ "mac" : "aa:22:01:d2:e6:f9","lat" : 33.53625,"lng" : -111.92674, "time" : 2017-07-12 04:46:59.707Z}
{ "mac" : "aa:22:01:d2:e6:f9","lat" : 33.53625,"lng" : -111.92674, "time" : 2017-07-12 04:47:29.707Z}
I want to display heat map. can anyone point me the best way to achieve this.
I'll have building image which i need to adjust in background later.

Basically you need to map your data to an array of google.maps.LatLng objects. Then init the map, init heatmap layer with mapped data and assign heatmap layer to the map. Check the sample
You need also to include the visualization library, because HeatmapLayer is there.
function initMap() {
/* Data points defined as an array of LatLng objects */
var data = [{
"mac": "aa:22:01:d2:e6:f9",
"lat": 33.53625,
"lng": -111.92674,
"time": '2017-07-12T04:44:13.707Z'
}, {
"mac": "aa:22:01:d2:e6:f9",
"lat": 33.53625,
"lng": -111.92674,
"time": '2017-07-12 04:44:13.707Z'
}, {
"mac": "aa:22:01:d2:e6:f9",
"lat": 33.53625,
"lng": -111.92674,
"time": '2017-07-12 04:46:59.707Z'
}, {
"mac": "aa:22:01:d2:e6:f9",
"lat": 33.53625,
"lng": -111.92674,
"time": '2017-07-12 04:47:29.707Z'
}];
var heatmapData = data.map(function(item) {
return new google.maps.LatLng(item.lat, item.lng)
});
var center = new google.maps.LatLng(33.53625, -111.92674);
map = new google.maps.Map(document.getElementById('map'), {
center: center,
zoom: 13,
mapTypeId: 'satellite'
});
var heatmap = new google.maps.visualization.HeatmapLayer({
data: heatmapData
});
heatmap.setMap(map);
}
.as-console-wrapper{
display:none !important;
}
<script async defer type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=false&libraries=visualization&callback=initMap"></script>
<div id="map" style="width:500px;height:150px"></div>

Related

$loaded is not working properly when the server data is changed

I am new to firebase and angularjs. For my sales application I would like to use both. So, in my app I am using AngularJS v1.5.8 + Firebase v3.3.0 + AngularFire 2.0.2. I have sales and users objects in firebase db, and has a business logic that one user can sell multiple products, but one product can have only one owner (user).
Here is the users and sales objects in database:
{
"sales" : {
"-KQlb5N6A9rclc5qcWGD" : {
"price" : 8,
"quantity" : {
"count" : 12,
"type" : "porsiyon"
},
"status" : "sale",
"title" : "Patlicanli Borek",
"user" : "-KQ52OJd-lwoDIWzfYFT"
},
"-KQlcScsq8cidk7Drs04" : {
"price" : 12,
"quantity" : {
"count" : 10,
"type" : "porsiyon"
},
"status" : "sale",
"title" : "Deneme",
"user" : "-KQ5-mZBt6MhYy401gGM"
},
"-KQzXHwOv2rC73scjV46" : {
"price" : 12,
"quantity" : {
"count" : 11,
"type" : "porsiyon"
},
"status" : "sale",
"title" : "Pacanga",
"user" : "-KQ5-mZBt6MhYy401gGM"
},
"-KSCBgpArtnKunUuEuVr" : {
"price" : 15,
"quantity" : {
"count" : 15,
"type" : "porsiyon"
},
"status" : "sale",
"title" : "Iskembe",
"user" : "-KQ52OJd-lwoDIWzfYFT"
}
},
"users" : {
"-KQ5-mZBt6MhYy401gGM" : {
"address" : "Halkali kucukcekmece",
"email" : "burak.kahraman#gmail.com",
"name" : "Burak Hero",
"nick" : "Burak'in Mutfagi"
},
"-KQ52OJd-lwoDIWzfYFT" : {
"address" : "Izmir kaynaklar",
"email" : "ayse#gmail.com",
"name" : "Ayse Kahraman",
"nick" : "Ayse'nin Mutfagi"
}
}
}
What I want to do is when my app is opened, it will show all sales together with corresponding user details. (just like main page of letgo application) Which means I should implement a simple join between sales and users objects. As far as I searched throughout internet and api docs, there is no way to implement this kind of join in a single call to firebase. (Pl correct me if I am wrong) So I used below method with using $loaded function inside of my SalesService to implement join.
angular.
module('core.sales')
.service('SalesService', function ($firebaseArray, $firebaseObject, UsersService) {
this.getAllSalesJoin = function () {
var sales;
var refSales = firebase.database().ref('sales');
sales = $firebaseObject(refSales);
sales.$loaded()
.then(function () {
angular.forEach(sales, function (sale) {
var saleUser = UsersService.getUserDetail(sale.user);
saleUser.$loaded()
.then(function () {
sale.user = saleUser;
});
});
});
return sales;
};
});
As you see I am fetching all sales, after it finishes, looping for each sale to get and set related user detail by calling another UsersService shown below
angular.
module('core.users')
.service('UsersService', function ($firebaseArray,$firebaseObject) {
this.getUserDetail = function (userId) {
var user;
var refUser = firebase.database().ref('users/'+userId);
user = $firebaseObject(refUser);
return user;
};
});
So far so good, when I call SalesService.getAllSalesJoin function within my Controller and print the JSON object using <pre>{{$ctrl.allSales | json}}</pre>, everything works as I wanted, below is the Controller code and printed JSON object in the template.
angular.
module('saleList').
component('saleList', {
templateUrl: 'MCTs/sale-list/sale-list-template.html',
controller: ['SalesService','UsersService', function SaleListController(SalesService,UsersService,$scope) {
this.allSales = SalesService.getAllSalesJoin();
}]
});
Template shows the merged objects
{
"$id": "sales",
"$priority": null,
"-KQlb5N6A9rclc5qcWGD": {
"price": 8,
"quantity": {
"count": 12,
"type": "porsiyon"
},
"status": "sale",
"title": "Patlicanli Borek",
"user": {
"$id": "-KQ52OJd-lwoDIWzfYFT",
"$priority": null,
"address": "Izmir kaynaklar",
"email": "ayse#gmail.com",
"name": "Ayse Kahraman",
"nick": "Ayse'nin Mutfagi"
}
},
"-KQlcScsq8cidk7Drs04": {
"price": 12,
"quantity": {
"count": 10,
"type": "porsiyon"
},
"status": "sale",
"title": "Deneme",
"user": {
"$id": "-KQ5-mZBt6MhYy401gGM",
"$priority": null,
"address": "Halkali kucukcekmece",
"email": "burak.kahraman#gmail.com",
"name": "Burak Hero",
"nick": "Burak'in Mutfagi"
}
},
.....
But the problem is, when server data is changed (new sale is entered or old one is deleted), angular automatically understands the change but it applies the change to the view without implementing or calling my joined function, it simply prints only the sales object not the merged one with users. Below is the showing object after server data is changed.
{
"$id": "sales",
"$priority": null,
"-KQlb5N6A9rclc5qcWGD": {
"price": 8,
"quantity": {
"count": 12,
"type": "porsiyon"
},
"status": "sale",
"title": "Patlicanli Borek",
"user": "-KQ52OJd-lwoDIWzfYFT"
},
"-KQlcScsq8cidk7Drs04": {
"price": 12,
"quantity": {
"count": 10,
"type": "porsiyon"
},
"status": "sale",
"title": "Deneme",
"user": "-KQ5-mZBt6MhYy401gGM"
},
....
I am confused why it behaves like that? Is my way to implement join using $loaded wrong? Or should I use another method to implement this kind of join? I am looking forward to see your priceless suggestions and ideas.
$loaded() only fires when the initial data has loaded. From the reference documentation (emphasis mine):
Returns a promise which is resolved when the initial object data has been downloaded from the database.
This is the main reason I often say: "if you're using $loaded(), you're doing it wrong".
You're right about needing to join data with multiple calls. In AngularFire you can extend $firebaseArray to perform such an operation. For a great example of how to do this, see this answer by Kato: Joining data between paths based on id using AngularFire
Thank for the guide #Frank. I read all your suggestions and found the solution. For contributing stackoverflow knowledge and to help others here is the complete solution for the problem.
I first created a new factory that extends $firebaseArray and override $$added and $$updated methods to perform join to Users object each time when the data is updated or added.
angular.
module('core.sales').factory("SalesFactory", function ($firebaseArray, Sales) {
return $firebaseArray.$extend({
$$added: function (snap) {
return new Sales(snap);
},
$$updated: function (snap) {
return this.$getRecord(snap.key).update(snap);
}
});
});
angular.
module('core.sales').factory("Sales", function ($firebaseArray, $firebaseObject) {
var refUsers = firebase.database().ref('users');
function Sales(snapshot) {
this.$id = snapshot.key;
this.update(snapshot);
}
Sales.prototype = {
update: function (snapshot) {
var oldTitle = angular.extend({}, this.title);
var oldPrice = angular.extend({}, this.price);
var oldQuantity = angular.extend({}, this.quantity);
this.userId = snapshot.val().user;
this.title = snapshot.val().title;
this.status = snapshot.val().status;
this.price = snapshot.val().price;
this.quantity = snapshot.val().quantity;
this.userObj = $firebaseObject(refUsers.child(this.userId));
if (oldTitle == this.title && oldPrice == this.price &&
oldQuantity.count == this.quantity.count && oldQuantity.type == this.quantity.type)
return false;
return true;
},
};
return Sales;
});
As you see, SalesFactory uses another factory called Sales. In that particular factory I retrieve all properties of Sales object and assign each of them to its corresponding property. And that is the case I am performing join to Users object by creating new property : this.userObj
One thing is missing that is just calling the new Factory instead of $firebaseArray
this.getAllSalesArray = function () {
var sales;
var refSales = firebase.database().ref('sales');
sales = SalesFactory(refSales);
return sales;
};
All in all, all Sales object joined with related User is printed to the view is,
[
{
"$id": "-KQlb5N6A9rclc5qcWGD",
"userId": "-KQ52OJd-lwoDIWzfYFT",
"title": "Patlicanli Borek",
"status": "sale",
"price": 12,
"quantity": {
"count": 11,
"type": "tabak"
},
"userObj": {
"$id": "-KQ52OJd-lwoDIWzfYFT",
"$priority": null,
"address": "İzmir kaynaklar",
"email": "ayse#gmail.com",
"name": "Ayşe Kahraman",
"nick": "Ayşe'nin Mutfağı"
}
},
{
"$id": "-KQlcScsq8cidk7Drs04",
"userId": "-KQ5-mZBt6MhYy401gGM",
"title": "Deneme",
"status": "sale",
"price": 12,
"quantity": {
"count": 10,
"type": "porsiyon"
},
"userObj": {
"$id": "-KQ5-mZBt6MhYy401gGM",
"$priority": null,
"address": "Halkalı küçükçekmece",
"email": "burak.kahraman#gmail.com",
"name": "Burak Hero",
"nick": "Burak'ın Mutfağı"
}
},
...
]

How can I change the attribute in dataset of Fusionchart?

Hi I am implementing a chart in my Angularjs Application, You can see this plunker http://jsfiddle.net/fusioncharts/73xgmacm/ The thing which I want to achieve is to change the value attribute to profit. How can I do this ? I want to display profit not values.
Regards
After 2 days I finally find out the answer. The thing is You cannot change the Fusionchart attribute value but you can change the attribute of your API once you fetched. I used a loop after I fetched the API and replace the 'profit' attribute with value in this way I made the chart. Yes The thing which i had been ignoring was the use of 'variable' instead of scope. If you see this example you would understand Example Here. I am sharing my code May be it helps someone else too.
Give below is my json array which i called tps.json
[
{
"index": "1",
"variantoption": "fan-green",
"company": "sk fans",
"quantity": "650",
"profit": "78296",
"loss": "8457",
"year": "2016"
},
{
"index": "2",
"variantoption": "fan-white",
"company": "al ahmed fans",
"quantity": "450",
"profit": "78296",
"loss": "8457",
"year": "2016"
},
{
"index": "3",
"variantoption": "fan-purple",
"company": "asia fans",
"quantity": "350",
"profit": "78296",
"loss": "8457",
"year": "2016"
},
{
"index": "4",
"variantoption": "fan-yellow",
"company": "falcon fans",
"quantity": "250",
"profit": "78296",
"loss": "8457",
"year": "2016"
}
]
and here is my controller
$http.get('js/tps.json').success(function (data) {
var chartdata = data;
var arrLength = chartdata.length;
console.log(arrLength);
for (var i = 0; i < arrLength; i++) {
if (chartdata[i]['profit'] && chartdata[i]['index']) {
chartdata[i].value = chartdata[i].profit;
delete chartdata[i].profit;
chartdata[i].label = chartdata[i].index;
delete chartdata[i].index;
console.log(chartdata);
}
}
console.log(chartdata);
FusionCharts.ready(function () {
var tps = new FusionCharts({
type: 'column2d',
renderAt: 'chart-container',
width: '500',
height: '300',
dataFormat: 'json',
dataSource: {
"chart": {
"caption": "Monthly",
"xaxisname": "Month",
"yaxisname": "Revenue",
"numberprefix": "$",
"showvalues": "1",
"animation": "1"
},
"data" : chartdata
}
});
tps.render();
});
}
);
}
-Stay foolish stay hungry

Bind to AngularJS Service property

I have a web page which uses a custom service to manage a map on the View (OpenLayers). I want to be able to display information about different markers on the page somewhere which means binding to a service property. The service is being called from a custom directive, and the binding (as far as I know) should be done from the Controller. The data being shown at the moment is the initialised object rather than binding to any changes to that object.
main.html
<h2>My Map</h2>
<div id="map" class="map"></div>
<p>
Name: {{selected.name}}</br>
Routers: {{selected.routers}}</br>
Switches: {{selected.switches}}
</p>
main.ctrl.js
angular.module("app").controller("MainController", function($scope, openlayers){
openlayers.init();
$scope.selected = openlayers.selected;
});
openlayers.js
angular.module("app").factory("openlayers", function(){
var init = function(){
var vectorLayers = [new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'osm'})
})];
vectorLayers.push(createMapLayer("red"));
vectorLayers.push(createMapLayer("orange"));
vectorLayers.push(createMapLayer("blue"));
setUpMap(vectorLayers);
};
var activeVector = {
name: null,
routers: null,
switches: null
};
function createMapLayer(markerColor){
var vectorSource = getVectorSource();
//add the feature vector to the layer vector, and apply a style to whole layer
var vectorLayer = new ol.layer.Vector({
source: getVectorSource(cities[markerColor]),
style: getIconStyle(markerColor)
});
return vectorLayer;
}
function getVectorSource(cities){
var vectorSource = new ol.source.Vector({
//create empty vector
});
//create a bunch of icons and add to source vector
for (var index in cities){
var city = cities[index];
var iconFeature = new ol.Feature({
geometry: new ol.geom.Point(
ol.proj.transform(
[city.lon, city.lat],
'EPSG:4326',
'EPSG:3857'
)),
name: city.name,
routers: 200,
switches: 100
});
vectorSource.addFeature(iconFeature);
}
return vectorSource;
}
function getIconStyle(markerColor){
//create the style
return new ol.style.Style({
image: new ol.style.Icon(/** #type {olx.style.IconOptions} */ ({
anchor: [0.5, 46],
anchorXUnits: 'fraction',
anchorYUnits: 'pixels',
opacity: 0.75,
src: "Images/"+markerColor+"-marker.png"
}))
});
}
function setUpMap(vectorLayers){
var map = new ol.Map({
target: 'map',
layers: vectorLayers,
view: new ol.View({
center: ol.proj.fromLonLat([2.808981, 46.609599]),
zoom: 4
})
});
addClickEventsToMapItems(map);
}
function addClickEventsToMapItems(map){
var interaction = new ol.interaction.Select({
condition: ol.events.condition.click
});
map.addInteraction(interaction);
interaction.on("select", function(e){
activeVector.name = e.target.getFeatures().item(0).get("name");
activeVector.routers = e.target.getFeatures().item(0).get("routers");
activeVector.switches = e.target.getFeatures().item(0).get("switches");
});
}
return {
init: init,
selected: activeVector
};
});
var red_cities = [
{ "lat": 40.462663, "lon": -3.626368, "name": "madrid" },
{ "lat": 53.381129, "lon": -1.470085, "name": "sheffield" },
{ "lat": 48.856614, "lon": 2.352222, "name": "paris" }
];
var orange_cities = [
{ "lat": 53.480759, "lon": -2.242631, "name": "manchester" },
{ "lat": 53.551085, "lon": 9.993682, "name": "hamburg" },
{ "lat": 50.850340, "lon": 4.351710, "name": "brussels" }
];
var blue_cities = [
{ "lat": 43.552847, "lon": 7.017369, "name": "cannes" },
{ "lat": 51.507351, "lon": -0.127758, "name": "london" },
{ "lat": 52.370216, "lon": 4.895168, "name": "amsterdam" },
{ "lat": 36.140751, "lon": -5.353585, "name": "gibraltar" }
];
var cities = {
red: red_cities,
orange: orange_cities,
blue: blue_cities
};
EDIT: Removed the directive to simplify the code.

Leaflet - Convert lat/lng to standard projection

How to convert coordinates from Leaflet coordinate system to coordinate system that Google uses (WGS-84?), if the data are in an external file (geojson)?
In example with external geojson file, I've defined coordinates for Paris and Zagreb and I'm looking for solution to transform these coordinates to accurate location :)
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"id": "par",
"properties": {
"name": "Paris"
},
"geometry": {
"type": "Point",
"coordinates": [
48.858093,
2.294694
]
}
},
{
"type": "Feature",
"id": "zg",
"properties": {
"name": "Zagreb"
},
"geometry": {
"type": "Point",
"coordinates": [
45.815399,
15.966568
]
}
}
]
}
There is Proj4js JavaScript library, but I cannot find similar example for this case (with external file).
Your GeoJSon can be used directly by Leaflet without converting the lat/lng.
I use google maps to get GPS lat/lng of some point and use them in Leaflet without conversion.
// Edit
For me Leaflet and Google maps use the same projection.
//EDIT 2
Html :
<div id="map" class="leaflet-container leaflet-fade-anim"></div>
JS :
var map=L.map( "map" ,{
center:[0,0],
zoom:1, minZoom: 1 , maxZoom:18
});
var base_maps = [];
var layer_OSM = new L.TileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
noWrap: true,
// continuousWorld: true,
attribution: '© OpenStreetMap contributors',
unloadInvisibleTiles: true
});
base_maps['OpenStreetMap'] = layer_OSM;
map.addLayer(layer_OSM);
var markersLayer = new L.FeatureGroup();
var marker = L.marker([p_lat, p_lon]);
markersLayer.addLayer(marker);
map.addLayer(markersLayer);

Angular-Leaflet-Directive + JSON markers

Try create Leaflet Map with clustering markers in my app. Using for this Angular Leaflet Directive plugin.
It's work with example controller and JSON data, but I have other JSON with other data format and have problem with get lattitude and longitude parameters for creating markers array on my map.
My Controller
app.controller("BasicFirstController", [ "$scope", "$http", function($scope, $http) {
var addressPointsToMarkers = function(points) {
return points.map(function(ap) {
return {
layer: 'realworld',
lat: ap[0],
lng: ap[1],
message: ap[2]
};
});
};
angular.extend($scope, {
center: {
lat: 53.13207624721133,
lng: 26.01689853383789,
zoom: 15
},
events: {
map: {
enable: ['moveend', 'popupopen'],
logic: 'emit'
},
marker: {
enable: [],
logic: 'emit'
}
},
layers: {
baselayers: {
osm: {
name: 'OSM',
url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
type: 'xyz'
},
overlays: {
realworld: {
name: "Real world data",
type: "markercluster",
visible: true
}
}
}
});
$http.get("sample.json").success(function(data) {
$scope.markers = addressPointsToMarkers(data);
});
}]);
Work with this JSON format
[
[-37.8839, 175.3745188667, "571"],
[-37.8869090667, 175.3657417333, "486"],
[-37.8894207167, 175.4015351167, "807"],
[-37.8927369333, 175.4087452333, "899"],
[-37.90585105, 175.4453463833, "1273"]
]
Need work with this JSON format
{
"posts": [
{
"ID": "1",
"title": "Title",
"tag": "tag1",
"lat": "53.11691211703813",
"lng": "26.03631556034088",
"thumb": "getImage-24-100x100.jpg",
"fullimg": "getImage-24.jpg",
"imgs": [
{
"imgurl": "getImage-24-300x200.jpg"
}
],
"place": "Place",
"type": "Photo",
"period": "War",
"year": "1985",
"url": "site.com",
"author": "author"
},
{
"ID": "2",
"title": "Title2",
"tag": "tag2",
"lat": "53.11691211703813",
"lng": "26.03631556034088",
"thumb": "getImage-24-100x100.jpg",
"fullimg": "getImage-24.jpg",
"imgs": [
{
"imgurl": "getImage-24-300x200.jpg"
}
],
"place": "Place",
"type": "Photo",
"period": "War",
"year": "1935",
"url": "site.com",
"author": "author"
}
]
}
How get data with lat and lng from JSON for markers array?
Here is what worked for me with a JSON file sent from server, to publish ALL markers at once:
Then with $HTTP I can "get" the data, but you will have to loop through it and push details to a new $scope array:
$scope.markers = []
$http.get('JSONfilePath').then(function (responseData) {
for (var i = 0; i < responseData.data.length; i++){
$scope.markers.push({
lat: responseData.data[i].latitude,
lng: responseData.data[i].longitude
})
}
})
In the HTML file, it's pretty straight forward:
<leaflet lf-center="center" defaults="defaults" markers="markers" width="90%" height="800px"></leaflet>

Resources