My issue is very specific. How I can add series dynamically in highcharts, through Angular JS, without button, otherwise, without function click.
This is my controller:
var deserialize = angular.fromJson(data.dataContent); //EspecĂfico para el dataContent
for(var i =0; i < deserialize.length; i++){
var url = deserialize[i];
$http.get(url).success(function(data){
var n_scope = [];//NOMBRES PARA LA SERIE
var e_scope = []; //EMPLEADOS
for (var i = 0; i < data.length; i++) {
var nombre_scope = n_scope.push(data[i].nombre);
var empleados_scope = e_scope.push(parseInt(data[i].empleados));
}
var chart = {};
chart.addSeries({
name: n_scope[i],
data: e_scope[i]
});
HERE GOES THE CHART:
$scope.renderChart = {
chart: {
type: typeArray[2]
},
title: {
text: titleArray[2]
},
xAxis:{
categories: yAxisTiArray[2],
title: {
enabled: false
},
labels: {
enabled: false
}
},
yAxis:{
title: {
text: yAxisTiArray[2]
}
},
series: chart,
legend: {
enabled: true
},
credits: {
enabled: false
},
lang: {
printChart: 'Imprimir gráfico',
downloadPNG: 'Descargar en PNG',
downloadJPEG: 'Descargar en JPG',
downloadPDF: 'Descargar en PDF',
downloadSVG: 'Descargar en SVG',
contextButtonTitle: 'EXPORTAR'
}
};
I was taking this fiddle as example: http://jsfiddle.net/engemasa/WEm4F/, but I don't want a button click function, I want that series add it to chart dynamically
You are almost there, just put your code inside success blockof your API (angularjs api call ). here is an example (how I used to plot series on data change)
var metricData = $http.get(url);
metricData.success(function(value) {
var data = value.responseData;
var graph = [];
angular.forEach(data.datatimeseries, function(metric) {
graph.push([ metric.timestamp, metric.value ]);
// Assuming that datatimeseries is the timeseiries
});
var chartX = $('#yourDivId').highcharts();
chartX.addSeries({
id : graph_id, // some id
data : graph
});
setYaxisExtremes(chartX); // must use it to reflect added series
});
**RESOLVED**
Altough have button, I could resolve this issue.
I have created a repository that integrates Angular.js, PHP, and Highcharts, with Materialize.css, adding series dynamically from external JSON.
link: https://github.com/Nullises/DynamicSeriesHighchartsAngular
Related
On my chart using Chart.js I have an annotation created with the chartjs-plugin-annotation. I would like the annotation label to be visible on hover over the line. But I can't get it to work. I have the following code:
//define ChartOneData
var ctx = document.getElementById("chart").getContext("2d");
var chartOne = new Chart(ctx, {
type: 'line',
data: chartOneData,
options: {
annotation: {
events: ["mouseenter", "mouseleave"],
annotations: [{
type: 'line',
mode: 'vertical',
scaleID: 'x-axis-0',
value: 1,
label: {
enabled: false,
content: "Text Label",
},
onMouseenter: function(e) {
var element = this;
element.options.label.enabled = true;
element.chartInstance.update();
},
onMouseleave: function(e) {
var element = this;
element.options.label.enabled = false;
element.chartInstance.update();
}]
}
}
}
}
The events fire and change the attribute 'enabled' (visible in console testing) but the chart, and visuals, do not update.
In fact I receive the error in the console:
Unable to preventDefault inside passive event listener invocation.
dispatcher # chartjs-plugin-annotation.js:261
I don't understand this, can anyone help?
So it turned out that this was an issue with the underlying pluging. The code was correct and worked with chart.js versions 2.5 and 2.6 but not with 2.7. An issue was added to the chart-annotations github repository.
The solution was to downgrade to 2.6 and await a fix in the next version of charts.js
The Problem
So i am currently trying to implement a color picker inside of a Kendo grid, that will hopefully send the chosen color to my Sql Table. Unfortunately, It doesn't seem as though the Update controller is being reached. I am relatively new to Kendo UI, so there might be some incredibly dumb errors shown.
Questions
I guess my main question would be: How can i call the update method when update is clicked on the grid. Essentially, the color picker and the edit command are showing up in beautiful fashion. I just want to know how i can be sure that the method is being called when 'Update' is clicked, seeing as it is not reaching my controller. Feel free to ask if you need to see more code or perhaps a screen shot.
Code
Config.cshtml ( Grid )
#model IEnumerable<STZN.Models.AGCData.ErrorCode>
#{
ViewBag.Title = "Config";
}
#section HeadContent{
<script src="~/Scripts/common.js"></script>
<script>
$(document).ready(function () {
$("#grid").kendoGrid({
editable: "inline",
selectable: "row",
dataSource: {
schema: {
model: {
id: "error_code",
fields: {
color: { type: 'string' }
}
}
},
transport: {
read: {
type: "POST",
dataType: "json",
url: "#Url.Action("ErrorCodes")"
},
update: {
type: "POST" ,
dataType: "json",
url: "#Url.Action("UpdateErrorCodes")",
}
}
},
columns: [
{ command : [ "edit" ] },
{
field: "error_code", title: "Error Code",
},
{
field: "error_description", title: "Error Description"
},
{
field: "color",
width: 150,
title: "Color",
template: function (dataItem) {
return "<div style = 'background-color: " + dataItem.color + ";' </div>"
},
editor: function (container, options) {
var input = $("<input/>");
input.attr("color",options.field);
input.appendTo(container);
input.kendoColorPicker({
value: options.model.color,
buttons: false
})
},
}
]
});
});
</script>
}
Update Controller
public JsonResult UpdateErrorCodes(ErrorCode model)
{
using (var db = new AgcDBEntities())
{
db.Entry(model).State = System.Data.Entity.EntityState.Modified;
db.SaveChanges();
db.Configuration.ProxyCreationEnabled = false;
var data = db.ErrorCodes.Where(d => d.error_code == model.error_code).Select(x => new
{
error_code = x.error_code,
description = x.error_description,
color = x.color,
});
return new JsonResult()
{
JsonRequestBehavior = System.Web.Mvc.JsonRequestBehavior.AllowGet,
};
}
}
I actually managed to fix my issue by adding an additional input attribute to my editor function in the "color" field. It looks like this:
input.attr("data-bind","value:" + options.field);
There are still some present issues (unrelated to the fix/server update) , but as far as updating to the server, It work's as intended.
I have a Page where I have some Project Stats based on different Project Task Statuses. On this page I use AJAX to update my Stat values as they change.
I am now trying to integrate a Highcharts bar chart/graph and I need to update it;s chart when my data changes.
There is a JSFiddle here showing the chart I am experimenting with now http://jsfiddle.net/jasondavis/9dr345og/1/
$(function () {
$('#container').highcharts({
data: {
table: document.getElementById('datatable')
},
chart: {
type: 'column'
},
title: {
text: 'Project Stats'
},
yAxis: {
allowDecimals: false,
title: {
text: 'Total'
}
},
tooltip: {
formatter: function () {
return '<b>' + this.series.name + '</b><br/>' +
this.point.y + ' ' + this.point.name.toLowerCase();
}
},
subtitle: {
enabled: true,
text: 'Project Stats'
},
legend: {
enabled: false
},
exporting: {
enabled: false
},
credits: {
enabled: false
}
});
// Button Click to Simulate my Data updating. This increments the Completed Tasks bar by 1 on each click.
$(".update").click(function() {
var completedVal = $('#completed').text();
++completedVal
$('#completed').text(completedVal)
});
});
So this example is getting the data from a Table but I do not have to use this method, I could also set it with JavaScript if needed.
I just need to figure out how I can update all these values on the fly as my real live page updates my task stat values using AJAX so I would like this chart to update live as well.
Any help on how to make it update? When my AJAX code is ran, I could call some JavaScript at that point if there is a function that rebuilds the chart?
I would drop the use of the table, especially since it looks like you are building it just for highcharts to consume it. Instead return your data via AJAX as a Highcharts series object. and then use the Series.setData method to update your plot. This would be the right way to do it.
If you really want to use the table, you could query out the data and still use setData (this is what Highcharts is doing for you under the hood). Updated fiddle.
$(".update").click(function() {
var completedVal = $('#completed').text();
++completedVal;
$('#completed').text(completedVal);
// get y values
var yValues = $.map($('#datatable tr td'),function(i){return parseFloat($(i).text());});
// set data
Highcharts.charts[0].series[0].setData(yValues);
});
I am using morris.js charts in my angular js app.
I converted it to directive like that:
barchart.js:
angular.module('app_name').directive('barchart', function () {
return {
// required to make it work as an element
restrict: 'AEC',
template: '<div class=chart_div></div>',
replace: true,
// observe and manipulate the DOM
link: function ($scope, element, attrs) {
var data = $scope[attrs.data],
xkey = $scope[attrs.xkey],
ykeys = $scope[attrs.ykeys],
labels = $scope[attrs.labels];
Morris.Bar({
element: element,
data: data,
xkey: xkey,
ykeys: ykeys,
labels: labels,
hideHover: true,
grid: false
});
}
};
});
then, in my page.html I use the directive like that:
<section class="graphs" ng-controller="ChartController">
<div class="graphs_box">
<div class="graphs_box_title">My Orders</div>
<div class="chart_bg">
<div barchart xkey="xkey" ykeys="ykeys" labels="labels" data="MyData"></div>
</div>
</div>
The problem is, when I am adding the data to the chart in 'ChartController'
like that:
getChartData = function () {
$scope.xkey = 'X';
$scope.ykeys = ['Y'];
$scope.labels = ['Total Tasks', 'Out of Budget Tasks'];
$scope.PlannedChart = [
{ range: 'A', total_tasks: 20 },
{ range: 'B', total_tasks: 35 },
{ range: 'C', total_tasks: 100 },
{ range: 'D', total_tasks: 50 }
];
};
It works. But when I try to add data from DB (json formatted) like that:
getChartData = function () {
ChartsService.getCharts("orders").success(function (data) {
$scope.xkey = 'X';
$scope.ykeys = 'Y';
$scope.labels = ['Total Tasks', 'Out of Budget Tasks'];
$scope.OrdersChart = data.Val_Chart;
});
};
It doesn't work.
The data is fetched from DB - OK (I saw it while debugging).
Also, I noticed when I debugged that the code first goes to barchart.js whith 'undefined' data, and only after that to the service that fetches the data.
I guess this is because of getCharts("orders") working asynchronously here. You'd need to call setData(data) on the object, that Morris.Bar() returns. See the Morris.js Documenation
I fixed it, with putting all the attributes for the directive in a single object and using this as link-function:
link: function ($scope, element, attrs) {
var params = $scope[attrs.params];
angular.extend(params, {element: element});
var graph = Morris.Line(params);
var refresh = function(new_params) {
graph.setData(new_params.data);
}
$scope.$watchCollection(attrs.params, refresh);
}
$scope.$watchCollection(attrs.params,refresh); observes the params object on the scope and you just give this object a new data-array, after the async loading finished. This updates it.
This is the directive element:
<barchart params="sentin_chart"></barchart>
And this ist the object in the controller:
$scope.sentin_chart = {};
$scope.sentin_chart.data = [];
$scope.sentin_chart.xkey = 'day';
$scope.sentin_chart.ykeys = ['sent_in'];
$scope.sentin_chart.labels = ['Sent in Stories'];
As I said you just need to put the new data array into this object to update the graph $scope.sentin_chart.data = %NEWDATAARRAY%
I hope this makes any sense for you.
Below is my code where getJSON method is not working
function loadJson() {
$(document).ready(function () {
alert("inside");
var chart;
var url = "values.json";
var seriesData = [];
var xCategories = [];
var i, cat;
alert("outside");
$.getJSON(url, function (data) {
alert("inside JSON function");
for (i = 0; i < data.length; i++) {
cat = '' + data[i].period_name;
if (xCategories.indexOf(cat) === -1) {
xCategories[xCategories.length] = cat;
}
}
for (i = 0; i < data.length; i++) {
if (seriesData) {
var currSeries = seriesData.filter(function (seriesObject) {
return seriesObject.name == data[i].series_name;
}
);
if (currSeries.length === 0) {
seriesData[seriesData.length] = currSeries = { name: data[i].series_name, data: [] };
} else {
currSeries = currSeries[0];
}
var index = currSeries.data.length;
currSeries.data[index] = data[i].period_final_value;
}
else {
seriesData[0] = { name: data[i].series_name, data: [data[i].period_final_value] }
}
}
//var chart;
//$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'bar'
},
title: {
text: 'Stacked column chart'
},
xAxis: {
categories: xCategories
},
yAxis: {
//min: 0,
//max: 100,
title: {
text: 'Total fruit consumption'
},
stackLabels: {
enabled: false,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},
legend: {
align: 'right',
x: -100,
verticalAlign: 'top',
y: 20,
floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColorSolid) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
formatter: function () {
return '<b>' + this.x + '</b><br/>' +
this.series.name + ': ' + this.y + '<br/>'
}
},
series: seriesData
});
});
});
}
In url , values.json is my JSON file as follows
[{"series_name":"Actual","period_name":"Q1 / 2013","period_final_value":17},
{"series_name":"Actual","period_name":"Q2 / 2013","period_final_value":15},
{"series_name":"Actual","period_name":"Q3 / 2013","period_final_value":13},
{"series_name":"Actual","period_name":"Q4 / 2013","period_final_value":19},
{"series_name":"Alarm","period_name":"Q1 / 2013","period_final_value":14.103},
{"series_name":"Alarm","period_name":"Q2 / 2013","period_final_value":14.404499999999999},
{"series_name":"Alarm","period_name":"Q3 / 2013","period_final_value":14.966999999999999},
{"series_name":"Alarm","period_name":"Q4 / 2013","period_final_value":50},
{"series_name":"Target","period_name":"Q1 / 2013","period_final_value":15.67},
{"series_name":"Target","period_name":"Q2 / 2013","period_final_value":16.005},
{"series_name":"Target","period_name":"Q3 / 2013","period_final_value":16.63},
{"series_name":"Target","period_name":"Q4 / 2013","period_final_value":100}]
file renders but data is not shown on chart, only the alert outside the getJSON method works, inner one doesnot works, the same code if I try to run from html page then it works fine, but now I have written the entire code as it is in VS in ASP.NET Web Application and I have called the loadJson function on body onLoad in javascript as follows,
<body onload="loadJson();">
but the method doesn't run,
not able to solve this, any help will be greatly appreciated...
----------Additional work------
when I add my JSON data in any variable above the getJSON method and eliminate the getJSON method and access that then I get the Graph properly but when I am using getJSON method then it's not working
-----Error Inspected----------
I inspected the error in chrome and I got to know it is not able to get the json file, I have kept the JSON file in project folder , then also I tried by keeping the json file in localhost, still its saying same error..
Now I am thinking I am facing problem with mime type handling with aspx page..is it anything to link with it..??
1) Make sure you are using a valid json: www.jsonlint.com
2) Run your json file on localhost. Tell me if you see the json file on your browser run on localhost. Make sure you have this in your web.config
<system.webServer>
<staticContent>
<mimeMap fileExtension=".json" mimeType="application/json" />
</staticContent>
</system.webServer>
3) Alert info using getJSON function
$(document).ready(function () {
$.getJSON("values.json", function (data) {
$.each(data, function () {
alert(this.series_name);
});
});
});
4) When you pass these tests, continue building up your jQuery codes.
Is there any error with the call of file?
try the following:
$.getJSON(url)
.done(function(data) {
alert("INSIDE FUNCTION")
})
.fail(function(jqXHR, textStatus) {
alert("Request failed: " + textStatus);
});
I use this coding style mostly for all jquery ajax (and wrapper) calls, so that I can give the user a response if
the request failed.
Use $.getJSON not $.get like,
$.getJSON(url, function (data) {
alert("inside JSON function");
And Check your json is valid or not (Check a JSON tab is there in your console)
http://jsonlint.com/ found an issue with your JSON
[{"series_name":"Actual","period_name":"Q1 / 2013","period_final_value":17},
{"series_name":"Actual","period_name":"Q2 / 2013","period_final_value":15},
{"series_name":"Actual","period_name":"Q3 / 2013","period_final_value":13},
{"series_name":"Actual","period_name":"Q4 / 2013","period_final_value":19},]
Its not a valid JSON because of the , just before the ] bracket.