It is time to fix time vector

This commit is contained in:
Roman Galochkin 2020-02-19 10:36:11 +03:00
parent fbd1b46b91
commit 10ad3be6b3
8 changed files with 89 additions and 48 deletions

View File

@ -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|],

View File

@ -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,

View File

@ -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=?,
) => {
<div className={Styles.graph(color)}>
<CdfChart__Base
height
?minX
?maxX
?minX
?scale
?timeScale
height
marginBottom=50
marginTop=0
onHover
showVerticalLine=false
showDistributionLines=false
primaryDistribution={data |> Shape.XYShape.toJs}
showDistributionLines=false
showVerticalLine=false
/>
</div>;
};

View File

@ -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(
() =>
<CdfChart__Plain
data
timeScale
color={`hex("333")}
onHover={r => setX(_ => r)}
/>,
[|data|],
);
<div>
chart
<table className="table-auto">

View File

@ -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,13 +339,13 @@ 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) => {
const selection = this.selectAll('.' + selector)
.data(data, (d, i) => {
if (typeof d === 'object' && d.id) return d.id;
return i;
});
@ -348,9 +358,3 @@ d3.selection.prototype.patternify = function patternify(params) {
.merge(selection)
.attr('class', selector);
};
function chart() {
return new Chart();
}
export default chart;

View File

@ -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;

View File

@ -47,3 +47,14 @@ type genericDistribution = {
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)
};
};

View File

@ -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};