doevisualization
Version:
Data Visualization Library based on RequireJS and D3.js (v4+)
359 lines (304 loc) • 14.7 kB
JavaScript
define(['jquery',
'underscore',
'jqueryuiwidget',
'handlebars',
'd3'
],
function($, _, ui, Handlebars, d3) {
$.widget("doe.doefootballfield", {
// Options to be used as defaults
options: {},
_privateData: {},
_template: function() {
var arrHTML = [];
arrHTML.push('<div class="doedivergedbar">');
arrHTML.push('<div class="title">');
arrHTML.push('</div>');
arrHTML.push('<div class="subTitle">');
arrHTML.push('</div>');
arrHTML.push('</div>');
return arrHTML.join('');
},
_create: function() {
this._fetchAndRender();
},
_fetchAndRender: function() {
this._compileTemplate();
},
_compileTemplate: function() {
var compiled = Handlebars.compile(this._template());
this.element.html(compiled({}));
this._compileTooltip();
this._buildVisualization();
this._bindEvents();
},
_compileTooltip: function() {
this._privateData.tooltipCompiled = Handlebars.compile(this.options.TooltipTemplate);
},
_bindEvents: function() {
},
_buildVisualization: function() {
this.element.find('div.title').html(this.options.ChartTitle);
this.element.find('div.subTitle').html(this.options.ChartSubTitle);
console.log("raw data:", this.options.Data);
var groupeddata = _.groupBy(this.options.Data, $.proxy(function(item) {
return item[this.options["Groupings"][0]];
}, this));
console.log("grouped data:", groupeddata);
var groupField = this.options["Groupings"];
var tooltipData = _.chain(this.options.Data)
.groupBy(function(d) { return d[groupField] })
.pairs()
.map(function(currentItem) {
return _.object(_.zip(["groupItem", "values"], currentItem));
})
.value();
console.log("tooltip data:", tooltipData);
for (var k in groupeddata) {
var uniquescope = _.uniq(groupeddata[k], $.proxy(function(x) {
return x[this.options["YFields"][0]];
}, this));
uniquescope = uniquescope.map($.proxy(function(item, index) {
return item[this.options["YFields"][0]];
}, this));
var uniquelabel = _.uniq(groupeddata[k], $.proxy(function(x) {
return x[this.options["XFields"][1]];
}, this));
uniquelabel = uniquelabel.map($.proxy(function(item, index) {
return item[this.options["XFields"][1]];
}, this));
console.log(uniquescope);
var finalobject = [];
var scopeMeetsReqs = [];
_.each(uniquescope, $.proxy(function(item) {
var filtereddata = _.filter(groupeddata[k], $.proxy(function(sitem) {
return sitem[this.options["YFields"][0]] === item;
}, this));
var obj = {};
obj["rows"] = item;
var temp = [];
_.each(filtereddata, $.proxy(function(tem) {
obj[tem[this.options["XFields"][1]]] = tem[this.options["XFields"][0]];
// obj["origdata"] = tem;
temp.push(tem);
}, this));
// if (obj[tem[this.options["XFields"][1]]] == tem[this.options["XFields"][0]]) {
// obj["origdata"] = tem;
// }
obj["origdata"] = temp;
finalobject.push(obj);
}, this));
console.log(finalobject);
console.log(uniquelabel);
this._privateData.finalobject = finalobject;
this._privateData.uniquelabel = uniquelabel;
this._privateData.uniquescope = uniquescope;
this._setupD3Element(k);
}
},
_setupD3Element: function(year) {
var margin = {
top: 80,
right: 20,
bottom: 20,
left: 50
},
width = 590 - margin.left - margin.right,
height = 230 - margin.top - margin.bottom;
var y = d3.scaleBand()
.rangeRound([0, height])
.padding(0.3);
var x = d3.scaleLinear()
.rangeRound([0, width]);
// var xAxis = d3.svg.axis()
// .scale(x)
// .tickFormat(d3.format(",%"))
// .orient("top");
var xAxis = d3.axisBottom(x).tickFormat(function(d) {
if (d === 0) return ''; // No label for '0'
else if (d < 0) d = -d; // No nagative labels
return d * 100 + '%';
});
// var yAxis = d3.svg.axis()
// .scale(y)
// .tickSize(0)
// .orient("left");
var yAxis = d3.axisLeft(y).tickSize(0);
var color = d3.scaleOrdinal()
.range(this.options.ColorPalette);
var svg = d3.select(this.element.find('div.doedivergedbar').get(0)).append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var tooltipcontainer = d3.select(this.element.find('div.doedivergedbar').get(0)).append("div")
.attr("class", "doedivergedbartooltip")
.style("opacity", 0);
this._drawDivergedChart(this._privateData.finalobject, this._privateData.uniquelabel, this._privateData.uniquescope, year, svg, x, y, color, xAxis, yAxis,
height, width, tooltipcontainer);
},
_drawDivergedChart: function(data, uniquelabel, uniquescope, year, svg, x, y, color, xAxis, yAxis, height,
width, tooltipcontainer) {
svg.append("text")
.attr("x", 0)
.attr("y", 0)
.text(year)
.attr("class", "instancetitle")
var rateNames = d3.keys(data[0]).filter(function(key) {
return (key !== "rows" && key !== "origdata");
});
var rowsNames = data.map(function(d) {
return d.rows;
});
var neutralIndex = Math.floor(rateNames.length / 2);
color.domain(rateNames);
data.forEach(function(row) {
row.total = d3.sum(rateNames.map(function(name) {
return +row[name];
}));
rateNames.forEach(function(name) {
row['relative' + name] = (row.total !== 0 ? +row[name] / row.total : 0);
});
var x0 = -1 * d3.sum(rateNames.map(function(name, i) {
return i < neutralIndex ? +row['relative' + name] : 0;
}));
if (rateNames.length & 1) x0 += -1 * row['relative' + rateNames[neutralIndex]] / 2;
var idx = 0;
row.boxes = rateNames.map(function(name) {
return {
name: name,
x0: x0,
x1: x0 += row['relative' + name],
total: row.total,
absolute: row[name],
origdata: row.origdata
};
});
});
var min = d3.min(data, function(d) {
return d.boxes["0"].x0;
});
var max = d3.max(data, function(d) {
return d.boxes[d.boxes.length - 1].x1;
});
x.domain([-1, 1]).nice();
y.domain(rowsNames);
svg.append("g")
.attr("class", "xaxis")
.attr("transform", "translate(0," + (height + 2) + ")")
.call(xAxis);
svg.append("g")
.attr("class", "yaxis")
.call(yAxis);
var rows = svg.selectAll(".row")
.data(data)
.enter().append("g")
.attr("class", "bar")
.attr("transform", function(d) {
return "translate(0," + y(d.rows) + ")";
})
.on("mouseover", function(d) {
svg.selectAll('.y').selectAll('text').filter(function(text) {
return text === d.rows;
})
.transition().duration(5).style('font', '9px');
})
.on("mouseout", function(d) {
svg.selectAll('.y').selectAll('text').filter(function(text) {
return text === d.rows;
})
.transition().duration(5).style('font', '9px');
});
var bars = rows.selectAll("rect")
.data(function(d) {
return d.boxes;
})
.enter().append("g");
bars.append("rect")
.attr("height", y.bandwidth())
.attr("x", function(d) {
return x(d.x0);
})
.attr("width", function(d) {
return x(d.x1) - x(d.x0);
})
.style("fill", function(d) {
return color(d.name);
})
.on("mouseover", $.proxy(function(d, i) {
d3.select(this.element.find(".doedivergedbartooltip").get(0)).transition()
.duration(200)
.style("opacity", .9);
d3.select(this.element.find(".doedivergedbartooltip").get(0)).html(this._privateData.tooltipCompiled(d.origdata[i]))
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px");
}, this))
.on("mouseout", $.proxy(function(d, i) {
d3.select(this.element.find(".doedivergedbartooltip").get(0)).transition()
.duration(500)
.style("opacity", 0);
}, this));
// bars.append("text")
// .attr("x", function (d) {
// return x(d.x0);
// })
// .attr("y", y.bandwidth() / 2)
// .attr("dy", "0.5em")
// .attr("dx", "0.5em")
// .style("text-anchor", "begin")
// .attr("class", "bartext")
// .text(function (d) {
// return d.absolute !== 0 && (d.x1 - d.x0) > 0.04 ? d.absolute : ""
// });
bars.append("text")
.attr("x", function(d) {
return x(d.x0);
})
.attr("y", y.bandwidth() / 2)
.attr("dy", "0.5em")
.attr("dx", "0.5em")
.style("text-anchor", "begin")
.attr("class", "bartext")
.attr("width", "12px")
.attr("height", "12px")
.text(function(d) {
return d.absolute !== 0 && (d.x1 - d.x0) > 0.04 ? d.absolute : ""
});
svg.append("g")
.attr("class", "y axis")
.append("line")
.attr("x1", x(0) + 1)
.attr("x2", x(0) + 1)
.attr("y2", height);
var legend = svg.selectAll(".legend")
.data(rateNames)
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(" + width / rateNames.length * i + ",-55)";
});
legend.append("rect")
.attr("x", 0)
.attr("width", 18)
.attr("height", 18)
.style("fill", color);
legend.append("text")
.attr("x", 22)
.attr("y", 9)
.attr("dy", ".12em")
.attr("class", "legend")
.style("text-anchor", "begin")
.text(function(d) {
return d;
});
},
destroy: function() {
},
_setOption: function(key, value) {
this._super(key, value);
},
_setOptions: function(options) {
this._super(options);
}
});
});