I'm trying to export a dynamically generated chart and I've noticed that some things don't get exported. For example, my chart has PlotBands which are dynamic depending on the data being displayed.
As I built my chart, I followed the standard code layout of all the great HighChart examples where I generated the chart immediately on the document load. Then later in my code, I use an Ajax call to load the data and modify things like titles, plot bands, custom text, etc.
The problem is that anything modified on the chart after the initial chart load won't be exported to images or PDFs. My PlotBands were added during the Ajax call. They couldn't be included in the chart object that was built on document.load(). So they were conveniently ignored by HighCharts.
In my chart, I want to show energy usage during a 24-hour period at different sites. The user can choose different days and different sites. The Plot Bands needed to highlight the operating hours and each site has different operating hours which are loaded with the data. Also, the chart title shows the site name and the subtitle shows the square footage.
Additionally, my code draws some custom text on the bottom of the graph using the HighCharts renderer text() command.
My code for the barely-functioning export looks something like this:
var chart;
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: "ChartContainer",
type: "line",
title: { text: null },
subtitle: { text: null }
}
}
});
function UpdateChart() {
$.ajax({
url: "/my/url.php",
success: function(json) {
chart.addSeries(json[1]);
chart.addSeries(json[2]);
chart.setTitle(json[0].title, json[0].subtitle);
chart.xAxis[0].addPlotBand({ color: "#FCFFB9", from: json[0].OpenInterval, to: json[0].CloseInterval, label: { text: "Operating Hours", verticalAlign: "bottom", y: -5, style: { fontSize: "8pt", color: "gray" } } });
chart.renderer.text("Custom Text", 50, 100);
}
});
}
Unfortunately, the title, the plot bands and the "custom text" won't appear if the user exports the chart.
yes - its possible and highcharts support things you mentioned here's sample code http://jsfiddle.net/vijaykumarkagne/9c2vqq7q/ of dynamic highchart using json data of file hosted in google drive.
$.getJSON("https://b943d995d961c8938d74bf398f8748e2b34864c6.googledrive.com/host/0B_i_hw1oG1HeaU9nMWxfTnJZd1k/data.json",{format:"json"},function(result){
chart = new Highcharts.Chart({
chart: {
zoomType: 'x',
type: 'line',
renderTo: 'container'
},
title: {
text: ' '
},
subtitle: {
text: 'Click and drag in the plot area to zoom in',
x: -20
},
xAxis: {
type: 'datetime',
title: {
text: ' '
}
},
yAxis: {
title: {
text: ' '
}
},
series:[{
name: 'Tokyo',
data: result
}]
});
});
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://b943d995d961c8938d74bf398f8748e2b34864c6.googledrive.com/host/0B_i_hw1oG1HeaU9nMWxfTnJZd1k/dataEmp.json"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/drilldown.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<body>
<div id="container"></div>
</body>
(answering my own question here)
The key is to re-arrange how you build your chart.
Don't generate the chart on the document.load(). Generate it in the success() function of the ajax call.
First, check if the chart already exists and destroy() it. If your code allows the users to dynamically change settings, that will cause a new ajax call to execute which will need to update the graph. The chart needs to be destroyed before being re-built.
Now build a new chart from scratch. But, now you already have the data you need from the ajax call so you can build it from scratch with the correct information. HighCharts will only export data that was included the first time the chart was created. So all custom data needs to be included here. If you need to change something on the graph, destroy it and rebuild it using the custom data.
function UpdateChart() {
$.ajax({
url: "/my/url.php",
success: function(json) {
// If the chart exists, destroy it
if (chart) chart.destroy();
// Create the chart
chart = new Highcharts.Chart({
chart: {
renderTo: "ChartContainer",
type: "line",
events: {
load: function(event) {
this.renderer.text("Custom Text", 50, 100);
}
},
title: { text: json[0].title },
subtitle: { text: json[0].sqft }
},
plotBands: {
color: "#FCFFB9",
from: json[0].OpenInterval,
to: json[0].CloseInterval,
label: {
text: "Store Hours", verticalAlign: "bottom", y: -5, style: { fontSize: "8pt", color: "gray" }
}
}
};
// Add two data series to the chart
chart.addSeries(json[1]);
chart.addSeries(json[2]);
// Set title and sub-title
chart.setTitle(json[0].title, json[0].subtitle);
}
});
}
Now, the chart will show all the custom things you've added. Notice that the custom text written to the chart using the renderer.text() command are added in the chart.load() event. For some reason, it only works here.
Remember the key: HighCharts will only export data that was included the first time the chart was created. This will save you a lot of headaches.
Related
I want to use Kendo Chart and created it as:
<div id="chart"></div>
function createChart() {
$("#chart").kendoChart({
dataSource: {
transport: {
read: {
url: '#Url.RouteUrl(new { Area = "SuperAdmin", Controller = "DeviceDataUsage", Action = "DeviceDataUsageChart" })',
type: "POST",
dataType: "json"
}
},
sort: {
field: "Date",
dir: "asc"
}
},
categoryAxis: {
field: "Date"
}
});
}
$(document).ready(function () {
createChart();
});
My ajax call returns the following JSON:
[{"Date":"2022-08-01T00:00:00","Account":"0442047510-00001","ByteUsed":32596822687},{"Date":"2022-08-02T00:00:00","Account":"0442047510-00001","ByteUsed":36612506846},{"Date":"2022-08-03T00:00:00","Account":"0442047510-00001","ByteUsed":33163744510},{"Date":"2022-08-04T00:00:00","Account":"0442047510-00001","ByteUsed":33885441890},{"Date":"2022-08-05T00:00:00","Account":"0442047510-00001","ByteUsed":34242721748},{"Date":"2022-08-06T00:00:00","Account":"0442047510-00001","ByteUsed":27183604932},{"Date":"2022-08-07T00:00:00","Account":"0442047510-00001","ByteUsed":24292004315},{"Date":"2022-08-08T00:00:00","Account":"0442047510-00001","ByteUsed":24229587601},{"Date":"2022-08-09T00:00:00","Account":"0442047510-00001","ByteUsed":32560544972},{"Date":"2022-08-10T00:00:00Z","Account":"0442047510-00001","ByteUsed":29415723282},{"Date":"2022-08-01T00:00:00","Account":"0642341711-00001","ByteUsed":7153376},{"Date":"2022-08-02T00:00:00","Account":"0642341711-00001","ByteUsed":18197239},{"Date":"2022-08-03T00:00:00","Account":"0642341711-00001","ByteUsed":27505657},{"Date":"2022-08-04T00:00:00","Account":"0642341711-00001","ByteUsed":26128919},{"Date":"2022-08-05T00:00:00","Account":"0642341711-00001","ByteUsed":20523014},{"Date":"2022-08-06T00:00:00","Account":"0642341711-00001","ByteUsed":25958925},{"Date":"2022-08-07T00:00:00","Account":"0642341711-00001","ByteUsed":25540890},{"Date":"2022-08-08T00:00:00","Account":"0642341711-00001","ByteUsed":18362064},{"Date":"2022-08-09T00:00:00","Account":"0642341711-00001","ByteUsed":26562369},{"Date":"2022-08-10T00:00:00Z","Account":"0642341711-00001","ByteUsed":25290919}]
so, as we can see, there are data for 2 different accounts (it can be 3 different accounts or more). Data can be exist for the same date for both or not, no matter (if not, we think it ByteUsed as 0).
Now I want to display this data like:
where every bar is account name, X axis is date, Y axis is byteUsed.
How to do it? I don't understand how to set series depends on Account value from my JSON
You can group by Account, for example, and define a series of type "column" to set the rest of the configurations. I've also added a logarithmic scale to this example, just to demonstrate a possible configuration, as the sample data points do not show clearly in a linear scale value axis.
I have up and down arrows in my Kendo UI grid. For the first item on the grid I do not want do allow the item to move down (it is impossible) and for the last item I do not want the item to move up (also impossible).
How can I do this?
$(document).ready(function() {
//Set URL of Rest Service
var loc = (location.href);
var url = loc.substring(0,loc.lastIndexOf("/")) + "/xpRest.xsp/xpRest1";
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: url,
type: 'GET'
},batch: false
}});
dataSource.read();
$("#gridIDNoScroll").kendoGrid({
dataSource: dataSource,
pageSize: 15,
noRecords: true,
selectable : false,
columns : [{
field : "name"
},{
field : "strDate",
width : 150
},{
field : "$10",
width : 150
},{
command: [
{
text: " ",
//click: moveDown,
imageClass: "k-icon k-i-arrow-s",
icon: "k-icon k-i-arrow-s",
title: "Up",
enable: false
},
{
text: " ",
//click: moveUp,
imageClass: "k-icon k-i-arrow-n",
icon: "k-icon k-i-arrow-n"
}
],
width:"90px"
},
]
});
});
This worked for me when I needed to disable the button. Use the databound event to basically change the state, use off to remove the event handler, and then override the click event. Something like this:
$('.k-grid-add').addClass('k-state-disabled');
$('.k-header').off('click').on('click', '.k-grid-add', function (e) {
// add new logic here or ignore it
});
If you have multiple buttons in the toolbar, the something like this:
$('.k-grid-add').addClass('k-state-disabled');
$('a.k-grid-add').on("click", function (e) {
e.preventDefault();
e.stopPropagation();
});
You can use the dataBound event of the Grid to apply a k-state-disabled CSS class to the desired buttons in the first and last row of the Grid.
Keep in mind that k-state-disabled only applies a "disabled" look, but the click event will still fire and the command function will execute. You can skip the row move logic for disabled buttons.
On a side note, you can use a command name to find buttons in the DOM more easily. For example, a command button with a name foo will have a CSS class of k-grid-foo.
I am trying different ways of rendering json data from mysql/php to Highcharts. So far I've been successful rendering bar charts using this approach but for some reason, I have not been able to render data in a pie chart.
One js file handles the AJAX call:
$(function () {
var select_program = program_type_php;
var select_year = '2016';
console.log ('pie_chart'+program_type_php);
$.ajax({
url: 'model/job_group_pie_chart.php',
data: {user: 2, select_program:select_program, select_year:select_year},
type: 'GET',
async: true,
dataType: "json",
success: function (year_2016) {
pie_chart_2016(year_2016);
console.log('data 2016 job groups'+year_2016);
}
});
Upon success, I call a function in another js file (in this example, 'pie_chart_2016' and pass it the data object.
Here's the other js file responsible for rendering the data into a Highchart:
function pie_chart_2016 (year_2016) {
console.log('year_2016'+year_2016);
$('#pie-chart1').highcharts({
chart: {
plotBackgroundColor: null,
plotBorderWidth: null,
plotShadow: false,
type: 'pie'
},
title: {
text: ''
},
tooltip: {
pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
},
plotOptions: {
pie: {
allowPointSelect: true,
cursor: 'pointer',
dataLabels: {
enabled: true,
format: '<b>{point.name}</b>: {point.percentage:.1f} %',
style: {
color: (Highcharts.theme && Highcharts.theme.contrastTextColor) || 'black'
}
},
showInLegend: true
},
series: year_2016
}
});
};
I have checked, and I do get valid json from my php file:
[{name:"Group1",y:829},{name:"Group2",y:9247},{name:"Group3",y:71}]
These are raw counts (829, 9247, 71) but when I was able to get a pie chart to render by inputting values manually, Highcharts calculated the percentages for me - nice!
I've also set up enough console.logs to know that my functions are being called, and that my data object is being processed.
Still, all I get is a blank panel, and 'highcharts.com' in the lower left hand corner, so the html is working too.
The approach I'm using works really well with bar charts, so I am stumped!
Thanks for any help you can provide.
Thanks to Rahul, I moved 'series:' outside of plotOptions, and added these lines. I should have caught this sooner, that pie charts needs the 'data' property while bar charts have that included in their JSON array. Appears to be working well for now. Thanks again Rahul!
series: [{
name: 'Job Group',
colorByPoint: true,
data: year_2016
}]
I have a simple KendoUI calendar widget implemented with a custom class on each day, which on click is suppose to show a kendoUI ToolTip
$("#calendar").kendoCalendar({
month: {
// template for dates in month view
content: '<div class="tool_tip">#=data.value#</div>'
},
footer: false
});
$(".tool_tip").kendoTooltip({
autoHide: false,
showOn: "click",
position: "top",
content: 'Hello'
});
For some odd reason it will only show the tooltip on click of each day for the current month. If I were to change the month the tooltip will no longer show. Also note that the class "tooltip" is injected to all other days in the month as well.
Thank you for reading.
The problem is with the way that you set the tooltip. Since this is initialized when the Calendar is created but not refreshed when you navigate. Elements created after navigating do not have the tooltip associated to it.
You should do:
$(document).ready(function () {
$("#calendar").kendoCalendar({
month: {
// template for dates in month view
content: '<div class="tool_tip">#=data.value#</div>'
},
footer: false,
navigate : function () {
$(".tool_tip").kendoTooltip({
autoHide: false,
showOn: "click",
position: "top",
content: 'Hello'
});
}
});
});
Check it running here: http://jsfiddle.net/OnaBai/kvbse/
Allright, I'm testing the Sencha Touch framework wrapped in Phonegap and compiled to a HTC Desire with Android 2.2. The purpose of this application is just to get familiar with the Framework and it's (in)capabilities.
I'm using the MVC model. The application consists of a list of items that are loaded into a data store from a json file using a proxy. When one of those items is clicked, a detail page is shown.
app.views.viewport.setActiveItem(app.views.placesList, options.animation);
But before the transition, there is some kind of lag, and a white screen is shown for a very small amount of time. I made a vid to make it more clear:
http://www.youtube.com/watch?v=uW8hspMKqfc
The code below shows the structure and functionality of my application:
Model
app.models.Place = Ext.regModel("app.models.Place", {
fields: [
{name: "name", type: "string"},
{name: "location", type: "string"}
]
});
app.stores.places = new Ext.data.Store({
model: "app.models.Place",
proxy: {
type: 'ajax',
url : 'js/app/data/products.json',
reader: {
type: 'json',
root: 'products'
}
}
});
View
app.views.PlacesList = Ext.extend(Ext.Panel, {
fullscreen: true,
scroll: 'vertical',
dockedItems: [{
xtype: 'toolbar',
title: 'PlacesList'
}],
items: [{
xtype: 'list',
store: app.stores.places,
itemTpl: '{name}',
onItemDisclosure: function () {
Ext.dispatch({
controller: app.controllers.places,
action: 'show'
});
}
}],
initComponent: function() {
app.stores.places.load();
app.views.PlacesList.superclass.initComponent.apply(this, arguments);
}
});
Controller
app.controllers.places = new Ext.Controller({
show: function(options) {
app.views.viewport.setActiveItem(app.views.placeDetail, options.animation);
},
back: function(options) {
app.views.viewport.setActiveItem(app.views.placesList, options.animation);
}
});
I'm wondering if the experienced lag is just something that comes with Sencha Touch, or comes from the code.
Thanks in advance,
Gerard
Credit Steffen Hiller for this answer: This bug appears for all transitions that set the opacity in CSS, which the slide animation in Sencha Touch does. Credits go to the interesting Performance tips for device page."
To clarify previous answers:
If you use the slide animation just for your panels within a card layout (e.g. via Ext.TabPanel), just add the following CSS/SCSS code and all will be fine.
.x-panel {
-webkit-backface-visibility: hidden;
}
I'm using Sencha Touch 1.0.1a and PhoneGap 0.9.4.
Credit for this goes to Steffen Hiller for hist post here: http://www.senchatouchbits.com/6/fixing-flickering-of-animations-in-phonegap.html