Created
October 4, 2019 15:35
-
-
Save c80609a/8b0d8eaceae6dfb46eca902d7622395d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | |
); | |
} | |
} |
Author
c80609a
commented
Oct 4, 2019
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment