Problems using json recursive in treemap using D3PLUS - javascript

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.

Related

Triggering an event from a custom formatter

I want to generate a table from a JSON objects array. Each object represents an application and has 4 properties: name, package, versions, and users.
name and package are textual, and users is numeric. versions, however, is an array of arrays: each internal array contains a version name and a version code. Here is a sample JSON:
[{
"name": "Angry Birds",
"package": "oldgames",
"versions": [
["alpha", 0.1],
["beta", 0.2],
["release", 1]
],
"users": 800
},
{
"name": "Temple Run",
"package": "oldgames",
"versions": [
["beta", 0.7],
["release", 2]
],
"users": 130
},
{
"name": "Snake",
"package": "veryoldgames",
"versions": [
["release", 0]
],
"users": 2
}]
The table requirements are as follows:
There should be 4 columns corresponding to the mentioned properties: Name, Package, Version (singular), and Users.
The Version column should contain a dropdown (an HTML select), with each option referring to a specific version. In addition, each dropdown contains an "All" option to refer to all the versions of the app.
The text of each option is the version name, and the value is the version code.
When a specific version is selected, an external function is called and returns the number of users that uses this specific version. Then, the row's Users cell is updated with the new number.
(I know it's a bit convoluted, and that there are probably better ways to visualize the data, but right now this is the architecture I have to implement and I can't change it)
To create the dropdown, I tried using the built-in List editor. I soon found out this is the wrong approach since the List editor is constructed with predefined values - identical values ​​for each and every row in the table, while I need every row to have a unique dropdown.
After researching a bit, I realized I needed to use a Custom Formatter. I take the versions array and manually construct a select. Here is a demo:
const data = [
{
"name": "Angry Birds",
"package": "oldgames",
"versions": [["alpha", 0.1], ["beta", 0.2], ["release", 1]],
"users": 800
},
{
"name": "Temple Run",
"package": "oldgames",
"versions": [["beta", 0.7], ["release", 2]],
"users": 130
},
{
"name": "Snake",
"package": "veryoldgames",
"versions": [["release", 0]],
"users": 2
}
];
new Tabulator("#example-table", {
data: data,
layout: "fitColumns",
height: 107,
columns: [
{
title: "Name",
field: "name",
},
{
title: "Package",
field: "package"
},
{
title: "Versions",
field: "versions",
formatter: function (cell, formatterParams, onRendered) {
const select = document.createElement("select");
const options = select.options;
options.add(new Option("all", "all"));
const value = cell.getValue();
for (let i = 0; i < value.length; i++) {
options.add(new Option(value[i][0], value[i][1]));
}
return select;
}
},
{
title: "Users",
field: "users"
}
],
});
<script src="https://unpkg.com/tabulator-tables/dist/js/tabulator.min.js"></script>
<link href="https://unpkg.com/tabulator-tables/dist/css/tabulator.min.css" rel="stylesheet"/>
<div id="example-table"></div>
The data is displayed properly. Initially, I planned to bind a change event listener to the select, but the documentation recommends not doing that:
...it is a bad idea to try to use code outside of Tabulator to
directly alter or bind events to DOM elements inside the table,
because there is a good chance that the element you are trying to
manipulate will be destroyed on the next scroll.
Instead, the documentation recommends using its predefined events:
Tabulator has a wide range of callbacks, formatters and other
functions that allow you to manipulate the table contents in a way
that is safe and won't be affected by the rows being recreated.
The closest event I could find is cellEditing. However, I don't know how to trigger it when the value of the select changes.
What is the recommended way to implement these requirements?

Making a gogocartojs map work in js project

