Kendo TreeList is Not Refreshing with flat Data - django

I am using the Kendo TreeList. I have a data structure in the database using an Adjacency List data structure using Django TreeBeard. For the treelist, since the data is nested, I create flat objects and put them into an array. This works, fine but the treelist doesn't refresh with the data.
The object structure is the same as the one for the parent but the children don't show.
Here is my code.
JSON: PARENT NODE
{"id": 26, "tgtWeight": 0.0, "currWeight": 0.0, "hasChildnode": true, "ext_model_id": 8, "parent": null, "SSM": {"id": 8, "securitySelectionModelName": "ssm8", "userCreatedModel": "[{\"classificationName\":\"ssm8\",\"id\":8,\"hasChildNode\":true,\"child\":[{\"classificationName\":\"MBS\",\"id\":14,\"hasChildNode\":true,\"child\":[{\"classificationName\":\"Common Stock\",\"id\":15,\"hasChildNode\":false}]}]}]", "classificationNames": []}, "classificationNameNode": null}
JSON CHILD NODE
[{"id": 27, "tgtWeight": 0.0, "currWeight": 0.0, "hasChildnode": true, "ext_model_id": 14, "parent": {"id": 26, "tgtWeight": 0.0, "currWeight": 0.0, "hasChildnode": true, "ext_model_id": 8, "parent": null, "SSM": 8, "classificationNameNode": null}, "SSM": {"id": 8, "securitySelectionModelName": "ssm8", "userCreatedModel": "[{\"classificationName\":\"ssm8\",\"id\":8,\"hasChildNode\":true,\"child\":[{\"classificationName\":\"MBS\",\"id\":14,\"hasChildNode\":true,\"child\":[{\"classificationName\":\"Common Stock\",\"id\":15,\"hasChildNode\":false}]}]}]", "classificationNames": []}, "classificationNameNode": {"id": 14, "classificationLevel": 2, "classificationName": "MBS", "hasChildNode": false, "parent": 2}}]
JAVASCRIPT
$(document).ready(function () {
var id = {{ id }};
var dataSource = new kendo.data.TreeListDataSource({
transport: {
read: {
url: "../getModelTargetWeights?SSM_id="+id,
dataType: "json"
}
},
schema: {
parse: function(response) {
NodeArray=[];
if (response.length == undefined) {
var node = {
id: response.id,
currWeight: response.currWeight,
tgtWeight: response.tgtWeight,
hasChildren: response.hasChildnode,
parentId: response.parent,
ext_model_id: response.ext_model_id,
securitySelectionModelName: response.SSM.securitySelectionModelName,
classificationNameNode: response.classificationNameNode
};
NodeArray.push(node);
} else {
for (var i=0; i < response.length; i++){
var node = {
id: response[i].id,
currWeight: response[i].currWeight,
tgtWeight: response[i].tgtWeight,
hasChildren: response[i].hasChildnode,
parentId: response[i].parent.ext_model_id,
ext_model_id: response[i].ext_model_id,
securitySelectionModelName: response[i].SSM.securitySelectionModelName,
classificationNameNode: response[i].classificationNameNode.classificationName
}
NodeArray.push(node);
}
}
return NodeArray;
},
model: {
id: "id",
parentId: "parentId",
fields: {
parentId: { field: "parentId", nullable: true },
securitySelectionModelName: "securitySelectionModelName",
classificationNameNode: "classificationNameNode",
tgtWeight: { field: "tgtWeight", nullable: true },
hasChildren: { type: "boolean", field: "hasChildren" }
}
}
}
});
$("#treeList").kendoTreeList({
dataSource: dataSource,
editable: true,
height: 540,
columns: [
{ field: "securitySelectionModelName", title: "Model Name" },
{ field: "classificationNameNode", title: "Classification" },
{ field: "tgtWeight", title: "Target" }
],
});
dataSource.read();
});
</script>

Related

Chartjs: how to remove datapoint info from label?

