Skip to content

Commit

Permalink
Merge pull request #855 from scottdickerson/fix-zoombar-scale
Browse files Browse the repository at this point in the history
* fix(zoombar): cache zoombar data and zoombar default domain

* fix(zoombar): cache custom zoom bar data in the model

* fix(zoombar): cache custom zoom bar data in the model

* Update packages/core/stories/utils.ts

Co-authored-by: Eliad Moosavi <theiliad@users.noreply.github.com>

* fix(zoombar): still need to sanitize

* test(dev): remove dev stories

* refactor(model-zoom): move methods zoom bar specific to model-zoom

* refactor(model-zoom): rename to model-cartesian-charts

* fix(lint): fix lint issue

* fix(stories): remove from non core stories

* fix(stories): remove from non core stories

Co-authored-by: Eliad Moosavi <theiliad@users.noreply.github.com>
  • Loading branch information
scottdickerson and theiliad authored Nov 6, 2020
1 parent 80d6906 commit 27e1725
Show file tree
Hide file tree
Showing 13 changed files with 242 additions and 148 deletions.
3 changes: 3 additions & 0 deletions packages/angular/stories/all.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ storybookDemoGroups.forEach(demoGroup => {

// Loop through the demos for the group
demoGroup.demos.forEach(demo => {
if (demo.isHighScale) {
return;
}
groupStories.add(demo.title, () => ({
template: getTemplate(demo),
moduleMetadata: {
Expand Down
7 changes: 7 additions & 0 deletions packages/core/demo/data/high-scale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { addZoomBarToOptions } from "./zoom-bar";
import * as lineChart from "./line";

export const zoomBarHighScaleLineTimeSeriesOptions = addZoomBarToOptions(
Object.assign({ highScale: true }, lineChart.lineTimeSeriesOptions)
);
zoomBarHighScaleLineTimeSeriesOptions["title"] = "High scale (zoom bar)";
79 changes: 52 additions & 27 deletions packages/core/demo/data/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as timeSeriesAxisDemos from "./time-series-axis";
import * as radarDemos from "./radar";
import * as toolbarDemos from "./toolbar";
import * as zoomBarDemos from "./zoom-bar";
import * as highScaleDemos from "./high-scale";

export * from "./area";
export * from "./bar";
Expand Down Expand Up @@ -886,46 +887,70 @@ let allDemoGroups = [
}
] as any;

const devOnlyDemoGroups = [
{
title: "High scale tests (DEV)",
demos: [
{
options: highScaleDemos.zoomBarHighScaleLineTimeSeriesOptions,
data: [],
isHighScale: true,
chartType: chartTypes.LineChart,
isDemoExample: false
}
]
}
] as any;

const formatTitleString = (str) =>
str
.replace(/[^\w\s]/gi, "")
.replace(/\s\s+/g, " ")
.toLowerCase()
.replace(/\s+/g, "-");

// add codesandbox and code to demos
allDemoGroups = allDemoGroups.map((demoGroup) => {
demoGroup.demos = demoGroup.demos.map((demo) => {
demo.title = demo.options.title;
demo.id = `${formatTitleString(demoGroup.title)}--${formatTitleString(
demo.options.title
)}`;
const mapDemoGroups = (demoGroups) =>
demoGroups.map((demoGroup) => {
demoGroup.demos = demoGroup.demos.map((demo) => {
demo.title = demo.options.title;
demo.id = `${formatTitleString(
demoGroup.title
)}--${formatTitleString(demo.options.title)}`;

// if there isnt a height set in the chart options, use 400
demo.options.height = demo.options.height ?? "400px";
// if there isnt a height set in the chart options, use 400
demo.options.height = demo.options.height ?? "400px";

if (!demo.codesandbox) {
demo.codesandbox = {};
}
demo.codesandbox.react = createChartSandbox(createReactChartApp(demo));
demo.codesandbox.vue = createChartSandbox(createVueChartApp(demo));
demo.codesandbox.vanilla = createChartSandbox(
createVanillaChartApp(demo)
);
demo.codesandbox.svelte = createChartSandbox(
createSvelteChartApp(demo)
);
if (!demo.codesandbox) {
demo.codesandbox = {};
}
demo.codesandbox.react = createChartSandbox(
createReactChartApp(demo)
);
demo.codesandbox.vue = createChartSandbox(createVueChartApp(demo));
demo.codesandbox.vanilla = createChartSandbox(
createVanillaChartApp(demo)
);
demo.codesandbox.svelte = createChartSandbox(
createSvelteChartApp(demo)
);

if (!demo.code) {
demo.code = {};
}
demo.code.angular = createAngularChartApp(demo);
if (!demo.code) {
demo.code = {};
}
demo.code.angular = createAngularChartApp(demo);

return demo;
});

return demo;
return demoGroup;
});
// add codesandbox and code to demos
allDemoGroups = mapDemoGroups(allDemoGroups);

return demoGroup;
});
// Only add the high-scale testcases in dev
if (process.env.NODE_ENV !== "production") {
allDemoGroups = allDemoGroups.concat(mapDemoGroups(devOnlyDemoGroups));
}

// in the storybook we want to show all the demos
export const storybookDemoGroups = allDemoGroups;
Expand Down
4 changes: 2 additions & 2 deletions packages/core/demo/data/zoom-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const definedZoomBarData = [
];

// utility function to update title and enable zoomBar option
const addZoomBarToOptions = (
export const addZoomBarToOptions = (
options,
configs: any = { includeDefinedZoomBarData: false }
) => {
Expand Down Expand Up @@ -234,5 +234,5 @@ export const zoomBarSkeletonOptions = addZoomBarToOptions(
barChart.stackedBarTimeSeriesOptions
)
);
zoomBarSkeletonOptions.title = "Zoom bar (skeleton)";
zoomBarSkeletonOptions["title"] = "Zoom bar (skeleton)";
zoomBarSkeletonOptions.zoomBar.top.loading = true;
2 changes: 2 additions & 0 deletions packages/core/src/axis-chart.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Chart } from "./chart";
import { ChartModelCartesian } from "./model-cartesian-charts";
import {
LayoutDirection,
LayoutGrowth,
Expand Down Expand Up @@ -30,6 +31,7 @@ export class AxisChart extends Chart {
curves: Curves,
zoom: Zoom
});
model: ChartModelCartesian = new ChartModelCartesian(this.services);

constructor(holder: Element, chartConfigs: ChartConfig<AxisChartOptions>) {
super(holder, chartConfigs);
Expand Down
40 changes: 33 additions & 7 deletions packages/core/src/components/axes/zoom-bar.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Internal Imports
import { Component } from "../component";
import { ChartModelCartesian } from "../../model-cartesian-charts";
import { Tools } from "../../tools";
import {
AxisPositions,
Expand All @@ -9,6 +10,7 @@ import {
} from "../../interfaces";
import { DOMUtils } from "../../services";
import * as Configuration from "../../configuration";
import isEmpty from "lodash/isEmpty";

// D3 Imports
import { extent } from "d3-array";
Expand All @@ -17,6 +19,7 @@ import { area, line } from "d3-shape";
import { event } from "d3-selection";

export class ZoomBar extends Component {
protected model: ChartModelCartesian;
type = "zoom-bar";

// The minimum selection x range to trigger handler update
Expand All @@ -43,6 +46,16 @@ export class ZoomBar extends Component {
Events.ZoomBar.UPDATE,
this.render.bind(this)
);
// check if pre-defined zoom bar data exists
const definedZoomBarData = Tools.getProperty(
this.model.getOptions(),
"zoomBar",
AxisPositions.TOP,
"data"
);

// load up the zoomBarData into this model
this.model.setZoomBarData(definedZoomBarData);
}

render(animate = true) {
Expand Down Expand Up @@ -115,14 +128,23 @@ export class ZoomBar extends Component {
const mainXScaleType = cartesianScales.getMainXScaleType();

if (mainXScale && mainXScaleType === ScaleTypes.TIME) {
const zoomBarData = this.services.zoom.getZoomBarData();
let zoomBarData = this.services.zoom.getZoomBarData();
if (isEmpty(zoomBarData)) {
// if there's no zoom bar data we can't do anything
return;
}
this.xScale = mainXScale.copy();
this.yScale = mainYScale.copy();

const defaultDomain = this.services.zoom.getDefaultZoomBarDomain();
const defaultDomain = this.services.zoom.getDefaultZoomBarDomain(
zoomBarData
);

// add value 0 to the extended domain for zoom bar area graph
this.compensateDataForDefaultDomain(zoomBarData, defaultDomain);
zoomBarData = this.compensateDataForDefaultDomain(
zoomBarData,
defaultDomain
);

// get old initialZoomDomain from model
const oldInitialZoomDomain = this.model.get("initialZoomDomain");
Expand Down Expand Up @@ -526,27 +548,31 @@ export class ZoomBar extends Component {
if (!data || data.length < 2) {
return;
}
const zoomBarData = Tools.clone(data);

const domainIdentifier = this.services.cartesianScales.getDomainIdentifier();
const rangeIdentifier = this.services.cartesianScales.getRangeIdentifier();

// if min domain is extended
if (Number(defaultDomain[0]) < Number(data[0][domainIdentifier])) {
if (
Number(defaultDomain[0]) < Number(zoomBarData[0][domainIdentifier])
) {
const newDatum = {};
newDatum[domainIdentifier] = defaultDomain[0];
newDatum[rangeIdentifier] = 0;
data.unshift(newDatum);
zoomBarData.unshift(newDatum);
}
// if max domain is extended
if (
Number(defaultDomain[1]) >
Number(data[data.length - 1][domainIdentifier])
Number(zoomBarData[zoomBarData.length - 1][domainIdentifier])
) {
const newDatum = {};
newDatum[domainIdentifier] = defaultDomain[1];
newDatum[rangeIdentifier] = 0;
data.push(newDatum);
zoomBarData.push(newDatum);
}
return zoomBarData;
}

destroy() {
Expand Down
74 changes: 74 additions & 0 deletions packages/core/src/model-cartesian-charts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Internal Imports
import { ChartModel } from "./model";
import { Tools } from "./tools";

/**
* This supports adding X and Y Cartesian[2D] zoom data to a ChartModel
* */
export class ChartModelCartesian extends ChartModel {
constructor(services: any) {
super(services);
}

setData(newData) {
let data;
if (newData) {
data = super.setData(newData);
if (Tools.getProperty(this.getOptions(), "zoomBar")) {
// if we have zoom bar data we need to update it as well
this.setZoomBarData();
}
}

return data;
}

/**
* @param zoomBarData any special zoom bar data to use instead of the model data
*/
setZoomBarData(newZoomBarData?) {
const sanitizedData = newZoomBarData
? this.sanitize(Tools.clone(newZoomBarData))
: this.getDisplayData(); // if we're not passed explicit zoom data use the model

let zoomBarNormalizedValues = sanitizedData;

const { cartesianScales } = this.services;
if (
sanitizedData &&
cartesianScales.domainAxisPosition &&
cartesianScales.rangeAxisPosition
) {
const domainIdentifier = cartesianScales.getDomainIdentifier();
const rangeIdentifier = cartesianScales.getRangeIdentifier();
// get all dates (Number) in displayData
let allDates = sanitizedData.map((datum) =>
datum[domainIdentifier].getTime()
);
allDates = Tools.removeArrayDuplicates(allDates).sort();

// Go through all date values
// And get corresponding data from each dataset
zoomBarNormalizedValues = allDates.map((date) => {
let sum = 0;
const datum = {};

sanitizedData.forEach((data) => {
if (data[domainIdentifier].getTime() === date) {
sum += data[rangeIdentifier];
}
});
datum[domainIdentifier] = new Date(date);
datum[rangeIdentifier] = sum;

return datum;
});
}

this.set({ zoomBarData: zoomBarNormalizedValues });
}

getZoomBarData() {
return this.get("zoomBarData");
}
}
Loading

0 comments on commit 27e1725

Please sign in to comment.