How to change Line Opacity in google charts? - javascript

I am using Google Charts and I am able to change the colour of a line half way through a graph conditionally using a dataView, as shown in code below:
var dataView = new google.visualization.DataView(data);
dataView.setColumns([
// reference existing columns by index
0, 1,
// add function for line color
{
calc: function (data, row) {
var colorDown = '#ff9900';
var colorUp = '#27B291';
var opacity = 'opacity, 0.2;'
var currentdate = new Date();
var givendate = new Date(row.getValue)
if (data.getValue(row, 0) > currentdate) {
return colorDown;
} else {
return colorUp;
}
},
type: 'string',
role: 'style'
}
]);
I was wondering if there is way I can also change the line opacity conditionally as I can't seem to find a way to do it and other methods I have tried do not seem to work? Thanks.

using the style column role, you can combine color and opacity as follows...
'color: #ff9900;opacity: 0.2;'
see following working snippet...
google.charts.load('current', {
packages: ['corechart']
}).then(function () {
var data = new google.visualization.arrayToDataTable([
['x', 'y'],
[new Date(2018, 6, 15), 2924],
[new Date(2018, 6, 16), 2381],
[new Date(2018, 6, 17), 2489],
[new Date(2018, 6, 18), 2235],
[new Date(2018, 6, 19), 2155],
[new Date(2018, 6, 20), 2844],
]);
var container = document.getElementById('chart_div');
var chart = new google.visualization.LineChart(container);
var dataView = new google.visualization.DataView(data);
dataView.setColumns([
// reference existing columns by index
0, 1,
// add function for line color
{
calc: function (data, row) {
var colorDown = 'color: #ff9900;';
var colorUp = 'color: #27B291;';
var opacity = 'opacity: 0.2;'
var currentdate = new Date();
var givendate = new Date(row.getValue)
if (data.getValue(row, 0) > currentdate) {
return colorDown + opacity;
} else {
return colorUp + opacity;
}
},
type: 'string',
role: 'style'
}
]);
chart.draw(dataView, {
legend: {
position: 'none'
}
});
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Related

Add custom icon on specific point on google charts timeline [duplicate]

I want to add markers on the Google Timeline chart as shown here Timeline Chart with Markers
I am currently following the solution given here: Google Charts Add Layer On Top Of Timeline. But, here there needs to be a timeline element only then can the marker be present over it. But, I want a way that a marker can be added without having any timeline data at that position in the row. Is there a built in feature for adding markers in Google Timelines, or a custom way which does not require adding a dummy timeline.
there are no built-in features for adding markers.
and since the answer you reference is a custom solution,
we can modify the solution to fit our needs.
we don't necessarily need a timeline element in order to place a marker.
but we do need data, in order to draw the timeline,
on which to place the markers.
out of the box, the timeline will limit the x-axis to the range of dates found in the data.
but we can set a custom x-axis range, to make it larger,
and allow more room for markers, where there are no timeline elements.
hAxis: {
minValue: dateRangeStart,
maxValue: dateRangeEnd,
}
see following working snippet...
google.charts.load('current', {
packages:['timeline']
}).then(function () {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({type: 'string', id: 'Row'});
dataTable.addColumn({type: 'string', id: 'Bar'});
dataTable.addColumn({type: 'date', id: 'Start'});
dataTable.addColumn({type: 'date', id: 'End'});
var currentYear = (new Date()).getFullYear();
dataTable.addRows([
['Row 1', 'A-1', new Date(currentYear, 0, 1), new Date(currentYear, 2, 31)],
['Row 1', 'A-2', new Date(currentYear, 3, 1), new Date(currentYear, 5, 30)],
['Row 2', 'B-1', new Date(currentYear, 6, 1), new Date(currentYear, 8, 31)],
['Row 2', 'B-2', new Date(currentYear, 9, 1), new Date(currentYear, 11, 31)]
]);
var dataTableGroup = google.visualization.data.group(dataTable, [0]);
var dateRangeStart = new Date(currentYear - 1, 0, 1);
var dateRangeEnd = new Date(currentYear + 1, 11, 31);
var rowHeight = 44;
var options = {
height: (dataTableGroup.getNumberOfRows() * rowHeight) + rowHeight,
hAxis: {
minValue: dateRangeStart,
maxValue: dateRangeEnd,
}
};
function drawChart() {
chart.draw(dataTable, options);
}
// add custom marker
function addMarkers(events) {
var baseline;
var baselineBounds;
var chartElements;
var labelFound;
var labelText;
var marker;
var markerLabel;
var markerSpan;
var rowLabel;
var svg;
var svgNS;
var timeline;
var timelineUnit;
var timelineWidth;
var timespan;
var xCoord;
var yCoord;
// initialize chart elements
baseline = null;
svg = null;
svgNS = null;
timeline = null;
chartElements = container.getElementsByTagName('svg');
if (chartElements.length > 0) {
svg = chartElements[0];
svgNS = svg.namespaceURI;
}
chartElements = container.getElementsByTagName('rect');
if (chartElements.length > 0) {
timeline = chartElements[0];
}
chartElements = container.getElementsByTagName('path');
if (chartElements.length > 0) {
baseline = chartElements[0];
}
if ((svg === null) || (timeline === null) || (baseline === null)) {
return;
}
timelineWidth = parseFloat(timeline.getAttribute('width'));
baselineBounds = baseline.getBBox();
timespan = dateRangeEnd.getTime() - dateRangeStart.getTime();
timelineUnit = (timelineWidth - baselineBounds.x) / timespan;
// add events
events.forEach(function (event) {
// find row label
rowLabel = dataTable.getValue(event.row, 0);
chartElements = container.getElementsByTagName('text');
if (chartElements.length > 0) {
Array.prototype.forEach.call(chartElements, function(label) {
if (label.textContent.indexOf('…') > -1) {
labelText = label.textContent.replace('…', '');
} else {
labelText = label.textContent;
}
if (rowLabel.indexOf(labelText) > -1) {
markerLabel = label.cloneNode(true);
}
});
}
// calculate placement
markerSpan = event.date.getTime() - dateRangeStart.getTime();
// add label
markerLabel.setAttribute('text-anchor', 'start');
markerLabel.setAttribute('fill', event.color);
markerLabel.setAttribute('x', (baselineBounds.x + (timelineUnit * markerSpan) + 6));
markerLabel.textContent = event.name;
svg.appendChild(markerLabel);
// add marker
xCoord = (baselineBounds.x + (timelineUnit * markerSpan) - 4);
yCoord = parseFloat(markerLabel.getAttribute('y'));
switch (event.type) {
case 'triangle':
marker = document.createElementNS(svgNS, 'polygon');
marker.setAttribute('fill', 'transparent');
marker.setAttribute('stroke', event.color);
marker.setAttribute('stroke-width', '3');
marker.setAttribute('points', xCoord + ',' + (yCoord - 10) + ' ' + (xCoord - 5) + ',' + yCoord + ' ' + (xCoord + 5) + ',' + yCoord);
svg.appendChild(marker);
break;
case 'circle':
marker = document.createElementNS(svgNS, 'circle');
marker.setAttribute('cx', xCoord);
marker.setAttribute('cy', yCoord - 5);
marker.setAttribute('r', '6');
marker.setAttribute('stroke', event.color);
marker.setAttribute('stroke-width', '3');
marker.setAttribute('fill', 'transparent');
svg.appendChild(marker);
break;
}
});
}
google.visualization.events.addListener(chart, 'ready', function () {
addMarkers([
{row: 0, date: new Date(currentYear - 1, 1, 11), name: 'Event 1', type: 'triangle', color: 'red'},
{row: 1, date: new Date(currentYear + 1, 5, 23), name: 'Event 2', type: 'circle', color: 'purple'},
{row: 3, date: new Date(currentYear + 1, 8, 2), name: 'Event 3', type: 'triangle', color: 'magenta'}
]);
});
window.addEventListener('resize', drawChart, false);
drawChart();
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="timeline"></div>

How to add 2 OpenLayer Marker Animations to page? Clickevent seems to be overwritten

I have an OpenLayer Marker Animation implemented in my (python) flask application.
However in my dataset that I am using for the Marker Animation I have an extra route that I would like to show an animation of as well.
When I add code to take care of the second animation it is like the controls for the first animation is overwritten and I have no idea of how to avoid this from happening. I've tried renaming all the vars to 1 and 2 to avoiding them from overwriting each other, but for some reason it seems like it still overwrites the controls.
I have created this fiddle to illustrate the problem. If you click the start animation under Map 1 it will run the animation on Map 2. I have just used the procedure below in my fiddle, but originally I had the code in a for-loop that was run twice to extract both routes and then draw the maps.
Route points for Map 1
Set up Map 1
Bind functions to Map 1 buttons
Route points for Map 2
Set up Map 2
Bind functions to Map 2 buttons
I guess my problem is about isolating code and/or bindings. First I tried renaming the functions (moveFeature, startAnimation, stopAnimation) to their respective names with either a "1" or "2" added. That did not do the trick, nor did renaming all the variables similarly.
You are creating a lot of variables with the same name. For example, when you overwrite the function StartAnimation, the buttons enter in the second one (Since both are pointing to a function called "StartAnimation").
To avoid this, you have to create different variables for each map. This way you would avoid unuseful code and can be sure that each element is using the variables they are supposed to use.
I've built an example based on your jsfiddle code:
var locations1 = [[53.44241609, 6.84913974], [53.44241894, 6.84913726], [53.44242156, 6.84913385], [53.44242473, 6.84913076], [53.44242859, 6.84912721], [53.44243324, 6.84912446], [53.44243724, 6.84912303], [53.44243994, 6.84912206], [53.44244199, 6.84911994], [53.44244474, 6.84911928], [53.44244757, 6.8491193], [53.44245181, 6.84911968], [53.44245596, 6.84912085], [53.44246139, 6.84912072], [53.4424669, 6.84912142], [53.44247222, 6.84912279], [53.4424778, 6.84912454], [53.44248644, 6.84912644], [53.44249062, 6.84912761], [53.44249409, 6.84913057], [53.44249746, 6.84913362], [53.44250197, 6.84913592], [53.44250901, 6.84913629], [53.44251198, 6.84913792], [53.44251293, 6.84913988], [53.44251458, 6.84914126], [53.44251596, 6.8491434], [53.44251778, 6.84914727], [53.44251988, 6.8491501], [53.44252248, 6.8491531], [53.44252517, 6.84915473], [53.44252316, 6.84915181], [53.44252377, 6.84915124], [53.4425233, 6.84914949], [53.44252341, 6.84914848], [53.44252276, 6.84914827], [53.44252397, 6.84914868], [53.4425216, 6.84914477], [53.44252001, 6.84914287], [53.44252107, 6.84914273], [53.44251986, 6.84913869], [53.44251841, 6.84913463], [53.44251482, 6.84912822], [53.44251525, 6.84912649], [53.4425148, 6.84912465], [53.44251483, 6.84912049], [53.44251625, 6.84911749], [53.44251677, 6.84911403], [53.4425187, 6.84910978], [53.44252028, 6.84910694], [53.44252218, 6.84910622], [53.44252457, 6.84910649], [53.44252783, 6.84910729], [53.44253168, 6.84910888], [53.44253668, 6.84910943], [53.44254088, 6.84910976], [53.44254363, 6.84910898], [53.44254612, 6.84910996], [53.44254803, 6.84910946], [53.44255004, 6.84910945], [53.44255416, 6.84910766], [53.44256019, 6.84910343], [53.44256469, 6.84909908], [53.44256753, 6.84909764], [53.44257106, 6.84909639], [53.44257482, 6.84909654], [53.44257861, 6.84909769]];
var locations2 = [[53.44241609, 6.84913974], [53.44241894, 6.84913726], [53.44242156, 6.84913385], [53.44242473, 6.84913076], [53.44242859, 6.84912721], [53.44243324, 6.84912446], [53.44243724, 6.84912303], [53.44243994, 6.84912206], [53.44244199, 6.84911994], [53.44244474, 6.84911928], [53.44244757, 6.8491193], [53.44245181, 6.84911968], [53.44245596, 6.84912085], [53.44246139, 6.84912072], [53.4424669, 6.84912142], [53.44247222, 6.84912279], [53.4424778, 6.84912454], [53.44248644, 6.84912644], [53.44249062, 6.84912761], [53.44249409, 6.84913057], [53.44249746, 6.84913362], [53.44250197, 6.84913592], [53.44250901, 6.84913629], [53.44251198, 6.84913792], [53.44251293, 6.84913988], [53.44251458, 6.84914126], [53.44251596, 6.8491434], [53.44251778, 6.84914727], [53.44251988, 6.8491501], [53.44252248, 6.8491531], [53.44252517, 6.84915473], [53.44252316, 6.84915181], [53.44252377, 6.84915124], [53.4425233, 6.84914949], [53.44252341, 6.84914848], [53.44252276, 6.84914827], [53.44252397, 6.84914868], [53.4425216, 6.84914477], [53.44252001, 6.84914287], [53.44252107, 6.84914273], [53.44251986, 6.84913869], [53.44251841, 6.84913463], [53.44251482, 6.84912822], [53.44251525, 6.84912649], [53.4425148, 6.84912465], [53.44251483, 6.84912049], [53.44251625, 6.84911749], [53.44251677, 6.84911403], [53.4425187, 6.84910978], [53.44252028, 6.84910694], [53.44252218, 6.84910622], [53.44252457, 6.84910649], [53.44252783, 6.84910729], [53.44253168, 6.84910888], [53.44253668, 6.84910943], [53.44254088, 6.84910976], [53.44254363, 6.84910898], [53.44254612, 6.84910996], [53.44254803, 6.84910946], [53.44255004, 6.84910945], [53.44255416, 6.84910766], [53.44256019, 6.84910343], [53.44256469, 6.84909908], [53.44256753, 6.84909764], [53.44257106, 6.84909639], [53.44257482, 6.84909654], [53.44257861, 6.84909769]];
locations1.map(function(l) {
return l.reverse();
});
locations2.map(function(l) {
return l.reverse();
});
// ---------------------------
//Defining Map 1 and Events
// ---------------------------
var route1 = new ol.geom.LineString(locations1)
.transform('EPSG:4326', 'EPSG:3857');
var routeCoords1 = route1.getCoordinates();
var routeLength1 = routeCoords1.length;
var routeFeature1 = new ol.Feature({
type: 'route',
geometry: route1
});
var geoMarker1 = new ol.Feature({
type: 'geoMarker',
geometry: new ol.geom.Point(routeCoords1[0])
});
var startMarker1 = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(routeCoords1[0])
});
var endMarker1 = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(routeCoords1[routeLength1 - 1])
});
var styles1 = {
'route': new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6,
color: [237, 212, 0, 0.8]
})
}),
'icon': new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'https://openlayers.org/en/v3.20.1/examples/data/icon.png'
})
}),
'geoMarker': new ol.style.Style({
image: new ol.style.Circle({
radius: 7,
snapToPixel: false,
fill: new ol.style.Fill({
color: 'black'
}),
stroke: new ol.style.Stroke({
color: 'white',
width: 2
})
})
})
};
var animating1 = false;
var speed1, now1;
var speedInput1 = document.getElementById('speed1');
var startButton1 = document.getElementById('start-animation1');
var vectorLayer1 = new ol.layer.Vector({
source: new ol.source.Vector({
features: [routeFeature1, geoMarker1, startMarker1, endMarker1]
}),
style: function(feature) {
// hide geoMarker if animation is active
if (animating1 && feature.get('type') === 'geoMarker') {
return null;
}
return styles1[feature.get('type')];
}
});
var map1 = new ol.Map({
target: document.getElementById('map1'),
loadTilesWhileAnimating: true,
view: new ol.View(),
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayer1
]
});
map1.getView().fit(
vectorLayer1.getSource().getExtent(), map1.getSize(),
{padding: [30, 5, 5, 5]});
var center1 = map1.getView().getCenter();
var moveFeature1 = function(event) {
var vectorContext = event.vectorContext;
var frameState = event.frameState;
if (animating1) {
var elapsedTime = frameState.time - now1;
// here the trick to increase speed is to jump some indexes
// on lineString coordinates
var index = Math.round(speed1 * elapsedTime / 1000);
if (index >= routeLength1) {
stopAnimation1(true);
return;
}
var currentPoint = new ol.geom.Point(routeCoords1[index]);
var feature = new ol.Feature(currentPoint);
vectorContext.drawFeature(feature, styles1.geoMarker);
}
// tell OL3 to continue the postcompose animation
map1.render();
};
function startAnimation1() {
if (animating1) {
stopAnimation1(false);
} else {
animating1 = true;
now1 = new Date().getTime();
speed1 = speedInput1.value;
startButton1.textContent = 'Cancel Animation';
// hide geoMarker
geoMarker1.setStyle(null);
// just in case you pan somewhere else
map1.getView().setCenter(center1);
map1.on('postcompose', moveFeature1);
map1.render();
}
}
function stopAnimation1(ended) {
animating1 = false;
startButton1.textContent = 'Start Animation';
// if animation cancelled set the marker at the beginning
var coord = ended ? routeCoords1[routeLength1 - 1] : routeCoords1[0];
/** #type {ol.geom.Point} */
(geoMarker1.getGeometry())
.setCoordinates(coord);
//remove listener
map1.un('postcompose', moveFeature1);
}
startButton1.addEventListener('click', startAnimation1, false);
// ---------------------------
//Defining Map 2 and Events
// ---------------------------
var route2 = new ol.geom.LineString(locations2)
.transform('EPSG:4326', 'EPSG:3857');
var routeCoords2 = route2.getCoordinates();
var routeLength2 = routeCoords2.length;
var routeFeature2 = new ol.Feature({
type: 'route',
geometry: route2
});
var geoMarker2 = new ol.Feature({
type: 'geoMarker',
geometry: new ol.geom.Point(routeCoords2[0])
});
var startMarker2 = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(routeCoords2[0])
});
var endMarker2 = new ol.Feature({
type: 'icon',
geometry: new ol.geom.Point(routeCoords2[routeLength2 - 1])
});
var styles2 = {
'route': new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6,
color: [237, 212, 0, 0.8]
})
}),
'icon': new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: 'https://openlayers.org/en/v3.20.1/examples/data/icon.png'
})
}),
'geoMarker': new ol.style.Style({
image: new ol.style.Circle({
radius: 7,
snapToPixel: false,
fill: new ol.style.Fill({
color: 'black'
}),
stroke: new ol.style.Stroke({
color: 'white',
width: 2
})
})
})
};
var animating2 = false;
var speed2, now2;
var speedInput2 = document.getElementById('speed2');
var startButton2 = document.getElementById('start-animation2');
var vectorLayer2 = new ol.layer.Vector({
source: new ol.source.Vector({
features: [routeFeature2, geoMarker2, startMarker2, endMarker2]
}),
style: function(feature) {
// hide geoMarker if animation is active
if (animating2 && feature.get('type') === 'geoMarker') {
return null;
}
return styles2[feature.get('type')];
}
});
var map2 = new ol.Map({
target: document.getElementById('map2'),
loadTilesWhileAnimating: true,
view: new ol.View(),
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayer2
]
});
map2.getView().fit(
vectorLayer2.getSource().getExtent(), map2.getSize(),
{padding: [30, 5, 5, 5]});
var center2 = map2.getView().getCenter();
var moveFeature2 = function(event) {
var vectorContext = event.vectorContext;
var frameState = event.frameState;
if (animating2) {
var elapsedTime = frameState.time - now2;
// here the trick to increase speed is to jump some indexes
// on lineString coordinates
var index = Math.round(speed2 * elapsedTime / 1000);
if (index >= routeLength2) {
stopAnimation2(true);
return;
}
var currentPoint = new ol.geom.Point(routeCoords2[index]);
var feature = new ol.Feature(currentPoint);
vectorContext.drawFeature(feature, styles2.geoMarker);
}
// tell OL3 to continue the postcompose animation
map2.render();
};
function startAnimation2() {
if (animating2) {
stopAnimation2(false);
} else {
animating2 = true;
now2 = new Date().getTime();
speed2 = speedInput2.value;
startButton2.textContent = 'Cancel Animation';
// hide geoMarker
geoMarker2.setStyle(null);
// just in case you pan somewhere else
map2.getView().setCenter(center2);
map2.on('postcompose', moveFeature2);
map2.render();
}
}
function stopAnimation2(ended) {
animating2 = false;
startButton2.textContent = 'Start Animation';
// if animation cancelled set the marker at the beginning
var coord = ended ? routeCoords2[routeLength2 - 1] : routeCoords2[0];
/** #type {ol.geom.Point} */
(geoMarker2.getGeometry())
.setCoordinates(coord);
//remove listener
map2.un('postcompose', moveFeature2);
}
startButton2.addEventListener('click', startAnimation2, false);
<script src="https://openlayers.org/en/v3.20.1/build/ol.js"></script>
<link href="https://openlayers.org/en/v3.20.1/css/ol.css" rel="stylesheet"/>
<h1>
Map 1
</h1>
<div id="map1" class="map"></div>
<label for="speed1">
speed:
<input id="speed1" type="range" min="10" max="999" step="10" value="60">
</label>
<button id="start-animation1">Start Animation</button>
<h1>
Map 2
</h1>
<div id="map2" class="map"></div>
<label for="speed2">
speed:
<input id="speed2" type="range" min="10" max="999" step="10" value="60">
</label>
<button id="start-animation2">Start Animation</button>

