Highmaps / highcharts is a javascript/jquery adapter that renders maps in browsers etc.
I have a map with a single country highlighted, however, the scale of the (world) map is such that I want zoom in after the map is loaded on the country in question.
Looking at the API I feel certain this is possible.
There is an event listener, such that I can execute custom functions on load. As illustrated with this example, where a series is added on load (Js fiddle)
Additionally there is a method mapZoom allowing you to specify a point to zoom to with the following arguments:
mapZoom (Number howMuch, [Number centerX], [Number centerY], [Number mouseX], [Number mouseY])
But when I try and call this method onload (my code attempt below, JS fiddle here), nothing happens.
$(function () {
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=world-population-density.json&callback=?', function (data) {
// Assign id's
$.each(data, function () {
this.id = this.code;
});
// Initiate the chart
$('#container').highcharts('Map', {
chart: {
events: {
load: function () {
mapZoom(0.5, 100, 100);
}
}
},
title: {
text: 'Zoom on load attempt'
},
legend: {
title: {
text: 'Population density per km²'
}
},
colorAxis: {
min: 1,
max: 1000,
type: 'logarithmic'
},
mapNavigation: {
enabled: true,
buttonOptions: {
verticalAlign: 'bottom'
}
},
series : [{
data : data,
mapData: Highcharts.maps['custom/world-highres'],
joinBy: ['iso-a2', 'code'],
name: 'Population density',
allowPointSelect: true,
cursor: 'pointer',
states: {
hover: {
color: '#BADA55'
}
},
tooltip: {
pointFormat: '{point.id} {point.name}',
valueSuffix: '/km²'
}
}]
});
});
});
mapZoom is a method that belongs to the chart object so, in order to call it as en event (load), you have to call it using this keyword.
You can edit your code like this (JSFiddle):
...
events: {
load: function () {
this.mapZoom(0.5, 100, 100);
}
}
}
...
Alternatively, you can call it whenever you want using a jQuery reference (JSFiddle):
$('#container').highcharts().mapZoom(0.5, 100, 100);
Zoom to a specific country on your map is easy
series : [{
...
data: [{code: 'HU', id: 'HU', value: 7.5, name: 'Hungary'}],
...
}
...and then...
var mapChart=$('#MapContainer').highcharts(); //get map chart object from DOM
mapChart.get('HU').zoomTo(); //zoom to the country using "id" from data serie
mapChart.mapZoom(5); //elevate viewpoint a little to see surrounding countries as well
If you want to zoom several countries, than you can try this
events: {
load: function () {
var mapChart = this;
['DE', 'HU', 'RO'].map(function(code){
return mapChart.get(code);
}).reduce(function(acc, current){
// Set map bounds
acc._minX = isNaN(acc._minX) ? current._minX : Math.min(acc._minX, current._minX);
acc._maxX = isNaN(acc._maxX) ? current._maxX : Math.max(acc._maxX, current._maxX);
acc._minY = isNaN(acc._minY) ? current._minY : Math.min(acc._minY, current._minY);
acc._maxY = isNaN(acc._maxY) ? current._maxY : Math.max(acc._maxY, current._maxY);
return acc;
}).zoomTo();
}}
Related
I'm using highchart large tree map demo. I'm getting level data on click of each section. But also need to get the data on back button. So I'm using events drill up function to get data on click of back button. below is my code.
this.setState({
data: {
series: [{
type: 'treemap',
layoutAlgorithm: 'squarified',
allowDrillToNode: true,
animationLimit: 1000,
dataLabels: {
enabled: false
},
levelIsConstant: false,
levels: [{
level: 1,
dataLabels: {
enabled: true
},
borderWidth: 0,
}],
data: points,
events: {
click:(e)=>{
console.log(e)
},
drillup:(e)=>{
console.log(e)
}
}
}],
// subtitle: {
// text: 'Click points to drill down. Source: WHO.'
// },
title: {
text: ''
}
}
})
But don't know drill up is not working even click is working and also I added
import drilldown from "highcharts/modules/drilldown";
drilldown(Highcharts);
But still not getting any data. Please help.
Notice that treemap series don't use the drilldown module, but has own drilldown implementation, which logic you can find here: https://code.highcharts.com/modules/treemap.src.js
What you will need to do is render a custom button while clicking the point and attach an update functionality on this button. Something like here:
Demo: https://jsfiddle.net/BlackLabel/gas07t34/
events: {
click() {
let chart = this.chart;
chart.button = chart.renderer.button('back', 500, 0, function() {
chart.series[0].update({
data: data1
})
chart.button.destroy();
}).add()
this.update({
data: data2
})
}
}
API: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#button
API: https://api.highcharts.com/class-reference/Highcharts.Series#update
I've searched around for several days and have not been able to find a solution to this issue. I'm generating highcharts with not problem. Inaddition, I'm using the below simple function to get the svg code for each chart.
function generateSVG (){
var svg_xml = $('#container').highcharts().getSVG();
document.getElementById('svg_code').innerHTML = svg_xml;
}
My issue is that with the chart originally generated by highcharts I am able to mouseover the chart and see tooltips. However, when I later embed the generated svg code, even with including all the external resources, the tooltips do not work - everything becomes like a static image. After inspecting the svg code extracted next to the code used to generate the initial chart, I noticed that the line of code which includes the tooltip class for highcharts was missing in the extracted code. Am I missing something here. Below is an example of one of the functions used to generate a chart.
function highArea(theD){
setHighSize();
var theData = theD;
$.get(theData, function(data) {
Highcharts.chart('chartDisplay', {
colors: ["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#ffffff"],
chart: {
type: "area",
useHTML: true
},
exporting: {
buttons: {
contextButton: {
enabled: false
}
}
},
title: {
text: chart_title
},
data: {
csv: data
},
title: {
text: chart_title
},
subtitle: {
text: ''
},
xAxis: {
allowDecimals: false,
labels: {
formatter: function () {
return this.value;
}
}
},
yAxis: {
title: {
text: some_label
},
},
tooltip: {
pointFormat: '{series.name} <b>{point.y:,.0f}</b><br/> {point.x}'
},
plotOptions: {
area: {
marker: {
enabled: true,
symbol: 'circle',
radius: 2,
states: {
hover: {
enabled: true
}
}
}
}
}
});
generateSVG();
});
}
Is what I'm trying to do even possible? I would really appreciate any feedback on this matter.
Thanks :)
I have a Stacked % Column Highchart which without Hyperlinks on data sets works perfectly, however I need to link away to another page from the chart, If it was a standard column chart, I would have no issue (I have one already). But i cannot seem to work out why I'm getting an undefined error on the link.
Ive searched around for a working example but havent been able to find one matching the stacked percentage column.
I've setup a fiddle to indicate where im up to, any help appreciated.
$(function () {
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Space Overview'
},
xAxis: {
categories: ['a', 'b', 'c', 'd']
},
yAxis: {
min: 0,
title: {
text: 'Total Space (%)'
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.percentage:.0f}%)<br/>',
shared: true
},
plotOptions: {
column: {
stacking: 'percent'
},
series: {
cursor: 'pointer',
point: {
events: {
click: function() {
location.href = this.options.url;
}
}
}
}
},
subtitle: {
text: '+ Items relate to items in the dispay cabinets.',
align: 'left',
x: 10
},
series: [{
name: 'Free',
data: [1498, 1123, 556, 1176],
url: ['Spaces.aspx?box=a', 'Spaces.aspx?box=b', 'Spaces.aspx?box=c', 'Spaces.aspx?box=d']
}, {
name: 'Used',
data: [1234,233,23,759],
url: ['Spaces.aspx?box=a', 'Spaces.aspx?box=b', 'Spaces.aspx?box=c', 'Spaces.aspx?box=d']
}]
});
http://jsfiddle.net/Mooglekins/qv8z5a2o/
This is a great question! I did some digging and think I've found a good solution for you.
First, I needed to update how you defined the custom value in your series. To capture certain values in events, I moved the url attribute within each data point. So now, each point has their y value and the new url value.
(Note: I used dummy URLs here since I wouldn't be able to connect to the ones you provided outside your website.)
series: [{
name: 'Free',
data: [
{ y: 1498, url: 'http://www.google.com' },
{ y: 1123, url: 'http://www.yahoo.com' },
{ y: 556, url: 'http://www.bing.com' },
{ y: 1176, url: 'http://www.msn.com' }
]
}, {
// second series here
}
]
Next, I updated your events call. Now that we've moved the url attribute to each point, we can refer to that value as point.url (as you could the y value using point.y).
What I also did here is use window.open vs. window.location. This will be a better experience for your users so they don't lose sight of the chart. Keep this if you wish.
plotOptions: {
column: {
stacking: 'percent'
},
series: {
cursor: 'pointer',
point: {
events: {
click: function (event) {
window.open(event.point.url);
}
}
}
}
}
Here's your updated fiddle with these changes: http://jsfiddle.net/brightmatrix/qv8z5a2o/5/
I hope this helps!
I am attempting to take the example produced by Highcharts here http://www.highcharts.com/maps/demo/color-axis and substitute the data loaded by the $.getJson with a local JSON file called 'testdata1.json'.
The code I've modified below produces no errors yet the map does not render. I think it's because the testdata1.json is loaded late, after the javascript is executed. If so, is there a better way I should be doing this -- perhaps waiting for the data to load before executing the JS file? I attempted to do this by placing a
$(document).ready(
in front of the function but it didn't work. Any thoughts are greatly appreciated, I think it's something relatively minor that is just escaping me.
Thank you.
$(function () {
// Map options
var options = {
chart : {
renderTo: '#map',
borderWidth : 1
},
title : {
text : 'US population density (/km²)'
},
legend: {
layout: 'horizontal',
borderWidth: 0,
backgroundColor: 'rgba(255,255,255,0.85)',
floating: true,
verticalAlign: 'top',
y: 25
},
mapNavigation: {
enabled: true
},
colorAxis: {
min: 1,
type: 'logarithmic',
minColor: '#EEEEFF',
maxColor: '#000022',
stops: [
[0, '#EFEFFF'],
[0.67, '#4444FF'],
[1, '#000022']
]
},
series : [{
animation: {
duration: 1000
},
mapData: Highcharts.maps['countries/us/us-all'],
joinBy: ['postal-code', 'code'],
dataLabels: {
enabled: true,
color: 'white',
format: '{point.code}'
},
name: 'Population density',
tooltip: {
pointFormat: '{point.code}: {point.value}/km²'
}
}]
};
$.getJSON('static/data/testdata1.json', function (data) {
// Make codes uppercase to match the map data
$.each(data, function () {
this.code = this.code.toUpperCase();
});
options.series.data= data;
var chart = new Highcharts.Chart(options)
});
});
You have three problems. Here's a fiddle based on their sample that uses your approach, but still uses their data, and works: http://jsfiddle.net/g29k24vw/1/
Here are the important parts:
chart : {
renderTo: 'container',
borderWidth : 1,
type: 'map'
},
And:
$.getJSON('http://www.highcharts.com/samples/data/jsonp.php?filename=us-population-density.json&callback=?', function (data) {
// Make codes uppercase to match the map data
$.each(data, function () {
this.code = this.code.toUpperCase();
});
options.series[0].data= data;
var chart = new Highcharts.Chart(options);
});
Note the differences here:
You need to specify the chart type in options if you're going to instantiate the chart object directly instead of using the jQuery helper.
renderTo doesn't want a hash in front of the element name.
options.series[0].data, not options.series.data...series is actually an array of objects.
I'm attempting to combine a couple of different chart demos from Highcharts.
My examples are: Data classes and popup and Small US with data labels
I want the map from the first with the popup feature of the second. I need to connect the map to my own google spreadsheet but for now I'm just trying to get the data from the first example to work.
This is what I have so far but can't seem to get any data in the map. I thought I had a joinBy problem, and I may still, but when I set joinBy to null I thought "the map items are joined by their position in the array", yet nothing happened.
https://jsfiddle.net/9eq6mydv/
$(function () {
// Load the data from a Google Spreadsheet
// https://docs.google.com/a/highsoft.com/spreadsheet/pub?hl=en_GB&hl=en_GB&key=0AoIaUO7wH1HwdFJHaFI4eUJDYlVna3k5TlpuXzZubHc&output=html
Highcharts.data({
googleSpreadsheetKey: '0AoIaUO7wH1HwdDFXSlpjN2J4aGg5MkVHWVhsYmtyVWc',
googleSpreadsheetWorksheet: 1,
// custom handler for columns
parsed: function (columns) {
// Make the columns easier to read
var keys = columns[0],
names = columns[1],
percent = columns[10],
// Initiate the chart
options = {
chart : {
renderTo: 'container',
type: 'map',
borderWidth : 1
},
title : {
text : 'US presidential election 2008 result'
},
subtitle: {
text: 'Source: <a href="http://en.wikipedia.org/wiki/United_States_presidential_election,' +
'_2008#Election_results">Wikipedia</a>'
},
mapNavigation: {
enabled: true,
enableButtons: false
},
legend: {
align: 'right',
verticalAlign: 'top',
x: -100,
y: 70,
floating: true,
layout: 'vertical',
valueDecimals: 0,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || 'rgba(255, 255, 255, 0.85)'
},
colorAxis: {
dataClasses: [{
from: -100,
to: 0,
color: '#C40401',
name: 'McCain'
}, {
from: 0,
to: 100,
color: '#0200D0',
name: 'Obama'
}]
},
series : [{
data : data,
dataLabels: {
enabled: true,
color: '#FFFFFF',
format: '{point.code}',
style: {
textTransform: 'uppercase'
}
},
mapData: Highcharts.geojson(Highcharts.maps['countries/us/custom/us-small']),
joinBy: keys,
name: 'Democrats margin',
point: {
events: {
click: pointClick
}
},
tooltip: {
ySuffix: ' %'
},
cursor: 'pointer'
}, {
type: 'mapline',
data: Highcharts.geojson(Highcharts.maps['countries/us/custom/us-small'], 'mapline'),
color: 'silver'
}]
};
/**
* Event handler for clicking points. Use jQuery UI to pop up
* a pie chart showing the details for each state.
*/
function pointClick() {
var row = this.options.row,
$div = $('<div></div>')
.dialog({
title: this.name,
width: 400,
height: 300
});
window.chart = new Highcharts.Chart({
chart: {
renderTo: $div[0],
type: 'pie',
width: 370,
height: 240
},
title: {
text: null
},
series: [{
name: 'Votes',
data: [{
name: 'Obama',
color: '#0200D0',
y: parseInt(columns[3][row], 10)
}, {
name: 'McCain',
color: '#C40401',
y: parseInt(columns[4][row], 10)
}],
dataLabels: {
format: '<b>{point.name}</b> {point.percentage:.1f}%'
}
}]
});
}
// Read the columns into the data array
var data = [];
$.each(keys, function (i, key) {
data.push({
key: key,//.toUpperCase(),
value: parseFloat(percent[i]),
name: names,
row: i
});
});
// Initiate the chart
window.chart = new Highcharts.Map(options);
},
error: function () {
$('#container').html('<div class="loading">' +
'<i class="icon-frown icon-large"></i> ' +
'Error loading data from Google Spreadsheets' +
'</div>');
}
});
});
UPDATE:
I wanted to share with everyone my final solution. Although Ondkloss did a magnificent job answering my question the popup feature still didn't work and this is because I forgot to include the jQuery for the .dialog call. Once I included that I had an empty popup with a highchart error 17, this is because the highmaps.js code doesn't include the pie chart class. So I had to add the highcharts.js code and include map.js module afterward. You can see my final jsfiddle here.
Thanks again to Ondkloss for the excellent answer!
The problem here mostly comes down to the use of joinBy. Also to correct it there are some required changes to your data and mapData.
Currently your joinBy is an array of strings, like ["al", "ak", ...]. This is quite simply not an accepted format of the joinBy option. You can read up on the details in the API documentation, but the simplest approach is to have a attribute in common in data and mapData and then supply a string in joinBy which then joins those two arrays by that attribute. For example:
series : [{
data : data,
mapData: mapData,
joinBy: "hc-key",
]
Here the "hc-key" attribute must exist in both data and mapData.
Here's how I'd create the data variable in your code:
var data = [];
$.each(keys, function (i, key) {
if(i != 0)
data.push({
"hc-key": "us-"+key,
code: key.toUpperCase(),
value: parseFloat(percent[i]),
name: names[i],
row: i
});
});
This skips the first key, which is just "Key" (the title of the column). Here we make the "hc-key" fit the format of the "hc-key" in our map data. An example would be "us-al". The rest is just metadata that will be joined in. Note that you were referencing your data in the options prior to filling it with data, so this has to be moved prior to this.
This is how I'd create the mapData variable in your code:
var mapData = Highcharts.geojson(Highcharts.maps['countries/us/custom/us-small']);
// Process mapdata
$.each(mapData, function () {
var path = this.path,
copy = { path: path };
// This point has a square legend to the right
if (path[1] === 9727) {
// Identify the box
Highcharts.seriesTypes.map.prototype.getBox.call(0, [copy]);
// Place the center of the data label in the center of the point legend box
this.middleX = ((path[1] + path[4]) / 2 - copy._minX) / (copy._maxX - copy._minX);
this.middleY = ((path[2] + path[7]) / 2 - copy._minY) / (copy._maxY - copy._minY);
}
// Tag it for joining
this.ucName = this.name.toUpperCase();
});
The first part is your "standard map data". The rest is to correctly center the labels for the popout states, and gotten directly from the example.
And voila, see this JSFiddle demonstration to witness your map in action.
I suggest doing some console.log-ing to see how data and mapData have the hc-key in common and that leads to the joining of the data in the series.