How to add tooltip for the inner doughnut - chart.js

Can't work out how to add tooltip for the inner doughnut
Using chart.js 1.0.1, the fiddle has 2.7.2 library
https://jsfiddle.net/xpvt214o/216304/
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var tooltipLabel = data.labels[tooltipItem.index];
var tooltipData = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
var tooltipData1 = data.datasets[tooltipItem.datasetIndex].data1[tooltipItem.index];
return tooltipLabel + ': £' + tooltipData + ', ' + tooltipData1 + '% ';
}
}
}
}
Any help would be appreciated.
Thanks

To future self:
added data1:[] after data[] in the dataset,
data: [
{% for row in monthlyChart_avg_prev %}
"{{ row[6] }}",
{% endfor %}
],
data1: [
{% for row in monthlyChart_avg_prev %}
"{{ row[8] }}",
{% endfor %}
],
then in toolips:
tooltips: {
callbacks: {
label: function(tooltipItem, data) {
var tooltipLabel = data.labels[tooltipItem.index];
var tooltipData = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
var tooltipData1 = data.datasets[tooltipItem.datasetIndex].data1[tooltipItem.index];
return tooltipLabel + ': £' + tooltipData + ', ' + tooltipData1 + '% ';
}
}
}
found on chartsjs.org

Related

chartjs not update using select option in laravel

I have problem with my code that when I use select option in chartjs datasets
below is the html code
<div class="form-group">
<select name="tahun" id="tahun" class="form-control">
#for ($i = 2021; $i <= date('Y'); $i++)
<option #if ($i == date('Y')) <?php echo 'selected'; ?> #endif value="{{ $i }}">{{ $i }}</option>
#endfor
</select>
</div>
<div id="parent-canvas">
<canvas id="chartpendapatan" width="400" height="200"></canvas>
</div>
and the jquery code is below :
const ctxpendapatan = document.getElementById('chartpendapatan').getContext('2d');
const myChartpendapatan = new Chart(ctxpendapatan, {
type: 'bar',
data: {
labels: [],
datasets: [{
label: 'Pendapatan Desa',
data: [],
borderWidth: 1
}]
},
options: {
legend: {
display: false
},
scales: {
y: {
beginAtZero: true
}
}
}
});
var getData = function() {
var tahun = $("#tahun").val();
$.ajax({
url: "{{ url('/grafik_pendapatan') }}" + '/' + tahun,
type: "GET",
dataType: "JSON",
success: function(data) {
$.each(data.result, function(id, value) {
myChartpendapatan.data.labels.push(value.nama_bidang);
myChartpendapatan.data.datasets[0].data.push(value.total_anggaran);
});
myChartpendapatan.update();
},
error: function() {
alert("Tidak Ada Data");
}
});
};
const brgy = document.getElementById('tahun');
brgy.addEventListener('change', getData);
the output of my code is :
It's the data after I select year 2021
but after I select again year 2022 the output below :
first time whe I click year 2021, display 4 data in chart because in the database there are four data. but after I click year 2022, the data in 2021 still exist and data 2022 display also. so my question how to not display previous data after I select another year?
You push to the labels and data array, if you dont want to show previous data you need to remove this data first or just entirly override the array:
success: function(data) {
myChartpendapatan.data.labels = [];
myChartpendapatan.data.datasets[0].data = [];
$.each(data.result, function(id, value) {
myChartpendapatan.data.labels.push(value.nama_bidang);
myChartpendapatan.data.datasets[0].data.push(value.total_anggaran);
});
myChartpendapatan.update();
},

jqgrid use in Django template: Reverse for 'item-jqgrid-entity1'

