123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
- /* ------------------------------------------------------------------------------
- *
- * # D3.js - horizontal bar chart
- *
- * Demo d3.js horizontal bar chart setup with .csv data source
- *
- * ---------------------------------------------------------------------------- */
- // Setup module
- // ------------------------------
- var DashboardAreas = function() {
- //
- // Setup module components
- //
- // Monthly sales area chart
- var _MonthlySalesAreaChart = function(element, height, color) {
- if (typeof d3 == 'undefined') {
- console.warn('Warning - d3.min.js is not loaded.');
- return;
- }
- // Initialize chart only if element exsists in the DOM
- if($(element).length > 0) {
- // Basic setup
- // ------------------------------
- // Define main variables
- var d3Container = d3.select(element),
- margin = {top: 20, right: 35, bottom: 40, left: 35},
- width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right,
- height = height - margin.top - margin.bottom;
- // Date and time format
- var parseDate = d3.time.format('%Y-%m-%d').parse,
- bisectDate = d3.bisector(function(d) { return d.date; }).left,
- formatDate = d3.time.format('%b %d');
- // Create SVG
- // ------------------------------
- // Container
- var container = d3Container.append('svg');
- // SVG element
- var svg = container
- .attr('width', width + margin.left + margin.right)
- .attr('height', height + margin.top + margin.bottom)
- .append('g')
- .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
- // Construct chart layout
- // ------------------------------
- // Area
- var area = d3.svg.area()
- .x(function(d) { return x(d.date); })
- .y0(height)
- .y1(function(d) { return y(d.value); })
- .interpolate('monotone')
- // Construct scales
- // ------------------------------
- // Horizontal
- var x = d3.time.scale().range([0, width ]);
- // Vertical
- var y = d3.scale.linear().range([height, 0]);
- // Create axes
- // ------------------------------
- // Horizontal
- var xAxis = d3.svg.axis()
- .scale(x)
- .orient('bottom')
- .ticks(d3.time.days, 6)
- .innerTickSize(4)
- .tickPadding(8)
- .tickFormat(d3.time.format('%b %d'));
- // Load data
- // ------------------------------
- d3.json('../../../../global_assets/demo_data/dashboard/monthly_sales.json', function (error, data) {
- // Show what's wrong if error
- if (error) return console.error(error);
- // Pull out values
- data.forEach(function (d) {
- d.date = parseDate(d.date);
- d.value = +d.value;
- });
- // Get the maximum value in the given array
- var maxY = d3.max(data, function(d) { return d.value; });
- // Reset start data for animation
- var startData = data.map(function(datum) {
- return {
- date: datum.date,
- value: 0
- };
- });
- // Set input domains
- // ------------------------------
- // Horizontal
- x.domain(d3.extent(data, function(d, i) { return d.date; }));
- // Vertical
- y.domain([0, d3.max( data, function(d) { return d.value; })]);
- //
- // Append chart elements
- //
- // Append axes
- // -------------------------
- // Horizontal
- var horizontalAxis = svg.append('g')
- .attr('class', 'd3-axis d3-axis-horizontal')
- .attr('transform', 'translate(0,' + height + ')')
- .call(xAxis);
- // Add extra subticks for hidden hours
- horizontalAxis.selectAll('.d3-axis-subticks')
- .data(x.ticks(d3.time.days), function(d) { return d; })
- .enter()
- .append('line')
- .attr('class', 'd3-axis-subticks')
- .attr('y1', 0)
- .attr('y2', 4)
- .attr('x1', x)
- .attr('x2', x);
- // Append area
- // -------------------------
- // Add area path
- svg.append('path')
- .datum(data)
- .attr('class', 'd3-area')
- .attr('d', area)
- .style('fill', color)
- .transition() // begin animation
- .duration(1000)
- .attrTween('d', function() {
- var interpolator = d3.interpolateArray(startData, data);
- return function (t) {
- return area(interpolator (t));
- }
- });
- // Append crosshair and tooltip
- // -------------------------
- //
- // Line
- //
- // Line group
- var focusLine = svg.append('g')
- .style('display', 'none');
- // Line element
- focusLine.append('line')
- .attr('class', 'vertical-crosshair d3-crosshair-line')
- .attr('y1', 0)
- .attr('y2', -maxY);
- //
- // Pointer
- //
- // Pointer group
- var focusPointer = svg.append('g')
- .attr('class', 'd3-crosshair-pointer')
- .style('display', 'none');
- // Pointer element
- focusPointer.append('circle')
- .attr('class', 'd3-line-circle')
- .attr('r', 3)
- .style('stroke', color)
- .style('stroke-width', 1.5);
- //
- // Text
- //
- // Text group
- var focusText = svg.append('g')
- .attr('class', 'd3-crosshair-text')
- .style('display', 'none');
- // Text element
- focusText.append('text')
- .attr('class', 'd3-text')
- .attr('dy', -10)
- .style('font-size', 12);
- //
- // Overlay with events
- //
- svg.append('rect')
- .attr('class', 'd3-crosshair-overlay')
- .style('fill', 'none')
- .style('pointer-events', 'all')
- .attr('width', width)
- .attr('height', height)
- .on('mouseover', function() {
- focusPointer.style('display', null);
- focusLine.style('display', null)
- focusText.style('display', null);
- })
- .on('mouseout', function() {
- focusPointer.style('display', 'none');
- focusLine.style('display', 'none');
- focusText.style('display', 'none');
- })
- .on('mousemove', mousemove);
- // Display tooltip on mousemove
- function mousemove() {
- // Define main variables
- var mouse = d3.mouse(this),
- mousex = mouse[0],
- mousey = mouse[1],
- x0 = x.invert(mousex),
- i = bisectDate(data, x0),
- d0 = data[i - 1],
- d1 = data[i],
- d = x0 - d0.date > d1.date - x0 ? d1 : d0;
- // Move line
- focusLine.attr('transform', 'translate(' + x(d.date) + ',' + height + ')');
- // Move pointer
- focusPointer.attr('transform', 'translate(' + x(d.date) + ',' + y(d.value) + ')');
- // Reverse tooltip at the end point
- if(mousex >= (d3Container.node().getBoundingClientRect().width - focusText.select('text').node().getBoundingClientRect().width - margin.right - margin.left)) {
- focusText.select('text').attr('text-anchor', 'end').attr('x', function () { return (x(d.date) - 15) + 'px' }).text(formatDate(d.date) + ' - ' + d.value + ' sales');
- }
- else {
- focusText.select('text').attr('text-anchor', 'start').attr('x', function () { return (x(d.date) + 15) + 'px' }).text(formatDate(d.date) + ' - ' + d.value + ' sales');
- }
- }
- // Resize chart
- // ------------------------------
- // Call function on window resize
- window.addEventListener('resize', monthlySalesAreaResize);
- // Call function on sidebar width change
- var sidebarToggle = document.querySelector('.sidebar-control');
- sidebarToggle && sidebarToggle.addEventListener('click', monthlySalesAreaResize);
- // Resize function
- //
- // Since D3 doesn't support SVG resize by default,
- // we need to manually specify parts of the graph that need to
- // be updated on window resize
- function monthlySalesAreaResize() {
- // Layout variables
- width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right;
- // Layout
- // -------------------------
- // Main svg width
- container.attr('width', width + margin.left + margin.right);
- // Width of appended group
- svg.attr('width', width + margin.left + margin.right);
- // Axes
- // -------------------------
- // Horizontal range
- x.range([0, width]);
- // Horizontal axis
- svg.selectAll('.d3-axis-horizontal').call(xAxis);
- // Horizontal axis subticks
- svg.selectAll('.d3-axis-subticks').attr('x1', x).attr('x2', x);
- // Chart elements
- // -------------------------
- // Area path
- svg.selectAll('.d3-area').datum(data).attr('d', area);
- // Crosshair
- svg.selectAll('.d3-crosshair-overlay').attr('width', width);
- }
- });
- }
- };
- // Messages area chart
- var _MessagesAreaChart = function(element, height, color) {
- if (typeof d3 == 'undefined') {
- console.warn('Warning - d3.min.js is not loaded.');
- return;
- }
- // Initialize chart only if element exsists in the DOM
- if($(element).length > 0) {
- // Basic setup
- // ------------------------------
- // Define main variables
- var d3Container = d3.select(element),
- margin = {top: 0, right: 0, bottom: 0, left: 0},
- width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right,
- height = height - margin.top - margin.bottom;
- // Date and time format
- var parseDate = d3.time.format('%Y-%m-%d').parse;
- // Create SVG
- // ------------------------------
- // Container
- var container = d3Container.append('svg');
- // SVG element
- var svg = container
- .attr('width', width + margin.left + margin.right)
- .attr('height', height + margin.top + margin.bottom)
- .append('g')
- .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
- // Construct chart layout
- // ------------------------------
- // Area
- var area = d3.svg.area()
- .x(function(d) { return x(d.date); })
- .y0(height)
- .y1(function(d) { return y(d.value); })
- .interpolate('monotone')
- // Construct scales
- // ------------------------------
- // Horizontal
- var x = d3.time.scale().range([0, width ]);
- // Vertical
- var y = d3.scale.linear().range([height, 0]);
- // Load data
- // ------------------------------
- d3.json('../../../../global_assets/demo_data/dashboard/monthly_sales.json', function (error, data) {
- // Show what's wrong if error
- if (error) return console.error(error);
- // Pull out values
- data.forEach(function (d) {
- d.date = parseDate(d.date);
- d.value = +d.value;
- });
- // Get the maximum value in the given array
- var maxY = d3.max(data, function(d) { return d.value; });
- // Reset start data for animation
- var startData = data.map(function(datum) {
- return {
- date: datum.date,
- value: 0
- };
- });
- // Set input domains
- // ------------------------------
- // Horizontal
- x.domain(d3.extent(data, function(d, i) { return d.date; }));
- // Vertical
- y.domain([0, d3.max( data, function(d) { return d.value; })]);
- //
- // Append chart elements
- //
- // Add area path
- svg.append('path')
- .datum(data)
- .attr('class', 'd3-area')
- .style('fill', color)
- .attr('d', area)
- .transition() // begin animation
- .duration(1000)
- .attrTween('d', function() {
- var interpolator = d3.interpolateArray(startData, data);
- return function (t) {
- return area(interpolator (t));
- }
- });
- // Resize chart
- // ------------------------------
- // Call function on window resize
- window.addEventListener('resize', messagesAreaResize);
- // Call function on sidebar width change
- var sidebarToggle = document.querySelector('.sidebar-control');
- sidebarToggle && sidebarToggle.addEventListener('click', messagesAreaResize);
- // Resize function
- //
- // Since D3 doesn't support SVG resize by default,
- // we need to manually specify parts of the graph that need to
- // be updated on window resize
- function messagesAreaResize() {
- // Layout variables
- width = d3Container.node().getBoundingClientRect().width - margin.left - margin.right;
- // Layout
- // -------------------------
- // Main svg width
- container.attr('width', width + margin.left + margin.right);
- // Width of appended group
- svg.attr('width', width + margin.left + margin.right);
- // Horizontal range
- x.range([0, width]);
- // Chart elements
- // -------------------------
- // Area path
- svg.selectAll('.d3-area').datum( data ).attr('d', area);
- }
- });
- }
- };
- //
- // Return objects assigned to module
- //
- return {
- init: function() {
- _MonthlySalesAreaChart('#monthly-sales-stats', 100, '#4DB6AC');
- _MessagesAreaChart('#messages-stats', 40, '#5C6BC0');
- }
- }
- }();
- // Initialize module
- // ------------------------------
- document.addEventListener('DOMContentLoaded', function() {
- DashboardAreas.init();
- });
|