From 66eecdc636b321282f7864d14fb6188e3cc1ab66 Mon Sep 17 00:00:00 2001 From: vargburz Date: Thu, 28 Oct 2021 14:19:56 +0300 Subject: [PATCH 1/5] add grid as a separate class --- src/components/grid.ts | 100 +++++++++++++++++++++++++++++++++++++++++ src/types.ts | 21 ++++----- 2 files changed, 111 insertions(+), 10 deletions(-) create mode 100644 src/components/grid.ts diff --git a/src/components/grid.ts b/src/components/grid.ts new file mode 100644 index 0000000..8f1ab90 --- /dev/null +++ b/src/components/grid.ts @@ -0,0 +1,100 @@ +import { GridOptions } from '../types'; + + +// we import only d3 types here +import * as d3 from 'd3'; + +import defaultsDeep from 'lodash/defaultsDeep'; + +const DEFAULT_GRID_TICK_COUNT = 5; +const DEFAULT_GRID_OPTIONS = { + x: { + isActive: true, + ticksCount: DEFAULT_GRID_TICK_COUNT, + }, + y: { + isActive: true, + ticksCount: DEFAULT_GRID_TICK_COUNT, + }, +} +export type SvgElOptions = { + height: number, + width: number, + xScale: d3.ScaleLinear, + yScale: d3.ScaleLinear, +} + + +// Grid Class - is a core component, which can be a separate Pod in the future. (but not in current Pod terminology) +// All components have construcor with required args: svg element which will be filled with this component and options for it. +// All compoтents have a reqiured method "render", which will be called in core costructor. <- this solution is temporary. +// svgElement should be a separate class with its own height, width, xScale, yScale params to avoid SvgElOptions as argument. +// We have a general problem with passing d3 as argument everywhere. Fix it, and remove from arg in constructor here. +export class Grid { + _gridOptions: GridOptions; + + constructor( + private _d3: typeof d3, + private _svgEl: d3.Selection, + private _svgElOptions: SvgElOptions, + gridOptions: GridOptions, + ) { + this._gridOptions = this.setOptionDefaults(gridOptions); + + this.render(); + } + + protected setOptionDefaults(gridOptions: GridOptions): GridOptions { + return defaultsDeep(gridOptions, DEFAULT_GRID_OPTIONS); + } + + render(): void { + // TODO: temporary. Move out of here + this._svgEl.selectAll('.grid').remove(); + + this.renderGridLinesX(); + this.renderGridLinesY(); + this.updateStylesOfTicks(); + } + + renderGridLinesX(): void { + if(!this._gridOptions.x.isActive) { + return; + } + this._svgEl + .append('g') + .attr('transform', `translate(0,${this._svgElOptions.height})`) + .attr('class', 'grid x-grid') + .style('pointer-events', 'none') + .call( + this._d3.axisBottom(this._svgElOptions.xScale) + .ticks(this._gridOptions.x.ticksCount) + .tickSize(-this._svgElOptions.height) + .tickFormat(() => '') + ); + } + + renderGridLinesY(): void { + if(!this._gridOptions.y.isActive) { + return; + } + this._svgEl + .append('g') + .attr('class', 'grid y-grid') + .style('pointer-events', 'none') + .call( + this._d3.axisLeft(this._svgElOptions.yScale) + .ticks(this._gridOptions.y.ticksCount) + .tickSize(-this._svgElOptions) + .tickFormat(() => '') + ); + } + + updateStylesOfTicks(): void { + // TODO: add options for these actions + this._svgEl.selectAll('.grid').selectAll('.tick') + .attr('opacity', '0.5'); + this._svgEl.selectAll('.grid').select('.domain') + .style('pointer-events', 'none'); + } +} diff --git a/src/types.ts b/src/types.ts index b49967d..e2dfbcd 100644 --- a/src/types.ts +++ b/src/types.ts @@ -30,16 +30,7 @@ export type Options = { y?: AxisOption, y1?: AxisOption }; - grid?: { - x?: { - isActive?: boolean; - ticksCount?: number; - }, - y?: { - isActive?: boolean; - ticksCount?: number; - }, - }; + grid?: GridOptions; crosshair?: { orientation?: CrosshairOrientation; color?: string; @@ -93,6 +84,16 @@ export type Options = { renderTicksfromTimestamps?: boolean; renderLegend?: boolean; }; +export type GridOptions = { + x?: { + isActive?: boolean; + ticksCount?: number; + }, + y?: { + isActive?: boolean; + ticksCount?: number; + }, +} export type AxisOption = { isActive?: boolean; ticksCount?: number; From fe89851de739afe4dcea292b8a24e96db5d04a86 Mon Sep 17 00:00:00 2001 From: vargburz Date: Thu, 28 Oct 2021 14:45:02 +0300 Subject: [PATCH 2/5] note --- src/components/grid.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/grid.ts b/src/components/grid.ts index 8f1ab90..45df12c 100644 --- a/src/components/grid.ts +++ b/src/components/grid.ts @@ -40,7 +40,8 @@ export class Grid { gridOptions: GridOptions, ) { this._gridOptions = this.setOptionDefaults(gridOptions); - + + // TODO: or public method that will be called outside this.render(); } From c38263ed3645252409bf60c8e466699618b2c14d Mon Sep 17 00:00:00 2001 From: vargburz Date: Fri, 29 Oct 2021 15:51:21 +0300 Subject: [PATCH 3/5] use grid in core constructor --- src/components/grid.ts | 27 ++++++---------- src/index.ts | 72 ++++++++++++++---------------------------- src/types.ts | 6 ++++ 3 files changed, 39 insertions(+), 66 deletions(-) diff --git a/src/components/grid.ts b/src/components/grid.ts index 45df12c..424602e 100644 --- a/src/components/grid.ts +++ b/src/components/grid.ts @@ -1,4 +1,4 @@ -import { GridOptions } from '../types'; +import { GridOptions, SvgElOptions } from '../types'; // we import only d3 types here @@ -17,12 +17,6 @@ const DEFAULT_GRID_OPTIONS = { ticksCount: DEFAULT_GRID_TICK_COUNT, }, } -export type SvgElOptions = { - height: number, - width: number, - xScale: d3.ScaleLinear, - yScale: d3.ScaleLinear, -} // Grid Class - is a core component, which can be a separate Pod in the future. (but not in current Pod terminology) @@ -31,25 +25,22 @@ export type SvgElOptions = { // svgElement should be a separate class with its own height, width, xScale, yScale params to avoid SvgElOptions as argument. // We have a general problem with passing d3 as argument everywhere. Fix it, and remove from arg in constructor here. export class Grid { - _gridOptions: GridOptions; + protected gridOptions: GridOptions; constructor( private _d3: typeof d3, private _svgEl: d3.Selection, private _svgElOptions: SvgElOptions, - gridOptions: GridOptions, + _gridOptions: GridOptions, ) { - this._gridOptions = this.setOptionDefaults(gridOptions); - - // TODO: or public method that will be called outside - this.render(); + this.gridOptions = this.setOptionDefaults(_gridOptions); } protected setOptionDefaults(gridOptions: GridOptions): GridOptions { return defaultsDeep(gridOptions, DEFAULT_GRID_OPTIONS); } - render(): void { + public render(): void { // TODO: temporary. Move out of here this._svgEl.selectAll('.grid').remove(); @@ -59,7 +50,7 @@ export class Grid { } renderGridLinesX(): void { - if(!this._gridOptions.x.isActive) { + if(!this.gridOptions.x.isActive) { return; } this._svgEl @@ -69,14 +60,14 @@ export class Grid { .style('pointer-events', 'none') .call( this._d3.axisBottom(this._svgElOptions.xScale) - .ticks(this._gridOptions.x.ticksCount) + .ticks(this.gridOptions.x.ticksCount) .tickSize(-this._svgElOptions.height) .tickFormat(() => '') ); } renderGridLinesY(): void { - if(!this._gridOptions.y.isActive) { + if(!this.gridOptions.y.isActive) { return; } this._svgEl @@ -85,7 +76,7 @@ export class Grid { .style('pointer-events', 'none') .call( this._d3.axisLeft(this._svgElOptions.yScale) - .ticks(this._gridOptions.y.ticksCount) + .ticks(this.gridOptions.y.ticksCount) .tickSize(-this._svgElOptions) .tickFormat(() => '') ); diff --git a/src/index.ts b/src/index.ts index b1f7704..e966ff3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,6 @@ import VueChartwerkPodMixin from './VueChartwerkPodMixin'; import { PodState } from './state'; +import { Grid } from './components/grid'; import styles from './css/style.css'; @@ -17,7 +18,8 @@ import { PanOrientation, yAxisOrientation, ScrollPanOrientation, - AxisOption + AxisOption, + SvgElOptions, } from './types'; import { uid } from './utils'; import { palette } from './colors'; @@ -101,16 +103,6 @@ const DEFAULT_OPTIONS: Options = { format: AxisFormat.NUMERIC } }, - grid: { - x: { - isActive: true, - ticksCount: 5, - }, - y: { - isActive: true, - ticksCount: 5, - }, - }, crosshair: { orientation: CrosshairOrientation.VERTICAL, color: 'red' @@ -146,6 +138,9 @@ abstract class ChartwerkPod { protected deltaYTransform = 0; protected debouncedRender = debounce(this.render.bind(this), 100); + // components + protected grid: Grid; + // TODO: test variables instead of functions with cache private _xScale: d3.ScaleLinear | null = null; private _yScale: d3.ScaleLinear | null = null; @@ -172,6 +167,9 @@ abstract class ChartwerkPod { this.d3Node = this.d3.select(this.el); this.addEventListeners(); + + this.createSvg(); + this.initComponents(); } protected addEventListeners(): void { @@ -185,7 +183,6 @@ abstract class ChartwerkPod { public render(): void { this.clearScaleCache(); - this.renderSvg(); this.renderAxes(); this.renderGrid(); @@ -237,11 +234,23 @@ abstract class ChartwerkPod { public abstract renderSharedCrosshair(values: { x?: number, y?: number }): void; public abstract hideSharedCrosshair(): void; - protected initPodState() { + protected initPodState(): void { this.state = new PodState(this.options); } - protected renderSvg(): void { + protected initComponents(): void { + // TODO: make chartContainer a separate class with SvgElOptions inside to avoid duplication + const svgElOptions = { + height: this.height, + width: this.width, + xScale: this.xScale, + yScale: this.yScale, + } + + this.grid = new Grid(this.d3, this.chartContainer, svgElOptions, this.options.grid); + } + + protected createSvg(): void { this.d3Node.select('svg').remove(); this.svg = this.d3Node .append('svg') @@ -254,40 +263,7 @@ abstract class ChartwerkPod { } protected renderGrid(): void { - this.chartContainer.selectAll('.grid').remove(); - - if(this.options.grid.x.isActive) { - this.chartContainer - .append('g') - .attr('transform', `translate(0,${this.height})`) - .attr('class', 'grid x-grid') - .style('pointer-events', 'none') - .call( - this.d3.axisBottom(this.xScale) - .ticks(this.options.grid.x.ticksCount) - .tickSize(-this.height) - .tickFormat(() => '') - ); - } - - if(this.options.grid.y.isActive) { - this.chartContainer - .append('g') - .attr('class', 'grid y-grid') - .style('pointer-events', 'none') - .call( - this.d3.axisLeft(this.yScale) - .ticks(this.options.grid.y.ticksCount) - .tickSize(-this.width) - .tickFormat(() => '') - ); - } - - this.chartContainer.selectAll('.grid').selectAll('.tick') - .attr('opacity', '0.5'); - - this.chartContainer.selectAll('.grid').select('.domain') - .style('pointer-events', 'none'); + this.grid.render(); } protected renderAxes(): void { diff --git a/src/types.ts b/src/types.ts index e2dfbcd..a082abb 100644 --- a/src/types.ts +++ b/src/types.ts @@ -165,3 +165,9 @@ export enum yAxisOrientation { RIGHT = 'right', BOTH = 'both' } +export type SvgElOptions = { + height: number, + width: number, + xScale: d3.ScaleLinear, + yScale: d3.ScaleLinear, +} From ee9e6f51a8b03641d5753bb70ed4ee95cb48fb59 Mon Sep 17 00:00:00 2001 From: vargburz Date: Fri, 29 Oct 2021 16:00:38 +0300 Subject: [PATCH 4/5] grid: isActive -> enabeld --- src/components/grid.ts | 11 ++++++----- src/types.ts | 4 ++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/components/grid.ts b/src/components/grid.ts index 424602e..2b097d8 100644 --- a/src/components/grid.ts +++ b/src/components/grid.ts @@ -7,13 +7,13 @@ import * as d3 from 'd3'; import defaultsDeep from 'lodash/defaultsDeep'; const DEFAULT_GRID_TICK_COUNT = 5; -const DEFAULT_GRID_OPTIONS = { +const DEFAULT_GRID_OPTIONS: GridOptions = { x: { - isActive: true, + enabled: true, ticksCount: DEFAULT_GRID_TICK_COUNT, }, y: { - isActive: true, + enabled: true, ticksCount: DEFAULT_GRID_TICK_COUNT, }, } @@ -22,6 +22,7 @@ const DEFAULT_GRID_OPTIONS = { // Grid Class - is a core component, which can be a separate Pod in the future. (but not in current Pod terminology) // All components have construcor with required args: svg element which will be filled with this component and options for it. // All compoтents have a reqiured method "render", which will be called in core costructor. <- this solution is temporary. +// Each component has its own default options. // svgElement should be a separate class with its own height, width, xScale, yScale params to avoid SvgElOptions as argument. // We have a general problem with passing d3 as argument everywhere. Fix it, and remove from arg in constructor here. export class Grid { @@ -50,7 +51,7 @@ export class Grid { } renderGridLinesX(): void { - if(!this.gridOptions.x.isActive) { + if(!this.gridOptions.x.enabled) { return; } this._svgEl @@ -67,7 +68,7 @@ export class Grid { } renderGridLinesY(): void { - if(!this.gridOptions.y.isActive) { + if(!this.gridOptions.y.enabled) { return; } this._svgEl diff --git a/src/types.ts b/src/types.ts index a082abb..249fa7d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -86,11 +86,11 @@ export type Options = { }; export type GridOptions = { x?: { - isActive?: boolean; + enabled?: boolean; ticksCount?: number; }, y?: { - isActive?: boolean; + enabled?: boolean; ticksCount?: number; }, } From 1d2050ce7ae1e9e1bc4fe0459c4db02518c6ac1f Mon Sep 17 00:00:00 2001 From: vargburz Date: Fri, 29 Oct 2021 16:49:21 +0300 Subject: [PATCH 5/5] svgElOptions -> svgElParams --- src/components/grid.ts | 16 ++++++++-------- src/index.ts | 8 ++++---- src/types.ts | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/components/grid.ts b/src/components/grid.ts index 2b097d8..a9bdd49 100644 --- a/src/components/grid.ts +++ b/src/components/grid.ts @@ -1,4 +1,4 @@ -import { GridOptions, SvgElOptions } from '../types'; +import { GridOptions, SvgElParams } from '../types'; // we import only d3 types here @@ -23,7 +23,7 @@ const DEFAULT_GRID_OPTIONS: GridOptions = { // All components have construcor with required args: svg element which will be filled with this component and options for it. // All compoтents have a reqiured method "render", which will be called in core costructor. <- this solution is temporary. // Each component has its own default options. -// svgElement should be a separate class with its own height, width, xScale, yScale params to avoid SvgElOptions as argument. +// svgElement should be a separate class with its own height, width, xScale, yScale params to avoid SvgElParams as argument. // We have a general problem with passing d3 as argument everywhere. Fix it, and remove from arg in constructor here. export class Grid { protected gridOptions: GridOptions; @@ -31,7 +31,7 @@ export class Grid { constructor( private _d3: typeof d3, private _svgEl: d3.Selection, - private _svgElOptions: SvgElOptions, + private _svgElParams: SvgElParams, _gridOptions: GridOptions, ) { this.gridOptions = this.setOptionDefaults(_gridOptions); @@ -56,13 +56,13 @@ export class Grid { } this._svgEl .append('g') - .attr('transform', `translate(0,${this._svgElOptions.height})`) + .attr('transform', `translate(0,${this._svgElParams.height})`) .attr('class', 'grid x-grid') .style('pointer-events', 'none') .call( - this._d3.axisBottom(this._svgElOptions.xScale) + this._d3.axisBottom(this._svgElParams.xScale) .ticks(this.gridOptions.x.ticksCount) - .tickSize(-this._svgElOptions.height) + .tickSize(-this._svgElParams.height) .tickFormat(() => '') ); } @@ -76,9 +76,9 @@ export class Grid { .attr('class', 'grid y-grid') .style('pointer-events', 'none') .call( - this._d3.axisLeft(this._svgElOptions.yScale) + this._d3.axisLeft(this._svgElParams.yScale) .ticks(this.gridOptions.y.ticksCount) - .tickSize(-this._svgElOptions) + .tickSize(-this._svgElParams) .tickFormat(() => '') ); } diff --git a/src/index.ts b/src/index.ts index e966ff3..e2aa858 100644 --- a/src/index.ts +++ b/src/index.ts @@ -19,7 +19,7 @@ import { yAxisOrientation, ScrollPanOrientation, AxisOption, - SvgElOptions, + SvgElParams, } from './types'; import { uid } from './utils'; import { palette } from './colors'; @@ -239,15 +239,15 @@ abstract class ChartwerkPod { } protected initComponents(): void { - // TODO: make chartContainer a separate class with SvgElOptions inside to avoid duplication - const svgElOptions = { + // TODO: make chartContainer a separate class with SvgElParams inside to avoid duplication + const svgElParams = { height: this.height, width: this.width, xScale: this.xScale, yScale: this.yScale, } - this.grid = new Grid(this.d3, this.chartContainer, svgElOptions, this.options.grid); + this.grid = new Grid(this.d3, this.chartContainer, svgElParams, this.options.grid); } protected createSvg(): void { diff --git a/src/types.ts b/src/types.ts index 249fa7d..5a898a5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -165,7 +165,7 @@ export enum yAxisOrientation { RIGHT = 'right', BOTH = 'both' } -export type SvgElOptions = { +export type SvgElParams = { height: number, width: number, xScale: d3.ScaleLinear,