diff --git a/example/app.js b/example/app.js
index aee2fc6..84a51a2 100644
--- a/example/app.js
+++ b/example/app.js
@@ -10,19 +10,6 @@ class App extends Component {
glPlot2d.defineGlPlot2d('gl-plot-2d');
}
- componentWillMount() {
- // TODO: Unique event names!
- document.addEventListener('gl-plot-2d-init-plot-done', () => {
- if (this.glPlot2dComponent1.plot) {
- this.glPlot2dComponent1.drawPlot();
- }
-
- if (this.glPlot2dComponent2.plot) {
- this.glPlot2dComponent2.drawPlot();
- }
- });
- }
-
makePlot1() {
const p1 = glPlot2d.getRandomPositions(1000);
const p2 = glPlot2d.getRandomPositions(100);
@@ -53,17 +40,18 @@ class App extends Component {
}
};
+ this.name1 = 'plot1';
this.traces1 = [trace1, trace2];
this.debug1 = true;
- this.height1 = '300px';
+ this.height1 = '200px';
this.width1 = '100%';
- const tickList = glPlot2d.getTicks(this.traces1, 'linear', 1, true);
+ const tickList = glPlot2d.getTicks(this.traces1, 'linear', 1, true, null);
this.plotOptions1 = {
pixelRatio: 1,
screenBox: null,
- dataBox: [tickList.t1[0].x - 0.25, tickList.t2[0].x - 0.25, tickList.t1[tickList.t1.length - 1].x + 0.25, tickList.t2[tickList.t2.length - 1].x + 0.25],
+ dataBox: [tickList.t1[0].x - 0.25, tickList.t2[0].x - 0.5, tickList.t1[tickList.t1.length - 1].x + 0.25, tickList.t2[tickList.t2.length - 1].x + 0.5],
viewBox: null,
titleEnabe: false,
title: '',
@@ -101,6 +89,7 @@ class App extends Component {
}
props(this.glPlot2dComponent1, {
+ name: this.name1,
traces: this.traces1,
debug: this.debug1,
height: this.height1,
@@ -110,8 +99,8 @@ class App extends Component {
}
makePlot2() {
- const p3 = glPlot2d.getRandomPositions(1000);
- const p4 = glPlot2d.getRandomPositions(100);
+ const p3 = glPlot2d.getRandomPositions(100);
+ const p4 = glPlot2d.getRandomPositions(1000);
const trace3 = {
mode: 'line',
@@ -139,17 +128,18 @@ class App extends Component {
}
};
+ this.name2 = 'plot2';
this.traces2 = [trace3, trace4];
this.debug2 = true;
- this.height2 = '300px';
+ this.height2 = '200px';
this.width2 = '100%';
- const tickList = glPlot2d.getTicks(this.traces1, 'log', 1, false);
+ const tickList = glPlot2d.getTicks(this.traces1, 'log', 1, true, null);
this.plotOptions2 = {
pixelRatio: 1,
screenBox: null,
- dataBox: [tickList.t1[0].x - 0.25, tickList.t2[0].x - 0.25, tickList.t1[tickList.t1.length - 1].x + 0.25, tickList.t2[tickList.t2.length - 1].x + 0.25],
+ dataBox: [tickList.t1[0].x - 0.25, tickList.t2[0].x - 0.5, tickList.t1[tickList.t1.length - 1].x + 0.25, tickList.t2[tickList.t2.length - 1].x + 0.5],
viewBox: null,
titleEnabe: false,
title: '',
@@ -187,6 +177,7 @@ class App extends Component {
}
props(this.glPlot2dComponent2, {
+ name: this.name2,
traces: this.traces2,
debug: this.debug2,
height: this.height2,
@@ -198,36 +189,25 @@ class App extends Component {
componentDidMount() {
this.makePlot1();
this.makePlot2();
+ window.dispatchEvent(new Event('resize'));
}
render() {
- let outerContainer = {
+ const outerContainer = {
width: '100%'
};
- let innerContainer = {
+ const innerContainer = {
paddingBottom: '0.5px'
};
return (
- { this.glPlot2dComponent1 = glPlot2dComponent1 }}
- traces={this.traces1}
- debug={this.debug1}
- height={this.height1}
- width={this.width1}
- plotOptions={this.plotOptions1} />
+ { this.glPlot2dComponent1 = glPlot2dComponent1 }}/>
- { this.glPlot2dComponent2 = glPlot2dComponent2 }}
- traces={this.traces2}
- debug={this.debug2}
- height={this.height2}
- width={this.width2}
- plotOptions={this.plotOptions2} />
+ { this.glPlot2dComponent2 = glPlot2dComponent2 }} />
);
diff --git a/src/GlPlot2dComponent.tsx b/src/GlPlot2dComponent.tsx
index 81994ae..7f30b91 100644
--- a/src/GlPlot2dComponent.tsx
+++ b/src/GlPlot2dComponent.tsx
@@ -35,6 +35,7 @@ export class GlPlot2dComponent extends skate.Component {
static get props(): skate.ComponentProps {
return {
// Custom.
+ name: skate.prop.string({ attribute: true }),
traces: skate.prop.array({
attribute: true,
coerce(traces) {
@@ -91,10 +92,12 @@ export class GlPlot2dComponent extends skate.Component {
* @memberOf GlPlot2dComponent
*/
public renderedCallback(): void {
- if (this.shadowRoot && !this.canvas) {
+ if (this.shadowRoot && !this.canvas && !this.plot) {
this.canvas = this.shadowRoot.querySelector('canvas');
- this.initResize();
+ this.initResizeEvents();
this.initPlot();
+ this.fitCanvas();
+ this.drawPlot();
}
}
@@ -115,14 +118,14 @@ export class GlPlot2dComponent extends skate.Component {
case 'plot-options':
if (newValue) {
this['plotOptions'] = JSON.parse(newValue);
- this['plotOptions'].gl = this.gl;
}
break;
default:
break;
}
- this.plot.update(this['plotOptions']);
+ this['plotOptions'].gl = this.gl;
+ this.fitCanvas();
this.drawPlot();
}
}
@@ -148,13 +151,10 @@ export class GlPlot2dComponent extends skate.Component {
* @memberOf GlPlot2dComponent
*/
public getStyles(): string {
- const width = this['width'];
- const height = this['height'];
-
const styles = `
div {
- width: ${width};
- height: ${height};
+ width: ${this['width']};
+ height: ${this['height']};
}
canvas {
@@ -166,49 +166,46 @@ export class GlPlot2dComponent extends skate.Component {
}
/**
- * Resize function that uses canvas-fit.
- * Sets the viewBox to contain the entire containing div.
+ * Resize fit canvas function that uses canvas-fit.
+ * Sets the viewBox to contain the entire surrounding div.
*
* @memberOf GlPlot2dComponent
*/
- public resize(): void {
+ public fitCanvas(): void {
// Setup fit().
const resize = fit(this.canvas, null, +window.devicePixelRatio);
if (this.shadowRoot) {
// Get the div around the canvas.
- let div = this.shadowRoot.querySelector('div');
+ const div = this.shadowRoot.querySelector('div');
if (div) {
- let boundingClientRect = div.getBoundingClientRect();
+ const boundingClientRect = div.getBoundingClientRect();
+
+ // Set the viewBox to contain the entire surrounding div.
+ // TODO: Parameterize the viewBox.
this['plotOptions'].viewBox = [50, 1, boundingClientRect.width - 1, boundingClientRect.height - 1];
}
}
- // Resize after setting up fit().
+ // Trigger resize.
resize();
}
/**
- * Helper function that initializes resize canvas logic.
+ * Helper function that initializes resize events.
* Should be only called once on component initialization.
*
* @memberOf GlPlot2dComponent
*/
- public initResize(): void {
- this.resize();
-
+ public initResizeEvents(): void {
// Debounce the resize call.
const debounceResize = debounce(() => {
- this.resize();
-
- if (this.plot) {
- this.plot.update(this['plotOptions']);
- this.drawPlot();
- }
+ this.fitCanvas();
+ this.drawPlot();
}, 200);
- // Setup resize event listener.
+ // Setup debounced window resize event listener.
window.addEventListener('resize', debounceResize, false);
}
@@ -238,7 +235,6 @@ export class GlPlot2dComponent extends skate.Component {
}
this['plotOptions'].gl = this.gl;
-
this.plot = createPlot(this['plotOptions']);
this['traces'].forEach((trace: Trace) => {
@@ -250,7 +246,7 @@ export class GlPlot2dComponent extends skate.Component {
}
});
- skate.emit(this, 'gl-plot-2d-init-plot-done');
+ skate.emit(this, `gl-plot-2d-init-plot-done-${this['name']}`);
}
/**
@@ -259,6 +255,9 @@ export class GlPlot2dComponent extends skate.Component {
* @memberOf GlPlot2dComponent
*/
public drawPlot(): void {
+ // Make sure plot is updated with current plotOptions before drawing.
+ this.plot.update(this['plotOptions']);
+
if (this['debug']) {
console.time('drawTime');
}
@@ -269,7 +268,7 @@ export class GlPlot2dComponent extends skate.Component {
console.timeEnd('drawTime');
}
- skate.emit(this, 'gl-plot-2d-draw-plot-done');
+ skate.emit(this, `gl-plot-2d-draw-plot-done-${this['name']}`);
}
/**
diff --git a/src/GlPlot2dComponentProps.ts b/src/GlPlot2dComponentProps.ts
index a046653..c080f1a 100644
--- a/src/GlPlot2dComponentProps.ts
+++ b/src/GlPlot2dComponentProps.ts
@@ -10,6 +10,7 @@ import { GlPlot2dOptions, Trace } from './';
*/
export interface GlPlot2dComponentProps {
// Custom.
+ name: string;
traces: Trace[];
debug: boolean;
height: string;
diff --git a/src/GlPlot2dUtils.ts b/src/GlPlot2dUtils.ts
index eb0bab4..2218964 100644
--- a/src/GlPlot2dUtils.ts
+++ b/src/GlPlot2dUtils.ts
@@ -52,7 +52,38 @@ export function getLogTicks(lo: number,
precision: number,
nice: boolean): Tick[] {
let scale = d3Scale.scaleLog()
- .domain([Math.max(1, Math.floor(lo)), Math.ceil(hi)]);
+ .domain([Math.max(1.0, Math.floor(lo)), Math.ceil(hi)]);
+
+ if (nice) {
+ scale = scale.nice();
+ }
+
+ const ticks = scale.ticks();
+
+ return ticks.map((tick: number) => new Tick(round(tick, precision)));
+}
+
+/**
+ * Helper function to make count pow tick marks on domain lo to hi.
+ * Uses d3-scale to do so.
+ * Coerces tick number[] to Tick[].
+ *
+ * @export
+ * @param {number} lo
+ * @param {number} hi
+ * @param {number} precision
+ * @param {boolean} nice
+ * @param {number} exponent
+ * @returns {Tick[]}
+ */
+export function getPowTicks(lo: number,
+ hi: number,
+ precision: number,
+ nice: boolean,
+ exponent: number): Tick[] {
+ let scale = d3Scale.scalePow()
+ .exponent(exponent)
+ .domain([lo, hi]);
if (nice) {
scale = scale.nice();
@@ -129,19 +160,21 @@ export function getRandomPositions(count: number): any {
/**
* Gets ticks by type.
- * Supported types are linear and log.
+ * Supported types are linear, log, and pow.
*
* @export
* @param {Trace[]} traces
* @param {string} type
* @param {number} precision
* @param {boolean} nice
+ * @param {number} exponent
* @returns {TickListPair}
*/
export function getTicks(traces: Trace[],
type: string,
precision: number,
- nice: boolean): TickListPair {
+ nice: boolean,
+ exponent: number): TickListPair {
const minMax = getMinMax(traces);
let xTicks: Tick[] = [];
@@ -155,6 +188,10 @@ export function getTicks(traces: Trace[],
xTicks = getLogTicks(minMax.p1.x, minMax.p2.x, precision, nice);
yTicks = getLogTicks(minMax.p1.y, minMax.p2.y, precision, nice);
}
+ else if (type === 'pow') {
+ xTicks = getPowTicks(minMax.p1.x, minMax.p2.x, precision, nice, exponent);
+ yTicks = getPowTicks(minMax.p1.y, minMax.p2.y, precision, nice, exponent);
+ }
return new TickListPair(xTicks, yTicks);
}
diff --git a/tslint.json b/tslint.json
index fe40571..c128dd5 100644
--- a/tslint.json
+++ b/tslint.json
@@ -4,6 +4,7 @@
"curly": true,
"interface-name": [true, "never-prefix"],
"no-console": [true, "log"],
+ "no-debugger": false,
"no-string-literal": false,
"object-literal-sort-keys": false,
"one-line": [false, "check-catch", "check-finally", "check-else"],