// 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}; // // The bar chart constructor // RGraph.Funnel = function (conf) { var id = conf.id; var canvas = document.getElementById(id); var data = conf.data; this.id = id; this.canvas = canvas; this.context = this.canvas.getContext ? this.canvas.getContext("2d", {alpha: (typeof id === 'object' && id.alpha === false) ? false : true}) : null; this.canvas.__object__ = this; this.type = 'funnel'; this.coords = []; this.isRGraph = true; this.isrgraph = true; this.rgraph = true; this.uid = RGraph.createUID(); this.canvas.uid = this.canvas.uid ? this.canvas.uid : RGraph.createUID(); this.coordsText = []; this.original_colors = []; this.firstDraw = true; // After the first draw this will be false // Check for support if (!this.canvas) { alert('[FUNNEL] No canvas support'); return; } // // The funnel charts properties // this.properties = { backgroundBars: false, backgroundBarsOpacity: 0.25, backgroundBarsColors: null, colorsStroke: 'rgba(0,0,0,0)', colors: ['red','green','gray','black','pink','orange','blue','yellow','green','red'], marginLeft: 35, marginRight: 35, marginTop: 35, marginBottom: 35, labels: null, labelsFont: null, labelsSize: null, labelsColor: null, labelsBold: null, labelsItalic: null, labelsSticks: false, labelsX: null, labelsPosition: 'edge', labelsOffsetx: 0, labelsOffsety: 0, labelsBackground: 'rgba(255,255,255,0.7)', labelsFormattedDecimals: 0, labelsFormattedPoint: '.', labelsFormattedThousand: ',', labelsFormattedUnitsPre: '', labelsFormattedUnitsPost: '', title: '', titleItalic: null, titleBold: true, titleFont: null, titleSize: null, titleColor: null, titleX: null, titleY: null, titleHalign: null, titleValign: null, titleOffsetx: 0, titleOffsety: 0, titleSubtitle: '', titleSubtitleSize: null, titleSubtitleColor: '#aaa', titleSubtitleFont: null, titleSubtitleBold: null, titleSubtitleItalic: null, titleSubtitleOffsetx: 0, titleSubtitleOffsety: 0, textSize: 12, textColor: 'black', textFont: 'Arial, Verdana, sans-serif', textBold: false, textItalic: false, textHalign: 'left', textAccessible: false, textAccessibleOverflow: 'visible', textAccessiblePointerevents: false, text: null, contextmenu: null, shadow: false, shadowColor: '#666', shadowBlur: 3, shadowOffsetx: 3, shadowOffsety: 3, key: null, keyBackground: 'white', keyPosition: 'graph', keyHalign: 'right', keyShadow: false, keyShadowColor: '#666', keyShadowBlur: 3, keyShadowOffsetx: 2, keyShadowOffsety: 2, keyPositionMarginBoxed: false, keyPositionMarginHSpace: 0, keyPositionX: null, keyPositionY: null, keyColorShape: 'square', keyRounded: true, keyLinewidth: 1, keyColors: null, keyInteractive: false, keyInteractiveHighlightChartLinewidth: 2, keyInteractiveHighlightChartStroke: 'black', keyInteractiveHighlightChartFill: 'rgba(255,255,255,0.7)', keyInteractiveHighlightLabel: 'rgba(255,0,0,0.2)', keyLabelsFont: null, keyLabelsSize: null, keyLabelsColor: null, keyLabelsBold: null, keyLabelsItalic: null, keyLabelsOffsetx: 0, keyLabelsOffsety: 0, keyFormattedDecimals: 0, keyFormattedPoint: '.', keyFormattedThousand: ',', keyFormattedUnitsPre: '', keyFormattedUnitsPost: '', keyFormattedValueSpecific: null, keyFormattedItemsCount: null, tooltipsHighlight: true, tooltips: null, tooltipsEffect: 'slide', tooltipsCssClass: 'RGraph_tooltip', tooltipsCss: null, tooltipsEvent: 'onclick', tooltipsPersistent: false, tooltipsFormattedThousand: ',', tooltipsFormattedPoint: '.', tooltipsFormattedDecimals: 0, tooltipsFormattedUnitsPre: '', tooltipsFormattedUnitsPost: '', tooltipsFormattedKeyColors: null, tooltipsFormattedKeyColorsShape: 'square', tooltipsFormattedKeyLabels: [], tooltipsFormattedListType: 'ul', tooltipsFormattedListItems: null, tooltipsFormattedTableHeaders: null, tooltipsFormattedTableData: null, tooltipsPointer: true, tooltipsPointerOffsetx: 0, tooltipsPointerOffsety: 0, tooltipsPositionStatic: true, tooltipsHotspotIgnore: null, highlightStroke: 'rgba(0,0,0,0)', highlightFill: 'rgba(255,255,255,0.7)', annotatable: false, annotatableColor: 'black', annotatableLinewidth: 1, effectGrowMultiplier: 1, clearto: 'rgba(0,0,0,0)', events: {}, scale: true, scaleFactor: 2, antialiasTranslate: false }; // // These are the properties that get scaled up if the // scale option is enabled. // this.properties_scale = [ 'marginLeft', 'marginRight', 'marginTop', 'marginBottom', 'labelsSize', 'labelsX', 'labelsOffsetx', 'labelsOffsety', 'titleSize', 'titleX', 'titleY', 'titleOffsetx', 'titleOffsety', 'titleSubtitleSize', 'titleSubtitleOffsetx', 'titleSubtitleOffsety', 'textSize', 'shadowBlur', 'shadowOffsetx', 'shadowOffsety', 'keyShadowBlur', 'keyShadowOffsetx', 'keyShadowOffsety', 'keyPositionMarginHSpace', 'keyPositionX', 'keyPositionY', 'keyLinewidth', 'keyInteractiveHighlightChartLinewidth', 'keyLabelsSize', 'keyLabelsOffsetx', 'keyLabelsOffsety' ]; // // Add the reverse look-up table for property names // so that property names can be specified in any case. // this.properties_lowercase_map = []; for (var i in this.properties) { if (typeof i === 'string') { this.properties_lowercase_map[i.toLowerCase()] = i; } } // If the data is a string split it up data = RGraph.stringsToNumbers(data); this.data = data; // // Create the dollar objects so that functions can be added to them // for (var i=0; i { // Note that we're in an arrow function so the // 'this' variable is OK to be used and refers // to the RGraph Line chart object. RGraph.scale(this); }); // Fire the onbeforedraw event RGraph.fireCustomEvent(this, 'onbeforedraw'); // // Install clipping // // MUST be the first thing that's done after the // beforedraw event // if (!RGraph.isNullish(this.properties.clip)) { RGraph.clipTo.start(this, this.properties.clip); } // Translate half a pixel for antialiasing purposes - but // only if it hasn't been done already // // The old style antialias fix // if ( !this.properties.scale && this.properties.antialiasTranslate && !this.canvas.__rgraph_aa_translated__) { this.context.translate(0.5,0.5); this.canvas.__rgraph_aa_translated__ = true; } // // Parse the colors. This allows for simple gradient syntax // if (!this.colorsParsed) { this.parseColors(); // Don't want to do this again this.colorsParsed = true; } // // Make the margins easy ro access // this.marginLeft = properties.marginLeft; this.marginRight = properties.marginRight; this.marginTop = properties.marginTop; this.marginBottom = properties.marginBottom; // This stops the coords array from growing this.coords = []; // // Stop this growing uncntrollably // this.coordsText = []; // Draw the title using the new drawTitle() function RGraph.drawTitle(this); // Draw the funnel this.drawFunnel(); // // Setup the context menu if required // if (properties.contextmenu) { RGraph.showContext(this); } // // Draw the labels on the chart // this.drawLabels(); // // Add custom text thats specified // RGraph.addCustomText(this); // // This installs the event listeners // RGraph.installEventListeners(this); // // End clipping // if (!RGraph.isNullish(this.properties.clip)) { RGraph.clipTo.end(); } // // Fire the onfirstdraw event // if (this.firstDraw) { this.firstDraw = false; RGraph.fireCustomEvent(this, 'onfirstdraw'); this.firstDrawFunc(); } // // Fire the RGraph draw event // RGraph.fireCustomEvent(this, 'ondraw'); // // Install any inline responsive configuration. This // should be last in the draw function - even after // the draw events. // RGraph.installInlineResponsive(this); return this; }; // // Draws a single background bar if requested. This // function is called by the drawFunnel() function // once the coordinates have been calculated. // // @param number index The zero-indexed number of the // segment // @param The coordinates of the section // this.drawBackgroundBar = function (index, coords) { var color = (RGraph.isArray(properties.backgroundBarsColors) && properties.backgroundBarsColors[index]) ? properties.backgroundBarsColors[index] : properties.colors[index]; if (properties.backgroundBars && this.data[index] && color && index < (this.data.length - 1) ) { this.path( 'b ga % r % % % % f % ga 1', properties.backgroundBarsOpacity, 0, coords[1], this.canvas.width, coords[5] - coords[3], color ); } }; // // Used in chaining. Runs a function there and then - not waiting for // the events to fire (eg the onbeforedraw event) // // @param function func The function to execute // this.exec = function (func) { func(this); return this; }; // // This function actually draws the chart // this.drawFunnel = function () { var width = this.canvas.width - this.marginLeft - this.marginRight; var height = this.canvas.height - this.marginTop - this.marginBottom; var max = RGraph.arrayMax(this.data); var accheight = this.marginTop; // // Loop through each segment to draw // // Set a shadow if it's been requested if (properties.shadow) { this.context.shadowColor = properties.shadowColor; this.context.shadowBlur = properties.shadowBlur; this.context.shadowOffsetX = properties.shadowOffsetx; this.context.shadowOffsetY = properties.shadowOffsety; } this.context.strokeStyle = '#0000'; for (i=0,len=this.data.length; i 0) { var font = properties.textFont, size = properties.textSize, color = properties.textColor, labels = properties.labels, halign = properties.textHalign === 'left' ? 'left' : 'center'; // Get the text configuration var textConf = RGraph.getTextConf({ object: this, prefix: 'labels' }); // Determine the X coordinate if (typeof properties.labelsX == 'number') { var x = properties.labelsX; } else { var x = halign == 'left' ? (this.marginLeft - 15) : ((this.canvas.width - this.marginLeft - this.marginRight) / 2) + this.marginLeft; } // Loop through the labels drawing them on the canvas. // All but the last label for (var j=0; j properties.marginLeft && mouseXY[0] < (this.canvas.width - properties.marginRight) && mouseXY[1] > properties.marginTop && mouseXY[1] < (this.canvas.height - properties.marginBottom) ) { return this; } }; // // This allows for easy specification of gradients // this.parseColors = function () { // Save the original colors so that they can be restored when the canvas is reset if (this.original_colors.length === 0) { this.original_colors.colors = RGraph.arrayClone(properties.colors); this.original_colors.keyColors = RGraph.arrayClone(properties.keyColors); this.original_colors.highlightFill = RGraph.arrayClone(properties.highlightFill); this.original_colors.highlightStroke = RGraph.arrayClone(properties.highlightStroke); this.original_colors.colorsStroke = RGraph.arrayClone(properties.colorsStroke); } var colors = properties.colors; for (var i=0; i