Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added value plotter to graph a value over time #226

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions src/dat/controllers/PlotterController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/

import Controller from './Controller';
import Plotter from '../utils/plotter';

/**
* @class Provides a canvas that graphically displays the value of the object property at the specified interval
*
* @extends dat.controllers.Controller
*
* @param {Object} object The object to be manipulated
* @param {string} property The name of the property to be manipulated
* @param {Object} params Contains the max and period properties
*/
class PlotterController extends Controller {
constructor(object, property, params) {
super(object, property);

/** The graph will be these many units high */
this.max = params.max;

/** Refresh rate. Value of 0 disables auto-refresh */
this.period = params.period;

/** Stores the current value for comparison during animation frame */
this.prevValue = this.getValue();

/** Allows acurate timing for the period to be checked during animation frame */
this.lastUpdate = Date.now();

this.__panel = new Plotter(params.fgColor, params.bgColor, params.type);
this.domElement.appendChild(this.__panel.dom);
}

updateDisplay() {
const value = this.getValue();
if (this.period < 1 && value !== this.prevValue) {
/* Update only on value change when auto-refresh is off */
this.__panel.update(value, this.max);
} else if ((Date.now() - this.lastUpdate) > this.period) {
/* Update if elapsed time since last update is greater than the period */
this.__panel.update(value, this.max);
this.lastUpdate = Date.now() * 2 - this.lastUpdate - this.period;
}

this.prevValue = value;

return super.updateDisplay();
}

}

export default PlotterController;
42 changes: 42 additions & 0 deletions src/dat/gui/GUI.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import FunctionController from '../controllers/FunctionController';
import NumberControllerBox from '../controllers/NumberControllerBox';
import NumberControllerSlider from '../controllers/NumberControllerSlider';
import ColorController from '../controllers/ColorController';
import PlotterController from '../controllers/PlotterController';
import requestAnimationFrame from '../utils/requestAnimationFrame';
import CenteredDiv from '../dom/CenteredDiv';
import dom from '../dom/dom';
Expand Down Expand Up @@ -556,6 +557,42 @@ common.extend(
);
},

/**
* Adds a new plotter controller to the GUI.
*
* @param object
* @param property
* @param max The maximum value that the plotter will display (default 10)
* @param period The update interval in ms or use 0 to only update on value change (default 500)
* @param type Type of graph to render - line or bar (default line)
* @param fgColor Foreground color of the graph in hex (default #fff)
* @param bgColor Background color of the graph in hex (default #000)
* @returns {Controller} The controller that was added to the GUI.
* @instance
*
* @example
* var obj = {
* value: 5
* };
* gui.addPlotter(obj, 'value', 10, 100);
* gui.addPlotter(obj, 'value', 10, 0);
*/
addPlotter: function(object, property, max, period, type, fgColor, bgColor) {
return add(
this,
object,
property,
{
plotter: true,
max: max || 10,
period: (typeof period === 'number') ? period : 500,
type: type || 'line',
fgColor: fgColor || '#fff',
bgColor: bgColor || '#000'
}
);
},

/**
* Removes the given controller from the GUI.
* @param {Controller} controller
Expand Down Expand Up @@ -1139,6 +1176,9 @@ function add(gui, object, property, params) {

if (params.color) {
controller = new ColorController(object, property);
} else if (params.plotter) {
controller = new PlotterController(object, property, params);
gui.listen(controller);
} else {
const factoryArgs = [object, property].concat(params.factoryArgs);
controller = ControllerFactory.apply(gui, factoryArgs);
Expand All @@ -1165,6 +1205,8 @@ function add(gui, object, property, params) {
dom.addClass(li, GUI.CLASS_CONTROLLER_ROW);
if (controller instanceof ColorController) {
dom.addClass(li, 'color');
} else if (controller instanceof PlotterController) {
dom.addClass(li, 'plotter');
} else {
dom.addClass(li, typeof controller.getValue());
}
Expand Down
8 changes: 7 additions & 1 deletion src/dat/gui/_structure.scss
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ $button-height: 20px;
}

/** Controller placement */
.c input[type=text] {
.c input[type=text], .c canvas {
border: 0;
margin-top: 4px;
padding: 3px;
Expand All @@ -195,6 +195,12 @@ $button-height: 20px;
margin-left: 0;
}

/** Reduce margin and set height for plotter */
.c canvas {
padding: 0;
height: 53px;
}

.slider {
float: left;
width: 66%;
Expand Down
4 changes: 4 additions & 0 deletions src/dat/gui/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ $input-color: lighten($background-color, 8.5%);
border-left: 3px solid;
}

&.plotter {
height: 58px;
}

&.function {
border-left: 3px solid $function-color;
}
Expand Down
112 changes: 112 additions & 0 deletions src/dat/utils/plotter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
* dat-gui JavaScript Controller Library
* http://code.google.com/p/dat-gui
*
* Copyright 2011 Data Arts Team, Google Creative Lab
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*/

/**
* @author mrdoob / http://mrdoob.com/
* Original code from stats.js r17: https://github.com/mrdoob/stats.js
* Modified by MacroMan
* Licence from that project:

The MIT License

Copyright (c) 2009-2016 stats.js authors

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.
*/
const plotter = function(fg, bg, type) {
let min = Infinity;
let max = 0;
const round = Math.round;
const PR = round(window.devicePixelRatio || 1);

const WIDTH = 160 * PR;
const HEIGHT = 60 * PR;
const GRAPH_X = 3 * PR;
const GRAPH_Y = 3 * PR;
const GRAPH_WIDTH = 154 * PR;
const GRAPH_HEIGHT = 54 * PR;

const canvas = document.createElement('canvas');
canvas.width = WIDTH;
canvas.height = HEIGHT;

const context = canvas.getContext('2d');
context.font = 'bold ' + (9 * PR) + 'px Helvetica,Arial,sans-serif';
context.textBaseline = 'top';

context.fillStyle = bg;
context.fillRect(0, 0, WIDTH, HEIGHT);

context.fillStyle = fg;
context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);

context.fillStyle = bg;
context.globalAlpha = 0.9;
context.fillRect(GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT);

return {
dom: canvas,
update: function (value, maxValue) {
min = Math.min(min, value);
max = Math.max(max, value);

context.globalAlpha = 1;
context.fillStyle = fg;

// Move graph over 1px
context.drawImage(canvas, GRAPH_X + PR, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT, GRAPH_X, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT);

// Draw fg color
context.fillRect(GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, GRAPH_HEIGHT);

context.fillStyle = bg;
context.globalAlpha = 0.9;

// Blank out above the value
context.fillRect(
GRAPH_X + GRAPH_WIDTH - PR,
GRAPH_Y,
PR,
round((1 - (value / maxValue)) * GRAPH_HEIGHT)
);

// Blank out below the value if line
if (type === 'line') {
context.fillRect(
GRAPH_X + GRAPH_WIDTH - PR,
round((1 - (value / maxValue)) * GRAPH_HEIGHT) + PR + 3,
PR,
round((value / maxValue) * GRAPH_HEIGHT)
);
}
}
};
};

export default plotter;