Skip to content

Commit f42fbd7

Browse files
authored
Merge pull request #96 from go-spatial/dev
Added infotip with screen position awareness
2 parents 31c5389 + 334ac77 commit f42fbd7

File tree

19 files changed

+252
-141
lines changed

19 files changed

+252
-141
lines changed

src/App.css

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,9 @@ label .badge{position:relative;top:2px;}
216216
.link-list.pr-list{padding-right:30px!important;}
217217
.link-list.pl-list{padding-left:30px!important;}
218218

219+
.map-control{cursor:pointer;}
220+
.map-control:hover button{background-color:rgba(0,0,0,.05);}
221+
219222
.map-inspect-list{}
220223
.map-inspect-list li{line-height:1.8;font-size:1.00em;cursor:pointer;}
221224
.map-inspect-list li:hover{background:#EEEEEE;}
@@ -310,30 +313,35 @@ label .badge{position:relative;top:2px;}
310313
.text-nav{line-height:34px;}
311314
.text-overflow-ellipsis{text-overflow:ellipsis;overflow:hidden;white-space: nowrap;}
312315

313-
.tooltip{font-size:0.7rem;}
314-
.tooltip-source{position:absolute;bottom:0;left:0;right:0;text-align:center;height:0;}
315-
.tooltip-source.tooltip-origin-left{bottom:0;left:0;top:0;text-align:center;width:0;}
316-
.tooltip-point{display:inline-block;position:relative;}
316+
.infotip{font-size:0.7rem;position:absolute;top:0;bottom:0;left:0;right:0;}
317+
.infotip-source{position:absolute;bottom:0;left:0;right:0;text-align:center;height:1px;}
318+
.infotip.y.bigY .infotip-source{top:0;left:0;right:0;bottom:auto;}
319+
.infotip.x .infotip-source{bottom:0;right:0;top:0;left:auto;height:auto;width:1px;}
320+
.infotip.x.bigX .infotip-source{bottom:0;left:0;top:0;right:auto;}
317321

318-
.tooltip-bubble{position:absolute;right:-11px;z-index:1000;top:-4px;
322+
.infotip-point{display:inline-block;position:relative;}
323+
.infotip-bubble{position:absolute;left:-11px;z-index:1000;top:-4px;
319324
background-color:#1B2124;color:#FFFFFF;
320325
padding:0.5rem 0.75rem;border-radius:0.25rem;display:block;
321-
font-size:0.8rem;line-height:1.2;display:none;
326+
font-size:0.8rem;line-height:1.2;
322327
text-align:left;z-index:100;}
323-
.tooltip-bubble.tooltip-bubble-right{left:-11px;right:auto;}
324-
.tooltip-bubble span{font-size:0.8rem;max-width:320px;}
325-
.tooltip-bubble span:after{content:'';position:absolute;right:0.5rem;top:-0.5rem;width:6px;height:8px;
328+
.infotip.y.bigY .infotip-bubble{bottom:20px;top:auto;}
329+
.infotip.y.bigX .infotip-bubble{right:-11px;left:auto;}
330+
.infotip.x .infotip-bubble{left:11px;top:-15px;}
331+
.infotip.x.bigX .infotip-bubble{right:11px;left:auto;top:-15px;}
332+
333+
.infotip-bubble:after{content:'';position:absolute;left:6px;top:-4px;width:8px;height:4px;
326334
border-left:4px solid transparent;border-bottom:4px solid #1B2124;border-right:4px solid transparent;}
327-
.tooltip-bubble.tooltip-bubble-right span:after{left:0.5rem;}
328-
.tooltip-text-long{min-width:120px;display:inline-block;}
329-
.tooltip-text-short{white-space: nowrap;}
330-
.tooltip-trigger:hover .tooltip-bubble{display:block;}
331-
.tooltip-trigger:hover .tooltip-source:hover .tooltip-bubble{display:none;}
332-
.tooltip-trigger{position:relative;}
333-
334-
.tooltip-source.tooltip-origin-left .tooltip-bubble {right:11px;top:-15px;}
335-
.tooltip-source.tooltip-origin-left .tooltip-bubble span:after{right:-8px;top:11px;width:6px;height:8px;
336-
border-left:4px solid #1B2124;border-bottom:4px solid transparent;border-top:4px solid transparent;}
335+
.infotip.y.bigY .infotip-bubble:after{bottom:-4px;top:auto;border-top:4px solid #1B2124;border-bottom:0;}
336+
.infotip.y.bigX .infotip-bubble:after{right:6px;left:auto;}
337+
.infotip.x .infotip-bubble:after{left:-4px;top:11px;right:auto;width:4px;height:8px;
338+
border-right:4px solid #1B2124;border-bottom:4px solid transparent;border-top:4px solid transparent;border-left:0;}
339+
.infotip.x.bigX .infotip-bubble:after{right:-4px;left:auto;
340+
border-right:0;border-left:4px solid #1B2124;}
341+
342+
.infotip-text-long{min-width:120px;display:inline-block;}
343+
.infotip-text-short{white-space: nowrap;}
344+
.infotip-trigger{position:relative;}
337345

338346
.w-max-500{max-width:500px;}
339347

src/component/Home/HomeStyles.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import modelStyle from '../../model/style'
88
import Field from '../Field'
99
import Icon from '../Icon'
1010
import StyleAdd from '../StyleAdd'
11-
import Tooltip from '../Tooltip'
11+
import Infotip from '../Infotip'
1212

1313
class HomeStyles extends React.Component {
1414
constructor(props) {
@@ -74,13 +74,13 @@ class HomeStyles extends React.Component {
7474
Styles ({styles? styles.size: 0})
7575
</span>
7676
<div className="content-title-options">
77-
<span onClick={()=>this.handleSearchShowSet({show:true})} className={'content-title-option interactive tooltip-trigger'}>
77+
<span onClick={()=>this.handleSearchShowSet({show:true})} className={'content-title-option interactive infotip-trigger'}>
7878
<Icon icon={'search'}/>
79-
<Tooltip message={'search'}/>
79+
<Infotip direction={'y'} message={'search'}/>
8080
</span>
81-
<Link to={`/styles/add`} className={'content-title-option interactive tooltip-trigger'}>
81+
<Link to={`/styles/add`} className={'content-title-option interactive infotip-trigger'}>
8282
<Icon icon={'add'}/>
83-
<Tooltip message={'add style'}/>
83+
<Infotip direction={'y'} message={'add style'}/>
8484
</Link>
8585
</div>
8686
</h2>

src/component/Home/index.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Alert from '../Alert'
77
import Icon from '../Icon'
88
import HomeStyles from './HomeStyles'
99
import HomeSettings from './HomeSettings'
10-
import Tooltip from '../Tooltip'
10+
import Infotip from '../Infotip'
1111

1212
class Home extends React.Component {
1313

@@ -80,9 +80,9 @@ class Home extends React.Component {
8080
renderOptions(){
8181
return (
8282
<div className="content-title-options">
83-
<NavLink to={'/styles'} className={'content-title-option tooltip-trigger interactive'}>
83+
<NavLink to={'/styles'} className={'content-title-option infotip-trigger interactive'}>
8484
<Icon icon={'style'}/>
85-
<Tooltip message={'styles'}/>
85+
<Infotip direction={'y'} message={'styles'}/>
8686
</NavLink>
8787
</div>
8888
)
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
2+
import React from 'react'
3+
import ReactDOM from 'react-dom'
4+
import PropTypes from 'prop-types'
5+
6+
class InfotipMessage extends React.Component {
7+
8+
constructor (props){
9+
super(props)
10+
11+
this.state = {
12+
built:false
13+
}
14+
15+
this.parentEl = null
16+
}
17+
18+
componentDidMount (){
19+
const {direction, sourceEl} = this.props
20+
if (!this.parentEl) this.parentEl = document.createElement('div')
21+
22+
const boundingRect = sourceEl.getBoundingClientRect()
23+
24+
let bigX = boundingRect.x > window.innerWidth/2? true: false
25+
let bigY = boundingRect.y > window.innerHeight/2? true: false
26+
27+
this.parentEl.style.position = 'absolute'
28+
this.parentEl.style.top = boundingRect.top+'px'
29+
this.parentEl.style.left = boundingRect.left+'px'
30+
this.parentEl.style.width = boundingRect.width+'px'
31+
this.parentEl.style.height = boundingRect.height+'px'
32+
this.parentEl.className = `infotip ${bigX? 'bigX': ''} ${bigY? 'bigY': ''} ${direction}`
33+
34+
document.body.appendChild(this.parentEl)
35+
36+
this.setState({
37+
built:true
38+
})
39+
}
40+
41+
componentWillUnmount (){
42+
console.log('cleanup:',this.parentEl)
43+
document.body.removeChild(this.parentEl)
44+
}
45+
46+
render (){
47+
const {message} = this.props,
48+
{built} = this.state
49+
50+
if (!built) return <div/>
51+
52+
const textClass = message.length > 20? 'infotip-text-long': 'infotip-text-short'
53+
54+
return ReactDOM.createPortal(
55+
<div className="infotip-source">
56+
<div className="infotip-point">
57+
<div className="infotip-bubble">
58+
<span className={textClass}>
59+
{message}
60+
</span>
61+
</div>
62+
</div>
63+
</div>,
64+
this.parentEl
65+
)
66+
}
67+
}
68+
69+
70+
InfotipMessage.propTypes = {
71+
direction: PropTypes.string,
72+
sourceEl: PropTypes.object,
73+
message: PropTypes.string,
74+
}
75+
76+
export default InfotipMessage

src/component/Infotip/index.jsx

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
import React from 'react'
3+
import PropTypes from 'prop-types'
4+
import InfotipMessage from './InfotipMessage'
5+
6+
class Infotip extends React.Component {
7+
8+
constructor (props){
9+
super(props)
10+
11+
this.el = React.createRef()
12+
this.state = {
13+
show:false,
14+
}
15+
}
16+
17+
handleClick = ()=>{
18+
const {handleClick} = this.props
19+
if (handleClick) handleClick()
20+
}
21+
22+
handleMouseEnter = (evt)=>{
23+
let el = evt.currentTarget
24+
if (el != null){
25+
this.setState({
26+
show: true,
27+
})
28+
}
29+
}
30+
31+
handleMouseLeave = (evt)=>{
32+
this.setState({
33+
show: false,
34+
})
35+
}
36+
37+
render (){
38+
const {direction = 'y', message} = this.props,
39+
{show} = this.state
40+
41+
return (
42+
<div
43+
className="infotip"
44+
onClick={this.handleClick}
45+
onMouseEnter={this.handleMouseEnter}
46+
onMouseLeave={this.handleMouseLeave}
47+
ref={this.el}>
48+
{show && this.el.current && (
49+
<InfotipMessage
50+
direction={direction}
51+
message={message}
52+
sourceEl={this.el.current}
53+
/>
54+
)}
55+
</div>
56+
)
57+
}
58+
}
59+
60+
61+
Infotip.propTypes = {
62+
children: PropTypes.node,
63+
handleClick: PropTypes.func,
64+
direction: PropTypes.oneOf([
65+
'x',
66+
'y',
67+
]),
68+
message: PropTypes.string,
69+
}
70+
71+
export default Infotip

src/component/LayerEdit/LayerEditActions.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class LayerEditActions extends React.Component {
4646
</h2>
4747
<div className="content-body">
4848
<div className="content-body-row">
49-
<button onClick={()=>this.handleClone()} className="btn btn-sm btn-outline-dark btn-block" disabled="disabled">
49+
<button disabled="disabled" onClick={()=>this.handleClone()} className="btn btn-sm btn-outline-dark btn-block">
5050
<Icon className="mr-1" icon={'clone'}/>
5151
Clone Layer
5252
</button>

src/component/LayerEdit/index.jsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import LayerEditActions from './LayerEditActions'
99
import LayerEditFeatures from './LayerEditFeatures'
1010
import LayerEditJson from './LayerEditJson'
1111
import LayerEditView from './LayerEditView'
12-
import Tooltip from '../Tooltip'
12+
import Infotip from '../Infotip'
1313
import modelMap from '../../model/map'
1414
import modelPreference from '../../model/preference'
1515
import modelStyle from '../../model/style'
@@ -98,22 +98,22 @@ class LayerEdit extends React.Component {
9898
</span>
9999
<div className="content-title-options">
100100
{focusFeatures.length > 0 && (
101-
<NavLink to={`${match.url}/features`} className={'content-title-option interactive tooltip-trigger'}>
101+
<NavLink to={`${match.url}/features`} className={'content-title-option interactive infotip-trigger'}>
102102
<Icon className="text-info" icon={'map-focus'} weight={'solid'}/>
103-
<Tooltip message={'layer features'}/>
103+
<Infotip direction={'y'} message={'layer features'}/>
104104
</NavLink>
105105
)}
106-
<NavLink to={`${match.url}/editor`} className={'content-title-option interactive tooltip-trigger'}>
106+
<NavLink to={`${match.url}/editor`} className={'content-title-option interactive infotip-trigger'}>
107107
<Icon icon={'editor'}/>
108-
<Tooltip message={'layer editor'}/>
108+
<Infotip direction={'y'} message={'layer editor'}/>
109109
</NavLink>
110-
<NavLink to={`${match.url}/json`} className={'content-title-option interactive tooltip-trigger'}>
110+
<NavLink to={`${match.url}/json`} className={'content-title-option interactive infotip-trigger'}>
111111
<Icon icon={'code'}/>
112-
<Tooltip message={'layer json'}/>
112+
<Infotip direction={'y'} message={'layer json'}/>
113113
</NavLink>
114-
<NavLink to={`${match.url}/actions`} className={'content-title-option interactive tooltip-trigger'}>
114+
<NavLink to={`${match.url}/actions`} className={'content-title-option interactive infotip-trigger'}>
115115
<Icon icon={'action'}/>
116-
<Tooltip message={'layer actions'}/>
116+
<Infotip direction={'y'} message={'layer actions'}/>
117117
</NavLink>
118118
</div>
119119
</h2>

src/component/Map/MapMapbox.jsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,6 @@ class MapMapbox extends React.Component {
201201
if (this.clickMarker) this.clickMarker.remove()
202202
}
203203

204-
205204
if (!this.style || !this.style.equals(style)){
206205
this.style = style
207206

src/component/Map/MapMapboxControls.jsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react'
22
import PropTypes from 'prop-types'
33
import Icon from '../Icon'
4-
import Tooltip from '../Tooltip'
4+
import Infotip from '../Infotip'
55

66
class MapMapboxControls extends React.Component {
77

@@ -32,17 +32,17 @@ class MapMapboxControls extends React.Component {
3232

3333
return (
3434
<React.Fragment>
35-
<div className="mapboxgl-ctrl mapboxgl-ctrl-group tooltip-trigger">
36-
<button className={`mapboxgl-ctrl-icon`} onClick={handleLocationToggle}>
35+
<div onClick={handleLocationToggle} className="mapboxgl-ctrl mapboxgl-ctrl-group infotip-trigger map-control">
36+
<button className={`mapboxgl-ctrl-icon`}>
3737
<Icon icon={'location'}/>
3838
</button>
39-
<Tooltip direction={'left'} message={'jump to location'} origin={'left'}/>
39+
<Infotip direction={'x'} message={'jump to location'}/>
4040
</div>
41-
<div className="mapboxgl-ctrl mapboxgl-ctrl-group tooltip-trigger">
42-
<button className={`mapboxgl-ctrl-icon ${debugLines? 'active': ''}`} onClick={this.handleDebugLinesToggle}>
41+
<div onClick={this.handleDebugLinesToggle} className="mapboxgl-ctrl mapboxgl-ctrl-group infotip-trigger map-control">
42+
<button className={`mapboxgl-ctrl-icon ${debugLines? 'active': ''}`}>
4343
<Icon icon={'debug-lines'}/>
4444
</button>
45-
<Tooltip direction={'left'} message={`debug lines ${debugLines? 'off': 'on'}`} origin={'left'}/>
45+
<Infotip direction={'x'} message={`debug lines ${debugLines? 'off': 'on'}`}/>
4646
</div>
4747
</React.Fragment>
4848
)

src/component/Property/PropertyInfo.jsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
33
import {Map, List} from 'immutable'
44

55
import Icon from '../Icon'
6-
import Tooltip from '../Tooltip'
6+
import Infotip from '../Infotip'
77

88
class PropertyInfo extends React.Component {
99

@@ -25,24 +25,24 @@ class PropertyInfo extends React.Component {
2525
//console.log('error:',error)
2626

2727
if (error !== null && error !== undefined) return (
28-
<span className="helper-icon tooltip-trigger">
28+
<span className="helper-icon infotip-trigger">
2929
<Icon
3030
className="text-danger"
3131
icon={'alert'}
3232
ref={ref => {this.errorIcon = ref}}
3333
weight={'solid'}
3434
/>
35-
<Tooltip direction={'right'} message={this.errorMessage(error)}/>
35+
<Infotip direction={'y'} message={this.errorMessage(error)}/>
3636
</span>
3737
)
3838
if (doc) return (
39-
<span className="helper-icon tooltip-trigger">
39+
<span className="helper-icon infotip-trigger">
4040
<Icon
4141
className="text-muted"
4242
icon={'info'}
4343
ref={ref => {this.icon = ref}}
4444
/>
45-
<Tooltip direction={'right'} message={doc}/>
45+
<Infotip direction={'y'} message={doc}/>
4646
</span>
4747
)
4848
return <span/>

0 commit comments

Comments
 (0)