UNPKG

transcend-charts

Version:

Transcend is a charting and graph library for NUVI

431 lines (377 loc) 14.4 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _Numbers = require('../helpers/Numbers'); var _Numbers2 = _interopRequireDefault(_Numbers); var _Charts = require('../helpers/Charts'); var _Charts2 = _interopRequireDefault(_Charts); var _Color = require('./Color'); var _Color2 = _interopRequireDefault(_Color); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var GroupedBarLine = function GroupedBarLine(htmlContainer, graphData, graphOptions, percentOfWidth) { var self = this; var htmlCanvas = null; var data = null; var plotVars = { graphArea: { top: 0, right: 0, bottom: 0, left: 0, width: 0, height: 0 } }; // this var is updated regularly in the render function to ensure it always contains correct data about the size and state of the graph var DEBUG = false; var fullScreenChangeListener; var webkitFullScreenChangeListener; var mozFullScreenChangeListener; var msFullScreenChangeListener; var resizeListener; var isDestroyed = false; var resizeTimer = null; var options = graphOptions; // background and padding if (!options.backgroundColor) { options.backgroundColor = new _Color2.default.Color('transparent'); } else { options.backgroundColor = new _Color2.default.Color(options.backgroundColor); } if (!options.padding) { options.padding = 0; } else { options.padding = parseFloat(options.padding); } // segment spacing if (!options.barSpacing && options.barSpacing !== 0) { options.barSpacing = 1; // as a percent of the width of each bar } else { options.barSpacing = _Numbers2.default.makeNumber(options.barSpacing); } // label font if (!options.barLabelFontColor) { options.barLabelFontColor = new _Color2.default.Color('#ffffff'); } else { options.barLabelFontColor = new _Color2.default.Color(options.barLabelFontColor); } if (!options.barLabelFontFamily) { options.barLabelFontFamily = 'Arial'; } // values floating on top of each bar if (options.showValues === undefined || options.showValues === false) { options.showValues = false; } else { options.showValues = true; } if (!options.valueFontColor) { options.valueFontColor = new _Color2.default.Color('#444444'); } if (!options.valueFontFamily) { options.valueFontFamily = 'Arial'; } if (!options.valueFontWeight) { options.valueFontWeight = '400'; } // stripes on the bars if (!options.barStripeSpacing) { options.barStripeSpacing = 10; } else { options.barStripeSpacing = parseFloat(options.barStripeSpacing); } if (!options.barStripeWidth) { options.barStripeWidth = 2; } else { options.barStripeWidth = parseFloat(options.barStripeWidth); } if (!options.barStripeType) { options.barStripeType = 'none'; } if (['none', 'horizontal', 'vertical', 'diagonal'].indexOf(options.barStripeType) === -1) { options.barStripeType = 'none'; } if (!options.barStripeColor) { options.barStripeColor = new _Color2.default.Color('#666666'); } else { options.barStripeColor = new _Color2.default.Color(options.barStripeColor); } if (!options.barFillColor) { options.barFillColor = new _Color2.default.Color('#666666'); } else { options.barFillColor = new _Color2.default.Color(options.barFillColor); } if (!percentOfWidth) { percentOfWidth = 1; } else if (typeof percentOfWidth === 'string' && percentOfWidth.indexOf('%') !== -1) { percentOfWidth = parseFloat(percentOfWidth) / 100; } else { percentOfWidth = parseFloat(percentOfWidth); } var barLabelSpacing = 8; // the spacing between the labels and the left of the bar var barValueSpacing = 4; // the spacing var pxRatio = window.devicePixelRatio || 1; this.render = function () { if (!data) { return false; } var ctx = htmlCanvas.getContext('2d'); // upscale this thang if the device pixel ratio is higher than 1 var backingStoreRatio = ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; ctx.save(); if (pxRatio > 1) { ctx.scale(pxRatio / backingStoreRatio, pxRatio / backingStoreRatio); } var canvasWidth = htmlCanvas.width / (pxRatio / backingStoreRatio); var canvasHeight = htmlCanvas.height / (pxRatio / backingStoreRatio); // fill background ctx.clearRect(0, 0, canvasWidth, canvasHeight); if (options.backgroundColor.toString() !== 'transparent') { ctx.fillStyle = options.backgroundColor.toString(); ctx.fillRect(0, 0, canvasWidth, canvasHeight); } // calculate grid area plotVars.graphArea = { left: options.padding, top: options.padding, right: options.padding, bottom: options.padding }; plotVars.graphArea.height = canvasHeight - plotVars.graphArea.top - plotVars.graphArea.bottom; var allowedBarHeight = plotVars.graphArea.height / data.length; var barHeight = allowedBarHeight / (1 + options.barSpacing); var barGap = allowedBarHeight - barHeight; var fontSize = barHeight; ctx.font = fontSize + 'px ' + options.barLabelFontFamily; // calculate the width of widest label var widestLabel = _lodash2.default.max(data, function (segment) { return ctx.measureText(segment.name).width; }).name; var widestLabelWidth = ctx.measureText(widestLabel).width; plotVars.graphArea.left = options.padding + widestLabelWidth + barLabelSpacing; plotVars.graphArea.width = canvasWidth - plotVars.graphArea.left - plotVars.graphArea.right; var total = _lodash2.default.sum(data, function (datum) { return datum.value; }); var maxValue = _lodash2.default.max(data, function (datum) { return datum.value; }).value; var maxWidth = plotVars.graphArea.width * percentOfWidth; ctx.textBaseline = 'top'; var somethingIsHighlighted = data.some(function (segment) { return segment.isHighlighted; }); // draw bars for (var i = 0; i < data.length; i++) { // bar var fillColor = options.barFillColor; if (data[i].barFillColor) { fillColor = data[i].barFillColor; } if (somethingIsHighlighted && !data[i].isHighlighted) { fillColor = new _Color2.default.Color(fillColor).fade(0.7); } ctx.fillStyle = fillColor.toString(); var barWidth = data[i].value / maxValue * maxWidth; if (!barWidth) { barWidth = 0.5; } var bar_x = plotVars.graphArea.left; var bar_y = plotVars.graphArea.top + i * allowedBarHeight + barGap / 2; ctx.textAlign = 'left'; data[i].boundingBox = { x: bar_x, y: bar_y, width: barWidth, height: barHeight }; ctx.fillRect(bar_x, bar_y, barWidth, barHeight); // bar value if (options.showValues) { var displayValue = data[i].prefix + data[i].value + data[i].suffix; if (data[i].displayValue) { displayValue = data[i].displayValue; } ctx.fillStyle = options.valueFontColor; var segmentValueWidth = ctx.measureText(displayValue).width; if (segmentValueWidth < barWidth - barValueSpacing * 2) { ctx.textAlign = 'right'; var value_x = plotVars.graphArea.left + barWidth - barValueSpacing; ctx.fillText(displayValue, value_x, bar_y); } else { ctx.fillStyle = new _Color2.default.Color(options.barLabelFontColor).fade(0.3); ctx.textAlign = 'left'; var value_x = plotVars.graphArea.left + barWidth + barValueSpacing; ctx.fillText(displayValue, value_x, bar_y); } } // label on left ctx.font = '300 ' + fontSize + 'px ' + options.barLabelFontFamily; ctx.fillStyle = options.barLabelFontColor.toString(); ctx.textAlign = 'right'; var label_x = plotVars.graphArea.left - barLabelSpacing; ctx.fillText(data[i].name, label_x, bar_y); } ctx.restore(); }; /*** * Initialize some basic vars including the html canvas to render on ***/ function _init() { var _this = this; htmlCanvas = document.createElement('CANVAS'); htmlContainer.appendChild(htmlCanvas); self.setData(graphData); fillParent.call(this); htmlCanvas.addEventListener('mouseout', function (event) { handleMouseOut.call(_this, event); }); htmlCanvas.addEventListener('mousemove', function (event) { var rect = htmlCanvas.getBoundingClientRect(); var pt = { x: event.clientX - rect.left, y: event.clientY - rect.top }; handleMouseMove.call(_this, event, pt); }); htmlCanvas.addEventListener('mouseup', function (event) { var rect = htmlCanvas.getBoundingClientRect(); var pt = { x: event.clientX - rect.left, y: event.clientY - rect.top }; handleMouseUp.call(_this, event, pt); }); resizeListener = window.addEventListener('resize', function () { clearTimeout(resizeTimer); resizeTimer = setTimeout(function () { fillParent.call(_this); }, 50); }); fullScreenChangeListener = window.addEventListener('webkitfullscreenchange', fullscreenChange); webkitFullScreenChangeListener = window.addEventListener('fullscreenchange', fullscreenChange); mozFullScreenChangeListener = window.addEventListener('mozfullscreenchange', fullscreenChange); msFullScreenChangeListener = window.addEventListener('msfullscreenchange', fullscreenChange); function fullscreenChange(event) { var fullscreenElement = document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement; if (!fullscreenElement) { // exiting full screen var targetElement = event.target; // if this element contains a canvas, make it tiny so we don't mess up the size of its parent // don't worry, the window.resize event that fires next will make it fill its parent just fine var canvases = targetElement.getElementsByTagName('CANVAS'); for (var c = 0; c < canvases.length; c++) { if (canvases[c] === htmlCanvas) { canvases[c].width = 1; canvases[c].height = 1; canvases[c].style.width = '1px'; canvases[c].style.height = '1px'; break; } } } } } function handleMouseMove(event, pt) { var oldHighlightedBar = data.find(function (bar) { return bar.isHighlighted; }); var highlightedBar = hitTestBars(pt, function (bar) { bar.isHighlighted = true; }, function (bar) { bar.isHighlighted = false; }); if (highlightedBar !== oldHighlightedBar) { this.render(); } } function handleMouseOut() { var wasSomethingHighlighted = data.some(function (bar) { return bar.isHighlighted; }); data.forEach(function (bar) { bar.isHighlighted = false; }); if (wasSomethingHighlighted) { this.render(); } } function handleMouseUp(event, pt) { var highlightedBar = hitTestBars(pt, null, null); if (highlightedBar && highlightedBar.onClick) { highlightedBar.onClick(event); } } function hitTestBars(pt, onHit, onMiss) { var hoveredBar = null; for (var i = 0; i < data.length; i++) { if (pt.x >= data[i].boundingBox.x && pt.x < data[i].boundingBox.x + data[i].boundingBox.width && pt.y >= data[i].boundingBox.y && pt.y < data[i].boundingBox.y + data[i].boundingBox.height) { hoveredBar = data[i]; if (onHit) { onHit(data[i]); } } else { if (onMiss) { onMiss(data[i]); } } } return hoveredBar; } /*** * Fills the parent container with this canvas element ***/ function fillParent() { if (htmlCanvas && htmlCanvas.parentNode) { var style = window.getComputedStyle(htmlCanvas.parentNode); var width = htmlCanvas.parentNode.offsetWidth - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight); var height = htmlCanvas.parentNode.offsetHeight - parseFloat(style.paddingTop) - parseFloat(style.paddingBottom); // upscale this thang if the device pixel ratio is higher than 1 htmlCanvas.width = width * pxRatio; htmlCanvas.height = height * pxRatio; htmlCanvas.style.width = width + 'px'; htmlCanvas.style.height = height + 'px'; this.render(); } } /*** * This function sets/resets the data for the graph ***/ this.setData = function (someData) { data = someData.slice(); if (data && data.length) { for (var i = 0; i < data.length; i++) { var parts = _Numbers2.default.separateNumberUnits(data[i].value); if (data[i].prefix === undefined) { data[i].prefix = parts.prefix; } if (data[i].suffix === undefined) { data[i].suffix = parts.suffix; } data[i].value = parts.value; if (data[i].barFillColor) { data[i].barFillColor = new _Color2.default.Color(data[i].barFillColor); } if (data[i].barBorderColor) { data[i].barBorderColor = new _Color2.default.Color(data[i].barBorderColor); } if (data[i].barStripeColor) { data[i].barStripeColor = new _Color2.default.Color(data[i].barStripeColor); } } //console.log(data); } }; this.destroy = function () { if (fullScreenChangeListener) { window.removeEventListener('fullscreenchange', fullScreenChangeListener); } if (webkitFullScreenChangeListener) { window.removeEventListener('webkitfullscreenchange', webkitFullScreenChangeListener); } if (mozFullScreenChangeListener) { window.removeEventListener('mozfullscreenchange', mozFullScreenChangeListener); } if (msFullScreenChangeListener) { window.removeEventListener('msfullscreenchange', msFullScreenChangeListener); } if (resizeListener) { window.removeEventListener('resize', resizeListener); } if (htmlCanvas && htmlCanvas.parentNode) { htmlCanvas.parentNode.removeChild(htmlCanvas); } isDestroyed = true; }; // Initialize _init.call(this); }; exports.default = GroupedBarLine;