react-meteo-chart
Version:
pre alpha of meteo chart
518 lines (484 loc) • 15.6 kB
JSX
import React, { Component, PureComponent } from "react";
import BasicChart, { rgbToHex } from "../BasicChart";
import LeBasicChart from "../LeBasicChart";
import Candlestick from "../Candlestick";
import sizeMe from "react-sizeme";
import {
FlexAmsLegend as AmsLegend,
TempLegend,
WindSpeedLegend,
PressureLegend,
BarTendencyLegend,
PrecipLegend,
COLORS,
} from "./AmsLegend";
import { AmsCrossFormat, EmptyCrossFormat } from "./AmsCrossFormat";
import GridDates, { fontSize } from "../GridDates";
import {
XYPlot,
FlexibleWidthXYPlot,
FlexibleXYPlot,
CustomSVGSeries,
YAxis,
XAxis,
VerticalBarSeries,
VerticalGridLines,
HorizontalGridLines,
LineSeries,
LineSeriesCanvas,
LineMarkSeries,
MarkSeries,
DecorativeAxis,
VerticalRectSeries,
Crosshair,
} from "react-vis";
import moment from "moment";
class MiddleVerticalRectSeries extends VerticalRectSeries {
_handleNearestX = function (event) {
var _props3 = this.props,
onNearestX = _props3.onNearestX,
data = _props3.data;
var minDistance = -Number.POSITIVE_INFINITY;
var value = null;
var valueIndex = null;
var coordinate = this._getXYCoordinateInContainer(event);
var xScaleFn = this._getAttributeFunctor("x");
data.forEach(function (item, i) {
var currentCoordinate = xScaleFn(item);
var newDistance = coordinate.x - currentCoordinate;
if (newDistance <= 0 && newDistance > minDistance) {
minDistance = newDistance;
value = item;
valueIndex = i;
}
});
if (!value) {
return;
}
onNearestX(value, {
innerX: xScaleFn(value),
index: valueIndex,
event: event.nativeEvent,
});
};
}
class AmsChart extends PureComponent {
constructor(props) {
super(props);
this.state = {
cross: [],
showcross: false,
showSpeedCross: false,
showTempCross: false,
showBarometricCross: false,
showPrecipCross: false,
showPressCross: false,
wind: true,
temp: true,
tendency: true,
precipit: true,
normalPress: true,
press: true,
width: 0,
};
}
componentWillUnmount() {
// window.removeEventListener("resizedir", e =>
// this.setState({ width: document.getElementById("dirwind").clientWidth })
// );
}
setTooltip = (value, crossName) => {
let { superArr } = this.props;
let xx = superArr.map((d) =>
Math.max.apply(
Math,
d
.filter((s) => s.y !== null)
.map((x) => x.x)
.filter((x) => {
return x <= value.x;
})
)
);
let cress = superArr.map((d, indx) =>
d.filter((asd, id) => asd.x == xx[indx])
);
// if (cress[3] && cress[3].length > 1)
// cress[3].sort((a, b) => b.y - a.y)[0].y;
this.setState({
cross: superArr.map((d, indx) => ({
x: value.x,
y: cress[indx][0]
? indx == 4
? cress[indx][0].z
: cress[indx][0].y
: null,
})),
[crossName]: true,
});
};
render() {
const { width } = this.props.size;
let {
superArr,
dateFrom,
dateTo,
plotHeight = 270,
plotWidth = width,
} = this.props;
let domainFrom = moment(
moment.utc(dateFrom).local().format("YYYY-MM-DDTHH:mm")
);
let domainTo = moment(
moment.utc(dateTo).local().format("YYYY-MM-DD:HH:mm")
);
let gridDates = GridDates(dateFrom, dateTo);
const setVal = (data, name) => {
this.setState({ [name]: !data });
};
if (this.props.arrows) {
var arrowsArr = superArr[4].filter(
(e, i) => i % Math.trunc((150 * superArr[4].length) / width) === 0
);
}
const {
cross,
showcross,
showSpeedCross,
showTempCross,
showBarometricCross,
showPrecipCross,
showPressCross,
wind,
temp,
tendency,
precipit,
normalPress,
press,
} = this.state;
const isAdmin = this.props.isAdmin;
const animated = this.props.animated;
return (
<>
<BasicChart
opacity={this.props.opacity}
superArr={superArr}
dateFrom={dateFrom}
dateTo={dateTo}
plotHeight={plotHeight > 130 ? plotHeight : 130}
plotWidth={plotWidth}
>
<FlexibleXYPlot
// width={plotWidth}
height={plotHeight > 130 ? plotHeight : 130}
className="mainPlot"
// yPadding={35}
margin={{ left: 65 }}
xDomain={[domainFrom, domainTo]}
onMouseLeave={() => {
this.setState({ showPressCross: false });
}}
>
<YAxis
left={0}
tickTotal={5}
tickFormat={(v) => (v !== null ? `${v} гПа` : "")}
/>
{/* <VerticalGridLines /> */}
<HorizontalGridLines />
{/* Normalized pressure array */}
{superArr[6] && normalPress && (
<LineMarkSeries
getNull={(d) => d.y !== null}
data={superArr[6]}
stroke={`${COLORS.normalizedPressureColor}`}
size="1"
curve={"curveMonotoneX"}
onNearestX={(value, { index }) => {
this.setTooltip(value, "showPressCross");
}}
/>
)}
{/* Pressure array */}
{superArr[5] && press && (
<LineMarkSeries
getNull={(d) => d.y !== null}
data={superArr[5]}
stroke={`${COLORS.pressureColor}`}
size="1"
curve={"curveMonotoneX"}
/>
)}
{superArr[2] && superArr[2].length > 0 && press && (
<Candlestick
className="mainPlot"
getNull={(d) => d.y !== null}
colorType="literal"
opacityType="literal"
stroke="#000000"
// fill="#ff0000"
data={superArr[2]}
/>
)}
{!animated && (
<Crosshair values={cross}>
{showPressCross && !animated ? (
<AmsCrossFormat superArr={superArr} cross={cross} />
) : (
<EmptyCrossFormat />
)}
</Crosshair>
)}
</FlexibleXYPlot>
{isAdmin && <PressureLegend setVal={setVal} isAdmin={isAdmin} />}
</BasicChart>
<BasicChart
opacity={this.props.opacity}
superArr={superArr}
dateFrom={dateFrom}
dateTo={dateTo}
// extremum={extremumArr[0]}
plotHeight={plotHeight > 180 ? plotHeight : 180}
plotWidth={plotWidth}
>
<FlexibleXYPlot
// width={plotWidth}
height={plotHeight > 180 ? plotHeight : 180}
className="mainPlot"
xDomain={[domainFrom, domainTo]}
margin={{ left: 65 }}
yPadding={15}
// getY={e => console.log(e)}
onMouseLeave={() => {
this.setState({ showSpeedCross: false });
}}
>
<YAxis
left={0}
tickFormat={(v) => (v !== null && v >= 0 ? `${v} м/с` : "")}
/>
{/* <VerticalGridLines /> */}
<HorizontalGridLines />
{/* Wind speed array */}
{superArr[0] && wind && (
<CustomSVGSeries
className="directionPlot"
data={arrowsArr ? arrowsArr : superArr[4]}
getNull={(d) => d.y !== null}
/>
)}
{superArr[0] && wind && (
<LineMarkSeries
ref={(lms) => {
this.lms = lms;
}}
getNull={(d) => d.y !== null}
data={superArr[0]}
curve={"linear"} //find solution
stroke={`${COLORS.widSpeedColor}`}
size="1"
onNearestX={(value, { index }) => {
this.setTooltip(value, "showSpeedCross");
}}
/>
)}
{!animated && (
<Crosshair values={cross}>
{showSpeedCross && !animated ? (
<AmsCrossFormat superArr={superArr} cross={cross} />
) : (
<EmptyCrossFormat />
)}
</Crosshair>
)}
</FlexibleXYPlot>
{isAdmin && <WindSpeedLegend setVal={setVal} isAdmin={true} />}
</BasicChart>
<BasicChart
opacity={this.props.opacity}
superArr={superArr}
dateFrom={dateFrom}
dateTo={dateTo}
plotHeight={plotHeight > 130 ? plotHeight : 130}
plotWidth={plotWidth}
>
<FlexibleXYPlot
// width={plotWidth}
// height={plotHeight > 120 ? plotHeight : 120}
className="mainPlot"
margin={{ left: 65 }}
yPadding={20}
xDomain={[domainFrom, domainTo]}
onMouseLeave={() => {
this.setState({ showTempCross: false });
}}
>
<YAxis
left={0}
tickTotal={5}
tickFormat={(v) => (v !== null ? `${v} C°` : "")}
/>
{/* <VerticalGridLines /> */}
<HorizontalGridLines />
{/* Temperature array */}
{superArr[1] && temp && (
<LineMarkSeries
getNull={(d) => d.y !== null}
data={superArr[1]}
style={{ strokeWidth: "3" }}
stroke={`${COLORS.temperatureColor}`}
size="1"
// onSeriesMouseOver={onNearestX}
onNearestX={(value, { index }) => {
this.setTooltip(value, "showTempCross");
}}
/>
)}
{!animated && (
<Crosshair values={cross}>
{showTempCross ? (
<AmsCrossFormat superArr={superArr} cross={cross} />
) : (
<EmptyCrossFormat />
)}
</Crosshair>
)}
</FlexibleXYPlot>
{isAdmin && <TempLegend setVal={setVal} isAdmin={true} />}
{isAdmin && <PrecipLegend setVal={setVal} isAdmin={true} />}
</BasicChart>
{superArr[3] !== undefined && superArr[3].length > 0 && precipit ? (
<div
style={{
// border: "1px solid #7d9cb8",
backgroundColor: rgbToHex(255, 255, 255, this.props.opacity),
}}
>
<FlexibleXYPlot
// width={plotWidth}
margin={{ left: 65 }}
height={plotHeight > 130 ? plotHeight : 130}
className="precipitationPlot"
xDomain={[domainFrom, domainTo]}
xType="time"
yDomain={
superArr[3].length > 0
? Math.max.apply(
Math,
superArr[3].map((d) => d.y)
) == 0
? [0, 5]
: [
0,
Math.max.apply(
Math,
superArr[3].map((d) => d.y)
),
]
: [0, 5]
}
// scale="1"
// dontCheckIfEmpty={true}
onMouseLeave={() => {
this.setState({ showPrecipCross: false });
}}
>
<YAxis
left={0}
// tickTotal={5}
tickFormat={(v) => (v >= 0 ? `${v} мм` : "")}
/>
<XAxis
tickFormat={(d) =>
moment(d).format("HH:mm") == "00:00"
? ``
: `${moment(d).format("HH:mm")}`
}
tickTotal={width * 0.01}
/>
<XAxis
tickFormat={(d) =>
moment(d).format("HH:mm") == "00:00"
? `${moment(d).format("D.MM")}`
: ``
}
style={{
line: { stroke: "#ADDDE1" },
ticks: { stroke: "#ADDDE1" },
text: {
stroke: "none",
fill: "#000000",
fontWeight: 750,
fontSize: 12,
},
}}
tickTotal={width * 0.01}
/>
<VerticalGridLines />
<HorizontalGridLines />
{/* Precipitation array */}
<MiddleVerticalRectSeries
className="precipitBars"
getNull={(d) => d.y !== null}
data={superArr[3]}
fill={`${COLORS.precipitationColor}`}
stroke={`#000000`}
// scale="2"
style={
{
// strokeWidth: 10
}
}
onNearestX={(value, { index }) => {
this.setTooltip(value, "showPrecipCross");
}}
/>
{gridDates.map((date) => {
return (
<DecorativeAxis
key={`${date}-axis`}
className="decaxis"
axisDomain={[]}
axisStart={{
x: moment(date.format("YYYY-MM-DD")),
y: 0,
}}
axisEnd={{
x: moment(date.format("YYYY-MM-DD")),
y: 1,
}}
tickTotal={0}
style={{
ticks: { display: "none" },
text: { display: "none" },
}}
/>
);
})}
{!animated && (
<Crosshair values={cross}>
{showPrecipCross ? (
<AmsCrossFormat superArr={superArr} cross={cross} />
) : (
<EmptyCrossFormat />
)}
</Crosshair>
)}
</FlexibleXYPlot>
</div>
) : (
<BasicChart
opacity={this.props.opacity}
superArr={superArr}
dateFrom={dateFrom}
dateTo={dateTo}
plotHeight={plotHeight > 130 ? plotHeight : 130}
plotWidth={plotWidth}
/>
)}
{!isAdmin && <AmsLegend setVal={setVal} />}
</>
);
}
}
export default sizeMe()(AmsChart);