TreeMap chart

1. TreeMap chart

A TreeMap chart is a sort of interlocking rectangle chart where the size of the individual rectangles are proportional to their values. You can see a flash version on The Guardian website at: http://www.guardian.co.uk/politics/interactive/2010/oct/19/comprehensive-spending-review-cuts

I've started my own version in Ext - see example at:
http://www.stevemcarthur.co.uk/widgets/SpendCuts/

Code:
```/**
*
* @author Steve McArthur
* @class HK.chart.TreeMap
* @extends Ext.draw.Component
* Treemaps display hierarchical (tree-structured) data as a set of nested rectangles.
* Each nested rectangle has an area proportional to a specified dimension on the data.
* See: http://en.wikipedia.org/wiki/Treemapping
* By default this class uses the Squarify algorithmn to calculate the tree map. It is
* based on the open source code written by Martin Cowie and found at: http://js-treemap.sourceforge.net/
*
* Example usage:
<pre><code>

Ext.define("Dept", {
extend : 'Ext.data.Model',
fields : ['id', 'Name', 'Title', {
name : 'Cost',
type : 'float'
}],
hasMany : {
model : 'Savings',
name : 'savings'
}
});

var myStore = Ext.create('Ext.data.ArrayStore', {
autoDestroy : true,
model : 'Dept',
data : [[1, "Corporate, Subsidy, Grant & Levies etc", "Corporate, Subsidy, Grant & Levies etc", 556.23], [2, "Health and Community Services", "Health and Community Services", 171.71], [3, "Children and Young People", "Children and\r\n Young People", 51.87], [4, "Finance and Resources", "Finance and Resources", 47.39], [5, "Legal, HR and Regulatory Services", "Legal, HR and\r\n Regulatory Services", 15.74], [6, "Chief Executive", "Chief Executive", 8.24], [7, "Housing", "Housing", 2]]
});

Ext.create('HK.chart.TreeMap', {
chartWidth: 1000,
chartHeight: 530,
chartX: 0,
chartY: 40,
store: myStore,
renderTo: Ext.getBody()
});
</code></pre>
* @xtype treemap
*
*/

Ext.define('HK.chart.TreeMap', {
extend: 'Ext.draw.Component',
alternateClassName: 'TreeMap',
requires: ['HK.chart.Squarify', 'HK.chart.TreeMapSprite'],
type: 'treemap',
store: {},
nodes: [],
sprites: [],
startTotal: 0,
textThreshold: 5,
inheritableStatics: {
TreeMapEngine: {
'squarify': HK.chart.Squarify
}
},
setOpacity: function(cmp, op, speed, callback) {
var duration = speed || 500;
if (!callback) {
callback = Ext.emptyFn;
}
// cmp.stopAnimation();
return cmp.animate({
to: {
opacity: op
},
duration: duration,
callback: callback
});
},
setSpriteOpacity: function(op, cmp, speed, arr) {
var me = this;
var items = arr || me.sprites;
var op2 = op === 1 ? 0 : 1;
me.hoverTitle.setAttributes({
text: cmp.text,
opacity: op2
}, true);
Ext.each(items, function(item, idx, all) {
if (item.id != cmp.id) {
item.stopAnimation();
me.setOpacity(item, op, speed);
if (item.title && !item.title.hidden) {
item.title.stopAnimation();
item.subTitle.stopAnimation();
me.setOpacity(item.title, op, speed);
me.setOpacity(item.subTitle, op, speed);

}
}
});
},
/**
* Creates new TreeMap.
* @param {Object} config Config object.
*/
constructor: function(config) {
var me = this;
me.store = config.store;

var defaults = {
viewBox: false,
autoShow: true,
width: config.chartWidth + 50,
height: config.chartHeight + 70,
x: 0,
y: 0,
renderTo: Ext.get('div1'),
engine: 'squarify'
};
config = Ext.apply(defaults, config);

me.callParent([config]);
var engine = TreeMap.TreeMapEngine[this.engine];

me.nodes = engine.create(me.store, config.chartX, config.chartY, config.chartWidth, config.chartHeight);
me.startTotal = HK.chart.Squarify.getTotal(me.nodes);
TreeMapSprite.surface = me.surface;

me.hoverTitle = Ext.create('Ext.draw.Sprite', {
type: 'text',
"text-anchor": "end",
"text": "hoverTitle",
opacity: 0,
font: 'bold 14px Arial',
fill: '#666666',
x: 950,
y: this.chartY + this.chartHeight + 20
});
},

show: function() {
var me = this;
var l = me.nodes.length;
var nodes = me.nodes;
for (var i = 0; i < l; i++) {
var rec = nodes[i];
var clr = Ext.draw.Color.fromString(rec.col);
//this will be the fade out color
var clr2 = clr.getLighter(0.4);
var width = rec.coords.width;
var height = rec.coords.height;
var txtX = rec.coords.x + 10;
var txtY = rec.coords.y + 20;

var text = "£" + rec.Cost;
text = rec.Cost < 150 ? text + "bn" : text + " billion";
var textSize = "25px";
var hidden = false;
if (rec.Cost < 150 && rec.Cost > 40) {
textSize = "20px";
} else if (rec.Cost < 41) {
textSize = "16px";
}
if (rec.Cost < this.textThreshold) {
hidden = true;
}

var cfg = {
x: rec.coords.x,
y: rec.coords.y,
width: width,
height: height,
startFill: clr2.toString(),
fill: rec.col,
costs: rec.Cost,
text: rec.Title + " " + text,
titleTxt: rec.Title,
itemNo: i,
hidden: false,
opacity: 0,
treeMap: me,
title: Ext.create('Ext.draw.Sprite', {
type: 'text',
"text-anchor": "left",
"text": text,
font: '500 ' + textSize + ' "Times New Roman",Georgia,Serif',
fill: '#FFFFFF',
// surface: this.surface,
hidden: hidden,
x: txtX,
y: txtY,
zIndex: 10
}),
subTitle: Ext.create('Ext.draw.Sprite', {
type: 'text',
"text-anchor": "left",
"text": rec.Name,
font: 'bold 12px Arial',
fill: '#FFFFFF',
hidden: hidden,
// surface: this.surface,
x: txtX,
y: txtY + 20,
zIndex: 10
})
};

var item = Ext.create('HK.chart.TreeMapSprite', cfg);
me.sprites.push(item);

}

Ext.each(me.sprites, function(sp, idx) {
to: {
opacity: 1
},
duration: 1000,
easing: 'easeIn'
});

});
me.showBorder();
},
showBorder: function() {
var me = this;
if (!me.chartBorder) {
me.chartBorder = Ext.create('Ext.draw.Sprite', {
type: 'rect',
width: me.chartWidth,
height: me.chartHeight,
x: me.chartX,
y: me.chartY,
stroke: '#000000',
"stroke-opacity": 1,
"stroke-width": 3,
fill: 'none',
opacity: 1,
zIndex: 9999
});
}
me.chartBorder.show(true);
}
})```
TreeMap.jpg
One of the main differences with the Guardian chart is that mine recalculates it size after changes are made.