I'm trying to remove a dataset from label:
But the label callback is called twice, so i don't know how to do it.
I was expecting an array in the callback and that you can simply remove the one not needed.
here's what i have so far and tried:
var labels = [];
for (let index = 0; index < 12; index++) {
labels.push(index);
}
window.onload = function () {
var canvas = document.getElementById('elm-chart'),
ctx = canvas.getContext('2d');
var myLineChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [
{
label: '-15',
data: [
{
x: 0,
y: 10,
},
{
x: 1,
y: 20,
},
],
borderColor: 'red',
},
{
label: '15',
data: [
{
x: 1,
y: 20,
},
{
x: 2,
y: 30,
},
],
borderColor: 'blue',
},
{
label: '25',
data: [
{
x: 2,
y: 30,
},
{
x: 3,
y: 35,
},
],
borderColor: 'yellow',
},
{
label: '-15',
data: [
{
x: 6,
y: -10,
},
{
x: 7,
y: -20,
},
],
borderColor: 'red',
},
{
label: '15',
data: [
{
x: 7,
y: -20,
},
{
x: 8,
y: -30,
},
],
borderColor: 'blue',
},
{
label: '25',
data: [
{
x: 8,
y: -30,
},
{
x: 9,
y: -35,
},
],
borderColor: 'yellow',
},
],
},
options: {
responsive: true,
plugins: {
legend: {
onClick: (evt, legendItem, legend) => {
let newVal = !legendItem.hidden;
legend.chart.data.datasets.forEach((dataset) => {
if (dataset.label === legendItem.text) {
dataset.hidden = newVal;
}
});
legend.chart.update();
},
labels: {
filter: (legendItem, chartData) => {
let entries = chartData.datasets.map((e) => e.label);
return entries.indexOf(legendItem.text) === legendItem.datasetIndex;
},
},
},
},
scales: {
x: {
type: 'linear',
ticks: {
stepSize: 30,
},
},
},
plugins: {
tooltip: {
callbacks: {
title: function (context) {
return [`test`, 'test2'];
},
label: function (context) {
console.log(context.dataset.label);
console.log(context.formattedValue);
console.log(context);
return [
`${context.dataset.label}:${context.formattedValue}`,
'test',
];
},
},
},
},
},
});
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.2.1/chart.min.js"></script>
<canvas id="elm-chart" width="640" height="480"></canvas>
So to be clear i don't want to remove the datapoint in the dataset. I just want to remove 1 datapoint from the label, the top one always
What you can do is instead of using the default tooltip instead use a html tooltip.
In the JS that makes the tooltip instead of looping over each active item you only take the first one and display that.
Official sample of html tooltip: https://www.chartjs.org/docs/master/samples/tooltip/html.html

Sort documents by date and group by type

I don't know how to write map/reduce functions to get all film genres sorted by date of the latest film.
async function test() {
const db = new PouchDB("film")
const docs = [
{ _id: "1", title: "Rambo", year: 2008, genre: "Action" },
{ _id: "2", title: "Forrest Gump", year: 1994, genre: "Drama" },
{ _id: "3", title: "Gladiator", year: 2000, genre: "Action" },
{ _id: "4", title: "The Mask", year: 1994, genre: "Comedy" }
]
await db.bulkDocs(docs)
const fan = {
map(doc) {
emit([doc.year, doc.genre])
},
reduce(keys, values, rereduce) {
return values
}
}
const result = await db.query(fan, { group: true })
result.rows.forEach(r => console.log(r))
}
Returns:
{key: [1994, "Comedy"], value: [null]}
{key: [1994, "Drama"], value: [null]}
{key: [2000, "Action"], value: [null]}
{key: [2008, "Action"], value: [null]}
I would probably invert the order of the fields indexed.
Here's some examples:
async function test() {
const db = new PouchDB("film");
const docs = [
{ _id: "1", title: "Rambo", year: 2008, genre: "Action" },
{ _id: "2", title: "Forrest Gump", year: 1994, genre: "Drama" },
{ _id: "3", title: "Gladiator", year: 2000, genre: "Action" },
{ _id: "4", title: "The Mask", year: 1994, genre: "Comedy" }
];
await db.bulkDocs(docs);
const fan = {
map: function(doc) {
emit([doc.genre, doc.year])
},
reduce: '_count'
};
// Get the view output
const result = await db.query(fan, {
reduce: false,
include_docs: true
})
// Get a certain group
const actionFilms = await db.query(fan, {
startkey: ["Action"],
endkey: ["Action", {}],
reduce: false,
include_docs: true
});
// Get the list of groups
const genres = await db.query(fan, {
group: true,
group_level: 1
});
// Get the most recent value of a group
const lastActionFilm = await db.query(fan, {
startkey: ["Action", {}],
endkey: ["Action"],
reduce: false,
descending: true,
limit: 1,
include_docs: true
});
result.rows.forEach(r => console.log(r))
}

Chart.js - displaying multiple line charts using multiple labels

