NgMap and Heatmap with async data - javascript

I'm having trouble consolidating NgMaps and the Heatmaps from Google Maps API.
If I load the data from a script tag, it works fine just like in the NgMap example.
But if I try to create the data array locally, it won't work and it will give me an invalid heatmap data <heatmap-layer id="foo" data="pointArray"> error.
The aim is to be able to update the array on the fly, and to update the map and the heatmap when necessary.
This is what I've tried so far:
HTML:
<ng-map center="21.088513,92.197204" zoom="16" map-type-id="SATELLITE" >
<heatmap-layer id="foo" data="pointArray"></heatmap-layer>
</ng-map>
AngularJS:
$scope.outbreak = [
[21.088, 92.19862],
[21.08866, 92.19874],
[21.08869, 92.19872],
[21.08865, 92.19875],
[21.08765, 92.19865],
[21.08752, 92.1981],
[21.08853, 92.19803],
[21.08883, 92.19724],
[21.08896, 92.19658],
[21.08888, 92.19656],
[21.08718, 92.19678],
[21.08965, 92.19624],
[21.08977, 92.19625],
[21.08958, 92.19656],
[21.08999, 92.19677],
[21.09024, 92.19709],
[21.09059, 92.19672],
[21.09092, 92.19645],
[21.09088, 92.19643],
[21.09083, 92.19574]
];
$scope.renderHeatMap = function() {
var heatmap, vm = this;
NgMap.getMap().then(function(map) {
var outbreakfin = [];
for (var i in $scope.outbreak) {
outbreakfin.push(new google.maps.LatLng($scope.outbreak[i][0], $scope.outbreak[i][1]));
};
var pointArray = new google.maps.MVCArray(outbreakfin);
heatmap = map.heatmapLayers.foo;
heatmap = new google.maps.visualization.HeatmapLayer({
data: pointArray
});
heatmap.setMap(map);
});
};
I get the feeling that the heatmap layer is not loaded when is it supposed to.
What am I missing?

You are getting the following error
invalid heatmap data
since pointArray array needs to be defined in scope of controller:
$scope.pointArray = [];
Secondly, there is no need to create the instance of HeatmapLayer:
heatmap = new google.maps.visualization.HeatmapLayer({
data: pointArray
});
heatmap.setMap(map);
since it is getting created within heatmapLayer directive and could be accessed from controller like this in your case:
heatmap = map.heatmapLayers.foo;
Modified example
angular.module('mapApp', ['ngMap'])
.controller("MapCtrl", function ($scope, $http, NgMap) {
$scope.pointArray = [];
$scope.outbreak = [
[21.088, 92.19862],
[21.08866, 92.19874],
[21.08869, 92.19872],
[21.08865, 92.19875],
[21.08765, 92.19865],
[21.08752, 92.1981],
[21.08853, 92.19803],
[21.08883, 92.19724],
[21.08896, 92.19658],
[21.08888, 92.19656],
[21.08718, 92.19678],
[21.08965, 92.19624],
[21.08977, 92.19625],
[21.08958, 92.19656],
[21.08999, 92.19677],
[21.09024, 92.19709],
[21.09059, 92.19672],
[21.09092, 92.19645],
[21.09088, 92.19643],
[21.09083, 92.19574]
];
$scope.renderHeatMap = function () {
NgMap.getMap().then(function (map) {
var outbreakfin = [];
for (var i in $scope.outbreak) {
outbreakfin.push(new google.maps.LatLng($scope.outbreak[i][0], $scope.outbreak[i][1]));
};
$scope.pointArray = new google.maps.MVCArray(outbreakfin);
heatmap = map.heatmapLayers.foo;
heatmap.setData($scope.pointArray);
});
};
$scope.renderHeatMap();
});
<script src="https://maps.google.com/maps/api/js?libraries=visualization"></script>
<script src="https://code.angularjs.org/1.3.15/angular.js"></script>
<script src="https://rawgit.com/allenhwkim/angularjs-google-maps/master/build/scripts/ng-map.js"></script>
<div ng-app="mapApp" ng-controller="MapCtrl">
<ng-map center="21.088513,92.197204" zoom="16" map-type-id="SATELLITE" >
<heatmap-layer id="foo" data="pointArray"></heatmap-layer>
</ng-map>
</div>

Related

How can I change data element on Vue.js?

