Skip to content

Commit

Permalink
Display info message regarding wheel zoom
Browse files Browse the repository at this point in the history
Also renamed Settings component to UserSettings since it is not as tightly linked to Settings in redux as you might expect from the name.

Added setting to regret clicking do not display again on wheel zoom info message.
  • Loading branch information
eijawerner committed Feb 7, 2022
1 parent d3ed396 commit 19f5963
Show file tree
Hide file tree
Showing 21 changed files with 294 additions and 70 deletions.
15 changes: 11 additions & 4 deletions src/browser/components/icons/Icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import copy from 'icons/copy.svg'
import databaseCheck from 'icons/database-check.svg'
import saveFavorite from 'icons/favorite.svg'
import file from 'icons/file.svg'
import fitToScreenIcon from 'icons/fit-to-screen.svg'
import folderEmpty from 'icons/folder-empty.svg'
import close from 'icons/frame-close.svg'
import upCaret from 'icons/frame-collapse.svg'
Expand All @@ -46,6 +45,10 @@ import pin from 'icons/frame-pin.svg'
import shrink from 'icons/frame-shrink.svg'
import help from 'icons/help.svg'
import vizIcon from 'icons/hierarchy-9.svg'
import fitToScreenIcon from 'icons/iconsToBeFetchedFromNDL/fit-to-screen.svg'
import infoCircle from 'icons/iconsToBeFetchedFromNDL/information-circle.svg'
import zoomInIcon from 'icons/iconsToBeFetchedFromNDL/zoom-in.svg'
import zoomOutIcon from 'icons/iconsToBeFetchedFromNDL/zoom-out.svg'
import monitorPlay from 'icons/monitor-play.svg'
import navigationMenuVertical from 'icons/navigation-menu-vertical.svg'
import neo4j from 'icons/neo4j-icon.svg'
Expand All @@ -54,8 +57,6 @@ import download from 'icons/save.svg'
import skipPrev from 'icons/skip-prev.svg'
import table from 'icons/table.svg'
import text from 'icons/text.svg'
import zoomInIcon from 'icons/zoom-in.svg'
import zoomOutIcon from 'icons/zoom-out.svg'

