How to insert complex code using DOM manipulation - javascript

I am still learning javascript.
Here is the site I am playing with. http://keysoft.keydesign-themes.com/demo1/
I want to insert google visualization chart code using DOM manipulation (insertAdjacentHTML) into this site.
Here is the code of google's timeline chart:
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'President' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'Washington', new Date(1789, 3, 30), new Date(1797, 2, 4) ],
[ 'Adams', new Date(1797, 2, 4), new Date(1801, 2, 4) ],
[ 'Jefferson', new Date(1801, 2, 4), new Date(1809, 2, 4) ]]);
chart.draw(dataTable);
}
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline" style="height: 180px;"></div>
I tried the code below in Chrome's console in order to insert it into this site but I think there are a lot of mistakes. Could you help me please how to improve the code below?
document.getElementsByClassName('container')[5].getElementsByClassName('row')[0].insertAdjacentHTML('afterend', '<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline" style="height: 180px;"></div>
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'President' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'Washington', new Date(1789, 3, 30), new Date(1797, 2, 4) ],
[ 'Adams', new Date(1797, 2, 4), new Date(1801, 2, 4) ],
[ 'Jefferson', new Date(1801, 2, 4), new Date(1809, 2, 4) ]]);
chart.draw(dataTable);
}');

You can turn this into a string literal by using back ticks (`) instead of single quotes. And to ensure it doesn't jam up on the script tags you will want to change the closing script tag inside the literal to
<\/script>
I don't know the rest of your HTML structure so there may also be some issues with selecting the elements you want to place the tag inside.
Here's a complete example of a simple page that works for me:
</head>
<body>
<div id="container" class='container'>
<div class="row"></div>
</div>
</body>
<script>'use strict';
document.getElementsByClassName('container')[0].getElementsByClassName('row')[0].insertAdjacentHTML('afterend', `<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"><\/script>
<div id="timeline" style="height: 180px;"></div>\n\n <script> google.charts.load(\'current\', {\'packages\':[\'timeline\']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById(\'timeline\');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: \'string\', id: \'President\' });
dataTable.addColumn({ type: \'date\', id: \'Start\' });
dataTable.addColumn({ type: \'date\', id: \'End\' });
dataTable.addRows([
[ \'Washington\', new Date(1789, 3, 30), new Date(1797, 2, 4) ],
[ \'Adams\', new Date(1797, 2, 4), new Date(1801, 2, 4) ],
[ \'Jefferson\', new Date(1801, 2, 4), new Date(1809, 2, 4) ]]);
chart.draw(dataTable);
}<\/script>`);
</script>
I changed the number of containers from 5 to 0 for simplicity's sake but in the browser this runs without issue and injects the JS code after the row element. The back ticks (`) are important .

Related

Using Years Only (Without Months or Days) with Google Timeline Charts

I want to show a timeline (with Google Charts) with years only.
However, the examples on Google Charts Timelines' webpage always comprise years, months and days (for instance, new Date(1789, 3, 30)).
I have tried reducing the new Date() to just a year (e.g. new Date(2019)), but Google Charts interprets it as seconds (2.019 seconds).
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load("current", {packages:["timeline"]});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('div_timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Nr' });
dataTable.addColumn({ type: 'string', id: 'Journal' });
dataTable.addColumn({ type: 'date', id: 'Founded' });
dataTable.addColumn({ type: 'date', id: 'Now' });
dataTable.addRows([
[ '1', 'Journal of Leisure Research', new Date(1969), new Date(2019) ],
[ '2', 'Critical Sociology', new Date(2009), new Date(2019) ],
[ '3', 'Geographical Analysis', new Date(1909), new Date(2019) ]
]);
chart.draw(dataTable,options);
}
</script>
With this code, Journal of Leisure Research is now 1.969 seconds to 2.019 seconds.
Instead, I want the chart to assign the years 1969 to 2019.
How can I do that? Thanks for your help!
Simply set the date to January 1st:
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Nr' });
dataTable.addColumn({ type: 'string', id: 'Journal' });
dataTable.addColumn({ type: 'date', id: 'Founded' });
dataTable.addColumn({ type: 'date', id: 'Now' });
dataTable.addRows([
[ '1', 'Journal of Leisure Research', new Date(1969,1,0), new Date(2019,1,0) ],
[ '2', 'Critical Sociology', new Date(2009,1,0), new Date(2019,1,0) ],
[ '3', 'Geographical Analysis', new Date(1909,1,0), new Date(2019,1,0) ]]);
chart.draw(dataTable);
}
</script>
</head>
<body>
<div id="timeline" style="height: 180px;"></div>
</body>
</html>

google charts timelines element border-radius

I have a problem figuring out how to set the border-radius on elements in a google charts Timeline. I have looked through all the options but there doesn't seem to be one for that.
I have tried manually setting it but without any luck.
Does anyone have a solution to this problem?
thx in advance
the chart elements can be modified when the chart's 'ready' event fires
however, the chart will revert back to the original style on any interactivity
a MutationObserver can be used to know when the chart has been modified
in order to re-apply the custom style / border radius
the chart is drawn using svg, to change the border radius on a rect element,
set attributes 'rx' and 'ry'
see the following working snippet...
google.charts.load('current', {
callback: drawChart,
packages: ['timeline']
});
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'President' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'Washington', new Date(1789, 3, 30), new Date(1797, 2, 4) ],
[ 'Adams', new Date(1797, 2, 4), new Date(1801, 2, 4) ],
[ 'Jefferson', new Date(1801, 2, 4), new Date(1809, 2, 4) ]
]);
var observer = new MutationObserver(setBorderRadius);
google.visualization.events.addListener(chart, 'ready', function () {
setBorderRadius();
observer.observe(container, {
childList: true,
subtree: true
});
});
function setBorderRadius() {
Array.prototype.forEach.call(container.getElementsByTagName('rect'), function (rect) {
if (parseFloat(rect.getAttribute('x')) > 0) {
rect.setAttribute('rx', 20);
rect.setAttribute('ry', 20);
}
});
}
chart.draw(dataTable);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline"></div>

how to use boolean type column in Google calendar charts?

I want to depict build status (Pass or fail) using a boolean type(true/false) on google's Calendar type charts. I am using the below HTML code for the same. But I am getting a red flag prompting me to add 2 columns . Any suggestions what could be wrong in this snippet ?
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load("current", {packages:["calendar"]});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'date', id: 'Date' });
dataTable.addColumn({ type: 'boolean',id :'pass/fail', role:'certainty' });
dataTable.addRows([
[ new Date(2012, 3, 13), true ],
[ new Date(2012, 3, 14), true ],
[ new Date(2012, 3, 15), true ],
[ new Date(2012, 3, 16), true ],
[ new Date(2012, 3, 17), false ]
// Many rows omitted for brevity.
]);
var chart = new google.visualization.Calendar(document.getElementById('calendar_basic'));
var options = {
title: "Build Execution Analytics",
height: 350,
};
chart.draw(dataTable, options);
}
</script>
</head>
<body>
<div id="calendar_basic" style="width: 1000px; height: 350px;"></div>
</body>
</html>
each chart type has a specific Data Format
Calendar charts do not accept a boolean column
from the reference, allowed columns are...
column 0 -- date, datetime, or timeofday
column 1 -- number
column n -- string -- role: tooltip (optional)
I would suggest using a certain number for pass and another for fail
google.charts.load('current', {
callback: function () {
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'date', id: 'Date' });
dataTable.addColumn({ type: 'number', id :'pass/fail' });
dataTable.addRows([
[ new Date(2012, 3, 13), 100 ], // pass
[ new Date(2012, 3, 14), 100 ], // pass
[ new Date(2012, 3, 15), 100 ], // pass
[ new Date(2012, 3, 16), 100 ], // pass
[ new Date(2012, 3, 17), 0 ] // fail
]);
var chart = new google.visualization.Calendar(document.getElementById('calendar_basic'));
chart.draw(dataTable, {
title: 'Build Execution Analytics',
height: 350,
});
},
packages:["calendar"]
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="calendar_basic"></div>

