How to use time-stamped data in chartist.js? - chartist.js

I have a data-set where the x-values are time-stamps.
The time-stamps are irregular - so one would be 2016-12-13T00:01:02Z and an other 2016-12-13T02:13:05Z.
I would like to draw this data into a line-chart where a whole day is displayed, meaning the X-axis would show 00 01 02 ... 22 23 24.
How would I do that in chartist.js?

I figured it out myself.
I use two data-sets. One that contains my data. The other one (baseData) will contain two time-stamps: begining of day and end of day. This will force the chart to draw the X-axis with 00 01 02 ... 21 22.
I do not want to show the "baseData" in the chart - so I hide it via css:
.ct-series-a .ct-line {
/* Set the color for seriesDataTemperatures */
stroke: green;
/* Control the thickness of seriesDataTemperatures */
stroke-width: 1px;
}
.ct-series-b .ct-line {
/* Set the color for baseData */
stroke: grey;
/* Control the thickness of baseData */
stroke-width: 0px;
}
Then I draw my chart like this:
// My time-stamped series go here
var seriesDataTemperatures = [];
// This data-set will have two values, begin of day and end of day.
// E.g. [{ x: new Date("2016-12-16T00:01:00.000Z").valueOf(), y: 0 }, { x: new Date("2016-12-16T23:59:00.000Z").valueOf(), y: 0}]
var baseData = [];
chartTemperatures = new Chartist.Line('.ct-chart-temperatures', {
series: [
{
name: 'temperatures',
data: seriesDataTemperatures
},
{
name: 'base',
data: baseData
}
]
}, {
showPoint: false,
lineSmooth: false,
axisX: {
type: Chartist.FixedScaleAxis,
divisor: 23,
labelInterpolationFnc: function (value) {
return moment(value).format('HH');
}
}
});

Related

How do I force line break in donut chart label?

I'm using C3 donut chart,
But the label is too long and I need a word-break like feature.
So I tried to set the following properties, non of them works
axis: {
x: {
tick: {
width: 100
}
}
},
legend: {
maxWidth: 100px;
},
Any ideas?
UPDATE
The tooltip.format.name function can partially solve this problem. But I'm unable to add newline here, tried "\n", <br/> and
tooltip: {
format: {
name: function (name, ratio, id, index) {
if (name.length > 70) {
return name.substr(0, 70) + ' 
 ...'
} else {
return name
}
}
}
}

Cesium Get color of picked entity to compare

Is there any way to get color of picked entity on Cesium?
Basically, I need to check the color of clicked entity, if its blue, change it to red and vice-versa.
Is there any way to achieve this? Thanks in advance.
Yes, with some caveats: First, the Cesium entity itself doesn't have a color. It can have a point, and the point can have a color and an outlineColor, it may also have a label with its own color(s), etc.
Next, Cesium properties are all capable of being time-dynamic or constant. So when you "get" an entity property such as a point color, you should normally pass in viewer.clock.currentTime to get the property at a particular time. This doesn't matter if you know for certain that the property you're getting is a ConstantProperty and not a SampledProperty or a TimeIntervalCollectionProperty.
For the demo below, I'm using ConstantProperty implicitly for all colors and properties. I've also suppressed the "SelectionIndicator" (the green box that normally appears when you click on an entity), because it looks odd for this case.
I'm using the selectedEntityChanged event to indicate when a point should change from blue to red or back. The selectedEntityChanged event is new in Cesium 1.31 released this month (March 2017). If you have an older version and can't upgrade, there is a workaround for old versions that I can post if needed.
var viewer = new Cesium.Viewer('cesiumContainer', {
// Turn off nav help and stuff we're not using.
navigationInstructionsInitiallyVisible: false, animation: false, timeline: false,
// Optionally, you can turn off the green selection box, like this:
selectionIndicator : false,
// These next 6 lines are just to avoid Stack Snippet error messages.
imageryProvider : Cesium.createTileMapServiceImageryProvider({
url : Cesium.buildModuleUrl('Assets/Textures/NaturalEarthII')
}),
baseLayerPicker : false,
geocoder : false,
infoBox : false
});
var dots = [
{ lon: -75, lat: 40 },
{ lon: -95, lat: 40 },
{ lon: -115, lat: 40 },
{ lon: -75, lat: 30 },
{ lon: -95, lat: 30 },
{ lon: -115, lat: 30 },
{ lon: -85, lat: 20 },
{ lon: -105, lat: 20 }
];
dots.forEach(function(dot) {
viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(dot.lon, dot.lat),
point : {
pixelSize : 7,
color : Cesium.Color.STEELBLUE,
outlineColor : Cesium.Color.BLACK,
outlineWidth : 1.0
}
});
});
viewer.selectedEntityChanged.addEventListener(function(entity) {
// Check if an entity with a point color was selected.
if (Cesium.defined(entity) &&
Cesium.defined(entity.point) &&
Cesium.defined(entity.point.color)) {
// Get the current color
var color = entity.point.color.getValue(viewer.clock.currentTime);
// Test for blue
if (Cesium.Color.equals(color, Cesium.Color.STEELBLUE)) {
// Set to red
entity.point.color = Cesium.Color.RED;
}
// Test for red
else if (Cesium.Color.equals(color, Cesium.Color.RED)) {
// Set to red
entity.point.color = Cesium.Color.STEELBLUE;
}
}
});
html, body, #cesiumContainer {
width: 100%; height: 100%; margin: 0; padding: 0; overflow: hidden;
font-family: sans-serif;
}
#message {
position: absolute;
top: 4px; left: 5px; color: #edffff;
}
<link href="http://cesiumjs.org/releases/1.31/Build/Cesium/Widgets/widgets.css"
rel="stylesheet"/>
<script src="http://cesiumjs.org/releases/1.31/Build/Cesium/Cesium.js">
</script>
<div id="cesiumContainer"></div>
<div id="message">Single-click a dot to change its color.</div>

