From cfd95ce1db2beea2289f51c21b9e1f100bfd853d Mon Sep 17 00:00:00 2001 From: Andrew Sutherland Date: Mon, 28 May 2018 17:16:55 -0400 Subject: [PATCH] implement next/prev and zoom-in/zoom-out buttons on timeline toolbar This makes the "Filters" button prettier too. Note that a forked version of binary-search-bounds was adopted that fixes https://github.com/mikolalysenko/binary-search-bounds/issues/5 wherein new Function() was being used in an eval style that is to be avoided. --- package-lock.json | 4 ++ package.json | 1 + .../components/sheets/trice_timeline.jsx | 59 ++++++++++++++++++- .../trice_timeline/timeline_vis.jsx | 8 +++ src/grokysis/frontend/trice_log.js | 25 ++++++++ 5 files changed, 95 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7df3dfd..505709c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -984,6 +984,10 @@ "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=", "dev": true }, + "binary-search-bounds": { + "version": "github:bvaughn/binary-search-bounds#971e0ecbabcb1e9e657a68bf7cd937598117b688", + "from": "github:bvaughn/binary-search-bounds#971e0ecbabcb1e9e657a68bf7cd937598117b688" + }, "blob": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", diff --git a/package.json b/package.json index 287feef..33c1ee5 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "dependencies": { + "binary-search-bounds": "github:bvaughn/binary-search-bounds#971e0ecbabcb1e9e657a68bf7cd937598117b688", "d3-array": "^1.2.1", "d3-axis": "^1.0.8", "d3-scale": "^2.0.0", diff --git a/src/grok-ui/components/sheets/trice_timeline.jsx b/src/grok-ui/components/sheets/trice_timeline.jsx index 5397ad0..bb03ab7 100644 --- a/src/grok-ui/components/sheets/trice_timeline.jsx +++ b/src/grok-ui/components/sheets/trice_timeline.jsx @@ -1,6 +1,6 @@ import React from 'react'; -import { Accordion, Button, Icon } from 'semantic-ui-react'; +import { Menu } from 'semantic-ui-react'; import TriceTimelineVis from '../trice_timeline/timeline_vis.jsx'; @@ -42,6 +42,10 @@ export default class TriceTimelineSheet extends React.PureComponent { this.onSeekRequest = this.onSeekRequest.bind(this); this.onRangeChanged = this.onRangeChanged.bind(this); + this.onZoomIn = this.onZoomIn.bind(this); + this.onZoomOut = this.onZoomOut.bind(this); + this.onMovePrev = this.onMovePrev.bind(this); + this.onMoveNext = this.onMoveNext.bind(this); } componentWillMount() { @@ -145,10 +149,61 @@ export default class TriceTimelineSheet extends React.PureComponent { thing.sendSlotMessage('triceLog:filters:seeked', { startBin, endBin }); } + /** Return the underlying vis.js timeline widget to invoke its methods */ + get visJsWidget() { + const visJsx = this.visRef.current; + return visJsx.visJsWidget; + } + + onZoomIn() { + this.visJsWidget.zoomIn(0.5); + } + + onZoomOut() { + this.visJsWidget.zoomOut(0.5); + } + + /** + * Move the window so that the first event preceding the visible window is + * brought to the center of the timline. + */ + onMovePrev() { + const triceLog = this.props.triceLog; + const startTime = this.visJsWidget.getWindow().start.valueOf(); + const event = triceLog.findfirstEventBeforeItemTime(startTime); + if (event) { + this.visJsWidget.moveTo(event.start); + } + } + + onMoveNext() { + const triceLog = this.props.triceLog; + const endTime = this.visJsWidget.getWindow().end.valueOf(); + const event = triceLog.findfirstEventAfterItemTime(endTime); + if (event) { + this.visJsWidget.moveTo(event.start); + } + } + render() { return (
- + + + + + + + + + + + + + + a.tick - b.tick); + /** * The (effective) TOML config file that was used to generate the trace and * may have display hints built-in. By effective, I mean that this might @@ -434,4 +439,24 @@ export default class TriceLog extends EE { const bin = Math.floor(this.NBINS * relTickTime / tickSpan); return bin; } + + findfirstEventBeforeItemTime(itemTime) { + // we can stay in scaled space for this. + const idx = bounds.lt(this.filteredVisItems, { start: itemTime }, + (a, b) => a.start - b.start); + if (idx === -1) { + return null; + } + return this.filteredVisItems[idx]; + } + + findfirstEventAfterItemTime(itemTime) { + // we can stay in scaled space for this. + const idx = bounds.gt(this.filteredVisItems, { start: itemTime }, + (a, b) => a.start - b.start); + if (idx === -1) { + return null; + } + return this.filteredVisItems[idx]; + } }