I need to draw a chart with 2 lines using Chart.js.
Each of this line has a different label set.
i.e.
Chart 1:
1 -> 2
2 -> 4
3 -> 8
4 -> 16
Chart 2:
1 -> 3
3 -> 4
4 -> 6
6 -> 9
This following sample obviously does not work as it uses the labels from chart1. But is it possible to realize this with Chart.js?
var config = {
type: 'line',
data: {
labels: [1,2,3,4,5],
datasets: [{
label: 'Chart 1',
data: [2,4,8,16],
}, {
label: 'Chart 2',
data: [3,4,6,9],
}]
},
Other charting libs offers a (label/data) set as parameter so I could simply give a tupel as parameter
(ie. [(1->2),(2->4),(3->8)...]
for each chart and the lib will match everything.
Thanks
Edit: Detailed sample as requested:
var config = {
type: 'line',
data: {
labels: [1, 2, 3, 4, 5],
datasets: [{
label: 'Chart 1',
data: [2, 4, 8, 16],
}, {
label: 'Chart 2',
data: [3, 4, 6, 9],
}]
},
options: {
spanGaps: true,
responsive: true,
title: {
display: true,
text: 'Chart.js Line Chart'
},
tooltips: {
mode: 'index',
intersect: false,
},
hover: {
mode: 'nearest',
intersect: true
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Labels'
}
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Values'
},
ticks: {
min: 1,
max: 10,
}
}]
}
}
};
window.onload = function() {
var ctx = document.getElementById('canvas').getContext('2d');
window.myLine = new Chart(ctx, config);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<div style="width:90%;" class="container">
<canvas id="canvas"></canvas><br>
</div>
Use scatter type chart and showLine: true instead of line type with labels:
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'scatter',
data: {
datasets: [
{
label: 'Chart 1',
data: [{x: 1, y: 2}, {x: 2, y: 4}, {x: 3, y: 8},{x: 4, y: 16}],
showLine: true,
fill: false,
borderColor: 'rgba(0, 200, 0, 1)'
},
{
label: 'Chart 2',
data: [{x: 1, y: 3}, {x: 3, y: 4}, {x: 4, y: 6}, {x: 6, y: 9}],
showLine: true,
fill: false,
borderColor: 'rgba(200, 0, 0, 1)'
}
]
},
options: {
tooltips: {
mode: 'index',
intersect: false,
},
hover: {
mode: 'nearest',
intersect: true
},
scales: {
yAxes: [{
ticks: {
beginAtZero:true
}
}]
},
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="myChart"></canvas>
What this code does is, it displays multi line graph using chart.js
Create a class for your labeling x and y values
//DataContract for Serializing Data - required to serve in JSON format
[DataContract]
public class LabelPoint
{
//Explicitly setting the name to be used while serializing to JSON.
[DataMember(Name = "label")]
public string Label { get; set; }
public DataPoint DataPoint { get; set; }
}
[DataContract]
public class DataPoint
{
[DataMember(Name = "x")]
public List<string> X { get; set; }
//Explicitly setting the name to be used while serializing to JSON.
[DataMember(Name = "y")]
public List<string> Y { get; set; }
}
Controller code to retrieve data
List<LabelPoint> dataPoints = GetProducts.ToList()
.GroupBy(p => p.ProductName,
(k, c) => new LabelPoint()
{
DataPoint = new DataPoint { X = c.Select(y => y.Date.ToString("dd/MM/yyyy HH:mm")).ToList(), Y = c.Select(cs => cs.Quantity).ToList() },
Label = k
}
).ToList();
ViewBag.DataPoints = dataPoints;
cshtml code to display chart and retrieve data
<canvas id="myChart"></canvas>
<script>
$(document).ready(function () {
// Get the data from the controller using viewbag
// so the data looks something like this [ { Label : "ABC" , DataPoint :[ { X: '222' , Y :60 } ] } ]
var data = #Html.Raw(Json.Encode(ViewBag.DataPoints));
// declare empty array
var dataSet = []; var qty= []; var dates= [];
// loop through the data and get the Label as well as get the created dates and qty for the array of object
for (var i = 0; i < data.length; i++) {
qty.push(data[i].DataPoint.Y);
for (var d = 0; d < data[i].DataPoint.X.length; d++) {
// we're setting this on the X- axis as the label so we need to make sure that we get all the dates between searched dates
dates.push(data[i].DataPoint.X[d]);
}
// we create an array of object, set the Lable which will display LocationName, The data here is the Quantity
dataSet.push(
{
label: data[i].Label,
data: data[i].DataPoint.Y,
fill: false,
borderColor: poolColors(qtyInLocations.length),
pointBorderColor: "black",
pointBackgroundColor: "white",
lineTension: 0.1
}
);
}
// this is the options to set the Actual label like Date And Quantity
var options = {
scales: {
xAxes: [{
scaleLabel: {
display: true,
labelString: "Date",
fontSize: 20
},
}],
yAxes: [{
ticks: {
beginAtZero:true
},
scaleLabel: {
display: true,
labelString: 'Quantity',
fontSize: 20
}
}]
}
};
// we need to remove all duplicate values from the CreatedDate array
var uniq = [ ...new Set(dates) ];
// get the canvas
var ctx = document.getElementById("myChart").getContext('2d');
// build the chart
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: uniq,
datasets:dataSet
},
options: options
});
});
/// will get get random colors each time
function dynamicColors() {
var r = Math.floor(Math.random() * 255);
var g = Math.floor(Math.random() * 255);
var b = Math.floor(Math.random() * 255);
return "rgba(" + r + "," + g + "," + b + ", 0.5)";
}
/// will display random colors each time
function poolColors(a) {
var pool = [];
for(i = 0; i < a; i++) {
pool.push(dynamicColors());
}
return pool;
}
</script>