Specify the color for a Pie in Dojo Charting

I am using Dojo 1.9, using memoryStore and the store has 4 data elements, in addition to the key. For each of the 4 data elements, I need to plot a Pie-Chart. working fine but only issue is that I do not know how to specify the color.
The identifier could be one of the Following - Low, Moderate,High and Extreme.
I want to use the same colors for each identifier, in all the charts. Is it possible for me to specify a color based on the value of the identifier?
The code snippet is as shown below:
var store = new Observable(new Memory({
data: {
identifier: "accumulation",
items: theData
}
}));
theChart.setTheme(PrimaryColors)
.addPlot("default", {
type: Pie,
font: "normal normal 11pt Tahoma",
fontColor: "black",
labelOffset: -30,
radius: 80
}).addSeries("accumulation", new StoreSeries(store, { query: { } }, dataElement));
I'm possibly misunderstanding your question here (is the plot interacting directly with the store? StoreSeries?), but is the fill property what you're looking for?
// Assuming data is an array of rows retrieved from the store
for(var i etc...) {
// make chart
// ...
chart.addSeries("things", [
{ y: data[i]["low"], fill: "#55FF55", text: "Low" },
{ y: data[i]["mod"], fill: "#FFFF00", text: "Moderate" },
{ y: data[i]["high"], fill: "#FFAA00", text: "High" },
{ y: data[i]["extr"], fill: "#FF2200", text: "Extreme" }
]);
}
Update: When using a StoreSeries, the third argument (dataElement in your code) can also be a function. You can use the function to return an object (containing the properties above, such as fill) instead of just a value.
chart.addSeries("thingsFromStore", new StoreSeries(store, {}, function(i) {
return {
y : i[dataElement],
text: "Label for " + i.accumulation,
fill: getColorForAccumulation(i)
};
}));

FullCalendar and Flot Resize Conflict