const inactive = `
color: #797979;
Expand Down Expand Up @@ -287,7 +288,11 @@ export const ZoomInIcon = ({ large }: { large: boolean }): JSX.Element => {
/>
)
}
export const ZoomOutIcon = ({ large }: { large: boolean }): JSX.Element => {
export const ZoomOutIcon = ({
large = false
}: {
large?: boolean
}): JSX.Element => {
const scale = large ? ZOOM_ICONS_LARGE_SCALE_FACTOR : 1
return (
<IconContainer
Expand Down Expand Up @@ -457,3 +462,5 @@ export const CopyIcon = ({
}: TitleAndWidthProps): JSX.Element => (
<IconContainer title={title} width={width} icon={copy} />
)

export const InfoIcon = (): JSX.Element => <IconContainer icon={infoCircle} />
File renamed without changes
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
4 changes: 2 additions & 2 deletions src/browser/modules/App/PerformanceOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useEffect, useRef } from 'react'
import { connect } from 'react-redux'
import styled from 'styled-components'

import { shouldshowPerformanceOverlay } from 'shared/modules/settings/settingsDuck'
import { shouldShowPerformanceOverlay } from 'shared/modules/settings/settingsDuck'

function perfTracker() {
let lastTime = performance.now()
Expand Down Expand Up @@ -139,7 +139,7 @@ const Overlay = styled.div`
`

const mapStateToProps = (state: any) => ({
shouldShow: shouldshowPerformanceOverlay(state)
shouldShow: shouldShowPerformanceOverlay(state)
})

export default connect(mapStateToProps)(PerformanceOverlay)
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { GetNodeNeighboursFn } from '../GraphEventHandler'
import { GraphStyle } from '../graphStyle'
import Graph from '../lib/visualization/components/Graph'
import { GraphStats } from '../mapper'
import { GraphComponent } from './Graph'
import GraphComponent from './Graph'
import { NodeInspectorPanel, defaultPanelWidth } from './NodeInspectorPanel'
import { StyledFullSizeContainer, panelMinWidth } from './styled'
import { VizItem } from './types'
Expand Down
90 changes: 78 additions & 12 deletions src/browser/modules/D3Visualization/components/Graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from 'react'
import { connect } from 'react-redux'
import { Action, Dispatch } from 'redux'

import { GetNodeNeighboursFn, GraphEventHandler } from '../GraphEventHandler'
import GraphStyle from '../graphStyle'
Expand All @@ -29,6 +31,7 @@ import {
getGraphStats,
mapRelationships
} from '../mapper'
import { WheelZoomInfoOverlay } from './WheelZoomInfoOverlay'
import { StyledSvgWrapper, StyledZoomButton, StyledZoomHolder } from './styled'
import { VizItem } from './types'
import {
Expand All @@ -37,8 +40,14 @@ import {
ZoomToFitIcon
} from 'browser-components/icons/Icons'
import { ZoomLimitsReached } from 'project-root/src/browser/modules/D3Visualization/lib/visualization/components/Visualization'
import { GlobalState } from 'project-root/src/shared/globalState'
import { shouldShowWheelZoomInfo } from 'project-root/src/shared/modules/settings/settingsDuck'
import * as actions from 'project-root/src/shared/modules/settings/settingsDuck'
import { BasicNode, BasicRelationship } from 'services/bolt/boltMappings'

const DISPLAY_WHEEL_ZOOM_INFO_DURATION_MS = 3000
const DISPLAY_WHEEL_ZOOM_INFO_MAX_TIMES = 10000 // TODO: remove! replace with consent

type GraphProps = {
isFullscreen: boolean
relationships: BasicRelationship[]
Expand All @@ -55,20 +64,28 @@ type GraphProps = {
) => void
setGraph: (graph: Graph) => void
offset: number
shouldShowWheelZoomInfo: boolean
updateShouldShowWheelZoomInfo: (showWheelZoomInfo: boolean) => void
}

type GraphState = {
zoomInLimitReached: boolean
zoomOutLimitReached: boolean
displayWheelZoomInfoMessage: boolean
}

export class GraphComponent extends React.Component<GraphProps, GraphState> {
class GraphComponent extends React.Component<GraphProps, GraphState> {
svgElement: React.RefObject<SVGSVGElement>
graphView: GraphView | null = null
displayWheelZoomInfoTimerId: number | undefined

constructor(props: GraphProps) {
super(props)
this.state = { zoomInLimitReached: false, zoomOutLimitReached: false }
this.state = {
zoomInLimitReached: false,
zoomOutLimitReached: false,
displayWheelZoomInfoMessage: false
}
this.svgElement = React.createRef()
}

Expand Down Expand Up @@ -99,6 +116,7 @@ export class GraphComponent extends React.Component<GraphProps, GraphState> {
this.svgElement.current,
measureSize,
this.handleZoomEvent,
this.handleDisplayZoomWheelInfoMessage,
graph,
graphStyle,
isFullscreen
Expand Down Expand Up @@ -139,6 +157,20 @@ export class GraphComponent extends React.Component<GraphProps, GraphState> {
}
}

componentDidUpdate(prevProps: GraphProps): void {
if (this.props.isFullscreen !== prevProps.isFullscreen) {
this.graphView?.resize(this.props.isFullscreen)
}

if (this.props.styleVersion !== prevProps.styleVersion) {
this.graphView?.init()
}
}

componentWillUnmount(): void {
clearTimeout(this.displayWheelZoomInfoTimerId)
}

handleZoomEvent = (limitsReached: ZoomLimitsReached): void => {
if (
limitsReached.zoomInLimitReached !== this.state.zoomInLimitReached ||
Expand All @@ -151,6 +183,28 @@ export class GraphComponent extends React.Component<GraphProps, GraphState> {
}
}

handleDisplayZoomWheelInfoMessage = (): void => {
if (
!this.state.displayWheelZoomInfoMessage &&
this.props.shouldShowWheelZoomInfo
) {
this.displayZoomWheelInfoMessage(true)
setTimeout(
this.displayZoomWheelInfoMessage,
DISPLAY_WHEEL_ZOOM_INFO_DURATION_MS,
false
)
}
}

displayZoomWheelInfoMessage = (show: boolean): void => {
this.setState({ displayWheelZoomInfoMessage: show })
}

updateShouldShowWheelZoomInfo = (show: boolean): void => {
this.props.updateShouldShowWheelZoomInfo(show)
}

zoomInClicked = (): void => {
if (this.graphView) {
this.graphView.zoomIn()
Expand All @@ -170,8 +224,12 @@ export class GraphComponent extends React.Component<GraphProps, GraphState> {
}

render(): JSX.Element {
const { offset, isFullscreen } = this.props
const { zoomInLimitReached, zoomOutLimitReached } = this.state
const { offset, isFullscreen, shouldShowWheelZoomInfo } = this.props
const {
zoomInLimitReached,
zoomOutLimitReached,
displayWheelZoomInfoMessage
} = this.state
return (
<StyledSvgWrapper>
<svg className="neod3viz" ref={this.svgElement} />
Expand All @@ -197,17 +255,25 @@ export class GraphComponent extends React.Component<GraphProps, GraphState> {
<ZoomToFitIcon large={isFullscreen} />
</StyledZoomButton>
</StyledZoomHolder>
{shouldShowWheelZoomInfo && (
<WheelZoomInfoOverlay
hide={isFullscreen || !displayWheelZoomInfoMessage}
onShouldShowUpdate={this.updateShouldShowWheelZoomInfo}
/>
)}
</StyledSvgWrapper>
)
}
}

componentDidUpdate(prevProps: GraphProps): void {
if (this.props.isFullscreen !== prevProps.isFullscreen) {
this.graphView?.resize(this.props.isFullscreen)
}
const mapStateToProps = (state: GlobalState) => ({
shouldShowWheelZoomInfo: shouldShowWheelZoomInfo(state)
})

if (this.props.styleVersion !== prevProps.styleVersion) {
this.graphView?.init()
}
const mapDispatchToProps = (dispatch: Dispatch<Action>) => ({
updateShouldShowWheelZoomInfo: (showWheelZoomInfo: boolean) => {
dispatch(actions.update({ showWheelZoomInfo: showWheelZoomInfo }))
}
}
})

export default connect(mapStateToProps, mapDispatchToProps)(GraphComponent)
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { ChangeEvent, useState } from 'react'

import {
StyledZoomInfo,
StyledZoomInfoCheckbox,
StyledZoomInfoCheckboxLabel,
StyledZoomInfoIconContainer,
StyledZoomInfoOverlay,
StyledZoomInfoText,
StyledZoomInfoTextContainer
} from './styled'
import { InfoIcon } from 'browser-components/icons/Icons'

const getModKeyString = () => {
const isOnMacComputer = navigator.appVersion.indexOf('Mac') !== -1
if (isOnMacComputer) {
return 'Cmd'
} else {
return 'Ctrl or Shift'
}
}

type WheelZoomInfoProps = {
hide: boolean
onShouldShowUpdate: (show: boolean) => void
}
export const WheelZoomInfoOverlay = ({
hide,
onShouldShowUpdate
}: WheelZoomInfoProps) => {
const [doNotShowAgain, setDoNotShowAgain] = useState<boolean>(false)
const handleCheckBoxChange = (event: ChangeEvent<HTMLInputElement>) => {
const doNotShow = event.currentTarget.checked
setDoNotShowAgain(doNotShow)
onShouldShowUpdate(!doNotShow)
}
return (
<StyledZoomInfoOverlay>
<StyledZoomInfo hide={hide}>
<StyledZoomInfoTextContainer>
<StyledZoomInfoIconContainer>
<InfoIcon />
</StyledZoomInfoIconContainer>
<StyledZoomInfoText>{`Use ${getModKeyString()} + scroll to zoom`}</StyledZoomInfoText>
</StyledZoomInfoTextContainer>

<StyledZoomInfoCheckbox>
<input
type="checkbox"
id="wheelZoomInfoCheckbox"
checked={doNotShowAgain}
onChange={handleCheckBoxChange}
/>
<StyledZoomInfoCheckboxLabel htmlFor="wheelZoomInfoCheckbox">
{`Don't show again`}
</StyledZoomInfoCheckboxLabel>
</StyledZoomInfoCheckbox>
</StyledZoomInfo>
</StyledZoomInfoOverlay>
)
}
69 changes: 55 additions & 14 deletions src/browser/modules/D3Visualization/components/styled.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,16 +107,6 @@ export const StyledSvgWrapper = styled.div`
}
`