Trying to revive a Django app that was working 2014-2015 then was turned off for almost 3 years and now is not willing to cooperate.
Mac OS X el Capitan 10.11.6
Python 3.6 (also tried 3.4)
Django 1.8.3
In short, how does notation (in template) {% url 'item-jqgrid-entity1' pk=original.id %} connects to django models Item and Entity1 WITHOUT having item-jqgrid-entity1 listed in url.py ? I am getting
Reverse for 'item-jqgrid-entity1' with arguments '()' and
keyword arguments '{'pk': 123}' not found. 0 pattern(s) tried: []
and it used to work somehow. If I introduce matching URL in urls.py, it works, but I want to know how it was working without it.
For a given model (Item) the default template change_form.html was overriden. The custom one goes like this:
{% extends "admin/change_form.html" %}
{% load admin_urls %}
.
.
var searchable_columns = {
alteration_type: {
searchoptions: {
dataUrl: '{% url 'item-jqgrid-entity1' pk=original.id %}'
}
},
disease: {
searchoptions: {
dataUrl: '{% url 'item-jqgrid-entity2' pk=original.id %}'
}
},
}
.
.
$(document).ready( function () {
$("#table_{{ original.id }}").jqGrid({
autowidth: true,
height: 300,
hidegrid: false,
// double click handler
ondblClickRow: function(rowid, iRow, iCol, e) {
// rowid is object ID i want to edit
// mimics showRelatedObjectPopup()
// in django's RelatedObjectLookups.js
href = '{% url 'admin:some real url here' %}' + rowid + '/?_to_field=id&_popup=1';
$('div.alert').remove();
var win = window.open(href,
'id_drug',
'height=500,width=800,resizable=yes,scrollbars=yes');
win.focus();
return false;
},
// #25: workflow: marking edited rows
gridComplete: function () {
for (var i = 0; i < rowsToColor.length; i++) {
$("#" + rowsToColor[i]).find("td").css("background-color", "#dff0d8");
$("#" + rowsToColor[i]).find("td").css("color", "#468847");
}
// this will overwrite green ones, too.
for (var i = 0; i < incompleteRowsToColor.length; i++) {
$("#" + incompleteRowsToColor[i]).find("td").css("background-color", "#fcf8e3");
$("#" + incompleteRowsToColor[i]).find("td").css("color", "#b94a48");
}
// this will overwrite green and yellow ones, too.
for (var i = 0; i < unworthyRowsToColor.length; i++) {
$("#" + unworthyRowsToColor[i]).find("td").css("background-color", "#f2dede");
$("#" + unworthyRowsToColor[i]).find("td").css("color", "#b94a48");
}
// commented lines are bold.
for (var i = 0; i < commentedRowsToBold.length; i++) {
$("#" + commentedRowsToBold[i]).find("td").css("font-weight", "bold");
}
},
datatype: "json",
colModel: [
{
label: 'Entity1',
name: 'entity1',
width: 45,
// search options
stype: 'select',
searchoptions: searchable_columns.entity1.searchoptions,
editable: true,
edittype: 'select',
editoptions: {
dataUrl: '{% url 'editdata-AllEntity1' %}',
},
},
{
label: 'Entity2',
name: 'entity2',
width: 75,
// search options
stype: 'select',
searchoptions: searchable_columns.entity2.searchoptions,
editable: true,
edittype: 'select',
editoptions: {
dataUrl: '{% url 'editdata-allEntity2' %}',
},
],
viewrecords: true, // show the current page, data rang and total records on the toolbar
caption: "{{ original.pk }}: {{ original }}",
pager: "#tablePager_{{ original.id }}",
}
});
$('#table_{{ original.id }}').jqGrid('filterToolbar');
$('#table_{{ original.id }}').navGrid("#tablePager_{{ original.id }}", {
search: false, // show search button on the toolbar
add: false,
edit: false,
del: false,
refresh: true, position: "left", cloneToTop: true
},

Vue order list view

I've been working with vue js 1.27 on a project and I need to be able to sort a list by numeric values, Alphabetic and reverse order.
I've been trying this all day with not really much progress.
I've left some of my previous code in my code sample to let you know what I've already attempted.
{% extends 'base.html.twig' %}
{% block body %}
<div id="wrap">
<h2>Select a category</h2>
<ul id="categorySelect">
<li v-for="cat in categories | orderBy reverse" #click="selectCategory(cat)" class="${cat.selectedCategory == category ? 'selected' : ''}">${cat.title}</li>
</ul>
</div>
{% endblock %}
{% block javascripts %}
<script type="text/javascript">
Vue.config.delimiters = ['${', '}'];
new Vue({
el: '#wrap',
data: {
//reverse: -1,
wasClicked: true,
selectedCategory: null,
categories: [{
title: 'ALL',
category: null
},
{
title: 'CATE',
category: 'sport'
},
{
title: 'DOG',
category: 'sport'
},
{
title: 'SPEED',
category: 'sport'
},
{
title: 'CAT',
category: 'sport'
},
{
title: 'SPORT',
category: 'sport'
},
{
title: 'ART',
category: 'sport'
},
{
title: 'PEOPLE',
category: 'people'
},
{
title: 'CAR',
category: 'car'
}]
},
filters: {
categoryFilter: function (infoBlocs) {
return this.wasClicked ? this.categories : {};
},
caseFilter: function () {
if (this.wasClicked) {
return this.reverseArray();
}
return this.alphaSortByKey(this.categories, 'category');
},
reverse: function(value) {
// slice to make a copy of array, then reverse the copy
return value.slice().reverse();
}
},
methods: {
selectCategory: function(category) {
//this.wasClicked =! this.wasClicked;
//this.categories = this.alphaSortByKey(this.categories, 'category');
// if (this.reverse) {
// this.categories = this.alphaSortByKey(this.categories, 'category');
// }
// else {
// this.categories = this.reverseArray();
// }
if (this.reverse) {
this.categories = this.alphaSortByKey(this.categories, 'category');
this.reverse = false;
}
else {
this.categories = this.reverseArray();
//this.reverse = true;
}
},
alphaSortByKey: function (arr, key) {
arr.sort(function (a, b) {
if (a[key] < b[key])
return -1;
if (a[key] > b[key])
return 1;
return 0;
});
return arr;
},
reverseArray: function () {
return this.categories.reverse();
},
changeOrder: function (event) {
var self = this;
self.reverse = self.reverse * -1
var newItems = self.categories.slice().sort(function (a, b) {
var result;
if (a.name < b.name) {
result = 1
}
else if (a.name > b.name) {
result = -1
}
else {
result = 0
}
return result * self.reverse
})
newItems.forEach(function (item, index) {
item.position = index;
});
this.categories = newItems;
}
}
});
</script>
{% endblock %}
Here is a fiddle with working functionality to sort and reverse the order of your array. For reverse I just used the built in reverse() Javascript function. For the alphanumeric sort I borrowed the solution from this answer: https://stackoverflow.com/a/4340339/6913895
https://jsfiddle.net/n1tbmgo9/
Html:
<div id="wrap">
<h2>Select a category</h2>
<button #click="sort">
Sort alphanumeric
</button>
<button #click="reverse">
Reverse list
</button>
<ul id="categorySelect">
<li v-for="cat in categories">${cat.title}</li>
</ul>
</div>
Javascript:
Vue.config.delimiters = ['${', '}'];
new Vue({
el: '#wrap',
data: {
selectedCategory: null,
categories: [{
title: 'ALL',
category: null
},
{
title: 'CATE',
category: 'sport'
},
{
title: 'DOG',
category: 'sport'
},
{
title: 'SPEED',
category: 'sport'
},
{
title: 'CAT',
category: 'sport'
},
{
title: 'SPORT',
category: 'sport'
},
{
title: 'ART',
category: 'sport'
},
{
title: 'PEOPLE',
category: 'people'
},
{
title: 'CAR',
category: 'car'
}]
},
methods: {
sort: function () {
this.categories.sort(this.sortAlphaNum);
},
reverse: function () {
this.categories.reverse();
},
sortAlphaNum: function (a,b) {
var reA = /[^a-zA-Z]/g;
var reN = /[^0-9]/g;
var aA = a.title.replace(reA, "");
var bA = b.title.replace(reA, "");
if(aA === bA) {
var aN = parseInt(a.title.replace(reN, ""), 10);
var bN = parseInt(b.title.replace(reN, ""), 10);
return aN === bN ? 0 : aN > bN ? 1 : -1;
} else {
return aA > bA ? 1 : -1;
}
}
}
});
The built in reverse() function is straightforward so I will elaborate on the sortAlphaNum() sort function. That function is passed into the sort() function and must return either 1, 0, or -1 to indicate if the objects passed in should be moved in a particular direction in the array.
The variables reA and reN are regexes to identify alphabetic and numeric characters, respectively.
First the function removes all alphabet characters from the titles of the two objects passed in and compares them for equality.
var aA = a.title.replace(reA, ""); and
var bA = b.title.replace(reA, "");
If they are not equal then it means we have alphabet characters (as opposed to just numeric input) and we can sort them accordingly.
return aA > bA ? 1 : -1;
If the titles with alphabet characters stripped are equal (if(aA === bA)) then we remove numeric digits from the object titles (leaving non-numeric characters).
var aN = parseInt(a.title.replace(reN, ""), 10);
var bN = parseInt(b.title.replace(reN, ""), 10);
Then we compare the resulting variables and return the appropriate sorting value (1, 0, -1).
return aN === bN ? 0 : aN > bN ? 1 : -1;
create a computed property where you manually sort it and then loop for that instead the data prop
There is my List Component implementation with client-side order implementation:
<template>
<div>
<table class="table table-bordered" v-if="data.length">
<thead>
<tr>
<th v-for="(colValue, colKey) in cols" :key="colKey">
<a #click="sort(colKey)" href="javascript:void(0)">
{{colValue}}
<icon :name="(sortColumn === colKey) ? (sortAsc ? 'sort-down' : 'sort-up') : 'sort'"></icon>
</a>
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in data" :key="row.id">
<td v-for="(colValue, colKey) in cols" :key="row.id + colKey">{{row[colKey]}}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
import _ from 'lodash';
import apiServer from '#/utils/apiServer'; //
export default {
name: 'List',
data() {
return {
data: [],
sortColumn: '',
sortAsc: true
};
},
props: {
cols: {
type: Object,
required: true
},
apiEndpoint: {
type: String,
required: true
}
}
created() {
this.fetchData();
},
watch: {
'$route': 'fetchData'
},
methods: {
async fetchData() {
const response = await apiServer.get(this.apiEndpoint);
this.data = response.data;
},
sort(colKey) {
this.data = _.sortBy(this.data, [colKey]);
if (this.sortColumn === colKey) {
if (!this.sortAsc) {
this.data = _.reverse(this.data);
}
this.sortAsc = !this.sortAsc;
} else {
this.sortAsc = false;
}
this.sortColumn = colKey;
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>
Usage example
<template>
<div>
<h1>Orders</h1>
<List :cols="cols" api-endpoint="/orders" title="Orders" />
</div>
</template>
<script>
import List from '#/components/List.vue';
export default {
name: 'OrderList',
components: { List },
data() {
return {
cols: {
id: 'Id',
title: 'Title',
created_at: 'Created at'
}
};
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
</style>

Create pie chart with HighCharts in Django error - Blank page

I'm trying to create a pie chart with highcharts with Django (with Mac Maverick), but I just get a blank page. Is there some error in my code below?
My data consists of a dictionary with 2 keys (body and id__count), the loop inside it works perfectly in body tag. But it's not working in script tag.
<script>
function numberWithCommas(x) {
var parts = x.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
}
$(function () {
var chart;
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'categoryPieChart'
},title: {
text: 'Category'
},tooltip: {
formatter: function() {
return '<b>'+ this.point.name +'</b>: '+ numberWithCommas(this.y.toFixed(2));
}
},exporting: {
enabled: false
},plotOptions: {
pie: {
dataLabels: {
enabled: true,
formatter: function() {
return '<b>'+ this.point.name +'</b>: '+ Math.round(this.percentage) +' %';
}
}
}
},series: [{
type: 'pie',
data: [
{% for cat in responses_pie %}
[
'{{ cat.body }}',
{% if cat.id__count > 0 %}
{{ cat.id__count }}
{% else %}
0
{% endif %}
],
{% endfor %}
]
}]
});
});
});
});
</script>
This is the view source on Chrome in the script tag:
function numberWithCommas(x) {
var parts = x.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
}
$(function () {
var chart;
$(document).ready(function() {
chart = new Highcharts.Chart({
chart: {
renderTo: 'categoryPieChart'
},title: {
text: 'Category'
},tooltip: {
formatter: function() {
return '<b>'+ this.point.name +'</b>: '+ numberWithCommas(this.y.toFixed(2));
}
},exporting: {
enabled: false
},plotOptions: {
pie: {
dataLabels: {
enabled: true,
formatter: function() {
return '<b>'+ this.point.name +'</b>: '+ Math.round(this.percentage) +' %';
}
}
}
},series: [{
type: 'pie',
data: [
[
'apple',
2
],
]
}]
});
});
});
});
And my view (views.py)
def piechart(request):
responses_pie = AnswerRadio.objects.values("body").annotate(Count("id"))
return render(request, 'chart_code_v2.html', {'responses_pie': responses_pie})
You have an extra }); at the end (one from Highcharts.Chart({, one from $(document).ready(function() {, one from $(function () { and one too much). This should be visible as a syntax error in your javascript console.
Also, calling $(document).ready(fn) is superfluous, because $(fn), which you use on the function around it, is a shorthand for $(document).ready(fn).
If you plan to support old Internet Explorer versions, you will also need to remove the last comma from your data, for example like this:
{% for cat in responses_pie %}
[
'{{ cat.body }}',
{% if cat.id__count > 0 %}
{{ cat.id__count }}
{% else %}
0
{% endif %}
]{% if not forloop.last %},{% endif %}
{% endfor %}
Generally, it is better to serialize data in the view via json.dumps and pass the string to the template, as it is less error prone. For example:
import json
def piechart(request):
responses_pie = AnswerRadio.objects.values("body").annotate(Count("id"))
res = []
for cat in responses_pie:
res.append([
cat.body,
cat.id__count,
# ... more stuff
])
return render(request, 'chart_code_v2.html', {'responses_pie_json': json.dumps(res)})
then just use data: {{ responses_pie_json|safe }} in your template. Be aware that some Python objects (datetime, Decimal, ...) need some extra work for JSON serialization.

django csrf cookie no longer working

I don't understand why, but Django has ceased including the csrf cookie in responses. I have the middleware enabled, have tried using RequestContext and am using render. I have even tried using the csrf_protect and requires_csrf_token decorators.
I am working on a dev server right now, and I can print the context after I use RequestContext, and it seems to include a csrf_token.
But when I look at the actual headers using Chrome's inspect element, the csrf_token isn't there, also when I use the console and type in "document.cookie" that does not have the csrf token.
HELP!
Here's an example view
#requires_csrf_token
def index(request):
context = RequestContext(request, {'foo':'bar'})
print context
return render(request, 'index.html', context)
The CSRF token seems to be in the context:
{u'csrf_token': <django.utils.functional.__proxy__ object at 0x1025ab990>}, ...
But it fails to make its way through...
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Cookie:__utma=96992031.468590559.1369255550.1369255550.1369255550.1; __utmb=96992031.17.10.1369255550; __utmc=96992031; __utmz=96992031.1369255550.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Host:127.0.0.1:8000
Referer:http://127.0.0.1:8000/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31
UPDATE: Here is the template I'm using:
{% extends "base.html" %}
{% block hello %}
Basic Stock Event Charts
{% endblock %}
{% block content %}
<div id="leftsidebar">
<p>Use this tool to graph a time series data for a security. You can graph a security and
four other features such as volume, call option volume, or implied volatility. The tool will
zoom in on the date of interest to show the target audience the changes in the selected
vaiables preceeding the event. Because of large movement in variables before the announcement,
it may be helpful to use the minimum and maximum tools to zoom in on smaller movements ahead
of the event. </p>
<div class="ui-widget inline">
<label for="securities">1. Type in a ticker symbol</label>
<input id="securities">
</div>
<div class="inline"><input type="button" id="reload" value="Reset" class="hide" /></div>
<label for="datepicker">2. Pick your event date of interest.</label>
<input type="text" id="datepicker" disabled />
<label>3. Choose other series to graph.</label>
<p><strong>Primary Axis</strong></p>
Left Axis: <select id="series1" class="selectpicker span2" disabled><option value=""></option></select>
<div id="series1minmax" class="hide">
Min <input type="text" id="min1" class="input-mini" />
Max <input type="text" id="max1" class="input-mini" />
</div><input type="button" id="addaxes1" value="Graph" class="hide" />
<input type="button" id="removeaxes1" value="Remove" class="hide" /><br />
<br/>Right Axis: <select id="series2" class="selectpicker span2" disabled><option value=""></option>></select>
<div id="series2minmax" class="hide">
Min <input type="text" id="min2" class="input-mini" />
Max <input type="text" id="max2" class="input-mini" />
</div><input type="button" id="addaxes2" value="Graph" class="hide" />
<input type="button" id="removeaxes2" value="Remove" class="hide" /><br />
<input type="button" id="addextraaxis" value="Add Additional Axis" disabled/><br />
<div id="additional" class="hide">
<p><strong>Additional Axis</strong></p>
Left Axis: <select id="series3" class="selectpicker span2" disabled><option value=""></option></select>
<div id="series3minmax" class="hide">
Min <input type="text" id="min3" class="input-mini" />
Max <input type="text" id="max3" class="input-mini" />
</div><input type="button" id="addaxes3" value="Graph" class="hide" />
<input type="button" id="removeaxes3" value="Remove" class="hide" /><br />
<br/>Right Axis: <select id="series4" class="selectpicker span2" disabled><option value=""></option>></select>
<div id="series4minmax" class="hide">
Min <input type="text" id="min4" class="input-mini" />
Max <input type="text" id="max4" class="input-mini" />
</div><input type="button" id="addaxes4" value="Graph" class="hide" />
<input type="button" id="removeaxes4" value="Remove" class="hide" /><br />
</div>
</div>
<div id="rightsidebar">
<div id="container" class="hide"></div>
</div>
</div>
<script src="http://code.highcharts.com/stock/highstock.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<script src="http://code.highcharts.com/stock/highcharts-more.js"></script>
<script>
$(function() {
$("#removefromchart").click(function() {
var conceptName = $('#savedseries').find(":selected").remove();
});
$("#reload").click(function() {
location.reload();
})
$("#addextraaxis").click(function() {
$("#additional").removeClass("hide");
this.disabled = true
$("#addextraaxis").addClass("hide");
var chart = $("#container").highcharts();
chart.setSize(null, 650);
})
});
$(function() {
$("#series1").change(function() {
$("#addaxes1").removeClass("hide");
});
$("#series2").change(function() {
$("#addaxes2").removeClass("hide");
});
$("#series3").change(function() {
$("#addaxes3").removeClass("hide");
});
$("#series4").change(function() {
$("#addaxes4").removeClass("hide");
});
});
$(function() {
function setExtreme(isMin, axis, value) {
console.log("fired");
var chart = $('#container').highcharts();
if (isMin) {
console.log(value + " " + chart.yAxis[axis].getExtremes()["max"])
chart.yAxis[axis].setExtremes(value, chart.yAxis[axis].getExtremes()["max"]);
} else {
console.log(value + " " + chart.yAxis[axis].getExtremes()["min"])
chart.yAxis[axis].setExtremes(chart.yAxis[axis].getExtremes()["min"], value);
}
console.log(value);
}
function getAxisNumber(series) {
var indicies = {}
$.each(chart.yAxis, function(index, element) {
indicies[element.options.id] = index;
console.log(element.options.id);
});
return indicies[series]
}
$("#max1").change(function() {setExtreme(0, getAxisNumber("#series1"), this.value)});
$("#min1").change(function() {setExtreme(1, getAxisNumber("#series1"), this.value)});
$("#max2").change(function() {setExtreme(0, getAxisNumber("#series2"), this.value)});
$("#min2").change(function() {setExtreme(1, getAxisNumber("#series2"), this.value)});
$("#max3").change(function() {setExtreme(0, getAxisNumber("#series3"), this.value)});
$("#min3").change(function() {setExtreme(1, getAxisNumber("#series3"), this.value)});
$("#max4").change(function() {setExtreme(0, getAxisNumber("#series4"), this.value)});
$("#min4").change(function() {setExtreme(1, getAxisNumber("#series4"), this.value)});
});
$(function()
{
$("#removefromchart").click(function()
{
var conceptName = $('#savedseries').find(":selected").remove();
});
});
$(function() {
function addPlotLine(ts) {
var chart = $('#container').highcharts();
chart.xAxis[0].addPlotBand({
from: ts,
to: ((ts + 86400000) * 365),
color: 'rgba(68, 170, 213, 0.2)',
id: 'tsband'
});
chart.xAxis[0].addPlotLine({
value: ts,
color: 'rgb(255, 0, 0)',
width: 1,
id: 'tsline'
});
chart.xAxis[0].setExtremes(ts - (86400000 * 30), ts + 86400000)
}
function removeEventIfExists() {
var chart = $("#container").highcharts()
chart.xAxis[0].removePlotBand("tsband");
chart.xAxis[0].removePlotLine("tsline");
}
$("#datepicker").datepicker({
showButtonPanel: true, /*added by oussama*/
changeMonth: true, /*added by oussama*/
changeYear: true, /*added by oussama*/
dateFormat: 'yy-mm-dd',
onSelect: function (dateText, inst) {
utcDate = Date.UTC(dateText.split("-")[0], dateText.split("-")[1] - 1, dateText.split("-")[2]);
removeEventIfExists();
addPlotLine(utcDate);
$("#series1").removeAttr("disabled");
$("#series2").removeAttr("disabled");
$("#series3").removeAttr("disabled");
$("#series4").removeAttr("disabled");
$("#addextraaxis").removeAttr("disabled");
var ticker = $("#securities").val();
var date = $("#datepicker").val();
chart.setTitle({text: ticker + " around " + date});
}
});
});
$(function() {
function createChart() {
var chart = $('#container').highcharts();
var options = {chart: {
renderTo: 'container',
height: 450,
},
events: {
load: function(event) {
this.setExtremes();
}
},
rangeSelector: {
enabled: false,
},
exporting: {
enabled: false,
},
navigator: {
enabled: true,
series: { id: 'navigator' },
},
yAxis: [{
title: {
text: 'Price'
},
height: 150,
}],
},
chart = new Highcharts.StockChart(options);
return chart;
}
$("#securities").autocomplete({
source: "/api/get_securities/",
minLength: 1,
select: function(event, ui) {
var ticker = ui.item.label;
getSeries(ticker);
chart = createChart();
getTimeSeriesData(ticker + "|PX_LAST", 0);
$('#container').show();
$('#datepicker').removeAttr("disabled");
$('#reload').removeClass("hide");
chart.setTitle({text: ticker});
this.disabled = 'disabled';
},
});
});
$(function() {
function removeAxes(id) {
var chart = $('#container').highcharts();
chart.get(id).remove();
}
$("#removeaxes1").click(function() {
console.log("removeaxes1 clicked");
removeAxes("#series1");
$("#removeaxes1").addClass("hide");
$("#series1minmax").addClass("hide");
$("#series1minmax").removeClass("inline");
$("#series1").val("");
$("#min1").val("");
$("#max1").val("");
$("#series1").removeAttr("disabled");
});
$("#removeaxes2").click(function() {
console.log("removeaxes2 clicked");
removeAxes("#series2");
$("#removeaxes2").addClass("hide");
$("#series2minmax").addClass("hide");
$("#series2minmax").removeClass("inline");
$("#series2").val("");
$("#min2").val("");
$("#max2").val("");
$("#series2").removeAttr("disabled");
});
$("#removeaxes3").click(function() {
console.log("removeaxes3 clicked");
removeAxes("#series3");
$("#removeaxes3").addClass("hide");
$("#series3minmax").addClass("hide");
$("#series3minmax").removeClass("inline");
$("#series3").val("");
$("#min3").val("");
$("#max3").val("");
$("#series3").removeAttr("disabled");
});
$("#removeaxes4").click(function() {
console.log("removeaxes4 clicked");
removeAxes("#series4");
$("#removeaxes4").addClass("hide");
$("#series4minmax").addClass("hide");
$("#series4minmax").removeClass("inline");
$("#series4").val("");
$("#min4").val("");
$("#max4").val("");
$("#series4").removeAttr("disabled");
});
function addSeries(id, minMaxId, isOpposite, isAdditional) {
var chart = $('#container').highcharts();
indicies = {}
console.log('climlckedaddaxes');
var series = $(id).val()
var top = 210
if (isAdditional) top = 380
var options = {
title: {
text: series.split("|")[1]
},
top: top,
height: 150,
opposite: isOpposite,
id: id,
offset: -30
}
chart.addAxis(options)
$.each(chart.yAxis, function(index, element) {
indicies[element.options.id] = index;
console.log(element.options.id);
});
getTimeSeriesData(series, indicies[id]);
$(minMaxId).removeClass("hide")
$(minMaxId).addClass("inline")
}
$("#addaxes1").click(function() {
addSeries('#series1', "#series1minmax", false, false);
$("#addaxes1").addClass("hide")
$("#removeaxes1").removeClass("hide")
$("#series1").attr("disabled", "disabled")
});
$("#addaxes2").click(function() {
addSeries('#series2', "#series2minmax", true, false);
$("#addaxes2").addClass("hide")
$("#removeaxes2").removeClass("hide")
$("#series2").attr("disabled", "disabled")
});
$("#addaxes3").click(function() {
addSeries('#series3', "#series3minmax", false, true);
$("#addaxes3").addClass("hide")
$("#removeaxes3").removeClass("hide")
$("#series3").attr("disabled", "disabled")
});
$("#addaxes4").click(function() {
addSeries('#series4', "#series4minmax", true, true);
$("#addaxes4").addClass("hide")
$("#removeaxes4").removeClass("hide")
$("#series4").attr("disabled", "disabled")
});
})
$('#addtochart').click(function() {
var selectedValues = $('#seriesselector').val();
$.each(selectedValues, function(index, value) {
$('#savedseries').append($('<option>', {
value: value,
text: value,
selected: true,
}));
$('#seriesselector option[value="' + value +'"]').remove();
});
});
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
function parseDate(inputdate, value) {
var date = inputdate;
var year = parseInt(date.split("-")[0]);
var month = parseInt(date.split("-")[1]) - 1;
var day = parseInt(date.split("-")[2]);
var outputdate = Date.UTC(year, month, day);
if (year == 2013 && month == 3) {
//console.log(inputdate, outputdate, value);
}
return outputdate;
};
function getTimeSeriesData(seriesName, axis) {
var csrftoken = getCookie('csrftoken');
console.log('csrftoken is :: ' + csrftoken);
$.ajax({ // create an AJAX call...
beforeSend: function(xhr, settings) {
var csrftoken = getCookie('csrftoken');
xhr.setRequestHeader("X-CSRFToken", csrftoken);
},
data: {'seriesName': seriesName }, // get the form data
type: 'POST',
url: '/api/get_time_series_data/',
success: function(response) { // on success..
console.log(response);
var series = {}
series['name'] = response[0]['series_name'];
series['data'] = []
$.each(response, function(index, value) {
series['data'][index] = [
parseDate(response[index]['date'], response[index]['value']),
parseFloat(response[index]['value'])
];
});
series['yAxis'] = axis
series['marker'] = {
enabled : true,
radius : 3
}
var chart = $('#container').highcharts();
chart.addSeries(series);
var nav = chart.get('navigator');
if (axis == 0) nav.setData(series['data']);
}
});
return false;
};
function getSeries(ticker) {
var csrftoken = getCookie('csrftoken');
$.ajax({ // create an AJAX call...
beforeSend: function(xhr, settings) {
var csrftoken = getCookie('csrftoken');
xhr.setRequestHeader("X-CSRFToken", csrftoken);
},
data: {'ticker': ticker }, // get the form data
type: 'POST',
url: '/api/get_series/',
success: function(response) { // on success..
$('#seriesselector').empty()
for (var i = 0; i < response.length; i++) {
if (response[i].value == 'PX_LAST') continue;
$('#series1').append($('<option>', {
value: ticker + "|" + response[i].value,
text: response[i].value
}));
$('#series2').append($('<option>', {
value: ticker + "|" + response[i].value,
text: response[i].value
}));
$('#series3').append($('<option>', {
value: ticker + "|" + response[i].value,
text: response[i].value
}));
$('#series4').append($('<option>', {
value: ticker + "|" + response[i].value,
text: response[i].value
}));
}
}
});
return false;
};
</script>
{% endblock %}
Turns out you need the
{% csrf_token %}
regardless of whether or not you are posting a html form. I was only doing AJAX requests, but Django won't include the token in the response header unless it sees it the template.