From 205900008a083c27e85995aec2b90e81e6d51c9e Mon Sep 17 00:00:00 2001 From: Robert Konigsberg Date: Fri, 6 Jan 2012 18:20:32 -0500 Subject: [PATCH] Add experimental palette. --- experimental/palette/index.html | 34 ++++++ experimental/palette/index.js | 104 +++++++++++++++++++ experimental/palette/options.js | 116 +++++++++++++++++++++ experimental/palette/palette.css | 5 + experimental/palette/palette.js | 219 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 478 insertions(+) create mode 100644 experimental/palette/index.html create mode 100644 experimental/palette/index.js create mode 100644 experimental/palette/options.js create mode 100644 experimental/palette/palette.css create mode 100644 experimental/palette/palette.js diff --git a/experimental/palette/index.html b/experimental/palette/index.html new file mode 100644 index 0000000..610d352 --- /dev/null +++ b/experimental/palette/index.html @@ -0,0 +1,34 @@ + + + + + Palette Demo + + + + + + + + + +

Palette

+

To configure this chart, tweak the values on the right. + Enter applies changes, and the filter bar on the top reduces selections

+ + + + + +
+
+
+ Other messages: +
+
+ + + diff --git a/experimental/palette/index.js b/experimental/palette/index.js new file mode 100644 index 0000000..6598602 --- /dev/null +++ b/experimental/palette/index.js @@ -0,0 +1,104 @@ +// Copyright (c) 2012 Google, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/** + * @fileoverview Javascript to run index.html. + * + * @author konigsberg@google.com (Robert Konigsberg) + */ + +"use strict"; + +function draw(element, options) { + try { + element.innerHTML = ""; + element.removeAttribute("style"); + var g = new Dygraph( + element, + function() { + var zp = function(x) { if (x < 10) return "0"+x; else return x; }; + var r = "date,parabola,line,another line,sine wave\n"; + for (var i=1; i<=31; i++) { + r += "201110" + zp(i); + r += "," + 10*(i*(31-i)); + r += "," + 10*(8*i); + r += "," + 10*(250 - 8*i); + r += "," + 10*(125 + 125 * Math.sin(0.3*i)); + r += "\n"; + } + return r; + }, options + ); + + // These don't work yet. + g.updateOptions({ + labelsDiv: 'status', + }); + } catch(err) { + addMessage(err); + throw(err); + } finally { + } +} + +function addMessage(text) { + var messages = document.getElementById("messages"); + messages.innerText = messages.innerText + text + "\n"; +} + +function start() { + var options = { + colors: [ + "rgb(51,204,204)", + "rgb(255,100,100)", + "#00DD55", + "rgba(50,50,200,0.4)" + ], + labelsSeparateLines: true, + labelsKMB: true, + legend: 'always', + width: 640, + height: 480, + title: 'Interesting Shapes', + xlabel: 'Date', + ylabel: 'Count', + axisLineColor: 'white', + drawXGrid: false, + pointClickCallback: function() { alert("p-click!"); }, + }; + + var redraw = function() { + draw(document.getElementById("graph"), palette.read()); + } + + var palette = new Palette(); + palette.create(document, document.getElementById("optionsPalette")); + palette.write(options); + palette.onchange = redraw; + palette.filterBar.focus(); + redraw(); + + for (var opt in Dygraph.OPTIONS_REFERENCE) { + if (!(opt in opts)) { + var entry = Dygraph.OPTIONS_REFERENCE[opt]; + console.warn("missing option: " + opt + " of type " + entry.type); + } + } +} diff --git a/experimental/palette/options.js b/experimental/palette/options.js new file mode 100644 index 0000000..e590693 --- /dev/null +++ b/experimental/palette/options.js @@ -0,0 +1,116 @@ +// Copyright (c) 2011 Google, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/** + * @fileoverview List of options and their types, used for the palette. + * + * @author konigsberg@google.com (Robert Konigsberg) + */ + +"use strict"; + +var opts = { + animatedZooms: { type: "boolean" }, + annotationClickHandler : {type: "function(annotation, point, dygraph, event)"}, + annotationDblClickHandler : {type: "function(annotation, point, dygraph, event)"}, + annotationMouseOutHandler : {type: "function(annotation, point, dygraph, event)"}, + annotationMouseOverHandler : {type: "function(annotation, point, dygraph, event)"}, + avoidMinZero: { type: "boolean" }, + axisLabelColor: { type: "string" }, + axisLabelFontSize: {type: "int" }, + axisLabelWidth: {type: "int" }, + axisLineColor: {type: "string" }, + axisLineWidth: {type: "int" }, + axisTickSize: {type: "int" }, + clickCallback : {type: "function(e, x, points)"}, + colorSaturation: { type: "float" }, + colors: { type: "array" }, + colorValue: { type: "float" }, + connectSeparatedPoints: { type: "boolean" }, + customBars: { type: "boolean" }, + dateWindow: { type: "array"}, + delimiter: { type: "string" }, + digitsAfterDecimal: { type: "int"}, + displayAnnotations: { type: "boolean" }, + drawCallback : {type: "function(dygraph, is_initial)"}, + drawPoints: { type: "boolean" }, + drawXAxis: {type: "boolean" }, + drawXGrid: {type: "boolean" }, + drawYAxis: {type: "boolean" }, + drawYGrid: {type: "boolean" }, + errorBars: { type: "boolean" }, + fillAlpha: { type: "float" }, + fillGraph: { type: "boolean" }, + fractions: { type: "boolean" }, + gridLineColor: { type: "string" }, + gridLineWidth: { type: "int" }, + height: {type: "int"}, + hideOverlayOnMouseOut: { type: "boolean" }, + highlightCallback : {type: "function(event, x, points,row)"}, + highlightCircleSize: { type: "int" }, + includeZero: { type: "boolean" }, + isZoomedIgnoreProgrammaticZoom: {type: "boolean" }, + labelsDivWidth: {type: "integer"}, + labels: {type: "array" }, + labelsKMB: {type: "boolean" }, + labelsKMG2: {type: "boolean"}, + labelsSeparateLines: {type: "boolean"}, + labelsShowZeroValues: {type: "boolean"}, + legend: {type: "string"}, + logscale: { type: "boolean" }, + maxNumberWidth: {type: "int"}, + panEdgeFraction: { type: "float" }, + pixelsPerLabel: { type: "int" }, + pixelsPerXLabel: { type: "int" }, + pixelsPerYLabel: { type: "int" }, + pointClickCallback : {type: "function(e, point)"}, + pointSize: { type: "integer" }, + rangeSelectorHeight: { type: "int" }, + rangeSelectorPlotFillColor: { type: "int" }, + rangeSelectorPlotStrokeColor: { type: "int" }, + rightGap: {type: "boolean"}, + rollPeriod: {type: "int"}, + showLabelsOnHighlight: { type: "boolean" }, + showRangeSelector: { type: "boolean" }, + showRoller: {type: "boolean" }, + sigFigs: {type: "int"}, + sigma: { type: "float" }, + stackedGraph: { type: "boolean" }, + stepPlot: { type: "boolean" }, + strokeWidth: { type: "integer" }, + timingName: { type: "string" }, + title: {type: "string"}, + titleHeight: {type: "integer"}, + underlayCallback : {type: "function(canvas, area, dygraph)"}, + unhighlightCallback : {type: "function(event)"}, + valueRange: {type: "array"}, + visibility: {type: "array"}, + width: {type: "int"}, + wilsonInterval: { type: "boolean" }, + xAxisHeight: {type: "int"}, + xAxisLabelWidth: {type: "int"}, + xLabelHeight: {type: "int"}, + xlabel : {type: "string" }, + xValueParser : {type: "function(str)"}, + yAxisLabelWidth: {type: "int"}, + yLabelWidth: {type: "int"}, + ylabel : {type: "string" }, + zoomCallback : {type: "function(minDate, maxDate, yRanges)"}, +}; diff --git a/experimental/palette/palette.css b/experimental/palette/palette.css new file mode 100644 index 0000000..ee63c5d --- /dev/null +++ b/experimental/palette/palette.css @@ -0,0 +1,5 @@ +.palette { + border-style: solid; + border-width: 1px; + font-size:smaller; +} diff --git a/experimental/palette/palette.js b/experimental/palette/palette.js new file mode 100644 index 0000000..f242545 --- /dev/null +++ b/experimental/palette/palette.js @@ -0,0 +1,219 @@ +// Copyright (c) 2011 Google, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +/** + * @fileoverview Dygraphs options palette. + * + * @author konigsberg@google.com (Robert Konigsberg) + */ +"use strict"; + +function Palette() { + this.model = {}; + this.onchange = function() {}; + this.filterBar = null; +} + +Palette.prototype.create = function(document, parentElement) { + var palette = this; + var createChild = function(type, parentElement) { + var element = document.createElement(type); + parentElement.appendChild(element); + return element; + }; + + var table = createChild("table", parentElement); + table.class = "palette"; + + var row = createChild("tr", table); + row.style.display = "block"; + + createChild("td", row).innerText = "Filter:"; + this.filterBar = createChild("input", createChild("td", row)); + this.filterBar.onkeyup = function() { + palette.filter(palette.filterBar.value) + }; + var go = document.createElement("button"); + createChild("td", row).appendChild(go); + go.innerText = "Redraw" + go.onclick = function() { + palette.onchange(); + }; + + for (var opt in opts) { + try { + if (opts.hasOwnProperty(opt)) { + var type = opts[opt].type; + var isFunction = type.indexOf("function(") == 0; + var row = createChild("tr", table); + var div = createChild("div", createChild("td", row)); + var a = createChild("a", div); + a.innerText = opt; + a.href = "http://dygraphs.com/options.html#" + opt; + a.title = Dygraph.OPTIONS_REFERENCE[opt].description; + a.target="_blank"; + + if (isFunction) { + var input = createChild("button", createChild("td", row)); + input.onclick = function(opt, palette) { + return function(event) { + var entry = palette.model[opt]; + var inputValue = entry.functionString; + if (inputValue == null || inputValue.length == 0) { + inputValue = type + "{ }"; + } + var value = prompt("enter function", inputValue); + if (value != null) { + if (value.length == 0) { + value = null; + } + if (value != inputValue) { + entry.functionString = value; + entry.input.innerText = value ? "defined" : "not defined"; + palette.onchange(); + } + } + } + }(opt, this); + } else { + var input = createChild("input", createChild("td", row)); + input.onkeypress = function(event) { + var keycode = event.which; + if (keycode == 13 || keycode == 8) { + palette.onchange(); + } + } + + input.type="text"; + } + this.model[opt] = { input: input, row: row }; + } + } catch(err) { + throw "For option " + opt + ":" + err; + } + } + this.filter(""); +} + +// TODO: replace semicolon parsing with comma parsing, and supporting quotes. +Palette.parseStringArray = function(value) { + if (value == null || value.length == 0) { + return null; + } + return value.split(";"); +} + +Palette.parseBooleanArray = function(value) { + if (value == null || value.length == 0) { + return null; + } + return value.split(',').map(function(x) { return x.trim() == "true"; }); +} + +Palette.parseFloatArray = function(value) { + if (value == null || value.length == 0) { + return null; + } + return value.split(',').map(function(x) { return parseFloat(x); }); +} + +Palette.parseIntArray = function(value) { + if (value == null || value.length == 0) { + return null; + } + return value.split(',').map(function(x) { return parseInt(x); }); +} + +Palette.prototype.read = function() { + var results = {}; + for (var opt in this.model) { + if (this.model.hasOwnProperty(opt)) { + var type = opts[opt].type; + var isFunction = type.indexOf("function(") == 0; + var input = this.model[opt].input; + var value = isFunction ? this.model[opt].functionString : input.value; + if (value && value.length != 0) { + if (type == "boolean") { + results[opt] = value == "true"; + } else if (type == "int") { + results[opt] = parseInt(value); + } else if (type == "float") { + results[opt] = parseFloat(value); + } else if (type == "array") { + results[opt] = Palette.parseStringArray(value); + } else if (type == "array") { + results[opt] = Palette.parseFloatArray(value); + } else if (type == "array") { + results[opt] = Palette.parseBooleanArray(value); + } else if (type == "array") { + results[opt] = Palette.parseIntArray(value); + } else if (isFunction) { + var localVariable = null; + eval("localVariable = " + value); + results[opt] = localVariable; + } else { + results[opt] = value; + } + } + } + } + return results; +} + +/** + * Write to input elements. + */ +Palette.prototype.write = function(hash) { + var results = {}; + for (var opt in this.model) { + // && hash.hasOwnProperty(opt) + if (this.model.hasOwnProperty(opt)) { + var input = this.model[opt].input; + var type = opts[opt].type; + var value = hash[opt]; + if (type == "array") { + if (value) { + input.value = value.join("; "); + } + } else if (type.indexOf("array") == 0) { + if (value) { + input.value = value.join(", "); + } + } else if (type.indexOf("function(") == 0) { + input.innerText = value ? "defined" : "not defined"; + this.model[opt].functionString = value ? value.toString() : null; + } else { + if (value) { + input.value = value; + } + } + } + } +} + +Palette.prototype.filter = function(pattern) { + pattern = pattern.toLowerCase(); + for (var opt in this.model) { + if (this.model.hasOwnProperty(opt)) { + var row = this.model[opt].row; + row.style.display = (opt.toLowerCase().indexOf(pattern) >= 0) ? "block" : "none"; + } + } +} -- 2.7.4