Showing
2 changed files
with
394 additions
and
1 deletions
... | ... | @@ -18,6 +18,7 @@ import tinycolor from 'tinycolor2'; |
18 | 18 | import TbGoogleMap from './google-map'; |
19 | 19 | import TbOpenStreetMap from './openstreet-map'; |
20 | 20 | import TbImageMap from './image-map'; |
21 | +import TbTencentMap from './tencent-map'; | |
21 | 22 | |
22 | 23 | import {processPattern, arraysEqual, toLabelValueMap, fillPattern, fillPatternWithActions} from './widget-utils'; |
23 | 24 | |
... | ... | @@ -83,6 +84,8 @@ export default class TbMapWidgetV2 { |
83 | 84 | settings.posFunction, |
84 | 85 | settings.imageEntityAlias, |
85 | 86 | settings.imageUrlAttribute); |
87 | + } else if (mapProvider === 'tencent-map') { | |
88 | + this.map = new TbTencentMap($element,this.utils, initCallback, this.defaultZoomLevel, this.dontFitMapBounds, minZoomLevel, settings.tmApiKey, settings.tmDefaultMapType); | |
86 | 89 | } |
87 | 90 | } |
88 | 91 | |
... | ... | @@ -466,6 +469,8 @@ export default class TbMapWidgetV2 { |
466 | 469 | schema = angular.copy(openstreetMapSettingsSchema); |
467 | 470 | } else if (mapProvider === 'image-map') { |
468 | 471 | return imageMapSettingsSchema; |
472 | + } else if (mapProvider === 'tencent-map') { | |
473 | + schema = angular.copy(tencentMapSettingsSchema); | |
469 | 474 | } |
470 | 475 | angular.merge(schema.schema.properties, commonMapSettingsSchema.schema.properties); |
471 | 476 | schema.schema.required = schema.schema.required.concat(commonMapSettingsSchema.schema.required); |
... | ... | @@ -544,7 +549,51 @@ const googleMapSettingsSchema = |
544 | 549 | } |
545 | 550 | ] |
546 | 551 | }; |
547 | - | |
552 | + | |
553 | +const tencentMapSettingsSchema = | |
554 | + { | |
555 | + "schema":{ | |
556 | + "title":"Tencent Map Configuration", | |
557 | + "type":"object", | |
558 | + "properties":{ | |
559 | + "tmApiKey":{ | |
560 | + "title":"Tencent Maps API Key", | |
561 | + "type":"string" | |
562 | + }, | |
563 | + "tmDefaultMapType":{ | |
564 | + "title":"Default map type", | |
565 | + "type":"string", | |
566 | + "default":"roadmap" | |
567 | + } | |
568 | + }, | |
569 | + "required":[ | |
570 | + "tmApiKey" | |
571 | + ] | |
572 | + }, | |
573 | + "form":[ | |
574 | + "tmApiKey", | |
575 | + { | |
576 | + "key":"tmDefaultMapType", | |
577 | + "type":"rc-select", | |
578 | + "multiple":false, | |
579 | + "items":[ | |
580 | + { | |
581 | + "value":"roadmap", | |
582 | + "label":"Roadmap" | |
583 | + }, | |
584 | + { | |
585 | + "value":"satellite", | |
586 | + "label":"Satellite" | |
587 | + }, | |
588 | + { | |
589 | + "value":"hybrid", | |
590 | + "label":"Hybrid" | |
591 | + }, | |
592 | + ] | |
593 | + } | |
594 | + ] | |
595 | + }; | |
596 | + | |
548 | 597 | const openstreetMapSettingsSchema = |
549 | 598 | { |
550 | 599 | "schema":{ | ... | ... |
ui/src/app/widget/lib/tencent-map.js
0 → 100644
1 | +/* | |
2 | + * Copyright © 2016-2017 The Thingsboard Authors | |
3 | + * | |
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | |
5 | + * you may not use this file except in compliance with the License. | |
6 | + * You may obtain a copy of the License at | |
7 | + * | |
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | |
9 | + * | |
10 | + * Unless required by applicable law or agreed to in writing, software | |
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | + * See the License for the specific language governing permissions and | |
14 | + * limitations under the License. | |
15 | + */ | |
16 | + | |
17 | +var tmGlobals = { | |
18 | + loadingTmId: null, | |
19 | + tmApiKeys: {} | |
20 | +} | |
21 | + | |
22 | +export default class TbTencentMap { | |
23 | + constructor($containerElement,utils, initCallback, defaultZoomLevel, dontFitMapBounds, minZoomLevel, tmApiKey, tmDefaultMapType) { | |
24 | + var tbMap = this; | |
25 | + this.utils = utils; | |
26 | + this.defaultZoomLevel = defaultZoomLevel; | |
27 | + this.dontFitMapBounds = dontFitMapBounds; | |
28 | + this.minZoomLevel = minZoomLevel; | |
29 | + this.tooltips = []; | |
30 | + this.defaultMapType = tmDefaultMapType; | |
31 | + | |
32 | + function clearGlobalId() { | |
33 | + if (tmGlobals.loadingTmId && tmGlobals.loadingTmId === tbMap.mapId) { | |
34 | + tmGlobals.loadingTmId = null; | |
35 | + } | |
36 | + } | |
37 | + | |
38 | + function displayError(message) { | |
39 | + $containerElement.html( // eslint-disable-line angular/angularelement | |
40 | + "<div class='error'>"+ message + "</div>" | |
41 | + ); | |
42 | + } | |
43 | + | |
44 | + function initTencentMap() { | |
45 | + tbMap.map = new qq.maps.Map($containerElement[0], { // eslint-disable-line no-undef | |
46 | + scrollwheel: true, | |
47 | + mapTypeId: getTencentMapTypeId(tbMap.defaultMapType), | |
48 | + zoom: tbMap.defaultZoomLevel || 8 | |
49 | + }); | |
50 | + | |
51 | + if (initCallback) { | |
52 | + initCallback(); | |
53 | + } | |
54 | + } | |
55 | + | |
56 | + /* eslint-disable no-undef */ | |
57 | + | |
58 | + function getTencentMapTypeId(mapType) { | |
59 | + var mapTypeId =qq.maps.MapTypeId.ROADMAP; | |
60 | + if (mapType) { | |
61 | + if (mapType === 'hybrid') { | |
62 | + mapTypeId = qq.maps.MapTypeId.HYBRID; | |
63 | + } else if (mapType === 'satellite') { | |
64 | + mapTypeId = qq.maps.MapTypeId.SATELLITE; | |
65 | + } else if (mapType === 'terrain') { | |
66 | + mapTypeId = qq.maps.MapTypeId.ROADMAP; | |
67 | + } | |
68 | + } | |
69 | + return mapTypeId; | |
70 | + } | |
71 | + | |
72 | + /* eslint-enable no-undef */ | |
73 | + | |
74 | + this.mapId = '' + Math.random().toString(36).substr(2, 9); | |
75 | + this.apiKey = tmApiKey || '84d6d83e0e51e481e50454ccbe8986b'; | |
76 | + | |
77 | + window.gm_authFailure = function() { // eslint-disable-line no-undef, angular/window-service | |
78 | + if (tmGlobals.loadingTmId && tmGlobals.loadingTmId === tbMap.mapId) { | |
79 | + tmGlobals.loadingTmId = null; | |
80 | + tmGlobals.tmApiKeys[tbMap.apiKey].error = 'Unable to authentificate for tencent Map API.</br>Please check your API key.'; | |
81 | + displayError(tmGlobals.tmApiKeys[tbMap.apiKey].error); | |
82 | + } | |
83 | + }; | |
84 | + | |
85 | + this.initMapFunctionName = 'initTencentMap_' + this.mapId; | |
86 | + | |
87 | + window[this.initMapFunctionName] = function() { // eslint-disable-line no-undef, angular/window-service | |
88 | + initTencentMap(); | |
89 | + }; | |
90 | + if (this.apiKey && this.apiKey.length > 0) { | |
91 | + if (tmGlobals.tmApiKeys[this.apiKey]) { | |
92 | + if (tmGlobals.tmApiKeys[this.apiKey].error) { | |
93 | + displayError(tmGlobals.tmApiKeys[this.apiKey].error); | |
94 | + } else if (tmGlobals.tmApiKeys[this.apiKey].loaded) { | |
95 | + initTencentMap(); | |
96 | + } else { | |
97 | + tmGlobals.tmApiKeys[this.apiKey].pendingInits.push(initTencentMap); | |
98 | + } | |
99 | + } else { | |
100 | + tmGlobals.tmApiKeys[this.apiKey] = { | |
101 | + loaded: false, | |
102 | + pendingInits: [] | |
103 | + }; | |
104 | + var tencentMapScriptRes = 'http://map.qq.com/api/js?v=2.exp&key='+this.apiKey+'&callback='+this.initMapFunctionName; | |
105 | + | |
106 | + tmGlobals.loadingTmId = this.mapId; | |
107 | + lazyLoad.load({ type: 'js', path: tencentMapScriptRes }).then( // eslint-disable-line no-undef | |
108 | + function success() { | |
109 | + setTimeout(clearGlobalId, 2000); // eslint-disable-line no-undef, angular/timeout-service | |
110 | + }, | |
111 | + function fail(e) { | |
112 | + clearGlobalId(); | |
113 | + tmGlobals.tmApiKeys[tbMap.apiKey].error = 'tencent map api load failed!</br>'+e; | |
114 | + displayError(tmGlobals.tmApiKeys[tbMap.apiKey].error); | |
115 | + } | |
116 | + ); | |
117 | + } | |
118 | + } else { | |
119 | + displayError('No tencent Map Api Key provided!'); | |
120 | + } | |
121 | + } | |
122 | + | |
123 | + inited() { | |
124 | + return angular.isDefined(this.map); | |
125 | + } | |
126 | + | |
127 | + /* eslint-disable no-undef,no-unused-vars*/ | |
128 | + updateMarkerLabel(marker, settings) { | |
129 | + | |
130 | + } | |
131 | + /* eslint-enable no-undef,no-unused-vars */ | |
132 | + | |
133 | + /* eslint-disable no-undef,no-unused-vars */ | |
134 | + updateMarkerColor(marker, color) { | |
135 | + this.createDefaultMarkerIcon(marker, color, (icon) => { | |
136 | + marker.setIcon(icon); | |
137 | + }); | |
138 | + } | |
139 | + /* eslint-enable no-undef,,no-unused-vars */ | |
140 | + | |
141 | + /* eslint-disable no-undef */ | |
142 | + updateMarkerIcon(marker, settings) { | |
143 | + this.createMarkerIcon(marker, settings, (icon) => { | |
144 | + marker.setIcon(icon); | |
145 | + }); | |
146 | + } | |
147 | + /* eslint-disable no-undef */ | |
148 | + | |
149 | + /* eslint-disable no-undef */ | |
150 | + createMarkerIcon(marker, settings, onMarkerIconReady) { | |
151 | + var currentImage = settings.currentImage; | |
152 | + var gMap = this; | |
153 | + if (currentImage && currentImage.url) { | |
154 | + this.utils.loadImageAspect(currentImage.url).then( | |
155 | + (aspect) => { | |
156 | + if (aspect) { | |
157 | + var width; | |
158 | + var height; | |
159 | + if (aspect > 1) { | |
160 | + width = currentImage.size; | |
161 | + height = currentImage.size / aspect; | |
162 | + } else { | |
163 | + width = currentImage.size * aspect; | |
164 | + height = currentImage.size; | |
165 | + } | |
166 | + | |
167 | + var icon = new qq.maps.MarkerImage(currentImage.url, | |
168 | + qq.maps.Size(width, height), | |
169 | + new qq.maps.Point(0,0), | |
170 | + new qq.maps.Point(10, 37)); | |
171 | + | |
172 | + onMarkerIconReady(icon); | |
173 | + } else { | |
174 | + gMap.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); | |
175 | + } | |
176 | + } | |
177 | + ); | |
178 | + } else { | |
179 | + this.createDefaultMarkerIcon(marker, settings.color, onMarkerIconReady); | |
180 | + } | |
181 | + } | |
182 | + /* eslint-enable no-undef */ | |
183 | + | |
184 | + /* eslint-disable no-undef */ | |
185 | + createDefaultMarkerIcon(marker, color, onMarkerIconReady) { | |
186 | + /* var pinColor = color.substr(1);*/ | |
187 | + var icon = new qq.maps.MarkerImage("http://api.map.qq.com/doc/img/nilt.png", | |
188 | + new qq.maps.Size(40, 37), | |
189 | + new qq.maps.Point(0,0), | |
190 | + new qq.maps.Point(10, 37)); | |
191 | + | |
192 | + onMarkerIconReady(icon); | |
193 | + } | |
194 | + /* eslint-enable no-undef */ | |
195 | + | |
196 | + /* eslint-disable no-undef */ | |
197 | + createMarker(location, settings, onClickListener, markerArgs) { | |
198 | + var marker = new qq.maps.Marker({ | |
199 | + map: this.map, | |
200 | + position:location | |
201 | + }); | |
202 | + | |
203 | + var gMap = this; | |
204 | + this.createMarkerIcon(marker, settings, (icon) => { | |
205 | + marker.setIcon(icon); | |
206 | + marker.setMap(gMap.map) | |
207 | + }); | |
208 | + | |
209 | + if (settings.displayTooltip) { | |
210 | + this.createTooltip(marker, settings.tooltipPattern, settings.tooltipReplaceInfo, settings.autocloseTooltip, markerArgs); | |
211 | + } | |
212 | + | |
213 | + if (onClickListener) { | |
214 | + qq.maps.event.addListener(marker, 'click', onClickListener); | |
215 | + } | |
216 | + | |
217 | + return marker; | |
218 | + } | |
219 | + | |
220 | + /* eslint-disable no-undef */ | |
221 | + removeMarker(marker) { | |
222 | + marker.setMap(null); | |
223 | + } | |
224 | + | |
225 | + /* eslint-enable no-undef */ | |
226 | + | |
227 | + /* eslint-disable no-undef */ | |
228 | + createTooltip(marker, pattern, replaceInfo, autoClose, markerArgs) { | |
229 | + var popup = new qq.maps.InfoWindow({ | |
230 | + map :this.map | |
231 | + }); | |
232 | + var map = this; | |
233 | + qq.maps.event.addListener(marker, 'click', function() { | |
234 | + if (autoClose) { | |
235 | + map.tooltips.forEach((tooltip) => { | |
236 | + tooltip.popup.close(); | |
237 | + }); | |
238 | + } | |
239 | + popup.open(); | |
240 | + popup.setPosition(marker); | |
241 | + }); | |
242 | + this.tooltips.push( { | |
243 | + markerArgs: markerArgs, | |
244 | + popup: popup, | |
245 | + pattern: pattern, | |
246 | + replaceInfo: replaceInfo | |
247 | + }); | |
248 | + } | |
249 | + /* eslint-enable no-undef */ | |
250 | + | |
251 | + /* eslint-disable no-undef */ | |
252 | + updatePolylineColor(polyline, settings, color) { | |
253 | + var options = { | |
254 | + path: polyline.getPath(), | |
255 | + strokeColor: color, | |
256 | + strokeOpacity: settings.strokeOpacity, | |
257 | + strokeWeight: settings.strokeWeight, | |
258 | + map: this.map | |
259 | + }; | |
260 | + polyline.setOptions(options); | |
261 | + } | |
262 | + /* eslint-enable no-undef */ | |
263 | + | |
264 | + /* eslint-disable no-undef */ | |
265 | + createPolyline(locations, settings) { | |
266 | + var polyline = new qq.maps.Polyline({ | |
267 | + path: locations, | |
268 | + strokeColor: settings.color, | |
269 | + strokeOpacity: settings.strokeOpacity, | |
270 | + strokeWeight: settings.strokeWeight, | |
271 | + map: this.map | |
272 | + }); | |
273 | + | |
274 | + return polyline; | |
275 | + } | |
276 | + /* eslint-enable no-undef */ | |
277 | + | |
278 | + removePolyline(polyline) { | |
279 | + polyline.setMap(null); | |
280 | + } | |
281 | + | |
282 | + /* eslint-disable no-undef ,no-unused-vars*/ | |
283 | + fitBounds(bounds) { | |
284 | + if (this.dontFitMapBounds && this.defaultZoomLevel) { | |
285 | + this.map.setZoom(this.defaultZoomLevel); | |
286 | + this.map.setCenter(bounds.getCenter()); | |
287 | + } else { | |
288 | + var tbMap = this; | |
289 | + qq.maps.event.addListenerOnce(this.map, 'bounds_changed', function() { // eslint-disable-line no-undef | |
290 | + if (!tbMap.defaultZoomLevel && tbMap.map.getZoom() > tbMap.minZoomLevel) { | |
291 | + tbMap.map.setZoom(tbMap.minZoomLevel); | |
292 | + } | |
293 | + }); | |
294 | + this.map.fitBounds(bounds); | |
295 | + } | |
296 | + } | |
297 | + /* eslint-enable no-undef,no-unused-vars */ | |
298 | + | |
299 | + createLatLng(lat, lng) { | |
300 | + return new qq.maps.LatLng(lat, lng); // eslint-disable-line no-undef | |
301 | + } | |
302 | + | |
303 | + extendBoundsWithMarker(bounds, marker) { | |
304 | + bounds.extend(marker.getPosition()); | |
305 | + } | |
306 | + | |
307 | + getMarkerPosition(marker) { | |
308 | + return marker.getPosition(); | |
309 | + } | |
310 | + | |
311 | + setMarkerPosition(marker, latLng) { | |
312 | + marker.setPosition(latLng); | |
313 | + } | |
314 | + | |
315 | + getPolylineLatLngs(polyline) { | |
316 | + return polyline.getPath().getArray(); | |
317 | + } | |
318 | + | |
319 | + setPolylineLatLngs(polyline, latLngs) { | |
320 | + polyline.setPath(latLngs); | |
321 | + } | |
322 | + | |
323 | + createBounds() { | |
324 | + return new qq.maps.LatLngBounds(); // eslint-disable-line no-undef | |
325 | + } | |
326 | + | |
327 | + extendBounds(bounds, polyline) { | |
328 | + if (polyline && polyline.getPath()) { | |
329 | + var locations = polyline.getPath(); | |
330 | + for (var i = 0; i < locations.getLength(); i++) { | |
331 | + bounds.extend(locations.getAt(i)); | |
332 | + } | |
333 | + } | |
334 | + } | |
335 | + | |
336 | + invalidateSize() { | |
337 | + qq.maps.event.trigger(this.map, "resize"); // eslint-disable-line no-undef | |
338 | + } | |
339 | + | |
340 | + getTooltips() { | |
341 | + return this.tooltips; | |
342 | + } | |
343 | + | |
344 | +} | ... | ... |