I've successfully integrated both a Flot line graph and an instance of FullCalendar into my site. They are both on separate pages (although the pages are loaded into a div via AJAX).
I've added the Flot Resize plugin and that works perfectly, re-sizing the line graph as expected. However, it seems to cause an error when resizing the calendar.
Even if I load the calendar page first, when I resize the window I get this error in the console (also, the calendar does not resize correctly):
TypeError: 'undefined' is not an object (evaluating 'r.w=o!==c?o:q.width()')
I was struggling to work out where the error was coming from, so I removed the link to the Flot Resize JS and tried again. Of course the line graph does not resize, but when resizing the calendar, it works correctly.
The div containers for the two elements have different names and the resize function is called from within the function to draw the line graph (as required).
I have tried moving the link to the Flot Resize plugin into different places (i.e. above/below the fullCalendar JS, into the template which holds the graph), but all to no avail.
Does anyone have any idea where the conflict might be and how I might solve it??
Thanks very much!
EDIT: It seems that the error is also triggered when loading the line graph (flot) page AFTER the fullcalendar page even without resizing the window.... Now I am very confused!
EDIT 2: The code which draws the line graph. The function is called on pageload and recieves the data from JSON pulled off the server. When the graph is loaded, I still get the error about shutdown() being undefined.
function plotLineGraph(theData){
var myData = theData['data'];
var myEvents = theData['events'];
var myDates = theData['dates'];
var events = new Array();
for (var i=0; i<myEvents.length; i++) {
events.push(
{
min: myEvents[i][0],
max: myEvents[i][1],
eventType: "Calendar Entry",
title: myEvents[i][2],
description: myEvents[i][3]
}
);
}
function showTooltip(x, y, contents) {
$('<div id="tooltip">' + contents + '</div>').css( {
position: 'absolute',
display: 'none',
top: y + 5,
left: x + 5,
border: '1px solid #fdd',
padding: '2px',
'background-color': 'black',
opacity: 0.80
}).appendTo("body").fadeIn(200);
}
var previousPoint = null;
$("#placeholder").bind("plothover", function (event, pos, item) {
$("#x").text(pos.x.toFixed(2));
$("#y").text(pos.y.toFixed(2));
if ($("#enableTooltip:checked").length == 0) {
if (item) {
if (previousPoint != item.dataIndex) {
previousPoint = item.dataIndex;
$("#tooltip").remove();
var x = item.datapoint[0].toFixed(2),
y = item.datapoint[1].toFixed(2);
if(item.series.label != null){
showTooltip(item.pageX, item.pageY,
item.series.label + " of " + y);
}
}
}
else {
$("#tooltip").remove();
previousPoint = null;
}
}
});
var d1 = [
myData[0], myData[1], myData[2], myData[3], myData[4],
myData[5], myData[6], myData[7], myData[8], myData[9],
myData[10], myData[11], myData[12], myData[13], myData[14],
myData[15], myData[16], myData[17], myData[18], myData[19],
myData[20], myData[21], myData[22], myData[23], myData[24],
myData[25], myData[26], myData[27], myData[28], myData[29]
];
var markings = [
{ color: '#FFBDC1', yaxis: { from: 0, to: 2 } },
{ color: '#F2E2C7', yaxis: { from: 2, to: 3.5 } },
{ color: '#B6F2B7', yaxis: { from: 3.5, to: 5 } }
];
$.plot($("#placeholder"), [
{label: "Average Daily Rating", data: d1, color: "black"}
], {
events: {
data: events,
},
series: {
lines: { show: true },
points: { show: true }
},
legend: { show: true, container: '#legend-holder' },
xaxis: {
ticks:[
myDates[0], myDates[1], myDates[2], myDates[3], myDates[4],
myDates[5], myDates[6], myDates[7], myDates[8], myDates[9],
myDates[10], myDates[11], myDates[12], myDates[13], myDates[14],
myDates[15], myDates[16], myDates[17], myDates[18], myDates[19],
myDates[20], myDates[21], myDates[22], myDates[23], myDates[24],
myDates[25], myDates[26], myDates[27], myDates[28], myDates[29]
],
},
yaxis: {
ticks: 5,
min: 0,
max: 5
},
grid: {
backgroundColor: { colors: ["#fff", "#eee"] },
hoverable: true,
clickable: true,
markings: markings
},
selection: {
color: 'white',
mode: 'x'
},
});
$('#placeholder').resize();
$('#placeholder').shutdown();
}
EDIT 3:
The calendar is called like this:
function showCalendar() {
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
$('#fullcalendar').fullCalendar({
header: {
left: 'prev',
center: 'title',
right: 'next'
},
clickable: true,
firstDay: 1,
eventSources: [
{
url: '/populate-calendar/{{theProductUuid}}/',
color: 'black',
data: {
text: 'text'
}
}
],
eventClick: function(calEvent, jsEvent, view) {
var startDate = $.fullCalendar.formatDate(calEvent.start, 'yyyy-MM-dd');
var endDate = $.fullCalendar.formatDate(calEvent.end, 'yyyy-MM-dd');
var eventId = calEvent.uuid;
$('#modal-event-title').text(calEvent.title);
$('#edit-event-name').val(calEvent.title);
$('#edit-start-date').val(startDate);
$('#edit-end-date').val(endDate);
$('#edit-event-text').val(calEvent.text);
$('#edit-event-btn').attr('data-uuid', eventId);
$('#modal-edit-event').on('click', '#delete-btn', function(){
deleteCalendarEvent(eventId);
});
$('#modal-edit-event').modal();
},
});
}
The AJAX to load the page containing the flot chart:
function loadDetailedReports(uuid){
$('#product-content').fadeOut('slow', function(){
$('#product-content').empty();
$('#whole-product-sub-nav .active').removeClass('active');
$('#detailed-reports-content').load('/detailed-reports/' + uuid + '/', function(){
$('#detailed-reports-btn').addClass('active');
$('#detailed-reports-content').fadeIn('slow', function(){
if (authorized){
setLocationHash('loadDetailedReports&' + uuid);
getChartData(uuid);
} else {
setLocationHash('');
}
});
});
});
}
And the AJAX to load the page containing the calendar:
function loadCalendar(uuid){
$('#detailed-reports-content').empty().hide();
$('#product-content').fadeOut('slow', function(){
$('#whole-product-sub-nav .active').removeClass('active');
$('#product-content').load('/calendar/' + uuid + '/', function(){
$('#calendar-btn').addClass('active');
$('#product-content').fadeIn('slow', function(){
if (authorized){
setLocationHash('loadCalendar&' + uuid);
} else {
setLocationHash('');
}
showCalendar();
});
});
});
}
The calls to .resize and .shutdown are there because I was under the impression that they are necessary to achieve the resizing function and in response to your earlier comment regarding shutdown...... They're quite possibly n00b errors........?!?!
It looks like this is triggering on line 198 of jquery-resize:
data.w = w !== undefined ? w : elem.width();
This sounds like a race-condition stemming from the way you load different content into the same div. Flot binds the resize event to the chart div, and only un-binds it if the plot is destroyed cleanly.
EDIT: Looking at your code, my first suggestion would be to get rid of the resize and shutdown calls at the end of plotLineGraph. The resize plugin doesn't require any setup; it hooks into Flot to attach automatically to any new plot. So your call to resize is actually to jQuery's resize event trigger, which may be what's causing the error.
EDIT #2: I'm still not clear on your structure, but to generalize: anywhere that you might be getting rid of #placeholder (via emptying its parent or anything like that) you should first call shutdown on the plot object. If you aren't keeping a reference to it, you can do it like this: $("#placeholder").data("plot").shutdown(); but then have to account for the fact that it's undefined prior to the creation of your first plot.
If that still doesn't work, I'd need to see a live (simplified) example to make any further suggestions.

