How to get base 64 of chart image in amcharts version 4 - javascript

I have plotted a simple amcharts column chart using amcharts version 4 , now i want to get the base 64 of the chart image how can I do it ?
My Chart Code
/**
* ---------------------------------------
* This demo was created using amCharts 4.
*
* For more information visit:
* https://www.amcharts.com/
*
* Documentation is available at:
* https://www.amcharts.com/docs/v4/
* ---------------------------------------
*/
// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
// Add data
chart.data = [{
"country": "USA",
"visits": 2025
}, {
"country": "China",
"visits": 1882
}, {
"country": "Japan",
"visits": 1809
}, {
"country": "Germany",
"visits": 1322
}, {
"country": "UK",
"visits": 1122
}, {
"country": "France",
"visits": 1114
}, {
"country": "India",
"visits": 984
}, {
"country": "Spain",
"visits": 711
}, {
"country": "Netherlands",
"visits": 665
}, {
"country": "Russia",
"visits": 580
}, {
"country": "South Korea",
"visits": 443
}, {
"country": "Canada",
"visits": 441
}, {
"country": "Brazil",
"visits": 395
}];
// Create axes
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "country";
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.renderer.minGridDistance = 30;
categoryAxis.renderer.labels.template.adapter.add("dy", function(dy, target) {
if (target.dataItem && target.dataItem.index & 2 == 2) {
return dy + 25;
}
return dy;
});
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
// Create series
var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueY = "visits";
series.dataFields.categoryX = "country";
series.name = "Visits";
series.columns.template.tooltipText = "{categoryX}: [bold]{valueY}[/]";
series.columns.template.fillOpacity = .8;
var columnTemplate = series.columns.template;
columnTemplate.strokeWidth = 2;
columnTemplate.strokeOpacity = 1;
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
#chartdiv {
width: 100%;
height: 500px;
}
<script src="https://cdn.amcharts.com/lib/4/core.js"></script>
<script src="https://cdn.amcharts.com/lib/4/charts.js"></script>
<script src="https://cdn.amcharts.com/lib/4/themes/animated.js"></script>
<div id="chartdiv"></div>
I have tried it using canvas but when I converted the base 64 to image it shows only scales , y-axis and x-axis but not showing the bars.
My requirement is I want to get base 64 of the exact image and upload it on s3 so on the first step I need to get base 64 which is the exact image of chart

May you can encode it to base 64 using btoa() and the data-url prefix?
Try this:
let svg = document.getElementsByTagName('svg')[0];
let base64 = "data:image/svg+xml;base64," + btoa(svg);

Related

Add hyperlink to nodes in amcharts Force Directed Tree

