UNPKG

3.63 kBTypeScriptView Raw
1import * as React from 'react';
2import { Map } from 'mapbox-gl';
3import { AnchorLimits } from './util/types';
4import { withMap } from './context';
5
6const containerStyle: React.CSSProperties = {
7 position: 'absolute',
8 zIndex: 10,
9 display: 'flex',
10 flexDirection: 'column',
11 boxShadow: '0px 1px 4px rgba(0, 0, 0, .3)',
12 border: '1px solid rgba(0, 0, 0, 0.1)'
13};
14
15const positions = {
16 'top-right': { top: 10, right: 10, bottom: 'auto', left: 'auto' },
17 'top-left': { top: 10, left: 10, bottom: 'auto', right: 'auto' },
18 'bottom-right': { bottom: 10, right: 10, top: 'auto', left: 'auto' },
19 'bottom-left': { bottom: 10, left: 10, top: 'auto', right: 'auto' }
20};
21
22const buttonStyle = {
23 backgroundColor: '#f9f9f9',
24 opacity: 0.95,
25 transition: 'background-color 0.16s ease-out',
26 cursor: 'pointer',
27 border: 0,
28 height: 26,
29 width: 26,
30 backgroundImage: `url('https://api.mapbox.com/mapbox.js/v2.4.0/images/icons-000000@2x.png')`,
31 backgroundPosition: '0px 0px',
32 backgroundSize: '26px 260px',
33 outline: 0
34};
35
36const buttonStyleHovered = {
37 backgroundColor: '#fff',
38 opacity: 1
39};
40
41const buttonStylePlus = {
42 borderBottom: '1px solid rgba(0, 0, 0, 0.1)',
43 borderTopLeftRadius: 2,
44 borderTopRightRadius: 2
45};
46
47const buttonStyleMinus = {
48 backgroundPosition: '0px -26px',
49 borderBottomLeftRadius: 2,
50 borderBottomRightRadius: 2
51};
52
53const [PLUS, MINUS] = [0, 1];
54const POSITIONS = Object.keys(positions);
55
56export interface Props {
57 zoomDiff?: number;
58 onControlClick?: (map: Map, zoomDiff: number) => void;
59 position?: AnchorLimits;
60 style?: React.CSSProperties;
61 className?: string;
62 tabIndex?: number;
63 map: Map;
64}
65
66export interface State {
67 hover?: number;
68}
69
70export class ZoomControl extends React.Component<Props, State> {
71 public static defaultProps = {
72 position: POSITIONS[0],
73 zoomDiff: 0.5,
74 onControlClick: (map: Map, zoomDiff: number) => {
75 map.zoomTo(map.getZoom() + zoomDiff);
76 }
77 };
78
79 public state = {
80 hover: undefined
81 };
82
83 private onMouseOut = () => {
84 this.setState({ hover: undefined });
85 };
86
87 private plusOver = () => {
88 if (PLUS !== this.state.hover) {
89 this.setState({ hover: PLUS });
90 }
91 };
92
93 private minusOver = () => {
94 if (MINUS !== this.state.hover) {
95 this.setState({ hover: MINUS });
96 }
97 };
98
99 private onClickPlus = () => {
100 this.props.onControlClick!(this.props.map, this.props.zoomDiff!);
101 };
102
103 private onClickMinus = () => {
104 this.props.onControlClick!(this.props.map, -this.props.zoomDiff!);
105 };
106
107 public render() {
108 const { position, style, className, tabIndex } = this.props;
109 const { hover } = this.state;
110 const plusStyle = {
111 ...buttonStyle,
112 ...buttonStylePlus,
113 ...(hover === PLUS ? buttonStyleHovered : {})
114 };
115 const minusStyle = {
116 ...buttonStyle,
117 ...buttonStyleMinus,
118 ...(hover === MINUS ? buttonStyleHovered : {})
119 };
120
121 return (
122 <div
123 className={className}
124 tabIndex={tabIndex}
125 style={{ ...containerStyle, ...positions[position!], ...style }}
126 >
127 <button
128 id="zoomIn"
129 type="button"
130 style={plusStyle}
131 aria-label="Zoom in"
132 onMouseOver={this.plusOver}
133 onMouseOut={this.onMouseOut}
134 onClick={this.onClickPlus}
135 />
136 <button
137 id="zoomOut"
138 type="button"
139 style={minusStyle}
140 aria-label="Zoom out"
141 onMouseOver={this.minusOver}
142 onMouseOut={this.onMouseOut}
143 onClick={this.onClickMinus}
144 />
145 </div>
146 );
147 }
148}
149
150export default withMap(ZoomControl);