<div id="SearchAddress">
<div class="main_class">
<div class="find_juso_map">
<input type="button" v-on:click="load_juso" value="주소 검색"><br>
<div id="map" style="width:300px;height:300px;margin-top:10px;"></div>
<input type="text" id="sample5_address" placeholder="메모">
<input type="button" v-on:click="add_place" value="장소 추가"><br>
</div>
<div class="set_juso_list">
<h4>요기조아</h4>
<div></div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'SearchAddress',
data() {
return {
center: new window.kakao.maps.LatLng(33.450701, 126.570667),
geocoder: new window.kakao.maps.services.Geocoder(),
joah_add: null,
joah_list: {}
}
},
props: {
},
mounted () {
var container = document.getElementById('map');
var options = {
center: this.center,
level: 3
};
new window.daum.maps.Map(container, options);
},
methods: {
load_juso() {
new window.daum.Postcode({
oncomplete: function(data) {
var addr = data.address; // 최종 주소 변수
console.log(addr,'주소')
this.joah_add = addr;
console.log(this.joah_add ,'조아조아')
// // 주소로 상세 정보를 검색
new window.kakao.maps.services.Geocoder().addressSearch(data.address, function(results, status) {
// 정상적으로 검색이 완료됐으면
if (status === window.daum.maps.services.Status.OK) {
var result = results[0]; //첫번째 결과의 값을 활용
// 해당 주소에 대한 좌표를 받아서
var coords = new window.daum.maps.LatLng(result.y, result.x);
// 지도를 보여준다.
var container = document.getElementById('map');
var map = new window.daum.maps.Map(container, {center: coords,level: 3});
container.style.display = "block";
map.relayout();
map.setCenter(coords);
new window.daum.maps.Marker({position: coords, map: map}).setPosition(coords);
}
});
}
}).open();
},
add_place() {
console.log('장소추가',this.joah_add)
}
}
}
</script>
I want to put joah_add data in the load_juso() and call it in the add_place.
first, I called load_juso() method.
I think, 'this.joah_add = addr;' <- this code can access data and set data: joah_add value.
second, I called add_place method.
why console print joah_add data -> null??
why doesn't it come out like 'this.joah_add = addr'?
please help me :'(
Javascript's this is not bound from the start
but is bound at the time of the call
So your this.joah_add = addr; of this
may be pointing to daum instead of vue
Javascript's this in normal function mode
points to whoever calls it
So
new window.daum.Postcode({... this.joah_add = addr})
could be equivalent to
new window.daum.Postcode({... daum.joah_add = addr})
and not
new window.daum.Postcode({... vue.joah_add = addr})
And your
add_place() {
console.log('장소추가',this.joah_add)
}
should be
add_place() {
console.log('장소추가',vue.joah_add)
}
So here's what you might need to do
load_juso() {
const that = this
new window.daum.Postcode({… that.joah_add = addr;...})
...
}
Hope it can help you

AngularJS: How to change data in ng-repeat upon model change in service

