Я пытаюсь воспроизвести этот пример , используя React.
Вот мой код:
import * as React from 'react'
import { mean, maxBy } from 'lodash'
import { line } from 'd3-shape'
import { scaleTime, ScaleTime, scaleLinear, ScaleLinear } from 'd3-scale'
import { extent } from 'd3-array'
import { select } from 'd3-selection'
import Draggable, { DraggableCore } from 'react-draggable'
type YouDrawItDatasetType = {
year: number
value: number
defined?: boolean
}
const YEAR_THRESHOLD = 2012
function youDrawItData(): YouDrawItDatasetType[] {
const years = range(2001, 2019)
const dataset = years.map(year => ({ year: year, value: random(0, 100, true) }))
return dataset
}
function clamp(a: number, b: number, c: number) {
return Math.max(a, Math.min(b, c))
}
export class YouDrawIt extends React.Component {
completed = false
userLinePathRef = React.createRef<SVGPathElement>()
rectRef = React.createRef<SVGRectElement>()
handleDragStart() {
}
handleDrag = (
xScale: ScaleTime<number, number>,
yScale: ScaleLinear<number, number>,
dataGreaterThanTreshold: any,
linePathGenerator: any,
) => (e: any, ui: any) => {
console.log('\nhandleDrag')
const x = ui.x
const y = ui.y
const pos = [x, y]
const year = clamp(
YEAR_THRESHOLD + 1,
xScale.domain()[1].getFullYear() + 1,
xScale.invert(pos[0]).getFullYear(),
)
const value = clamp(0, yScale.domain()[1], yScale.invert(pos[1]))
dataGreaterThanTreshold.forEach((d: any) => {
if (Math.abs(d.year - year) < 0.5) {
d.value = value
d.defined = true
}
const dataGreaterThanTresholdDefined = dataGreaterThanTreshold.filter((d: any) => d.defined)
const dPath = linePathGenerator(dataGreaterThanTresholdDefined)
this.userLinePathRef.current.setAttribute('d', dPath)
const meanDataGreaterThanTresholdDefined = mean(dataGreaterThanTresholdDefined)
const lastYear = new Date(maxBy(dataGreaterThanTreshold, 'year')['year'])
console.log('lastYear: ', lastYear)
if (!this.completed && meanDataGreaterThanTresholdDefined === 1) {
this.completed = true
select(this.rectRef.current)
.transition()
.duration(1000)
.attr('width', xScale(lastYear))
}
})
}
handleDragStop() {
}
render() {
const width = window.innerWidth / 1.1
const height = window.innerHeight / 2
const dataset = youDrawItData()
const xScale = scaleTime<number, number>()
.domain(extent(dataset, d => d.year))
.range([0, width])
const yScale = scaleLinear<number, number>()
.domain(extent(dataset, d => d.value))
.range([0, height])
const linePathGenerator = line<YouDrawItDatasetType>()
.x(d => xScale(d.year))
.y(d => yScale(d.value))
const dPath = linePathGenerator(dataset)
const dataGreaterThanTreshold = dataset
.map(function(d) {
return { year: d.year, value: d.value, defined: false }
})
.filter(function(d) {
if (d.year == YEAR_THRESHOLD) d.defined = true
return d.year >= YEAR_THRESHOLD
})
return (
<div className="black">
<Draggable
onStart={this.handleDragStart}
onDrag={this.handleDrag(xScale, yScale, dataGreaterThanTreshold, linePathGenerator)}
onStop={this.handleDragStop}
>
<svg className="ba b--black" width={width} height={height}>
<rect className="ba b--black" width={width} height={height} opacity={0} />
<clipPath id="clip">
<rect className="ba b--black" width={width / 2} height={height} ref={this.rectRef} />
</clipPath>
<g clipPath="url(#clip)">
<path d={dPath} fill="none" stroke="tomato" strokeWidth={3} />
</g>
<path
className=""
ref={this.userLinePathRef}
fill="none"
stroke="lime"
strokeWidth={3}
/>
</svg>
</Draggable>
</div>
)
}
}
Результат не тот, который я хочу.В результате я могу перетащить все SVG, но мне бы это не понравилось.Я хотел бы, чтобы результат был связанным: пользователь перемещает мышь и создает новые точки.
Когда я делаю:
const year = clamp(
YEAR_THRESHOLD + 1,
xScale.domain()[1].getFullYear() + 1,
xScale.invert(pos[0]).getFullYear(),
)
, итоговый год всегда равен 2013
, почему?
Мне нужна рука для отладки этого кода.Я пытался скопировать логику, найденную в коде Адама Пирса, но я делаю что-то не так.