export const StyledRowToggle = styled.div`
float: right;
display: block;
width: 21px;
height: 21px;
line-height: 21px;
text-align: center;
cursor: pointer;
`

export const StyledInlineList = styled.ul`
list-style: none;
word-break: break-word;
Expand Down Expand Up @@ -162,10 +152,6 @@ export const StyledTokenRelationshipType = styled(StyledToken)`
cursor: default;
`

export const StyledTokenCount = styled.span`
font-weight: normal;
`

export const StyledLegendInlineList = styled(StyledInlineList)`
padding: 4px 0 0 0;
&.contracted {
Expand Down Expand Up @@ -373,3 +359,58 @@ export const StyledExpandValueButton = styled.button`
background-color: inherit;
color: ${props => props.theme.link};
`

export const StyledZoomInfoOverlay = styled.div`
position: absolute;
width: 100%;
bottom: 2rem;
display: flex;
flex-direction: row;
pointer-events: none;
`

export const StyledZoomInfo = styled.div<{ hide: boolean }>`
background: ${props => props.theme.infoBackground};
position: relative;
border: ${props => props.theme.infoBorder};
border-radius: 4px;
box-shadow: ${props => props.theme.standardShadow}
margin-left: auto;
margin-right: auto;
padding: 1rem;
transition: opacity 1.5s ease-in-out;
opacity: ${props => (props.hide ? 0 : 1)};
flex: 0 0 auto;
display: flex;
flex-direction: column;
align-items: baseline;
gap: 1rem;
pointer-events: ${props => (props.hide ? 'none' : 'auto')};
`

export const StyledZoomInfoTextContainer = styled.div`
display: flex;
flex-direction: row;
align-items: center;
gap: 1rem;
`

export const StyledZoomInfoText = styled.span`
line-height: 1.5rem;
`

export const StyledZoomInfoIconContainer = styled.div`
color: ${props => props.theme.infoIconColor};
`

export const StyledZoomInfoCheckbox = styled.div`
display: flex;
flex-direction: row;
align-items: center;
gap: 0.5rem;
margin-left: 30px;
`

export const StyledZoomInfoCheckboxLabel = styled.label`
font-size: 12px;
`

0 comments on commit 19f5963

Please sign in to comment.