I try to update the info shown in a "ng-repeat"-div when the connected variable changes in a service. According to this fiddle by Ian Brown the data in the HTML code should be updated every time when the BikeService.bikes variable is changed. When I open the website in my browser (Browser A), then adding bikes works perfectly (locally and remotely). Now I open the page with another browser (Browser B) on either my own machine or another machine. Also in that browser everything works perfectly, when bikes are added from THAT browser. Here my code:
HTML
<div ng-app"ubobApp">
<!--For testing purposes I added 2 buttons each adding a new bike.
One does so "locally", i.e. within the browser, and the other does
it "remotely" by communicating with a MongoDB-controller using a web socket-->
<div ng-controller="buttonCtrl">
<md-button class="primary" ng-click="localAddRandomBike()">
Local: Add Random Bike
</md-button>
<md-button class="primary" ng-click="remoteAddRandomBike()">
Remote: Add Random Bike
</md-button>
</div>
<!--Here the data is displayed using the GoogleMaps API-->
<md-content flex ng-controller="MapCtrl">
<ng-map center="[53.219, 6.567]" zoom="13" id="map">
<marker ng-repeat="bike in service.bikes"
icon={{image}}
title="Title"
position="{{bike.lon}}, {{bike.lat}}"
z-index="1"
></marker>
</ng-map>
</md-content>
</div>
Javascript
var ubob = angular.module('ubobApp', ['ngMap']);
ubob.service('BikeService', function() {
this.bikes = [
new Bike(53.224, 6.558, true)
];
this.addBike = function(bike) {
this.bikes.push(bike);
};
}
ubob.service('WebsocketService', function (BikeService) {
var socket = new WebSocket(...url...);
socket.onmessage = onMessage;
this.onMessage = function(event) {
var message = JSON.parse(event.data);
switch (message.action) {
case "addBike":
var bike = new Bike(message.lon, message.lat, message.available);
BikeService.addBike(bike);
break;
...Some other cases...
}
}
this.addRandomBike = function (bike) {
var data = {
action: "addBike",
lon: bike.lon,
lat: bike.lat,
available: bike.available
};
socket.send(JSON.stringify(data));
}
});
ubob.controller('buttonCtrl', function ($scope, BikeService, WebsocketService) {
$scope.localAddRandomBike = function() {
var lon = getRandomArbitrary(53.15, 53.25);
var lat = getRandomArbitrary(6.55, 6.57);
BikeService.addBike(new Bike(lon, lat, true));
};
$scope.remoteAddRandomBike = function () {
var lon = getRandomArbitrary(53.15, 53.25);
var lat = getRandomArbitrary(6.54, 6.58);
WebsocketService.addRandomBike(new Bike(lon, lat, true))
}
});
ubob.controller('MapCtrl', function($scope, BikeService) {
$scope.image = {url: 'img/bike64.png', ...otherConfig...};
$scope.service = BikeService;
});
Now comes the weird part; Bikes should also be displayed in Browser A when they are added in Browser B. That does not happen. Browser A receives the object and also adds it to the BikeService.bikes-array, but it does not display it. I have then to click on either one of the "Add Bike" buttons and then the bike created in Browser B is shown together with the bike which was just created in Browser A.
I have the slight suspicion that it has something to do with asynchronous modification of the BikeService.bikes variable, but I'm not sure. Any other suggestions, please? :-)
I think your problem comes from the wrong use of this
ubob.service('BikeService', function() {
var self = this;
self.bikes = [
new Bike(53.224, 6.558, true)
];
self.addBike = function(bike) {
self.bikes.push(bike);
};
}

knockout.js Observable array, error "Uncaught ReferenceError: Unable to process binding "

I am using JS Knockout for displaying Search results from the Four Square API.
I have this View Model in my Javascript code
var ViewModel = function(){
var self = this;
// Foursquare API Call :
this.foursquareURL = 'https://api.foursquare.com/v2/venues/search?ll=37.8,-122.4&query=croissant&client_id=CLIENT_ID&client_secret=CLIENT_SECRET';
this.fs_ApiCall = function()
{
$.getJSON(foursquareURL, function(data){
$foursquareElem.text('Get a croissant');
var venues = data.response.venues;
self.venueList = ko.observableArray([]);
for (var i=0; i<venues.length; i++){
self.venueList.push ({
name: venues[i].name,
lat: venues[i].location.lat,
lng: venues[i].location.lng
});
}
}).error(function() {
$foursquareElem.text( "No data available" );
});
};
};
ko.applyBindings(new ViewModel());
This is how I apply the binding in the HTML doc
<div id="foursquare-venues">
<ul data-bind= "foreach:venueList">
<li id="li-name" data-bind = "text:name">
</li>
</ul>
Uncaught ReferenceError: Unable to process binding "foreach: function (){return venueList }"
Message: venueList is not defined
I was not sure if I did use the right way to push the API response in an API , but the error message seems to say that the array isn’t even defined (?)
I am not sure what is going wrong here.
That is because you instanciate venueList in the getJSON callback, which is invoked after bindings are applied.
You should instead do:
var ViewModel = function() {
var self = this;
self.venueList = ko.observableArray([]); // instanciate here
// Foursquare API Call :
this.foursquareURL = 'https://api.foursquare.com/v2/venues/search?ll=37.8,-122.4&query=croissant&client_id=CLIENT_ID&client_secret=CLIENT_SECRET';
this.fs_ApiCall = function() {
$.getJSON(foursquareURL, function(data) {
// you might want to clear venueList here
$foursquareElem.text('Get a croissant');
var venues = data.response.venues;
for (var i = 0; i < venues.length; i++) {
self.venueList.push({
name: venues[i].name,
lat: venues[i].location.lat,
lng: venues[i].location.lng
});
}
}).error(function() {
// and here
$foursquareElem.text("No data available");
});
};
};
ko.applyBindings(new ViewModel());
Instantiate the observableArray, venueList initially, so that it can be accessible in the html. Giving code below for the js.
var ViewModel = function() {
var self = this;
self.venueList = ko.observableArray([]);
this.foursquareURL = 'https://api.foursquare.com/v2/venues/search?ll=37.8,-122.4&query=croissant&client_id=CLIENT_ID&client_secret=CLIENT_SECRET';
this.fs_ApiCall = function()
{
$.getJSON(foursquareURL, function(data) {
// you might want to clear venueList here
$foursquareElem.text('Get a croissant');
var venues = data.response.venues;
for (var i = 0; i < venues.length; i++) {
self.venueList.push({
name: venues[i].name,
lat: venues[i].location.lat,
lng: venues[i].location.lng
});
}
}).error(function() {
// and here
$foursquareElem.text("No data available");
});
};
};
ko.applyBindings(new ViewModel());
Also in the HTML make the change for the text binding as below:-
<div id="foursquare-venues">
<ul data-bind= "foreach:venueList">
<li id="li-name" data-bind = "text: $data.name"> //Use $data.name instead of using just name.
</li>
</ul>
</div>
Use text : $data.name instead of using text : name.
Refer foreach binding for more knowledge.

angular-charts.js wont properly update with new data

the chart HTML
<!-- the data-component is a block where theres a chart
and a table. Since the table doesn't ever have issues,
it always displays the real async data...
but because the chart wont render my async data,
I start it off with some fake data so I can see it -->
<div class="data-component">
<canvas id="bar"
class="chart chart-bar"
data="data"
labels="labels">
<table>
... the real data ...
</table>
</div>
Initial (fake) data:
$scope.data= [
[1,2,3]
];
$scope.labels = [1,2,3];
$scope.series = ['field1'];
Results in this:
data update:
$http.get( _url )
.success(function(distribution) {
$scope.loading = false;
console.log(distribution);
var seriesData = [];
var labels = [];
for(var i in distribution)
{
var step = distribution[i];
//This is the data returned
//[{"segment":null,"count":308,"percentage":0.77},
//{"segment":1,"count":16346,"percentage":40.71},
//{"segment":2,"count":13186,"percentage":32.84},
//{"segment":3,"count":10309,"percentage":25.68}]
seriesData.push(step.count);
labels.push(step.segment || "null");
}
$scope.distribution = distribution;
$scope.data = [seriesData];
$scope.labels = labels;
$scope.series = ["Field2"];
})
.error(function() {});
results in this:
Does anyone know why async updates of the data causes it to render nothing at all?

YUI Datatable - "Data Error."

I'm trying to make a datatable using YUI with JSON returned data.
Included is the json returned data, and the page data displayed.
JSON Data:
[{"supplier_id":"127","name":"Adams Farms","description":"","ofarm":"1","active":"1"},{"supplier_id":"141","name":"Barriger Farms","description":"","ofarm":"1","active":"1"}]
Javascript for YUI:
<script type="text/javascript">
YAHOO.util.Event.addListener(window, "load", function() {
YAHOO.example.JSON = function() {
var myColumnDefs = [
{key:"supplier_id", label:"ID"},
{key:"name", label:"Name"},
{key:"description", label:"Notes"},
{key:"ofarm", label:"Ofarm"},
{key:"active", label:"Active"}
];
var myDataSource = new YAHOO.util.DataSource("ajax/select/supplier");
myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
myDataSource.responseSchema = {
fields: ["supplier_id","name","description","ofarm","active"]
};
var myDataTable = new YAHOO.widget.DataTable("json", myColumnDefs,
myDataSource);
return {
oDS: myDataSource,
oDT: myDataTable
};
}();
});
</script>
Page View:
YUI Test (header)
This example populates a DataTable with data. (intro text)
ID - Name - Notes - Ofarm - Active (column titles)
Data error. (returned data)
According to YUI dataSource page, YUI dataSource expectes an JavaScript object, not an array of objects. And when using JSON, use must set a resultsList on the responseSchema property. Something as (Notice dataSourceSettings.responseSchema.fields property)
(function() {
var YdataTable = YAHOO.widget.DataTable,
YdataSource = YAHOO.util.DataSource;
var settings = {
container:"<DATATABLE_CONTAINER_GOES_HERE>",
source:"<URL_TO_RETRIEVE_YOUR_DATA>",
columnSettings:[
{key:"supplier_id", label:"ID"},
{key:"name", label:"Name"},
{key:"description", label:"Notes"},
{key:"ofarm", label:"Ofarm"},
{key:"active", label:"Active"}
],
dataSourceSettings:{
responseType:YdataSource.TYPE_JSON,
responseSchema:{
resultsList:"<DOT_NOTATION_LOCATION_TO_RESULTS>",
fields:[
{key:"supplier_id"},
{key:"name"},
{key:"description"},
{key:"ofarm"},
{key:"active"}
]
}
},
dataTableSettings:{
initialLoad:false
}
}
var dataTable = new YdataTable(
settings.container,
settings.columnSettings,
new YdataSource(
settings.source,
settings.dataSourceSettings),
settings.dataTableSettings);
})();
As a side note, I found this page when looking for the cause of "Data error" in a YUI datatable, and I eventually found out that I was missing the /build/connection/connection-min.js script reference on my web page.

Categories