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;