How to autofit Kendo TreeList column onExpand & onCollapse? - javascript

I have a Kendo TreeList. The collapse event is bound to an onCollapse() method, the expand event is bound to an onExpand() method.
In words: the first column consists of levels. The default level is 0 and is expanded as default and shows (all of it's children) all rows of level 1. When expanding a level 1 row, its children (level 2) are shown. At the same time, the column has to stretch a bit (to show the next level number). When expanding another level 1 row, the column does not need to stretch but when a row of level 2 is expanded, the first column has to stretch again for showing level 3 and so on.
Therefore, I use treeList.autoFitColumn(0). This causes an auto fit after every second expand whenever I expand rows of same level (that is not what I expect because expanding same level means the column did grow after the first expand but not after the second expand.
An alternative could be changing the width manually, but I cannot find something like treeList.columns[0].setWidth(x).

The behavior you are seeing is happening because the collapse and expand events are firing before the width of the content has actually changed.
What you can do to circumvent this is to "delay" the auto-fit until after the current code finished running. You do this by using setTimeout with a 0 timeout. This places the execution of the function inside the setTimeout at the end of the execution queue.
See the snippet for a demo.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Kendo UI Snippet</title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.3.911/styles/kendo.common.min.css"/>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.3.911/styles/kendo.rtl.min.css"/>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.3.911/styles/kendo.silver.min.css"/>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2018.3.911/styles/kendo.mobile.all.min.css"/>
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2018.3.911/js/kendo.all.min.js"></script>
</head>
<body>
<div id="treeList"></div>
<script>
$("#treeList").kendoTreeList({
resizable: true,
columns: [
{ field: "Name" },
{ field: "Text" }
],
dataSource: [
{ id: 1, Name: "Name 1", Text: "Sample text 1", parentId: null },
{ id: 2, Name: "Name 2", Text: "Sample text 2", parentId: null },
{ id: 3, Name: "Name 3", Text: "Sample text 3", parentId: 1 },
{ id: 4, Name: "Very long name 4", Text: "Sample text 4", parentId: 2 }
],
expand: function(e) {
setTimeout(() => treeList.autoFitColumn(0), 0);
},
collapse: function(e) {
setTimeout(() => treeList.autoFitColumn(0), 0);
}
});
var treeList = $("#treeList").data("kendoTreeList");
treeList.autoFitColumn(0);
</script>
</body>
</html>

Related

How to include custom data into vis.js timeline item

I have been using vis.js timeline to keep items in a time order.
I use the following to add timeline items :
timeline_items.add({
id : entity_id + uuidv4(),
group : "timeline_video_group_id",
start : start_date,
end : end_date,
content : "<img src='" + element_src_link + "'></img>",
className : 'imagecontainer'
});
However, I cannot add any custom data into this add function.
How may I add custom data, so it may hold information such as entity-uuid=xxxx inside the div below ?
<div class="vis-item vis-range imagecontainer vis-editable" style="transform...">
<div class="vis-item-overflow">
<div class="vis-item-content" style="transform: translateX(0px);">
<img src="image_src">
</div>
<div class="vis-item-visible-frame">
</div>
</div>
</div>
You can update the content to the full HTML you would like, including an image and text, then store this in the DataSet. The vis.js example named 'Custom Styling' here uses this approach.
content: '<div>Mail from boss</div><img src="../resources/img/mail-icon.png" style="width:32px; height:32px;">',
Alternatively you could add custom data to the items in the DataSet, then use the template feature described in the documentation here to construct the HTML. This is the approach I would use.
An example of a template is incorporated into the post below and also at https://jsfiddle.net/xm95u40f/. The example adds a property named imageColor to each item in the DataSet, this is used in combination with the text from the content to display the item. You could store and use your entity-uuid value in a similar way.
// DOM element where the Timeline will be attached
var container = document.getElementById("visualization");
// Create a DataSet (allows two way data-binding)
var items = new vis.DataSet();
items.add([
{ id: 1, content: "item 1", start: "2021-12-21", end: "2021-12-23", imageColor: "0000FF" },
{ id: 2, content: "item 2", start: "2021-12-14", end: "2021-12-17", imageColor: "FFFFFF" },
{ id: 3, content: "item 3", start: "2021-12-18", end: "2021-12-20", imageColor: "0000FF" },
{ id: 4, content: "item 4", start: "2021-12-16", end: "2021-12-21", imageColor: "FFFFFF" },
{ id: 5, content: "item 5", start: "2021-12-25", end: "2021-12-27", imageColor: "000000" },
{ id: 6, content: "item 6", start: "2021-12-27", end: "2021-12-28", imageColor: "008000" },
]);
// Configuration for the Timeline
var options = {
// Define a template function which constructions the HTML for each item
template: function (item, element, data) {
var html = "<img class='timeline-image' src='https://via.placeholder.com/40/" + item.imageColor + "'><div>" + item.content + "</div>"
return html;
},
// Using a template requires any attributes to be whitelisted to prevent XSS
// More details at https://github.com/visjs/vis-timeline/pull/1010
xss: {
disabled: false,
filterOptions: {
whiteList: { img: ['src', 'class'], div: 'class' }
},
},
};
// Create a Timeline
var timeline = new vis.Timeline(container, items, options);
body,
html {
font-family: sans-serif;
}
/*
Timeline image is defined with a fixed height and width.
When the timeline loads it determines the size of items
then uses this to place them, as the images won't be
loaded at this point the size must be set to ensure the
spacing is correct
*/
.timeline-image {
height: 40px;
width: 40px
}
<script src="https://visjs.github.io/vis-timeline/standalone/umd/vis-timeline-graph2d.min.js"></script>
<link href="https://visjs.github.io/vis-timeline/styles/vis-timeline-graph2d.min.css" rel="stylesheet"/>
<div id="visualization"></div>

Tabulator , Is there a way of adding sum of page to the footer?

Tabulator have a module named Column Calculations.
I need to add both sum of page and sum of total
I can add footer for calculate sum of total for example, but I can't add sum of visible rows or in another words sum of current page only in same time.
I can add a footer to bottom or top of the table : topCalc& bottomCalc .
For example I can add sum of price.
As you can see in the example below , I added sum of price here.
Also I put the example here : https://jsfiddle.net/o2ycm5dp/
function generateTable(data) {
tableInstance = new Tabulator("#simpleTable", {
layout: "fitColumns",
resizableColumns: false,
selectable: false,
paginationSize: 3,
responsiveLayout: "hide",
ajaxFiltering: false,
pagination: "local",
columns: [{
title: "name",
field: "name",
},
{
title: "price",
field: "price",
bottomCalc: "sum",
},
],
});
tableInstance.setData(data);
}
$(document).ready(function() {
var data = [{
name: "Tiger Nixon",
price: "320800"
}, {
name: "Garrett Winters",
price: "170750"
}, {
name: "Ashton Cox",
price: "86000"
}, {
name: "Cedric Kelly",
price: "433060"
}, {
name: "Airi Satou",
price: "162700"
}, {
name: "Brielle Williamson",
price: "372000"
}, {
name: "Herrod Chandler",
price: "137500"
}];
generateTable(data);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://unpkg.com/tabulator-tables#4.5.3/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/tabulator-tables#4.5.3/dist/js/tabulator.min.js"></script>
<div id="simpleTable"></div>
On this line : bottomCalc: "sum", , calculation function will called and we can see the sum of price column.
There is an option named Custom Calculations which I can add a function to calculate only current page values, but I can't have the calculation of total pages values.
Another solution maybe append an html element to the footer but I don't think it could be a good solution. Because I should handle all those functions related to Tabulator footer.
Tabulator does not have the ability to layout the table as you request. you would need to manually create a footer element to handle this, and then use the Pagination Callbacks to work out the values to show

Fancytree is open and how are all selected by default?

My fancytree looks like the following. It is running but i want to add some features, first page load all checkbox is selected and all tree opened. How can i do it?
$("#definition-tree").fancytree({
checkbox: true,
selectMode: 3,
icons: false,
source: convertData(#Html.Raw(ViewBag.ResumeSettingDefinitions)),
select: function (event, data) {
var selNodes = data.tree.getSelectedNodes();
var selKeys = $.map(selNodes,
function (node) {
return parseInt(node.key);
});
selectedResumeSettingDefinitionsId = selKeys;
},
click: function (event, data) {
if ($.ui.fancytree.getEventTargetType(event.originalEvent) == "title") {
data.node.toggleExpanded();
data.node.render();
}
},
keydown: function (event, data) {
if (event.which === 32) {
data.node.toggleSelected();
return false;
}
}
});
I've found two ways to expand all tree nodes. To select all nodes I've found only one.
In my answer I'll be using the code from your jsfiddle-link.
OPTION 1
Use expanded:true on a per-node-basis during initialization, meaning you'd have to add that option to every node that is expandable:
$(function(){
$("#tree").fancytree({
checkbox: true,
source: [
{title:"Node 1"},
{title:"Node 2"},
{title:"Folder 3", folder:true, expanded:true, children: [
{title:"Node 3.1"},
{title:"Node 3.2"}
]},
{title:"Folder 2", folder:true}
]
});
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery.fancytree/2.27.0/skin-win8/ui.fancytree.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery.fancytree/dist/jquery.fancytree-all-deps.min.js"></script>
<div id="tree"></div>
In theory this would have my preference, because you wouldn't need an extra function to accomplish your goal. The downside of this is of course that you would have to add the option for every expandable node, and since I haven't found an option to select all nodes during initialization, you would still need an extra function for that anyway.
So with that in mind, my practical preference goes to option 2.
OPTION 2
Use an extra function after initialization, to both expand and select all nodes in the tree:
$("#tree").fancytree("getTree").visit(function(node) {
node.setExpanded(true);
node.setSelected(true);
});
$(function(){
$("#tree").fancytree({
checkbox: true,
source: [
{title:"Node 1"},
{title:"Node 2"},
{title:"Folder 3", folder:true, children: [
{title:"Node 3.1"},
{title:"Node 3.2"}
]},
{title:"Folder 2", folder:true}
]
});
$("#tree").fancytree("getTree").visit(function(node) {
node.setExpanded(true);
node.setSelected(true);
});
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery.fancytree/2.27.0/skin-win8/ui.fancytree.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery.fancytree/dist/jquery.fancytree-all-deps.min.js"></script>
<div id="tree"></div>
jsfiddle: http://jsfiddle.net/sturLzes/
Sources:
https://github.com/mar10/fancytree
http://wwwendt.de/tech/fancytree/doc/jsdoc/
http://wwwendt.de/tech/fancytree/demo/sample-api.html
http://wwwendt.de/tech/fancytree/demo/sample-select.html

Problems using json recursive in treemap using D3PLUS

I'm using the D3PlUS JS library (http://d3plus.org/) and I need to implement a treemap chart with a json recursive structure. I could just to do a first level treemap chart, but I couldn't do mack my code to be multilevel.
example.json
[
{
"id":"First cell",
"value": 10,
"child":
[
{
"id":"Child first cel",
"value": 10,
"child":[]
}
]
},
{
"id":"Second cell",
"value": 90,
"child":
[
{
"id":"Child second cell 1",
"value": 10,
"child":[]
},
{
"id":"Child second cell 2",
"value": 20,
"child":[]
},{
"id":"Child second cell 3",
"value": 10,
"child":[]
}
]
}
]
<!doctype html>
<meta charset="utf-8">
<link href="http://d3plus.org/css/d3plus.css" media="screen" rel="stylesheet" type="text/css" />
<script src="http://d3plus.org/js/d3.js"></script>
<script src="http://d3plus.org/js/d3.geo.tile.js"></script>
<script src="http://d3plus.org/js/topojson.js"></script>
<script src="http://d3plus.org/js/modernizr.js"></script>
<script src="http://d3plus.org/js/d3plus.js"></script>
<!-- create container element for visualization -->
<div id="viz"></div>
<script>
// instantiate d3plus
var visualization = d3plus.viz()
.container("#viz") // container DIV to hold the visualization
.data("data/exemple.json")
.type("tree_map") // visualization type
.id("id") // key for which our data is unique on
.size("value") // sizing of blocks
.draw() // finally, draw the visualization!
</script>
Anybody can help me?
Two modifications were necessary:
changing the data to what is expected by the chart, paying special attention to getting the IDs right (see docs). This was the trickiest part.
nesting the ids in the config param, in accordance with the data: .id(["id","cid"])
Here is a complete working PLUNK.
EDIT: Per OP request, I added one more level to the treemap. It is important to keep the id hierarchy, so now the config param is: .id(["id","cid","gid"]). Also, make sure to remove the value field in the json file for all records that have children...otherwise, D3plus will consider that as part of the values to display with the children.

Getting most basic Backgrid.js example working

I am trying to get the most basic example of backgrid.js to work. In other words, an example where i can drop the source folder into my xampp/htdocs folder and run without having to do anything else.
I have tried many ways to get the code to run but i cannot get anything to show up.
Here is the html page i made to try to see an example working.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="bootstrap/css/bootstrap.css"/>
<link rel="stylesheet" href="lib/backgrid.css"/>
<script src="jquery-1.10.2.min.js"></script>
<script src="underscore-min.js"></script>
<script src="backbone-min.js"></script>
<script src="lib/backgrid.js"></script>
</head>
<body>
<div id="grid">
<script type="text/javascript">
var Territory = Backbone.Model.extend({});
var Territories = Backbone.Collection.extend({
model: Territory,
url: "territories.json"
});
var territories = new Territories();
var columns = [{
name: "id", // The key of the model attribute
label: "ID", // The name to display in the header
editable: false, // By default every cell in a column is editable, but *ID* shouldn't be
// Defines a cell type, and ID is displayed as an integer without the ',' separating 1000s.
cell: Backgrid.IntegerCell.extend({
orderSeparator: ''
})
}, {
name: "name",
label: "Name",
// The cell type can be a reference of a Backgrid.Cell subclass, any Backgrid.Cell subclass instances like *id* above, or a string
cell: "string" // This is converted to "StringCell" and a corresponding class in the Backgrid package namespace is looked up
}, {
name: "pop",
label: "Population",
cell: "integer" // An integer cell is a number cell that displays humanized integers
}, {
name: "percentage",
label: "% of World Population",
cell: "number" // A cell type for floating point value, defaults to have a precision 2 decimal numbers
}, {
name: "date",
label: "Date",
cell: "date"
}, {
name: "url",
label: "URL",
cell: "uri" // Renders the value in an HTML anchor element
}];
// Initialize a new Grid instance
var grid = new Backgrid.Grid({
columns: columns,
collection: territories
});
// Render the grid and attach the root to your HTML document
$("#example-1-result").append(grid.render().el);
// Fetch some countries from the url
territories.fetch({reset: true});
</script>
</div>
</body>
</html>
Thanks for your time!
You seem to be adding the grid to non-existing element:
$("#example-1-result").append(grid.render().el);
Use $("#grid") instead and you should see the result.

Categories