Google Timeline Chart: Color each bar individually when multiple on "same" line

The Google Timeline charts seem to suggest coloring individual blocks on the timeline per the documentation:
https://google-developers.appspot.com/chart/interactive/docs/gallery/timeline#ControllingColors
But there seems to be a problem when two bars "overlap" on the same line, as you can see in this fiddle:
http://jsfiddle.net/7A88H/21/
Here is the key code:
dataTable.addRows([
[ 'red/green/blue', 'NAME OF BAR (should be RED) (ff0000)', new Date(1789, 3, 29), new Date(1797, 2, 3) ],
[ 'red/green/blue', 'NAME OF BAR (should be GREEN) (00ff00)', new Date(1796, 2, 3), new Date(1801, 2, 3) ],
[ 'red/green/blue', 'NAME OF BAR (should be BLUE) (0000ff)', new Date(1801, 2, 3), new Date(1809, 2, 3) ]]);
var options = {
colors: ['#ff0000', '#00ff00', '#0000ff'],
};
I tried playing with the accepted answer from this question by adding a 5th column (the color) to my data rows:
Google Charts API: Add Blank Row to Timeline?
Specifically, here is the function I thought I might be able to hijack to build my hack:
(function(){ //anonymous self calling function to prevent variable name conficts
var el=container.getElementsByTagName("rect"); //get all the descendant rect element inside the container
var width=100000000; //set a large initial value to width
var elToRem=[]; //element would be added to this array for removal
for(var i=0;i<el.length;i++){ //looping over all the rect element of container
var cwidth=parseInt(el[i].getAttribute("width"));//getting the width of ith element
if(cwidth<width){ //if current element width is less than previous width then this is min. width and ith element should be removed
elToRem=[el[i]];
width=cwidth; //setting the width with min width
}
else if(cwidth==width){ //if current element width is equal to previous width then more that one element would be removed
elToRem.push(el[i]);
}
}
for(var i=0;i<elToRem.length;i++)
elToRem[i].setAttribute("fill","none"); //make invisible all the rect element which has minimum width
})();
The hope was to grab each rect (skipping the bounding ones) and filling them (with a third loop, at the end) with their appropriate colors, but I couldn't figure out how to get their associated color (which was in the row objects) from the rect objects themselves.
I think you will need to use the additional options:
timeline: { groupByRowLabel: false }
Because, if you go to the g-page: https://google-developers.appspot.com/chart/interactive/docs/gallery/timeline#BarsOneRow in the Bars in One Row section they show how Presidents DON'T overlap, so you can't use it in this case, but for the method you are using it, timelines do overlap so they must be in their own row. It would probably be hard to read overlapping titles anyhow.
Side note: I noticed what google is doing. It's assigning the colors left to right, then wrapping. The titles however, are not wrapping, they just go left to right. Here is a fiddle I made: https://jsfiddle.net/camp185/2Lopnnt3/2/ to show how wrapping of colors working...added more colors.
function drawChart() {
var container = document.getElementById('example5.4');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Role' });
dataTable.addColumn({ type: 'string', id: 'Name' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'red/green/blue', 'NAME OF BAR (should be RED) (ff0000)', new Date(1789, 3, 29), new Date(1797, 2, 3) ],
[ 'red/green/blue', 'NAME OF BAR (should be GREEN) (00ff00)', new Date(1796, 2, 3), new Date(1801, 2, 3) ],
[ 'red/green/blue', 'NAME OF BAR (should be BLUE) (0000ff)', new Date(1801, 2, 3), new Date(1809, 2, 3) ]]);
var options = {
colors: ['#ff0000', '#00ff00', '#0000ff'],
timeline: { groupByRowLabel: false }
};
chart.draw(dataTable, options);
}
google.load('visualization', '1', {packages:['timeline'], callback: drawChart});
<script src="https://www.google.com/jsapi?.js"></script>
<div id='example5.4'></div>
Hope this will help you:
google.load("visualization", "1", {packages:["timeline"]});
google.setOnLoadCallback(drawChart);
// google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('example5.4');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Role' });
dataTable.addColumn({ type: 'string', id: 'Name' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'red/green/blue', 'NAME OF BAR (should be RED) (ff0000)', new Date(1789, 3, 30), new Date(1797, 2, 4) ],
[ 'red/green/blue', 'NAME OF BAR (should be GREEN) (00ff00)', new Date(1797, 2, 4), new Date(1801, 2, 4) ],
[ 'red/green/blue', 'NAME OF BAR (should be BLUE) (0000ff)', new Date(1801, 2, 4), new Date(1809, 2, 4) ]
]);
// dataTable.addRows([
// [ 'red/green/blue', 'NAME OF BAR (should be RED) (ff0000)', new Date(1789, 3, 29), new Date(1797, 2, 3) ],
// [ 'red/green/blue', 'NAME OF BAR (should be GREEN) (00ff00)', new Date(1796, 2, 3), new Date(1801, 2, 3) ],
// [ 'red/green/blue', 'NAME OF BAR (should be BLUE) (0000ff)', new Date(1801, 2, 3), new Date(1809, 2, 3) ]]);
var options = {
colors: ['#ff0000', '#00ff00', '#0000ff'],
};
chart.draw(dataTable, options);
}
<script src="https://www.google.com/jsapi?.js"></script>
<div id='example5.4'></div>
There are two ways to do what you want, both of which change the background color based on the title you give the row. With your current code, when you hover over one of the rows, it displays information about that row. However, when leaving the hover, it redraws the box, making it much more complicated. I have done it both ways for you:
JSFiddle with Interactivity disabled (much simpler.. unfortunately I did this one after I did the complicated one)
JSFiddle with Interactivity enabled and messy setTimeOut functions (doesn't always work)
Here's the code when interactivity is disabled:
function drawChart() {
var container = document.getElementById('example5.4');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Role' });
dataTable.addColumn({ type: 'string', id: 'Name' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'red/green/blue', 'SHORT TEXT GREEN(00ff00)', new Date(1796, 2, 3), new Date(1801, 2, 3) ],
[ 'red/green/blue', 'NAME OF BAR (should be BLUE) (0000ff)', new Date(1801, 2, 3), new Date(1809, 2, 3) ],
[ 'red/green/blue', 'NAME OF BAR (should be RED) (ff0000)', new Date(1789, 3, 29), new Date(1797, 2, 3) ]]);
// dataTable.addRows([]);
var options = {
colors: ['#000', '#000', '#000'], // assign black background to each row
enableInteractivity: false //interactivity disabled
};
chart.draw(dataTable, options);
var elements = document.getElementsByTagName("text");
for(var el in elements)
{
if(typeof colorArray[elements[el].innerHTML] != "undefined")
{
setColor(elements[el],colorArray[elements[el].innerHTML]);
}
}
}
google.load('visualization', '1', {packages:['timeline'], callback: drawChart});
var colorArray = []; // format: colorArray["TEXT IN ROW"] = "COLOR"
colorArray["NAME OF BAR (should be RED) (ff0000)"] = "#ff0000";
function setColor(elem,newColor)
{
var rect = elem.previousSibling;
var rTitle = rect.innerHTML;
rect.setAttribute("fill",newColor);
}
NOTE: if the page is too narrow and text in a row is shortened with an ellipsis (...), this method fails because it is based off of the text in each row.
-- Old answer with no hack --
After looking into it further, it appears a simple way to fix this is by shortening the text of the green bar, because even when adding a new, separate row, the text for the green box doesn't fit inside of the box.
Additionally, it is processing the colors by line, so the Blue bar is getting the green color since the Green bar is being pushed to a new line. I would add any rows that will make a new line in a separate statement just to make it map out more logically, although it doesn't make a difference what order the arrays are in.
Here's the JSFiddle

