UNPKG

@mint-ui/map

Version:

- React map library - Control various map with one interface - Google, Naver, Kakao map supported now - Typescript supported - Canvas marker supported

789 lines (645 loc) 28.2 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var tslib = require('tslib'); var MintMapController = require('../core/MintMapController.js'); var waiting = require('../core/util/waiting.js'); var tools = require('@mint-ui/tools'); var MapTypes = require('../types/MapTypes.js'); var MapEventTypes = require('../types/MapEventTypes.js'); var log = require('../core/util/log.js'); var status = require('../core/util/status.js'); require('../core/MintMapCore.js'); require('react'); require('../types/MapDrawables.js'); require('../core/provider/MintMapProvider.js'); require('react-dom'); require('../core/util/animation.js'); require('../core/util/geo.js'); var polygon = require('../core/util/polygon.js'); require('../naver/NaverMintMapController.js'); require('../core/advanced/MapLoadingComponents.js'); require('../core/wrapper/MapControlWrapper.js'); var KakaoMintMapController = /** @class */ function (_super) { tslib.__extends(KakaoMintMapController, _super); function KakaoMintMapController(props) { var _a; var _this = _super.call(this, props) || this; _this.type = 'kakao'; _this.map = null; _this.scriptUrl = 'https://dapi.kakao.com/v2/maps/sdk.js'; _this.scriptModules = ['services', 'clusterer']; // , 'geocoder' , 'panorama' , 'visualization'] _this.mapEvent = new MapEventTypes.MapEvent(); _this.mapUIEvent = new MapEventTypes.MapUIEvent(); _this.polylineEvents = ['mouseover', 'mouseout']; _this.polygonEvents = ['mouseover', 'mouseout']; _this.markerEvents = ['click', 'mouseover', 'mouseout']; _this.dragged = false; _this.eventMap = new Map(); //scriptModules 병합 if (props.scriptModules) { (_a = _this.scriptModules).push.apply(_a, props.scriptModules); } //kakao only 이벤트이름 재정의 zoom_start _this.mapEvent.ZOOMSTART = 'zoom_start'; //contextmenu 는 지원하지 않지만 호환성을 위해 rightclick 으로 대체 _this.mapUIEvent.CONTEXTMENU = 'rightclick'; Object.freeze(_this.mapEvent); Object.freeze(_this.mapUIEvent); return _this; // console.log(`${this.type} controller loadded`); } KakaoMintMapController.prototype.initMarkerPool = function () { var _this = this; if (!this.mapProps.markerCache) return; //marker pool setting this.markerPool = new tools.ObjectPool() //logging on //.setLog(true) //factory 셋팅 .setFactory(function () { //console.log('pool item created'); return new kakao.maps.CustomOverlay({ position: _this.positionToLatLng(new MapTypes.Position(0, 0)), map: _this.map || undefined }); }) //clear function 셋팅 .setClear(function (item) { //console.log('pool item cleared'); item.setMap(null); }) //초기 pool 사이즈 .createPool(this.mapProps.markerCachePoolSize && this.mapProps.markerCachePoolSize > 0 ? this.mapProps.markerCachePoolSize : 1000) //TTL 체크 간격 (기본 5초) .setCheckLiveTimeInterval(1000); }; KakaoMintMapController.prototype.createPolyline = function (polyline) { var _this = this; var _a = polyline.options, position = _a.position, _b = _a.lineColor, lineColor = _b === void 0 ? 'blue' : _b, _c = _a.lineSize, lineSize = _c === void 0 ? 1 : _c, _d = _a.lineOpacity, lineOpacity = _d === void 0 ? 1 : _d; _a.visible; _a.editable; var event = _a.event; //console.log('controller createPolyline start', polyline); if (this.map && Array.isArray(position)) { var path = position.map(function (elem) { return _this.positionToLatLng(Array.isArray(elem) ? new MapTypes.Position(elem[1], elem[0]) : elem); }); var pol_1 = new kakao.maps.Polyline({ map: this.map, path: path, strokeColor: lineColor, strokeWeight: lineSize, strokeOpacity: lineOpacity }); // if(editable){ // //@ts-ignore // this.drawingManager.addDrawing(pol, kakao.maps.drawing.DrawingMode.POLYLINE) // } polyline.native = pol_1; event && event.forEach(function (handler, key) { if (_this.polylineEvents.includes(key)) { kakao.maps.event.addListener(pol_1, key, handler); } }); } }; KakaoMintMapController.prototype.updatePolyline = function (polyline, options) { //console.log('controller updatePolyline', options); var _this = this; if (polyline && polyline.native && polyline.native instanceof kakao.maps.Polyline) { //console.log('controller updatePolyline start'); var path = void 0; if (Array.isArray(options.position)) { path = options.position.map(function (elem) { return _this.positionToLatLng(Array.isArray(elem) ? new MapTypes.Position(elem[1], elem[0]) : elem); }); } polyline.native.setOptions({ path: path || polyline.native.getPath(), //visible:options.visible === undefined || options.visible, strokeColor: options.lineColor, strokeWeight: options.lineSize, strokeOpacity: options.lineOpacity }); } }; KakaoMintMapController.prototype.createPolygon = function (polygon) { var _this = this; var _a = polygon.options, position = _a.position, innerPositions = _a.innerPositions, _b = _a.lineColor, lineColor = _b === void 0 ? 'green' : _b, _c = _a.lineSize, lineSize = _c === void 0 ? 1 : _c, _d = _a.lineOpacity, lineOpacity = _d === void 0 ? 1 : _d, _e = _a.fillColor, fillColor = _e === void 0 ? 'lightgreen' : _e, _f = _a.fillOpacity, fillOpacity = _f === void 0 ? 0.5 : _f; _a.visible; _a.editable; var event = _a.event; //console.log('polygon', polygon); if (this.map && Array.isArray(position)) { var outLine = position.map(function (elem) { return _this.positionToLatLng(Array.isArray(elem) ? new MapTypes.Position(elem[1], elem[0]) : elem); }); var path = [outLine]; innerPositions && path.push.apply(path, innerPositions.map(function (inner) { return inner.map(function (innerItem) { return _this.positionToLatLng(innerItem); }); })); var pol_2 = new kakao.maps.Polygon({ map: this.map, path: path, strokeColor: lineColor, strokeWeight: lineSize, strokeOpacity: lineOpacity, fillColor: fillColor, fillOpacity: fillOpacity // clickable:true, // visible:visible, }); //@ts-ignore //pol.setEditable(editable) polygon.native = pol_2; event && event.forEach(function (handler, key) { if (_this.polygonEvents.includes(key)) { kakao.maps.event.addListener(pol_2, key, handler); } }); } }; KakaoMintMapController.prototype.updatePolygon = function (polygon, options) { //console.log('controller updatePolygon', options); var _this = this; if (polygon && polygon.native && polygon.native instanceof kakao.maps.Polygon) { //console.log('controller updatePolygon start'); var paths = void 0; if (Array.isArray(options.position)) { var outLine = options.position.map(function (elem) { return _this.positionToLatLng(Array.isArray(elem) ? new MapTypes.Position(elem[1], elem[0]) : elem); }); paths = [outLine]; options.innerPositions && paths.push.apply(paths, options.innerPositions.map(function (inner) { return inner.map(function (innerItem) { return _this.positionToLatLng(innerItem); }); })); } polygon.native.setOptions({ path: paths || polygon.native.getPath(), // visible:options.visible === undefined || options.visible, strokeColor: options.lineColor, strokeWeight: options.lineSize, strokeOpacity: options.lineOpacity, fillColor: options.fillColor, fillOpacity: options.fillOpacity }); //@ts-ignore // options.editable !== undefined && polygon.native.setEditable(options.editable) } }; KakaoMintMapController.prototype.createMarker = function (marker) { var _this = this; var _a; if (this.map) { var options = { map: this.map, position: this.positionToLatLng(marker.options.position) // visible:marker.options.visible === undefined || marker.options.visible, }; //console.log('controller createMarker', marker.options); marker.element && (options.content = marker.element); var kakaoMarker_1; if (this.mapProps.markerCache && this.markerPool) { kakaoMarker_1 = this.markerPool.getPoolItem(); kakaoMarker_1.setVisible(true); options.content && kakaoMarker_1.setContent(options.content); marker.native = kakaoMarker_1; this.updateMarker(marker, marker.options); } else { kakaoMarker_1 = new kakao.maps.CustomOverlay(options); log.log(this.mapProps.debug || marker.options.debug, marker.options.debugLabel, this.type + ' marker created'); status.Status.setMarker(1, marker.options.debugLabel); marker.options.visible !== undefined && kakaoMarker_1.setVisible(marker.options.visible); this.removeParentElementsMargin(marker); marker.native = kakaoMarker_1; } ((_a = marker.options) === null || _a === void 0 ? void 0 : _a.event) && marker.options.event.forEach(function (handler, key) { if (_this.markerEvents.includes(key)) { kakao.maps.event.addListener(kakaoMarker_1, key, handler); } }); } }; KakaoMintMapController.prototype.updateMarker = function (marker, options) { //console.log('controller updateMarker', options); if (marker && marker.native && marker.native instanceof kakao.maps.CustomOverlay) { var map = marker.native.getMap(); if (map) { //Position if (options.position && options.position instanceof MapTypes.Position) { marker.native.setPosition(this.positionToLatLng(options.position)); } if (options.visible !== undefined) { marker.native.setVisible(options.visible); } log.log(this.mapProps.debug || options.debug, marker.options.debugLabel, this.type + ' marker updated'); this.removeParentElementsMargin(marker); } } }; KakaoMintMapController.prototype.removeParentElementsMargin = function (marker) { //맵 별로 offset 통일을 위해서 margin 제거 marker.element && marker.element instanceof HTMLElement && marker.element.parentElement && (marker.element.parentElement.style.margin = '0'); }; KakaoMintMapController.prototype.getMaxZIndex = function (increment, parent) { if (increment === void 0) { increment = 0; } if (this.map) { var targetPane = parent.parentElement; var max = 0; if (targetPane) { for (var i = 0; i < targetPane.childElementCount; i++) { var elem = targetPane.children[i]; if (elem instanceof HTMLElement) { var index = Number(elem.style.zIndex); if (!isNaN(index) && index > max) { max = index; } } } } this.markerMaxZIndex = max + increment; return this.markerMaxZIndex; } else { return this.markerMaxZIndex || 1; } }; KakaoMintMapController.prototype.setMarkerZIndex = function (marker, zIndex) { if (this.map && marker.element && marker.element instanceof HTMLElement) { var parent_1 = marker.element.parentElement; if (parent_1) { parent_1.style.zIndex = String(zIndex); } } }; KakaoMintMapController.prototype.markerToTheTop = function (marker) { if (this.map && marker.element && marker.element instanceof HTMLElement) { var parent_2 = marker.element.parentElement; if (parent_2) { this.setMarkerZIndex(marker, this.getMaxZIndex(1, parent_2)); } } }; KakaoMintMapController.prototype.clearDrawable = function (drawable) { var _this = this; var _a, _b; if (drawable && drawable.native && (drawable.native instanceof kakao.maps.CustomOverlay || drawable.native instanceof kakao.maps.Polyline || drawable.native instanceof kakao.maps.Polygon)) { if (drawable.native instanceof kakao.maps.CustomOverlay) { if (this.mapProps.markerCache && this.markerPool) { drawable.native.setVisible(false); (_a = this.markerPool) === null || _a === void 0 ? void 0 : _a.releasePoolItem(drawable.native); } else { drawable.native.setMap(null); log.log(this.mapProps.debug || drawable.options.debug, drawable.options.debugLabel, this.type + ' marker cleared'); status.Status.setMarker(-1, drawable.options.debugLabel); } } else { drawable.native.setMap(null); } ((_b = drawable.options) === null || _b === void 0 ? void 0 : _b.event) && drawable.options.event.forEach(function (handler, key) { if (_this.markerEvents.includes(key)) { kakao.maps.event.removeListener(drawable.native, key, handler); } }); return true; } return false; }; KakaoMintMapController.prototype.isMapDragged = function () { return this.dragged; }; KakaoMintMapController.prototype.setMapDragged = function (value) { this.dragged = value; }; KakaoMintMapController.prototype.checkLoaded = function () { var _a, _b; return ((_b = (_a = window.kakao) === null || _a === void 0 ? void 0 : _a.maps) === null || _b === void 0 ? void 0 : _b.Map) ? true : false; }; KakaoMintMapController.prototype.loadMapApi = function () { return tslib.__awaiter(this, void 0, void 0, function () { var _this = this; return tslib.__generator(this, function (_a) { return [2 /*return*/ , new Promise(function (resolve) { return tslib.__awaiter(_this, void 0, void 0, function () { var params, ok; var _this = this; return tslib.__generator(this, function (_a) { switch (_a.label) { case 0: params = tslib.__assign({ appkey: this.mapProps.mapKey, libraries: this.scriptModules.join(','), autoload: false }, this.mapProps.scriptParams); return [4 /*yield*/ , this.loadScript(this.buildUrl(this.scriptUrl, params), 'kakao_map_script', this.checkLoaded)]; case 1: _a.sent(); window.kakao.maps.load(function () {}); return [4 /*yield*/ , waiting.waiting(function () { return _this.checkLoaded() ? true : false; })]; case 2: ok = _a.sent(); if (!ok) { throw new Error('kakao script api load failed!!'); } this.mapApiLoaded = true; resolve(true); return [2 /*return*/ ]; } }); }); })]; }); }); }; KakaoMintMapController.prototype.initializingMap = function (divElement) { return tslib.__awaiter(this, void 0, void 0, function () { var _this = this; return tslib.__generator(this, function (_a) { this.mapDivElement = divElement; return [2 /*return*/ , new Promise(function (resolve) { return tslib.__awaiter(_this, void 0, void 0, function () { var options, maxZoom, minZoom, map; var _this = this; var _a, _b, _c, _d, _e, _f; return tslib.__generator(this, function (_g) { switch (_g.label) { case 0: if (!!this.mapApiLoaded) return [3 /*break*/ , 2]; return [4 /*yield*/ , this.loadMapApi()]; case 1: _g.sent(); _g.label = 2; case 2: options = { center: this.positionToLatLng((_a = this.mapProps.base) === null || _a === void 0 ? void 0 : _a.center), level: this.getBaseToMapZoom(((_b = this.mapProps.base) === null || _b === void 0 ? void 0 : _b.zoomLevel) || 15), draggable: this.mapProps.draggable === false ? false : true, scrollWheel: this.mapProps.draggable === false ? false : true, keyboardShortcuts: this.mapProps.keyboardShortcuts === false ? false : true }; maxZoom = 1; minZoom = 14; if ((_c = this.mapProps.base) === null || _c === void 0 ? void 0 : _c.maxZoomLevel) { maxZoom = this.getSafeZoomValue(this.mapProps.base.maxZoomLevel); } if ((_d = this.mapProps.base) === null || _d === void 0 ? void 0 : _d.minZoomLevel) { minZoom = this.getSafeZoomValue(this.mapProps.base.minZoomLevel); } if (minZoom < maxZoom) { minZoom = 14; } divElement.innerHTML = ''; map = new kakao.maps.Map(divElement, options); map.setMaxLevel(minZoom); map.setMinLevel(maxZoom); this.map = map; //맵 커서 초기화 ((_e = this.mapProps.base) === null || _e === void 0 ? void 0 : _e.mapCursor) && this.setMapCursor((_f = this.mapProps.base) === null || _f === void 0 ? void 0 : _f.mapCursor); //@ts-ignore // map.addListener('dragstart', (e)=>{ // //console.log('map dragstart', e); // this.dragStartPoint[0] = e.domEvent.clientX // this.dragStartPoint[1] = e.domEvent.clientY // }) //@ts-ignore // map.addListener('dragend', (e)=>{ // //console.log('map dragend', e); // if(this.dragStartPoint[0] === e.domEvent.clientX && this.dragStartPoint[1] === e.domEvent.clientY){ // this.dragged = false // }else{ // this.dragged = true // } // //console.log('map dragend', this.dragged) // }) //@ts-ignore map.addListener('mousedown', function () { _this.dragged = false; // console.log('map mousedown / dragged => ', this.dragged); }); //@ts-ignore map.addListener('dragstart', function () { _this.dragged = true; // console.log('map dragstart / dragged => ', this.dragged); }); //@ts-ignore map.addListener('idle', function (e) { //onBoundsChanged event _this.map && _this.checkBoundsChangeThrottleTime() && _this.mapProps.onBoundsChanged && _this.mapProps.onBoundsChanged(_this.getCurrBounds()); }); //@ts-ignore map.addListener('zoom_changed', function () { //onZoomChanged event //console.log('zoom_changed'); _this.map && _this.mapProps.onZoomChanged && _this.mapProps.onZoomChanged(_this.getZoomLevel()); }); //@ts-ignore map.addListener('click', function (e) { // console.log('map click', e); if (!_this.mapProps.onClick) return; var pos = new MapTypes.Position(e.latLng.getLat(), e.latLng.getLng()); pos.offset = new MapTypes.Offset(e.point.x, e.point.y); _this.mapProps.onClick(pos); }); //@ts-ignore map.addListener('mousemove', function (e) { if (!_this.mapProps.onMouseMove) return; var pos = new MapTypes.Position(e.latLng.getLat(), e.latLng.getLng()); pos.offset = new MapTypes.Offset(e.point.x, e.point.y); // console.log('mousemove', pos) _this.mapProps.onMouseMove(pos); }); this.mapInitialized = true; this.initMarkerPool(); // console.log(`${this.type} map script initialized`, divElement); resolve(map); return [2 /*return*/ ]; } }); }); })]; }); }); }; KakaoMintMapController.prototype.getSafeZoomValue = function (value) { /** * 카카오는 구글/네이버와 다르게 줌레벨이 작아질수록 확대된다 (가장 확대된 것이 0) * - 가장 확대된 값 : 1 * - 가장 축소된 값 : 14 * * 그래서 세계지도가 없는 카카오는 동일한 사정인 네이버와 매핑하기로 한다. * 문제는 둘 간의 줌 레벨별 축척이 일치하지 않는다. 그래서 가장 유사한 레벨 끼리 매핑이 필요하다 */ var mapValue = this.getBaseToMapZoom(value); if (mapValue > 14) { return 14; } else if (mapValue < 1) { return 1; } return mapValue; }; KakaoMintMapController.prototype.destroyMap = function () { var _a; try { this.removeAllEventListener(); (_a = this.markerPool) === null || _a === void 0 ? void 0 : _a.destroy(); } catch (e) { console.log('kakao map destroy error', e); } // console.log(`${this.type} map destroyed`); }; KakaoMintMapController.prototype.getCurrBounds = function () { if (!this.map) { throw new Error('Map is not initialized!!'); } var bounds = this.map.getBounds(); return MapTypes.Bounds.fromNESW(this.latLngToPosition(bounds.getNorthEast()), this.latLngToPosition(bounds.getSouthWest())); }; KakaoMintMapController.prototype.panningTo = function (targetCenter) { var _a; (_a = this.map) === null || _a === void 0 ? void 0 : _a.panTo(this.positionToLatLng(targetCenter)); }; KakaoMintMapController.prototype.getZoomLevel = function () { return this.map ? this.getMapToBaseZoom(this.map.getLevel()) : 13; }; KakaoMintMapController.prototype.setZoomLevel = function (zoom) { var _a; (_a = this.map) === null || _a === void 0 ? void 0 : _a.setLevel(this.getBaseToMapZoom(zoom)); }; KakaoMintMapController.prototype.getCenter = function () { return this.getCurrBounds().getCenter(); }; KakaoMintMapController.prototype.setCenter = function (position) { var _a; (_a = this.map) === null || _a === void 0 ? void 0 : _a.setCenter(this.positionToLatLng(position)); }; KakaoMintMapController.prototype.setMapCursor = function (cursor) { var _a; var target = (_a = this.mapDivElement.firstElementChild) === null || _a === void 0 ? void 0 : _a.firstElementChild; target && (target.style.cursor = cursor); }; KakaoMintMapController.prototype.positionToLatLng = function (pos) { return pos ? new kakao.maps.LatLng(pos.lat, pos.lng) : new kakao.maps.LatLng(0, 0); }; KakaoMintMapController.prototype.latLngToPosition = function (latLng) { return latLng ? new MapTypes.Position(latLng.getLat(), latLng.getLng()) : new MapTypes.Position(0, 0); }; KakaoMintMapController.prototype.focusPositionsToFitViewport = function (positions, spacing) { var _a; var markerBounds = polygon.PolygonCalculator.getRegionInfo(positions); if (!markerBounds.maxLat || !markerBounds.minLat || !markerBounds.maxLng || !markerBounds.minLng) { throw new Error('markerBounds is invalid! in focusPositionsToFitViewport'); } var pointBounds = new kakao.maps.LatLngBounds(new kakao.maps.LatLng(markerBounds.minLat, markerBounds.minLng), new kakao.maps.LatLng(markerBounds.maxLat, markerBounds.maxLng)); var topSpacing, rightSpacing, bottomSpacing, leftSpacing; if (typeof spacing === 'number') { topSpacing = rightSpacing = bottomSpacing = leftSpacing = spacing; } else if (spacing instanceof MapTypes.Spacing) { topSpacing = spacing.top, rightSpacing = spacing.right, bottomSpacing = spacing.bottom, leftSpacing = spacing.left; } // 카카오 지도는 setBounds 함수를 실행 할 때 애니메이션 효과가 없다. (_a = this.map) === null || _a === void 0 ? void 0 : _a.setBounds(pointBounds, topSpacing, rightSpacing, bottomSpacing, leftSpacing); }; KakaoMintMapController.prototype.addEventListener = function (eventName, callback) { var _this = this; var kakaoEventName = this.mapEvent.get(eventName) || this.mapUIEvent.get(eventName); if (!kakaoEventName) { console.warn("MapEventName ".concat(eventName, " is not supported")); return; } // console.log(`${eventName} add`); var map = this.eventMap.get(eventName); if (!map) { map = new Map(); this.eventMap.set(eventName, map); } var wrappingCallback = function (e) { if (eventName in _this.mapEvent) { var bounds = _this.getCurrBounds(); var param = { name: eventName, mapType: 'kakao', vendorEventName: kakaoEventName, param: { bounds: bounds, center: bounds.getCenter(), zoomLevel: _this.getZoomLevel() } }; callback(param); } else if (eventName in _this.mapUIEvent) { var position = new MapTypes.Position(e.latLng.getLat(), e.latLng.getLng()); position.offset = new MapTypes.Offset(e.point.x, e.point.y); var param = { name: eventName, mapType: 'kakao', vendorEventName: kakaoEventName, param: { position: position, offset: position.offset } }; callback(param); } }; kakao.maps.event.addListener(this.map, kakaoEventName, wrappingCallback); map.set(callback, wrappingCallback); }; KakaoMintMapController.prototype.removeEventListener = function (eventName, callback) { var kakaoEventName = this.mapEvent.get(eventName) || this.mapUIEvent.get(eventName); if (!kakaoEventName) { console.warn("MapEventName ".concat(eventName, " is not supported")); return; } var map = this.eventMap.get(eventName); if (map) { var wrappingCallback = map.get(callback); if (wrappingCallback) { // console.log(`${naverEventListener.eventName} remove`); kakao.maps.event.removeListener(this.map, kakaoEventName, wrappingCallback); map.delete(callback); } } }; KakaoMintMapController.prototype.removeAllEventListener = function (eventName) { var _this = this; if (eventName) { this.clearEventListener(eventName); } else { this.eventMap.forEach(function (_map, eventName) { _this.clearEventListener(eventName); }); this.eventMap.clear(); } }; KakaoMintMapController.prototype.clearEventListener = function (eventName) { var _this = this; var kakaoEventName = this.mapEvent.get(eventName) || this.mapUIEvent.get(eventName); if (!kakaoEventName) { console.warn("MapEventName ".concat(eventName, " is not supported")); return; } var map = this.eventMap.get(eventName); if (map) { map.forEach(function (wrappingCallback) { // console.log(`${naverEventListener.eventName} remove`); kakao.maps.event.removeListener(_this.map, kakaoEventName, wrappingCallback); }); this.eventMap.delete(eventName); } }; return KakaoMintMapController; }(MintMapController.MintMapController); exports.KakaoMintMapController = KakaoMintMapController;