// 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 chart constuctor // RGraph.RScatter = function (conf) { // Store the data set(s) this.data = RGraph.arrayClone(conf.data); // Account for just one dataset being given if (typeof conf.data === 'object' && typeof conf.data[0] === 'object' && (typeof conf.data[0][0] === 'number' || typeof conf.data[0][0] === 'string') ) { var tmp = RGraph.arrayClone(conf.data); conf.data = new Array(); conf.data[0] = RGraph.arrayClone(tmp); this.data = RGraph.arrayClone(conf.data); } this.id = conf.id this.canvas = document.getElementById(this.id) this.context = this.canvas.getContext ? this.canvas.getContext("2d") : null; this.canvas.__object__ = this; this.type = 'rscatter'; this.hasTooltips = false; 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.colorsParsed = false; this.coordsText = []; this.original_colors = []; this.firstDraw = true; // After the first draw this will be false this.centerx = 0; this.centery = 0; this.radius = 0; this.max = 0; // Convert all of the data pieces to numbers as necessary for (var i=0; i 0 && properties.key.length >= 3) { this.centerx = this.centerx - properties.marginRight + 5; } // // Populate the colors array for the purposes of // generating the key // if (typeof properties.key === 'object' && RGraph.isArray(properties.key) && properties.key[0]) { // Reset the colors array properties.colors = []; for (var i=0; i -1) RGraph.text({object: this,tag: 'scale',font: textConf.font,size: textConf.size,color: textConf.color,bold: textConf.bold,italic: textConf.italic,x:centerx - offset + properties.labelsAxesOffsetx,y:centery - (r * ((i+1) / len)) + properties.labelsAxesOffsety,text:this.scale2.labels[i],valign:'center',halign:centered ? 'center' : 'right',bounding: true, boundingFill: properties.labelsAxesBackground, boundingStroke: 'rgba(0,0,0,0)'}); if (axes.indexOf('s') > -1) RGraph.text({object: this,tag: 'scale',font: textConf.font,size: textConf.size,color: textConf.color,bold: textConf.bold,italic: textConf.italic,x:centerx - offset + properties.labelsAxesOffsetx,y:centery + (r * ((i+1) / len)) + properties.labelsAxesOffsety,text:this.scale2.labels[i],valign:'center',halign:centered ? 'center' : 'right',bounding: true, boundingFill: properties.labelsAxesBackground, boundingStroke: 'rgba(0,0,0,0)'}); if (axes.indexOf('e') > -1) RGraph.text({object: this,tag: 'scale',font: textConf.font,size: textConf.size,color: textConf.color,bold: textConf.bold,italic: textConf.italic,x:centerx + (r * ((i+1) / len)) + properties.labelsAxesOffsetx,y:centery + offset + properties.labelsAxesOffsety,text:this.scale2.labels[i],valign:centered ? 'center' : 'top',halign:'center',bounding: true, boundingFill: properties.labelsAxesBackground, boundingStroke: 'rgba(0,0,0,0)'}); if (axes.indexOf('w') > -1) RGraph.text({object: this,tag: 'scale',font: textConf.font,size: textConf.size,color: textConf.color,bold: textConf.bold,italic: textConf.italic,x:centerx - (r * ((i+1) / len)) + properties.labelsAxesOffsetx,y:centery + offset + properties.labelsAxesOffsety,text:this.scale2.labels[i],valign:centered ? 'center' : 'top',halign:'center',bounding: true, boundingFill: properties.labelsAxesBackground, boundingStroke: 'rgba(0,0,0,0)'}); } // Draw the center minimum value (but only if there's at least one axes labels stipulated) if (properties.labelsAxes.length > 0 && properties.scaleZerostart) { RGraph.text({ object: this, font: textConf.font, size: textConf.size, color: textConf.color, bold: textConf.bold, italic: textConf.italic, x: centerx + properties.labelsAxesOffsetx, y: centery + properties.labelsAxesOffsety, text: RGraph.numberFormat({ object: this, number: Number(this.scale2.min).toFixed(this.scale2.decimals), unitspre: this.scale2.units_pre, unitspost: this.scale2.units_post }), valign: 'center', halign: 'center', bounding: true, boundingFill: properties.labelsAxesBackground, boundingStroke: 'rgba(0,0,0,0)', tag: 'scale' }); } }; // // Draws the circular labels that go around the charts // // @param labels array The labels that go around the chart // this.drawCircularLabels = function (context, labels, font_face, font_size, r) { var r = r + properties.labelsOffsetRadius + 25, color = properties.labelsColor; for (var i=0; i this.centerx) ? 'left' : 'right', tag: 'labels', cssClass: RGraph.getLabelsCSSClassName({ object: this, name: 'labelsClass', index: i }) }); } }; // // Draws a single tickmark // this.drawTick = function (x, y, color) { var tickmarks = properties.tickmarksStyle || properties.tickmarks; var ticksize = properties.tickmarksSize; this.context.strokeStyle = color; this.context.fillStyle = color; // Set the linewidth for the tickmark to 1 var prevLinewidth = this.context.lineWidth; this.context.lineWidth = 1; // Cross if (tickmarks == 'cross') { this.context.beginPath(); this.context.moveTo(x + ticksize, y + ticksize); this.context.lineTo(x - ticksize, y - ticksize); this.context.stroke(); this.context.beginPath(); this.context.moveTo(x - ticksize, y + ticksize); this.context.lineTo(x + ticksize, y - ticksize); this.context.stroke(); // Circle } else if (tickmarks == 'circle') { this.context.beginPath(); this.context.arc(x, y, ticksize, 0, 6.2830, false); this.context.fill(); // Square } else if (tickmarks == 'square') { this.context.beginPath(); this.context.fillRect(x - ticksize, y - ticksize, 2 * ticksize, 2 * ticksize); this.context.fill(); // Diamond shape tickmarks } else if (tickmarks == 'diamond') { this.context.beginPath(); this.context.moveTo(x, y - ticksize); this.context.lineTo(x + ticksize, y); this.context.lineTo(x, y + ticksize); this.context.lineTo(x - ticksize, y); this.context.closePath(); this.context.fill(); // Plus style tickmarks } else if (tickmarks == 'plus') { this.context.lineWidth = 1; this.context.beginPath(); this.context.moveTo(x, y - ticksize); this.context.lineTo(x, y + ticksize); this.context.moveTo(x - ticksize, y); this.context.lineTo(x + ticksize, y); this.context.stroke(); } this.context.lineWidth = prevLinewidth; }; // // This function makes it much easier to get the (if any) point that is currently being hovered over. // // @param object e The event object // this.getShape = function (e) { var mouseXY = RGraph.getMouseXY(e); var mouseX = mouseXY[0]; var mouseY = mouseXY[1]; var overHotspot = false; var offset = properties.tooltipsHotspot; // This is how far the hotspot extends for (var i=0,len=this.coords.length; i (x - offset) && mouseY < (y + offset) && mouseY > (y - offset) && (this.properties.clip ? RGraph.clipTo.test(this, mouseX, mouseY) : true) ) { if (RGraph.parseTooltipText) { var tooltip = RGraph.parseTooltipText(properties.tooltips, i); } var indexes = RGraph.sequentialIndexToGrouped(i, this.data); return { object: this, x: x, y: y, dataset: indexes[0], index: indexes[1], sequentialIndex: i, tooltip: typeof tooltip === 'string' ? tooltip : null }; } } }; // // This function facilitates the installation of tooltip event listeners if // tooltips are defined. // this.allowTooltips = function () { // Preload any tooltip images that are used in the tooltips RGraph.preLoadTooltipImages(this); // // This installs the window mousedown event listener that lears any // highlight that may be visible. // RGraph.installWindowMousedownTooltipListener(this); // // This installs the canvas mousemove event listener. This function // controls the pointer shape. // RGraph.installCanvasMousemoveTooltipListener(this); // // This installs the canvas mouseup event listener. This is the // function that actually shows the appropriate tooltip (if any). // RGraph.installCanvasMouseupTooltipListener(this); }; // // Each object type has its own Highlight() function which highlights the appropriate shape // // @param object shape The shape to highlight // this.highlight = function (shape) { if (typeof properties.highlightStyle === 'function') { (properties.highlightStyle)(shape); } else if (properties.highlightStyle === 'invert') { var radius = RGraph.isNumber(properties.highlightSize) ? properties.highlightSize : 25; this.path( 'b a % % % -1 6.29 false', this.centerx, this.centery, this.radius ); this.path( 'a % % % 0 6.29 true c s rgba(0,0,0,0) f %', shape.x, shape.y, radius, properties.highlightFill ); // Draw a border around the circular cutout this.path( 'b a % % % 0 6.29 false s %', shape.x, shape.y, radius, properties.highlightStroke ); } else { // // Draw an arc on the canvas to highlight the appropriate area // this.context.beginPath(); this.context.strokeStyle = properties.highlightStroke; this.context.fillStyle = properties.highlightFill; this.context.arc( shape.x, shape.y, RGraph.isNumber(properties.highlightSize) ? properties.highlightSize : properties.tickmarksSize, 0, RGraph.TWOPI, false ); this.context.stroke(); this.context.fill(); } }; // // The getObjectByXY() worker method. Don't call this call: // // RGraph.ObjectRegistry.getObjectByXY(e) // // @param object e The event object // this.getObjectByXY = function (e) { var mouseXY = RGraph.getMouseXY(e); var mouseX = mouseXY[0]; var mouseY = mouseXY[1]; var centerx = this.centerx; var centery = this.centery; var radius = this.radius; if ( mouseX > (centerx - radius) && mouseX < (centerx + radius) && mouseY > (centery - radius) && mouseY < (centery + radius) ) { return this; } }; // // This function returns the radius (ie the distance from the center) for a particular // value. // // @param number value The value you want the radius for // this.getRadius = function (value) { var max = this.max; if (value < 0 || value > max) { return null; } var r = (value / max) * this.radius; return r; }; // // 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.data = RGraph.arrayClone(this.data); this.original_colors.highlightStroke = RGraph.arrayClone(properties.highlightStroke); this.original_colors.highlightFill = RGraph.arrayClone(properties.highlightFill); this.original_colors.colorsDefault = RGraph.arrayClone(properties.colorsDefault); this.original_colors.backgroundGridColor = RGraph.arrayClone(properties.backgroundGridColor); this.original_colors.backgroundColor = RGraph.arrayClone(properties.backgroundColor); this.original_colors.segmentHighlightStroke = RGraph.arrayClone(properties.segmentHighlightStroke); this.original_colors.segmentHighlightFill = RGraph.arrayClone(properties.segmentHighlightFill); } // Go through the data for (var i=0; i