Just looking for feedback really.

2. Thank you for the contribution.

Scott.

3. Simple TreeMap Example

Hi all

I've now added a more simple example of a TreeMap chart at: http://www.stevemcarthur.co.uk/widge...sicTreeMap.htm.

Planning to do an example in conjunction with either a plain html table or Ext Grid where they user can change the values

4. I've now added some additional animation to get it to work like the Guardian version with the rectangles moving in from the edge of the page. At the moment, this is hard coded into the extension as I'm not sure how to generate the direction based on the data. Have a look again:
http://www.stevemcarthur.co.uk/widge...sicTreeMap.htm

5. Hi Steve,

I need a TreeMap in my current project. It seems that all links that you provided in this thread are no longer valid. Is your TreeMap plugin still available?

Mikhail

6. TreeMap

Hi Steve,

The links you have provided in the above thread seems to be no longer valid I request you to please send us the new link to your website for our reference and study on it.

Manish Sharma

7. Still getting hits on this so I've re-uploaded the page to: http://www.stevemcarthur.co.uk/widgets/SpendCuts/BasicTreeMap.htm

Also uploaded a zip file of the webpage and resources to:
http://www.stevemcarthur.co.uk/widge...ts/TreeMap.zip

8. Recommended way to integrate

Hi Steve, your work looks really great!

I would like to use a treemap chart as well in a Ext 5.x project but I wonder what is the best way to integrate it. Is there a user extension build somewhere, should I generate one myself or should I just include the files in resources folder then require it?

Any advice would be very apreciated, thanks!