Commit adf69885 authored by Lauri Himanen's avatar Lauri Himanen Committed by Markus Scheidgen
Browse files

Finally tooltips are working nicely together with SVG canvas.

parent 3186c52d
import React, { useRef, useState, useEffect } from 'react' import React, { useRef, useState, useEffect } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Select, MenuItem, Card, CardContent, CardHeader, makeStyles } from '@material-ui/core' import { Select, MenuItem, Card, CardContent, CardHeader, makeStyles, Tooltip } from '@material-ui/core'
import * as d3 from 'd3' import * as d3 from 'd3'
import { scaleBand, scalePow } from 'd3-scale' import { scaleBand, scalePow } from 'd3-scale'
import { formatQuantity, nomadPrimaryColor, nomadSecondaryColor, nomadFontFamily } from '../config.js' import { formatQuantity, nomadPrimaryColor, nomadSecondaryColor, nomadFontFamily } from '../config.js'
...@@ -42,20 +42,18 @@ const useStyles = makeStyles(theme => ({ ...@@ -42,20 +42,18 @@ const useStyles = makeStyles(theme => ({
position: 'relative' position: 'relative'
}, },
tooltip: { tooltip: {
textAlign: 'center', width: '100%',
position: 'absolute', height: '100%'
pointerEvents: 'none',
opacity: 0
}, },
tooltipContent: { tooltipContent: {
// copy of the material ui popper style position: 'absolute',
display: 'inline-block', // backgroundColor: '#ffbb00' // Uncomment for debugging tooltips
color: '#fff', display: 'none',
padding: '4px 8px', zIndex: 1,
fontSize: '0.625rem', cursor: 'pointer'
lineHeight: '1.4em', },
borderRadius: '4px', canvas: {
backgroundColor: '#616161' zIndex: 2
} }
})) }))
export default function Histogram({ export default function Histogram({
...@@ -68,11 +66,17 @@ export default function Histogram({ ...@@ -68,11 +66,17 @@ export default function Histogram({
getValueLabel = getValueLabel || (value => value.name) getValueLabel = getValueLabel || (value => value.name)
title = title || 'Histogram' title = title || 'Histogram'
const [tooltipHTML, setTooltipHTML] = useState()
const [item, setItem] = useState()
const [scale, setScale] = useState(initialScale)
const classes = useStyles() const classes = useStyles()
const containerRef = useRef() const containerRef = useRef()
const [scale, setScale] = useState(initialScale)
const handleItemClicked = item => onClick(item) const handleItemClicked = item => {
if (item.value !== 0) {
onClick(item)
}
}
useEffect(() => { useEffect(() => {
for (let i = data.length; i < numberOfValues; i++) { for (let i = data.length; i < numberOfValues; i++) {
...@@ -88,6 +92,7 @@ export default function Histogram({ ...@@ -88,6 +92,7 @@ export default function Histogram({
const containerWidth = containerRef.current.offsetWidth const containerWidth = containerRef.current.offsetWidth
const width = containerWidth / columns - (12 * (columns - 1)) const width = containerWidth / columns - (12 * (columns - 1))
const height = columnSize * 32 const height = columnSize * 32
const padding = 16
const x = scalePow().range([0, width]).exponent(scale) const x = scalePow().range([0, width]).exponent(scale)
...@@ -96,16 +101,21 @@ export default function Histogram({ ...@@ -96,16 +101,21 @@ export default function Histogram({
x.domain([0, max]) x.domain([0, max])
const rectColor = d => isSelected(d, selected, multiple) ? nomadPrimaryColor.dark : nomadSecondaryColor.light const rectColor = d => isSelected(d, selected, multiple) ? nomadPrimaryColor.dark : nomadSecondaryColor.light
const textColor = d => isSelected(d, selected, multiple) ? '#FFF' : '#000' const textColor = d => {
if (d.value === 0) {
return '#999'
}
return isSelected(d, selected, multiple) ? '#FFF' : '#000'
}
const container = d3.select(containerRef.current) const container = d3.select(containerRef.current)
const tooltip = container.select('.' + classes.tooltip)
.style('width', width + 'px')
.style('opacity', 0)
const tooltipContent = container.select('.' + classes.tooltipContent) const tooltipContent = container.select('.' + classes.tooltipContent)
const svg = container.select('svg') const svg = container.select('svg')
.attr('width', containerWidth) .attr('width', containerWidth)
.attr('height', height) .attr('height', height)
tooltipContent
.style('width', width + 'px')
.style('height', 27 + 'px')
const columnsG = svg const columnsG = svg
.selectAll('.column') .selectAll('.column')
...@@ -130,12 +140,14 @@ export default function Histogram({ ...@@ -130,12 +140,14 @@ export default function Histogram({
items.exit().remove() items.exit().remove()
items items
.on('click', d => handleItemClicked(d)) .on('click', handleItemClicked)
let item = items.enter() let item = items.enter()
.append('g') .append('g')
.attr('class', 'item') .attr('class', 'item')
.attr('display', d => getValueLabel(d) === '' ? 'none' : 'show') .attr('display', d => getValueLabel(d) === '' ? 'none' : 'show')
.style('cursor', 'pointer')
.on('click', handleItemClicked)
item item
.append('rect') .append('rect')
...@@ -181,31 +193,19 @@ export default function Histogram({ ...@@ -181,31 +193,19 @@ export default function Histogram({
.text(d => formatQuantity(d.value)) .text(d => formatQuantity(d.value))
item item
.style('cursor', 'pointer') .on('mouseenter', function(d) {
.on('click', d => handleItemClicked(d)) setItem(d)
item
.on('mouseover', function(d) {
d3.select(this).select('.background')
.style('opacity', 0.08)
if (tooltips) { if (tooltips) {
tooltip.transition() if (d.tooltip) {
.duration(200) tooltipContent
.style('opacity', 1) .style('left', i * (width) + padding + 'px')
tooltip .style('top', (y(d.key)) + 'px')
.style('left', i * (width + 12) + 'px') .style('display', 'block')
.style('top', (y(d.key) + 32) + 'px') setTooltipHTML(d.tooltip)
tooltipContent.html(getValueLabel(d)) }
} }
}) })
.on('mouseout', function(d) { .on('mouseleave', function(d) {
d3.select(this).select('.background')
.style('opacity', 0)
if (tooltips) {
tooltip.transition()
.duration(200)
.style('opacity', 0)
}
}) })
item = items.transition(d3.transition().duration(500)) item = items.transition(d3.transition().duration(500))
...@@ -234,9 +234,16 @@ export default function Histogram({ ...@@ -234,9 +234,16 @@ export default function Histogram({
const chart = <div ref={containerRef}> const chart = <div ref={containerRef}>
<div className={classes.tooltip}> <div className={classes.tooltip}>
<div className={classes.tooltipContent}></div> <Tooltip
interactive
placement='right'
title={tooltipHTML}
>
<div className={classes.tooltipContent} onClick={() => { handleItemClicked(item) }}>
</div>
</Tooltip>
<svg className={classes.canvas}></svg>
</div> </div>
<svg />
</div> </div>
if (card) { if (card) {
......
...@@ -173,7 +173,7 @@ export function DFTPropertyVisualizations(props) { ...@@ -173,7 +173,7 @@ export function DFTPropertyVisualizations(props) {
return ( return (
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid item xs={7}> <Grid item xs={7}>
<QuantityHistogram quantity="dft.searchable_quantities" values={electronic_quantities} valueLabels={labels} title="Electronic" initialScale={0.5} tooltips multiple/> <QuantityHistogram quantity="dft.searchable_quantities" values={electronic_quantities} valueLabels={labels} title="Electronic" initialScale={0.5} tooltips={labels} multiple/>
<QuantityHistogram quantity="dft.searchable_quantities" values={mechanical_quantities} valueLabels={labels} title="Mechanical" initialScale={0.5} multiple/> <QuantityHistogram quantity="dft.searchable_quantities" values={mechanical_quantities} valueLabels={labels} title="Mechanical" initialScale={0.5} multiple/>
<QuantityHistogram quantity="dft.searchable_quantities" values={thermal_quantities} valueLabels={labels} title="Thermal" initialScale={0.5} multiple/> <QuantityHistogram quantity="dft.searchable_quantities" values={thermal_quantities} valueLabels={labels} title="Thermal" initialScale={0.5} multiple/>
<QuantityHistogram quantity="dft.searchable_quantities" values={optical_quantities} valueLabels={labels} title="Optical" initialScale={1} multiple/> <QuantityHistogram quantity="dft.searchable_quantities" values={optical_quantities} valueLabels={labels} title="Optical" initialScale={1} multiple/>
......
...@@ -18,9 +18,12 @@ export default function QuantityHistogram({ ...@@ -18,9 +18,12 @@ export default function QuantityHistogram({
const statisticsData = statistics[quantity] const statisticsData = statistics[quantity]
const handleItemClicked = useCallback(item => { const handleItemClicked = useCallback(item => {
console.log(quantity)
console.log(query)
if (multiple) { if (multiple) {
// Add or remove item from query // Add or remove item from query
let newQuery = query[quantity] let newQuery = query[quantity]
console.log("Old query: " + newQuery)
if (newQuery === undefined) { if (newQuery === undefined) {
newQuery = [item.key] newQuery = [item.key]
} else { } else {
...@@ -35,6 +38,7 @@ export default function QuantityHistogram({ ...@@ -35,6 +38,7 @@ export default function QuantityHistogram({
} }
newQuery = Array.from(newQuery.values()) newQuery = Array.from(newQuery.values())
} }
console.log("New query: " + newQuery)
setQuery({[quantity]: newQuery}) setQuery({[quantity]: newQuery})
} else { } else {
setQuery({[quantity]: (query[quantity] === item.key) ? null : item.key}) setQuery({[quantity]: (query[quantity] === item.key) ? null : item.key})
...@@ -50,7 +54,7 @@ export default function QuantityHistogram({ ...@@ -50,7 +54,7 @@ export default function QuantityHistogram({
key: value, key: value,
name: valueLabels[value] || value, name: valueLabels[value] || value,
value: statisticsData[value] ? statisticsData[value][metric] : 0, value: statisticsData[value] ? statisticsData[value][metric] : 0,
tooltip: tooltips[value] || valueLabels[value] || value tooltip: tooltips[value]
})) }))
} else { } else {
data = Object.keys(statisticsData) data = Object.keys(statisticsData)
...@@ -79,6 +83,7 @@ export default function QuantityHistogram({ ...@@ -79,6 +83,7 @@ export default function QuantityHistogram({
onClick={handleItemClicked} onClick={handleItemClicked}
selected={query[quantity]} selected={query[quantity]}
multiple={multiple} multiple={multiple}
tooltips={!!tooltips}
{...props} {...props}
/> />
} }
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment