aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-07-05 15:55:14 +0200
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-07-13 14:34:17 +0200
commitbd28f67e3f5250a5e4ac5706eeb555f416e15782 (patch)
treebe42afce0d9be47b147fda149bb66f4cd7e44f5d /server
parent223c274b837e855af0dc8c6fa7be3ea591f34feb (diff)
downloadsonarqube-bd28f67e3f5250a5e4ac5706eeb555f416e15782.tar.gz
sonarqube-bd28f67e3f5250a5e4ac5706eeb555f416e15782.zip
SONAR-9415 Click on the graph or on the list to see the matching analysis on project activity page
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysesList.js69
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.js136
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js1
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js5
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/StaticGraphs.js19
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap1
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css8
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/types.js3
-rw-r--r--server/sonar-web/src/main/js/apps/projectActivity/utils.js25
-rw-r--r--server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js54
10 files changed, 212 insertions, 109 deletions
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysesList.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysesList.js
index a2aa8084c66..9c98102a95e 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysesList.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysesList.js
@@ -25,7 +25,12 @@ import { throttle } from 'lodash';
import ProjectActivityAnalysis from './ProjectActivityAnalysis';
import FormattedDate from '../../../components/ui/FormattedDate';
import { translate } from '../../../helpers/l10n';
-import { activityQueryChanged, getAnalysesByVersionByDay } from '../utils';
+import {
+ activityQueryChanged,
+ getAnalysesByVersionByDay,
+ selectedDateQueryChanged
+} from '../utils';
+import type { RawQuery } from '../../../helpers/query';
import type { Analysis, Query } from '../types';
type Props = {
@@ -39,13 +44,15 @@ type Props = {
deleteAnalysis: (analysis: string) => Promise<*>,
deleteEvent: (analysis: string, event: string) => Promise<*>,
loading: boolean,
- query: Query
+ query: Query,
+ updateQuery: RawQuery => void
};
export default class ProjectActivityAnalysesList extends React.PureComponent {
- scrollContainer: HTMLElement;
+ analyses: HTMLCollection<HTMLElement>;
badges: HTMLCollection<HTMLElement>;
props: Props;
+ scrollContainer: HTMLElement;
constructor(props: Props) {
super(props);
@@ -54,22 +61,36 @@ export default class ProjectActivityAnalysesList extends React.PureComponent {
componentDidMount() {
this.badges = document.getElementsByClassName('project-activity-version-badge');
+ this.analyses = document.getElementsByClassName('project-activity-analysis');
}
componentDidUpdate(prevProps: Props) {
- if (prevProps.analysis !== this.props.analyses && this.scrollContainer) {
- if (activityQueryChanged(prevProps.query, this.props.query)) {
- this.scrollContainer.scrollTop = 0;
- }
- for (let i = 1; i < this.badges.length; i++) {
- this.badges[i].removeAttribute('originOffsetTop');
- this.badges[i].classList.remove('sticky');
+ if (this.scrollContainer) {
+ const selectedDateChanged = selectedDateQueryChanged(prevProps.query, this.props.query);
+ if (selectedDateChanged || prevProps.analysis !== this.props.analyses) {
+ if (selectedDateChanged && this.props.query.selectedDate) {
+ const selectedDate = this.props.query.selectedDate.valueOf();
+ for (let i = 1; i < this.analyses.length; i++) {
+ if (Number(this.analyses[i].getAttribute('data-date')) === selectedDate) {
+ const containerHeight = this.scrollContainer.offsetHeight - 100;
+ const scrollDiff = Math.abs(
+ this.scrollContainer.scrollTop - this.analyses[i].offsetTop
+ );
+ // Center only the extremities and the ones outside of the container
+ if (scrollDiff > containerHeight || scrollDiff < 100) {
+ this.resetScrollTop(this.analyses[i].offsetTop - containerHeight / 2);
+ }
+ break;
+ }
+ }
+ } else if (activityQueryChanged(prevProps.query, this.props.query)) {
+ this.resetScrollTop(0, true);
+ }
}
- this.handleScroll();
}
}
- handleScroll = () => {
+ updateStickyBadges = (forceBadgeAlignement?: boolean) => {
if (this.scrollContainer && this.badges) {
const scrollTop = this.scrollContainer.scrollTop;
if (scrollTop != null) {
@@ -78,11 +99,12 @@ export default class ProjectActivityAnalysesList extends React.PureComponent {
const badge = this.badges[i];
let originOffsetTop = badge.getAttribute('originOffsetTop');
if (originOffsetTop == null) {
+ // Set the originOffsetTop attribute, to avoid using getBoundingClientRect
originOffsetTop = badge.offsetTop;
badge.setAttribute('originOffsetTop', originOffsetTop.toString());
}
if (Number(originOffsetTop) < scrollTop + 18 + i * 2) {
- if (!badge.classList.contains('sticky')) {
+ if (forceBadgeAlignement && !badge.classList.contains('sticky')) {
newScrollTop = originOffsetTop;
}
badge.classList.add('sticky');
@@ -90,12 +112,26 @@ export default class ProjectActivityAnalysesList extends React.PureComponent {
badge.classList.remove('sticky');
}
}
- if (newScrollTop != null) {
+ if (forceBadgeAlignement && newScrollTop != null) {
this.scrollContainer.scrollTop = newScrollTop - 6;
}
}
}
};
+ handleScroll = () => this.updateStickyBadges(true);
+
+ resetScrollTop = (newScrollTop: number, forceBadgeAlignement?: boolean) => {
+ this.scrollContainer.scrollTop = newScrollTop;
+ for (let i = 1; i < this.badges.length; i++) {
+ this.badges[i].removeAttribute('originOffsetTop');
+ this.badges[i].classList.remove('sticky');
+ }
+ this.updateStickyBadges(forceBadgeAlignement);
+ };
+
+ updateSelectedDate = (date: Date) => {
+ this.props.updateQuery({ selectedDate: date });
+ };
render() {
if (this.props.analyses.length === 0) {
@@ -110,6 +146,9 @@ export default class ProjectActivityAnalysesList extends React.PureComponent {
const firstAnalysisKey = this.props.analyses[0].key;
const byVersionByDay = getAnalysesByVersionByDay(this.props.analyses);
+ const selectedDate = this.props.query.selectedDate
+ ? this.props.query.selectedDate.valueOf()
+ : null;
return (
<ul
className={classNames('project-activity-versions-list', this.props.className)}
@@ -145,6 +184,8 @@ export default class ProjectActivityAnalysesList extends React.PureComponent {
deleteEvent={this.props.deleteEvent}
isFirst={analysis.key === firstAnalysisKey}
key={analysis.key}
+ selected={analysis.date.valueOf() === selectedDate}
+ updateSelectedDate={this.updateSelectedDate}
/>
))}
</ul>
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.js
index 1cd17b22bb9..4ccb7cb9718 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAnalysis.js
@@ -19,6 +19,7 @@
*/
// @flow
import React from 'react';
+import classNames from 'classnames';
import Events from './Events';
import AddEventForm from './forms/AddEventForm';
import RemoveAnalysisForm from './forms/RemoveAnalysisForm';
@@ -34,72 +35,87 @@ type Props = {
changeEvent: (event: string, name: string) => Promise<*>,
deleteAnalysis: (analysis: string) => Promise<*>,
deleteEvent: (analysis: string, event: string) => Promise<*>,
- isFirst: boolean
+ isFirst: boolean,
+ selected: boolean,
+ updateSelectedDate: Date => void
};
-export default function ProjectActivityAnalysis(props: Props) {
- const { date, events } = props.analysis;
- const { isFirst, canAdmin } = props;
- const analysisTitle = translate('project_activity.analysis');
- const hasVersion = events.find(event => event.category === 'VERSION') != null;
- return (
- <li className="project-activity-analysis clearfix">
- <div className="project-activity-time spacer-right">
- <FormattedDate date={date} format="LT" tooltipFormat="LTS" />
- </div>
- <div
- className="project-activity-analysis-icon little-spacer-top big-spacer-right"
- title={analysisTitle}
- />
+export default class ProjectActivityAnalysis extends React.PureComponent {
+ props: Props;
- {canAdmin &&
- <div className="project-activity-analysis-actions spacer-left">
- <div className="dropdown display-inline-block">
- <button
- className="js-analysis-actions button-small button-compact dropdown-toggle"
- data-toggle="dropdown">
- <i className="icon-settings" />
- {' '}
- <i className="icon-dropdown" />
- </button>
- <ul className="dropdown-menu dropdown-menu-right">
- {!hasVersion &&
+ handleClick = () => this.props.updateSelectedDate(this.props.analysis.date);
+
+ render() {
+ const { analysis, isFirst, canAdmin } = this.props;
+ const { date, events } = analysis;
+ const analysisTitle = translate('project_activity.analysis');
+ const hasVersion = events.find(event => event.category === 'VERSION') != null;
+ return (
+ <li
+ className={classNames('project-activity-analysis clearfix', {
+ selected: this.props.selected
+ })}
+ data-date={date.valueOf()}
+ onClick={this.handleClick}
+ role="listitem"
+ tabIndex="0">
+ <div className="project-activity-time spacer-right">
+ <FormattedDate date={date} format="LT" tooltipFormat="LTS" />
+ </div>
+ <div
+ className="project-activity-analysis-icon little-spacer-top big-spacer-right"
+ title={analysisTitle}
+ />
+
+ {canAdmin &&
+ <div className="project-activity-analysis-actions spacer-left">
+ <div className="dropdown display-inline-block">
+ <button
+ className="js-analysis-actions button-small button-compact dropdown-toggle"
+ data-toggle="dropdown">
+ <i className="icon-settings" />
+ {' '}
+ <i className="icon-dropdown" />
+ </button>
+ <ul className="dropdown-menu dropdown-menu-right">
+ {!hasVersion &&
+ <li>
+ <AddEventForm
+ addEvent={this.props.addVersion}
+ analysis={analysis}
+ addEventButtonText="project_activity.add_version"
+ />
+ </li>}
<li>
<AddEventForm
- addEvent={props.addVersion}
- analysis={props.analysis}
- addEventButtonText="project_activity.add_version"
- />
- </li>}
- <li>
- <AddEventForm
- addEvent={props.addCustomEvent}
- analysis={props.analysis}
- addEventButtonText="project_activity.add_custom_event"
- />
- </li>
- {!isFirst && <li role="separator" className="divider" />}
- {!isFirst &&
- <li>
- <RemoveAnalysisForm
- analysis={props.analysis}
- deleteAnalysis={props.deleteAnalysis}
+ addEvent={this.props.addCustomEvent}
+ analysis={analysis}
+ addEventButtonText="project_activity.add_custom_event"
/>
- </li>}
- </ul>
- </div>
- </div>}
+ </li>
+ {!isFirst && <li role="separator" className="divider" />}
+ {!isFirst &&
+ <li>
+ <RemoveAnalysisForm
+ analysis={analysis}
+ deleteAnalysis={this.props.deleteAnalysis}
+ />
+ </li>}
+ </ul>
+ </div>
+ </div>}
- {events.length > 0 &&
- <Events
- analysis={props.analysis.key}
- canAdmin={canAdmin}
- changeEvent={props.changeEvent}
- deleteEvent={props.deleteEvent}
- events={events}
- isFirst={props.isFirst}
- />}
+ {events.length > 0 &&
+ <Events
+ analysis={analysis.key}
+ canAdmin={canAdmin}
+ changeEvent={this.props.changeEvent}
+ deleteEvent={this.props.deleteEvent}
+ events={events}
+ isFirst={this.props.isFirst}
+ />}
- </li>
- );
+ </li>
+ );
+ }
}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js
index dc7d213f30f..46b6dd4fe53 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js
@@ -112,6 +112,7 @@ export default class ProjectActivityApp extends React.PureComponent {
deleteEvent={this.props.deleteEvent}
loading={this.props.loading}
query={this.props.query}
+ updateQuery={this.props.updateQuery}
/>
</div>
<div className="project-activity-layout-page-main">
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js
index 4baa9a82dba..03605c8114c 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js
@@ -40,7 +40,6 @@ type Props = {
};
type State = {
- selectedDate?: ?Date,
graphStartDate: ?Date,
graphEndDate: ?Date,
series: Array<Serie>
@@ -97,7 +96,7 @@ export default class ProjectActivityGraphs extends React.PureComponent {
}
};
- updateSelectedDate = (selectedDate: ?Date) => this.setState({ selectedDate });
+ updateSelectedDate = (selectedDate: ?Date) => this.props.updateQuery({ selectedDate });
updateGraphZoom = (graphStartDate: ?Date, graphEndDate: ?Date) => {
if (graphEndDate != null && graphStartDate != null) {
@@ -138,7 +137,7 @@ export default class ProjectActivityGraphs extends React.PureComponent {
measuresHistory={this.props.measuresHistory}
metricsType={metricsType}
project={this.props.project}
- selectedDate={this.state.selectedDate}
+ selectedDate={this.props.query.selectedDate}
series={series}
updateGraphZoom={this.updateGraphZoom}
updateSelectedDate={this.updateSelectedDate}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/StaticGraphs.js b/server/sonar-web/src/main/js/apps/projectActivity/components/StaticGraphs.js
index fbea7a4d2c8..d07737c8d02 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/StaticGraphs.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/StaticGraphs.js
@@ -47,6 +47,7 @@ type Props = {
};
type State = {
+ selectedDate?: ?Date,
tooltipIdx: ?number,
tooltipXPos: ?number
};
@@ -86,8 +87,8 @@ export default class StaticGraphs extends React.PureComponent {
hasSeriesData = () => some(this.props.series, serie => serie.data && serie.data.length > 2);
- updateTooltipPos = (tooltipXPos: ?number, tooltipIdx: ?number) =>
- this.setState({ tooltipXPos, tooltipIdx });
+ updateTooltip = (selectedDate: ?Date, tooltipXPos: ?number, tooltipIdx: ?number) =>
+ this.setState({ selectedDate, tooltipXPos, tooltipIdx });
render() {
const { loading } = this.props;
@@ -111,8 +112,8 @@ export default class StaticGraphs extends React.PureComponent {
</div>
);
}
-
- const { graph, selectedDate, series } = this.props;
+ const { selectedDate, tooltipIdx, tooltipXPos } = this.state;
+ const { graph, series } = this.props;
return (
<div className="project-activity-graph-container">
<StaticGraphsLegend series={series} />
@@ -129,16 +130,16 @@ export default class StaticGraphs extends React.PureComponent {
formatYTick={this.formatValue}
leakPeriodDate={this.props.leakPeriodDate}
metricType={this.props.metricsType}
- selectedDate={selectedDate}
+ selectedDate={this.props.selectedDate}
series={series}
showAreas={['coverage', 'duplications'].includes(graph)}
startDate={this.props.graphStartDate}
updateSelectedDate={this.props.updateSelectedDate}
- updateTooltipPos={this.updateTooltipPos}
+ updateTooltip={this.updateTooltip}
updateZoom={this.props.updateGraphZoom}
/>
{selectedDate != null &&
- this.state.tooltipXPos != null &&
+ tooltipXPos != null &&
<GraphsTooltips
formatValue={this.formatValue}
graph={graph}
@@ -146,8 +147,8 @@ export default class StaticGraphs extends React.PureComponent {
measuresHistory={this.props.measuresHistory}
selectedDate={selectedDate}
series={series}
- tooltipIdx={this.state.tooltipIdx}
- tooltipPos={this.state.tooltipXPos}
+ tooltipIdx={tooltipIdx}
+ tooltipPos={tooltipXPos}
/>}
</div>
)}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap
index b97c9aa9054..91f1dcdc0e4 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap
@@ -117,6 +117,7 @@ exports[`should render correctly 1`] = `
"project": "org.sonarsource.sonarqube:sonarqube",
}
}
+ updateQuery={[Function]}
/>
</div>
<div
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css b/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css
index 1702b791a09..903bd9ff4f9 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css
+++ b/server/sonar-web/src/main/js/apps/projectActivity/components/projectActivity.css
@@ -119,6 +119,14 @@
cursor: pointer;
}
+.project-activity-analysis.selected {
+ background-color: #ecf6fe;
+}
+
+.project-activity-analysis:focus {
+ outline: none;
+}
+
.project-activity-analysis:hover {
background-color: #ecf6fe;
}
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/types.js b/server/sonar-web/src/main/js/apps/projectActivity/types.js
index 106fb632866..f3c75fa8535 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/types.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/types.js
@@ -53,5 +53,6 @@ export type Query = {
from?: Date,
graph: string,
project: string,
- to?: Date
+ to?: Date,
+ selectedDate?: Date
};
diff --git a/server/sonar-web/src/main/js/apps/projectActivity/utils.js b/server/sonar-web/src/main/js/apps/projectActivity/utils.js
index 50b3ab32929..5e04dcc5436 100644
--- a/server/sonar-web/src/main/js/apps/projectActivity/utils.js
+++ b/server/sonar-web/src/main/js/apps/projectActivity/utils.js
@@ -49,16 +49,25 @@ export const GRAPHS_METRICS = {
};
export const activityQueryChanged = (prevQuery: Query, nextQuery: Query): boolean =>
- prevQuery.category !== nextQuery.category ||
- prevQuery.from !== nextQuery.from ||
- prevQuery.to !== nextQuery.to;
+ prevQuery.category !== nextQuery.category || datesQueryChanged(prevQuery, nextQuery);
-export const datesQueryChanged = (prevQuery: Query, nextQuery: Query): boolean =>
- prevQuery.from !== nextQuery.from || prevQuery.to !== nextQuery.to;
+export const datesQueryChanged = (prevQuery: Query, nextQuery: Query): boolean => {
+ const nextFrom = nextQuery.from ? nextQuery.from.valueOf() : null;
+ const previousFrom = prevQuery.from ? prevQuery.from.valueOf() : null;
+ const nextTo = nextQuery.to ? nextQuery.to.valueOf() : null;
+ const previousTo = prevQuery.to ? prevQuery.to.valueOf() : null;
+ return previousFrom !== nextFrom || previousTo !== nextTo;
+};
export const historyQueryChanged = (prevQuery: Query, nextQuery: Query): boolean =>
prevQuery.graph !== nextQuery.graph;
+export const selectedDateQueryChanged = (prevQuery: Query, nextQuery: Query): boolean => {
+ const nextSelectedDate = nextQuery.selectedDate ? nextQuery.selectedDate.valueOf() : null;
+ const previousSelectedDate = prevQuery.selectedDate ? prevQuery.selectedDate.valueOf() : null;
+ return nextSelectedDate !== previousSelectedDate;
+};
+
export const generateCoveredLinesMetric = (
uncoveredLines: MeasureHistory,
measuresHistory: Array<MeasureHistory>,
@@ -143,7 +152,8 @@ export const parseQuery = (urlQuery: RawQuery): Query => ({
from: parseAsDate(urlQuery['from']),
graph: parseGraph(urlQuery['graph']),
project: parseAsString(urlQuery['id']),
- to: parseAsDate(urlQuery['to'])
+ to: parseAsDate(urlQuery['to']),
+ selectedDate: parseAsDate(urlQuery['selected_date'])
});
export const serializeQuery = (query: Query): RawQuery =>
@@ -160,6 +170,7 @@ export const serializeUrlQuery = (query: Query): RawQuery => {
from: serializeDate(query.from),
graph: serializeGraph(query.graph),
id: serializeString(query.project),
- to: serializeDate(query.to)
+ to: serializeDate(query.to),
+ selected_date: serializeDate(query.selectedDate)
});
};
diff --git a/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js b/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js
index fc2123d1fe4..413a53a78d3 100644
--- a/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js
+++ b/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js
@@ -50,7 +50,7 @@ type Props = {
showEventMarkers?: boolean,
startDate: ?Date,
updateSelectedDate?: (selectedDate: ?Date) => void,
- updateTooltipPos?: (tooltipXPos: ?number, tooltipIdx: ?number) => void,
+ updateTooltip?: (selectedDate: ?Date, tooltipXPos: ?number, tooltipIdx: ?number) => void,
updateZoom?: (start: ?Date, endDate: ?Date) => void,
zoomSpeed: number
};
@@ -59,6 +59,7 @@ type State = {
maxXRange: Array<number>,
mouseOver?: boolean,
mouseOverlayPos?: { [string]: number },
+ selectedDate: ?Date,
selectedDateXPos: ?number,
selectedDateIdx: ?number,
yScale: Scale,
@@ -78,8 +79,9 @@ export default class AdvancedTimeline extends React.PureComponent {
constructor(props: Props) {
super(props);
const scales = this.getScales(props);
- this.state = { ...scales, ...this.getSelectedDatePos(scales.xScale, props.selectedDate) };
- this.updateSelectedDate = throttle(this.updateSelectedDate, 40);
+ const selectedDatePos = this.getSelectedDatePos(scales.xScale, props.selectedDate);
+ this.state = { ...scales, ...selectedDatePos };
+ this.updateTooltipPos = throttle(this.updateTooltipPos, 40);
}
componentWillReceiveProps(nextProps: Props) {
@@ -100,8 +102,9 @@ export default class AdvancedTimeline extends React.PureComponent {
const xScale = scales ? scales.xScale : this.state.xScale;
const selectedDatePos = this.getSelectedDatePos(xScale, nextProps.selectedDate);
this.setState({ ...scales, ...selectedDatePos });
- if (nextProps.updateTooltipPos) {
- nextProps.updateTooltipPos(
+ if (nextProps.updateTooltip) {
+ nextProps.updateTooltip(
+ selectedDatePos.selectedDate,
selectedDatePos.selectedDateXPos,
selectedDatePos.selectedDateIdx
);
@@ -158,12 +161,13 @@ export default class AdvancedTimeline extends React.PureComponent {
this.props.series.some(serie => serie.data[idx].y || serie.data[idx].y === 0)
) {
return {
+ selectedDate,
selectedDateXPos: xScale(selectedDate),
selectedDateIdx: idx
};
}
}
- return { selectedDateXPos: null, selectedDateIdx: null };
+ return { selectedDate: null, selectedDateXPos: null, selectedDateIdx: null };
};
getEventMarker = (size: number) => {
@@ -197,31 +201,43 @@ export default class AdvancedTimeline extends React.PureComponent {
handleMouseMove = (evt: MouseEvent & { target: HTMLElement }) => {
const parentBbox = this.getMouseOverlayPos(evt.target);
- this.updateSelectedDate(evt.pageX - parentBbox.left);
+ this.updateTooltipPos(evt.pageX - parentBbox.left);
};
handleMouseEnter = () => this.setState({ mouseOver: true });
handleMouseOut = (evt: Event & { relatedTarget: HTMLElement }) => {
- const { updateSelectedDate } = this.props;
+ const { updateTooltip } = this.props;
const targetClass = evt.relatedTarget && typeof evt.relatedTarget.className === 'string'
? evt.relatedTarget.className
: '';
if (
- !updateSelectedDate ||
+ !updateTooltip ||
targetClass.includes('bubble-popup') ||
targetClass.includes('graph-tooltip')
) {
return;
}
- this.setState({ mouseOver: false });
- updateSelectedDate(null);
+ this.setState({
+ mouseOver: false,
+ selectedDate: null,
+ selectedDateXPos: null,
+ selectedDateIdx: null
+ });
+ updateTooltip(null, null, null);
};
- updateSelectedDate = (xPos: number) => {
+ handleClick = () => {
const { updateSelectedDate } = this.props;
+ if (updateSelectedDate) {
+ updateSelectedDate(this.state.selectedDate);
+ }
+ };
+
+ updateTooltipPos = (xPos: number) => {
const firstSerie = this.props.series[0];
- if (this.state.mouseOver && firstSerie && updateSelectedDate) {
+ if (this.state.mouseOver && firstSerie) {
+ const { updateTooltip } = this.props;
const date = this.state.xScale.invert(xPos);
const bisectX = bisector(d => d.x).right;
let idx = bisectX(firstSerie.data, date);
@@ -231,7 +247,12 @@ export default class AdvancedTimeline extends React.PureComponent {
if (!nextPoint || (previousPoint && date - previousPoint.x <= nextPoint.x - date)) {
idx--;
}
- updateSelectedDate(firstSerie.data[idx].x);
+ const selectedDate = firstSerie.data[idx].x;
+ const xPos = this.state.xScale(selectedDate);
+ this.setState({ selectedDate, selectedDateXPos: xPos, selectedDateIdx: idx });
+ if (updateTooltip) {
+ updateTooltip(selectedDate, xPos, idx);
+ }
}
}
};
@@ -428,11 +449,14 @@ export default class AdvancedTimeline extends React.PureComponent {
if (zoomEnabled) {
mouseEvents.onWheel = this.handleWheel;
}
- if (this.props.updateSelectedDate) {
+ if (this.props.updateTooltip) {
mouseEvents.onMouseEnter = this.handleMouseEnter;
mouseEvents.onMouseMove = this.handleMouseMove;
mouseEvents.onMouseOut = this.handleMouseOut;
}
+ if (this.props.updateSelectedDate) {
+ mouseEvents.onClick = this.handleClick;
+ }
return (
<rect
className="chart-mouse-events-overlay"