Skip to content

Instantly share code, notes, and snippets.

@c80609a
Created October 4, 2019 15:35
Show Gist options
  • Save c80609a/8b0d8eaceae6dfb46eca902d7622395d to your computer and use it in GitHub Desktop.
Save c80609a/8b0d8eaceae6dfb46eca902d7622395d to your computer and use it in GitHub Desktop.
import React from 'react';
import { timeFormatLocale, max, min, curveCatmullRom } from "d3";
import { axisLeft, axisBottom } from "d3-axis";
import { scaleTime, scaleLinear } from "d3-scale";
import { area, line } from 'd3-shape';
import { Axis, Grid, Dots } from '../';
import d3_locale from '../utils/';
import './index.scss';
let LOCALE = timeFormatLocale(d3_locale);
export default class LineChart extends React.Component {
render() {
const { data, width, margin, color } = this.props;
if(!width) {
return null
}
if(!data || data.length < 2) {
return (
<div className='noDataBox' style={{ width, height: width / 2.8 }}>
Wrong data
</div>
);
}
//<editor-fold desc="// хитрые манипуляции с deltaValue - вертикальную ось делим на 8 частей">
const maxValue = max(data, d => d.value);
const minValue = min(data, d => d.value);
const deltaValue = maxValue - minValue;
let yDomain, yMax, yMin, yDelta;
if(deltaValue === 0) {
if(maxValue <= 8) {
yMax = 8
} else {
yMax = maxValue + maxValue / 3;
}
yMin = 0;
yDomain = [yMin, yMax];
}
/**
* Если разница значений меньше 8 но и эта разница меньше чем [0,8]
*/
if(deltaValue > 0 && deltaValue < 8 && maxValue - 8 <= 0) {
yDomain = [0, 8];
}
/**
* Если разница значений меньше 8 но и эта разница больше чем [0,8]
*/
if(deltaValue > 0 && deltaValue < 8 && maxValue - 8 > 0) {
yDelta = 8 - deltaValue;
yMax = maxValue + Math.ceil(yDelta / 2) + 1;
if(minValue - Math.ceil(yDelta / 2) - 1 <= 0) {
yMin = 0
} else {
yMin = minValue - Math.ceil(yDelta / 2) - 1;
}
yDomain = [yMin, yMax];
}
if(deltaValue >= 8) {
yMax = Math.ceil(maxValue + deltaValue / 3);
yMin = minValue === 0 ? 0 : Math.ceil(minValue - deltaValue / 5);
yDomain = [yMin, yMax];
}
//</editor-fold>
/**
* Вычисляем длинну строки значения и из нее делаем margin left
* @type {number}
*/
const marginLeft = ((maxValue + '').length + 2) * 12;
const boxWidth = width - (marginLeft + margin.right);
const boxHeight = width / 2.8 - (margin.top + margin.bottom);
//const dateRange = timeDay.every(1).range(data[0].date, data[data.length - 1].date).splice(1)
let x = scaleTime()
.domain([data[0].date, data[data.length - 1].date])
.range([0, boxWidth]);
let y = scaleLinear()
.domain(yDomain)
.range([boxHeight, 0]);
let lineD = line()
.x(d => x(d.date))
.y(d => y(d.value))
.curve(curveCatmullRom.alpha(1));
let areaD = area()
.x(d => x(d.date))
.y1(d => y(d.value))
.y0(y(yDomain[0]))
.curve(curveCatmullRom.alpha(1));
const finalLine = lineD(data);
const finalArea = areaD(data);
const dataLength = data.length - 1;
const dateArr = data.map(d => d.date);
const dayTickValues = dateArr.reduce((prev, next, i) => {
if(!((dataLength - i) % 7)) {
prev.push(next);
}
return prev;
}, []);
const axisX = axisBottom(x)
.tickFormat(LOCALE.format("%b %d"))
.tickValues(dayTickValues);
const axisY = axisLeft(y)
.ticks(5);
const gridY = axisLeft(y)
.ticks(5)
.tickSize(-boxWidth, 0, 0)
.tickFormat("");
let transform = 'translate(' + marginLeft + ',' + margin.top + ')';
let svg_id = `line_chart_${this.props.boat_id}`;
return (
<div className='box'>
<svg
id={svg_id}
className='color'
style={{
width: boxWidth + marginLeft + margin.right,
height: boxHeight + margin.top + margin.bottom
}}
>
<g transform={transform}>
<Grid grid={gridY} gridType="y" height={boxHeight} />
<Axis axis={axisX} axisType="x" height={boxHeight} />
<Axis axis={axisY} axisType="y" height={boxHeight} />
<g>
<path
className='lineStyle'
d={finalLine}
/>
<path
className='areaStyle'
d={finalArea}
/>
</g>
<Dots data={data} x={x} y={y} color={color} parent_id={svg_id} />
</g>
</svg>
</div>
);
}
}
@c80609a
Copy link
Author

c80609a commented Oct 4, 2019

Selection_012

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment