JSFiddle - React, Tailwind, and code Playground
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.2.1/backbone-min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/heatmap.js"></script>
<script src="https://code.highcharts.com/modules/treemap.js"></script>
<p>Highcharts Treemap with custom breadcrumb navigation built using Backbone.js</p>
<h4>Days of Month with ganache instead of frosting</h4>
<h5>Data from: Georgetown Cupcake secret flavors (December 2013 - November 2014)</h5>
<div id="breadcrumbs">Top Level</div>
<div id="treemap-container"></div>
JavaScript
// ----- Backbone Models and Views -----
var TreemapModel = Backbone.Model.extend({
// holds treemap data and a selected_point state value
select_point: function (point_id) {
this.set({
'selected_point': this.find_point(point_id)
});
},
find_point: function (point_id) {
return _.find(this.get('data'), function (point) {
return point.id == point_id;
});
},
});
var BreadcrumbModel = Backbone.Model.extend({
// maintains a list of breadcrumb points
initialize: function () {
this.reset();
},
reset: function () {
this.set({
'crumbs': []
})
},
add_point: function (point) {
// Backbone won't trigger a 'change' event if we use push
// because the underlying array is the same, but concat
// creates & returns a new array
this.set({
'crumbs': this.get('crumbs').concat(point)
});
},
rewind_to: function (id) {
// rewinds crumbs so the given id is the leaf node
var new_crumbs = [],
found = false;
_.each(this.get('crumbs'), function (crumb) {
if (!found) {
new_crumbs.push(crumb);
if (crumb.id == id) {
found = true;
}
}
});
this.set({
'crumbs': new_crumbs
});
},
is_leaf: function (point) {
// returns true if given point is the leaf node of the crumbs
var last = _.last(this.get('crumbs'));
return (last && last.id == point.id);
}
});
var TreemapView = Backbone.View.extend({
// view for managing treemap itself
initialize: function (options) {
_.bindAll(this,
'drill_to_point',
'render');
this.model.bind('change:selected_point', this.drill_to_point);
// normally you'd want to bind render to the model change:data
// event...