From 181c98ec6a70d8949fac4e4fc674f99f63e0220c Mon Sep 17 00:00:00 2001 From: Charles Grandfield Date: Fri, 1 Jul 2016 12:09:08 -0400 Subject: [PATCH] Added support for drawing legends to all graph types other than line and barsize. Added a "showLegend" option which can be used to toggle legend drawing Added legend drawing to 11_tooltips and to playground examples Added description of showLegend option to documentation --- docs/graph3d/index.html | 10 +- examples/graph3d/11_tooltips.html | 1 + examples/graph3d/playground/index.html | 4 + examples/graph3d/playground/playground.js | 1 + lib/graph3d/Graph3d.js | 148 +++++++++++++--------- 5 files changed, 105 insertions(+), 59 deletions(-) diff --git a/docs/graph3d/index.html b/docs/graph3d/index.html index c0e604a7..16467484 100644 --- a/docs/graph3d/index.html +++ b/docs/graph3d/index.html @@ -435,6 +435,14 @@ var options = { when drawn in perspective. + + showLegend + boolean + none + If true, a legend is drawn for the graph (if the graph type supports it). + By default a legend is drawn for dot and dot-color style graphs. + + showShadow boolean @@ -796,4 +804,4 @@ graph3d.on('cameraPositionChange', onCameraPositionChange); - \ No newline at end of file + diff --git a/examples/graph3d/11_tooltips.html b/examples/graph3d/11_tooltips.html index 6ae32a39..508e7e0a 100644 --- a/examples/graph3d/11_tooltips.html +++ b/examples/graph3d/11_tooltips.html @@ -48,6 +48,7 @@ height: '600px', style: style, showPerspective: true, + showLegend: true, showGrid: true, showShadow: false, diff --git a/examples/graph3d/playground/index.html b/examples/graph3d/playground/index.html index 4f42260e..134bb264 100644 --- a/examples/graph3d/playground/index.html +++ b/examples/graph3d/playground/index.html @@ -116,6 +116,10 @@ showPerspective + + showLegend + + showShadow diff --git a/examples/graph3d/playground/playground.js b/examples/graph3d/playground/playground.js index 5b93dddb..a2e28728 100644 --- a/examples/graph3d/playground/playground.js +++ b/examples/graph3d/playground/playground.js @@ -407,6 +407,7 @@ function getOptions() { showAnimationControls: (document.getElementById("showAnimationControls").checked != false), showGrid: (document.getElementById("showGrid").checked != false), showPerspective: (document.getElementById("showPerspective").checked != false), + showLegend: (document.getElementById("showLegend").checked != false), showShadow: (document.getElementById("showShadow").checked != false), keepAspectRatio: (document.getElementById("keepAspectRatio").checked != false), verticalRatio: document.getElementById("verticalRatio").value, diff --git a/lib/graph3d/Graph3d.js b/lib/graph3d/Graph3d.js index 9db4fbeb..f2c17507 100644 --- a/lib/graph3d/Graph3d.js +++ b/lib/graph3d/Graph3d.js @@ -44,6 +44,7 @@ function Graph3d(container, data, options) { this.filterLabel = 'time'; this.legendLabel = 'value'; + this.showLegend = undefined; // auto by default (based on graph style) this.style = Graph3d.STYLE.DOT; this.showPerspective = true; @@ -494,7 +495,11 @@ Graph3d.prototype._dataInitialize = function (rawData, style) { this.valueMax = (this.defaultValueMax !== undefined) ? this.defaultValueMax : valueRange.max; if (this.valueMax <= this.valueMin) this.valueMax = this.valueMin + 1; } - + + // these styles default to having legends + var isLegendGraphStyle = this.style === Graph3d.STYLE.DOTCOLOR || this.style === Graph3d.STYLE.DOTSIZE; + this.showLegend = (this.defaultShowLegend !== undefined) ? this.defaultShowLegend : isLegendGraphStyle; + // set the scale dependent on the ranges. this._setScale(); }; @@ -838,6 +843,7 @@ Graph3d.prototype.setOptions = function (options) { if (options.filterLabel !== undefined) this.filterLabel = options.filterLabel; if (options.legendLabel !== undefined) this.legendLabel = options.legendLabel; + if (options.showLegend !== undefined) this.defaultShowLegend = options.showLegend; if (options.xLabel !== undefined) this.xLabel = options.xLabel; if (options.yLabel !== undefined) this.yLabel = options.yLabel; if (options.zLabel !== undefined) this.zLabel = options.zLabel; @@ -972,46 +978,64 @@ Graph3d.prototype._redrawClear = function() { /** - * Redraw the legend showing the colors + * Get legend width */ -Graph3d.prototype._redrawLegend = function() { - var y; - - if (this.style === Graph3d.STYLE.DOTCOLOR || - this.style === Graph3d.STYLE.DOTSIZE) { - +Graph3d.prototype._getLegendWidth = function() { + var width; + if (this.style === Graph3d.STYLE.DOTSIZE) { var dotSize = this.frame.clientWidth * this.dotSizeRatio; + width = dotSize / 2 + dotSize * 2; + } else if (this.style === Graph3d.STYLE.BARSIZE) { + width = this.xBarWidth ; + } else { + width = 20; + } + return width; +} - var widthMin, widthMax; - if (this.style === Graph3d.STYLE.DOTSIZE) { - widthMin = dotSize / 2; // px - widthMax = dotSize / 2 + dotSize * 2; // Todo: put this in one function - } - else { - widthMin = 20; // px - widthMax = 20; // px - } - var height = Math.max(this.frame.clientHeight * 0.25, 100); - var top = this.margin; - var right = this.frame.clientWidth - this.margin; - var left = right - widthMax; - var bottom = top + height; - } +/** + * Redraw the legend based on size, dot color, or surface height + */ +Graph3d.prototype._redrawLegend = function() { + + //Return without drawing anything, if no legend is specified + if (this.showLegend !== true) {return;} + + // Do not draw legend when graph style does not support + if (this.style === Graph3d.STYLE.LINE + || this.style === Graph3d.STYLE.BARSIZE //TODO add legend support for BARSIZE + ){return;} + + // Legend types - size and color. Determine if size legend. + var isSizeLegend = (this.style === Graph3d.STYLE.BARSIZE + || this.style === Graph3d.STYLE.DOTSIZE) ; + + // Legend is either tracking z values or style values. This flag if false means use z values. + var isValueLegend = (this.style === Graph3d.STYLE.DOTSIZE + || this.style === Graph3d.STYLE.DOTCOLOR + || this.style === Graph3d.STYLE.BARCOLOR); + + var height = Math.max(this.frame.clientHeight * 0.25, 100); + var top = this.margin; + var width = this._getLegendWidth() ; // px - overwritten by size legend + var right = this.frame.clientWidth - this.margin; + var left = right - width; + var bottom = top + height; var canvas = this.frame.canvas; var ctx = canvas.getContext('2d'); ctx.lineWidth = 1; ctx.font = '14px arial'; // TODO: put in options - if (this.style === Graph3d.STYLE.DOTCOLOR) { + if (isSizeLegend === false) { // draw the color bar var ymin = 0; var ymax = height; // Todo: make height customizable + var y; + for (y = ymin; y < ymax; y++) { var f = (y - ymin) / (ymax - ymin); - - //var width = (dotSize / 2 + (1-f) * dotSize * 2); // Todo: put this in one function var hue = f * 240; var color = this._hsv2rgb(hue, 1, 1); @@ -1021,55 +1045,63 @@ Graph3d.prototype._redrawLegend = function() { ctx.lineTo(right, top + y); ctx.stroke(); } - ctx.strokeStyle = this.axisColor; - ctx.strokeRect(left, top, widthMax, height); - } + ctx.strokeRect(left, top, width, height); - if (this.style === Graph3d.STYLE.DOTSIZE) { - // draw border around color bar + } else { + + // draw the size legend box + var widthMin; + if (this.style === Graph3d.STYLE.DOTSIZE) { + var dotSize = this.frame.clientWidth * this.dotSizeRatio; + widthMin = dotSize / 2; // px + } else if (this.style === Graph3d.STYLE.BARSIZE) { + //widthMin = this.xBarWidth * 0.2 this is wrong - barwidth measures in terms of xvalues + } ctx.strokeStyle = this.axisColor; ctx.fillStyle = this.dataColor.fill; ctx.beginPath(); ctx.moveTo(left, top); ctx.lineTo(right, top); - ctx.lineTo(right - widthMax + widthMin, bottom); + ctx.lineTo(right - width + widthMin, bottom); ctx.lineTo(left, bottom); ctx.closePath(); ctx.fill(); ctx.stroke(); } - if (this.style === Graph3d.STYLE.DOTCOLOR || - this.style === Graph3d.STYLE.DOTSIZE) { - // print values along the color bar - var gridLineLen = 5; // px - var step = new StepNumber(this.valueMin, this.valueMax, (this.valueMax-this.valueMin)/5, true); - step.start(); - if (step.getCurrent() < this.valueMin) { - step.next(); - } - while (!step.end()) { - y = bottom - (step.getCurrent() - this.valueMin) / (this.valueMax - this.valueMin) * height; - - ctx.beginPath(); - ctx.moveTo(left - gridLineLen, y); - ctx.lineTo(left, y); - ctx.stroke(); - - ctx.textAlign = 'right'; - ctx.textBaseline = 'middle'; - ctx.fillStyle = this.axisColor; - ctx.fillText(step.getCurrent(), left - 2 * gridLineLen, y); + // print value text along the legend edge + var gridLineLen = 5; // px + + var legendMin = isValueLegend ? this.valueMin : this.zMin; + var legendMax = isValueLegend ? this.valueMax : this.zMax; + var step = new StepNumber(legendMin, legendMax, (legendMax-legendMin)/5, true); + step.start(); + if (step.getCurrent() < legendMin) { + step.next(); + } + var y; + while (!step.end()) { + y = bottom - (step.getCurrent() - legendMin) / (legendMax - legendMin) * height; - step.next(); - } + ctx.beginPath(); + ctx.moveTo(left - gridLineLen, y); + ctx.lineTo(left, y); + ctx.stroke(); ctx.textAlign = 'right'; - ctx.textBaseline = 'top'; - var label = this.legendLabel; - ctx.fillText(label, right, bottom + this.margin); + ctx.textBaseline = 'middle'; + ctx.fillStyle = this.axisColor; + ctx.fillText(step.getCurrent(), left - 2 * gridLineLen, y); + + step.next(); } + + ctx.textAlign = 'right'; + ctx.textBaseline = 'top'; + var label = this.legendLabel; + ctx.fillText(label, right, bottom + this.margin); + }; /**