|
8 | 8 | <style> |
9 | 9 | body { margin: 0; padding: 0; } |
10 | 10 | html, body, #map { height: 100%; } |
11 | | - .map-overlay { |
12 | | - background-color: #fff; |
13 | | - border-radius: 3px; |
14 | | - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); |
15 | | - font: bold 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif; |
16 | | - left: 10px; |
17 | | - padding: 10px; |
18 | | - position: absolute; |
19 | | - top: 10px; |
20 | | - width: 150px; |
21 | | - z-index: 1; |
22 | | - } |
23 | | - |
24 | | - fieldset { |
25 | | - border: none; |
26 | | - padding: 5px 0; |
27 | | - } |
28 | | - |
29 | | - select, input { |
30 | | - background-color: transparent; |
31 | | - border-radius: 3px; |
32 | | - margin: 0; |
33 | | - } |
34 | | - |
35 | | - select { |
36 | | - width: 100%; |
37 | | - } |
| 11 | + </style> |
| 12 | + <style> |
| 13 | + .map-overlay { |
| 14 | + font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif; |
| 15 | + position: absolute; |
| 16 | + width: 200px; |
| 17 | + top: 0; |
| 18 | + left: 0; |
| 19 | + padding: 10px; |
| 20 | + } |
| 21 | + |
| 22 | + .map-overlay .map-overlay-inner { |
| 23 | + background-color: #fff; |
| 24 | + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); |
| 25 | + border-radius: 3px; |
| 26 | + padding: 10px; |
| 27 | + margin-bottom: 10px; |
| 28 | + } |
| 29 | + |
| 30 | + .map-overlay-inner fieldset { |
| 31 | + border: none; |
| 32 | + padding: 0; |
| 33 | + margin: 0 0 10px; |
| 34 | + } |
| 35 | + |
| 36 | + .map-overlay-inner fieldset:last-child { |
| 37 | + margin: 0; |
| 38 | + } |
| 39 | + |
| 40 | + .map-overlay-inner select, |
| 41 | + .map-overlay-inner input { |
| 42 | + width: 100%; |
| 43 | + } |
| 44 | + |
| 45 | + .map-overlay-inner label { |
| 46 | + display: block; |
| 47 | + font-weight: bold; |
| 48 | + margin: 0 0 5px; |
| 49 | + } |
38 | 50 | </style> |
39 | 51 | </head> |
40 | 52 |
|
41 | 53 | <body> |
42 | | - <div class="map-overlay top"> |
| 54 | +<div id='map'></div> |
| 55 | +<div class="map-overlay top"> |
| 56 | + <details open> |
| 57 | + <summary>Toggle controls</summary> |
| 58 | + <div class="map-overlay-inner"> |
| 59 | + <fieldset> |
| 60 | + <label>Select style</label> |
| 61 | + <select id="style" name="style"> |
| 62 | + <option value="streets-v11">Streets</option> |
| 63 | + <option value="satellite-v9">Satellite</option> |
| 64 | + </select> |
| 65 | + </fieldset> |
43 | 66 | <fieldset> |
44 | | - <label>Projection:</label> |
45 | | - <select id="projName"> |
46 | | - <option value="albers" selected>Albers USA</option> |
| 67 | + <label>Select projection</label> |
| 68 | + <select id="projection" name="projection"> |
| 69 | + <option value="albers">Albers</option> |
47 | 70 | <option value="equalEarth">Equal Earth</option> |
48 | 71 | <option value="equirectangular">Equirectangular</option> |
49 | | - <option value="lambertConformalConic">Lambert Conformal Conic</option> |
| 72 | + <option value="lambertConformalConic" selected> |
| 73 | + Lambert Conformal Conic |
| 74 | + </option> |
50 | 75 | <option value="mercator">Mercator</option> |
51 | 76 | <option value="naturalEarth">Natural Earth</option> |
52 | 77 | <option value="winkelTripel">Winkel Tripel</option> |
53 | 78 | </select> |
54 | 79 | </fieldset> |
55 | | - <fieldset> |
56 | | - <label>Style:</label> |
57 | | - <select id="styleName"> |
58 | | - <option value="streets" selected>Streets</option> |
59 | | - <option value="satellite">Satellite</option> |
60 | | - </select> |
| 80 | + <fieldset class="conic-param-input"> |
| 81 | + <label>Center Longitude: <span id="lng-value">0</span></label> |
| 82 | + <input |
| 83 | + id="lng" |
| 84 | + type="range" |
| 85 | + min="-180" |
| 86 | + max="180" |
| 87 | + step="any" |
| 88 | + value="0" |
| 89 | + /> |
61 | 90 | </fieldset> |
62 | | - <fieldset> |
63 | | - <label>Graticule:</label> |
64 | | - <input id="graticule" type="checkbox"> |
| 91 | + <fieldset class="conic-param-input"> |
| 92 | + <label>Center Latitude: <span id="lat-value">30</span></label> |
| 93 | + <input |
| 94 | + id="lat" |
| 95 | + type="range" |
| 96 | + min="-90" |
| 97 | + max="90" |
| 98 | + step="any" |
| 99 | + value="30" |
| 100 | + /> |
| 101 | + </fieldset> |
| 102 | + <fieldset class="conic-param-input"> |
| 103 | + <label |
| 104 | + >Southern Parallel Lat: <span id="lat1-value">30</span></label |
| 105 | + > |
| 106 | + <input |
| 107 | + id="lat1" |
| 108 | + type="range" |
| 109 | + min="-90" |
| 110 | + max="90" |
| 111 | + step="any" |
| 112 | + value="30" |
| 113 | + /> |
| 114 | + </fieldset> |
| 115 | + <fieldset class="conic-param-input"> |
| 116 | + <label |
| 117 | + >Northern Parallel Lat: <span id="lat2-value">30</span></label |
| 118 | + > |
| 119 | + <input |
| 120 | + id="lat2" |
| 121 | + type="range" |
| 122 | + min="-90" |
| 123 | + max="90" |
| 124 | + step="any" |
| 125 | + value="30" |
| 126 | + /> |
65 | 127 | </fieldset> |
66 | 128 | <fieldset> |
67 | 129 | <label>Show Debug Tiles:</label> |
68 | | - <input id="debug" type="checkbox" checked=true> |
| 130 | + <input id="debug" type="checkbox"> |
69 | 131 | </fieldset> |
70 | 132 | </div> |
71 | | - <div id='map'></div> |
| 133 | + </details> |
| 134 | +</div> |
72 | 135 |
|
73 | 136 | <script src='../dist/mapbox-gl-dev.js'></script> |
74 | 137 | <script src='../debug/access_token_generated.js'></script> |
75 | 138 | <script> |
76 | 139 |
|
77 | | -let map; |
78 | | - |
79 | | -const zooms = { |
80 | | - albers: 3, |
81 | | - lambertConformalConic: 3, |
82 | | - winkelTripel: 1.2 |
83 | | -}; |
84 | | -const centers = { |
85 | | - albers: [-122.414, 37.776], |
86 | | - lambertConformalConic: [-122.414, 37.776] |
87 | | -}; |
88 | | - |
89 | | -makeMap(); |
90 | | - |
91 | | -function makeMap() { |
92 | | - if (map) map.remove(); |
93 | | - const el = document.getElementById('projName'); |
94 | | - const projection = el.options[el.selectedIndex].value; |
95 | | - const zoom = zooms[projection] || 1; |
96 | | - const center = centers[projection] || [0, 0]; |
97 | | - const styles = { |
98 | | - streets: 'mapbox://styles/mapbox/streets-v10', |
99 | | - satellite: 'mapbox://styles/mapbox/satellite-streets-v11' |
100 | | - }; |
101 | | - const styleEl = document.getElementById('styleName'); |
102 | | - const styleName = styleEl.options[styleEl.selectedIndex].value; |
103 | | - const style = styles[styleName]; |
104 | | - |
105 | | - map = new mapboxgl.Map({ |
106 | | - projection, |
107 | | - container: 'map', |
108 | | - zoom, |
109 | | - center, |
110 | | - style, |
111 | | - hash: true |
112 | | - }); |
113 | | - map.showTileBoundaries = true; |
114 | | - addGraticule(); |
115 | | -} |
116 | | - |
117 | | -map.on('click', function () { |
118 | | - console.log('projection', map.getProjection()); |
119 | | -}); |
120 | | - |
121 | | -document.getElementById('projName').addEventListener('change', (e) => { |
122 | | - const el = document.getElementById('projName'); |
123 | | - const projection = el.options[el.selectedIndex].value; |
124 | | - const zoom = zooms[projection] || 1; |
125 | | - const center = centers[projection] || [0, 0]; |
126 | | - map.jumpTo({center, zoom}); |
127 | | - map.setProjection(el.options[el.selectedIndex].value); |
| 140 | +const map = new mapboxgl.Map({ |
| 141 | + container: 'map', |
| 142 | + hash: true, |
| 143 | + style: 'mapbox://styles/mapbox/streets-v11', |
| 144 | + zoom: 0, |
| 145 | + center: [0, 1], |
| 146 | + projection: { |
| 147 | + name: 'lambertConformalConic', |
| 148 | + center: [0, 30], |
| 149 | + parallels: [30, 30] |
| 150 | + } |
128 | 151 | }); |
129 | 152 |
|
130 | | -document.getElementById('styleName').addEventListener('change', (e) => { |
131 | | - makeMap(); |
| 153 | +const projectionInput = document.getElementById('projection'); |
| 154 | +const styleInput = document.getElementById('style'); |
| 155 | +const debugInput = document.getElementById('debug'); |
| 156 | +const conicParamInputs = |
| 157 | + document.getElementsByClassName('conic-param-input'); |
| 158 | +const lngInput = document.getElementById('lng'); |
| 159 | +const lngValue = document.getElementById('lng-value'); |
| 160 | +const latInput = document.getElementById('lat'); |
| 161 | +const latValue = document.getElementById('lat-value'); |
| 162 | +const lat1Input = document.getElementById('lat1'); |
| 163 | +const lat1Value = document.getElementById('lat1-value'); |
| 164 | +const lat2Input = document.getElementById('lat2'); |
| 165 | +const lat2Value = document.getElementById('lat2-value'); |
| 166 | + |
| 167 | +projectionInput.addEventListener('change', (e) => { |
| 168 | + const isConic = ['albers', 'lambertConformalConic'].includes( |
| 169 | + e.target.value |
| 170 | + ); |
| 171 | + |
| 172 | + // Hide non-conic projection params |
| 173 | + for (const input of conicParamInputs) { |
| 174 | + input.style.display = isConic ? 'block' : 'none'; |
| 175 | + } |
| 176 | + |
| 177 | + const projection = isConic ? { |
| 178 | + name: e.target.value |
| 179 | + } : e.target.value; |
| 180 | + |
| 181 | + map.setProjection(projection); |
| 182 | + |
| 183 | + if (isConic) { |
| 184 | + const p = map.getProjection(); |
| 185 | + lngInput.value = p.center[0]; |
| 186 | + latInput.value = p.center[1]; |
| 187 | + lat1Input.value = p.parallels[0]; |
| 188 | + lat2Input.value = p.parallels[1]; |
| 189 | + for (const [input, value] of inputs) { |
| 190 | + value.textContent = input.value; |
| 191 | + } |
| 192 | + } |
132 | 193 | }); |
133 | 194 |
|
134 | | -document.getElementById('graticule').addEventListener('change', (e) => { |
135 | | - map.setPaintProperty('graticule', 'line-opacity', e.target.checked ? 1 : 0); |
| 195 | +styleInput.addEventListener('change', () => { |
| 196 | + map.setStyle('mapbox://styles/mapbox/' + styleInput.value); |
136 | 197 | }); |
137 | | - |
138 | | -document.getElementById('debug').addEventListener('change', (e) => { |
139 | | - map.showTileBoundaries = e.target.checked; |
| 198 | +debugInput.addEventListener('change', () => { |
| 199 | + map.showTileBoundaries = debugInput.checked; |
140 | 200 | }); |
141 | 201 |
|
142 | | -function addGraticule() { |
143 | | - map.on('style.load', () => { |
144 | | - const fc = { |
145 | | - type: 'FeatureCollection', |
146 | | - features: [] |
147 | | - }; |
148 | | - |
149 | | - for (let i = -170; i < 180; i += 10) { |
150 | | - fc.features.push({ |
151 | | - type: 'Feature', |
152 | | - geometry: { |
153 | | - type: 'LineString', |
154 | | - coordinates: [[i, -80], [i, 80]] |
155 | | - } |
156 | | - }); |
157 | | - } |
158 | | - for (let i = -80; i < 80; i += 10) { |
159 | | - fc.features.push({ |
160 | | - type: 'Feature', |
161 | | - geometry: { |
162 | | - type: 'LineString', |
163 | | - coordinates: [[-180, i], [180, i]] |
164 | | - } |
165 | | - }); |
166 | | - } |
167 | | - |
168 | | - map.addSource('graticule', { |
169 | | - buffer: 0, |
170 | | - type: 'geojson', |
171 | | - data: fc |
172 | | - }); |
173 | | - |
174 | | - map.addLayer({ |
175 | | - id: 'graticule', |
176 | | - source: 'graticule', |
177 | | - type: 'line', |
178 | | - paint: { |
179 | | - 'line-width': 1, |
180 | | - 'line-color': '#aaa', |
181 | | - 'line-opacity': document.getElementById('graticule').checked ? 1 : 0 |
182 | | - } |
| 202 | +const inputs = [ |
| 203 | + [lngInput, lngValue], |
| 204 | + [latInput, latValue], |
| 205 | + [lat1Input, lat1Value], |
| 206 | + [lat2Input, lat2Value] |
| 207 | +]; |
| 208 | + |
| 209 | +for (const [input, value] of inputs) { |
| 210 | + input.addEventListener('change', (e) => { |
| 211 | + value.textContent = e.target.value; |
| 212 | + map.setProjection({ |
| 213 | + name: projectionInput.value, |
| 214 | + center: [Number(lngInput.value), Number(latInput.value)], |
| 215 | + parallels: [Number(lat1Input.value), Number(lat2Input.value)] |
183 | 216 | }); |
184 | 217 | }); |
185 | 218 | } |
|
0 commit comments