Background - I have a spreadsheet with some data in it, I want to prepare and present some "dynamic charts" from this data, what I have thought is create some charts in script editor - HTML and then in the .gs code call this HTML file with a doGet function (after publishing - will be used by Internal members only)
A similar example of chart can be viewed here but when I add the HTML code to the HTML page and Javascript code as with script tags in the HTML page, nothing is displayed in the browser.
How can I implment this chart (or other with similar type) within google doGet function.
Code
<script src="http://www.amcharts.com/lib/amcharts.js" type="text/javascript"></script>
<div id="chartdiv" style="width: 100%; height: 362px;"></div>
var lineChartData = [{
date: new Date(2009, 10, 2),
value: 5},
{
date: new Date(2009, 10, 3),
value: 15},
{
date: new Date(2009, 10, 4),
value: 13},
{
date: new Date(2009, 10, 5),
value: 17},
{
date: new Date(2009, 11, 4),
value: 26}];
AmCharts.ready(function() {
var chart = new AmCharts.AmSerialChart();
chart.dataProvider = lineChartData;
chart.pathToImages = "http://www.amcharts.com/lib/images/";
chart.categoryField = "date";
// sometimes we need to set margins manually
// autoMargins should be set to false in order chart to use custom margin values
chart.autoMargins = false;
chart.marginRight = 0;
chart.marginLeft = 0;
chart.marginBottom = 22;
chart.marginTop = 0;
// AXES
// category
var categoryAxis = chart.categoryAxis;
categoryAxis.parseDates = true; // as our data is date-based, we set parseDates to true
categoryAxis.minPeriod = "DD"; // our data is daily, so we set minPeriod to DD
categoryAxis.gridAlpha = 0;
categoryAxis.tickLength = 0;
categoryAxis.axisAlpha = 0;
// value
var valueAxis = new AmCharts.ValueAxis();
valueAxis.dashLength = 4;
valueAxis.axisAlpha = 0;
chart.addValueAxis(valueAxis);
// GRAPH
var graph = new AmCharts.AmGraph();
graph.type = "line";
graph.valueField = "value";
graph.lineColor = "#D8E63C";
graph.customBullet = "http://www.amcharts.com/lib/images/star.gif"; // bullet for all data points
graph.bulletSize = 14; // bullet image should be a rectangle (width = height)
graph.customBulletField = "customBullet"; // this will make the graph to display custom bullet (red star)
chart.addGraph(graph);
// CURSOR
var chartCursor = new AmCharts.ChartCursor();
chart.addChartCursor(chartCursor);
// WRITE
chart.write("chartdiv");
});
Apologies, if I am not able to explain it properly. I am still a newbie in this...
(Note:- have deleted some part of actual code to make it short)
If I understood your question right, you need to use the HTML Service to display that code. Basically, your Apps Script project will have two files, one Code.gs and an html file. Then, use the following in Code.gs, assuming the file with the HTML is called "index.html".
function doGet() {
return HtmlService.createHtmlOutputFromFile('index').setSandboxMode(HtmlService.SandboxMode.NATIVE);
}
Good luck using AmCharts, though - I've never tried that one. However, every other charts library I've tried has failed in HTML Service except for Piety. The Caja sanitizer prevents a lot of stuff from running.
Related
I would like to be able to plot two or three values on one stacked gauge chart, similar to the following, with a light green, on top of another blue and a main thick value:
I have seen examples of these lines being separated, which would also do.
The first two need not be superimposed, but would be nice.
In looking at https://github.com/pguso/jquery-plugin-circliful, I can create multiple values on a chart but only in full-circle, not half-circle.
In the following JSFiddle, https://jsfiddle.net/0c8qaqaj/41/
<section class="container">
<h3>Circliful</h3>
<div class="row">
<div class="col-lg-4">
<div id="test-circle"></div>
</div> </div>
</section>
<script>
$( document ).ready(function() { // 6,32 5,38 2,34
$("#test-circle").circliful({
animation: 1,
animationStep: 5,
foregroundBorderWidth: 7,
backgroundBorderWidth: 7,
percent: 99,
textSize: 28,
textStyle: 'font-size: 12px;',
textColor: '#666',
multiPercentage: 1,
//halfCircle: 1,
halfCircle: false,
percentages: [
{'percent': 10, 'color': '#3180B8', 'title': 'Gryffindor' },
{'percent': 30, 'color': '#4ADBEA', 'title': 'Ravenclaw' },
{'percent': 50, 'color': '#49EBA8', 'title': 'Hufflepuff' },
{'percent': 70, 'color': '#FFCA35', 'title': 'Slytherin' }
],
multiPercentageLegend: 1,
replacePercentageByText: '',
backgroundColor: '#eee',
icon: 'f0d0',
iconPosition: 'middle',
iconColor: '#273B4E'
});
});
</script>
Setting 'halfCircle: true', only draws one value. Obviously not what I'm looking for.
The library does have a sample with two values, although I'm not sure how to replicate this example and whether or not it would work in halfcircle or if I can create an array to stack these values.
In another test, using AMCharts, I was able to create a semi-circle, stacked gauge chart.
A few issues:
I am unable to change the chart line widths manually. They seem to be proportional to the larger of the chart's height or width setting.
Setting width: 350:
I cannot change the white-space/padding above/below the charts. This one is fixable using css position: relative; left: -150; or whatever works. I don't really want to have to do this for anything around sides (top, bottom, etc.)
The charts do not display in a '' tag. To get in-line charts, I am using table cells.
Here is the JSFiddle for it.
I managed to locate a closer example of what I'm looking for in Chart.JS
The issue remains that I still am unable achieve exactly what I'm looking for as once again, the line sizing seems to be directly proportional to the container. You can see this by resizing the window.
The question/problem: I am m looking for a library that gives me the ability to customize the line widths in semi-circular gauge/doughnut charts and not be auto-constrained to the chart's dimensions.
Any recommendations on another library that would give me what I'm looking for please?
There is more than one way to do it with amCharts 4, here is one:
am4core.useTheme(am4themes_animated);
var chart = am4core.create("chartdiv", am4charts.GaugeChart);
chart.innerRadius = am4core.percent(80);
var colorSet = new am4core.ColorSet();
var axis = chart.xAxes.push(new am4charts.ValueAxis());
axis.min = 0;
axis.max = 100;
axis.renderer.innerRadius = 10
axis.strictMinMax = true;
axis.renderer.labels.template.disabled = true;
axis.renderer.ticks.template.disabled = true;
axis.renderer.grid.template.disabled = true;
var range0 = axis.axisRanges.create();
range0.value = 0;
range0.endValue = 60;
range0.axisFill.fillOpacity = 1;
range0.axisFill.fill = colorSet.getIndex(0);
range0.grid.disabled = true;
var range1 = axis.axisRanges.create();
range1.value = 60;
range1.endValue = 100;
range1.axisFill.fillOpacity = 1;
range1.axisFill.fill = am4core.color("#DADADA");
range1.grid.disabled = true;
var axis2 = chart.xAxes.push(new am4charts.ValueAxis());
axis2.min = 0;
axis2.max = 100;
axis2.strictMinMax = true;
axis2.renderer.labels.template.disabled = true;
axis2.renderer.ticks.template.disabled = true;
axis2.renderer.grid.template.disabled = true;
var range2 = axis2.axisRanges.create();
range2.value = 0;
range2.endValue = 90;
range2.axisFill.fillOpacity = 1;
range2.axisFill.fill = colorSet.getIndex(3);
range2.axisFill.radius = am4core.percent(105);
range2.axisFill.innerRadius = am4core.percent(100); // set it to >100 if you'd like to have some gap between fills
range2.grid.disabled = true;
var range3 = axis2.axisRanges.create();
range3.value = 90;
range3.endValue = 100;
range3.axisFill.fillOpacity = 0.5;
range3.axisFill.fill = am4core.color("#DADADA");
range3.axisFill.radius = am4core.percent(105);
range3.axisFill.innerRadius = am4core.percent(100); // set it to >100 if you'd like to have some gap between fills
range3.grid.disabled = true;
var label = chart.radarContainer.createChild(am4core.Label);
label.isMeasured = false;
label.fontSize = 45;
label.x = am4core.percent(50);
label.y = am4core.percent(100);
label.horizontalCenter = "middle";
label.verticalCenter = "bottom";
label.text = "50%";
And this is a result: https://codepen.io/team/amcharts/pen/qgxyZK
Having a hard time understanding why some objects won't return properly:
If I run console.log(obj.R) it returns "different", as expected. If I run console.log(obj.g) it just returns undefined. My goal is to return the first value of the g object, so something like console.log(obj.g[0]) and have the value "0.04600" returned.
Full function as requested:
function buildCandleStickChart_() {
CurrencyDataService.getChartData('BTC', vm_.selectedMarket).
then(function(data) {
// Set a default theme for the entire chart.
anychart.theme({
'defaultFontSettings': {
'fontSize': 12,
'fontFamily': 'Roboto'
}
});
var table = anychart.data.table();
// Map API data to table data.
dataArray = data.response.map(function(obj) {
// Format Date
var formatedDate = moment(obj.time * 1000).format('M-D HH:mm');
return [formatedDate, obj.open, obj.high, obj.low, obj.close, obj.volumeto];
});
// Add API data to table.
table.addData(dataArray);
// Map data to candlesticks.
var mapping = table.mapAs();
mapping.addField('open', 1, 'first');
mapping.addField('high', 2, 'max');
mapping.addField('low', 3, 'min');
mapping.addField('close', 4, 'last');
// Map data to volume bars.
var volMapping = table.mapAs();
volMapping.addField('value', 5);
// Get current lowest price.
var getLowestValue = _.minBy(data.response, 'low');
lowestLow = getLowestValue.low;
// Get current highest price.
var getHighestValue = _.maxBy(data.response, 'high');
highestHigh = getHighestValue.high;
// Scale down the volume bars.
var getHighestVolume = _.maxBy(data.response, 'volumeto');
var highestVolume = getHighestVolume.volumeto;
var getLowestVolume = _.minBy(data.response, 'volumeto');
var lowestVolume = getLowestVolume.volumeto;
// Initialize the chart.
var chart = anychart.stock();
candleStickChartRef = chart;
candleStickPlotRef = chart.plot(0);
// Initialize the candlesticks.
var candleSticks = chart.plot(0).candlestick(mapping);
candleSticks.name(vm_.selectedMarket);
// Toggle chart tooltip
chart.tooltip(false);
// Chart Padding
var padding = chart.padding();
padding.bottom(0);
padding.left(0);
padding.right(88);
padding.top(0);
// Chart Margins
var margin = chart.margin();
margin.bottom(-1);
margin.left(0);
margin.top(-1);
margin.right(0);
// Create custom date time scale.
var dateTimeScale = anychart.scales.dateTime();
var dateTimeTicks = dateTimeScale.ticks();
dateTimeTicks.interval(0, 0, 0, 1);
// Style the X-Axis.
var xAxis = chart.plot(0).xAxis();
xAxis.background('#FFFFFF');
xAxis.height(24);
xAxis.enabled(true);
// Adjust axis labels.
var labels = xAxis.labels();
labels.format(function(value) {
var date = new Date(value.tickValue);
var formattedDate = moment(date).format('MMM DD, HH:mm');
return formattedDate;
});
labels.width(118);
// Apply date time scale.
var scale = chart.xScale();
scale.ticks([{major: {unit: 'minute', count: 15}, minor: {unit: 'second', count: 1}}]);
// Declare the Y-Axis scale.
var yScale = chart.plot(0).yScale();
// Set the position of the Y-Axis values.
var yAxis = chart.plot(0).yAxis(0);
yAxis.orientation('right');
yAxis.drawFirstLabel(true);
yAxis.drawLastLabel(false);
// Set the position of the Y-Axis labels.
var yLabels = chart.plot(0).yAxis().labels();
yLabels.offsetX(0);
yLabels.format(function() {
return this.value.toFixed(vm_.currencySettings[vm_.selectedMarket].decimal);
});
console.log(chart.plot(0).yAxis().labels());
// Horizontal Grid Lines.
chart.plot(0).yGrid().enabled(true);
chart.plot(0).yGrid().stroke('#ced4da', 1);
// Enable current price indicator.
var indicator = chart.plot(0).priceIndicator();
// Set line settings.
indicator.value('last-visible');
indicator.fallingStroke('#ff6b6b');
indicator.fallingLabel({background: '#ff6b6b'});
indicator.risingStroke('#20c997');
indicator.risingLabel({background: '#20c997'});
indicator.label().fontColor('White');
indicator.label().fontFamily('Roboto');
// Initialize the volume bars.
var volumeBars = chart.plot(0);
var volume = volumeBars.column(volMapping).name('Volume');
volume.zIndex(1);
// Create and tune Y-Scale for volume bars.
var extraYScale = anychart.scales.linear();
extraYScale.maximum(highestVolume + (highestVolume * 4));
extraYScale.minimum(lowestVolume);
volume.yScale(extraYScale);
// Enable Legend.
var legend = chart.plot(0).legend();
legend.enabled(false);
// Set legend position.
legend.positionMode('inside');
// Style legend.
legend.position('top');
legend.align('left');
legend.background().enabled(true);
legend.background().fill('#fff', 0.87);
legend.background().stroke('#ced4da', 1);
legend.padding(8);
legend.margin(8);
legend.drag(true);
// Set listener on the chart container.
document.getElementById('chart-left').onclick = function(event) {
mouseHoverHandler_(event);
};
// Event handler to get Y-Axis value on click.
function mouseHoverHandler_(event) {
// X click coordinate on plot.
var y = event.offsetY;
// Plot bounds related to chart container.
var plotHeight = chart.plot(0).yAxis().getPixelBounds().height;
// Plot left margin
var plotTopoffset = chart.plot(0).yAxis().getPixelBounds().top;
// Click on data area.
if (y < plotTopoffset || y > plotTopoffset + plotHeight) {
return;
}
// Get value of click related to yScale.
var ratio = (y - plotTopoffset) / plotHeight;
var value = (yScale.inverseTransform(1 - ratio)).toFixed(8);
// Setting this value triggers watch which will build line.
vm_.chartSelectedSwapRate = parseFloat(value);
}
// Customize the crosshair and yLabel.
chart.crosshair(true);
chart.crosshair().xLabel(false);
chart.crosshair().yLabel().format(function() {
return Number(this.value).toFixed(8);
});
chart.crosshair().xStroke(null);
chart.crosshair().yStroke('#212529', 1);
chart.crosshair().yLabel().fontColor('#fff');
chart.crosshair().yLabel().fontSize(12);
chart.crosshair().yLabel().padding(2);
chart.crosshair().yLabel().hAlign('center');
chart.crosshair().yLabel().width(78);
chart.crosshair().yLabel().fontFamily('Roboto');
chart.crosshair().yLabel().background({
fill: '#212529',
stroke: '#212529'
});
// Toggle the timeline scroller.
chart.scroller().enabled(false);
// Configure the visual settings of the falling candlesticks.
candleSticks.fallingFill('#ff6b6b');
candleSticks.fallingStroke('#ff6b6b', 1, '0', 'round');
// Configure the visual settings of the rising candlesticks.
candleSticks.risingFill('#20c997');
candleSticks.risingStroke('#20c997', 1, '0', 'round');
// Configure the visual settings of the volume bars.
volume.normal().fill('#e9ecef');
// Set the width of candlesticks and volume bars.
chart.plot(0).pointWidth(6);
// Toggle the default contextual menu.
chart.contextMenu(false);
// Enable the custom contextual menu.
// var customContextMenu = anychart.ui.contextMenu();
// Build the custom contextual menu.
// (TODO)jberthelot: Connect these menu actions with the Go Long and Go Short sidebar
// functions.
// customContextMenu.attach(chart);
// customContextMenu.itemsFormatter(function(items) {
// items = {
// 'menu-item-1': {
// 'text': 'Create a Long Cryptoswap',
// 'action': function() {
// alert('You are going Long!');
// }
// },
// 'menu-item-2': {
// 'text': 'Create a Short Cryptoswap',
// 'action': function() {
// alert('You are going Short!');
// }
// }
// };
// return items;
// });
// Add a custom class name to the contextual menu for easier styling.
// customContextMenu.addClassName('custom-context-menu');
// Set the candlestick chart container element.
chart.container('chart-left');
// Initiate the candlestick chart display.
if (vm_.chart) {
vm_.chart.dispose();
}
vm_.chart = chart;
chart.draw();
});
}
I have a json with the name of each server and 3 values: memory, load and cpu.
[
{
"server": "Server1",
"Load": "0.04",
"Mem": "64.46",
"Idle": "97.00"
},
{
"server": "Server2",
"Load": "0.01",
"Mem": "64.79",
"Idle": "97.49"
}
]
I'm having some issues trying to create Google Chart dynamically. Looks like Javascript can't create variables using the loop variable 'i'. See my code below:
var obj = JSON.parse(jsonData);
for (i in obj)
{
var data_table[i] = new google.visualization.DataTable();
data_table[i].addColumn('string', 'Label');
data_table[i].addColumn('number', 'Value');
var server = obj[i].server;
var Load = parseFloat(obj[i].Load);
var Mem = parseFloat(obj[i].Mem);
var Idle = parseFloat(obj[i].Idle);
data_table[i].addRow([server, Load]);
data_table[i].addRow([server, Mem]);
data_table[i].addRow([server, Idle]);
var options = {width: 1500, height: 1000, redFrom: 90, redTo: 100, yellowFrom:75, yellowTo: 90, minorTicks: 5};
var chart[i] = new google.visualization.Gauge(document.getElementById('chart_div'+ i +));
chart[i].draw(data_table+i+, options); ' );
$('body').append('<div id="div'+ i +'" />')
}
I want to create the Chart dynamically to control these chart's later in the javascript/html and also and most important because my json is a little big so I want to avoid to have to create each chart one by one, or have to separate the json for each server.
Any help will be really appreciated. ;-)
Try it like this...
// load json
var obj = JSON.parse(jsonData);
// define arrays to store data and charts
var data_tables = [];
var google_charts = [];
// this is the div that will store all of the charts
var chart_area;
chart_area = document.getElementById('chart_div');
// set the chart options
var chart_options;
chart_options = {
width: 1500,
height: 1000,
redFrom: 90,
redTo: 100,
yellowFrom: 75,
yellowTo: 90,
minorTicks: 5
};
// process json array -- fyi: use 'in' keyword for object keys
for (var i = 0; i < obj.length; i++) {
var chart_container; // chart container for this json instance
var data_table; // data table for this json instance
var google_chart; // google chart for this json instance
// load data table
data_table = new google.visualization.DataTable();
data_table.addColumn('string', 'Label');
data_table.addColumn('number', 'Value');
data_table.addRow([obj[i].server, parseFloat(obj[i].Load)]);
data_table.addRow([obj[i].server, parseFloat(obj[i].Mem)]);
data_table.addRow([obj[i].server, parseFloat(obj[i].Idle)]);
// save it to the array
data_tables.push(data_table);
// create the container for this chart
chart_container = document.createElement('DIV');
chart_area.appendChild(chart_container);
// create -- save -- draw the chart
google_chart = new google.visualization.Gauge(chart_container);
google_charts.push(google_chart);
google_chart.draw(data_table, chart_options);
}
// access the charts / data later using arrays --> data_tables and google_charts
I created an amchart for plotting time based area. I need to add an export to image option to this graph. Below shows my amchart code. What are the lines needed to add the export to image option to this graph
AmCharts.ready(function () {
// first we generate some random data
generateChartData();
// SERIAL CHART
chart = new AmCharts.AmSerialChart();
chart.pathToImages = "../amcharts/images/";
chart.dataProvider = chartData;
chart.categoryField = "date";
// data updated event will be fired when chart is first displayed,
// also when data will be updated. We'll use it to set some
// initial zoom
chart.addListener("dataUpdated", zoomChart);
// AXES
// Category
var categoryAxis = chart.categoryAxis;
categoryAxis.parseDates = true; // in order char to understand dates, we should set parseDates to true
categoryAxis.minPeriod = "mm"; // as we have data with minute interval, we have to set "mm" here.
categoryAxis.gridAlpha = 0.07;
categoryAxis.axisColor = "#DADADA";
// Value
var valueAxis = new AmCharts.ValueAxis();
valueAxis.gridAlpha = 0.07;
valueAxis.title = "Unique visitors";
chart.addValueAxis(valueAxis);
// GRAPH
var graph = new AmCharts.AmGraph();
graph.type = "line"; // try to change it to "column"
graph.title = "red line";
graph.valueField = "visits";
graph.lineAlpha = 1;
graph.lineColor = "#d1cf2a";
graph.fillAlphas = 0.3; // setting fillAlphas to > 0 value makes it area graph
chart.addGraph(graph);
// CURSOR
var chartCursor = new AmCharts.ChartCursor();
chartCursor.cursorPosition = "mouse";
chartCursor.categoryBalloonDateFormat = "JJ:NN, DD MMMM";
chart.addChartCursor(chartCursor);
// SCROLLBAR
var chartScrollbar = new AmCharts.ChartScrollbar();
chart.addChartScrollbar(chartScrollbar);
// WRITE
chart.write("chartdiv");
});
You should just be able to add the following before you write the chart to the DIV.
"exportConfig":{
"menuTop": 0,
menuItems: [{
textAlign: 'center',
icon: 'images/graph_export.png',
iconTitle: 'Save chart as an image',
onclick:function(){},
items: [
{title:'JPG', format:'jpg'},
{title:'PNG', format:'png'},
{title:'SVG', format:'svg'}
]
}]
}
This will give you a download icon on the graph to download in either JPG, PNG or SVG formats.
Try this code :
chart.export = {
enabled: true,
position: "bottom-right"
}
chart.initHC = false;
chart.validateNow();
And don't forget to include the needed export plugin!
I have multiple graphs per chart and for some unknown(to me) reason each graph is connected by the start and the end points of it e.g.
Simple question: How to remove it? I couldn't find anything in the documentation that controls it.
My code as follows:
lineChart = function(id, period) {
var chart, data = [];
var cData = chartData[id];
AmCharts.ready(function() {
for (item in cData) {
var i = cData[item];
data.push({
date: new Date(i.date),
impressions: i.impressions,
clicks: i.clicks,
conversions: i.conversions,
ctr: i.ctr,
profit: i.profit,
cost: i.cost,
revenue: i.revenue
});
}
chart = new AmCharts.AmSerialChart();
chart.dataProvider = data;
chart.categoryField = "date";
chart.balloon.color = "#000000";
// AXES
// category
var categoryAxis = chart.categoryAxis;
categoryAxis.fillAlpha = 1;
categoryAxis.fillColor = "#FAFAFA";
categoryAxis.gridAlpha = 0;
categoryAxis.axisAlpha = 0;
categoryAxis.minPeriod = period;
categoryAxis.parseDates = true;
categoryAxis.gridPosition = "start";
categoryAxis.position = "bottom";
// value
var valueAxis = new AmCharts.ValueAxis();
valueAxis.dashLength = 5;
valueAxis.axisAlpha = 0;
valueAxis.integersOnly = true;
valueAxis.gridCount = 10;
chart.addValueAxis(valueAxis);
// GRAPHS
// Impressions graph
var graph = new AmCharts.AmGraph();
graph.title = "Impressions";
graph.valueField = "impressions";
graph.balloonText = "[[title]]: [[value]]";
//graph.lineAlpha = 1;
graph.bullet = "round";
chart.addGraph(graph);
// Clicks graph
var graph = new AmCharts.AmGraph();
graph.title = "Clicks";
graph.valueField = "clicks";
graph.balloonText = "[[title]]: [[value]]";
graph.bullet = "round";
chart.addGraph(graph);
// Conversions graph
var graph = new AmCharts.AmGraph();
graph.title = "Conversion";
graph.valueField = "conversions";
graph.balloonText = "[[title]]: [[value]]";
graph.bullet = "round";
chart.addGraph(graph);
// LEGEND
var legend = new AmCharts.AmLegend();
legend.markerType = "circle";
chart.addLegend(legend);
var chartCursor = new AmCharts.ChartCursor();
chartCursor.cursorPosition = "mouse";
if(period == 'hh')
chartCursor.categoryBalloonDateFormat = "MMM DD, JJ:00";
chart.addChartCursor(chartCursor);
// WRITE
chart.write(id);
});
};
This looks like the data issue. Make sure your data points are strictly in consecutive ascending order.
To verify how your actual data looks like, add the second line below to your code. Then run your chart in Google Chrome with Console open (F12 then select Console tab)
chart.dataProvider = data;
console.debug(data);
Check the datapoints for irregularities. Especially the last two ones.
The problem was that each chart was rendered within it's own AmCharts.ready method. The documentation states that it's allowed, however it didn't work for me, therefore I wrapped all rendering within one ready method and the issue was fixed.