how to show lines separately without overlapping when values are same

Working on google charts API (Line chart).I have same set of values which are used to draw lines for server and shipping, as the values are same two lines are overlapping as shown in the demo https://plnkr.co/edit/PNA1XQapRzvxGfm7behd?p=preview
Is there a way where we can see two lines instead of overlapping when they have the same values?
angular.module('myApp', ['googlechart'])
.controller('myController', function($scope) {
var chart1 = {};
chart1.type = "LineChart";
chart1.displayed = false;
chart1.data = {
"cols": [{
id: "month",
label: "Month",
type: "string"
}, {
id: "laptop-id",
label: "Laptop",
type: "number"
}, {
id: "desktop-id",
label: "Desktop",
type: "number"
}, {
id: "server-id",
label: "Server",
type: "number"
}, {
id: "cost-id",
label: "Shipping",
type: "number"
}],
"rows": [{
c: [{
v: "January"
}, {
v: 19,
}, {
v: 12,
}, {
v: 7, //server
}, {
v: 7 //shipping
}]
}, {
c: [{
v: "February"
}, {
v: 13
}, {
v: 1,
}, {
v: 12 //server
}, {
v: 12 //shipping
}]
}, {
c: [{
v: "March"
}, {
v: 24
}, {
v: 5
}, {
v: 11 //server
}, {
v: 11 //shipping
}
]
}]
};
chart1.options = {
"title": "Sales per month",
"colors": ['#0000FF', '#009900', '#CC0000', '#DD9900'],
"defaultColors": ['#0000FF', '#009900', '#CC0000', '#DD9900'],
"isStacked": "percent",
focusTarget: 'category',
"fill": 20,
"displayExactValues": true,
"vAxis": {
"title": "Sales unit",
"gridlines": {
"count": 10
}
},
"hAxis": {
"title": "Date"
}
};
chart1.view = {
columns: [0, 1, 2, 3, 4]
};
$scope.myChart = chart1;
});
use the series chart option to set pointSize on a specific series
the following will change the server series in the example provided...
series: {
2: {
pointSize: 8
}
}
see forked plnker...

List paging from json

I am finaly able to retrieve my datas from the json file BUT the paging system still sucks. The pageSize property seems not to respond therefore when i press on the load more plugin text that appears at the bottom of my list, it appends all my json elements to my list everytime. I am confident about the fact that i am almost there but i can't see how to make it happen.
Here is the code:
Ext.setup({
tabletStartupScreen: 'tablet_startup.png',
phoneStartupScreen: 'phone_startup.png',
icon: 'icon.png',
glossOnIcon: false,
onReady : function() {
var dataLink;
if (Ext.is.Desktop) {
dataLink = "http://127.0.0.1/Appsfan-v2";
} else {
dataLink = "http://appsfan.kreactive.eu";
}
Ext.regModel('Profile', {
fields: [
{name: 'firstname', type: 'string'},
{name: 'lastname', type: 'string'},
{name: 'age', type: 'number'}
]
});
var store = new Ext.data.JsonStore({
model: 'Profile',
autoLoad: false,
remoteFilter: true,
sortOnFilter: true,
//sorters: [{property : 'lastname', direction: 'ASC'}],
pageSize: 1,
clearOnPageLoad: false,
proxy: {
type: 'ajax',
url: dataLink+'/data.json',
reader: {
root: 'profile',
type: 'tree'
}
}
});
console.log(store)
//console.log(store.loadPage(0))
var groupingBase = new Ext.List({
fullscreen: true,
itemTpl: '<div class="contact2"><strong>{firstname}</strong> {lastname} -> {age}</div>',
indexBar: false,
store: store,
plugins: [{
ptype: 'listpaging',
autoPaging: false
}]
});
var panel = new Ext.Panel({
layout: 'card',
fullscreen: true,
items: [groupingBase],
dockedItems: [{
xtype: 'toolbar',
title: 'paging example',
}]
})
//console.log(datas)
}
});
The json
{
"profile": [{
"firstname": "firstname1",
"lastname": "lastname1",
"age": "1"
},{
"firstname": "firstname2",
"lastname": "lastname2",
"age": "2"
},{
"firstname": "firstname3",
"lastname": "lastname3",
"age": "3"
}]
}
Thank you
You can set the clearOnPageLoad config option in your store. This will remove previous records when the next page of the paginated data is loaded.
Here is an example:
Ext.regStore('BarginsStore', {
model: 'BarginModel',
autoLoad: false,
pageSize: 6,
clearOnPageLoad: false,
});