timeline charts not working in Google Apps Script

I'm trying to draw some charts with Google Visualization API in Apps Script.
All charts work fine (PieChart, ComboChart...) but timeline.
If I copy/paste my code in a HTML file works fine however in an Apps Script project throw this error when a call the builder (new google.visualization.Timeline(container): "undefined is not a function".
Here my code:
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load('visualization', '1', {packages: ['corechart','timeline']});
function pintarGraficaTimeline(){
var chart = new google.visualization.Timeline(document.getElementById('divGrafica'));
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'President' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'Washington', new Date(1789, 3, 29), new Date(1797, 2, 3) ],
[ 'Adams', new Date(1797, 2, 3), new Date(1801, 2, 3) ],
[ 'Jefferson', new Date(1801, 2, 3), new Date(1809, 2, 3) ]]);
chart.draw(dataTable);
}
</script>
</head>
<body style="font-family: Arial;border: 0 none;">
<div id="divGraficaTimeline" style="float:right;display:block;">
<div style="float: right;"> <input type="button" value="Buscar" style="float: right;margin-right: 4%;" onclick="pintarGraficaTimeline()" /></div>
</div>
<div id="divGrafica" > </div>
Doesn't Timeline package work in Apps Scripts??
The Timeline package is not yet available in Apps Script, though that shouldn't be an issue since you are not using Apps Script to drive the visualizations. This seems likely to be caused by trying to draw the chart before the API finishes loading. Try assigning your button click event in a callback from the google loader:
function init () {
var el = document.querySelector('#divGraficaTimeline input');
if (document.addEventListener) {
el.addEventListener('click', pintarGraficaTimeline);
}
else if (document.attachEvent) {
el.attachEvent('onclick', pintarGraficaTimeline);
}
else {
el.onclick = pintarGraficaTimeline;
}
}
google.load('visualization', '1', {packages: ['corechart','timeline'], callback: init});

Categories

Resources