|
@@ -0,0 +1,1878 @@
|
|
|
+let _size = [48, 48, 48, 48, 40, 32, 24, 22, 20, 18, 18];
|
|
|
+let _AtrdData = [];
|
|
|
+let _AtrdMap = new Map();
|
|
|
+let selectIncidentId = null;
|
|
|
+
|
|
|
+//시설물 유형
|
|
|
+const _FacilityArray = ['cctv', 'vms', 'intersection', 'incident', 'traffic', 'parking', 'intersectionCamera'];
|
|
|
+
|
|
|
+const g_color = new Map();
|
|
|
+g_color.set('LTC0', '#888888;');
|
|
|
+g_color.set('LTC1', '#2fba2c;');
|
|
|
+g_color.set('LTC2', '#ffc500;');
|
|
|
+g_color.set('LTC3', '#ee0000;');
|
|
|
+
|
|
|
+const CCTV_DISPLAY_TIME = 30 * 1000; // 영상 표출 시간
|
|
|
+const VMS_DISPLAY_TIME = 4 * 1000; // VMS 이미지 표출 시간
|
|
|
+
|
|
|
+let _MapHandler; //카카오 맵 핸들러
|
|
|
+let _Level = 6; //현재 줌레벨
|
|
|
+
|
|
|
+let _methodMap = new Map();
|
|
|
+_methodMap.set('cctv', getCctv);
|
|
|
+_methodMap.set('vms', getVms);
|
|
|
+_methodMap.set('incident', getIncident);
|
|
|
+_methodMap.set('intersection', getIntersection);
|
|
|
+_methodMap.set('traffic', getAtrd);
|
|
|
+_methodMap.set('parking', getParking);
|
|
|
+
|
|
|
+$(()=>{
|
|
|
+ // Map 요소 ID로 생성
|
|
|
+ _MapHandler = new MapHandler('map');
|
|
|
+ _MapHandler.init();
|
|
|
+
|
|
|
+ // 시설물 유형 정보로 flag 값 세팅
|
|
|
+ if (_type) {
|
|
|
+ _MapHandler[_type + 'Flag'] = true;
|
|
|
+ _MapHandler[_type + 'ListFlag'] = true;
|
|
|
+ _methodMap.get(_type)();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 범례 클릭 이벤트 및 색 변환
|
|
|
+ * */
|
|
|
+ $('.legend-bottom button').on('click', function (){
|
|
|
+ const target = $(this);
|
|
|
+ const legendIcon = target.children().eq(0);
|
|
|
+ const isShow = !legendIcon.hasClass('active');
|
|
|
+
|
|
|
+ const id = target.attr('id');
|
|
|
+ const type = id.replace('-legend', '');
|
|
|
+
|
|
|
+ let subType = null;
|
|
|
+
|
|
|
+ if (type === 'intersection') {
|
|
|
+ subType = type + 'Camera';
|
|
|
+ }
|
|
|
+
|
|
|
+ if (type === 'traffic') {
|
|
|
+ subType = 'atrd';
|
|
|
+ getVertex();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (_MapHandler[type] && _MapHandler[type].length <= 0) {
|
|
|
+ _methodMap.get(type)();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let toggle = 'hide';
|
|
|
+ let classToggle = 'removeClass';
|
|
|
+ if (isShow === true) {
|
|
|
+ toggle = 'show';
|
|
|
+ classToggle = 'addClass';
|
|
|
+ }
|
|
|
+
|
|
|
+ legendIcon[classToggle]('active');
|
|
|
+ target[classToggle]('active');
|
|
|
+
|
|
|
+ _MapHandler[toggle](type);
|
|
|
+ if (subType) {
|
|
|
+ _MapHandler[toggle](subType);
|
|
|
+ }
|
|
|
+
|
|
|
+ })
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 범례 호버 색 변환
|
|
|
+ * */
|
|
|
+ $('.legend-bottom ul li').hover((event)=>{
|
|
|
+ const iconDiv = $(event.currentTarget).children().eq(0);
|
|
|
+ const childDiv = iconDiv.children().eq(0);
|
|
|
+ if (!iconDiv.hasClass('active')) {
|
|
|
+ childDiv.addClass('hover');
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (childDiv.hasClass('hover')) {
|
|
|
+ childDiv.removeClass('hover');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ (event)=>{
|
|
|
+ const iconDiv = $(event.currentTarget).children().eq(0);
|
|
|
+ const childDiv = iconDiv.children().eq(0);
|
|
|
+
|
|
|
+ if (!iconDiv.hasClass('active')) {
|
|
|
+ childDiv.removeClass('hover');
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (childDiv.hasClass('hover')) {
|
|
|
+ childDiv.removeClass('hover');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 탭 호버 색 변환
|
|
|
+ * */
|
|
|
+ $('.left-list-area .list-tab > li').hover((event)=>{
|
|
|
+ const iconDiv = $(event.currentTarget);
|
|
|
+ const childDiv = iconDiv.children().eq(0);
|
|
|
+ if (!iconDiv.hasClass('active')) {
|
|
|
+ childDiv.addClass('hover');
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (childDiv.hasClass('hover')) {
|
|
|
+ childDiv.removeClass('hover');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ (event)=>{
|
|
|
+ const iconDiv = $(event.currentTarget);
|
|
|
+ const childDiv = iconDiv.children().eq(0);
|
|
|
+ if (!iconDiv.hasClass('active')) {
|
|
|
+ childDiv.removeClass('hover');
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (childDiv.hasClass('hover')) {
|
|
|
+ childDiv.removeClass('hover');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+
|
|
|
+ let _MarkerArr = [];
|
|
|
+ $('.tab-title > div').on('click', function(){
|
|
|
+ const $spot = $('.list-content.spot');
|
|
|
+ const $list = $('.list-content.list');
|
|
|
+ let searchType = $('.tab-title > div.active').text();
|
|
|
+ if (searchType === $(this).text()) return;
|
|
|
+ $('.tab-title > div').toggleClass("active");
|
|
|
+ searchType = $(this).text();
|
|
|
+ let list;
|
|
|
+ let spot;
|
|
|
+ if (searchType === '지점 검색') {
|
|
|
+ list = 'none';
|
|
|
+ spot = 'block';
|
|
|
+ $spot.html("");
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ list = 'block';
|
|
|
+ spot = 'none';
|
|
|
+ $('.list-content.list > li').css('display', 'block');
|
|
|
+ }
|
|
|
+
|
|
|
+ $('#search-box').val("");
|
|
|
+ $list.css('display', list);
|
|
|
+ $spot.css('display', spot);
|
|
|
+ if (_MarkerArr.length > 0) {
|
|
|
+ _MarkerArr.forEach((obj)=>{
|
|
|
+ obj.setMap(null);
|
|
|
+ });
|
|
|
+ _MarkerArr = [];
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+
|
|
|
+ $('#search-box').on('keyup', function () {
|
|
|
+ const searchType = $('.tab-title > div.active').text();
|
|
|
+ const searchText = $(this).val();
|
|
|
+
|
|
|
+ if (searchType === '리스트') {
|
|
|
+ const $list = $('.list-content.list > li');
|
|
|
+ if (!$list.length) return;
|
|
|
+
|
|
|
+ for (let ii = 0; ii < $list.length; ii++) {
|
|
|
+ const li = $list.eq(ii);
|
|
|
+ if ($(this).val().length === 0) {
|
|
|
+ li.css('display', 'block');
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ let text = $('.list-content.list > li').eq(ii).text().toLowerCase();
|
|
|
+ if (text.includes(searchText.toLowerCase())) {
|
|
|
+ li.css('display', 'block');
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ li.css('display', 'none');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (_MarkerArr.length > 0) {
|
|
|
+ _MarkerArr.forEach((obj)=>{
|
|
|
+ obj.setMap(null);
|
|
|
+ });
|
|
|
+ _MarkerArr = [];
|
|
|
+ }
|
|
|
+ $('.list-content.spot').html("");
|
|
|
+ if (!searchText || !searchText.trim()) return;
|
|
|
+ $.ajax({
|
|
|
+ url: 'https://dapi.kakao.com/v2/local/search/address.json',
|
|
|
+ headers: { 'Authorization': 'KakaoAK 4896b94398b96949d349881d004835cf'},
|
|
|
+ data :{
|
|
|
+ query : searchText,
|
|
|
+ },
|
|
|
+ type: 'GET'
|
|
|
+ }).done(function(data) {
|
|
|
+ if (data && data.documents.length > 0) {
|
|
|
+ let str = "";
|
|
|
+ const setMap = new Map();
|
|
|
+
|
|
|
+ const bounds = new kakao.maps.LatLngBounds();
|
|
|
+ let minX;
|
|
|
+ let minY;
|
|
|
+ let maxX;
|
|
|
+ let maxY;
|
|
|
+ let idx = 0;
|
|
|
+ data.documents.forEach((obj)=>{
|
|
|
+ if (!setMap.get(obj.address_name) && obj.address_name.includes("경북 포항시")) {
|
|
|
+ idx++;
|
|
|
+ let addr = obj.address_name;
|
|
|
+ if (obj.x && obj.y) {
|
|
|
+ const position = getKakaoPosition(obj.y, obj.x);
|
|
|
+ let marker = new kakao.maps.Marker({
|
|
|
+ position : position,
|
|
|
+ title : addr ,
|
|
|
+ content : addr
|
|
|
+ });
|
|
|
+
|
|
|
+ new kakao.maps.event.addListener(marker, 'click', function() {
|
|
|
+ moveLocation(obj.x, obj.y, idx);
|
|
|
+ })
|
|
|
+ if (!minX) {
|
|
|
+ minX = obj.x;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!maxX) {
|
|
|
+ maxX = obj.x;
|
|
|
+ }
|
|
|
+ if (!minY) {
|
|
|
+ minY = obj.y;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!maxY) {
|
|
|
+ maxY = obj.y;
|
|
|
+ }
|
|
|
+
|
|
|
+ minX = minX <= obj.x ? minX : obj.x;
|
|
|
+ maxX = maxX >= obj.x ? maxX : obj.x;
|
|
|
+ minY = minY <= obj.y ? minY : obj.y;
|
|
|
+ maxY = maxY >= obj.y ? maxY : obj.y;
|
|
|
+
|
|
|
+ marker.setMap(_MapHandler.map);
|
|
|
+ _MarkerArr.push(marker);
|
|
|
+ setMap.set(addr, obj);
|
|
|
+
|
|
|
+ str+= `<li id="spot-${idx}" onclick="moveLocation(${obj.x}, ${obj.y}, ${idx})">
|
|
|
+ ${obj.address_name}
|
|
|
+ </li>`;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ if (minX && minY && maxX && maxY) {
|
|
|
+ bounds.extend(new kakao.maps.LatLng(minY, minX));
|
|
|
+ bounds.extend(new kakao.maps.LatLng(maxY, maxX));
|
|
|
+ _MapHandler.map.setBounds(bounds);
|
|
|
+ $('.list-content.spot').html(str);
|
|
|
+ getVertex();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ })
|
|
|
+});
|
|
|
+
|
|
|
+/**
|
|
|
+ * 간선도로 마커 레벨별 이미지 보이기 감추기
|
|
|
+ */
|
|
|
+function atrdMarkerResize() {
|
|
|
+ let level = _Level;
|
|
|
+
|
|
|
+ let atrdArr = _MapHandler['atrd'];
|
|
|
+ atrdArr.forEach((atrd)=>{
|
|
|
+ setMarkerImage(atrd, atrd.obj.drct_cd, true);
|
|
|
+ });
|
|
|
+
|
|
|
+ if (level === 3) {
|
|
|
+ level = 4;
|
|
|
+ }
|
|
|
+ if (level >= 8) {
|
|
|
+ level = 7;
|
|
|
+ }
|
|
|
+ else if (level >= 6) {
|
|
|
+ level = 6;
|
|
|
+ }
|
|
|
+
|
|
|
+ const atrdInfo = _AtrdMap.get(level.toString());
|
|
|
+ if (atrdInfo) {
|
|
|
+ _AtrdData = [];
|
|
|
+ let upHillArr = [];
|
|
|
+ let downHillArr = [];
|
|
|
+ const $selectedLi = $(".left-list-area .list-content.list > li.click");
|
|
|
+ let id;
|
|
|
+ let idArr;
|
|
|
+ if ($selectedLi[0]) {
|
|
|
+ id = $selectedLi.attr('id');
|
|
|
+ }
|
|
|
+ if (id) {
|
|
|
+ idArr = id.split("_");
|
|
|
+ }
|
|
|
+ atrdInfo.forEach((atrd)=>{
|
|
|
+ if (atrd.atrd_id.toString() === idArr[1] || atrd.atrd_id.toString() === idArr[2]) {
|
|
|
+ _AtrdData.push(atrd);
|
|
|
+
|
|
|
+ if (atrd.atrd_id.toString() === idArr[1]) {
|
|
|
+ upHillArr.push(atrd);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ downHillArr.push(atrd);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ if (upHillArr[0]) {
|
|
|
+ let upHillX = upHillArr[0].x_crdn_arr.split(',')[0];
|
|
|
+ let upHillY = upHillArr[0].y_crdn_arr.split(',')[0];
|
|
|
+ atrdArr[0].marker.setPosition(getKakaoPosition(upHillY, upHillX));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (downHillArr[0]) {
|
|
|
+ let downHillX = downHillArr[0].x_crdn_arr.split(',')[0];
|
|
|
+ let downHillY = downHillArr[0].y_crdn_arr.split(',')[0];
|
|
|
+ atrdArr[1].marker.setPosition(getKakaoPosition(downHillY, downHillX));
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 스마트교차로 카메라 레벨별 이미지 보이기 감추기
|
|
|
+ */
|
|
|
+function intersectionCameraChangeWidthZoomLevel() {
|
|
|
+ const level = _Level;
|
|
|
+ const size = [48, 48, 48]
|
|
|
+ const levelSize = size[level];
|
|
|
+ const type = 'intersectionCamera';
|
|
|
+ const markerArr = _MapHandler[type];
|
|
|
+ const map = _MapHandler.map;
|
|
|
+ if (markerArr.length > 0) {
|
|
|
+ markerArr.forEach((obj) => {
|
|
|
+ const content = $('<div title='+obj.NAME+'>');
|
|
|
+ content.css(
|
|
|
+ {
|
|
|
+ width: levelSize+ 'px',
|
|
|
+ height: levelSize+ 'px',
|
|
|
+ backgroundImage:'url(/images/icon/intersection-cctv.png)',
|
|
|
+ backgroundSize : levelSize+'px '+levelSize+'px',
|
|
|
+ backgroundRepeat: 'no-repeat',
|
|
|
+ backgroundPosition : 'center',
|
|
|
+ transform : 'rotate(' + obj.obj.cmra_angn +'deg)',
|
|
|
+ cursor : 'pointer'
|
|
|
+ });
|
|
|
+
|
|
|
+ obj.marker.setContent(content[0]);
|
|
|
+ content.on('click', ()=> {
|
|
|
+ _MapHandler.click(type, obj.ID);
|
|
|
+ });
|
|
|
+
|
|
|
+ if (level <= 2 && _MapHandler['intersectionFlag']) {
|
|
|
+ obj.marker.setMap(map);
|
|
|
+ obj.polyline.setMap(map);
|
|
|
+ } else {
|
|
|
+ obj.marker.setMap(null);
|
|
|
+ obj.polyline.setMap(null);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 스마트교차로 레벨별 이미지 보이기 감추기
|
|
|
+ */
|
|
|
+function intersectionMarkerChangeWithZoomLevel() {
|
|
|
+ const level = _Level;
|
|
|
+ if (_MapHandler['intersection'].length > 0) {
|
|
|
+ _MapHandler['intersection'].forEach((obj)=>{
|
|
|
+ setMarkerImage(obj, "", false);
|
|
|
+ if (level > 2 && _MapHandler['intersectionFlag']) {
|
|
|
+ obj.marker.setVisible(true);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ obj.marker.setVisible(false);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 맵 레벨별 이미지 변환
|
|
|
+ * @param array
|
|
|
+ */
|
|
|
+function markerSizeChangeWithZoomLevel(array) {
|
|
|
+ if (array && array.length > 0) {
|
|
|
+ array.forEach((obj)=>{
|
|
|
+ if (obj.isClick) {
|
|
|
+ setMarkerImage(obj, 2, false)
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ setMarkerImage(obj, 1, false);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 지점 클릭 위치 이동
|
|
|
+ * @param xCoordinate x좌표
|
|
|
+ * @param yCoordinate y좌표
|
|
|
+ * @param listIndex 지점 선택 인덱스
|
|
|
+ */
|
|
|
+function moveLocation(xCoordinate, yCoordinate, listIndex) {
|
|
|
+ const position = getKakaoPosition(yCoordinate, xCoordinate);
|
|
|
+
|
|
|
+ _MapHandler.map.setCenter(position);
|
|
|
+ _MapHandler.map.setLevel(3);
|
|
|
+ $('.list-content.spot > li.click').removeClass('click');
|
|
|
+ $('#spot-' +listIndex).addClass('click');
|
|
|
+ getVertex();
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * cctv 데이터 가져오기
|
|
|
+ */
|
|
|
+function getCctv() {
|
|
|
+ getDataAsync('/api/traffic/cctv-list', 'POST', null, null, (jsonData)=>{
|
|
|
+ if (jsonData && jsonData.length > 0) {
|
|
|
+ receiveFacilityData(jsonData, TbCCtvObj,'cctv');
|
|
|
+ }
|
|
|
+ }, null);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * vms 데이터 가져오기
|
|
|
+ */
|
|
|
+function getVms() {
|
|
|
+ getDataAsync('/api/traffic/vms-list', 'POST', null, null, (jsonData)=>{
|
|
|
+ if (jsonData && jsonData.length > 0) {
|
|
|
+ jsonData.sort((a, b)=>{
|
|
|
+ return a.vms_nm > b.vms_nm ? 1 : a.vms_nm < b.vms_nm ? -1 : 0;
|
|
|
+ })
|
|
|
+ receiveFacilityData(jsonData, TbVmsObj,'vms');
|
|
|
+ }
|
|
|
+ }, null);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 돌발정보
|
|
|
+ */
|
|
|
+function getIncident () {
|
|
|
+ getDataAsync('/api/traffic/incident-list', 'POST', null, null, (jsonData)=>{
|
|
|
+ if (jsonData && jsonData.length > 0) {
|
|
|
+ receiveFacilityData(jsonData, TbIncdObj, 'incident');
|
|
|
+ if (selectIncidentId) {
|
|
|
+ _MapHandler.click('incident', selectIncidentId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, null);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 스마트교차로
|
|
|
+ */
|
|
|
+function getIntersection() {
|
|
|
+ getDataAsync('/api/itcs/list', 'POST', null, null, (jsonData)=>{
|
|
|
+ if (jsonData && jsonData.length > 0) {
|
|
|
+ jsonData.sort((a, b)=>{
|
|
|
+ return a.ixr_nm > b.ixr_nm ? 1 : a.ixr_nm < b.ixr_nm ? -1 : 0;
|
|
|
+ });
|
|
|
+ let data = [];
|
|
|
+ jsonData.forEach((obj)=>{
|
|
|
+ if(obj.detail.length > 0) {
|
|
|
+ data.push(obj);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ receiveFacilityData(data, IntersectionObj, 'intersection');
|
|
|
+ }
|
|
|
+ }, null);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 주차정보
|
|
|
+ */
|
|
|
+function getParking() {
|
|
|
+ getDataAsync('/api/traffic/parking-list', 'POST', null, null, (jsonData)=>{
|
|
|
+ if (jsonData && jsonData.length > 0) {
|
|
|
+ receiveFacilityData(jsonData, TbParkingObj, 'parking');
|
|
|
+ }
|
|
|
+ }, null);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 간선도로 정보
|
|
|
+ */
|
|
|
+function getAtrd() {
|
|
|
+ getDataAsync("/api/traffic/atrd-vertex-all", "POST", null, null, (jsonData)=>{
|
|
|
+ if (jsonData && jsonData.length > 0) {
|
|
|
+ _AtrdMap = new Map();
|
|
|
+ jsonData.forEach((obj)=>{
|
|
|
+ _AtrdMap.set(obj.level, obj.list);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }, null);
|
|
|
+
|
|
|
+ getDataAsync('/api/traffic/atrd-list', 'POST', null, null, (jsonData)=>{
|
|
|
+ if (jsonData) {
|
|
|
+ let listStr = "";
|
|
|
+ let mobileStr = "";
|
|
|
+ let atrdData = [];
|
|
|
+
|
|
|
+ for (let key in jsonData){
|
|
|
+ atrdData.push({
|
|
|
+ name : key,
|
|
|
+ list : jsonData[key]
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ atrdData.sort((a,b)=>{
|
|
|
+ return a.name > b.name ? 1 : a.name < b.name ? -1 : 0;
|
|
|
+ });
|
|
|
+
|
|
|
+ atrdData.forEach((obj)=>{
|
|
|
+ let upHillId = null;
|
|
|
+ let downHillId = null;
|
|
|
+ const list = obj.list;
|
|
|
+ if (list && list.length === 2) {
|
|
|
+ upHillId = list[0].atrd_id;
|
|
|
+ downHillId = list[1].atrd_id;
|
|
|
+
|
|
|
+ if (list[0].drct_cd === "1") {
|
|
|
+ upHillId = list[1].atrd_id;
|
|
|
+ downHillId = list[0].atrd_id;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ listStr += `<li id="atrd_${upHillId}_${downHillId}" onclick="atrdClickEvent('${upHillId}', '${downHillId}')">${obj.name}</li>`
|
|
|
+ mobileStr += `<option value="${upHillId}_${downHillId}">${obj.name}</option>`
|
|
|
+ });
|
|
|
+
|
|
|
+ const $mobileSelect = $('.mobile-select');
|
|
|
+ $mobileSelect.append($(mobileStr));
|
|
|
+ $mobileSelect.on('change', function(){
|
|
|
+ const ids = $(this).val();
|
|
|
+ if (ids && ids !== '-') {
|
|
|
+ const idArr = ids.split('_');
|
|
|
+ atrdClickEvent(idArr[0], idArr[1]);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ const array = _MapHandler['atrd'];
|
|
|
+ if (array.length > 0) {
|
|
|
+ array.forEach((atrd)=>{
|
|
|
+ atrd.close();
|
|
|
+ })
|
|
|
+ _MapHandler['atrd'] = [];
|
|
|
+ getVertex();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ const listSection = $('.left-list-area .list-content.list');
|
|
|
+ listSection.empty();
|
|
|
+ listSection.html(listStr);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ getVertex();
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 소통정보 가져오기
|
|
|
+ */
|
|
|
+function getVertex() {
|
|
|
+ const array = _MapHandler['traffic'];
|
|
|
+ if (array.length > 0) {
|
|
|
+ array.forEach((obj) => {
|
|
|
+ obj.setVisibleMarker(false);
|
|
|
+ if (obj.infoWindow) {
|
|
|
+ obj.infoWindow.setMap(null);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ _MapHandler['traffic'] = [];
|
|
|
+ }
|
|
|
+
|
|
|
+ let level = _MapHandler.map.getLevel();
|
|
|
+ const bounds = _MapHandler.map.getBounds();
|
|
|
+ const swLatLng = bounds.getSouthWest();
|
|
|
+ const neLatLng = bounds.getNorthEast();
|
|
|
+ const data = {
|
|
|
+ levl : level,
|
|
|
+ swLat : swLatLng.getLat(),
|
|
|
+ neLat : neLatLng.getLat(),
|
|
|
+ swLng : swLatLng.getLng(),
|
|
|
+ neLng : neLatLng.getLng(),
|
|
|
+ }
|
|
|
+ if (_MapHandler.atrd && _MapHandler.atrd.length > 0) {
|
|
|
+ _MapHandler.atrd.forEach((atrd)=>{
|
|
|
+ atrd.cnt = 0;
|
|
|
+ atrd.trvl_hh = 0;
|
|
|
+ atrd.sped = 0;
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ getDataAsync('/api/traffic/vertex-list', 'POST', data, null, (jsonData)=>{
|
|
|
+ if (jsonData && jsonData.length > 0) {
|
|
|
+ jsonData.forEach((obj)=>{
|
|
|
+ const trafficObj = new TrafficObj(obj);
|
|
|
+ if (_AtrdData.length > 0) {
|
|
|
+
|
|
|
+ _AtrdData.forEach((atrd)=>{
|
|
|
+ if (atrd.road_id.toString() === trafficObj.ID.toString()) {
|
|
|
+ let sped = Number(obj.sped);
|
|
|
+ let trvl_hh = Number(obj.trvl_hh);
|
|
|
+ const atrdObj = _MapHandler.getSelectObj(_MapHandler['atrd'], atrd.atrd_id);
|
|
|
+ if (!isNaN(sped)) {
|
|
|
+ atrdObj.sped += sped;
|
|
|
+ }
|
|
|
+ if (!isNaN(trvl_hh)) {
|
|
|
+ atrdObj.trvl_hh += trvl_hh;
|
|
|
+ }
|
|
|
+ atrdObj.cnt += 1;
|
|
|
+ trafficObj.polyBackLine.setOptions({
|
|
|
+ strokeColor : 'black',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ _MapHandler['traffic'].push(trafficObj);
|
|
|
+ })
|
|
|
+ }
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * 간선도로 클릭 이벤트
|
|
|
+ * @param AupHillId 상행 ID
|
|
|
+ * @param AdownHillId 하행 ID
|
|
|
+ */
|
|
|
+function atrdClickEvent(AupHillId, AdownHillId) {
|
|
|
+ let atrdArr = _MapHandler['atrd'];
|
|
|
+ if (atrdArr.length > 0) {
|
|
|
+ atrdArr.forEach((atrd)=>{
|
|
|
+ atrd.close();
|
|
|
+ });
|
|
|
+ _MapHandler['atrd'] = [];
|
|
|
+ }
|
|
|
+ const selectedObj = _MapHandler.selectedObj;
|
|
|
+ if (selectedObj) {
|
|
|
+ _MapHandler.close(selectedObj.type, selectedObj.ID);
|
|
|
+ }
|
|
|
+ _AtrdData = [];
|
|
|
+ const $selectedLi = $('.left-list-area .list-content.list > li.click');
|
|
|
+ if ($selectedLi) {
|
|
|
+ $selectedLi.removeClass('click');
|
|
|
+ }
|
|
|
+ const $selectLi = $('#atrd_' + AupHillId + "_" + AdownHillId);
|
|
|
+ $selectLi.addClass('click');
|
|
|
+ $selectLi.focus();
|
|
|
+
|
|
|
+ //상행, 하행 ID 가 있다면 실행
|
|
|
+ if (AupHillId && AdownHillId) {
|
|
|
+ const upHillArr = [];
|
|
|
+ const downHillArr = [];
|
|
|
+ const bounds = new kakao.maps.LatLngBounds();
|
|
|
+
|
|
|
+ //전체 간선도로 목록을 담은 Map 에서 기준값을 5레벨로 잡아 포커스 좌표를 설정
|
|
|
+ if (_AtrdMap.get("5")) {
|
|
|
+ const basicAtrd = _AtrdMap.get("5");
|
|
|
+ for (let idx in basicAtrd) {
|
|
|
+ const obj = basicAtrd[idx];
|
|
|
+ if (obj.atrd_id.toString() === AupHillId || obj.atrd_id.toString() === AdownHillId) {
|
|
|
+ bounds.extend(new kakao.maps.LatLng(obj.y_crdn_min, obj.x_crdn_min));
|
|
|
+ bounds.extend(new kakao.maps.LatLng(obj.y_crdn_max, obj.x_crdn_max));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ _MapHandler.map.setBounds(bounds);
|
|
|
+
|
|
|
+ //전체 레벨이 다있는게 아니므로 로드 레벨은 재설정
|
|
|
+ let level = _Level;
|
|
|
+ if (level >= 8) {
|
|
|
+ level = 7;
|
|
|
+ }
|
|
|
+ else if (level >= 6) {
|
|
|
+ level = 6;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 범위를 포커스 하게 되면 레벨이 변경되므로 변경 된 레벨의 간선도로 목록에서
|
|
|
+ * 상행, 하행 ID가 포함된 데이터 갖고오며 상행, 하행 데이터 따로 구분
|
|
|
+ */
|
|
|
+ const atrdInfo = _AtrdMap.get(level.toString());
|
|
|
+ if (atrdInfo) {
|
|
|
+ atrdInfo.forEach((atrd)=>{
|
|
|
+ if (atrd.atrd_id.toString() === AupHillId.toString() || atrd.atrd_id.toString() === AdownHillId.toString()) {
|
|
|
+ _AtrdData.push(atrd);
|
|
|
+
|
|
|
+ if (atrd.atrd_id === AupHillId) {
|
|
|
+ upHillArr.push(atrd);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ downHillArr.push(atrd);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ //레벨이 변경됐으므로 다시한번 버텍스를 초기화해준다
|
|
|
+ getVertex();
|
|
|
+
|
|
|
+ //각 상행 하행의 첫번째 좌표를 가지고 상행, 하행 아이콘을 생성 하며 객체는 array에 보관해둠
|
|
|
+ if (upHillArr[0]) {
|
|
|
+ const upHillObj = new TbAtrdObj(upHillArr[0]);
|
|
|
+ _MapHandler['atrd'].push(upHillObj);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (downHillArr[0]) {
|
|
|
+ const downHillObj = new TbAtrdObj(downHillArr[0]);
|
|
|
+ _MapHandler['atrd'].push(downHillObj);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 간선도로 상,하행 마커 그리기
|
|
|
+ * @param src 상, 하행 코드
|
|
|
+ * @param lat X 좌표
|
|
|
+ * @param lng Y 좌표
|
|
|
+ * @param name 명칭
|
|
|
+ * @returns {daum.maps.Marker} 생성 마커
|
|
|
+ */
|
|
|
+function drawAtrdMakrer(src, lng, lat, name) {
|
|
|
+ let imageSize;
|
|
|
+ let imageOption;
|
|
|
+ let imageSrc = '/images/icon/atrd' + src + '.png';
|
|
|
+
|
|
|
+ //레벨별 사이즈를 다르게 표출
|
|
|
+ const level = _Level;
|
|
|
+ let size = 48;
|
|
|
+ if (level >= 7) {
|
|
|
+ size = 24;
|
|
|
+ }
|
|
|
+
|
|
|
+ imageSize = new kakao.maps.Size(size, size);
|
|
|
+ imageOption = {
|
|
|
+ offset: new kakao.maps.Point(size/2, size),
|
|
|
+ };
|
|
|
+
|
|
|
+ let markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption);
|
|
|
+ let markerPosition = new kakao.maps.LatLng(lng, lat);
|
|
|
+
|
|
|
+ let atrdSideMarker = new kakao.maps.Marker({
|
|
|
+ position: markerPosition,
|
|
|
+ image: markerImage,
|
|
|
+ zIndex: 5,
|
|
|
+ title: name,
|
|
|
+ });
|
|
|
+ return atrdSideMarker;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 소통정보 Object
|
|
|
+ */
|
|
|
+class TrafficObj {
|
|
|
+ constructor(obj) {
|
|
|
+ this.ID = obj.roadway_id;
|
|
|
+ this.NAME = obj.roadway_nm;
|
|
|
+ this.obj = obj;
|
|
|
+ this.infoWindow = null;
|
|
|
+ this.polyLine = null;
|
|
|
+ this.polyBackLine = null;
|
|
|
+ this.init();
|
|
|
+ }
|
|
|
+
|
|
|
+ init() {
|
|
|
+ const _self = this;
|
|
|
+ const trafficObj = this.obj;
|
|
|
+ const xArray = trafficObj.x_crdn.split(",");
|
|
|
+ const yArray = trafficObj.y_crdn.split(",");
|
|
|
+ const linePath = [];
|
|
|
+ for (let ii = 0; ii < xArray.length; ii++) {
|
|
|
+ const x_crdn = Number(xArray[ii]);
|
|
|
+ const y_crdn = Number(yArray[ii]);
|
|
|
+ const coordinates = getKakaoPosition(y_crdn, x_crdn);
|
|
|
+ linePath.push(coordinates);
|
|
|
+ }
|
|
|
+
|
|
|
+ let strokeWeight = 5;
|
|
|
+ let strokeWeightBack = 7;
|
|
|
+ const level = _Level;
|
|
|
+
|
|
|
+ if (level === 3) {
|
|
|
+ strokeWeightBack = 6;
|
|
|
+ } else if (level === 5 || level === 4) {
|
|
|
+ strokeWeight = 3;
|
|
|
+ strokeWeightBack = 5;
|
|
|
+ } else if (level >= 6) {
|
|
|
+ strokeWeight = 2;
|
|
|
+ strokeWeightBack = 4;
|
|
|
+ }
|
|
|
+ this.polyBackLine = new kakao.maps.Polyline({
|
|
|
+ path: linePath, // 선을 구성하는 좌표배열 입니다
|
|
|
+ strokeWeight: strokeWeightBack, // 선의 두께 입니다
|
|
|
+ strokeColor: '#eeeeee', // 선의 색깔입니다
|
|
|
+ strokeOpacity: 1, // 선의 불투명도 입니다 1에서 0 사이의 값이며 0에 가까울수록 투명합니다
|
|
|
+ strokeStyle: 'solid', // 선의 스타일입니다
|
|
|
+ zIndex: 1
|
|
|
+ });
|
|
|
+ this.polyLine = new kakao.maps.Polyline({
|
|
|
+ path: linePath, // 선을 구성하는 좌표배열 입니다
|
|
|
+ strokeWeight: strokeWeight, // 선의 두께 입니다
|
|
|
+ strokeColor: g_color.get(trafficObj.cmtr_grad_cd), // 선의 색깔입니다
|
|
|
+ strokeOpacity: 1, // 선의 불투명도 입니다 1에서 0 사이의 값이며 0에 가까울수록 투명합니다
|
|
|
+ strokeStyle: 'solid', // 선의 스타일입니다
|
|
|
+ zIndex: 2
|
|
|
+ });
|
|
|
+
|
|
|
+ this.setVisibleMarker(_MapHandler['trafficFlag']);
|
|
|
+
|
|
|
+ new kakao.maps.event.addListener(this.polyLine, 'mouseover', function (event) {
|
|
|
+
|
|
|
+ this.setOptions({strokeColor: '#0000FF'});
|
|
|
+ const iwContent =
|
|
|
+ `<div class="trafficPop">
|
|
|
+ <div class="traffic-speed ${trafficObj.cmtr_grad_cd}">
|
|
|
+ <span class="traffic-name">${_self.NAME}</span>
|
|
|
+ <span class="traffic-speed-info border-back ${trafficObj.cmtr_grad_cd}">${trafficObj.grad_nm}</span>
|
|
|
+ </div>
|
|
|
+ <div class="traffic-info">
|
|
|
+ <span>${trafficObj.strt_nm_node} → ${trafficObj.end_nm_node}</span>
|
|
|
+ <br>
|
|
|
+ <span>소요시간 : </span>
|
|
|
+ <span class="${trafficObj.cmtr_grad_cd}">약 ${textFormat(trafficObj.trvl_hh)}분 </span>
|
|
|
+ <span> 속도 : </span>
|
|
|
+ <span class="${trafficObj.cmtr_grad_cd}">약 ${textFormat(trafficObj.sped)}km/h</span>
|
|
|
+ </div>
|
|
|
+ </div>`;
|
|
|
+ _self.infoWindow = new kakao.maps.CustomOverlay({
|
|
|
+ map: _MapHandler.map,
|
|
|
+ clickable: true,
|
|
|
+ position: event.latLng,
|
|
|
+ content: iwContent,
|
|
|
+ xAnchor: -0.1,
|
|
|
+ yAnchor: 1.1,
|
|
|
+ zIndex: 4
|
|
|
+ });
|
|
|
+
|
|
|
+ });
|
|
|
+
|
|
|
+ daum.maps.event.addListener(this.polyLine, 'mouseout', function () {
|
|
|
+ this.setOptions({strokeColor: g_color.get(trafficObj.cmtr_grad_cd)});
|
|
|
+ if (_self.infoWindow != null) _self.infoWindow.setMap(null);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ setVisibleMarker(isVisible) {
|
|
|
+ const isShow = isVisible ? _MapHandler.map : null;
|
|
|
+ this.polyBackLine.setMap(isShow);
|
|
|
+ this.polyLine.setMap(isShow);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 간선도로 Object
|
|
|
+ */
|
|
|
+class TbAtrdObj {
|
|
|
+ constructor(obj) {
|
|
|
+ this.ID = obj.atrd_id;
|
|
|
+ this.NAME = obj.atrd_nm;
|
|
|
+ this.X_CRDN = null;
|
|
|
+ this.Y_CRDN = null;
|
|
|
+ this.obj = obj;
|
|
|
+ this.marker = null;
|
|
|
+ this.imgSrc = '/images/icon/atrd';
|
|
|
+ this.isClick = false;
|
|
|
+ this.sped = 0;
|
|
|
+ this.trvl_hh = 0;
|
|
|
+ this.cnt = 0;
|
|
|
+ this.infoWindow = null;
|
|
|
+ this.init();
|
|
|
+ }
|
|
|
+
|
|
|
+ init() {
|
|
|
+ if (this.obj.x_crdn_arr) {
|
|
|
+ this.X_CRDN = this.obj.x_crdn_arr.split(",")[0];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (this.obj.y_crdn_arr) {
|
|
|
+ this.Y_CRDN = this.obj.y_crdn_arr.split(",")[0];
|
|
|
+ }
|
|
|
+ const name = this.NAME + " [" + this.obj.drct_nm + "]";
|
|
|
+ this.marker = drawAtrdMakrer(this.obj.drct_cd, this.Y_CRDN, this.X_CRDN, name);
|
|
|
+ this.click();
|
|
|
+ // let _self = this;
|
|
|
+ // new kakao.maps.event.addListener(this.marker, 'mouseover', function (event) {
|
|
|
+ // let position = getKakaoPosition(_self.Y_CRDN, _self.X_CRDN);
|
|
|
+ // const iwContent =
|
|
|
+ // `<div class="trafficPop">
|
|
|
+ // <div>
|
|
|
+ // <span class="traffic-name">${_self.NAME}</span>
|
|
|
+ // <span>[${_self.obj.drct_nm}]</span>
|
|
|
+ // </div>
|
|
|
+ // <div class="traffic-info">
|
|
|
+ // <span>평균속도 : ${Math.round(_self.sped/_self.cnt)} km/h</span><br>
|
|
|
+ // <span>통행시간 : ${textFormat(Math.round(_self.trvl_hh/_self.trvl_hh))}분 </span>
|
|
|
+ // </div>
|
|
|
+ // </div>`;
|
|
|
+ // _self.infoWindow = new kakao.maps.CustomOverlay({
|
|
|
+ // map: _MapHandler.map,
|
|
|
+ // clickable: true,
|
|
|
+ // position: position,
|
|
|
+ // content: iwContent,
|
|
|
+ // xAnchor: -0.1,
|
|
|
+ // yAnchor: 1.1,
|
|
|
+ // zIndex: 4
|
|
|
+ // });
|
|
|
+ // });
|
|
|
+ // new kakao.maps.event.addListener(this.marker, 'mouseout', function (event) {
|
|
|
+ // _self.infoWindow.setMap(null);
|
|
|
+ // })
|
|
|
+ }
|
|
|
+
|
|
|
+ click() {
|
|
|
+ this.setVisibleMarker(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ setVisibleMarker(isVisible) {
|
|
|
+ let visible = isVisible ? _MapHandler.map : null;
|
|
|
+ this.marker.setMap(visible);
|
|
|
+ this.isClick = isVisible;
|
|
|
+ }
|
|
|
+
|
|
|
+ close() {
|
|
|
+ this.setVisibleMarker(false);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * CCTV Object
|
|
|
+ */
|
|
|
+class TbCCtvObj {
|
|
|
+ constructor(obj) {
|
|
|
+ this.ID = obj.cctv_mngm_nmbr;
|
|
|
+ this.NAME = obj.istl_lctn_nm;
|
|
|
+ this.X_CRDN = obj.x_crdn;
|
|
|
+ this.Y_CRDN = obj.y_crdn;
|
|
|
+ this.URL = obj.strm_http_addr;
|
|
|
+ this.type = 'cctv';
|
|
|
+ this.obj = obj;
|
|
|
+ this.marker = null;
|
|
|
+ this.infoWindow = null;
|
|
|
+ this.iwContent = null;
|
|
|
+ this.isClick = false;
|
|
|
+ this.imgSrc = '/images/icon/cctv';
|
|
|
+ this.timer = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ init() {
|
|
|
+ this.marker = createMarker(this, 'cctv');
|
|
|
+ this.iwContent = `<div class="cctv-info-window">
|
|
|
+ <div class="title">
|
|
|
+ <div class="cctv-name-${this.ID}">${this.NAME}</div>
|
|
|
+ <div onclick="infoWindowEvent('cctv', '${this.ID}', 'close')">X</div>
|
|
|
+ </div>
|
|
|
+ <div class="content">
|
|
|
+ <div>
|
|
|
+ <video id="video-${this.ID}" class="video-js" playsinline style="width: 100%; height: 100%;"></video>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div>※ CCTV영상은 30초간 제공됩니다.</div>
|
|
|
+ <div class="continue-play">계속재생</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>`;
|
|
|
+ }
|
|
|
+
|
|
|
+ setVisibleMarker(isVisible) {
|
|
|
+ this.marker.setVisible(isVisible);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+/**
|
|
|
+ * Parking Object
|
|
|
+ */
|
|
|
+class TbParkingObj {
|
|
|
+ constructor(obj) {
|
|
|
+ this.ID = obj.parking_id;
|
|
|
+ this.NAME = obj.parking_nm;
|
|
|
+ this.X_CRDN = obj.x_crdn;
|
|
|
+ this.Y_CRDN = obj.y_crdn;
|
|
|
+ this.obj = obj;
|
|
|
+ this.marker = null;
|
|
|
+ this.infoWindow = null;
|
|
|
+ this.iwContent = null;
|
|
|
+ this.isClick = false;
|
|
|
+ this.imgSrc = '/images/icon/parking';
|
|
|
+ this.timer = null;
|
|
|
+ this.type = 'parking';
|
|
|
+ }
|
|
|
+
|
|
|
+ init() {
|
|
|
+ this.marker = createMarker(this, 'parking');
|
|
|
+ this.iwContent = `<div class="parking-info-window">
|
|
|
+ <div class="title">
|
|
|
+ <div class="parking-name-${this.ID}">${this.NAME}</div>
|
|
|
+ <div onclick="infoWindowEvent('parking', '${this.ID}', 'close')"></div>
|
|
|
+ </div>
|
|
|
+ <div class="content">
|
|
|
+ <div class="row">
|
|
|
+ <div>주차면수</div>
|
|
|
+ <div title="주차면수 : ${this.obj.parking_num} 대">${this.obj.parking_num} 대</div>
|
|
|
+ </div>
|
|
|
+ <div class="row">
|
|
|
+ <div>구분</div>
|
|
|
+ <div title="구분 : ${this.obj.parking_type_desc}">${this.obj.parking_type_desc}</div>
|
|
|
+ </div>
|
|
|
+ <div class="row">
|
|
|
+ <div>기본요금</div>
|
|
|
+ <div title="기본요금 : ${this.obj.parking_fee_type_desc}">${this.obj.parking_fee_type_desc}</div>
|
|
|
+ </div>
|
|
|
+ <div class="row">
|
|
|
+ <div>주소</div>
|
|
|
+ <div title="주소 : ${this.obj.parking_addr}">${this.obj.parking_addr}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>`;
|
|
|
+ }
|
|
|
+
|
|
|
+ setVisibleMarker(isVisible) {
|
|
|
+ this.marker.setVisible(isVisible);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * VMS Object
|
|
|
+ */
|
|
|
+class TbVmsObj {
|
|
|
+ constructor(obj) {
|
|
|
+ this.ID = obj.vms_ctlr_nmbr;
|
|
|
+ this.NAME = obj.vms_nm;
|
|
|
+ this.X_CRDN = obj.x_crdn;
|
|
|
+ this.Y_CRDN = obj.y_crdn;
|
|
|
+ this.obj = obj;
|
|
|
+ this.marker = null;
|
|
|
+ this.infoWindow = null;
|
|
|
+ this.iwContent = null;
|
|
|
+ this.isClick = false;
|
|
|
+ this.imgSrc = '/images/icon/vms';
|
|
|
+ this.timer = null;
|
|
|
+ this.phaseArray = [];
|
|
|
+ this.type = 'vms';
|
|
|
+ }
|
|
|
+
|
|
|
+ init() {
|
|
|
+ this.marker = createMarker(this, 'vms');
|
|
|
+ this.phaseArray = [];
|
|
|
+ let width;
|
|
|
+ let height;
|
|
|
+ let isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
|
|
|
+ switch (this.obj.vms_type_cd) {
|
|
|
+ case 'VMC1':
|
|
|
+ width = 400;
|
|
|
+ height = 64;
|
|
|
+ break;
|
|
|
+ case 'VMC2':
|
|
|
+ width = 384;
|
|
|
+ height = 64;
|
|
|
+ break;
|
|
|
+ case 'VMC3':
|
|
|
+ width = 288;
|
|
|
+ height = 160;
|
|
|
+ break;
|
|
|
+ case 'VMC4':
|
|
|
+ width = 256;
|
|
|
+ height = 192;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ const windowHeight = $(window).height();
|
|
|
+ if (isMobile || windowHeight < 900) {
|
|
|
+ width = width/2;
|
|
|
+ height = height/2;
|
|
|
+ }
|
|
|
+ width = width +'px';
|
|
|
+ height = height + 'px';
|
|
|
+
|
|
|
+ const msg = this.obj.msg;
|
|
|
+
|
|
|
+ if (!msg || msg.length === 0) {
|
|
|
+ width = '256px';
|
|
|
+ height = '50px';
|
|
|
+ }
|
|
|
+
|
|
|
+ let iwContent =
|
|
|
+ `<div class="vms-info-window" style="width: calc(${width} + 10px); height: calc(${height} + 50px);">
|
|
|
+ <div class="title">
|
|
|
+ <div class="vms-name-${this.ID}">${this.NAME}</div>
|
|
|
+ <div onclick="infoWindowEvent('vms', ${this.ID}, 'close')">X</div>
|
|
|
+ </div>
|
|
|
+ <div class="content" style="width: ${width}; height: ${height};">`;
|
|
|
+ if (msg && msg.length > 0) {
|
|
|
+ for (let idx in msg) {
|
|
|
+ let msgObj = msg[idx];
|
|
|
+ let className = '';
|
|
|
+ if (idx === "0") {
|
|
|
+ className = 'active'
|
|
|
+ }
|
|
|
+ iwContent += `<img id="phase-${msgObj.phase}" class="${className}" style="width: ${width}; height: ${height};" src="/api/traffic/vms-dspl-image/${this.ID}/${msgObj.phase}">`;
|
|
|
+ this.phaseArray.push(msgObj.phase);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ iwContent += '표출 이미지 데이터가 없습니다.';
|
|
|
+ }
|
|
|
+ iwContent += `</div></div>`;
|
|
|
+ this.iwContent = iwContent;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ setVisibleMarker(isVisible) {
|
|
|
+ this.marker.setVisible(isVisible);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 돌발정보 Object
|
|
|
+ */
|
|
|
+class TbIncdObj {
|
|
|
+ constructor(obj) {
|
|
|
+ this.ID = obj.incd_ocrr_id;
|
|
|
+ this.NAME = obj.incd_titl;
|
|
|
+ this.X_CRDN = obj.x_crdn;
|
|
|
+ this.Y_CRDN = obj.y_crdn;
|
|
|
+ this.obj = obj;
|
|
|
+ this.marker = null;
|
|
|
+ this.infoWindow = null;
|
|
|
+ this.isClick = false;
|
|
|
+ this.imgSrc = '/images/icon/incd';
|
|
|
+ this.iwContent = null;
|
|
|
+ this.type = 'incident';
|
|
|
+ }
|
|
|
+
|
|
|
+ init() {
|
|
|
+ this.marker = createMarker(this, 'incident');
|
|
|
+ this.iwContent = `<div class="incident-info-window">
|
|
|
+ <div class="title">
|
|
|
+ <div class="incident-name-${this.ID}">${this.NAME}</div>
|
|
|
+ <div onclick="infoWindowEvent('incident', '${this.ID}', 'close')">X</div>
|
|
|
+ </div>
|
|
|
+ <div class="content">
|
|
|
+ <div>
|
|
|
+ 위치 : ${this.obj.road_nm}
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ 설명 : ${this.obj.incd_expl}
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ 기간 : ${this.obj.incd_strt_dt} ~ ${this.obj.incd_end_prar_dt}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>`;
|
|
|
+ }
|
|
|
+
|
|
|
+ setVisibleMarker(isVisible) {
|
|
|
+ this.marker.setVisible(isVisible);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 스마트 교차로 Object
|
|
|
+ */
|
|
|
+class IntersectionObj {
|
|
|
+ constructor(obj) {
|
|
|
+ this.ID = obj.ixr_id;
|
|
|
+ this.NAME = obj.ixr_nm;
|
|
|
+ this.X_CRDN = obj.x_crdn;
|
|
|
+ this.Y_CRDN = obj.y_crdn;
|
|
|
+ this.obj = obj;
|
|
|
+ this.marker = null;
|
|
|
+ this.infoWindow = null;
|
|
|
+ this.isClick = false;
|
|
|
+ this.imgSrc = '/images/icon/intersection';
|
|
|
+ this.detail = [];
|
|
|
+ this.type = 'intersection';
|
|
|
+ }
|
|
|
+
|
|
|
+ init() {
|
|
|
+ let imageSrc = this.imgSrc + '.png', // 마커이미지의 주소입니다
|
|
|
+ size = _size[_Level],
|
|
|
+ imageSize = new kakao.maps.Size(size, size), // 마커이미지의 크기입니다
|
|
|
+ imageOption = {
|
|
|
+ offset: new kakao.maps.Point(size/2, size/2),
|
|
|
+ alt: this.NAME,
|
|
|
+ };
|
|
|
+
|
|
|
+ // 마커의 이미지정보를 가지고 있는 마커이미지를 생성합니다
|
|
|
+ let markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption),
|
|
|
+ markerPosition = getKakaoPosition(this.Y_CRDN, this.X_CRDN); // 마커가 표시될 위치입니다
|
|
|
+
|
|
|
+ this.marker = new kakao.maps.Marker(
|
|
|
+ {map: _MapHandler.map, position: markerPosition, image: markerImage, zindex: 10, clickable: true, title : this.NAME}
|
|
|
+ );
|
|
|
+ const level = _Level;
|
|
|
+ const isVisible = (level > 2 && _MapHandler['intersectionFlag']);
|
|
|
+ this.marker.setVisible(isVisible);
|
|
|
+ let _self = this;
|
|
|
+ new kakao.maps.event.addListener(this.marker, 'click', ()=> _MapHandler.click('intersection', _self.ID));
|
|
|
+ }
|
|
|
+
|
|
|
+ setVisibleMarker(isVisible) {
|
|
|
+ if (_Level <= 2) isVisible = false;
|
|
|
+ this.marker.setVisible(isVisible);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 스마트교차로 카메라 Object
|
|
|
+ */
|
|
|
+class IntersectionCameraObj {
|
|
|
+ constructor(obj) {
|
|
|
+ this.ID = obj.cmra_id + '_' + obj.drct_dvsn_cd;
|
|
|
+ this.NAME = obj.drct_lctn;
|
|
|
+ this.X_CRDN = obj.cmra_x_crdn;
|
|
|
+ this.Y_CRDN = obj.cmra_y_crdn;
|
|
|
+ this.URL = obj.hmpg_cmra_url;
|
|
|
+ this.obj = obj;
|
|
|
+ this.marker = null;
|
|
|
+ this.infoWindow = null;
|
|
|
+ this.iwContent = null;
|
|
|
+ this.isClick = false;
|
|
|
+ this.timer = null;
|
|
|
+ this.polyline = null;
|
|
|
+ this.type = 'intersectionCamera';
|
|
|
+ }
|
|
|
+
|
|
|
+ init() {
|
|
|
+ this.marker = createIntersectionCameraMarker(this);
|
|
|
+ this.iwContent =
|
|
|
+ `<div class="cctv-info-window">
|
|
|
+ <div class="title">
|
|
|
+ <div class="intersectionCamera-name-${this.ID}">${this.NAME}</div>
|
|
|
+ <div class="close-window" onclick="infoWindowEvent('intersectionCamera', '${this.ID}', 'close')">X</div>
|
|
|
+ </div>
|
|
|
+ <div class="content">
|
|
|
+ <div>
|
|
|
+ <video id="video-${this.ID}" class="video-js" style="width: 100%; height: 100%;"></video>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <div>※ CCTV영상은 30초간 제공됩니다.</div>
|
|
|
+ <div class="continue-play">계속재생</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>`;
|
|
|
+ }
|
|
|
+
|
|
|
+ setVisibleMarker(isVisible) {
|
|
|
+ const visible = isVisible && _Level <= 2 ? _MapHandler.map : null;
|
|
|
+ this.marker.setMap(visible);
|
|
|
+ this.polyline.setMap(visible);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 인포윈도우 이벤트
|
|
|
+ * @param type 시설물 유형
|
|
|
+ * @param id 요소 ID
|
|
|
+ * @param event 이벤트 종류 (click, close)
|
|
|
+ */
|
|
|
+function infoWindowEvent(type, id, event) {
|
|
|
+ _MapHandler[event](type, id);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+let isHide = false
|
|
|
+
|
|
|
+/**
|
|
|
+ * 좌측 목록 토글 이벤트
|
|
|
+ */
|
|
|
+function toggleEvent() {
|
|
|
+ const $listArea = $('.left-list-area');
|
|
|
+ const $toggleButton = $('.toggle-button');
|
|
|
+
|
|
|
+ if (!isHide) {
|
|
|
+ $toggleButton.animate({
|
|
|
+ left: 0
|
|
|
+ }, 'slow');
|
|
|
+ $listArea .animate({
|
|
|
+ left: -$listArea.width()
|
|
|
+ }, 'slow');
|
|
|
+ $toggleButton.text('>');
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ $toggleButton.animate({
|
|
|
+ left: $listArea.width()
|
|
|
+ }, 'slow');
|
|
|
+ $listArea .animate({
|
|
|
+ left: 0
|
|
|
+ }, 'slow');
|
|
|
+ $toggleButton.text('<');
|
|
|
+ }
|
|
|
+ isHide = !isHide;
|
|
|
+}
|
|
|
+
|
|
|
+window.addEventListener('resize', function(event) {
|
|
|
+ if ($(this).width() > 450) {
|
|
|
+ const $toggleButton = $('.toggle-button');
|
|
|
+ const $listArea = $('.left-list-area');
|
|
|
+ const left = $toggleButton.offset().left;
|
|
|
+ const listLeft = $listArea.offset().left;
|
|
|
+ if ($(this).width() >= 920) {
|
|
|
+ if (left > 0 && left < 400) {
|
|
|
+ $toggleButton.css('left', 400);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (listLeft > -400 && listLeft < 0) {
|
|
|
+ $listArea.css('left', -400);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (left > 0 && left > 275) {
|
|
|
+ $toggleButton.css('left', 275);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (listLeft < -273) {
|
|
|
+ $listArea.css('left', -273);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+})
|
|
|
+/**
|
|
|
+ * 시설물 마커 초기화
|
|
|
+ * @param obj 시설물 객체
|
|
|
+ * @returns {kakao.maps.Marker}
|
|
|
+ */
|
|
|
+function createMarker(obj, type) {
|
|
|
+ let map = _MapHandler.map;
|
|
|
+ let imageSrc = obj.imgSrc + '1.png', // 마커이미지의 주소입니다
|
|
|
+ size = _size[map.getLevel()],
|
|
|
+ imageSize = new kakao.maps.Size(size, size), // 마커이미지의 크기입니다
|
|
|
+ imageOption = {
|
|
|
+ offset: new kakao.maps.Point(size/2, size/2),
|
|
|
+ alt: obj.NAME,
|
|
|
+ };
|
|
|
+
|
|
|
+ // 마커의 이미지정보를 가지고 있는 마커이미지를 생성합니다
|
|
|
+ let markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption),
|
|
|
+ markerPosition = getKakaoPosition(obj.Y_CRDN, obj.X_CRDN); // 마커가 표시될 위치입니다
|
|
|
+
|
|
|
+ let marker = new kakao.maps.Marker(
|
|
|
+ {map: map, position: markerPosition, image: markerImage, zindex: 10, clickable: true, title : obj.NAME}
|
|
|
+ );
|
|
|
+ let flag = _MapHandler[type+'Flag'];
|
|
|
+ marker.setVisible(flag);
|
|
|
+
|
|
|
+ kakao.maps.event.addListener(marker, 'mouseover', function () {
|
|
|
+ if (!obj.isClick) {
|
|
|
+ setMarkerImage(obj, 2, false);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ kakao.maps.event.addListener(marker, 'mouseout', function () {
|
|
|
+ if (!obj.isClick) {
|
|
|
+ setMarkerImage(obj, 1, false)
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ kakao.maps.event.addListener(marker, 'click', ()=> _MapHandler.click(type, obj.ID));
|
|
|
+
|
|
|
+ return marker;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 스마트 교차로 카메라 마커 초기화
|
|
|
+ * @param obj 스마트 교차로 카메라 객체
|
|
|
+ * @returns {kakao.maps.Marker}
|
|
|
+ */
|
|
|
+function createIntersectionCameraMarker(obj) {
|
|
|
+ const position = getKakaoPosition(obj.Y_CRDN, obj.X_CRDN);
|
|
|
+ const content = $('<div id="camera_'+obj.ID+'" title="'+obj.NAME+'">');
|
|
|
+ const angle = Number(obj.obj.cmra_angn);
|
|
|
+ content.css(
|
|
|
+ {
|
|
|
+ width: '38.45px',
|
|
|
+ height: '38.45px',
|
|
|
+ backgroundImage:'url(/images/icon/intersection-cctv.png)',
|
|
|
+ backgroundSize : '38.45px 38.45px',
|
|
|
+ backgroundRepeat: 'no-repeat',
|
|
|
+ backgroundPosition : 'center',
|
|
|
+ transform : 'rotate(' + angle +'deg)'
|
|
|
+ });
|
|
|
+
|
|
|
+ const marker = new kakao.maps.CustomOverlay({
|
|
|
+ content: content[0],
|
|
|
+ position: position,
|
|
|
+ zindex: 15,
|
|
|
+ });
|
|
|
+
|
|
|
+ const linePath1 = [obj.obj.start_x, obj.obj.start_y]
|
|
|
+ const linePath2 = [obj.obj.end_x, obj.obj.end_y];
|
|
|
+ const color = ['#888888', '#15B337', '#15B337', '#15B337', '#FFAA00', '#FFAA00', '#EB260C', '#EB260C', '#EB260C'];
|
|
|
+ obj.polyline = new kakao.maps.Polyline({
|
|
|
+ path: [
|
|
|
+ getKakaoPosition(linePath1[1], linePath1[0]),
|
|
|
+ getKakaoPosition(linePath2[1], linePath2[0]),
|
|
|
+ ],
|
|
|
+ strokeWeight: 10,
|
|
|
+ strokeColor: color[obj.obj.acrd_los],
|
|
|
+ strokeOpacity: 1,
|
|
|
+ strokeStyle: 'solid',
|
|
|
+ endArrow: true,
|
|
|
+ name : obj.NAME,
|
|
|
+ });
|
|
|
+
|
|
|
+ if (_Level <= 2 && _MapHandler['intersectionFlag']){
|
|
|
+ marker.setMap(_MapHandler.map);
|
|
|
+ obj.polyline.setMap(_MapHandler.map);
|
|
|
+ }
|
|
|
+
|
|
|
+ content.on('click', ()=> {
|
|
|
+ obj.click();
|
|
|
+ });
|
|
|
+
|
|
|
+ return marker;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 시설물 이미지 유형 변경 이벤트
|
|
|
+ * @param obj 시설물 객체
|
|
|
+ * @param type 시설물 이미지 유형
|
|
|
+ */
|
|
|
+function setMarkerImage(obj, type, isAtrd) {
|
|
|
+ const currentLevel = _Level;
|
|
|
+ let size = _size[currentLevel];
|
|
|
+ let point1 = size/2;
|
|
|
+ let point2 = size/2;
|
|
|
+ if (isAtrd) {
|
|
|
+ size = ( currentLevel >= 7 ) ? 24 : 48;
|
|
|
+ point1 = size/2;
|
|
|
+ point2 = size;
|
|
|
+ }
|
|
|
+
|
|
|
+ const imageSize = new kakao.maps.Size(size, size);
|
|
|
+ const imageSrc = obj.imgSrc + type +'.png';
|
|
|
+ const imageOption = {
|
|
|
+ offset: new kakao.maps.Point(point1, point2),
|
|
|
+ alt: obj.NAME
|
|
|
+ };
|
|
|
+ const markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption);
|
|
|
+ obj.marker.setImage(markerImage);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 선택 리스트 스크롤 높이 반환 이벤트
|
|
|
+ * @param selectIndex 선택 인덱스
|
|
|
+ * @returns {number} 스크롤 높이
|
|
|
+ */
|
|
|
+function getScrollTop(selectIndex) {
|
|
|
+ let scrollTop = 0;
|
|
|
+ for (let ii=0; ii < selectIndex; ii++) {
|
|
|
+ let height = $('.left-list-area .list-content.list').children().eq(ii).css('height');
|
|
|
+ if (height) {
|
|
|
+ height = Number(height.replace('px', ''));
|
|
|
+ if (!isNaN(height)) {
|
|
|
+ scrollTop += height;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return scrollTop;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 좌측 리스트 선택 시 스크롤 변경 이벤트
|
|
|
+ * @param flag
|
|
|
+ * @param array
|
|
|
+ * @param id
|
|
|
+ */
|
|
|
+function moveToScroll(flag, array, id) {
|
|
|
+ if (flag) {
|
|
|
+ let selectIndex = array.findIndex((obj)=> obj.ID == id);
|
|
|
+ let scrollTop = getScrollTop(selectIndex);
|
|
|
+ $('.left-list-area .list-content.list').animate({
|
|
|
+ scrollTop : scrollTop + 'px'
|
|
|
+ });
|
|
|
+ $('.mobile-select').val(id);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 시설물 데이터 처리 메서드
|
|
|
+ * @param jsonData 수신 데이터
|
|
|
+ * @param array 시설물 Object Array List
|
|
|
+ * @param facilityClass 시설물 Object Class
|
|
|
+ * @param listFlag 시설물 리스트 목록 표출 플래그
|
|
|
+ * @param type 시설물 유형
|
|
|
+ * @returns {*[]} 시설물 Object Array List
|
|
|
+ */
|
|
|
+function receiveFacilityData(jsonData, facilityClass, type) {
|
|
|
+ if (_MapHandler[type].length > 0) {
|
|
|
+ _MapHandler[type].forEach((obj)=>{
|
|
|
+ if (obj.marker) {
|
|
|
+ obj.marker.setMap(null);
|
|
|
+ }
|
|
|
+ if (obj.polyline) {
|
|
|
+ obj.polyline.setMap(null);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ _MapHandler[type] = [];
|
|
|
+ }
|
|
|
+ let listStr = "";
|
|
|
+ let mobileStr = "";
|
|
|
+ if (jsonData && jsonData.length > 0) {
|
|
|
+ jsonData.forEach((obj)=>{
|
|
|
+ const marker = new facilityClass(obj);
|
|
|
+ marker.init();
|
|
|
+ if (type === 'intersection') {
|
|
|
+ if (obj.detail && obj.detail.length > 0) {
|
|
|
+ obj.detail.forEach((cameraObj)=>{
|
|
|
+ const camera = new IntersectionCameraObj(cameraObj);
|
|
|
+ camera.init();
|
|
|
+ _MapHandler[type + 'Camera'].push(camera);
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ listStr += `<li id="${type}-${marker.ID}" onclick="infoWindowEvent('${type}', '${marker.ID}' , 'click')">${marker.NAME}</li>`
|
|
|
+ mobileStr += `<option value="${marker.ID}">${marker.NAME}</option>`;
|
|
|
+ _MapHandler[type].push(marker);
|
|
|
+ });
|
|
|
+
|
|
|
+ if (_MapHandler[type + 'Flag']) {
|
|
|
+ _MapHandler.show(type);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_MapHandler[type + 'ListFlag'] === true) {
|
|
|
+ const listSection = $('.left-list-area .list-content.list');
|
|
|
+ listSection.empty();
|
|
|
+ listSection.html(listStr);
|
|
|
+ const $mobileSelect = $('.mobile-select');
|
|
|
+ $mobileSelect.append($(mobileStr));
|
|
|
+ $mobileSelect.on('change', function(){
|
|
|
+ const id = $(this).val();
|
|
|
+ if (id && id !== "-") {
|
|
|
+ infoWindowEvent(type, id , 'click');
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 맵 중앙 아이콘 위 위치 좌표
|
|
|
+ * @param infoWindow
|
|
|
+ * @returns {number[]}
|
|
|
+ */
|
|
|
+function getInfoWidowPosition(infoWindow) {
|
|
|
+ const map = $('#map');
|
|
|
+
|
|
|
+ let mapHalfW = map.innerWidth() / 2;
|
|
|
+ let mapHalfH = map.innerHeight() / 2;
|
|
|
+ let mapTop = map.offset().top;
|
|
|
+ let halfW = infoWindow.innerWidth() / 2;
|
|
|
+ let height = infoWindow.innerHeight();
|
|
|
+ let left = mapHalfW - halfW;
|
|
|
+ let iconH = _size[_Level];
|
|
|
+ let top = mapTop + mapHalfH - height - iconH;
|
|
|
+ return [top, left];
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 맵 드래그 적용
|
|
|
+ */
|
|
|
+function setInfoWindowPositionWidthDraggable(markerObj, type) {
|
|
|
+ const {infoWindow, ID} = markerObj;
|
|
|
+ const position = getInfoWidowPosition(infoWindow);
|
|
|
+ let top = position[0];
|
|
|
+ let left = position[1];
|
|
|
+ infoWindow.css({
|
|
|
+ top : top + 'px',
|
|
|
+ left : left + 'px',
|
|
|
+ position : 'absolute',
|
|
|
+ zIndex : 999,
|
|
|
+ });
|
|
|
+ infoWindow.draggable({containment : 'body', handle: '.'+ type + '-name-' + ID});
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * 카카오 포지션 지정
|
|
|
+ */
|
|
|
+function getKakaoPosition(yCoordinate, xCoordinate) {
|
|
|
+ return new kakao.maps.LatLng(Number(yCoordinate), Number(xCoordinate));
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * videoJs 객체 생성
|
|
|
+ */
|
|
|
+function createVideoJs(id, url) {
|
|
|
+ let video = videojs("video-" + id, {
|
|
|
+ sources: [
|
|
|
+ {
|
|
|
+ src: url,
|
|
|
+ type: "application/x-mpegURL",
|
|
|
+ crossorigin: "anonymous",
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ responsive: false,
|
|
|
+ autoplay: true,
|
|
|
+ muted: true,
|
|
|
+ preload: "metadata",
|
|
|
+ });
|
|
|
+
|
|
|
+ video.on('error', ()=>{
|
|
|
+ if (video.error().code === 4) {
|
|
|
+ video.pause();
|
|
|
+ video.dispose();
|
|
|
+ const $errorBox = $('.content > div:nth-child(1)');
|
|
|
+ $errorBox.append($('<img src="/images/icon/error.png" alt="스트리밍 오류 이미지">'));
|
|
|
+ $errorBox.css({
|
|
|
+ display : 'flex',
|
|
|
+ alignItems : 'center',
|
|
|
+ justifyContent : 'center',
|
|
|
+ });
|
|
|
+ video = null;
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ return video;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+class MapHandler {
|
|
|
+ constructor(id) {
|
|
|
+ this.selectedObj = null;
|
|
|
+ this.map = null;
|
|
|
+ this.mapElement = id;
|
|
|
+ this.atrd = [];
|
|
|
+ }
|
|
|
+ init () {
|
|
|
+ //시설물별 배열, 토글 플래그, 리스트 플래그 생성
|
|
|
+ _FacilityArray.forEach((type)=>{
|
|
|
+ this[type] = [];
|
|
|
+ this[type + 'Flag'] = false;
|
|
|
+ this[type + 'ListFlag'] = false;
|
|
|
+ });
|
|
|
+
|
|
|
+ const container = document.getElementById(this.mapElement); //지도를 담을 영역의 DOM 레퍼런스
|
|
|
+ const options = { //지도를 생성할 때 필요한 기본 옵션
|
|
|
+ center: getKakaoPosition(36.0191816, 129.3432983), //지도의 중심좌표.
|
|
|
+ level: _Level,
|
|
|
+ maxLevel: 9,
|
|
|
+ minLevel: 1,
|
|
|
+ disableDoubleClickZoom: true
|
|
|
+ };
|
|
|
+ this.map = new kakao.maps.Map(container, options);
|
|
|
+ const mapTypeControl = new kakao.maps.MapTypeControl();
|
|
|
+ this.map.addControl(mapTypeControl, kakao.maps.ControlPosition.TOPRIGHT);
|
|
|
+ const zoomControl = new kakao.maps.ZoomControl();
|
|
|
+ this.map.addControl(zoomControl, kakao.maps.ControlPosition.RIGHT);
|
|
|
+
|
|
|
+ const handler = this;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Map Zoom Level Change 이벤트 (이미지 사이즈, 스마트 교차로 이미지 토글, 소통정보 정보 변경)
|
|
|
+ */
|
|
|
+ kakao.maps.event.addListener(this.map, 'zoom_changed', function () {
|
|
|
+ _Level = this.getLevel();
|
|
|
+ const zoomChangeArray = ['cctv', 'vms', 'parking', 'incident'];
|
|
|
+ zoomChangeArray.forEach((type)=>{
|
|
|
+ const markerArr = handler[type];
|
|
|
+ const markerFlag = handler[type + 'Flag'];
|
|
|
+ markerSizeChangeWithZoomLevel(markerArr, markerFlag);
|
|
|
+ });
|
|
|
+
|
|
|
+ intersectionMarkerChangeWithZoomLevel();
|
|
|
+ intersectionCameraChangeWidthZoomLevel();
|
|
|
+ if (handler['atrd'].length > 0) {
|
|
|
+ atrdMarkerResize();
|
|
|
+ }
|
|
|
+ getVertex();
|
|
|
+ });
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 좌표 데이터가의 양이 많으므로 이동 할때마다 영역별 소통정보를 새로 그려줌
|
|
|
+ */
|
|
|
+ kakao.maps.event.addListener(this.map, 'dragend', function() {
|
|
|
+ getVertex();
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ //마커 클릭 이벤트
|
|
|
+ click(type, id) {
|
|
|
+ const markerArr = this[type]; // 시설물 배열
|
|
|
+ const markerFlag = this[ type + 'Flag']; // 시설물 토글 플래그
|
|
|
+ const markerListFlag = this[ type + 'ListFlag']; // 시설물 토글 플래그
|
|
|
+ const atrdArr = this['atrd'];
|
|
|
+ if (atrdArr && atrdArr.length > 0) {
|
|
|
+ atrdArr.forEach((atrd)=>{
|
|
|
+ atrd.close();
|
|
|
+ });
|
|
|
+ this['atrd'] = [];
|
|
|
+ _AtrdData = [];
|
|
|
+ const $selectedLi = $('.left-list-area .list-content.list > li.click');
|
|
|
+ if ($selectedLi) {
|
|
|
+ $selectedLi.removeClass('click');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let selectObj = this.selectedObj; // 이전 클릭 객체
|
|
|
+ let clickObj = this.getSelectObj(markerArr, id); // 현재 클릭 객체
|
|
|
+
|
|
|
+ if (selectObj) {
|
|
|
+ if (selectObj === clickObj && type !== 'intersection') {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ _MapHandler.close(selectObj.type, selectObj.ID);
|
|
|
+ }
|
|
|
+
|
|
|
+ const coordinates = getKakaoPosition(clickObj.Y_CRDN, clickObj.X_CRDN);
|
|
|
+
|
|
|
+ this.selectedObj = clickObj;
|
|
|
+
|
|
|
+ const selectedLi = $('#'+type+'-' + clickObj.ID);
|
|
|
+ selectedLi.addClass('click');
|
|
|
+ selectedLi.focus();
|
|
|
+
|
|
|
+ this.map.setCenter(coordinates);
|
|
|
+ if (this['trafficFlag']) {
|
|
|
+ getVertex();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (clickObj.iwContent) { // 인포 윈도우가 있을때만 실행
|
|
|
+ clickObj.infoWindow = $(clickObj.iwContent);
|
|
|
+ $('body').append(clickObj.infoWindow);
|
|
|
+ setInfoWindowPositionWidthDraggable(clickObj, type);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (clickObj.URL) { // Url 유무로 영상 이벤트 실행
|
|
|
+ this.videoEvent(clickObj);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (type === 'vms') { // vms 일 경우 이미지 표출실행
|
|
|
+ this.vmsEvent(clickObj);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (type === 'intersection') { // 스마트 교차로는 줌레벨 2로 변경
|
|
|
+ this.map.setLevel(2);
|
|
|
+ }
|
|
|
+ else if (clickObj.imgSrc) { // img src 값이 있는 객체만 클릭 이미지 변경
|
|
|
+ setMarkerImage(clickObj, 2, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ clickObj.isClick = true;
|
|
|
+ if (markerListFlag) {
|
|
|
+ moveToScroll(markerFlag, markerArr, clickObj.ID); // 클릭 시 리스트 이동
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //마커 이벤트 종료
|
|
|
+ close(type, id) {
|
|
|
+ const markerArr = this[type];
|
|
|
+ const listFlag = this[type + 'ListFlag'];
|
|
|
+ const closeObj = this.getSelectObj(markerArr, id);
|
|
|
+ if (closeObj) {
|
|
|
+ closeObj.isClick = false;
|
|
|
+ this.selectedObj = null;
|
|
|
+
|
|
|
+ if (!type.includes('intersection')) { // 스마트교차로 아닌 화면은 이미지를 원래대로 돌린다.
|
|
|
+ setMarkerImage(closeObj, 1, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ let oldPlayer = document.getElementById("video-" + closeObj.ID);
|
|
|
+ let selectedLi = $("#" + type + "-" + closeObj.ID);
|
|
|
+
|
|
|
+ if (selectedLi.hasClass('click')) { // 선택 리스트가 있는지 여부
|
|
|
+ selectedLi.removeClass('click');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (listFlag) { // 리스트 플래그 있는지 여부
|
|
|
+ $('.mobile-select').val("-");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (oldPlayer) { // 켜져있던 영상이 있는지 여부
|
|
|
+ videojs(oldPlayer).dispose();
|
|
|
+ }
|
|
|
+ if (closeObj.infoWindow) { // 인포 윈도우를 화면에 올려놨는지
|
|
|
+ closeObj.infoWindow.remove();
|
|
|
+ closeObj.infoWindow = null;
|
|
|
+ }
|
|
|
+ if (closeObj.timer) { // 인터벌 된 객체가 있는지
|
|
|
+ clearTimeout(closeObj.timer);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //선택 객체 찾기
|
|
|
+ getSelectObj(array, id) {
|
|
|
+ let idx = array.findIndex(obj => obj.ID.toString() === id.toString());
|
|
|
+ return array[idx];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 마커 보이기
|
|
|
+ show(type) {
|
|
|
+ this[type].forEach(obj => obj.setVisibleMarker(true));
|
|
|
+ this[type + 'Flag'] = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 마커 숨기기
|
|
|
+ hide(type) {
|
|
|
+ this[type].forEach(obj => {
|
|
|
+ obj.setVisibleMarker(false);
|
|
|
+ if (obj.isClick === true) {
|
|
|
+ _MapHandler.close(type, obj.ID);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ this[type + 'Flag'] = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ //영상 이벤트
|
|
|
+ videoEvent(obj) {
|
|
|
+ let video = createVideoJs(obj.ID, obj.URL);
|
|
|
+
|
|
|
+ obj.timer = setTimeout(()=>{
|
|
|
+ if (video) {
|
|
|
+ video.pause();
|
|
|
+ }
|
|
|
+ }, CCTV_DISPLAY_TIME);
|
|
|
+
|
|
|
+ $('.continue-play').on('click', ()=>{
|
|
|
+ if (obj.timer) {
|
|
|
+ setTimeout(obj.timer);
|
|
|
+ }
|
|
|
+ if (video) {
|
|
|
+ video.play();
|
|
|
+ obj.timer = setTimeout(()=>{
|
|
|
+ video.pause();
|
|
|
+ }, CCTV_DISPLAY_TIME);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ //vms 이미지 표출 이벤트
|
|
|
+ vmsEvent(obj) {
|
|
|
+ let cnt = 1;
|
|
|
+ if (obj.phaseArray.length > 0) {
|
|
|
+ obj.timer = setInterval(()=>{
|
|
|
+ if (cnt === obj.phaseArray.length) {
|
|
|
+ cnt = 0;
|
|
|
+ }
|
|
|
+ const activeImage = $('.vms-info-window .content img.active');
|
|
|
+ if (activeImage[0]) {
|
|
|
+ activeImage.removeClass('active');
|
|
|
+ }
|
|
|
+ $("#phase-" + obj.phaseArray[cnt]).addClass('active');
|
|
|
+ cnt++;
|
|
|
+ }, VMS_DISPLAY_TIME);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|