ExtJS How to add a click event to Pie Chart pieces

I have created a Pie chart using the Pie chart example in sencha ExtJS website , I wanted to add a click event to the each Pie slice so that i get handle to the contextual data on that slice. I was able to add a click listener to the Pie but not sure how to get the data on the slice.
Below is the ExtJS code.
Ext.onReady(function(){
var store = Ext.create('Ext.data.JsonStore', {
fields: ['name', 'data1', 'data2', 'data3', 'data4', 'data5'],
data: [{
'name': 'January',
'data1': 10
}, {
'name': 'February',
'data1': 7
}, {
'name': 'March',
'data1': 5
}, {
'name': 'April',
'data1': 2
}, {
'name': 'May',
'data1': 27
}]
});
Ext.create('Ext.chart.Chart', {
renderTo: Ext.getBody(),
width: 800,
height: 600,
animate: true,
store: store,
theme: 'Base:gradients',
legend: { // Pie Chart Legend Position
position: 'right'
},
series: [{
type: 'pie',
field: 'data1',
showInLegend: true,
tips: {
trackMouse: true,
width: 140,
height: 28,
renderer: function(storeItem, item){
//calculate and display percentage on hover
var total = 0;
store.each(function(rec){
total += rec.get('data1');
});
this.setTitle(storeItem.get('name') + ': ' + Math.round(storeItem.get('data1') / total * 100) + '%');
}
},
highlight: {
segment: {
margin: 5
}
},
label: {
field: 'name',
display: 'rotate',
contrast: true,
font: '18px Arial'
},
listeners: {//This Doesnt Work :(
itemclick: function(o){
alert('clicked at : ' + o);
}
}
}],
listeners: { //This Event handler works but I am not sure how to figure how which slice i have clicked ..................................
click: {
element: store, //bind to the underlying el property on the panel
fn: function(o, a){
alert('clicked' + o + a + this);
}
}
}
});
});
Kindly help.
Regards,
Lalit
Here is how you get data of the clicked slice. The series class supports listeners via the Observable syntax and they are:
itemmouseup When the user interacts with a marker.
itemmousedown When the user interacts with a marker.
itemmousemove When the user iteracts with a marker.
afterrender Will be triggered when the animation ends or when the series has been rendered completely.
I will make use of the itemmousedown event to capture the clicked slice. Here is my listener method:
series: [{
.
.
.
listeners:{
itemmousedown : function(obj) {
alert(obj.storeItem.data['name'] + ' &' + obj.storeItem.data['data1']);
}
}
.
}]
Note that I have placed my listener inside the series and not the chart! Now, the obj variable holds lot of information. For each series, the property to get data will differ. So, you will have to carefully inspect the object using firebug or some other developer tool.
Now, in case of Piecharts, you can get the slice information by using the obj:
obj.storeItem.data['your-series-variable-name']
Here is the obj from firebug..
I'm using a more selective approach, because I needed to add some custom logic in order to implement drag-and-drop for our charts. So after the chart definition I just add the following:
// Add drag-and-drop listeners to the sprites
var surface = chart.surface;
var items = surface.items.items;
for (var i = 0, ln = items.length; i < ln; i++) {
var sprite = items[i];
if (sprite.type != "circle") { continue; } // only add listeners to circles
// Additional funky checks for the draggable sprites
sprite.on("mousedown", onSpriteMouseDown, sprite); // mouse down ONLY for sprites
}
surface.on("mousemove", onSurfaceMouseMove, surface); // mouse move for the entire surface
surface.on("mouseup", onSurfaceMouseUp, surface);
Cheers!
Frank