Browse Source

update 2024-07-15

junggilpark 1 year ago
parent
commit
14a9b4614d

+ 7 - 1
pom.xml

@@ -15,7 +15,12 @@
     <description>Intelligent Traffic System Web Server</description>
 
     <packaging>war</packaging>
-
+    <repositories>
+        <repository>
+            <id>local-repository</id>
+            <url>file:///C:/java/repository</url>
+        </repository>
+    </repositories>
     <properties>
         <java.version>1.8</java.version>
         <swagger.version>2.9.2</swagger.version>
@@ -275,6 +280,7 @@
     </dependencies>
 
     <build>
+        <defaultGoal>install</defaultGoal>
         <plugins>
             <plugin>
                 <groupId>org.springframework.boot</groupId>

+ 0 - 1
src/main/java/com/its/web/config/DatabaseItcsConfig.java

@@ -49,7 +49,6 @@ public class DatabaseItcsConfig {
     @Bean(name="itcsSqlSessionFactory")
     public SqlSessionFactory sqlSessionFactoryBean(
             @Autowired @Qualifier("itcsDataSource") DataSource dataSource, ApplicationContext applicationContext) {
-        log.info("dataSource : {}", dataSource);
         log.info("mapperLocations: {}", this.mapperLocations);
         SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
         factoryBean.setDataSource(dataSource);

+ 8 - 0
src/main/java/com/its/web/controller/traffic/TrafficController.java

@@ -93,4 +93,12 @@ public class TrafficController {
     @ResponseBody
     public List<TbPrkPlceDto> findParkingList() {return this.service.findParkingList();}
 
+    @ApiOperation(value = "09.실시간 주차면수 조회")
+    @PostMapping(value = "/parking-live-info", produces = {"application/json; charset=utf-8"})
+    @ResponseBody
+    public TbPrkPlceRtDto findPrkPlceRtInfo(@ApiParam(value = "주차장관리번호", example = "1000", required = true)
+                                            @RequestParam("nmbr") Long nmbr) {
+        return this.service.findPrkPlceRtInfo(nmbr);
+    }
+
 }

+ 8 - 0
src/main/java/com/its/web/dto/traffic/TbPrkPlceDto.java

@@ -49,6 +49,10 @@ public class TbPrkPlceDto {
     @JsonProperty("parking_addr")
     private String parkingAddr; //N VARCHAR(200)
 
+    @ApiModelProperty("주차장 총주차면수")
+    @JsonProperty("parking_oper_time")
+    private String parkingOperTime; //N VARCHAR(11)
+
     @ApiModelProperty("주차장 총주차면수")
     @JsonProperty("parking_num")
     private Integer parkingNum; //N NUMBER(4)
@@ -61,6 +65,10 @@ public class TbPrkPlceDto {
     @JsonProperty("y_crdn")
     private Double yCrdn; //N NUMBER(10,8)
 
+    @ApiModelProperty("실시간 주차장 관리번호")
+    @JsonProperty("prk_plce_nmbr")
+    private Long prkPlceNmbr; //N NUMBER(10)
+
     @ApiModelProperty("비고")
     @JsonProperty("rmrk")
     private String rmrk; //N VARCHAR(256)

+ 47 - 0
src/main/java/com/its/web/dto/traffic/TbPrkPlceRtDto.java

@@ -0,0 +1,47 @@
+package com.its.web.dto.traffic;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@ApiModel("TbPrkPlceRtDto(TB_PRK_PLCE_RT 테이블 DTO)")
+public class TbPrkPlceRtDto {
+
+    @ApiModelProperty("주차장 ID")
+    @JsonProperty("prk_plce_nmbr")
+    private Long prkPlceNmbr; //Number(11)
+
+    @ApiModelProperty("실시간 주차데이터 수집 시간")
+    @JsonProperty("data_colct_time")
+    private String dataColctTime;
+
+    @ApiModelProperty("주차장 통신 상태 코드(0: 정상, 1: 비정상)")
+    @JsonProperty("stts_cd")
+    private String sttsCd;
+
+    @ApiModelProperty("주차장 상태코드(0:여유(점유 50%미만), 1:보통(점유 70%미만), 2:혼잡(점유90% 미만), 3:만차(점유90%초과))")
+    @JsonProperty("parking_cgs_sttus")
+    private Integer parkingCgsSttus;
+
+    @ApiModelProperty("주차장의 총 주차 구획 수, 150 (면)")
+    @JsonProperty("prk_cmprt_co")
+    private Long prkCmprtCo;
+
+    @ApiModelProperty("주차장의 총 잔여 주차 구획 수, 150 (면)")
+    @JsonProperty("remndr_prk_cmprt_co")
+    private Long remndrPrkCmprtCo;
+
+    @ApiModelProperty("현재 주차 구획 수, 150 (면)")
+    @JsonProperty("prk_parking_co")
+    private Long prkParkingCo;
+
+    @ApiModelProperty("특이사항, 기타 주차장 실시간 정보 관련")
+    @JsonProperty("partclr_matter")
+    private String partclrMatter;
+}

+ 2 - 0
src/main/java/com/its/web/mapper/its/traffic/TrafficMapper.java

@@ -44,4 +44,6 @@ public interface TrafficMapper {
     List<TbPrkPlceDto> findParkingList();
 
     int updateCctvHmpgUseYn(HmpgUseYnDto param);
+
+    TbPrkPlceRtDto findPrkPlceRtInfo(Long nmbr);
 }

+ 5 - 0
src/main/java/com/its/web/service/traffic/TrafficService.java

@@ -262,4 +262,9 @@ public class TrafficService {
     public List<TbPrkPlceDto> findParkingList() {
         return this.mapper.findParkingList();
     }
+
+    public TbPrkPlceRtDto findPrkPlceRtInfo(Long nmbr) {
+        log.info("findPrkPlceRtInfo nmbr : {}",nmbr);
+        return this.mapper.findPrkPlceRtInfo(nmbr);
+    }
 }

+ 34 - 15
src/main/resources/mybatis/mapper/its/traffic/TrafficMapper.xml

@@ -628,20 +628,39 @@
 
     <select id="findParkingList" resultType="com.its.web.dto.traffic.TbPrkPlceDto">
         SELECT
-            parking_id,
-            parking_nm,
-            parking_kind,
-            DECODE(parking_kind, '0', '공영', '1', '사립', '-')AS parking_kind_desc,
-            parking_type,
-            DECODE(parking_type, '0', '노상', '1', '노외', '2','부설', '-') AS parking_type_desc,
-            parking_fee_type,
-            DECODE(parking_fee_type, '0', '무료', '1', '유료', '-') AS parking_fee_type_desc,
-            parking_addr,
-            parking_num,
-            x_crdn,
-            y_crdn,
-            rmrk
-        FROM TB_PARKING_INFR
-        ORDER BY parking_nm ASC
+            A.parking_id,
+            A.parking_nm,
+            A.parking_kind,
+            DECODE(A.parking_kind, '0', '공영', '1', '사립', '-')AS parking_kind_desc,
+            A.parking_type,
+            DECODE(A.parking_type, '0', '노상', '1', '노외', '2','부설', '-') AS parking_type_desc,
+            A.parking_fee_type,
+            DECODE(A.parking_fee_type, '0', '무료', '1', '유료', '-') AS parking_fee_type_desc,
+            A.parking_addr,
+            A.parking_oper_time,
+            A.parking_num,
+            A.x_crdn,
+            A.y_crdn,
+            B.prk_plce_nmbr AS prk_plce_nmbr,
+            A.rmrk
+          FROM TB_PARKING_INFR A
+          LEFT OUTER JOIN TB_PRK_PLCE B ON A.parking_id = B.prk_plce_manage_no
+         ORDER BY parking_nm ASC;
+    </select>
+
+    <select id="findPrkPlceRtInfo" resultType="com.its.web.dto.traffic.TbPrkPlceRtDto">
+        SELECT
+            prk_plce_nmbr,
+            data_colct_time,
+            stts_cd,
+            parking_cgs_sttus,
+            prk_cmprt_co,
+            remndr_prk_cmprt_co,
+            prk_parking_co,
+            partclr_matter
+        FROM
+            TB_PRK_PLCE_RT
+        WHERE
+            prk_plce_nmbr = #{nmbr}
     </select>
 </mapper>

+ 104 - 5
src/main/resources/static/css/traffic.css

@@ -101,6 +101,43 @@ ul, li {
     width: calc(100% - 100px);
 }
 
+.arrow.LTC1{
+    background-color: #2fba2c;
+}
+.arrow.LTC1::after {
+    border-top-color: #2fba2c !important;
+}
+.arrow.LTC1::before {
+    border-bottom-color: #2fba2c !important;
+}
+.arrow.LTC2{
+    background-color : #ffc500;
+}
+.arrow.LTC2::after{
+    border-top-color: #ffc500 !important;
+}
+.arrow.LTC2::before{
+    border-bottom-color: #ffc500 !important;
+}
+.arrow.LTC3{
+    background-color : #ee0000;
+}
+.arrow.LTC3::before {
+    border-bottom-color: #ee0000 !important;
+}
+.arrow.LTC3::after{
+    border-top-color: #ee0000 !important;
+}
+.arrow.LTC0{
+    background-color : #888888;
+}
+.arrow.LTC0::before {
+    border-bottom-color: #888888 !important;
+}
+.arrow.LTC0::after{
+    border-top-color: #888888 !important;
+
+}
 .tab-title {
     padding: 10px;
     height: 35px;
@@ -113,7 +150,47 @@ ul, li {
     align-items: center;
     justify-content: flex-end;
 }
-
+.down{
+    width: 16px;
+    height: calc(100% - 5px);
+    margin-right: 10px;
+    margin-bottom: 5px;
+    position: relative;
+}
+.down.arrow::after{
+    position: absolute;
+    border-top: 13px solid ;
+    border-left: 13px solid transparent;
+    border-right: 13px solid transparent;
+    width: 0px;
+    height: 0px;
+    bottom: -9px;
+    left: -5px;
+    /*width: 26px;*/
+    /*height: 16px;*/
+    content: "";
+    z-index: 3;
+}
+.up {
+    width: 16px;
+    height: calc(100% - 5px);
+    margin-right: 10px;
+    margin-top: 5px;
+    position: relative;
+}
+.up.arrow::before {
+    position: absolute;
+    top: -8px;
+    left: -5px;
+    border-bottom: 13px solid ;
+    border-left: 13px solid transparent;
+    border-right: 13px solid transparent;
+    /*width: 26px;*/
+    /*height: 16px;*/
+    /*transform: rotate(180deg);*/
+    content: "";
+    z-index: 3;
+}
 .tab-title > div {
     padding: 5px;
     border: 1px solid #c3c1c1;
@@ -177,7 +254,27 @@ ul, li {
 .left-list-area .list-tab > li{
     color: #a59d9d;
 }
-
+.left-list-area .list-content > ul > li .traffic-list {
+    display: flex; padding: 10px; border-bottom: 1px solid #c3c1c1; cursor: pointer;
+}
+.left-list-area .list-content > ul > li {
+    padding: 0 15px;
+    border-bottom: 1px solid #c3c1c1;
+    font-size: 13px;
+}
+.left-list-area .list-content > ul > li > div {
+    display: flex;
+    gap: 5px;
+}
+.left-list-area .list-content > ul > li > div > div {
+    width: 50%;
+}
+.left-list-area .list-content > ul {
+    display: none;
+}
+.left-list-area .list-content > ul.on {
+    display: block;
+}
 .location-box .list-content > li:hover,
 .left-list-area .list-content > li:hover,
 .left-list-area .list-tab > li:hover {
@@ -460,7 +557,7 @@ ul, li {
 }
 .parking-info-window{
     width: 300px;
-    height: 240px;
+    /*height: 240px;*/
     background-color: white;
     box-shadow: 2px 2px 2px 2px #2b333f;
     z-index: 999;
@@ -494,7 +591,7 @@ ul, li {
 }
 .parking-info-window > .content .row > div:nth-child(1){
     display: inline-block;
-    width: 80px;
+    width: 90px;
     height: 30px;
     line-height: 30px;
     border-radius: 6px;
@@ -502,6 +599,7 @@ ul, li {
     text-align: center;
     color: #fff;
     margin: 0 10px;
+    font-size: 14px;
 }
 .parking-info-window > .content .row > div:nth-child(2) {
     width: calc(100% - 110px);
@@ -667,7 +765,8 @@ ul, li {
     filter: brightness(1.1);
 }
 
-.trafficPop{position:absolute; bottom:-50px; margin-left:45px;left:50%; min-width:250px; width: auto; height:80px; padding:10px 10px 10px 7px; border:1px solid #a0a0a0;background:#fff;box-shadow:5px 5px 5px grey}
+/*.trafficPop{position:absolute; bottom:-50px; margin-left:45px;left:50%; min-width:250px; width: auto; height:80px; padding:10px 10px 10px 7px; border:1px solid #a0a0a0;background:#fff;box-shadow:5px 5px 5px grey}*/
+.trafficPop{min-width:250px; width: auto; height:80px; padding:10px 10px 10px 7px; border:1px solid #a0a0a0;background:#fff;box-shadow:5px 5px 5px grey}
 .trafficPop .close-btn{position:absolute; top:13px; right:14px;}
 .traffic-speed{overflow:hidden; padding-bottom:6px; margin-bottom:5px; border-bottom: 3px solid; color: black;}
 .traffic-speed.LTC0{border-color: #888888;}

BIN
src/main/resources/static/images/icon/parking1-2.png


BIN
src/main/resources/static/images/icon/parking2-2.png


+ 186 - 25
src/main/resources/static/js/traffic/traffic.js

@@ -20,7 +20,7 @@ g_color.set('LTC3', '#ee0000;');
 
 const CCTV_DISPLAY_TIME = 30 * 1000; // 영상 표출 시간
 const VMS_DISPLAY_TIME  = 4 * 1000; // VMS 이미지 표출 시간
-
+const _TrafficListMap = new Map();
 let _MapHandler; //카카오 맵 핸들러
 let _Level = 6; //현재 줌레벨
 let _MarkerHandle;
@@ -192,7 +192,6 @@ $(()=>{
         if (markerArr.length) {
             showIdArr = markerArr.map((item)=>{
                 if (item.ADDR && item.ADDR.includes(searchText)) {
-                    console.log(item);
                     if (type === 'intersectionCamera') {
                         return 'intersection-' + item.prop.ixr_id;
                     }
@@ -392,8 +391,8 @@ function getAtrd() {
     getDataAsync("/api/traffic/atrd-vertex-all", "POST", null, null, (jsonData)=>{
         if (jsonData && jsonData.length > 0) {
             _AtrdMap = new Map();
-            console.log(jsonData);
             jsonData.forEach((obj)=>{
+                _TrafficListMap.set(obj.level, obj.list);
                 obj.list.forEach((atrd)=>{
                     const key = atrd.atrd_id +'_' + atrd.drct_cd +'_' + obj.level;
                     let atrdArr = _AtrdMap.get(key);
@@ -408,6 +407,8 @@ function getAtrd() {
                     _AtrdMap.get(key).push(atrd);
                 });
             });
+
+            getVertex();
         }
     }, null);
 
@@ -433,7 +434,9 @@ function getAtrd() {
                     const upHillId   = upHill.atrd_id;
                     const downHillId = downHill.atrd_id;
 
-                    listStr += `<li id="atrd_${upHillId}_${downHillId}" onclick="atrdClickEvent('${upHillId}', '${downHillId}')">${key}</li>`
+                    listStr += `<li id="atrd_${upHillId}_${downHillId}" onclick="atrdClickEvent('${upHillId}', '${downHillId}')">
+                                    ${key}
+                                </li><ul id="${upHillId}_${downHillId}"></ul>`
                     mobileStr += `<option value="${upHillId}_${downHillId}">${key}</option>`
                 }
             }
@@ -455,7 +458,7 @@ function getAtrd() {
                             }
                         })
                         _MarkerHandle.selectedAtrd = [];
-                        getVertex();
+                        // getVertex();
                     }
                 }
             })
@@ -468,25 +471,12 @@ function getAtrd() {
         listSection.html(listStr);
     });
 
-    getVertex();
 }
 
 /**
  * 소통정보 가져오기
  */
 function getVertex() {
-    let markerArr = _MarkerHandle.findMarkerArr('traffic');
-    if (markerArr.length > 0) {
-        markerArr.forEach((obj) => {
-            obj.setVisibleMarker(false);
-            if (obj.infoWindow) {
-                obj.infoWindow.setMap(null);
-            }
-        })
-
-        _MarkerHandle.findMarkerArr('traffic').markers = [];
-    }
-
     let level = _MapHandler.getLevel();
     const bounds = _MapHandler.getBounds();
     const swLatLng = bounds.getSouthWest();
@@ -500,10 +490,25 @@ function getVertex() {
     }
 
     getDataAsync('/api/traffic/vertex-list', 'POST', data, null, (jsonData)=>{
+        let markerArr = _MarkerHandle.findMarkerArr('traffic');
+        if (markerArr.length > 0) {
+            markerArr.forEach((obj) => {
+                obj.setVisibleMarker(false);
+                if (obj.infoWindow) {
+                    obj.infoWindow.setMap(null);
+                }
+            })
+
+            _MarkerHandle.findMarkerArr('traffic').markers = [];
+        }
         if (jsonData && jsonData.length > 0) {
             let upHill = null;
             let dowHill = null;
+            let upHillId = null;
+            let downHillId = null;
             let roadIdArr = [];
+            let uRoadIdArr = [];
+            let dRoadIdArr = [];
             if (_MarkerHandle.selectedAtrd.length > 0 && _MarkerHandle.isDraw('traffic')) {
                 const selectedAtrd = _MarkerHandle.selectedAtrd;
                 upHill = _MarkerHandle.findMarkerObj('atrd', selectedAtrd[0]);
@@ -515,26 +520,152 @@ function getVertex() {
                 const upHillArr = _AtrdMap.get(selectedAtrd[0]);
                 const downHillArr = _AtrdMap.get(selectedAtrd[1]);
                 const roadArr = [...upHillArr, ...downHillArr];
+                upHillId = selectedAtrd[0].substring(0, selectedAtrd[0].indexOf('_'));
+                downHillId = selectedAtrd[1].substring(0, selectedAtrd[1].indexOf('_'));
                 roadArr.forEach((obj)=>{
+                    if (obj.atrd_id === upHillId) {
+                        uRoadIdArr.push(obj);
+                    }
+                    else {
+                        dRoadIdArr.push(obj);
+                    }
                     roadIdArr.push(obj.road_id.toString());
                 });
+
             }
+
+            const $ul = $(`#${upHillId}_${downHillId}`);
+
+            const trafficArr = [];
             jsonData.forEach((obj)=>{
                 const trafficObj = new TrafficObj(obj);
                 if (roadIdArr.length > 0) {
-                    if (roadIdArr.includes(trafficObj.ID.toString())) {
+                   if (roadIdArr.includes(trafficObj.ID.toString())) {
                         trafficObj.polyBackLine.setOptions({
                             strokeColor : 'black',
                         });
+                        trafficArr.push(obj);
                     }
                 }
                 _MarkerHandle.markerMaps.get('traffic').markers.push(trafficObj);
             })
+            // if ($ul[0]) {
+            //     $ul.empty();
+            //     let uRoadObjArr = [];
+            //     let dRoadObjArr = [];
+            //     let upStr = '';
+            //     let downStr = '';
+            //     for (let ii= uRoadIdArr.length - 1; ii >= 0; ii--) {
+            //         const idx = trafficArr.findIndex(obj=> obj.roadway_id === uRoadIdArr[ii].road_id.toString());
+            //         if (idx >= 0) {
+            //             uRoadObjArr.push(trafficArr[idx])
+            //         }
+            //     }
+            //
+            //     uRoadObjArr.forEach((obj, idx)=>{
+            //         const {cmtr_grad_cd, strt_nm_node, end_nm_node, sped, trvl_hh, roadway_id} = obj;
+            //         const isEnd = (uRoadObjArr.length - 1) === idx;
+            //         upStr +=`<div class="traffic-list" onmouseover="showSelectLine('${roadway_id}', true, ${isEnd})" onmouseleave="showSelectLine('${roadway_id}', false, ${isEnd})">
+            //                     <div>
+            //                         <div class="up arrow ${cmtr_grad_cd}"></div>
+            //                     </div>
+            //                     <div>
+            //                         <div>${end_nm_node}</div>
+            //                         <div>${sped}km/h 약 ${trvl_hh}분</div>
+            //                     </div>
+            //                 </div>`
+            //         if (isEnd) {
+            //             upStr+= `<div style="margin-left: 35px; padding-top: 10px; padding-bottom: 10px;">${strt_nm_node}</div>`;
+            //         }
+            //     })
+            //
+            //     for (let ii= 0; ii < dRoadIdArr.length; ii++) {
+            //         const idx = trafficArr.findIndex(obj=> obj.roadway_id === dRoadIdArr[ii].road_id.toString());
+            //         if (idx >= 0) {
+            //             dRoadObjArr.push(trafficArr[idx]);
+            //         }
+            //     }
+            //
+            //     dRoadObjArr.forEach((obj, idx)=>{
+            //         const {sped, trvl_hh, cmtr_grad_cd, strt_nm_node, end_nm_node, roadway_id} = obj;
+            //         let isStart = idx === 0;
+            //         downStr +=`<div class="traffic-list" onmouseover="showSelectLine('${roadway_id}', true, ${isStart})" onmouseleave="showSelectLine('${roadway_id}', false, ${isStart})">
+            //                         <div>
+            //                             <div class="down arrow ${cmtr_grad_cd}"></div>
+            //                         </div>
+            //                         <div>
+            //                             <div>${strt_nm_node}</div>
+            //                             <div>${sped}km/h 약 ${trvl_hh}분</div>
+            //                         </div>
+            //                     </div>`
+            //         if (dRoadObjArr.length - 1 === idx) {
+            //             downStr += `<div style="margin-left: 35px; padding-top: 10px; padding-bottom: 10px;">${end_nm_node}</div>`
+            //         }
+            //     })
+            //     let str = `<li>
+            //                     <div>
+            //                             <div>
+            //                                 ${upStr}
+            //                             </div>
+            //                             <div>
+            //                                 ${downStr}
+            //                             </div>
+            //                     </div>
+            //                 </li>`;
+            //
+            //     $ul.html(str);
+            // }
         }
     });
 }
 
 
+function showSelectLine(id, isShow, isEnd) {
+    const trafficObj = _MarkerHandle.findMarkerObj('traffic', id);
+    if (trafficObj.infoWindow) trafficObj.infoWindow.setMap(null);
+    if (isShow) {
+        const xCoordinateArr = trafficObj.obj.x_crdn.split(',');
+        const yCoordinateArr = trafficObj.obj.y_crdn.split(',');
+        let position    = getKakaoPosition(yCoordinateArr[0], xCoordinateArr[0]);
+        if (isEnd) {
+            console.log(isEnd);
+            const lastYIdx = yCoordinateArr.length - 1;
+            const lastXIdx = xCoordinateArr.length - 1;
+            position = getKakaoPosition(yCoordinateArr[lastYIdx], xCoordinateArr[lastXIdx])
+        }
+        const {cmtr_grad_cd, grad_nm, strt_nm_node, end_nm_node, trvl_hh, sped} = trafficObj.obj;
+        const iwContent =
+            `<div class="trafficPop">
+                            <div class="traffic-speed ${cmtr_grad_cd}">
+                                <span class="traffic-name">${trafficObj.NAME}</span>
+                                <span class="traffic-speed-info border-back ${cmtr_grad_cd}">${grad_nm}</span>
+                            </div>
+                            <div class="traffic-info">
+                                <span>${strt_nm_node} → ${end_nm_node}</span>
+                                <br>
+                                <span>소요시간 : </span>
+                                <span class="${cmtr_grad_cd}">약 ${textFormat(trvl_hh)}분 </span>
+                                <span>&nbsp; 속도 : </span>
+                                <span class="${cmtr_grad_cd}">약 ${textFormat(sped)}km/h</span>
+                            </div>
+                         </div>`;
+        trafficObj.infoWindow = new kakao.maps.CustomOverlay({
+            clickable: true,
+            position: position,
+            content: iwContent,
+            xAnchor: -0.05,
+            yAnchor: 1.1,
+            zIndex: 999
+        });
+
+        trafficObj.polyLine.setOptions({strokeColor: '#0000FF'});
+        trafficObj.infoWindow.setMap(_MapHandler.map);
+    }
+    else {
+        trafficObj.polyLine.setOptions({strokeColor: g_color.get(trafficObj.obj.cmtr_grad_cd)});
+    }
+}
+
 /**
  * 간선도로 클릭 이벤트
  * @param AupHillId 상행 ID
@@ -544,6 +675,7 @@ function atrdClickEvent(AupHillId, AdownHillId) {
     if (! _MarkerHandle.findMarkerArr('atrd').length) {
         return alert('도로정보를 불러오는 중입니다.');
     }
+
     if (_MarkerHandle.selectedAtrd.length > 0) {
         _MarkerHandle.selectedAtrd.forEach((atrdId)=>{
             _MarkerHandle.findMarkerObj('atrd', atrdId).marker.setMap(null);
@@ -575,6 +707,10 @@ function atrdClickEvent(AupHillId, AdownHillId) {
 
         _MarkerHandle.selectedAtrd = [AupHillId + '_0_' + boundAfterLevel, AdownHillId + '_1_' + boundAfterLevel];
         getVertex();
+        if ($('.list-content > ul.on')[0]) {
+            $('.list-content > ul.on').removeClass('on');
+        }
+        $(`#${AupHillId}_${AdownHillId}`).addClass('on');
     }
 }
 
@@ -616,7 +752,7 @@ class MarkerObj {
         this.prop       = {...DATA};
         this.size       = [48, 48, 48, 48, 40, 32, 24, 22, 20, 18, 18];
         this.atrdSize   = [48, 48, 48, 48, 48, 48, 48, 24, 24, 24, 24];
-        this.imageOnOff = ['cctv', 'incident', 'vms', 'parking'];
+        this.imageOnOff = ['cctv', 'incident', 'vms'];
     }
 
     //스마트교차로 카메라는 카메라 방향별로 이미지를 돌려야하므로 두개 만드는 방식이 다름
@@ -717,7 +853,7 @@ class MarkerObj {
     }
 
     //클릭 이벤트
-    click() {
+    async click() {
         const selectObj = _MarkerHandle.selectedMarker;
         if (selectObj) {
             if (selectObj === this) {
@@ -752,6 +888,14 @@ class MarkerObj {
         if (this.iwContent) {
             this.infoWindow = $(this.iwContent);
             $('body').append(this.infoWindow);
+            if (this.type === 'parking' && this.prop.prk_plce_nmbr) {
+                const parkData = await $.ajax({url: '/api/traffic/parking-live-info', method: 'post', data:{nmbr: this.prop.prk_plce_nmbr}});
+                if (parkData.remndr_prk_cmprt_co && parkData.remndr_prk_cmprt_co >= 0) {
+                    const remndrPrkCmprtCo = parkData.remndr_prk_cmprt_co + '대';
+                    $('.remndr_prk_cmprt_co').attr('title', '주차가능면수 : '+ remndrPrkCmprtCo);
+                    $('.remndr_prk_cmprt_co').html(remndrPrkCmprtCo);
+                }
+            }
             let type = this.type;
             if (type === 'intersectionCamera') type = 'cctv';
             setInfoWindowPositionWidthDraggable(this, type);
@@ -1100,8 +1244,8 @@ class TbParkingObj extends MarkerObj{
             URL         : null,
             TYPE        : 'parking',
             DATA        : obj,
-            IMAGE_TYPE  : '1',
-            IMAGE       : '/images/icon/parking',
+            IMAGE_TYPE  : '',
+            IMAGE       : '/images/icon/parking' + (obj.prk_plce_nmbr ? '1-2' : '2-2'),
             ADDR        : obj.parking_addr,
         })
         this.iwContent = this.getIwContent();
@@ -1119,14 +1263,25 @@ class TbParkingObj extends MarkerObj{
                             <div class="row">
                                 <div>주차면수</div>
                                 <div title="주차면수 : ${prop.parking_num} 대">${prop.parking_num} 대</div>
-                            </div>
-                            <div class="row">
+                            </div>`;
+                if (prop.prk_plce_nmbr) {
+                    iwContent +=`<div class="row">
+                                    <div>주차가능면수</div>
+                                    <div class="remndr_prk_cmprt_co">- 대</div>
+                                </div>`;
+                }
+
+                iwContent +=`<div class="row">
                                 <div>구분</div>
                                 <div title="구분 : ${prop.parking_type_desc}">${prop.parking_type_desc}</div>
                             </div>
                             <div class="row">
                                 <div>기본요금</div>
                                 <div title="기본요금 : ${prop.parking_fee_type_desc}">${prop.parking_fee_type_desc}</div>
+                            </div>
+                             <div class="row">
+                                <div>운영시간</div>
+                                <div title="운영시간 : ${prop.parking_oper_time}">${prop.parking_oper_time}</div>
                             </div>
                             <div class="row">
                                 <div>주소</div>
@@ -1715,6 +1870,12 @@ class MapHandler {
             }
         });
 
+        // kakao.maps.event.addListener(this.map, 'bounds_changed', function() {
+        //     if (_MarkerHandle.isDraw('traffic')) {
+        //         getVertex();
+        //     }
+        // });
+
         /**
          * 맵 클릭 이벤트
          */