Goole Visualization DateRangeFilter Data issue. Data Conflict between Feb and March

When I'm selecting the dates between 1st feb to 28th feb, the Google visualization displaying the data of March instead of February.
Screenshot
The Below code has data and control and chart wrappers.
google.load('visualization', '1', {packages:['corechart','controls','table'], callback:drawChart});
Js Fiddle Link
Please help me in finding a solution for this.
Thanks in advance.
try using the newer library, loader.js vs jsapi
seems to work fine here...
google.charts.load('current', {
callback: function () {
var data = new google.visualization.DataTable();
data.addColumn('date','OrderDate');
data.addColumn('number','Order_Qty');
data.addRows([
[new Date(2014,0,1),100],
[new Date(2014,0,3),120],
[new Date(2014,0,30),110],
[new Date(2014,1,1),170],
[new Date(2014,1,10),180],
[new Date(2014,1,25),110],
[new Date(2014,2,1),170],
[new Date(2014,2,14),170],
[new Date(2014,2,20),170],
[new Date(2014,3,12),170],
[new Date(2014,3,16),170],
[new Date(2014,3,13),170]
]);
var table_Chart = new google.visualization.ChartWrapper({
'chartType': 'Table',
'containerId': 'table_div',
'options': {},
'view': {'columns':[0, 1]}
});
var slider_Date = new google.visualization.ControlWrapper({
'controlType': 'DateRangeFilter',
'containerId': 'filter_date_div_Date',
'options': {
'filterColumnIndex':'0'
}
});
new google.visualization.Dashboard(document.getElementById('dashboard_div'))
.bind([slider_Date],[table_Chart])
.draw(data);
},
packages: ['controls', 'table']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard_div">
<div id="filter_date_div_Date"></div>
<div id="table_div"></div>
</div>
This was a bug in the Google charts Date() handling. It is fixed now by its developer.
Github: google/google-visualization-issues Chart data series shows up mis-aligned for all February data
Short term solution for the .clone() and .toDataTable() issue with the live version of the Visualization.
Clone Usage:
prev: newDatatable = oldDatatable.clone();
now: newDatatable = cloneDataTable(oldDatatable);
ToDatatableUsage:
prev: newDatatable = oldDataView.toDatatable();
now: newDatatable = convertDataViewToDataTable(oldDataView);
Functions:
function cloneDataTable(dataTable) {
var newDataTable = dataTable.clone();
for (var c = 0; c < dataTable.getNumberOfColumns(); c++) {
if (dataTable.getColumnType(c) == 'datetime' || dataTable.getColumnType(c) == 'date' ) {
for (var r = 0; r < dataTable.getNumberOfRows() ; r++) {
newDataTable.setValue(r, c, dataTable.getValue(r, c));
}
}
}
return newDataTable;
}
function convertDataViewToDataTable(dataView) {
var newDataTable = dataView.toDataTable();
for (var c = 0; c < dataView.getNumberOfColumns(); c++) {
if (dataView.getColumnType(c) == 'datetime' || dataView.getColumnType(c) == 'date' ) {
for (var r = 0; r < dataView.getNumberOfRows(); r++) {
newDataTable.setValue(r, c, dataView.getValue(r, c));
}
}
}
return newDataTable;
}
Hope this helps...
J

Empty GetSelection() Object in Google Charts' Gantt Chart

I've been learning to use Google Charts for a while and so far, I'm having no problem. However, recently I tried using Gantt Charts and a problem came up. I managed to draw a chart correctly with a data fed by SQL server. However, I want to alert the ID of the selected entity if a chart entity is clicked.
I understand that Google Charts have this getSelection() function and Event Handler. However, when I'm trying to implement that, the array returns empty (just [{}] written in the console). I even used Google Charts' example but it still returns empty array.
Here's the code I use:
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script>
google.charts.load('current', {'packages':['gantt']});
google.charts.setOnLoadCallback(drawChart);
function daysToMilliseconds(days) {
return days * 24 * 60 * 60 * 1000;
}
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Task ID');
data.addColumn('string', 'Task Name');
data.addColumn('date', 'Start Date');
data.addColumn('date', 'End Date');
data.addColumn('number', 'Duration');
data.addColumn('number', 'Percent Complete');
data.addColumn('string', 'Dependencies');
data.addRows([
['Research', 'Find sources',
new Date(2015, 0, 1), new Date(2015, 0, 5), null, 100, null],
['Write', 'Write paper',
null, new Date(2015, 0, 9), daysToMilliseconds(3), 25, 'Research,Outline'],
['Cite', 'Create bibliography',
null, new Date(2015, 0, 7), daysToMilliseconds(1), 20, 'Research'],
['Complete', 'Hand in paper',
null, new Date(2015, 0, 10), daysToMilliseconds(1), 0, 'Cite,Write'],
['Outline', 'Outline paper',
null, new Date(2015, 0, 6), daysToMilliseconds(1), 100, 'Research']
]);
var options = {
height: 275
};
var chart = new google.visualization.Gantt(document.getElementById('chart_div'));
// When the table is selected, update the orgchart.
google.visualization.events.addListener(chart, 'select', function()
{
var obj = chart.getSelection();
alert(obj[0].column);
});
chart.draw(data, options);
}
</script>
<div id="chart_div"></div>
Here's the jsfiddle: https://jsfiddle.net/2ku7tzex/1/#&togetherjs=cjVlbdFhV3
Does anybody know where I did wrong?
Thanks before!
This https://jsfiddle.net/hrtgp54r/ resolved the issue for me.
google.visualization.events.addListener(chart, 'select', selectHandler);
function selectHandler(){
var selections = chart.getSelection();
if (selections.length == 0)
{
alert('Nothing selected');
}
else
{
var selection = selections[0];
console.info(selection);
alert('You selected ' + (selection.row == null ? 'something' : data.getValue(selection.row, 0)));
}
};

Visualize table on tooltip with amCharts

I'm novice on JavaScript, but really amazed by amCharts.
So, I ask here, after search a lot on internet: is it possible (or someone can tell me how) make a table as a tooltip on a amCharts graph?
I mean: I have a trend graph, based on "date", if I click on a date of a day, view a popup with a table of the details of the day's data.
Searching and try a lot of code, and I reach a possible solution.
So, considering that there aren't similar questions here or developed like I ask, I post my solution to share it.
You can try clicking "RUN": When you clicking on a point of graph, an HTML Table was displayed filled by data (fake value in this example).
THIS IS THE SNIPPET:
function createTable(){
var table = "<table>";
table += "<thead>";
table += "<tr>";
table +="<th> Dealer </th>";
table +="<th> Percent </th>";
table +="<th> Proportional </th>";
table +="</tr>";
table +="</thead>";
table +="<tbody>";
for(var i=0;i<200;i++){
table += "<tr>";
table +="<td> New York </td>";
table +="<td> "+Math.random();+" </td>";
table +="<td> "+Math.random();+" </td>";
table +="</tr>";
};
table += "</tbody>";
table += "</table>";
return table;
};
var chartData = [{
date: new Date(2012, 0, 1),
distance: 227,
duration: 408},
{
date: new Date(2012, 0, 2),
distance: 371,
duration: 482},
{
date: new Date(2012, 0, 3),
distance: 433,
duration: 562},
{
date: new Date(2012, 0, 4),
distance: 345,
duration: 379},
{
date: new Date(2012, 0, 5),
distance: 480,
duration: 501},
{
date: new Date(2012, 0, 6),
distance: 386,
duration: 443},
{
date: new Date(2012, 0, 7),
distance: 348,
duration: 405},
{
date: new Date(2012, 0, 8),
distance: 238,
duration: 309},
{
date: new Date(2012, 0, 9),
distance: 218,
duration: 287},
{
date: new Date(2012, 0, 10),
distance: 349,
duration: 485},
{
date: new Date(2012, 0, 11),
distance: 603,
duration: 890},
{
date: new Date(2012, 0, 12),
distance: 534,
duration: 810}];
var chart;
AmCharts.ready(function() {
// SERIAL CHART
chart = new AmCharts.AmSerialChart();
chart.dataProvider = chartData;
chart.categoryField = "date";
chart.marginTop = 0;
chart.autoMarginOffset = 5;
chart.balloon.showBullet = false;
// AXES
// category axis
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.autoGridCount = false;
categoryAxis.gridCount = 50;
categoryAxis.gridAlpha = 0;
categoryAxis.gridColor = "#000000";
categoryAxis.axisColor = "#555555";
// we want custom date formatting, so we change it in next line
categoryAxis.dateFormats = [{
period: 'DD',
format: 'DD'},
{
period: 'WW',
format: 'MMM DD'},
{
period: 'MM',
format: 'MMM'},
{
period: 'YYYY',
format: 'YYYY'}];
// as we have data of different units, we create two different value axes
// Duration value axis
var durationAxis = new AmCharts.ValueAxis();
durationAxis.title = "duration";
durationAxis.gridAlpha = 0.05;
durationAxis.axisAlpha = 0;
durationAxis.inside = true;
// the following line makes this value axis to convert values to duration
// it tells the axis what duration unit it should use. mm - minute, hh - hour...
durationAxis.duration = "mm";
durationAxis.durationUnits = {
DD: "d. ",
hh: "h ",
mm: "min",
ss: ""
};
chart.addValueAxis(durationAxis);
// Distance value axis
var distanceAxis = new AmCharts.ValueAxis();
distanceAxis.title = "distance";
distanceAxis.gridAlpha = 0;
distanceAxis.position = "right";
distanceAxis.inside = true;
distanceAxis.unit = "mi";
distanceAxis.axisAlpha = 0;
chart.addValueAxis(distanceAxis);
// GRAPHS
// duration graph
var durationGraph = new AmCharts.AmGraph();
durationGraph.title = "duration";
durationGraph.valueField = "duration";
durationGraph.type = "line";
durationGraph.valueAxis = durationAxis; // indicate which axis should be used
durationGraph.lineColor = "#CC0000";
durationGraph.balloonText = "[[value]]";
durationGraph.lineThickness = 1;
durationGraph.legendValueText = "[[value]]";
durationGraph.bullet = "square";
chart.addGraph(durationGraph);
// CURSOR
var chartCursor = new AmCharts.ChartCursor();
chartCursor.zoomable = false;
chartCursor.categoryBalloonDateFormat = "DD";
chartCursor.cursorAlpha = 0;
chart.addChartCursor(chartCursor);
// LEGEND
var legend = new AmCharts.AmLegend();
legend.bulletType = "round";
legend.equalWidths = false;
legend.valueWidth = 120;
legend.color = "#000000";
chart.addLegend(legend);
// SET UP CLICK EVENTS
// create prerequisite properties
AmCharts.clickTimeout = 0; // this will hold setTimeout reference
AmCharts.lastClick = 0; // last click timestamp
AmCharts.doubleClickDuration = 300; // distance between clicks in ms - if it's less than that - it's a doubleckick
// let's define functions to actually do something on clicks/doubleclicks
// you will want to replace the insides of these with your own code
AmCharts.doSingleClick = function (event) {
//var div = document.getElementById("databody");
var table=createTable();
document.getElementById("databody").innerHTML=table;
//div.innerHTML = "Ciao<br />" + div.innerHTML;
}
/*AmCharts.doDoubleClick = function (event) {
var div = document.getElementById("events");
div.innerHTML = "Double Click<br />" + div.innerHTML;
}*/
// create click handler
AmCharts.myClickHandler = function (event) {
var ts = (new Date()).getTime();
if ((ts - AmCharts.lastClick) < AmCharts.doubleClickDuration) {
// it's double click!
// let's clear the timeout so the "click" event does not fire
if (AmCharts.clickTimeout) {
clearTimeout(AmCharts.clickTimeout);
}
// reset last click
AmCharts.lastClick = 0;
// now let's do whatever we want to do on double-click
AmCharts.doDoubleClick(event);
}
else {
// single click!
// let's delay it to see if a second click will come through
AmCharts.clickTimeout = setTimeout(function () {
// let's do whatever we want to do on single click
AmCharts.doSingleClick(event);
}, AmCharts.doubleClickDuration);
}
AmCharts.lastClick = ts;
}
// add handler to the chart
chart.addListener("clickGraphItem", AmCharts.myClickHandler);
// WRITE
chart.write("chartdiv");
});
body {
font-family: Verdana;
font-size: 12px;
padding: 10px;
}
#databody, #databody th, #databody td {
border: 1px solid #ccc;
padding: 10px;
}
#databody th {
font-weight: bold;
background-color: #eee;
}
div.box{
width:360px !important; width /**/:200px;
height:190px !important; height /**/: 200px;
padding: 4px;
border:1px solid #EEE; border-right:0 solid;
background:url(gradient.png) repeat-x fixed top left;
overflow:auto
}
}
<script src="http://www.amcharts.com/lib/amcharts.js" type="text/javascript"></script>
<div id="chartdiv" style="height: 362px;"></div>
<div class="box" id="databody">
</div>

Categories

Resources