diff --git a/src/client/visualizations/scatterplot/point.tsx b/src/client/visualizations/scatterplot/point.tsx index ea6e310f7..1600ac5d8 100644 --- a/src/client/visualizations/scatterplot/point.tsx +++ b/src/client/visualizations/scatterplot/point.tsx @@ -27,19 +27,34 @@ interface PointProps { yScale: LinearScale; xSeries: ConcreteSeries; ySeries: ConcreteSeries; + setHover(datum: Datum): void; + resetHover(): void; } const POINT_RADIUS = 3; +const HOVER_AREA_RADIUS = 6; -export const Point: React.SFC = ({ datum, xScale, yScale, xSeries, ySeries }) => { +export const Point: React.SFC = ({ datum, xScale, yScale, xSeries, ySeries, setHover, resetHover }) => { const xValue = xSeries.selectValue(datum); const yValue = ySeries.selectValue(datum); - return ( + return ( + <> + + setHover(datum)} + onMouseLeave={() => resetHover()} + cx={xScale(xValue)} + cy={yScale(yValue)} + r={HOVER_AREA_RADIUS} + stroke="none" + fill="transparent" + /> + ); }; diff --git a/src/client/visualizations/scatterplot/scatterplot.scss b/src/client/visualizations/scatterplot/scatterplot.scss index 64febeea9..7c3d0fbc5 100644 --- a/src/client/visualizations/scatterplot/scatterplot.scss +++ b/src/client/visualizations/scatterplot/scatterplot.scss @@ -56,4 +56,12 @@ position: absolute; font-weight: $bold; } + + .segment-bubble-text { + .content { + strong { + font-weight: $bold; + } + } + } } diff --git a/src/client/visualizations/scatterplot/scatterplot.tsx b/src/client/visualizations/scatterplot/scatterplot.tsx index 1c26686b2..55d6a8552 100644 --- a/src/client/visualizations/scatterplot/scatterplot.tsx +++ b/src/client/visualizations/scatterplot/scatterplot.tsx @@ -31,8 +31,9 @@ import "./scatterplot.scss"; import { Stage } from "../../../common/models/stage/stage"; import { GridLines } from "../../components/grid-lines/grid-lines"; -import { pickTicks } from "../../utils/linear-scale/linear-scale"; +import { pickTicks } from "../../utils/linear-scale/linear-scale"; import { Point } from "./point"; +import { Tooltip } from "./tooltip"; import { XAxis } from "./x-axis"; import { YAxis } from "./y-axis"; @@ -41,39 +42,68 @@ const MARGIN = 40; const X_AXIS_HEIGHT = 50; const Y_AXIS_WIDTH = 50; -const Scatterplot: React.SFC = ({ data, essence, stage }) => { - const [xSeries, ySeries] = essence.getConcreteSeries().toArray(); - const scatterplotData = selectFirstSplitDatums(data); - const xExtent = getExtent(scatterplotData, xSeries); - const yExtent = getExtent(scatterplotData, ySeries); - - const plottingStage = calculatePlottingStage(stage); - const yScale = d3.scale.linear().domain(yExtent).nice().range([plottingStage.height, 0]); - const xScale = d3.scale.linear().domain(xExtent).nice().range([0, plottingStage.width]); - const xTicks = pickTicks(xScale, 10); - const yTicks = pickTicks(yScale, 10); - - return
- {xSeries.title()} - {ySeries.title()} - - - - - - - {scatterplotData.map(datum => ( - - ))} - - -
; -}; +interface ScatterplotState { + hoveredPoint: Datum | null; +} + +export class Scatterplot extends React.Component { + state: ScatterplotState = { + hoveredPoint: null + }; + + setPointHover = (datum: Datum): void => + this.setState({ hoveredPoint: datum }); + + resetPointHover = (): void => + this.setState({ hoveredPoint: null }); + + render() { + const { data, essence, stage } = this.props; + const splitKey = essence.splits.splits.first().toKey(); + const [xSeries, ySeries] = essence.getConcreteSeries().toArray(); + const scatterplotData = selectFirstSplitDatums(data); + const xExtent = getExtent(scatterplotData, xSeries); + const yExtent = getExtent(scatterplotData, ySeries); + + const plottingStage = calculatePlottingStage(stage); + const yScale = d3.scale.linear().domain(yExtent).nice().range([plottingStage.height, 0]); + const xScale = d3.scale.linear().domain(xExtent).nice().range([0, plottingStage.width]); + const xTicks = pickTicks(xScale, 10); + const yTicks = pickTicks(yScale, 10); + + return
+ {xSeries.title()} + {ySeries.title()} + + + + + + + + {scatterplotData.map(datum => { + return ( + + ); } + )} + + +
; + } +} export function ScatterplotVisualization(props: VisualizationProps) { return diff --git a/src/client/visualizations/scatterplot/tooltip.tsx b/src/client/visualizations/scatterplot/tooltip.tsx new file mode 100644 index 000000000..32fe52e3a --- /dev/null +++ b/src/client/visualizations/scatterplot/tooltip.tsx @@ -0,0 +1,55 @@ +/* + * Copyright 2017-2022 Allegro.pl + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import * as React from "react"; + +import { Datum } from "plywood"; +import { ConcreteSeries } from "../../../common/models/series/concrete-series"; +import "./scatterplot.scss"; + +import { Stage } from "../../../common/models/stage/stage"; +import { SegmentBubbleContent } from "../../components/segment-bubble/segment-bubble"; +import { TooltipWithinStage } from "../../components/tooltip-within-stage/tooltip-within-stage"; +import { LinearScale } from "../../utils/linear-scale/linear-scale"; + +interface TooltipProps { + splitKey: string; + datum: Datum; + stage: Stage; + xSeries: ConcreteSeries; + ySeries: ConcreteSeries; + xScale: LinearScale; + yScale: LinearScale; +} + +const TOOLTIP_OFFSET_Y = 50; +const TOOLTIP_OFFSET_X = 100; + +export const Tooltip: React.SFC = ({ datum, stage, xSeries, ySeries, xScale, yScale, splitKey }) => { + if (!Boolean(datum)) return null; + + const title = datum[splitKey] as string; + const xValue = xSeries.selectValue(datum); + const yValue = ySeries.selectValue(datum); + + return + + {xSeries.title()} {xSeries.formatValue(datum)}
+ {ySeries.title()} {ySeries.formatValue(datum)} + } /> +
; +};