We're using an amcharts map, and so far, it all looks pretty good.
What I'm trying to do is change the color of the pins based on some value coming from our json stream.
javascript:
AmCharts.makeChart("mapdiv", {
"type": "map",
"theme": "light",
"imagesSettings": {
"rollOverColor": "#089282",
"rollOverScale": 1,
"selectedScale": 0.5,
"selectedColor": "#089282",
"color": "#13564e",
"selectable": false,
"bringForwardOnHover": false
},
"areasSettings": {
"color": "#D3D3D3",
"autoZoom": true
},
"data": {
"map": "puertoRicoHigh",
"getAreasFromMap": true
},
"dataLoader": {
"url": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/716619/30189.json",
"format": "json",
"showErrors": true,
"postProcess": function(data, config, map) {
// create a new dataProvider
var mapData = map.data;
// init images array
if (mapData.images === undefined)
mapData.images = [];
// create images out of loaded data
for(var i = 0; i < data.length; i++) {
var image = data[i];
image.type = "circle";
mapData.images.push(image);
}
return mapData;
}
}
});
That works well, but I would like to change the pins being displayed in the map. Ideally, I would like to use images (jpg, png, etc) that I've downloaded from the web.
So let's say that my json looks like this:
[{"title":"Site1","longitude":18.4262,"latitude":-67.1483,"inservice":true},
{"title":"Site2","longitude":18.3663,"latitude":-66.1887,"inservice":false}]
How can I change the pin color/size/font (or even image) so that if "inservice" is true, then use one pin. If it's false, then use another pin.
I tried using the SO snippet tool, but it's not rendering the map. So here it is, in jsfiddle: https://jsfiddle.net/wn61bfqb/
AmCharts.makeChart("mapdiv", {
"type": "map",
"theme": "light",
"imagesSettings": {
"rollOverColor": "#089282",
"rollOverScale": 1,
"selectedScale": 0.5,
"selectedColor": "#089282",
"color": "#13564e",
"selectable": false,
"bringForwardOnHover": false
},
"areasSettings": {
"color": "#D3D3D3",
"autoZoom": true
},
"data": {
"map": "puertoRicoHigh",
"getAreasFromMap": true
},
"dataLoader": {
"url": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/716619/30189.json",
"format": "json",
"showErrors": true,
"postProcess": function(data, config, map) {
// create a new dataProvider
var mapData = map.data;
// init images array
if (mapData.images === undefined)
mapData.images = [];
// create images out of loaded data
for(var i = 0; i < data.length; i++) {
var image = data[i];
image.type = "circle";
mapData.images.push(image);
}
return mapData;
}
}
});
#mapdiv {
width: 100%;
height: 300px;
<script src="https://www.amcharts.com/lib/3/ammap.js"></script>
<script src="https://www.amcharts.com/lib/3/maps/js/puertoRicoHigh.js"></script>
<script src="https://www.amcharts.com/lib/3/plugins/export/export.min.js"></script>
<link rel="stylesheet" href="https://www.amcharts.com/lib/3/plugins/export/export.css" type="text/css" media="all" />
<script src="https://www.amcharts.com/lib/3/themes/light.js"></script>
<script src="https://www.amcharts.com/lib/3/plugins/dataloader/dataloader.js"></script>
<div id="mapdiv"></div>
Thanks.
inside the dataLoader function where your are looping through the datasets add a check if inservice is true. Based on this check add a color.
for (var i = 0; i < data.length; i++) {
var image = data[i];
image.type = "circle";
if(data[i].inservice){
image.color = 'green'; // if inservice is true
} else {
image.color = 'red'; // if inservice is false or undefined
}
mapData.images.push(image);
}
I noticed that the end point you are calling to create this map is not returning inservice field yet. So till then we end up showing red pin all the time.
jsFiddle link
Related
I have the following code but when I click on a point to open a popup it returns 'undefined' and I cannot seem to work out why.
I'm pulling the description field from the geoJSON external source which I have control over but for some reason it just does not want to populate the description HTML in my array. I took the example for the popup from the mapbox website so I know it works there. I have checked, rechecked and triple checked but I think I cannot see the tree for the forest lol.
Could someone maybe help me please? thanks.
<script>
// ajax loading gif
$(document).ready(function () {
setTimeout(function () {
$("#ajax-loader").removeClass("is-active");
}, 6000);
});
// vars
var initialOpacity = 0.2;
var opacity = initialOpacity;
// mapbox api
mapboxgl.accessToken = "hidden_api_key";
var map = new mapboxgl.Map({
container: "map", // container ID
style: "mapbox://styles/mapbox/dark-v10",
center: [-2.582861, 53.5154517],
zoom: 5,
maxZoom: 16,
minZoom: 0,
});
map.on("load", function () {
// get hotspot locations
map.addSource("hotspot_locations", {
type: "geojson",
data: "https://netmaker.io/dashboard/public_actions.php?a=ajax_helium_miners_location",
cluster: false,
clusterMaxZoom: 10, // max zoom to cluster points on
clusterRadius: 50, // radius of each cluster when clustering points (defaults to 50)
});
// add 300m circle around each hotspot
map.addLayer({
id: "circle500",
type: "circle",
source: "hotspot_locations",
paint: {
"circle-radius": {
stops: [
[0, 1],
[16, 600],
],
base: 2,
},
"circle-color": "green",
"circle-opacity": 0.1,
"circle-stroke-width": 0,
"circle-stroke-color": "white",
},
});
// add hotspot location
map.addLayer({
id: "hotspots-layer",
type: "circle",
source: "hotspot_locations",
paint: {
"circle-radius": 2,
"circle-stroke-width": 2,
// "circle-color": "#36d293",
"circle-color": "white",
"circle-stroke-color": [
"match",
["get", "status"],
"online",
"#36d293",
"offline",
"#d23636",
"orange", // other
],
// "circle-stroke-color": '#36d293',
},
});
});
// ajax call hotspots location by name
var customData;
$.ajax({
async: false,
type: "GET",
global: false,
dataType: "json",
url: "https://netmaker.io/dashboard/public_actions.php?a=ajax_helium_miners_location_customdata",
success: function (data) {
customData = data;
},
});
// custom data using hotspot name
function forwardGeocoder(query) {
var matchingFeatures = [];
for (var i = 0; i < customData.features.length; i++) {
var feature = customData.features[i];
if (feature.properties.title.toLowerCase().search(query.toLowerCase()) !== -1) {
// feature["place_name"] = '<img src="https://netmaker.io/dashboard/images/helium_logo.svg" alt="" width="15px"> ' + feature.properties.title;
feature["place_name"] = feature.properties.title;
feature["center"] = feature.geometry.coordinates;
feature["place_type"] = ["hotspot"];
matchingFeatures.push(feature);
}
}
return matchingFeatures;
}
// add the control to the map.
map.addControl(
new MapboxGeocoder({
accessToken: mapboxgl.accessToken,
localGeocoder: forwardGeocoder,
zoom: 14,
placeholder: "Search: address or hotspot name",
mapboxgl: mapboxgl,
})
);
map.on("click", "hotspots-layer", function (e) {
var coordinates = e.features[0].geometry.coordinates.slice();
var description = e.features[0].properties.description;
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
new mapboxgl.Popup().setLngLat(coordinates).setHTML(description).addTo(map);
});
map.on("mouseenter", "hotspots-layer", function () {
map.getCanvas().style.cursor = "pointer";
});
map.on("mouseleave", "hotspots-layer", function () {
map.getCanvas().style.cursor = "";
});
</script>
You're recieving an undefined because e.features[0].properties.description doesn't exist in the "hotspots-layer" data.
"features": [
{
"type": "Feature",
"properties": {
"status": "online"
},
"geometry": {
"type": "Point",
"coordinates": [
"119.73479929772",
"30.240836896893",
0
]
}
},
The only "description" in this case that you can return is the e.features[0].properties.status as seen here:
map.on("click", "hotspots-layer", function (e) {
var coordinates = e.features[0].geometry.coordinates.slice();
var description = e.features[0].properties.status;
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
console.log(description)
new mapboxgl.Popup().setLngLat(coordinates).setHTML(description).addTo(map);
});
This code snippet will allow the click event to show you the status when you interact with the hotspot location.
I have a pie chart integration in Spotfire which works well when the data is in a simpler format in 'data' and 'columns'. The data binds to the chart properly (this is the kind of format i've seen in most demos).
However in other real-life usages in Spotfire, the JSON which is produced is differently formatted and ceases to draw a pie chart properly. I think it should be possible to adjust the script to bind to this data format, but i don't know how?
In my fiddle it is working with simpler data format, if commenting this out and uncommenting the other data the failed chart can be seen...
https://jsfiddle.net/paulsmithleadershipfactor/3k2gzuw0/
The full code is here also...
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE9"/>
<title>JS Visualization Tester with Highcharts</title>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script>
var chart; // Global chart object used to determine whether Highcharts has been intialized
var color = null;
var pie = null;
var svg = null;
var path = null;
function renderCore(sfdata)
{
if (resizing) {
return;
}
// Extract the columns
var columns = sfdata.columns;
columns.shift();
// Extract the data array section
var chartdata = sfdata.data;
// count the marked rows in the data set, needed later for marking rendering logic
var markedRows = 0;
for (var i = 0; i < chartdata.length; i++)
{
if (chartdata[i].hints.marked)
{
markedRows = markedRows + 1;
}
}
var width = window.innerWidth;
var height = window.innerHeight;
var radius = Math.min(width, height) / 2;
if ( !chart )
{
$('#js_chart').highcharts({
chart: {
plotBackgroundColor: '#f1f2f2',
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: 'Pie',
},
tooltip: {
formatter: function() {
var sliceIndex = this.point.index;
var sliceName = this.series.chart.axes[0].categories[sliceIndex];
return sliceName + ':' +
'<b>' + this.y + '</b>';
}
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
showInLegend: true,
depth: 35,
innerSize: 100,
dataLabels: {
enabled: true,
format: '{point.y:,.0f}'
}
}
},
legend: {
enabled: true,
labelFormatter: function() {
var legendIndex = this.index;
var legendName = this.series.chart.axes[0].categories[legendIndex];
return legendName;
}
},
xAxis: {
categories: columns
}
});
}
chart = $('#js_chart').highcharts();
for ( var nIndex = 0 ; nIndex < chartdata.length ; nIndex++ )
{
var row = chartdata[nIndex];
// Check for an existing chart data series with the current id
var series = chart.get ( row.items[0] );
var seriesData = [];
for (var c = 1; c < row.items.length; c++) {
seriesData.push(Number(row.items[c]));
}
if ( series != null )
{
// Update the existing series with the new data
series.update ( {
data: seriesData
}, false );
}
else
{
// Create a new series
chart.addSeries ( {
id: row.items[0],
name: row.items[0],
data: seriesData
}, false );
}
}
for ( nSeriesIndex = 0 ; nSeriesIndex < chart.series.length ; nSeriesIndex++ )
{
var series = chart.series[nSeriesIndex];
var found = false;
for ( nDataIndex = 0 ; nDataIndex < chartdata.length ; nDataIndex++ )
{
var row = chartdata[nDataIndex];
if ( series.name == row.items[0] )
{
found = true;
break;
}
}
if ( found != true )
{
series.remove ( false );
nSeriesIndex = 0;
}
}
chart.redraw ();
wait ( sfdata.wait, sfdata.static );
}
var resizing = false;
window.onresize = function (event) {
resizing = true;
if ($("#js_chart")) {
}
resizing = false;
}
</script>
</head>
<body>
<button style="position:absolute; z-index:99" type="button" onclick="call_renderCore()">Call renderCore</button>
<div id="js_chart"></div>
<script type="text/javascript">
function call_renderCore()
{
var sfdata =
{
"columns": ["Sales (Total)", "Marketing (Total)", "Development (Total)", "Customer Support (Total)", "IT (Total)", "Administration (Total)"],
/* comment out the 'columns' above and uncomment 'columns' below */
/* "columns": [
"count([lastcontact])",
"First([lastcontact])"
], */
/* uncomment above and comment below */
"data": [{"items": [93000, 58000, 102000, 66000, 43000, 24000], "hints": {"index": 0}}]
/* comment out the 'data' above and uncomment 'data' below */
/* "data": [
{
"items": [
131,
"3 – 6 months"
],
"hints": {
"index": 0
}
},
{
"items": [
78,
"6 months – 1 year"
],
"hints": {
"index": 1
}
},
{
"items": [
89,
"Can't remember"
],
"hints": {
"index": 2
}
},
{
"items": [
56,
"Over a year ago"
],
"hints": {
"index": 4
}
},
{
"items": [
442,
"Less than 3 months"
],
"hints": {
"index": 3
}
}
], */
}
renderCore ( sfdata );
display_data ( sfdata );
}
</script>
</body>
</html>
I'm trying to implement this demo in my app but I get whole map black regardless of values. here is my code:
var map = AmCharts.makeChart( "chartdiv", {
"type": "map",
"theme": "light",
"colorSteps": 10,
"dataProvider": {
"mapURL": "https://www.amcharts.com//lib/3/maps/svg/iranLow.svg",
"getAreasFromMap": true,
"zoomLevel": 0.9,
"areas": []
},
"areasSettings": {
"autoZoom": true,
"balloonText": "[[title]]: <strong>[[value]]</strong>"
},
"valueLegend": {
"right": 10,
"minValue": "little",
"maxValue": "a lot!"
},
"zoomControl": {
"minZoomLevel": 0.9
},
"titles": 'titles',
"listeners": [ {
"event": "init",
"method": updateHeatmap
} ]
} );
function updateHeatmap( event ) {
var map = event.chart;
if ( map.dataGenerated )
return;
if ( map.dataProvider.areas.length === 0 ) {
setTimeout( updateHeatmap, 100 );
return;
}
for ( var i = 0; i < map.dataProvider.areas.length; i++ ) {
map.dataProvider.areas[ i ].value = Math.round( Math.random() * 10000 );
}
map.dataGenerated = true;
map.validateNow();
}
is there anything else that I should do in order to get color range based on values?
You're likely running into cross origin issues when using the SVG on AmCharts' site as your source when running your code locally (especially if your local environment is http - the include is https).
Ideally you should be using the map JavaScript instead of the SVG file. Try including the iranLow.js map javascript file and use map: "iranLow" instead of mapURL: 'path/to/svg'.
iranLow.js include (after ammap.js):
<script type="text/javascript" src="https://www.amcharts.com/lib/3/maps/js/iranLow.js"></script>
Modified dataprovider definition
"dataProvider": {
"map": "iranLow",
"getAreasFromMap": true,
"zoomLevel": 0.9,
"areas": []
},
Demo below:
var map = AmCharts.makeChart( "chartdiv", {
"type": "map",
"theme": "light",
"colorSteps": 10,
"dataProvider": {
"map": "iranLow",
"getAreasFromMap": true,
"zoomLevel": 0.9,
"areas": []
},
"areasSettings": {
"autoZoom": true,
"balloonText": "[[title]]: <strong>[[value]]</strong>"
},
"valueLegend": {
"right": 10,
"minValue": "little",
"maxValue": "a lot!"
},
"zoomControl": {
"minZoomLevel": 0.9
},
"titles": 'titles',
"listeners": [ {
"event": "init",
"method": updateHeatmap
} ]
} );
function updateHeatmap( event ) {
var map = event.chart;
if ( map.dataGenerated )
return;
if ( map.dataProvider.areas.length === 0 ) {
setTimeout( updateHeatmap, 100 );
return;
}
for ( var i = 0; i < map.dataProvider.areas.length; i++ ) {
map.dataProvider.areas[ i ].value = Math.round( Math.random() * 10000 );
}
map.dataGenerated = true;
map.validateNow();
}
#chartdiv {
width: 100%;
height: 300px;
}
<script type="text/javascript" src="https://www.amcharts.com/lib/3/ammap.js"></script>
<script type="text/javascript" src="https://www.amcharts.com/lib/3/themes/light.js"></script>
<script type="text/javascript" src="https://www.amcharts.com/lib/3/maps/js/iranLow.js"></script>
<div id="chartdiv"></div>
OK, so I have this map in AMCharts where I have external buttons that contain IDs, LAT and Long of certain countries, and when I hover over them I want the map to zoom and center itself to that country, here's the code example ...
http://codepen.io/sheko_elanteko/pen/rjYvgE
var map = AmCharts.makeChart("chartdiv", {
"type": "map",
"dataProvider": {
"map": "worldLow",
"getAreasFromMap": true,
"areas": [ {
"id": "EG",
"color": "#67b7dc",
"rollOverOutlineColor": "#000",
"autoZoom": true,
"balloonText": "Egypt"
}, {
"id": "KZ",
"color": "#67b7dc",
"rollOverOutlineColor": "#000",
"autoZoom": true,
"balloonText": "Kazakistan"
}, {
"id": "US",
"color": "#67b7dc",
"rollOverOutlineColor": "#000",
"autoZoom": true,
"balloonText": "United States"
}]
},
"areasSettings": {
"color": "#999",
"autoZoom": false,
// "selectedColor": "#CC0000",
"balloonText": "",
"outlineColor": "#fff",
"rollOverOutlineColor": "#fff"
},
"listeners": [{
"event": "rendered",
"method": function(e) {
// Let's log initial zoom settings (for home button)
var map = e.chart;
map.initialZoomLevel = map.zoomLevel();
map.initialZoomLatitude = map.zoomLatitude();
map.initialZoomLongitude = map.zoomLongitude();
}
}]
});
function centerMap() {
map.zoomToLongLat(map.initialZoomLevel, map.initialZoomLongitude, map.initialZoomLatitude);
}
$("button.country").mouseenter(function(event) {
event.stopPropagation();
var countryID = $(this).data("id");
var country = map.getObjectById(countryID);
var lat = $(this).data("lat");
var long = $(this).data("long");
country.color = '#000';
// map.zoomToSelectedObject(country);
map.zoomToLongLat(3, lat, long);
country.validate();
}).mouseleave(function(event){
event.stopPropagation();
var countryID = $(this).data("id");
var country = map.getObjectById(countryID);
country.color = '#CC0000';
country.validate();
centerMap();
});
As you can see I have the coordinates of each country hard coded, as well as the zoom level, but the zooming doesn't work properly, especially for US!!
I also wonder if there's a way to get the LAT and Long of each country so that I don't hard-code them.
There's a function in AMCharts called "zoomToSelectedObject", but I tried that and gave it the object with no luck.
You could try amCharts' selectObject method. Its default function is to zoom to the map object provided (the one that you already get by using getObjectById. Example:
$("button.country").mouseenter(function(event) {
event.stopPropagation();
var countryID = $(this).data("id");
var country = map.getObjectById(countryID);
map.selectObject(country);
}).mouseleave( ... );
Just make sure that you add "selectable": true to your areasSettings. Without it, the selectObject method won't work.
amCharts maps have excellent docs that you'll find here: https://docs.amcharts.com/3/javascriptmaps/AmMap#selectObject.
I'm using the ng-google-charts module to build google charts for my angular application, what I'm trying to do is draw a column chart.
The code works the chart seems to be drawn correctly but I can't figure out how to add a colour in the rows I'm generating so that each column is coloured differently.
Here is my code, looking at google charts documentation it seems that I should be able to assign a hex code for each column but none of the examples I've seen use angular and none of them build their rows as literal objects like I need to do.
var collsArray = [];
var rowsArray = [];
for (var i = 0; i < vm.projects.length ; i++) {
//this is where I build each data row and where I think I need to add the color
rowsArray.push({
"c": [
{
"v": vm.projects[i].name
},
{
"v": vm.projects[i].developers,
"f": vm.projects[i].developers + ' developers working on ' + vm.projects[i].name
}]
});
}
collsArray = [{id: 'project', label: 'Project', type: 'string'},
{id: 'developers', label: 'Developers working', type: 'number'}];
vm.chartProjects = {
"type": "ColumnChart",
"displayed": false,
"data": {
"cols": collsArray,
"rows": rowsArray
},
"options": {
"isStacked": "true",
"fill": 0,
"width": '100%',
"height": '100%',
"displayExactValues": true,
"chartArea": {
"left": "1%",
"top": "1%",
"height": "98%",
"width": "98%"
}
},
"formatters": {},
"view": {}
};
Adding a Style Column Role is the easiest way to color an individual bar.
You could try something like this...
var colorPallette = [
'#7B241C', '#CB4335', '#FF9900', 'Gold', '#28B463',
'#196F3D', '#0D47A1', '#29B6F6', 'Indigo', 'Violet'
];
var collsArray = [];
var rowsArray = [];
collsArray = [
{id: 'project', label: 'Project', type: 'string'},
{id: 'developers', label: 'Developers working', type: 'number'},
{role: 'style', type: 'string'} // style column
];
var colorIndex = -1;
for (var i = 0; i < vm.projects.length ; i++) {
// manage color pallette
colorIndex++;
if (colorIndex === colorPallette.length) {
colorIndex = 0;
}
rowsArray.push({
"c": [
{
"v": vm.projects[i].name
},
{
"v": vm.projects[i].developers,
"f": vm.projects[i].developers + ' developers working on ' + vm.projects[i].name
},
{
"v": colorPallette[colorIndex] // style column
}
]
});
}
This answer shows the various color definitions you could use.
FYI: this option does not work with Material charts...