let _size = [48, 48, 48, 48, 40, 32, 24, 22, 20, 18, 18,],
_Map = null,
_SelectedObj = null,
_CctvArray = [],
_CctvFlag = false,
_CctvListFlag = false,
_IntersectionArray = [],
_IntersectionFlag = false,
_IntersectionListFlag = false,
_IntersectionCameraArray = [],
_AtrdArray = [],
_AtrdData = [],
_AtrdMap = new Map(),
_VmsArray = [],
_VmsFlag = false,
_VmsListFlag = false,
_IncidentArray = [],
_IncidentFlag = false,
_IncidentListFlag = false,
_TrafficArray = [],
_TrafficFlag = false,
_TrafficListFlag = false,
selectIncidentId = null
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;');
$(()=>{
/**
* 카카오 맵 생성
* @type {HTMLElement}
*/
const container = document.getElementById('map'); //지도를 담을 영역의 DOM 레퍼런스
const options = { //지도를 생성할 때 필요한 기본 옵션
center: new kakao.maps.LatLng(36.0191816, 129.3432983), //지도의 중심좌표.
level: 6,
maxLevel: 9,
minLevel: 1,
disableDoubleClickZoom: true
};
_Map = new kakao.maps.Map(container, options);
const mapTypeControl = new kakao.maps.MapTypeControl();
_Map.addControl(mapTypeControl, kakao.maps.ControlPosition.TOPRIGHT);
const zoomControl = new kakao.maps.ZoomControl();
_Map.addControl(zoomControl, kakao.maps.ControlPosition.RIGHT);
/**
* Map Zoom Level Change 이벤트
*/
kakao.maps.event.addListener(_Map, 'zoom_changed', function () {
markerSizeChangeWithZoomLevel(_CctvArray, _CctvFlag);
markerSizeChangeWithZoomLevel(_VmsArray, _VmsFlag);
intersectionMarkerChangeWithZoomLevel();
intersectionCameraChangeWidthZoomLevel();
markerSizeChangeWithZoomLevel(_IncidentArray, _IncidentFlag);
if (_AtrdArray.length > 0) {
atrdMarkerResize();
}
getVertex();
});
kakao.maps.event.addListener(_Map, 'dragend', function() {
getVertex();
})
function atrdMarkerResize() {
let size = 48;
let level = _Map.getLevel();
if (level >= 7) {
size = 24;
}
_AtrdArray.forEach((atrd)=>{
const imageSize = new kakao.maps.Size(size, size);
const imageSrc = '/images/icon/atrd' + atrd.obj.drct_cd +'.png';
const imageOption = {
offset: new kakao.maps.Point(size/2, size),
};
const markerImage = new kakao.maps.MarkerImage(imageSrc, imageSize, imageOption);
atrd.marker.setImage(markerImage);
})
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 === idArr[1] || atrd.atrd_id == idArr[2]) {
_AtrdData.push(atrd);
if (atrd.atrd_id === 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];
_AtrdArray[0].marker.setPosition(new kakao.maps.LatLng(upHillY, upHillX));
}
if (downHillArr[0]) {
let downHillX = downHillArr[0].x_crdn_arr.split(',')[0];
let downHillY = downHillArr[0].y_crdn_arr.split(',')[0];
_AtrdArray[1].marker.setPosition(new kakao.maps.LatLng(downHillY, downHillX));
}
}
}
/**
* 스마트교차로 카메라 레벨별 이미지 보이기 감추기
*/
function intersectionCameraChangeWidthZoomLevel() {
const level = _Map.getLevel();
const size = [32, 32, 32]
const levelSize = size[level];;
if (_IntersectionCameraArray.length > 0) {
_IntersectionCameraArray.forEach((obj) => {
const content = $('
');
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', ()=> {
obj.click();
});
if (level <= 2 && _IntersectionFlag) {
obj.marker.setMap(_Map);
obj.polyline.setMap(_Map);
} else {
obj.marker.setMap(null);
obj.polyline.setMap(null);
}
})
}
}
/**
* 스마트교차로 레벨별 이미지 보이기 감추기
*/
function intersectionMarkerChangeWithZoomLevel() {
const level = _Map.getLevel();
if (_IntersectionArray.length > 0) {
_IntersectionArray.forEach((obj)=>{
setMarkerImage(obj, "");
if (level > 2 && _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)
}
else {
setMarkerImage(obj, 1);
}
});
}
}
/**
* 범례 클릭 색 변환
* */
$('.legend-bottom button').on('click', function (){
const target = $(this);
const legendIcon = target.children().eq(0);
const legendText = target.children().eq(1).text();
const isShow = !legendIcon.hasClass('active');
switch (legendText) {
case 'CCTV' :
onOffFacility(_CctvArray, isShow, legendIcon, target, null);
_CctvFlag = isShow;
break;
case '스마트교차로CCTV':
onOffFacility(_IntersectionArray, isShow, legendIcon, target, _IntersectionCameraArray);
_IntersectionFlag = isShow;
break;
case '도로전광판':
onOffFacility(_VmsArray, isShow, legendIcon, target, null);
_VmsFlag = isShow;
break;
case '돌발정보':
onOffFacility(_IncidentArray, isShow, legendIcon, target, null);
_IncidentFlag = isShow;
break;
case '소통정보':
onOffFacility(_TrafficArray, isShow, legendIcon, target, _AtrdArray);
_TrafficFlag = isShow;
break;
}
})
/**
* 범례 호버 색 변환
* */
$('.legend-bottom ul li').hover((event)=>{
const iconDiv = $(event.currentTarget).children().eq(0);
if (!iconDiv.hasClass('active')) {
iconDiv.children().eq(0).addClass('hover');
}
else {
if (iconDiv.children().eq(0).hasClass('hover')) {
iconDiv.children().eq(0).removeClass('hover');
}
}
}, (event)=>{
const iconDiv = $(event.currentTarget).children().eq(0);
if (!iconDiv.hasClass('active')) {
iconDiv.children().eq(0).removeClass('hover');
}
else {
if (iconDiv.children().eq(0).hasClass('hover')) {
iconDiv.children().eq(0).removeClass('hover');
}
}
});
/**
* 탭 호버 색 변환
* */
$('.left-list-area .list-tab > li').hover((event)=>{
const iconDiv = $(event.currentTarget);
if (!iconDiv.hasClass('active')) {
iconDiv.children().eq(0).addClass('hover');
}
else {
if (iconDiv.children().eq(0).hasClass('hover')) {
iconDiv.children().eq(0).removeClass('hover');
}
}
}, (event)=>{
const iconDiv = $(event.currentTarget);
if (!iconDiv.hasClass('active')) {
iconDiv.children().eq(0).removeClass('hover');
}
else {
if (iconDiv.children().eq(0).hasClass('hover')) {
iconDiv.children().eq(0).removeClass('hover');
}
}
});
initFaicilityData();
getVertex();
let _MakerArr = [];
$('.tab-title > div').on('click', function(){
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';
$('.list-content.spot').html("");
}
else {
list = 'block';
spot = 'none';
$('.list-content.list > li').css('display', 'block');
}
$('#search-box').val("");
$('.list-content.list').css('display', list);
$('.list-content.spot').css('display', spot);
if (_MakerArr.length > 0) {
_MakerArr.forEach((obj)=>{
obj.setMap(null);
});
_MakerArr = [];
}
})
$('#search-box').on('keyup', function () {
const searchType = $('.tab-title > div.active').text();
const searchText = $(this).val();
if (searchType === '리스트') {
if (!$('.list-content.list > li').length) return;
for (let ii = 0; ii < $('.list-content.list > li').length; ii++) {
const li = $('.list-content.list > li').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 (_MakerArr.length > 0) {
_MakerArr.forEach((obj)=>{
obj.setMap(null);
});
_MakerArr = [];
}
$('.list-content.spot').html("");
$.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 daum.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 = new kakao.maps.LatLng(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(_Map);
_MakerArr.push(marker);
setMap.set(addr, obj);
str+= `
${obj.address_name}
`;
}
}
});
if (minX && minY && maxX && maxY) {
bounds.extend(new daum.maps.LatLng(minY, minX));
bounds.extend(new daum.maps.LatLng(maxY, maxX));
_Map.setBounds(bounds);
$('.list-content.spot').html(str);
getVertex();
}
}
});
}
})
});
function moveLocation(xCoordinate, yCoordinate, listIndex) {
const position = new kakao.maps.LatLng(yCoordinate, xCoordinate);
_Map.setCenter(position);
_Map.setLevel(3);
$('.list-content.spot > li.click').removeClass('click');
$('#spot-' +listIndex).addClass('click');
getVertex();
}
function getVertex() {
if (_TrafficArray.length > 0) {
_TrafficArray.forEach((obj) => {
obj.setVisibleMarker(false);
if (obj.infoWindow) {
obj.infoWindow.setMap(null);
}
})
_TrafficArray = [];
}
let level = _Map.getLevel();
const bounds = _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(),
}
console.log(level);
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 == trafficObj.ID) {
trafficObj.polyBackLine.setOptions({
strokeColor : 'black',
});
}
})
}
_TrafficArray.push(trafficObj);
})
}
})
}
function initFaicilityData() {
getDataAsync('/api/traffic/cctv-list', 'POST', null, null, (jsonData)=>{
if (jsonData && jsonData.length > 0) {
_CctvArray = receiveFacilityData(jsonData, _CctvArray, TbCCtvObj, _CctvListFlag, 'cctv');
}
}, null);
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;
})
_VmsArray = receiveFacilityData(jsonData, _VmsArray, TbVmsObj, _VmsListFlag, 'vms');
}
}, null);
getDataAsync('/api/traffic/incd-list', 'POST', null, null, (jsonData)=>{
if (jsonData && jsonData.length > 0) {
_IncidentArray = receiveFacilityData(jsonData, _IncidentArray, TbIncdObj, _IncidentListFlag, 'incident');
if (selectIncidentId) {
_IncidentArray.forEach((incd)=>{
if (incd.ID === selectIncidentId) {
incd.click();
}
})
}
}
}, null);
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);
}
})
_IntersectionArray = receiveFacilityData(data, _IntersectionArray, IntersectionObj, _IntersectionListFlag, 'intersection');
}
}, null);
if (_TrafficListFlag) {
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 += `
${obj.name}`
mobileStr += `
`
});
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 {
if (_AtrdArray.length > 0) {
_AtrdArray.forEach((atrd)=>{
atrd.close();
})
_AtrdData = [];
getVertex();
}
}
})
const listSection = $('.left-list-area .list-content.list');
listSection.empty();
listSection.html(listStr);
}
});
}
}
/**
* 간선도로 클릭 이벤트
* @param AupHillId 상행 ID
* @param AdownHillId 하행 ID
*/
function atrdClickEvent(AupHillId, AdownHillId) {
if (_AtrdArray.length > 0) {
_AtrdArray.forEach((atrd)=>{
atrd.close();
});
_AtrdArray = [];
}
_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 daum.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 == AupHillId || obj.atrd_id == AdownHillId) {
bounds.extend(new daum.maps.LatLng(obj.y_crdn_min, obj.x_crdn_min));
bounds.extend(new daum.maps.LatLng(obj.y_crdn_max, obj.x_crdn_max));
}
}
_Map.setBounds(bounds);
//전체 레벨이 다있는게 아니므로 로드 레벨은 재설정
let level = _Map.getLevel();
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 === AupHillId || atrd.atrd_id == AdownHillId) {
_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]);
_AtrdArray.push(upHillObj);
}
if (downHillArr[0]) {
const downHillObj = new TbAtrdObj(downHillArr[0]);
_AtrdArray.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 = _Map.getLevel();
let size = 48;
if (level >= 7) {
size = 24;
}
imageSize = new daum.maps.Size(size, size);
imageOption = {
offset: new daum.maps.Point(size/2, size),
};
let markerImage = new daum.maps.MarkerImage(imageSrc, imageSize, imageOption);
let markerPosition = new daum.maps.LatLng(lng, lat);
let atrdSideMarker = new daum.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 = new kakao.maps.LatLng(y_crdn, x_crdn);
linePath.push(coordinates);
}
let strokeWeight = 5;
let strokeWeightBack = 7;
const level = _Map.getLevel();
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 daum.maps.Polyline({
path: linePath, // 선을 구성하는 좌표배열 입니다
strokeWeight: strokeWeightBack, // 선의 두께 입니다
strokeColor: '#eeeeee', // 선의 색깔입니다
strokeOpacity: 1, // 선의 불투명도 입니다 1에서 0 사이의 값이며 0에 가까울수록 투명합니다
strokeStyle: 'solid', // 선의 스타일입니다
zIndex: 1
});
this.polyLine = new daum.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(_TrafficFlag);
daum.maps.event.addListener(this.polyLine, 'mouseover', function (event) {
this.setOptions({strokeColor: '#0000FF'});
const iwContent =
`
${_self.NAME}
${trafficObj.grad_nm}
${trafficObj.strt_nm_node} → ${trafficObj.end_nm_node}
소요시간 :
약 ${textFormat(trafficObj.trvl_hh)}분
속도 :
약 ${textFormat(trafficObj.sped)}km/h
`;
_self.infoWindow = new daum.maps.CustomOverlay({
map: _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 ? _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.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();
}
click() {
this.setVisibleMarker(true);
}
setVisibleMarker(isVisible) {
let visible = isVisible ? _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.obj = obj;
this.marker = null;
this.infoWindow = null;
this.isClick = false;
this.imgSrc = '/images/icon/cctv';
this.timer = null;
}
init() {
this.marker = markerInit(this, _CctvFlag);
}
setVisibleMarker(isVisible) {
this.marker.setVisible(isVisible);
}
click() {
const coordinates = new kakao.maps.LatLng(Number(this.Y_CRDN), Number(this.X_CRDN));
if (_SelectedObj != null) {
if (_SelectedObj === this) {
return;
}
_SelectedObj.close();
}
_SelectedObj = this;
const selectedLi = $('#cctv-' + this.ID);
selectedLi.addClass('click');
selectedLi.focus();
_Map.setCenter(coordinates);
const iwContent =
`
※ CCTV영상은 30초간 제공됩니다.
계속재생
`;
$('body').append($(iwContent));
this.infoWindow = $('.cctv-info-window');
let position = getInfoWidowPosition(this.infoWindow);
let top = position[0];
let left = position[1];
this.infoWindow.css({
top : top + 'px',
left : left + 'px',
position : 'absolute'
});
this.infoWindow.draggable({containment : 'body', handle: '.cctv-name-'+this.ID});
// this.infoWindow = new kakao.maps.CustomOverlay({position: coordinates, content: iwContent, zindex: 15, yAnchor: 1.1});
// this.infoWindow.setMap(_Map);
let video = videojs("video-" + this.ID, {
sources: [
{
src: this.obj.strm_http_addr,
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();
if (this.timer) {
clearTimeout(this.timer);
}
$('.content > div:nth-child(1)').append($('

'));
$('.content > div:nth-child(1)').css({
display : 'flex',
alignItems : 'center',
justifyContent : 'center',
});
video = null;
}
})
this.timer = setTimeout(()=>{
if (video) {
video.pause();
}
}, 30000);
let cctvObj = this;
$('.continue-play').on('click', ()=>{
if (cctvObj.timer) {
setTimeout(cctvObj.timer);
}
if (video) {
video.play();
cctvObj.timer = setTimeout(()=>{
video.pause();
}, 30000);
}
});
setMarkerImage(this, 2);
this.isClick = true;
moveToScroll(_CctvListFlag, _CctvArray, this.ID);
}
close() {
this.isClick = false;
_SelectedObj = null;
setMarkerImage(this, 1);
let oldPlayer = document.getElementById("video-" + this.ID);
let selectedLi = $("#cctv-" + this.ID);
if (selectedLi.hasClass('click')) {
selectedLi.removeClass('click');
}
if (_CctvListFlag) {
$('.mobile-select').val("-");
}
if (oldPlayer) {
videojs(oldPlayer).dispose();
}
if (this.infoWindow) {
this.infoWindow.remove();
// this.infoWindow.setMap(null);
this.infoWindow = null;
}
if (this.timer) {
clearTimeout(this.timer);
}
}
}
/**
* 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.isClick = false;
this.imgSrc = '/images/icon/vms';
this.timer = null;
}
init() {
this.marker = markerInit(this, _VmsFlag);
}
setVisibleMarker(isVisible) {
this.marker.setVisible(isVisible);
}
click() {
if (_SelectedObj != null) {
if (_SelectedObj === this) {
return;
}
_SelectedObj.close();
}
_SelectedObj = this;
const selectedLi = $('#vms-' + this.ID);
selectedLi.addClass('click');
selectedLi.focus();
const coordinates = new kakao.maps.LatLng(Number(this.Y_CRDN), Number(this.X_CRDN));
_Map.setCenter(coordinates);
let 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 =
`
`;
if (msg && msg.length > 0) {
for (let idx in msg) {
let msgObj = msg[idx];
let className = '';
if (idx === "0") {
className = 'active'
}
iwContent += `

`;
phaseArray.push(msgObj.phase);
}
}
else {
iwContent += '표출 이미지 데이터가 없습니다.';
}
iwContent += `
`;
// this.infoWindow = new kakao.maps.CustomOverlay({position: coordinates, content: iwContent, zindex: 15, yAnchor: 1.2});
$('body').append($(iwContent));
this.infoWindow = $('.vms-info-window');
let position = getInfoWidowPosition(this.infoWindow);
let top = position[0];
let left = position[1];
this.infoWindow.css({
top : top + 'px',
left : left + 'px',
position: 'absolute',
zIndex : '999',
})
this.infoWindow.draggable({containment : 'body', handle: '.vms-name-'+this.ID});
// this.infoWindow.setMap(_Map);
setMarkerImage(this, 2)
this.isClick = true;
moveToScroll(_VmsListFlag, _VmsArray, this.ID);
let cnt = 1;
this.timer = setInterval(()=>{
if (phaseArray.length > 0) {
if (cnt === phaseArray.length) {
cnt = 0;
}
const activeImage = $('.vms-info-window .content img.active');
if (activeImage[0]) {
activeImage.removeClass('active');
}
$("#phase-" + phaseArray[cnt]).addClass('active');
cnt++;
}
}, 4000);
}
close() {
this.isClick = false;
_SelectedObj = null;
setMarkerImage(this, 1);
let selectedLi = $("#vms-" + this.ID);
if (selectedLi.hasClass('click')) {
selectedLi.removeClass('click');
}
if (_VmsListFlag) {
$('.mobile-select').val("-");
}
if (this.infoWindow) {
// this.infoWindow.setMap(null);
this.infoWindow.remove();
this.infoWindow = null;
}
if (this.timer) {
clearTimeout(this.timer);
}
}
}
/**
* 돌발정보 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';
}
init() {
this.marker = markerInit(this, _IncidentFlag);
}
setVisibleMarker(isVisible) {
this.marker.setVisible(isVisible);
}
click() {
if (_SelectedObj != null) {
if (_SelectedObj === this) {
return;
}
_SelectedObj.close();
}
_SelectedObj = this;
const selectedLi = $('#incident-' + this.ID);
selectedLi.addClass('click');
selectedLi.focus();
const coordinates = new kakao.maps.LatLng(Number(this.Y_CRDN), Number(this.X_CRDN));
_Map.setCenter(coordinates);
let iwContent =
`
위치 : ${this.obj.road_nm}
설명 : ${this.obj.incd_expl}
기간 : ${this.obj.incd_strt_dt} ~ ${this.obj.incd_end_prar_dt}
`;
// this.infoWindow = new kakao.maps.CustomOverlay({position: coordinates, content: iwContent, zindex: 15, yAnchor: 1.2});
// this.infoWindow.setMap(_Map);
$('body').append($(iwContent));
this.infoWindow = $('.incident-info-window');
let position = getInfoWidowPosition(this.infoWindow);
let top = position[0];
let left = position[1];
this.infoWindow.css({
top : top + 'px',
left : left + 'px',
position: 'absolute',
zIndex : '999',
})
this.infoWindow.draggable({containment : 'body', handle: '.incident-name-'+ this.ID});
setMarkerImage(this, 2);
this.isClick = true;
moveToScroll(_IncidentListFlag, _IncidentArray, this.ID);
}
close() {
this.isClick = false;
_SelectedObj = null;
setMarkerImage(this, 1)
let selectedLi = $("#incident-" + this.ID);
if (selectedLi.hasClass('click')) {
selectedLi.removeClass('click');
}
if (_IncidentListFlag) {
$('.mobile-select').val("-");
}
if (this.infoWindow) {
// this.infoWindow.setMap(null);
this.infoWindow.remove();
this.infoWindow = null;
}
}
}
/**
* 스마트 교차로 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 = [];
}
init() {
let imageSrc = this.imgSrc + '.png', // 마커이미지의 주소입니다
size = _size[_Map.getLevel()],
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 = new kakao.maps.LatLng(this.Y_CRDN, this.X_CRDN); // 마커가 표시될 위치입니다
this.marker = new kakao.maps.Marker(
{map: _Map, position: markerPosition, image: markerImage, zindex: 10, clickable: true, title : this.NAME}
);
const level = _Map.getLevel();
const isVisible = (level > 2 && _IntersectionFlag);
this.marker.setVisible(isVisible);
let _self = this;
kakao.maps.event.addListener(this.marker, 'click', ()=> _self.click());
}
setVisibleMarker(isVisible) {
if (_Map.getLevel() <= 2) isVisible = false;
this.marker.setVisible(isVisible);
}
click() {
if (_SelectedObj != null) {
// if (_SelectedObj === this) {
// return;
// }
_SelectedObj.close();
}
_SelectedObj = this;
const selectedLi = $('#intersection-' + this.ID);
selectedLi.addClass('click');
selectedLi.focus();
const coordinates = new kakao.maps.LatLng(Number(this.Y_CRDN), Number(this.X_CRDN));
_Map.setCenter(coordinates);
this.isClick = true;
moveToScroll(_IntersectionListFlag, _IntersectionArray, this.ID);
_Map.setLevel(2);
}
close() {
this.isClick = false;
_SelectedObj = null;
if (_IntersectionListFlag) {
$('.mobile-select').val("-");
}
let selectedLi = $("#intersection-" + this.ID);
if (selectedLi.hasClass('click')) {
selectedLi.removeClass('click');
}
}
}
/**
* 스마트교차로 카메라 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.obj = obj;
this.marker = null;
this.infoWindow = null;
this.isClick = false;
this.timer = null;
this.polyline = null;
}
init() {
this.marker = intersectionCameraMarkerInit(this);
}
setVisibleMarker(isVisible) {
const visible = isVisible && _Map.getLevel() <= 2 ? _Map : null;
this.marker.setMap(visible);
this.polyline.setMap(visible);
}
click() {
const coordinates = new kakao.maps.LatLng(Number(this.Y_CRDN), Number(this.X_CRDN));
if (_SelectedObj != null) {
if (_SelectedObj === this) {
return;
}
_SelectedObj.close();
}
_SelectedObj = this;
_Map.setCenter(coordinates);
const iwContent =
`
※ CCTV영상은 30초간 제공됩니다.
계속재생
`;
$('body').append($(iwContent));
this.infoWindow = $('.cctv-info-window');
// const headerH = $('header').height();
// const wrapH = $('.trafficWrap').innerHeight();
// let top = headerH + (wrapH/2) - this.infoWindow.innerHeight() + 10;
// let left = (window.innerWidth / 2) - (this.infoWindow.width() / 2);
let position = getInfoWidowPosition(this.infoWindow);
let top = position[0];
let left = position[1];
this.infoWindow.css({
top : top + 'px',
left : left + 'px',
position: 'absolute',
zIndex : '999',
});
this.infoWindow.draggable({containment : 'body', handle : '.ixr-name-' + this.ID});
// this.infoWindow = new kakao.maps.CustomOverlay({
// position: coordinates,
// content: iwContent,
// zindex: 15,
// yAnchor: 1.1
// });
// this.infoWindow.setMap(_Map);
let video = videojs("video-" + this.ID, {
sources: [
{
src: this.obj.hmpg_cmra_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();
$('.content > div:nth-child(1)').append($('

'));
$('.content > div:nth-child(1)').css({
display : 'flex',
alignItems : 'center',
justifyContent : 'center',
});
video = null;
}
});
this.timer = setTimeout(() => {
if (video) {
video.pause();
}
}, 30000);
let _self = this;
$('.continue-play').on('click', () => {
if (_self.timer) {
setTimeout(_self.timer);
}
if (video) {
video.play();
_self.timer = setTimeout(() => {
video.pause();
}, 30000);
}
});
this.isClick = true;
$('.close-window').on('click', (event)=> {
event.preventDefault();
this.close();
});
}
close() {
this.isClick = false;
_SelectedObj = null;
let oldPlayer = document.getElementById("video-" + this.ID);
if (oldPlayer) {
videojs(oldPlayer).dispose();
}
if (this.infoWindow) {
// this.infoWindow.setMap(null);
this.infoWindow.remove();
this.infoWindow = null;
}
if (this.timer) {
clearTimeout(this.timer);
}
}
}
/**
* 인포윈도우 이벤트
* @param type 시설물 유형
* @param id 요소 ID
* @param event 이벤트 종류 (click, close)
*/
function infoWindowEvent(type, id, event) {
window.event.preventDefault();
let array = [];
switch (type) {
case 'cctv':
array = _CctvArray;
break;
case 'vms':
array = _VmsArray;
break;
case 'incident':
array = _IncidentArray;
break;
case 'intersection':
array = _IntersectionArray;
break;
}
if (array.length > 0) {
let idx = array.findIndex(markerObj => markerObj.ID == id);
if (event === 'click') {
array[idx].click();
if (_TrafficFlag) {
getVertex();
}
}
else if (event === 'close') {
array[idx].close();
}
else {}
}
}
/**
* 범례 클릭 시설물 아이콘 보이기 / 감추기
* @param array 시설물 리스트
* @param isShow 보이기/감추기(true / false)
* @param icon 범례 아이콘
* @param target 범례 요소
*/
function onOffFacility(array, isShow, icon, target, subArray) {
if (isShow === false) {
icon.removeClass('active');
target.removeClass('active');
array.forEach((obj)=>{
obj.setVisibleMarker(false);
if (obj.isClick === true) {
obj.close();
}
});
if (subArray) {
subArray.forEach((obj)=>{
obj.setVisibleMarker(false);
if (obj.isClick === true) {
obj.close();
}
})
}
}
else {
icon.addClass('active')
target.addClass('active');
array.forEach((obj)=>{
obj.setVisibleMarker(true);
});
if (subArray) {
subArray.forEach((obj)=>{
obj.setVisibleMarker(true);
})
}
}
}
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 markerInit(obj, flag) {
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 = new kakao.maps.LatLng(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}
);
marker.setVisible(flag);
kakao.maps.event.addListener(marker, 'mouseover', function () {
if (!obj.isClick) {
setMarkerImage(obj, 2);
}
});
kakao.maps.event.addListener(marker, 'mouseout', function () {
if (!obj.isClick) {
setMarkerImage(obj, 1)
}
});
kakao.maps.event.addListener(marker, 'click', ()=> obj.click());
return marker;
}
/**
* 스마트 교차로 카메라 마커 초기화
* @param obj 스마트 교차로 카메라 객체
* @returns {kakao.maps.Marker}
*/
function intersectionCameraMarkerInit(obj) {
const position = new kakao.maps.LatLng(obj.Y_CRDN, obj.X_CRDN);
const content = $('
');
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 daum.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: [
new kakao.maps.LatLng(linePath1[1], linePath1[0]),
new kakao.maps.LatLng(linePath2[1], linePath2[0]),
],
strokeWeight: 10,
strokeColor: color[obj.obj.acrd_los],
strokeOpacity: 1,
strokeStyle: 'solid',
endArrow: true,
name : obj.NAME,
});
if (_Map.getLevel() <= 2 && _IntersectionFlag){
marker.setMap(_Map);
obj.polyline.setMap(_Map);
}
content.on('click', ()=> {
obj.click();
});
return marker;
}
/**
* 시설물 이미지 유형 변경 이벤트
* @param obj 시설물 객체
* @param type 시설물 이미지 유형
*/
function setMarkerImage(obj, type) {
const size = _size[_Map.getLevel()];
const point = size/2;
const imageSize = new kakao.maps.Size(size, size);
const imageSrc = obj.imgSrc + type +'.png';
const imageOption = {
offset: new kakao.maps.Point(point, point),
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, array, facilityClass, listFlag, type) {
if (array.length > 0) {
array.forEach((obj)=>{
obj.marker.setVisible(false);
})
}
if (type === 'intersection') {
if (_IntersectionCameraArray.length > 0) {
_IntersectionCameraArray.forEach((obj) => {
obj.marker.setMap(null);
obj.polyline.setMap(null);
})
}
}
array = [];
let listStr = "";
let mobileStr = "";
jsonData.forEach((obj)=>{
const markerObj = new facilityClass(obj);
if (type === 'intersection') {
if (obj.detail && obj.detail.length > 0) {
obj.detail.forEach((cameraObj)=>{
const camera = new IntersectionCameraObj(cameraObj);
camera.init();
_IntersectionCameraArray.push(camera);
})
}
}
markerObj.init();
listStr += `
${markerObj.NAME}`
mobileStr += ``;
array.push(markerObj);
});
if (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');
}
})
}
return array;
}
//https://map.kakao.com/link/search/카카오
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[_Map.getLevel()];
let top = mapTop + mapHalfH - height - iconH;
return [top, left];
}