I created a project and I'm trying to add gogocartoJs in it.
The project works but the map is not showing.
I tried with the guides I found in the site, it looks plain and easy, but there is an step that I'm not understanding (please dont just copy/paste a piece of the site like it was obvious what it is the mistake, because it is not for me)
<html lang="en">
<head>
<link
rel="stylesheet"
href="https://gogocarto.fr/assets/css/gogocarto.min.css"
/>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<script type="text/javascript" src="./jquery.js"></script>
<script src="https://gogocarto.fr/js/gogocarto.min.js"></script>
<title>Hello Webpack</title>
</head>
<body>
<div>
<h1>Hello Webpack</h1>
<div id="gogocarto"></div>
</div>
<script>
$(document).ready(function() {
carto = goGoCarto("#gogocarto", {
data: {
taxonomy: taxonomy,
elements: elements
}
});
});
</script>
<script src="./bundle.js"></script>
</body>
</html>
I expect the map to show, and it doesnt
I added the project to github to show better
https://github.com/Aredros/testGogo/tree/master/dist
elements & taxonomy are js variables containing data you must provide according to the format described in the documentation.
// taxonomy
let taxonomy = {
"options":[
{
"id": "eu1",
"name":"Belgium",
"color":"#9acd32",
"icon":"fa-solid fa-building"
},
{
"id": "eu2",
"name": "Netherland",
"color": "#ffa500",
"icon": "fa-solid fa-fan"
},
{
"id": "eu3",
"name": "Luxembourg",
"color": "#a52a2a",
"icon": "fa-solid fa-money-bill-1"
}
]
}
The only missing info in the documentation is the id key in the taxonomy which must be referenced in your elements source dataset.
// elements
let elements = [
{
"title": "Brussels",
"geo": {
"latitude":50.84,
"longitude":4.34
},
"taxonomy": [ "eu1" ],
},
{
"title": "Namur",
"geo": {
"latitude":50.45,
"longitude":4.88
},
"taxonomy": [ "eu1" ],
},
{
"title": "Liege",
"geo": {
"latitude":50.62,
"longitude":5.60
},
"taxonomy": [ "eu1" ],
},
{
"title": "Rotterdam",
"geo": {
"latitude":51.88,
"longitude":4.51
},
"taxonomy": [ "eu2" ],
},
{
"title": "Amsterdam",
"geo": {
"latitude":52.07,
"longitude":5.12
},
"taxonomy": [ "eu2" ],
},
]
Idealy you should build an API returning taxonomy classification & elements data. Then perform ajax call in your html page.
$.ajax({
type: 'GET',
url: '/ajax/url_to_get_elements',
dataType: 'json',
success: function(elements, status) {
build_map(elements);
}
});
// build map = function with 1 arguments (elements) where you put the call to goGoCarto and options...
You can define more than 1 taxonomy group (Example above is about English countries) with the name you want => Cfr. Advanced Taxonomy with Categories. Your elements can then have multiple taxonomy reference listed [ "eu1", "week22", 14 ]. Items in the list can be Integer or String. The only important thing is the ID key and the taxonomy order! Keep the same order in your taxonomy than in your key "taxonomy": in your elements data sources!
Point of attention
Because the library is highly configurable with options, colors and icons it is important to put all your <scripts> tags inside <head> tags of your html page!

How to autofit Kendo TreeList column onExpand & onCollapse?

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>

Remove x-axis and y-axis from Zingchart

I want to completely remove, not hide, the x and y-axis in my Zingcharts. I have a graph that does not need an x or y axis, and although I can hide them, they are taking up valuable space, which results in a compressed graph. Is there anyway to do this?
Sounds like you may be setting scales to visible: false, but there is still a lot of space around the chart where these items used to be.
You can eliminate this space by setting items to visible:false, setting associated line-color attributes to "none" and adding:
"plotarea":{
"margin":"0 0"
}
to your JSON. Below is an example with this spacing removed using the method described above. Click the "run code snippet" button to see the resulting chart.
var myConfig = {
"type": "line",
"scale-x":{
"line-color":"none",
"item":{
"visible":false
},
"tick":{
"line-color":"none"
}
},
"scale-y":{
"line-color":"none",
"item":{
"visible":false
},
"tick":{
"line-color":"none"
}
},
"plotarea":{
"margin":"0 0"
},
"series": [
{
"values":[20,40,25,50,15,45,33,34]
},
{
"values":[5,30,21,18,59,50,28,33]
},
{
"values":[30,5,18,21,33,41,29,15]
},
]
};
zingchart.render({
id : 'myChart',
data : myConfig,
height: 400,
width: 600
});
<html>
<head>
<!--Assets will be injected here on compile. Use the assets button above-->
<script src= 'https://cdn.zingchart.com/2.1.2/zingchart.min.js'></script>
<script> zingchart.MODULESDIR = 'https://cdn.zingchart.com/2.1.2/modules/';</script>
<!--Inject End-->
</head>
<body>
<div id='myChart'></div>
</body>
</html>
If you're setting scales to visible:false, that may create some issues. Instead, adjusting the styling so they are simply not seen can prevent conflicts with other functionality. I'm on the ZingChart team, so please let me know if this answers your question or if you would like additional clarification.

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