diff --git a/showcase/entries/Continuous.re b/showcase/entries/Continuous.re
index 832d6789..4d56c583 100644
--- a/showcase/entries/Continuous.re
+++ b/showcase/entries/Continuous.re
@@ -1,5 +1,3 @@
-open ForetoldComponents.Base;
-
let data: DistributionTypes.xyShape = {
xs: [|1., 10., 10., 200., 250., 292., 330.|],
ys: [|0.0, 0.0, 0.1, 0.3, 0.5, 0.2, 0.1|],
diff --git a/src/components/charts/CdfChart__Base.re b/src/components/charts/CdfChart__Base.re
index 273bc028..ffcaf2f0 100644
--- a/src/components/charts/CdfChart__Base.re
+++ b/src/components/charts/CdfChart__Base.re
@@ -11,16 +11,17 @@ type primaryDistribution = {
let make =
(
~height=?,
- ~verticalLine=?,
- ~showVerticalLine=?,
~marginBottom=?,
~marginTop=?,
- ~showDistributionLines=?,
~maxX=?,
~minX=?,
~onHover=(f: float) => (),
~primaryDistribution=?,
~scale=?,
+ ~showDistributionLines=?,
+ ~showVerticalLine=?,
+ ~timeScale=?,
+ ~verticalLine=?,
~children=[||],
) =>
ReasonReact.wrapJsForReason(
@@ -28,16 +29,17 @@ let make =
~props=
makeProps(
~height?,
- ~verticalLine?,
~marginBottom?,
~marginTop?,
- ~onHover,
- ~showVerticalLine?,
- ~showDistributionLines?,
~maxX?,
~minX?,
+ ~onHover,
~primaryDistribution?,
~scale?,
+ ~showDistributionLines?,
+ ~showVerticalLine?,
+ ~timeScale?,
+ ~verticalLine?,
(),
),
children,
diff --git a/src/components/charts/CdfChart__Plain.re b/src/components/charts/CdfChart__Plain.re
index 8f4859de..16d3b37a 100644
--- a/src/components/charts/CdfChart__Plain.re
+++ b/src/components/charts/CdfChart__Plain.re
@@ -18,26 +18,28 @@ module Styles = {
[@react.component]
let make =
(
- ~data,
- ~minX=?,
- ~maxX=?,
- ~scale=?,
- ~height=200,
~color=`hex("111"),
+ ~data,
+ ~height=200,
+ ~maxX=?,
+ ~minX=?,
~onHover: float => unit,
+ ~scale=?,
+ ~timeScale=?,
) => {
Shape.XYShape.toJs}
+ showDistributionLines=false
+ showVerticalLine=false
/>
;
};
\ No newline at end of file
diff --git a/src/components/charts/GenericDistributionChart.re b/src/components/charts/GenericDistributionChart.re
index 3e0b96f7..f7402f8b 100644
--- a/src/components/charts/GenericDistributionChart.re
+++ b/src/components/charts/GenericDistributionChart.re
@@ -2,16 +2,19 @@ module Continuous = {
[@react.component]
let make = (~data, ~unit) => {
let (x, setX) = React.useState(() => 0.);
+ let timeScale = unit |> DistributionTypes.DistributionUnit.toJson;
let chart =
React.useMemo1(
() =>
setX(_ => r)}
/>,
[|data|],
);
+
chart
diff --git a/src/components/charts/cdfChartD3.js b/src/components/charts/cdfChartD3.js
index a341cba0..417ca247 100644
--- a/src/components/charts/cdfChartD3.js
+++ b/src/components/charts/cdfChartD3.js
@@ -1,7 +1,8 @@
+const _ = require('lodash');
const d3 = require('d3');
const moment = require('moment');
-class Chart {
+export class CdfChartD3 {
constructor() {
this.attrs = {
@@ -13,10 +14,11 @@ class Chart {
marginRight: 50,
marginLeft: 5,
- container: 'body',
+ container: null,
minX: false,
maxX: false,
scale: 'linear',
+ timeScale: null,
showDistributionLines: true,
areaColors: ['#E1E5EC', '#E1E5EC'],
logBase: 10,
@@ -28,6 +30,7 @@ class Chart {
};
this.hoverLine = null;
this.xScale = null;
+ this.xScaleTime = null;
this.dataPoints = null;
this.mouseover = this.mouseover.bind(this);
this.mouseout = this.mouseout.bind(this);
@@ -59,6 +62,11 @@ class Chart {
return this;
}
+ timeScale(timeScale) {
+ this.attrs.timeScale = timeScale;
+ return this;
+ }
+
onHover(onHover) {
this.attrs.onHover = onHover;
return this;
@@ -119,10 +127,7 @@ class Chart {
const len = data.xs.length;
for (let i = 0; i < len; i++) {
- dt.push({
- x: data.xs[i],
- y: data.ys[i]
- })
+ dt.push({ x: data.xs[i], y: data.ys[i] });
}
return dt;
@@ -133,6 +138,7 @@ class Chart {
const container = d3.select(attrs.container);
if (container.node() === null) return;
+ // Sets the width from the DOM element.
const containerRect = container.node().getBoundingClientRect();
if (containerRect.width > 0) {
attrs.svgWidth = containerRect.width;
@@ -159,10 +165,6 @@ class Chart {
this.xScale = d3.scaleLinear()
.domain([attrs.minX || xMin, attrs.maxX || xMax])
.range([0, calc.chartWidth]);
- } else if (attrs.scale === 'time') {
- this.xScale = d3.scaleLinear()
- .domain([new Date(2012, 0, 1), new Date(2020, 0, 31)])
- .range([0, calc.chartWidth]);
} else {
this.xScale = d3.scaleLog()
.base(attrs.logBase)
@@ -178,9 +180,17 @@ class Chart {
.range([calc.chartHeight, 0]);
// Axis generator.
- if (attrs.scale === 'time') {
+ if (!!this.attrs.timeScale) {
+ const zero = _.get(this.attrs.timeScale, 'zero', moment());
+ const unit = _.get(this.attrs.timeScale, 'unit', null);
+ const length = zero.clone().add('year', 5);
+
+ this.xScaleTime = d3.scaleLinear()
+ .domain([zero.toDate(), length.toDate()])
+ .range([0, calc.chartWidth]);
+
this.xAxis = d3.axisBottom()
- .scale(this.xScale)
+ .scale(this.xScaleTime)
.ticks(5)
.tickFormat(this.formatDates);
} else {
@@ -329,16 +339,16 @@ class Chart {
}
}
-
d3.selection.prototype.patternify = function patternify(params) {
const selector = params.selector;
const elementTag = params.tag;
const data = params.data || [selector];
- const selection = this.selectAll('.' + selector).data(data, (d, i) => {
- if (typeof d === 'object' && d.id) return d.id;
- return i;
- });
+ const selection = this.selectAll('.' + selector)
+ .data(data, (d, i) => {
+ if (typeof d === 'object' && d.id) return d.id;
+ return i;
+ });
selection.exit().remove();
@@ -348,9 +358,3 @@ d3.selection.prototype.patternify = function patternify(params) {
.merge(selection)
.attr('class', selector);
};
-
-function chart() {
- return new Chart();
-}
-
-export default chart;
diff --git a/src/components/charts/cdfChartReact.js b/src/components/charts/cdfChartReact.js
index 95b2a61b..e2c48952 100644
--- a/src/components/charts/cdfChartReact.js
+++ b/src/components/charts/cdfChartReact.js
@@ -1,7 +1,7 @@
import React, { useEffect } from 'react';
import { useSize } from 'react-use';
-import chart from './cdfChartD3';
+import { CdfChartD3 } from './cdfChartD3';
/**
* @param min
@@ -19,8 +19,9 @@ function getRandomInt(min, max) {
* @returns {*}
* @constructor
*/
-function CdfChart(props) {
- const id = "chart-" + getRandomInt(0, 100000);
+function CdfChartReact(props) {
+ const containerRef = React.createRef();
+ const key = "cdf-chart-react-" + getRandomInt(0, 1000);
const scale = props.scale || 'linear';
const style = !!props.width ? { width: props.width + "px" } : {};
@@ -33,7 +34,7 @@ function CdfChart(props) {
});
useEffect(() => {
- chart()
+ new CdfChartD3()
.svgWidth(width)
.svgHeight(props.height)
.maxX(props.maxX)
@@ -46,9 +47,10 @@ function CdfChart(props) {
.showDistributionLines(props.showDistributionLines)
.verticalLine(props.verticalLine)
.showVerticalLine(props.showVerticalLine)
- .container("#" + id)
+ .container(containerRef.current)
.data({ primary: props.primaryDistribution })
.scale(scale)
+ .timeScale(props.timeScale)
.render();
});
@@ -59,8 +61,12 @@ function CdfChart(props) {
},
}, [
sized,
- React.createElement("div", { id, style, key: id }),
+ React.createElement("div", {
+ key,
+ style,
+ ref: containerRef,
+ }),
]);
}
-export default CdfChart;
+export default CdfChartReact;
diff --git a/src/core/DistributionTypes.re b/src/core/DistributionTypes.re
index d19070df..cfc5cf29 100644
--- a/src/core/DistributionTypes.re
+++ b/src/core/DistributionTypes.re
@@ -46,4 +46,15 @@ type genericDistribution = {
probabilityType,
domain,
unit: distributionUnit,
+};
+
+module DistributionUnit = {
+ let toJson = (distributionUnit: distributionUnit) =>
+ switch (distributionUnit) {
+ | Time({zero, unit}) =>
+ Js.Null.fromOption(
+ Some({"zero": zero, "unit": unit |> TimeTypes.TimeUnit.toString}),
+ )
+ | _ => Js.Null.fromOption(None)
+ };
};
\ No newline at end of file
diff --git a/src/core/TimeTypes.re b/src/core/TimeTypes.re
index db08c5bd..75e158e2 100644
--- a/src/core/TimeTypes.re
+++ b/src/core/TimeTypes.re
@@ -20,6 +20,21 @@ type timePoint = {
value: float,
};
+module TimeUnit = {
+ let toString = (timeUnit: timeUnit) =>
+ switch (timeUnit) {
+ | `days => "days"
+ | `hours => "hours"
+ | `milliseconds => "milliseconds"
+ | `minutes => "minutes"
+ | `months => "months"
+ | `quarters => "quarters"
+ | `seconds => "seconds"
+ | `weeks => "weeks"
+ | `years => "years"
+ };
+};
+
module TimePoint = {
let fromTimeVector = (timeVector, value): timePoint => {timeVector, value};