// o---------------------------------------------------------------------------------o // | This file is part of the RGraph package - you can learn more at: | // | | // | https://www.rgraph.net/license.html | // | | // | RGraph is dual-licensed under the Open Source GPL license. That means that it's | // | free to use and there are no restrictions on what you can use RGraph for! | // | If the GPL license does not suit you however, then there's an inexpensive | // | commercial license option available. See the URL above for more details. | // o---------------------------------------------------------------------------------o RGraph = window.RGraph || {isrgraph:true,isRGraph:true,rgraph:true}; RGraph.SVG = RGraph.SVG || {}; // Module pattern (function (win, doc, undefined) { RGraph.SVG.Bipolar = function (conf) { // // A setter that the constructor uses (at the end) // to set all of the properties // // @param string name The name of the property to set // @param string value The value to set the property to // this.set = function (name, value) { if (arguments.length === 1 && typeof name === 'object') { for (i in arguments[0]) { if (typeof i === 'string') { name = ret.name; value = ret.value; this.set(name, value); } } } else { // Go through all of the properties and make sure // that they're using the correct capitalisation name = this.properties_lowercase_map[name.toLowerCase()] || name; var ret = RGraph.SVG.commonSetter({ object: this, name: name, value: value }); name = ret.name; value = ret.value; this.properties[name] = value; // If setting the colors, update the originalColors // property too if (name === 'colors') { this.originalColors = RGraph.SVG.arrayClone(value); this.colorsParsed = false; } } return this; }; // // A getter. // // @param name string The name of the property to get // this.get = function (name) { // Go through all of the properties and make sure // that they're using the correct capitalisation name = this.properties_lowercase_map[name.toLowerCase()] || name; return this.properties[name]; }; this.type = 'bipolar'; this.id = conf.id; this.uid = RGraph.SVG.createUID(); this.container = document.getElementById(this.id); this.layers = {}; // MUST be before the SVG tag is created! this.svg = RGraph.SVG.createSVG({object: this,container: this.container}); this.svgAllGroup = RGraph.SVG.createAllGroup(this); this.clipid = null; // Used to clip the canvas this.isRGraph = true; this.isrgraph = true; this.rgraph = true; this.data = [conf.left, conf.right]; this.left = conf.left; this.right = conf.right; this.coords = []; this.coordsLeft = []; this.coordsRight = []; this.coords2 = []; this.coords2Left = []; this.coords2Right = []; this.stackedBackfacesLeft = []; this.stackedBackfacesRight = []; this.originalColors = {}; this.gradientCounter = 1; this.sequentialIndex = 0; // Used for tooltips this.firstDraw = true; // After the first draw this will be false // // Convert strings to numbers // this.data[0] = RGraph.SVG.stringsToNumbers(this.data[0]); this.data[1] = RGraph.SVG.stringsToNumbers(this.data[1]); this.left = RGraph.SVG.stringsToNumbers(this.left); this.right = RGraph.SVG.stringsToNumbers(this.right); // // Make the .data_arr variable (All data in a linear array) // this.data_arr = []; for (var i=0; i this.scale.max) { return null; } if (value < this.scale.min) { return null; } width = ((value - this.scale.min) / (this.scale.max - this.scale.min)); width *= this.graphWidth; // Calculate the X coord var x = properties.marginLeft + this.graphWidth - width; return x; }; // // This function gets an X coordinate for the RIGHT // side. // // @param int value The value to get the coordinate for. // this.getRightXCoord = function (value) { var width; if (value > this.scale.max) { return null; } if (value < this.scale.min) { return null; } width = ((value - this.scale.min) / (this.scale.max - this.scale.min)); width *= this.graphWidth; // Calculate the X coord var x = properties.marginLeft + this.graphWidth + properties.marginCenter + width; return x; }; // // This function can be used to highlight a bar on the chart // // @param object rect The rectangle to highlight // this.highlight = function (rect) { var x = parseFloat(rect.getAttribute('x')) - 0.5, y = parseFloat(rect.getAttribute('y')) - 0.5, width = parseFloat(rect.getAttribute('width')) + 1, height = parseFloat(rect.getAttribute('height')) + 1; var highlight = RGraph.SVG.create({ svg: this.svg, parent: this.svgAllGroup, type: 'rect', attr: { 'stroke-width': properties.highlightLinewidth, stroke: properties.highlightStroke, fill: properties.highlightFill, x: x, y: y, width: width, height: height }, style: { pointerEvents: 'none' } }); // Store the highlight rect in the rebistry so // it can be cleared later RGraph.SVG.REG.set('highlight', highlight); }; // // This allows for easy specification of gradients // this.parseColors = function () { // Save the original colors so that they can be restored when // the canvas is cleared if (!Object.keys(this.originalColors).length) { this.originalColors = { colors: RGraph.SVG.arrayClone(properties.colors), backgroundGridColor: RGraph.SVG.arrayClone(properties.backgroundGridColor), highlightFill: RGraph.SVG.arrayClone(properties.highlightFill), backgroundColor: RGraph.SVG.arrayClone(properties.backgroundColor) } } // colors var colors = properties.colors; if (colors) { for (var i=0; i= startFrames_left[seq]) { var isNull = RGraph.SVG.isNull(obj.left[i]); // Regular bars if (typeof obj.left[i] === 'number') { obj.left[i] = Math.min( Math.abs(original_left[i]), Math.abs(original_left[i] * ( (counters_left[i]++) / framesperbar)) ); var rect_left = obj.coords[seq].element; rect_left.setAttribute( 'width', parseFloat(rect_left.getAttribute('data-original-width')) * (obj.left[i] / rect_left.getAttribute('data-value')) ); rect_left.setAttribute( 'x', obj.properties.marginLeft + obj.graphWidth - (parseFloat(rect_left.getAttribute('data-original-width')) * (obj.left[i] / rect_left.getAttribute('data-value'))) ); // Stacked or grouped bars } else if (RGraph.SVG.isArray(obj.left[i])) { for (var j=0,accWidth=0; j= startFrames_right[seq]) { var isNull = RGraph.SVG.isNull(obj.right[i]); // Regular bars if (typeof obj.right[i] === 'number') { obj.right[i] = Math.min( Math.abs(original_right[i]), Math.abs(original_right[i] * ( (counters_right[i]++) / framesperbar)) ); var rect_right = obj.coordsRight[seq].element; rect_right.setAttribute( 'width', parseFloat(rect_right.getAttribute('data-original-width')) * (obj.right[i] / rect_right.getAttribute('data-value')) ); rect_right.setAttribute( 'x', properties.marginLeft + obj.graphWidth + properties.marginCenter ); // Stacked or grouped bars } else if (RGraph.SVG.isArray(obj.right[i])) { for (var j=0,accWidth=0; j= this.left.length ? linear_indexes[0] - this.left.length : linear_indexes[0], sequentialIndex: opt.index, value: typeof this.data_arr[linear_indexes[0]] === 'number' ? this.data_arr[linear_indexes[0]] : this.data_arr[linear_indexes[0]][linear_indexes[1]], values: typeof this.data_arr[linear_indexes[0]] === 'number' ? [this.data_arr[linear_indexes[0]]] : this.data_arr[linear_indexes[0]] }; }; // // A worker function that returns the correct color/label/value // // @param object specific The indexes that are applicable // @param number index The appropriate index // this.tooltipsFormattedCustom = function (specific, index) { var side = ((specific.dataset + 1) > this.left.length) ? 'right' : 'left'; var color = (!RGraph.SVG.isNull(properties.tooltipsFormattedKeyColors) && typeof properties.tooltipsFormattedKeyColors === 'object' && properties.tooltipsFormattedKeyColors[index]) ? properties.tooltipsFormattedKeyColors[index] : properties.colors[index]; if (typeof this[side][specific.dataset2] === 'object') { var label = (!RGraph.SVG.isNull(properties.tooltipsFormattedKeyLabels) && typeof properties.tooltipsFormattedKeyLabels === 'object' && properties.tooltipsFormattedKeyLabels[index]) ? properties.tooltipsFormattedKeyLabels[index] : ''; } else { var label = (!RGraph.SVG.isNull(properties.tooltipsFormattedKeyLabels) && typeof properties.tooltipsFormattedKeyLabels === 'object' && properties.tooltipsFormattedKeyLabels[specific.dataset2]) ? properties.tooltipsFormattedKeyLabels[specific.dataset2] : ''; } return { label: label, color: color }; }; // // This allows for static tooltip positioning // this.positionTooltipStatic = function (args) { var obj = args.object, e = args.event, tooltip = args.tooltip, index = args.index, svgXY = RGraph.SVG.getSVGXY(obj.svg), coords = this.coords[args.index]; // Position the tooltip in the X direction args.tooltip.style.left = ( svgXY[0] // The X coordinate of the canvas + coords.x // The X coordinate of the bar on the chart - (tooltip.offsetWidth / 2) // Subtract half of the tooltip width + (coords.width / 2) // Add half of the bar width ) + 'px'; args.tooltip.style.top = ( svgXY[1] // The Y coordinate of the canvas + coords.y // The Y coordinate of the bar on the chart - tooltip.offsetHeight // The height of the tooltip - 10 // An arbitrary amount ) + 'px'; }; // // This function handles clipping to scale values. Because // each chart handles scales differently, a worker function // is needed instead of it all being done centrally in the // RGraph.clipTo.start() function. // // @param string clip The clip string as supplied by the // user in the chart configuration // this.clipToScaleWorker = function (clipPath) { var match1 = RegExp.$1; var match2 = RegExp.$2; // The Regular expression is actually done by the // calling RGraph.clipTo.start() function in the core // library if (match1 === 'min') from = 0; else from = Number(match1); if (match2 === 'max') to = this.scale.max; else to = Number(match2); var x1 = this.getLeftXCoord(to); var x2 = this.getLeftXCoord(from); var x3 = this.getRightXCoord(from); var x4 = this.getRightXCoord(to); for (var i=0; i<2; ++i) { // LEFT-HAND-SIDE if (i === 0) { // Change the X if the number is "min" if (match1 === 'min') { x2 += (this.properties.marginCenter / 2); } // Change the width if the number is "max" if (match2 === 'max') { x1 = 0; } RGraph.SVG.create({ svg: this.svg, type: 'rect', parent: clipPath, attr: { x: x1, y: 0, width: Math.abs(x1 - x2), height: this.height } }); // Now set the clip-path attribute on the first // Line charts all-elements group this.svgAllGroup.setAttribute( 'clip-path', 'url(#' + clipPath.id + ')' ); // RIGHT-HAND-SIDE } else { // Change the X if the number is "min" if (match1 === 'min') { x3 -= (this.properties.marginCenter / 2); } // Change the width if the number is "max" if (match2 === 'max') { x4 = this.width; } RGraph.SVG.create({ svg: this.svg, type: 'rect', parent: clipPath, attr: { x: x3, y: 0, width: Math.abs(x4 - x3), height: this.height } }); // Now set the clip-path attribute on the first // Line charts all-elements group this.svgAllGroup.setAttribute( 'clip-path', 'url(#' + clipPath.id + ')' ); }; } }; // // Set the options that the user has provided // for (i in conf.options) { if (typeof i === 'string') { this.set(i, conf.options[i]); } } }; return this; // End module pattern })(window, document);