I would like to do map drilldown using Highcharts by following this US Map Drilldown example : US Map Drilldown Highcharts
This is the sample of my drilldown javascript file
var data = Highcharts.geojson(Highcharts.maps['countries/my/my-all']),
separators = Highcharts.geojson(Highcharts.maps['countries/my/my-all'], 'mapline'),
// Some responsiveness
small = $('#container').width() < 400;
// Set drilldown pointers
$.each(data, function (i) {
this.drilldown = this.properties['hc-key'];
this.value = i; // Non-random bogus data
});
// Instantiate the map
Highcharts.mapChart('container', {
chart: {
events: {
drilldown: function (e) {
if (!e.seriesOptions) {
var chart = this,
mapKey = 'countries/my/' + e.point.drilldown + '-all',
// Handle error, the timeout is cleared on success
fail = setTimeout(function () {
if (!Highcharts.maps[mapKey]) {
chart.showLoading('<i class="icon-frown"></i> Failed loading ' + e.point.name);
fail = setTimeout(function () {
chart.hideLoading();
}, 1000);
}
}, 3000);
// Show the spinner
chart.showLoading('<i class="icon-spinner icon-spin icon-3x"></i>'); // Font Awesome spinner
// Load the drilldown map
$.getScript('https://code.highcharts.com/mapdata/' + mapKey + '.js', function () {
data = Highcharts.geojson(Highcharts.maps[mapKey]);
// Set a non-random bogus value
$.each(data, function (i) {
this.value = i;
});
// Hide loading and add series
chart.hideLoading();
clearTimeout(fail);
chart.addSeriesAsDrilldown(e.point, {
name: e.point.name,
data: data,
dataLabels: {
enabled: true,
format: '{point.name}'
}
});
});
}
this.setTitle(null, { text: e.point.name });
},
drillup: function () {
this.setTitle(null, { text: '' });
}
}
This is sample code for states.json
"features": [
{
"type": "Feature",
"id": "MY.SA",
"properties": {
"hc-group": "admin1",
"hc-middle-x": 0.32,
"hc-middle-y": 0.6,
"hc-key": "my-sa",
"hc-a2": "SA",
"labelrank": "6",
"hasc": "MY.SA",
"alt-name": "North Borneo",
"woe-id": "2346310",
"subregion": null,
"fips": "MY16",
"postal-code": "SA",
"name": "Sabah",
"country": "Malaysia",
"type-en": "State",
"region": null,
"longitude": "117.095",
"woe-name": "Sabah",
"latitude": "5.31115",
"woe-label": "Sabah, MY, Malaysia",
"type": "State"
},
This is sample code for district in district.json
{
"type": "Feature",
"properties": {
"GID_0": "MYS",
"NAME_0": "Malaysia",
"GID_1": "MYS.13_1",
"NAME_1": "Sabah",
"NL_NAME_1": null,
"GID_2": "MYS.13.1_1",
"NAME_2": "Beaufort",
"VARNAME_2": null,
"NL_NAME_2": null,
"TYPE_2": "Daerah",
"ENGTYPE_2": "District",
"CC_2": null,
"HASC_2": "MY.SA.BF",
"ISO": "MY-12",
"ISO_district": "MY-12.1"
},
I need to use getJSON function right? Can someone help me how to do the declaration in the javascript file?
Related
I'm drawing a pie chart using AmCharts V3 and am using the export plugin to export the data as a file. I'm displaying a percentage contibution of the sale in different countries and would like to also display this percentage when I export my data to a CSV or XLSX file, but I'm not able to do so.
Here is my code
var chart = AmCharts.makeChart("chartdivtaxes", {
type: "pie",
startDuration: 0,
theme: "light",
addClassNames: true,
labelText: "[[percents]]",
innerRadius: "30%",
labelFunction: function(value, valueText, valueAxis) {
valueText = parseFloat(valueText);
var percentageText = valueText
.toFixed(1)
.replace(/(\d)(?=(\d{3})+\.)/g, "$1,");
return percentageText + "%";
},
defs: {
filter: [
{
id: "shadow",
width: "200%",
height: "200%",
feOffset: {
result: "offOut",
in: "SourceAlpha",
dx: 0,
dy: 0
},
feGaussianBlur: {
result: "blurOut",
in: "offOut",
stdDeviation: 5
},
feBlend: {
in: "SourceGraphic",
in2: "blurOut",
mode: "normal"
}
}
]
},
dataProvider: [
{
countryName: "India",
country: "sale in india:",
litres: "800.00"
},
{
countryName: "africa",
country: "sale in africa:",
litres: "800.00"
},
{
countryName: "UK",
country: "sale in UK:",
litres: "800.00"
},
{
countryName: "US",
country: "sale in US:",
litres: "800.00"
}
],
valueField: "litres",
titleField: "country",
balloon: {
fixedPosition: false,
color: "#ffffff",
fillAlpha: 0.9,
fillColor: "#00000"
},
export: {
enabled: true,
divId: "exportLevy",
columnNames: {
litres: "TotalSale",
countryName: "Name"
},
menu: [
{
class: "export-main",
label: "Export",
menu: [
{
format: "XLSX"
},
{
format: "CSV"
}
]
}
],
exportFields: ["countryName", "litres", "percents"]
}
});
There are two ways you can go about this - both of which involve using the processData callback offered by the export plugin.
1) Use processData to add a percent property in your data and manually trigger a download with toCSV or toXLSX. Note that you will need to throw an exception to prevent the plugin from triggering the download multiple times:
var chart = AmCharts.makeChart("...", {
// ...
export: {
// ...
processData: function(data, cfg) {
//only for CSV and XLSX export. Wrap in an ignore call to prevent infinite loop
if ((cfg.format === "CSV" || cfg.format === "XLSX") && !cfg.ignoreThatRequest) {
var sum = data.reduce(function(accumulator, currentDataValue) {
return accumulator + parseFloat(currentDataValue.TotalSale);
}, 0);
data.forEach(function(currentDataValue) {
currentDataValue.percents =
(parseFloat(currentDataValue.TotalSale) / sum * 100).toFixed(1) + "%";
});
//will map to this.toCSV or this.toXLSX
this["to" + cfg.format]({
data: JSON.parse(JSON.stringify(data)),
ignoreThatRequest: true, //set ignore flag as processData will execute again when this is called
exportFields: ["Name", "TotalSale", "percents"]
},
function(output) {
this.download(output, cfg.mimeType, cfg.fileName + "." + cfg.extension);
}
);
throw "Invoked – Use custom handler (stop multiple download)"; //throw an exception to stop the multi-download attempt
}
return data;
}
}
});
Demo of method #1
2) Alternatively, add a dummy percents property in your dataProvider with its value set to null and use processData to fill it in before exporting the chart. This is simpler and doesn't require an exception workaround to prevent multiple downloads:
var chart = AmCharts.makeChart("...", {
// ...
export: {
// ...
processData: function(data, cfg) {
var sum = data.reduce(function(accumulator, currentDataValue) {
return accumulator + parseFloat(currentDataValue.TotalSale);
}, 0);
data.forEach(function(currentDataValue) {
currentDataValue.percents =
(parseFloat(currentDataValue.TotalSale) / sum * 100).toFixed(1) + "%";
});
return data;
}
}
});
Demo of method #2
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 have a large set of 8 series of data over time, and currently I have two working graphs, one that has a range selector (allowing you to slide a bar to select which dates to show), and the other has the ability to click on the chart legend to choose which of the series to show and which of the series to hide.
I haven't been able to combine them together, though, into one unified dashboard that does both together. This particular code allows you to filter the date, but hiding/showing a series doesn't work. I've tried various combinations in place of the last line (chart.draw(view);) such as redrawing the dashboard and rebinding the dashboard, but still can't get it working. Any suggestions would be greatly appreciated. Here's the relevant code (edit to include sample json_obj):
var json_obj = {
"cols": [{ "label": "Date", "type": "date" },
{ "label": "F1", "type": "number" },
{ "label": "F2", "type": "number" },
{ "label": "F3", "type": "number" },
{ "label": "F4", "type": "number" }],
"rows": [{
"c": [{ "v": Date(6,1,14) },
{ "v": .25 },
{ "v": .55 },
{ "v": .12 },
{ "v": .067 }
]
},
{
"c": [{ "v": Date(6,2,14) },
{ "v": .27 },
{ "v": .52 },
{ "v": .18 },
{ "v": .055 }
]
},
{
"c": [{ "v": Date(6,3,14) },
{ "v": .30 },
{ "v": .60 },
{ "v": .17 },
{ "v": .043 }
]
},
{
"c": [{ "v": Date(6,4,14) },
{ "v": .33 },
{ "v": .57 },
{ "v": .14 },
{ "v": .05 }
]
}]
};
var data = new google.visualization.DataTable(json_obj);
var formatter = new google.visualization.NumberFormat({
pattern: '#.###%'
});
for (i = 1; i <= 4; i++) {
formatter.format(data, i);
}
var dashboard = new google.visualization.Dashboard(
document.getElementById('dashboard'));
var columns = [];
var series = {};
for (var i = 0; i < data.getNumberOfColumns() ; i++) {
columns.push(i);
if (i > 0) {
series[i - 1] = {};
}
}
var control = new google.visualization.ControlWrapper({
controlType: 'ChartRangeFilter',
containerId: 'control',
options: {
// Filter by the date axis.
filterColumnIndex: 0,
ui: {
chartType: 'LineChart',
chartOptions: {
hAxis: {
baselineColor: 'none',
format: 'MM/dd/yy'
}
},
// 1 day in milliseconds = 24 * 60 * 60 * 1 * 1000 = 86400000
minRangeSize: 86400000
}
}
});
var chart = new google.visualization.ChartWrapper({
chartType: 'LineChart',
containerId: 'chart',
options: {
title: 'Feature Users Over Time',
vAxis: {
title: "Percent of Users",
format: '#.###%',
viewWindow: { min: 0 }
},
lineWidth: 2,
curveType: 'function',
series: series
}
});
dashboard.bind(control, chart);
dashboard.draw(data);
google.visualization.events.addListener(chart, 'select', function () {
var sel = chart.getSelection();
// if selection length is 0, we deselected an element
if (sel.length > 0) {
// if row is undefined, we clicked on the legend
if (sel[0].row === null) {
var col = sel[0].column;
if (columns[col] == col) {
// hide the data series
columns[col] = {
label: data.getColumnLabel(col),
type: data.getColumnType(col),
calc: function () {
return null;
}
};
// grey out the legend entry
series[col - 1].color = '#CCCCCC';
}
else {
// show the data series
columns[col] = col;
series[col - 1].color = null;
}
var view = new google.visualization.DataView(data);
view.setColumns(columns);
chart.draw(view);
}
}
});
If row can be 'undefined' then you need to check:
if (!sel[0].row)
..or
if (sel[0].row == 0)
..instead of
if (sel[0].row === null)
..because the result are different in each case.
See http://jsfiddle.net/3wcd3w7x/2/
Edit: for fix jsfiddle example.
You almost have it; you need to change the chart's series option and set the chart's view parameter instead of creating a DataView. Replace these lines:
var view = new google.visualization.DataView(data);
view.setColumns(columns);
chart.draw(view);
with these:
chart.setOption('series', series);
chart.setView({columns: columns});
chart.draw();
I'm using Kendo Data viz and am passing JSON to an .NET MVC page to initialise the chart:
<div class="k-chart" id="SummaryWeekImportChart"></div>
$("#SummaryWeekImportChart").kendoChart(
#Html.Raw(Model.KendoLineChartJson));
The JSON (important bits):
"dataSource":{
"schema":{
"model":{
"fields":{
"TotalValue":{
"type":"number"
},
"SuccessValue":{
"type":"number"
},
"ErrorValue":{
"type":"number"
},
"Date":{
"type":"date"
},
"Category":{
"type":"string"
},
"ToolTip":{
"editable":false,
"type":"string"
}
}
}
},
"data":[
{
"TotalValue":0,
"SuccessValue":0,
"ErrorValue":0,
"Date":"2013-10-18T00:00:00",
"Category":"18/10/2013",
"ToolTip":"18/10/2013"
},
{
"TotalValue":0,
"SuccessValue":0,
"ErrorValue":0,
"Date":"2013-10-19T00:00:00",
"Category":"19/10/2013",
"ToolTip":"19/10/2013"
},
{
"TotalValue":0,
"SuccessValue":0,
"ErrorValue":0,
"Date":"2013-10-20T00:00:00",
"Category":"20/10/2013",
"ToolTip":"20/10/2013"
},
{
"TotalValue":0,
"SuccessValue":0,
"ErrorValue":0,
"Date":"2013-10-21T00:00:00",
"Category":"21/10/2013",
"ToolTip":"21/10/2013"
},
{
"TotalValue":1,
"SuccessValue":0,
"ErrorValue":1,
"Date":"2013-10-22T00:00:00",
"Category":"22/10/2013",
"ToolTip":"22/10/2013"
},
{
"TotalValue":68,
"SuccessValue":68,
"ErrorValue":0,
"Date":"2013-10-23T00:00:00",
"Category":"23/10/2013",
"ToolTip":"23/10/2013"
},
{
"TotalValue":96,
"SuccessValue":96,
"ErrorValue":0,
"Date":"2013-10-24T00:00:00",
"Category":"24/10/2013",
"ToolTip":"24/10/2013"
}
]
I'm using javascript to poll the server every x seconds:
$.get("/Dash/GetLineChartData", { searchDateString: searchDateForm },
function (incomingData) {
console.log("GetLineChartData back...", incomingData);
// Replace the data in the pie chart with the new data
var chart = $('#SummaryWeekImportChart').data("kendoChart");
var currSource = chart.dataSource;
currSource.data(incomingData.dataSource.data);
chart.refresh();
});
The data is loading ok but the labels across the x axis break.
Does anyone know how to update a line chart's data without messing up the labels?
you can add categoryAxis property inside the for the kendo chart like
categoryAxis: {
field: "Date",
labels: {
rotation: -65
},
majorGridLines: {
visible: false
}
},
The tooltips for my hacked gantt chart using highcharts doesnt seem to be working properly. I used the gantt chart provided by the highcharts team from here-:
http://jsfiddle.net/highcharts/r6emu/
I am using UnixTime and that seems to be somehow throwing off the tooltips. Here-:
http://jsfiddle.net/bootkick/NFS5M/
// Define tasks
var tasks = [{
"name": "a",
"intervals": [{
"from": 1366005607000,
"to": 1366006490000
}]
}, {
"name": "b",
"intervals": [{
"from": 1366059607000,
"to": 1366061858000
}, {
"from": 1366056006000,
"to": 1366058223000
}, {
"from": 1366047007000,
"to": 1366049299000
}, {
"from": 1366034407000,
"to": 1366036682000
}, {
"from": 1366030808000,
"to": 1366033050000
}, {
"from": 1366027208000,
"to": 1366029512000
}, {
"from": 1366018209000,
"to": 1366021296000
}]
}, {
"name": "c",
"intervals": [{
"from": 1366018209000,
"to": 1366019966000
}]
}, {
"name": "d",
"intervals": [{
"from": 1366005607000,
"to": 1366047612000
}, {
"from": 1366002007000,
"to": 1366002202000
}]
}];
// re-structure the tasks into line seriesvar series = [];
var series = [];
$.each(tasks.reverse(), function (i, task) {
var item = {
name: task.name,
data: []
};
$.each(task.intervals, function (j, interval) {
item.data.push({
x: interval.from,
y: i,
label: interval.label,
from: interval.from,
to: interval.to
}, {
x: interval.to,
y: i,
from: interval.from,
to: interval.to
});
// add a null value between intervals
if (task.intervals[j + 1]) {
item.data.push(
[(interval.to + task.intervals[j + 1].from) / 2, null]);
}
});
series.push(item);
});
// create the chart
var chart = new Highcharts.Chart({
chart: {
renderTo: 'container'
},
title: {
text: 'Daily activities'
},
xAxis: {
type: 'datetime'
},
yAxis: {
tickInterval: 1,
labels: {
formatter: function () {
if (tasks[this.value]) {
return tasks[this.value].name;
}
}
},
startOnTick: false,
endOnTick: false,
title: {
text: 'Activity'
},
minPadding: 0.2,
maxPadding: 0.2
},
legend: {
enabled: false
},
tooltip: {
formatter: function () {
return '<b>' + tasks[this.y].name + '</b><br/>' + Highcharts.dateFormat('%H:%M', this.point.options.from) +
' - ' + Highcharts.dateFormat('%H:%M', this.point.options.to);
}
},
plotOptions: {
line: {
lineWidth: 9,
marker: {
enabled: false
},
dataLabels: {
enabled: true,
align: 'left',
formatter: function () {
return this.point.options && this.point.options.label;
}
}
}
},
series: series
});
I am relatively new to Javascript and Highcharts so pardon the obvious if any.
I figured it out. The problem was that the from,to timestamp pairs within a name/category are not in the ascending order. For the tooltip to work correctly, they need to be in the ascending order which is kinda weird.