diff --git a/src/index.ts b/src/index.ts index 331cec9..7632605 100644 --- a/src/index.ts +++ b/src/index.ts @@ -107,13 +107,13 @@ const DEFAULT_OPTIONS: Options = { abstract class ChartwerkPod { protected d3Node?: d3.Selection; - protected chartContainer?: d3.Selection; protected customOverlay?: d3.Selection; protected crosshair?: d3.Selection; protected brush?: d3.BrushBehavior; protected zoom?: any; protected svg?: d3.Selection; - protected state?: PodState; + protected state: PodState; + protected pan?: any; // TODO: not any; protected clipPath?: any; protected isPanning = false; protected isBrushing = false; @@ -131,7 +131,10 @@ abstract class ChartwerkPod { protected readonly d3: typeof d3; protected deltaYTransform = 0; protected debouncedRender = debounce(this.render.bind(this), 100); - + // containers + // TODO: add better names + protected chartContainer: d3.Selection; + protected metricContainer: d3.Selection; // components protected grid: Grid; @@ -175,6 +178,7 @@ abstract class ChartwerkPod { this.addEvents(); this.renderCrosshair(); + this.renderMetricsContainer(); this.renderMetrics(); this.renderLegend(); @@ -201,7 +205,7 @@ abstract class ChartwerkPod { let options = cloneDeep(newOptions); defaultsDeep(options, DEFAULT_OPTIONS); this.options = options; - + // TODO: update state if axis ranges were changed } protected updateSeries(newSeries: T[]): void { @@ -240,6 +244,22 @@ abstract class ChartwerkPod { this.grid = new Grid(this.d3, this.chartContainer, svgElParams, this.options.grid); } + protected renderMetricsContainer(): void { + this.d3.select('.metrics-container').remove(); + + // TODO: it should be a class with svgElParams as fields + // container for clip path + const clipContatiner = this.chartContainer + .append('g') + .attr('clip-path', `url(#${this.rectClipId})`) + .attr('class', 'metrics-container'); + + // container for panning + this.metricContainer = clipContatiner + .append('g') + .attr('class', 'metrics-rect'); + } + protected createSvg(): void { this.d3Node.select('svg').remove(); this.svg = this.d3Node @@ -329,6 +349,8 @@ abstract class ChartwerkPod { } protected renderCrosshair(): void { + this.d3.selectAll('#crosshair-container').remove(); + this.crosshair = this.chartContainer.append('g') .attr('id', 'crosshair-container') .style('display', 'none'); @@ -463,11 +485,11 @@ abstract class ChartwerkPod { if(this.options.axis.y1.isActive === true) { this.initScaleY1 = this.y1Scale.copy(); } - const pan = this.d3.zoom() + this.pan = this.d3.zoom() .on('zoom', this.onPanning.bind(this)) .on('end', this.onPanningEnd.bind(this)); - this.chartContainer.call(pan); + this.chartContainer.call(this.pan); } protected renderClipPath(): void { @@ -592,13 +614,11 @@ abstract class ChartwerkPod { public rescaleMetricAndAxis(event: d3.D3ZoomEvent): void { this.isPanning = true; this.onMouseOut(); - this.onPanningRescale(event); // TODO: check clear state for necessity this.renderYAxis(); this.renderXAxis(); - // metrics-rect wrapper is required for panning this.chartContainer.select('.metrics-rect') .attr('transform', `translate(${this.state.transform.x},${this.state.transform.y}), scale(${this.state.transform.k})`); diff --git a/src/state.ts b/src/state.ts index d5afd72..b042fb2 100755 --- a/src/state.ts +++ b/src/state.ts @@ -21,7 +21,8 @@ const DEFAULT_TRANSFORM = { // TODO: replace all getters with fields. Because getters will be recalculated on each call. Use scales as example. // TODO: remove duplicates in max/min values. -// TODO: PodState can be divided in two classes, but it is hard now. +// TODO: PodState can be divided in two classes, but it is hard now. +// TODO: PodState.transform has conflicts with d3.zoom.event.transform. It should be synchronized. export class PodState { private _xValueRange: [number, number]; private _yValueRange: [number, number];