I've got an issue, I'm trying to create a chart (pie) with ChartJS using twig data.
The chart label uses an array, so I'm giving a twig array to it like this :
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: ({{array|json_encode()|raw}})
But it displays "object Object". For my purpose I want to display an attribute of that object, in that example : "intitule"
Thanks a lot.
I suggest you write an own Twig extension and add a filter function to it:
1. Create the extension class and add a filter with name chart:
// src/AppBundle/Twig/AppExtension.php
namespace AppBundle\Twig;
class AppExtension extends \Twig_Extension
{
public function getFilters()
{
return array(
new \Twig_SimpleFilter('chart', array($this, 'chartFilter')),
);
}
public function chartFilter($items, $key = 'intitule')
{
$output = [];
foreach ($items as $item {
if (array_key_exists($key, $item)) {
$output[] = $item[$key];
}
}
return json_encode($output));
}
}
2. Create service
Depending on your services.yml definition you may need to create a service for the extension:
app.twig_extension:
class: AppBundle\Twig\AppExtension
tags:
- { name: twig.extension }
3. Use the filter in your view
you can use the filter using it like this:
var myChart = new Chart(ctx, {
type: 'pie',
data: {
labels: ({{array|chart|raw}})
Related
This question already has an answer here:
Retrieving JSON data for Highcharts with multiple series?
(1 answer)
Closed 2 years ago.
I have been trying to display the second value of my json file in highcharts for two days.
my json file:
[[1591518187000,17.3,12.7],[1591518135000,17.2,12.7]...[1591518074000,17.2,12.6],[1591518020000,17.2,12.7]]
The time and the first value are displayed correctly.
my script in php file:
<script type="text/javascript">
var chart;
function requestData() {
$.getJSON('../****json.php',
function (data) {
var series = chart.series[0];
series.setData(data);
}
);
}
(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
defaultSeriesType: 'line',
marginRight: 10,
marginBottom: 25,
events: { load: requestData }
},
.....
series: [{
name: 'Temperatur',
data: []
},
{
name: "Taupunkt",
data: []
......
</script>
Does anyone happen to have a way of drawing the second values as a line?
You could process your data and make two data sets for both series. Both data sets will have the same x values, but different y values. The code could look something like this:
$.getJSON('../****json.php',
function (data) {
var dataSetOne = [],
dataSetTwo = [];
data.forEach(function(point) {
dataSetOne.push([point[0], point[1]);
dataSetTwo.push([point[0], point[2]);
});
chart.series[0].setData(dataSetOne);
chart.series[1].setData(dataSetTwo);
}
);
I have created a pie chart using Chart.js and data is taken from the SQL-server database using entity framework. That is done in the controller.
namespace ChartJsDatabase.Controllers
{
public class ChartController : Controller
{
//============ The Object Created here is used to get the database connection =============
CSharpCornerEntities entities = new CSharpCornerEntities();
//==========================================================================================
// GET: Chart
public ActionResult Index()
{
return View();
}
public ActionResult PieChart()
//============= This Action Result Requires ===============
//============= String Database Query =====================
{
using (entities)//;
{
var studentName = entities.Database.SqlQuery<PlannedVsActualModel>(#"SELECT [Planned], [Actual] FROM [dbo].[PlanVsActual]").ToList();
return Json( studentName, JsonRequestBehavior.AllowGet);
}
}
}
}
The View is as follows
<div class="col-lg-4">
<canvas id="chart_3" width="800" height="800" http-equiv="refresh" content="5"></canvas>
<h5 style="text-align:center">Total</h5>
</div>
<script type="text/javascript">
$(document).ready(function () {
$.ajax({
type: "GET",
url: "/Chart/PieChart",
data: {},
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
successFunc(response);
},
});
function successFunc(jsondata) {
console.log(jsondata);
window.globalVariable = jsondata;
console.log(globalVariable[0].Actual)
//===========Chart Js Code Starts Here ============
//=================================================
var ctx = document.getElementById('chart_3').getContext('2d');
var chart = new Chart(ctx, {
type: 'doughnut',
data: {
datasets: [
{
backgroundColor: ["#228B22", "#f0eeef"],
//========== Data for Chart JS ==============
data: [globalVariable[0].Actual, (globalVariable[0].Planned - globalVariable[0].Actual)],
//===========================================
label: ["Actual", "Planned"],
borderWidth: 0,
}
]
},
options: {
cutoutPercentage: 80,
elements: {
center: {
text: [(globalVariable[0].Actual/globalVariable[0].Planned*100).toFixed(2)]+"%",
color: '#666666', //Default black
fontStyle: 'Helvetica', //Default Arial
FontSize: 1,
sidePadding: 1 //Default 20 (as a percentage)
}
}
}
});
// ==========Chart Js Chart Ends Here==========
//==============================================
}
});
</script>
I have created the following Model
namespace ChartJsDatabase.Models
{
public class PlannedVsActualModel
{
public int Planned { get; set; }
public int Actual { get; set; }
}
}
I need to update the pie chart when there is a change in the SQL Server Database values. We are not going to refresh the entire page, but only the chart and it should happen automatically in a continuous-time interval.
Simple, really. Just use the chart.config to edit it's property, then run chart.update()
Here is more info: https://www.chartjs.org/docs/latest/developers/updates.html
You can achieve it in multiple ways, here is the one with partial views
a) Create a partial view and include it with your page
<Div id="pieChart">
#HTML.Partial("__pieChartPartial" , chartdata)
</Div>
b) write a jquery script in page
<script>
setInterval(function()
{$('#__pieChartPartial').load("controller/action")},1000); # adjust interval time based on your requirement
</script>
c) In the action method return partial view result
Return PartialView("__pieChartPartial", chartdata)
d) Make output cache, nostore and set duration to 1 min
[OutputCache(NoStore=true,Location=System.Web.UI.OutputCacheLocation.Client,Duration=1)]
e) Enable sql broker.
f) Install-Package SqlTableDependency
g) Write a code for table watcher and start watching in controller's constructor
h) In table dependency change event, refresh chart data.
This question has been asked many times and I went through most of them but non of them helped me finding a solution.
I am generating couple of bar charts using a for loop as a part of reporting functionality.
I am using node.js with Express Handlebars.
My page looks like:
<div class="row report-charts">
<div class="col-md-12">
{{#buildings}}
<div class="col-md-6">
<h4>{{Name}}</h4>
<canvas id="{{idBuildings}}" width="200" height="80"></canvas>
</div>
{{/buildings}}
</div>
</div>
My js code looks like:
$('.case-report-btn').click(function(){
$.ajax({
type: 'post',
url: '/reports/cases/filter',
data : {
StartDate : $('.start-ms-time-hidden').val(),
EndDate : $('.end-ms-time-hidden').val(),
ReportKey : $('.cases-filter-type').val()
},
dataType: 'json',
success: function(res) {
$('.report-charts').show();
for(key in res) {
var innerObj = res[key]; //gives the inner obj
var ctx = document.getElementById(key); //the idBuildings
var labels = [];
var data = [];
var buildingName = innerObj.Name;
for(innerKey in innerObj) {
if(innerKey != 'Name' && innerKey != 'Total') {
labels.push(innerKey);
data.push(innerObj[innerKey]);
}
}
var options = {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: buildingName,
data: data,
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255,99,132,1)',
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero:true,
fixedStepSize: 1
}
}]
}
}
}
var myChart = new Chart(ctx, options);
}
$('#pleaseWaitDialog').modal('hide');
},
error: function(err) {
$('#pleaseWaitDialog').modal('hide');
bootbox.alert('Error: ' + err);
}
});
});
So basically, I am using for loop to generate multiple charts on the page. Inside the loop I declared the chart variable, every time I change the report parameters and hit the button, the new chart is generated. But when I hover over it, the old one still shows up.
Now I am not sure where I should be putting the myChart.destroy() or myChart.clear() methods. I also tried moving the myChart declaration outside the for loop but it didn't help either.
Any suggestions on how to handle this?
I think there are a few ways to do it. You can update your chart data if the chart already exist. Here two functions you can use:
function removeData(chart) {
chart.data.labels.pop();
chart.data.datasets.forEach((dataset) => {
dataset.data.pop();
});
chart.update();
}
function addData(chart, label, data) {
chart.data.labels.push(label);
chart.data.datasets.forEach((dataset) => {
dataset.data.push(data);
});
chart.update();
}
First you have to remove all your data and then add the new data.
If you want to destroy the chart and create it again you have to save your variable as global. To do this you have yo declare your variable like window.myChart and then before create the new chart, something like this:
if (window.myChart) window.myChart.destroy();
window.myChart = new Chart(ctx, options);
Another way you can try is removing your canvas and creating another one. Something like this:
$('#your_canvas').remove();
$('#your_canvas_father').append('<canvas id="your_canvas"></canvas>');
I'm totally new to Highcharts and I made two types of them: spline and pie. They now look like this:
And this:
The problem I have can be seen immediately. Since I have two buttons on which user can determine how he wants his chart to appear:
I succeed to update chart type like so:
$('#pie').click(function(){
if($('#pie').hasClass('active')!=true){
$('#spline').removeClass('active');
$('#pie').addClass('active');
$('#curve_chart').highcharts().series[0].update({
type: "pie"
});
}
});
But I don't want this pie chart to appear like this. I want, like in spline type that values represent each day, not Notiflow:35 etc. This is code responsible for charts:
var type='';
$('#spline').click(function(){
if($('#spline').hasClass('active')!=true){
$('#pie').removeClass('active');
$('#spline').addClass('active');
$('#curve_chart').highcharts().series[0].update({
type: "spline"
});
}
});
$('#pie').click(function(){
if($('#pie').hasClass('active')!=true){
$('#spline').removeClass('active');
$('#pie').addClass('active');
$('#curve_chart').highcharts().series[0].update({
type: "pie"
});
}
});
$(function () {
if($('#spline').hasClass('active')){
type='spline';
}else{
type='pie';
}
$('#curve_chart').highcharts({
chart: {
type: type
},
title: {
text: 'Click through rate:'
},
xAxis: {
categories: [<?php foreach ($percentagePerDay as $key => $value) {
if ($value != $last) {
echo substr($key, -2);
echo ',';
} else {
echo substr($key, -2);
}
}?>]//key
},
yAxis: {
title: {
text: 'Percentage'
}
},
series: [{
name: '<?= $name ?>',
data: [<?php foreach ($percentagePerDay as $key => $value) {
if ($value != $last) {
echo $value;
echo ',';
} else {
echo $value;
}
}?>]//value
}]
});
});
I tried to make pie chart to represent hard coded values like so:
$('#pie').click(function(){
if($('#pie').hasClass('active')!=true){
$('#spline').removeClass('active');
$('#pie').addClass('active');
$('#curve_chart').highcharts().series[0].update({
type: "pie"
series:[{
data:[['11',35],['12',15],['13',30],['14',20]]
}]
});
}
});
}
});
But pie highchart didn't changed. What more do I need to add to this line(except of type):
$('#curve_chart').highcharts().series[0].update({});
in order for my pie to represent values for each day within range like spline does and to remove those 'slice' moments?
UPDATE:
So, this is how I want my pie to look:
When updating series o not pass series in object - only series properties, like name, type, data, etc. To have dataLabels like in the image you only will need to set names for points, Highcharts will make it work.
Example: http://jsfiddle.net/tvd6faf9/
Sometimes I like to use the HTML5/Javascript implementations of the Kendo framework because you can do some things a little easier. In this case I need to know the number of results so I can either display a kendo grid or not, however other times I need to modify the datasource based on user input on the client side. Unfortunately you can't get the number of results or modify the datasource (as far as I know) using the MVC wrappers. How can I call the controller using the Javascript implementation of the Kendo datasource?
I was able to get this working using the following code:
Controller:
public ActionResult GetStuff(string parameter)
{
// Get your data here ...
var data = GetData(parameter);
return Json(data, JsonRequestBehavior.AllowGet);
} // end
Markup/cshtml:
<div id='myGrid'></div>
<script>
$(document).ready(function () {
// Define the dataSource, note that the schema elements are specified
var dataSource = new kendo.data.DataSource({
dataType: "json",
type: "GET",
transport: {
read: '#Url.Action("MethodName", "ControllerName", new {parameter = myParameter} )'
},
schema: {
data: "Stuff",
total: "TotalNumberofStuff",
errors: "ErrorMessage"
}
});
}
// Call fetch on the dataSource - this gets the data - the fetch method will make only one call.
// Please note that the datasource fetch call is async, so we must use it's results within the fetch function.
dataSource.fetch(function () {
var numberOfItems = dataSource.total();
if (numberOfItems == 0) {
// If 0 items are returned show the label that says there are no items
$("#myGrid").append("<p><label style='font-size: small; color: red;'>-- No Items --</label></p>");
}
else {
$("#myGrid").kendoGrid({
dataSource: dataSource,
height: function () {
return (numberOfItems >= 1 && numberOfItems <= 5) ? null : "225";
},
columns: [
{ field: "StuffId", title: "Id", width: 150 },
{ field: "Stuff", title: "Stuff", width: 150 }
]
});
}
});
</script>