I have this amcharts 4 Force Directed Tree as a map for different pages I have on my website. What I want (and could not figure out how despite searching a lot) is that when a user clicks on a node they go to the webpage corresponding to that node. In short, I wonder if I can have a clickable name for nodes? I greatly appreciate any helps. Here is the JavaScript code:
am4core.useTheme(am4themes_dark);
am4core.useTheme(am4themes_animated);
var chart = am4core.create("chartdiv", am4plugins_forceDirected.ForceDirectedTree);
var networkSeries = chart.series.push(new am4plugins_forceDirected.ForceDirectedSeries())
networkSeries.nodes.template.outerCircle.filters.push(new am4core.DropShadowFilter());
networkSeries.dataFields.linkWith = "linkWith";
networkSeries.dataFields.name = "name";
networkSeries.dataFields.id = "name";
networkSeries.dataFields.value = "value";
networkSeries.dataFields.children = "children";
networkSeries.dataFields.color = "color";
networkSeries.dataFields.fixed = "fixed";
networkSeries.nodes.template.propertyFields.x = "x";
networkSeries.nodes.template.propertyFields.y = "y";
networkSeries.links.template.strength = 1;
networkSeries.manyBodyStrength = -20;
networkSeries.centerStrength = 0.4;
networkSeries.nodes.template.label.text = "{name}"
networkSeries.fontSize = 16;
networkSeries.minRadius = 40;
networkSeries.maxRadius = 80;
var nodeTemplate = networkSeries.nodes.template;
nodeTemplate.fillOpacity = 1;
nodeTemplate.label.hideOversized = true;
nodeTemplate.label.truncate = true;
var linkTemplate = networkSeries.links.template;
linkTemplate.strokeWidth = 5;
linkTemplate.distance = 1.5;
nodeTemplate.events.on("out", function (event) {
var dataItem = event.target.dataItem;
dataItem.childLinks.each(function (link) {
link.isHover = false;
})
})
networkSeries.events.on("inited", function() {
networkSeries.animate({
property: "velocityDecay",
to: 0.7
}, 3000);
});
networkSeries.data = [
{
"name":"Complex Networks",
"value":1000,
"color":"#0086ad",
"fixed": true,
x: am4core.percent(50),
y: am4core.percent(10),
"children":[
{
"name":"Theory \n and Model",
"value":600,
"color":"#0086ad",
"fixed": true,
x: am4core.percent(20),
y: am4core.percent(20),
"children":[
{
"name":"Statistical \n Physics \n Approach",
"value":600,
"color":"#36896E"
},
{
"name":"Balance Theory \n Approach",
"value":600,
"color":"#36896E"
},
{
"name":"Topological \n Data \n Analysis",
"value":400,
"color":"#36896E"
},
{
"name": "Aged \n Networks",
"value": 200,
"color":"#36896E"
},
{
"name": "Dark \n Networks",
"value": 100,
"color":"#36896E"
}
]
},
{
"name":"Application \n and Real-data",
"color":"#0086ad",
"fixed": true,
x: am4core.percent(80),
y: am4core.percent(20),
"value":600,
"children":[
{
"name": "Cancer \n Project",
"value": 100,
"color":"#36896E",
"linkWith":[
"Balance Theory \n Approach"
]
},
{
"name": "Social Data",
"value": 200,
"color":"#8b225b",
"fixed": true,
x: am4core.percent(80),
y: am4core.percent(33),
"children":[
{"name":"Twitter \n Project",
"value":200,
"color":"#36896E"},
{"name":"Complex \n Social \n Systems",
"value":300,
"color":"#36896E"}
]
}
]
}
]
},
{
"name":"Stochastic \n Process",
"value":200,
"color":"#0086ad",
"fixed":true,
x: am4core.percent(50),
y: am4core.percent(45),
"linkWith":[
"Financial \n Markets",
"Application \n and Real-data"
]
},
{
"name":"Network \n Neuroscience \n and Cognition",
"value":500,
"fixed": true,
x: am4core.percent(35),
y: am4core.percent(45),
"linkWith":[
"Balance Theory \n Approach",
"Application \n and Real-data",
"Topological \n Data \n Analysis",
],
"children":[
{
"name":"Resting-state \n fMRI Networks",
"value":600,
"color":"#36896E",
"url":"https://ccnsd.ir/research_projects/brain_networks/"
}
]
},
{
"name":"Econo-physics",
"value":500,
"fixed": true,
x: am4core.percent(65),
y: am4core.percent(45),
"linkWith":[
"Theory \n and Model",
"Application \n and Real-data"
],
"children":[
{
"name":"Quantum \n Economics",
"value":100,
"color":"#36896E"
},
{
"name":"Financial \n Markets",
"value":100,
"children":[
{"name": "Cryptocurrency",
"value": 500,
"color":"#36896E"},
{"name": "Stock \n Markets",
"value": 500,
"color":"#36896E"}
]
}
]
}
];
And the HTML:
<head>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
body { background-color: #30303d; color: #fff; }
#chartdiv {
width: 100%;
height: 1300px;
}
</style>
</head>
<script src="https://cdn.amcharts.com/lib/4/core.js"></script>
<script src="https://cdn.amcharts.com/lib/4/charts.js"></script>
<script src="https://cdn.amcharts.com/lib/4/plugins/forceDirected.js"></script>
<script src="https://cdn.amcharts.com/lib/4/themes/dark.js"></script>
<script src="https://cdn.amcharts.com/lib/4/themes/animated.js"></script>
<div id="chartdiv"></div>
Thanks in advance!
You can put click event in each node and use the following code.
Please take note that I used amchart 5 version.
series.nodes.template.events.on("click", function (e) {
switch (e.target.dataItem.dataContext.name) {
case 'Econo-physics':
window.open("https://stackoverflow.com/questions/68037180/add-hyperlink-to-nodes-in-amcharts-force-directed-tree");
}
}

How to set different colors on circles in amcharts map

I have implemented a map in amcharts plugin and drawing circles on locations where I have servers.
I want to show different colors on servers based on availability Green, Yellow and Red, as per business requirement. I have implemented circles on preferred location and I am able to assign only one color.
This is my code
public ServerMap()
{
this.mapChart = am4core.create("chartdiv", am4maps.MapChart);
this.mapChart .geodata = am4geodata_worldLow;
//Set projection
this.mapChart .projection = new am4maps.projections.Miller();
//Create map polygon series
this.polygonSeries = this.mapChart .series.push(new am4maps.MapPolygonSeries());
this.polygonSeries.exclude = ["AQ"];
this.polygonSeries.useGeodata = true;
this.polygonSeries.nonScalingStroke = true;
this.polygonSeries.calculateVisualCenter = true;
let imageSeries = this.mapChart .series.push(new am4maps.MapImageSeries());
imageSeries.dataFields.value = "value";
var place = imageSeries.mapImages.template;
place.nonScaling = true;
place.propertyFields.latitude = "latitude";
place.propertyFields.longitude = "longitude";
imageSeries.data=
[
{
"latitude": 17.3850,
"longitude": 78.4867,
"name": "Miam",
"value": 123,
},
{
"latitude":49.619446,
"longitude": -128.695623,
"name": "Washingto DC",
"value": 123,
},
{
"latitude": 41.8278767,
"longitude": -87.9986114,
"name": "Chicago",
"value": 123,
}
]
//Here creating circle
var circle = place.createChild(am4core.Circle);
circle.radius = 12;
circle.fill = am4core.color("#e33");
circle.strokeWidth = 1;
circle.fillOpacity = 0.7;
circle.propertyFields.fill = "color";
circle.tooltipText = "{name}: [bold]{value}[/]";
imageSeries.heatRules.push({
"target": circle,
"property": "radius",
"min": 6,
"max": 15,
"dataField": "value",
})
}
How can I set individual colors on circle based on conditions?
This is my output screen
you already have "circle.propertyFields.fill = "color";" defined.
Including "color" property in data should work.
imageSeries.data=
[
{
"latitude": 17.3850,
"longitude": 78.4867,
"name": "Miam",
"value": 123,
"color": 'red' // or rgb() or Hexa
},
{
"latitude":49.619446,
"longitude": -128.695623,
"name": "Washingto DC",
"value": 123,
"color": 'blue'
},

Confusion about d3.interpolateObject

I was just investigating the D3 Interpolate Object function, and I noticed some strange behavior. However, I'm not very familiar with D3, so it could be that I'm simply misunderstanding something. Given the following data and interpolation function:
var a = {"Country": "Ireland", "Year": 2010, "Data": 10};
var b = {"Country": "Ireland", "Year": 2015, "Data": 50};
var iFunc = d3.interpolateObject(a, b);
The following results are as expected:
console.log(iFunc(0.2)) // Returns: { Country: "Ireland", Year: 2011, Data: 18 }
console.log(iFunc(0.4)) // Returns: { Country: "Ireland", Year: 2012, Data: 26 }
However, when both function calls are included in the same console log, like this:
console.log(iFunc(0.2), iFunc(0.4))
The output is just the second Object twice:
{ Country: "Ireland", Year: 2012, Data: 26 } { Country: "Ireland", Year: 2012, Data: 26 }
And, when the function calls are put inside an array like so:
console.log([iFunc(0.2), iFunc(0.4)])
The previous output gets multiplied by two:
[{ Country: "Ireland", Year: 2014, Data: 42 }, { Country: "Ireland", Year: 2014, Data: 42 }]
What is going on here?
The reason I am investigating this is that I'd like to create a series of intermediate objects using something like:
var iVals = d3.range(0, 1, 0.2).map( iFunc );
If anybody can show me how I could achieve this, I'd really appreciate it!
This is an interesting problem. The explanation can be found in the own documentation:
Note: no defensive copy of the template object is created; modifications of the returned object may adversely affect subsequent evaluation of the interpolator. No copy is made for performance reasons; interpolators are often part of the inner loop of animated transitions. (emphasis mine)
As you can see, if you use the same interpolator you get the weird result you described (open your browser's console, don't use the snippet's one):
var a = {
"Country": "Ireland",
"Year": 2010,
"Data": 10
};
var b = {
"Country": "Ireland",
"Year": 2015,
"Data": 50
};
var iFunc = d3.interpolateObject(a, b);
var iVals = d3.range(0, 1, 0.2).map(iFunc);
console.log(iVals)
<script src="https://d3js.org/d3.v5.min.js"></script>
So, the simplest solution is defining the interpolator function inside the map():
var iVals = d3.range(0, 1, 0.2).map(function(d) {
return d3.interpolateObject(a, b)(d)
});
Here is the demo:
var a = {
"Country": "Ireland",
"Year": 2010,
"Data": 10
};
var b = {
"Country": "Ireland",
"Year": 2015,
"Data": 50
};
var iVals = d3.range(0, 1, 0.2).map(function(d) {
return d3.interpolateObject(a, b)(d)
});
console.log(iVals)
<script src="https://d3js.org/d3.v5.min.js"></script>
Alternatively, create a function that returns the interpolator:
var iFunc = function(d) {
return d3.interpolateObject(a, b)(d)
};
var iVals = d3.range(0, 1, 0.2).map(iFunc);
Here is the corresponding demo:
var a = {
"Country": "Ireland",
"Year": 2010,
"Data": 10
};
var b = {
"Country": "Ireland",
"Year": 2015,
"Data": 50
};
var iFunc = function(d) {
return d3.interpolateObject(a, b)(d)
};
var iVals = d3.range(0, 1, 0.2).map(iFunc);
console.log(iVals)
<script src="https://d3js.org/d3.v5.min.js"></script>
PS: Not related to your question, but the "stop" value in d3.range() is not inclusive. So, if you want to get the values in the object b, it should be:
d3.range(0, 1.2, 0.2)
Here it is:
var a = {
"Country": "Ireland",
"Year": 2010,
"Data": 10
};
var b = {
"Country": "Ireland",
"Year": 2015,
"Data": 50
};
var iVals = d3.range(0, 1.2, 0.2).map(function(d) {
return d3.interpolateObject(a, b)(d)
});
console.log(iVals)
<script src="https://d3js.org/d3.v5.min.js"></script>

Display Data from mysql database in Chart

I'm using AmCharts to create a pie chart.
I'm trying to assign data from my mysql database to the variable chartData
that has the fields country and liters. How can I assign my mysql data to chartdata?
<script>
var chart;
var legend;
var chartData = [{
"country": "Czech Republic",
"litres": 156.9
},
{
"country": "Ireland",
"litres": 131.1
},
{
"country": "Germany",
"litres": 115.8
},
{
"country": "Australia",
"litres": 109.9
},
{
"country": "Austria",
"litres": 108.3
},
{
"country": "UK",
"litres": 65
},
{
"country": "Belgium",
"litres": 50
}
];
AmCharts.ready(function () {
// PIE CHART
chart = new AmCharts.AmPieChart();
chart.dataProvider = chartData;
chart.titleField = "country";
chart.valueField = "litres";
// LEGEND
legend = new AmCharts.AmLegend();
legend.align = "center";
legend.markerType = "circle";
chart.balloonText = "[[title]]<br><span style='font-size:14px'><b>[[value]]</b> ([[percents]]%)</span>";
chart.addLegend(legend);
// WRITE
chart.write("chartdiv");
});
// changes label position (labelRadius)
function setLabelPosition() {
if (document.getElementById("rb1").checked) {
chart.labelRadius = 30;
chart.labelText = "[[title]]: [[value]]";
} else {
chart.labelRadius = -30;
chart.labelText = "[[percents]]%";
}
chart.validateNow();
}
// makes chart 2D/3D
function set3D() {
if (document.getElementById("rb3").checked) {
chart.depth3D = 10;
chart.angle = 10;
} else {
chart.depth3D = 0;
chart.angle = 0;
}
chart.validateNow();
}
// changes switch of the legend (x or v)
function setSwitch() {
if (document.getElementById("rb5").checked) {
legend.switchType = "x";
} else {
legend.switchType = "v";
}
legend.validateNow();
}
</script>
You cannot directly access your mysql database from javascript. You will have to ask your server for some data. Typicaly, you will want to get JSON formated data (using ajax) :
Javascript (using .getJSON()):
$.getJSON('/get-my-data.php', function(json) {
var chart;
var legend;
var chartData = json;
AmCharts.ready(function () {
chart = new AmCharts.AmPieChart();
chart.dataProvider = chartData;
// code ...
});
});
get-my-data.php (using mysqli) :
$mysqli = new mysqli("localhost", "my_user", "my_password", "my_database");
$stats = array();
$query = "
SELECT `country`, `litres`
FROM `mytable`
";
$statement = $mysqli->prepare($query);
$result = $statement->get_result();
while ($data = $result->fetch_assoc())
{
$stats[] = $data;
}
echo json_encode($stats);
If you don't want or can't use jQuery, there's a built-in solution using amCharts' own Data Loader plugin. To use it simply include plugins/dataloader/dataloader.min.js file from the same directory you include the rest of the amCharts js files, then add the following directive to your chart config:
AmCharts.makeChart("chartdiv", {
"type": "pie",
"dataLoader": {
"url": "data.php"
},
// the reset of your chart config
// ..
});
On the server-side you can use PHP function json_encode() to format your data as JSON. I.e.:
<?php
// load your data
// ...
// format as JSON
echo json_encode( $data );
?>
Here's more info about the plugin and how to get your data from MySQL server:
http://www.amcharts.com/tutorials/using-data-loader-to-connect-charts-to-mysql-data-base/

Javascript code when copy pasted in a function, doesnt get called. Otherwise it does. What is the logic here?

Following is the code written to load a chart by calling a function:
//Capture customer and measures values in an array
$("document").ready(function(){
$("button").click(function(){
Load_PieTest();
var custArray = new Array();
var measureArray = new Array();
var formElements = new Array();
$("#custSelect >option:selected").each(function(i){
custArray[i]=$(this).val();
});
//alert(custArray);
$("#measureSelect >option:selected").each(function(j){
measureArray[j]=$(this).val();
});
//alert(measureArray);
//Convert into suitable JSON
var length = Math.max(custArray.length, measureArray.length);
var k;
for(k=0;k<length;k++){
//alert("Inside for loop")
if(typeof(custArray[k])=="undefined"){
//alert("Undefined customer");
custArray[k]==null;
}else if(typeof(measureArray[k])=="undefined"){
//alert("Undefined measure");
measureArray[k]==null;
}
//alert("About to push into array");
formElements.push({"customer":custArray[k],"measure":measureArray[k]});
}
//alert("outside loop");
//alert(formElements[0].customer);
var chartSelect = document.getElementById("typeOfChart");
var chartOption = chartSelect.options[chartSelect.selectedIndex].value;
alert(chartOption);
//Call appropriate AMCharts javascripts
LoadCharts(chartOption,formElements);
});
});
LoadCharts is a function that loads a chart based on the selected option. Suppose PieChart is selected. Pie chart should pop up using AMCharts library
When writing the code for making the chart in between the script tag, it works fine. But if written in a function which is getting called, the inner custom methods AmCharts.ready() arent getting called. Following is the code wriitten by me:
function Load_PieTest(){
var chart;
var legend;
var chartData = [{
country: "Czech Republic",
litres: 301.90
}, {
country: "Ireland",
litres: 201.10
}, {
country: "Germany",
litres: 165.80
}, {
country: "Australia",
litres: 139.90
}, {
country: "Austria",
litres: 128.30
}, {
country: "UK",
litres: 99.00
}, {
country: "Belgium",
litres: 60.00
}];
alert("yupp");
AmCharts.ready(function () {
// PIE CHART
alert("No");
chart = new AmCharts.AmPieChart();
chart.dataProvider = chartData;
chart.titleField = "country";
chart.valueField = "litres";
chart.outlineColor = "#FFFFFF";
chart.outlineAlpha = 0.8;
chart.outlineThickness = 2;
// WRITE
chart.write("chartdiv");
});
}
</script>
same thing when written outside the function in the script tag. works fine.Please tell me why is it happening?
The answer to your question is that AmCharts.ready waits until the window.onload event has occurred to execute your function. In your example above, where it's not working, it's because the window.onload event has already fired before you called AmCharts.ready. So AmCharts.ready is just waiting indefinitely.
Just remove AmCharts.ready altogether and execute the function code directly. Like this:
}, {
country: "Belgium",
litres: 60.00
}];
alert("yupp");
// PIE CHART
alert("No");
chart = new AmCharts.AmPieChart();
chart.dataProvider = chartData;
chart.titleField = "country";
chart.valueField = "litres";
chart.outlineColor = "#FFFFFF";
chart.outlineAlpha = 0.8;
chart.outlineThickness = 2;
// WRITE
chart.write("chartdiv");
}
Perhaps the event which triggeres AmCharts.ready() has already fired before you call the function? Does this work:
function Load_PieTest(){
var chart;
var legend;
var chartData = [{
country: "Czech Republic",
litres: 301.90
}, {
country: "Ireland",
litres: 201.10
}, {
country: "Germany",
litres: 165.80
}, {
country: "Australia",
litres: 139.90
}, {
country: "Austria",
litres: 128.30
}, {
country: "UK",
litres: 99.00
}, {
country: "Belgium",
litres: 60.00
}];
//alert("yupp");
// PIE CHART
//alert("No");
chart = new AmCharts.AmPieChart();
chart.dataProvider = chartData;
chart.titleField = "country";
chart.valueField = "litres";
chart.outlineColor = "#FFFFFF";
chart.outlineAlpha = 0.8;
chart.outlineThickness = 2;
// WRITE
chart.write("chartdiv");
}
AmCharts.ready(function () {
Load_PieTest();
})
I moved the ready to outside, which calls the function.

Categories

Resources