PageSourceSearch

https://durunubi.kr/js/koreatrailsMap.js?version=1

js durunubi.kr collected 2026-10-01 14:13:37 UTC 29,827 bytes, 830 lines download raw bytes

1const Location = new Array();
2const courseList = new Array();
3const paging = {
4    curPage: 1,
5    curBlock: 1,
6    prePage: 1,
7    nextPage: 1,
8    pageSize: 10,
9    blockSize: 5,
10    totalCount: 0,
11    totalPageCount: 0,
12    totalBlockCount: 0,
13    blockList: []
14};
15
16class CommonMap {
17    _map;
18    langCode = null;
19
20    constructor(langCode) {
21        this.langCode = langCode;
22    }
23
24
25    removeLogo() {
26    }
27
28    getModal(dot, classStr) {
29        let modal = null;
30        if (!this.langCode || this.langCode == 'ko') {
31            modal = '<div class="map-modal" style="top:-47px;left: 70px">' +
32                '<div class="map-modal-content ' + classStr + ' shadow"> <!-- 해파랑길 -->' +
33                '<div class="address text-truncate mb-1">' + dot.locationName + '</div>' +
34                '<div class="tit mb-2">' +
35                '<i class="icon"></i>' + dot.name +
36                '</div>' +
37                '<ul class="d-flex justify-content-center w-100">' +
38                '<li><span>' + dot.distance + 'km</span></li>' +
39                '<li><span>' + appVue.getDistanceString(dot.hour, dot.minute) + '</span></li>' +
40                '<li><span>' + appVue.getLevelString(dot.level) + '</span></li>' +
41                '</ul>' +
42                '<a target="_blank" title="새창 열림" href="/course-detail-view.do?crs_idx=' + dot.idx + '" class="stretched-link"></a>' +
43                '<button type="button" class="closed" onclick="mapObj.closeOpenInfoWindow()"></button>' +
44                '</div>' +
45                '<div class="map-modal-back"></div>' +
46                '</div>'
47        } else if (this.langCode == 'en') {
48            modal = '<div class="map-modal" style="top:-47px;left: 70px">' +
49                '<div class="map-modal-content ' + classStr + ' shadow"> <!-- 해파랑길 -->' +
50                '<div class="address text-truncate mb-1">' + dot.locationName + '</div>' +
51                '<div class="tit mb-2">' +
52                '<i class="icon"></i>' + dot.name +
53                '</div>' +
54                '<ul class="d-flex justify-content-center w-100">' +
55                '<li><span>' + dot.distance + 'km</span></li>' +
56                '<li><span>' + appVue.getDistanceString(dot.hour, dot.minute) + '</span></li>' +
57                '<li><span>' + appVue.getLevelString(dot.level) + '</span></li>' +
58                '</ul>' +
59                '<a target="_blank" title="새창 열림" href="/course-detail-view.do?crs_idx=' + dot.idx + '" class="stretched-link"></a>' +
60                '<button type="button" class="closed" onclick="mapObj.closeOpenInfoWindow()"></button>' +
61                '</div>' +
62                '<div class="map-modal-back"></div>' +
63                '</div>'
64        }
65
66        return modal;
67    }
68
69    //for abstract
70    //drawCourse(settingPath, serviceFlag){}
71}
72
73class KakaoMap extends CommonMap {
74
75    #selectedMarker = null;
76    #selectedwindow = null;
77
78    #heMarkerImage = null;
79    #naMarkerImage = null;
80    #seoMarkerImage = null;
81    #dmzMarkerImage = null;
82
83    #hePickMarkerImage = null;
84    #naPickMarkerImage = null;
85    #seoPickMarkerImage = null;
86    #dmzPickMarkerImage = null;
87
88    constructor(serviceFlag, langCode) {
89        super(langCode);
90        this.init(serviceFlag);
91    }
92
93    init(serviceFlag) {
94        let center;
95        let level = 0;
96        if (serviceFlag == 'DMZ') {
97            center = new daum.maps.LatLng(38.2, 127.7);
98            level = 11; // 지도의 확대 레벨
99        } else if (serviceFlag == 'NA') {
100            center = new daum.maps.LatLng(35.0, 127.87395);
101            level = 12; // 지도의 확대 레벨
102        } else {
103            center = new daum.maps.LatLng(36.59479, 127.87395);
104            level = 13; // 지도의 확대 레벨
105        }
106
107        this._map = new daum.maps.Map($('#map')[0], {center, level});
108
109        Location.forEach(function (dot) {
110            const markerPosition = new kakao.maps.LatLng(dot.lat, dot.lon);
111            let imageSrc;
112            let imagePickSrc;
113            const imageSize = new kakao.maps.Size(21, 21);
114            const pickImageSize = new kakao.maps.Size(21, 25);
115            let classStr = "he"
116
117            if (dot.serviceFlag == 'HE') {
118                imageSrc = "/durunubi_2022/images/dot_haeparang.png";
119                imagePickSrc = "/durunubi_2022/images/dot_haeparang_pick.png";
120                this.#heMarkerImage = new kakao.maps.MarkerImage(imageSrc, imageSize);
121                this.#hePickMarkerImage = new kakao.maps.MarkerImage(imagePickSrc, pickImageSize);
122                classStr = "hea";
123            } else if (dot.serviceFlag == 'NA') {
124                imageSrc = "/durunubi_2022/images/dot_namparang.png";
125                imagePickSrc = "/durunubi_2022/images/dot_namparang_pick.png";
126                this.#naMarkerImage = new kakao.maps.MarkerImage(imageSrc, imageSize);
127                this.#naPickMarkerImage = new kakao.maps.MarkerImage(imagePickSrc, pickImageSize);
128                classStr = "nam";
129            } else if (dot.serviceFlag == 'SEO') {
130                imageSrc = "/durunubi_2022/images/dot_seohaerang.png";
131                imagePickSrc = "/durunubi_2022/images/dot_seohaerang_pick.png";
132                this.#seoMarkerImage = new kakao.maps.MarkerImage(imageSrc, imageSize);
133                this.#seoPickMarkerImage = new kakao.maps.MarkerImage(imagePickSrc, pickImageSize);
134                classStr = "su";
135            } else if (dot.serviceFlag == 'DMZ') {
136                imageSrc = "/durunubi_2022/images/dot_dmz.png";
137                imagePickSrc = "/durunubi_2022/images/dot_dmz_pick.png";
138                this.#dmzMarkerImage = new kakao.maps.MarkerImage(imageSrc, imageSize);
139                this.#dmzPickMarkerImage = new kakao.maps.MarkerImage(imagePickSrc, pickImageSize);
140                classStr = "dmz";
141            } else {
142                imageSrc = "/durunubi_2022/images/dot_haeparang.png";
143                imagePickSrc = "/durunubi_2022/images/dot_haeparang_pick.png";
144                classStr = "hea";
145            }
146
147            const basicMarkerImage = new kakao.maps.MarkerImage(imageSrc, imageSize);
148
149            const modal = this.getModal(dot, classStr);
150            const infowindow = new kakao.maps.InfoWindow({
151                content: modal,
152                removable: true // removeable 속성을 ture 로 설정하면 인포윈도우를 닫을 수 있는 x버튼이 표시됩니다
153            });
154
155            const marker = new kakao.maps.Marker({
156                map: this._map, // 마커를 표시할 지도
157                position: markerPosition, // 마커를 표시할 위치
158                title: dot.serviceFlag,
159                image: basicMarkerImage, // 마커 이미지
160                clickable: true
161            });
162            marker.setMap(this._map);
163            kakao.maps.event.addListener(marker, 'click', this.makeClickListener(marker, infowindow).bind(this));
164            kakao.maps.event.addListener(marker, 'mouseover', this.makeOverListener(this._map, marker, infowindow).bind(this));
165            kakao.maps.event.addListener(marker, 'mouseout', this.makeOutListener(marker, infowindow).bind(this));
166
167            this.drawCourse(dot.gpx.road, dot.serviceFlag);
168        }, this);
169    }
170
171    makeClickListener(marker, infowindow) {
172        return function () {
173            // 클릭된 마커가 없고, click 마커가 클릭된 마커가 아니면
174            // 마커의 이미지를 클릭 이미지로 변경합니다
175            if (!this.#selectedMarker && this.#selectedMarker !== marker) {
176                infowindow.open(this._map, marker);
177                // infowindow.setMap(map);
178                switch (marker.getTitle()) {
179                    case "HE":
180                        marker.setImage(this.#hePickMarkerImage);
181                        break;
182                    case "NA":
183                        marker.setImage(this.#naPickMarkerImage);
184                        break;
185                    case "SEO":
186                        marker.setImage(this.#seoPickMarkerImage);
187                        break;
188                    case "DMZ":
189                        marker.setImage(this.#dmzPickMarkerImage);
190                        break;
191                }
192            } else if (this.#selectedMarker && this.#selectedMarker !== marker) {
193                this.#selectedwindow.close();
194                infowindow.open(this._map, marker);
195                // infowindow.setMap(map);
196                switch (marker.getTitle()) {
197                    case "HE":
198                        marker.setImage(this.#hePickMarkerImage);
199                        break;
200                    case "NA":
201                        marker.setImage(this.#naPickMarkerImage);
202                        break;
203                    case "SEO":
204                        marker.setImage(this.#seoPickMarkerImage);
205                        break;
206                    case "DMZ":
207                        marker.setImage(this.#dmzPickMarkerImage);
208                        break;
209                }
210
211                switch (this.#selectedMarker.getTitle()) {
212                    case "HE":
213                        this.#selectedMarker.setImage(this.#heMarkerImage);
214                        break;
215                    case "NA":
216                        this.#selectedMarker.setImage(this.#naMarkerImage);
217                        break;
218                    case "SEO":
219                        this.#selectedMarker.setImage(this.#seoMarkerImage);
220                        break;
221                    case "DMZ":
222                        this.#selectedMarker.setImage(this.#dmzMarkerImage);
223                        break;
224                }
225            }
226
227            // 클릭된 마커를 현재 클릭된 마커 객체로 설정합니다
228            this.#selectedMarker = marker;
229            this.#selectedwindow = infowindow;
230        };
231    }
232
233    makeOverListener(map, marker, infowindow) {
234        return function () {
235            infowindow.open(map, marker);
236            // infowindow.setMap(map);
237        };
238    }
239
240    makeOutListener(marker, infowindow) {
241        return function () {
242            if (!this.#selectedMarker || this.#selectedMarker !== marker) {
243                infowindow.close();
244                // infowindow.setMap(null);
245            }
246        };
247    }
248
249    removeLogo() {
250        //접근성을 위해 제거
251        //init listener가 없어서 timeout으로 진행
252        const kakaoItem = $("a[href$='map.kakao.com/']")
253        if (kakaoItem) {
254            kakaoItem.attr("tabindex", "-1");
255        }
256    }
257
258    closeOpenInfoWindow() {
259        this.#selectedwindow.close();
260        switch (this.#selectedMarker.getTitle()) {
261            case "HE":
262                this.#selectedMarker.setImage(this.#heMarkerImage);
263                break;
264            case "NA":
265                this.#selectedMarker.setImage(this.#naMarkerImage);
266                break;
267            case "SEO":
268                this.#selectedMarker.setImage(this.#seoMarkerImage);
269                break;
270            case "DMZ":
271                this.#selectedMarker.setImage(this.#dmzMarkerImage);
272                break;
273        }
274        this.#selectedMarker = null;
275        this.#selectedwindow = null;
276    }
277
278    zoomIn() {
279        const level = this._map.getLevel();
280        this._map.setLevel(level - 1);
281    }
282
283    zoomOut() {
284        const level = this._map.getLevel();
285        if (level == 13) {
286            // 지도 최대 배율 제한
287            return;
288        }
289        this._map.setLevel(level + 1);
290    }
291
292    drawCourse(settingPath, serviceFlag) {
293        let lineColor = '';
294        switch (serviceFlag) {
295            case 'HE' :
296                lineColor = '#ea5236';
297                break;
298            case 'NA' :
299                lineColor = '#1556aa';
300                break;
301            case 'SEO' :
302                lineColor = '#fc9703';
303                break;
304            case 'DMZ' :
305                lineColor = '#009d63';
306                break;
307        }
308
309        if(!settingPath){
310            console.log("settingPath == null");
311            return;
312        }
313
314        if(settingPath != null && settingPath.length > 0){
315            let duruTrack = settingPath[0];
316            const linePath = new Array(); //다음맵에 그릴 전체 좌표
317
318            for (let j = 0; j < duruTrack.track.length; j++) {
319                let point = duruTrack.track[j];
320                linePath.push(new daum.maps.LatLng(point.lat, point.lon));
321            }
322
323            // 라인
324            // 지도에 표시할 선을 생성합니다
325            const polyline = new daum.maps.Polyline({
326                path: linePath, // 선을 구성하는 좌표배열 입니다
327                strokeWeight: 3, // 선의 두께 입니다
328                strokeColor: lineColor, // 선의 색깔입니다
329                strokeOpacity: 1.00, // 선의 불투명도 입니다 1에서 0 사이의 값이며 0에 가까울수록 투명합니다
330            });
331            polyline.setMap(this._map);
332        }
333    }
334}
335
336class NgiiMap extends CommonMap {
337    #selected = false;
338
339    constructor(serviceFlag, langCode) {
340        super(langCode);
341        this.init(serviceFlag);
342    }
343
344    init(serviceFlag) {
345        let center;
346        let level = 0;
347        if (serviceFlag == 'DMZ') {
348            center = this.changeCoord(38.2, 127.7);
349            level = 1; // 지도의 확대 레벨
350        } else if (serviceFlag == 'NA') {
351            center = this.changeCoord(35.0, 127.87395);
352            level = 1; // 지도의 확대 레벨
353        } else {
354            center = this.changeCoord(36.59479, 127.87395);
355            level = 1; // 지도의 확대 레벨
356        }
357
358        //0:일반, 1:색각, 2:큰글자, 3:English, 4:백지도, 5:中國語, 6:にほんご, 7:교육용백지도, 8:mobile, 9:항공영상, 10:야간지도
359        let mapNode = $('#map')[0]
360        this._map = new ol.Map({
361            target: mapNode,
362            view: new ol.View({
363                projection: 'EPSG:5179',
364                resolutions: [2088.96, 1044.48, 522.24, 261.12, 130.56, 65.28, 32.64, 16.32, 8.16, 4.08, 2.04, 1.02, 0.51, 0.255],
365                maxResolution: 2088.96,
366                minResolution: 0.255,
367                constrainResolution: true,
368            }),
369            interactions: ol.interaction.defaults({
370                doubleClickZoom: true
371            }),
372            controls: [],
373        })
374
375        let mapBounds = [705680.0000, 1349270.0000, 1388291.0000, 2581448.0000];
376        let layer2 = new ol.layer.Tile(wmtEmapOption2('english_map', false));
377        this._map.addLayer(layer2);
378        this._map.getView().fit(mapBounds);
379        ngii_wmts.setBaseLayer(this._map, layer2)
380
381        this._map.getView().setZoom(level);   //줌을 생성자에서 넣으면 이상하게 보인다.
382        this._map.getView().setCenter(center); //마찬가지
383
384        const map1 = this._map;
385        const container = document.getElementById('popup');
386        const content = document.getElementById('popup-content');
387        const closer = document.getElementById('popup-closer');
388
389        const $this = this;
390
391        const createPopup = function(e, modal){
392            content.innerHTML = modal;
393
394            var coordinate = e.coordinate; // 클릭한 지도 좌표
395            const overlay = new ol.Overlay({
396                id: 'popup',
397                element: container,
398                offset : [-50, -50] //마우스 오버할때 POI와 팝업이 겹치지 않게 함
399            });
400            overlay.setPosition(coordinate, map1.getView().getProjection());
401
402            map1.addOverlay(overlay);
403        };
404
405        this._map.on('click', function (e) {
406            var feature = map1.forEachFeatureAtPixel(e.pixel,
407                function (feature) {
408                    return feature;
409                });
410
411            if (feature) {
412                this.#selected = true;
413
414                let modal = feature.get("modalData");
415                createPopup(e, modal);
416
417                e.preventDefault(); // avoid bubbling
418            }
419        }.bind(this));
420
421        this._map.on('pointermove', function (e) {
422            var feature = map1.forEachFeatureAtPixel(e.pixel,
423                function (feature) {
424                    return feature;
425                });
426
427            if(this.#selected === true){
428                return;
429            }
430
431            if (feature) {
432                console.log("mouseover");
433
434                let modal = feature.get("modalData");
435                createPopup(e, modal);
436            }else{
437                $this.closeOpenInfoWindow();
438            }
439        }.bind(this));
440
441        var markerSource = new ol.source.Vector();
442        for (let i = 0; i < Location.length; i++) {
443            let dot = Location[i];
444
445            let imageSrc;
446            let imagePickSrc;
447            let classStr = "he"
448
449            if (dot.serviceFlag == 'HE') {
450                imageSrc = "/durunubi_2022/images/dot_haeparang.png";
451                imagePickSrc = "/durunubi_2022/images/dot_haeparang_pick.png";
452                classStr = "hea";
453            } else if (dot.serviceFlag == 'NA') {
454                imageSrc = "/durunubi_2022/images/dot_namparang.png";
455                imagePickSrc = "/durunubi_2022/images/dot_namparang_pick.png";
456                classStr = "nam";
457            } else if (dot.serviceFlag == 'SEO') {
458                imageSrc = "/durunubi_2022/images/dot_seohaerang.png";
459                imagePickSrc = "/durunubi_2022/images/dot_seohaerang_pick.png";
460                classStr = "su";
461            } else if (dot.serviceFlag == 'DMZ') {
462                imageSrc = "/durunubi_2022/images/dot_dmz.png";
463                imagePickSrc = "/durunubi_2022/images/dot_dmz_pick.png";
464                classStr = "su";
465            } else {
466                imageSrc = "/durunubi_2022/images/dot_haeparang.png";
467                imagePickSrc = "/durunubi_2022/images/dot_haeparang_pick.png";
468                classStr = "hea";
469            }
470
471            const modal = this.getModal(dot, classStr);
472
473            let marker = new ol.Feature({
474                geometry: this.changeCoordPoint(dot.lat, dot.lon),
475                modalData: modal,
476            });
477
478            var markerStyle = new ol.style.Style({
479                image: new ol.style.Icon({
480                    src: imageSrc
481                })
482            });
483
484            marker.setStyle(markerStyle);
485            markerSource.addFeature(marker);
486
487            this.drawCourse(dot.gpx.road, dot.serviceFlag);
488        }
489
490
491    }
492
493    changeCoord(x, y) {
494        //ngii맵 좌표계인 EPSG:5179에서 두루누비 표준 좌표인 WGS84로 변환
495        const changed = new ol.geom.Point([Number(y), Number(x)])
496            .transform('WGS84', 'EPSG:5179')
497            .getCoordinates();
498
499        return changed;
500    }
501
502    changeCoordPoint(x, y) {
503        //ngii맵 좌표계인 EPSG:5179에서 두루누비 표준 좌표인 WGS84로 변환
504        const changed = new ol.geom.Point([Number(y), Number(x)])
505            .transform('WGS84', 'EPSG:5179');
506
507        return changed;
508    }
509
510    removeLogo() {
511    }
512
513    closeOpenInfoWindow() {
514        this._map.getOverlays().forEach(layer => {
515            this._map.removeOverlay(layer)
516        })
517
518        this.#selected = false;
519    }
520
521    zoomIn() {
522        const level = this._map.getView().getZoom();
523        this._map.getView().setZoom(level + 1);
524    }
525
526    zoomOut() {
527        const level = this._map.getView().getZoom();
528        this._map.getView().setZoom(level - 1);
529    }
530
531    drawCourse(settingPath, serviceFlag) {
532        let lineColor = '';
533        switch (serviceFlag) {
534            case 'HE' :
535                lineColor = '#ea5236';
536                break;
537            case 'NA' :
538                lineColor = '#1556aa';
539                break;
540            case 'SEO' :
541                lineColor = '#fc9703';
542                break;
543            case 'DMZ' :
544                lineColor = '#009d63';
545                break;
546        }
547
548        if (!settingPath) {
549            console.error("settingPath == null");
550            return;
551        }
552
553        let lineSource = new ol.source.Vector();
554
555        if(settingPath != null && settingPath.length > 0){
556            let duruTrack = settingPath[0];
557
558            const linePath = new Array(); //다음맵에 그릴 전체 좌표
559
560            for (let j = 0; j < duruTrack.track.length; j++) {
561                let point = duruTrack.track[j];
562                const changedPoint = this.changeCoord(point.lat, point.lon);
563                linePath.push(changedPoint);
564            }
565
566            let line = new ol.Feature({
567                geometry: new ol.geom.LineString(linePath)
568            });
569
570            // 라인의 스타일을 정의합니다.
571            let lineStyle = new ol.style.Style({
572                stroke: new ol.style.Stroke({
573                    color: lineColor,
574                    width: 5
575                })
576            });
577
578            line.setStyle(lineStyle);
579
580            lineSource.addFeature(line);
581        }
582
583        let lineLayer = new ol.layer.Vector({
584            name: "lineLayer",
585            source: lineSource, //마커 feacture들
586        });
587
588        this._map.addLayer(lineLayer);
589    }
590}
591
592
593
594function initMaps(serviceFlag) {
595
596    //지도 변경 필요
597    if (!langCode || langCode == 'ko') {
598        mapObj = new KakaoMap(serviceFlag, langCode);
599    } else {
600        mapObj = new NgiiMap(serviceFlag, langCode);
601    }
602
603    setTimeout(function () {
604        mapObj.removeLogo();
605    }, 1000);
606}
607
608function getMarkerLocation(serviceFlag, langCode1) {
609    langCode = langCode1;
610
611    $.ajax({
612        type: 'GET',
613        dataType: 'json',
614        url: '/api/course/list',
615        data: {
616            type: 'DNWW',
617            serviceFlag: serviceFlag,
618            orderBy: 4,
619            size: 500,
620            langCode: langCode,
621            gpx_parse_mode: 2,
622
623        },
624        success: function (result) {
625            if (!result.success) {
626                return false;
627            }
628            result.response.forEach(function (element) {
629                Location.push({
630                    idx: element.crs_idx,
631                    name: element.crs_Kor_Nm,
632                    locationName: element.sigun,
633                    lat: element.startLat,
634                    lon: element.startLon,
635                    serviceFlag: element.serviceFlag,
636                    distance: element.crs_Dstnc,
637                    hour: parseInt(element.crs_Totl_Rqrm_Hour) / 60,
638                    minute: parseInt(element.crs_Totl_Rqrm_Hour) % 60,
639                    lev: element.lev,
640                    level: element.level,
641                    //gpx_src : element.gpx_src,
642                    gpx: element.gpx,
643                    crsInfo : element.crsInfo,
644                });
645            });
646
647            paging.totalCount = Location.length;
648
649            initMaps(serviceFlag);
650            drawTable(paging.curPage - 1);
651        }
652    });
653}
654
655function drawTable(offset) {
656    const start = offset * paging.pageSize;
657    const end = (offset + 1) * paging.pageSize;
658    const dataList = Location.slice(start, end);
659
660    calculatePage();
661    drawPaging();
662
663    vueData.courseList = dataList;
664}
665
666function drawPaging() {
667    let html = '';
668
669    if (!langCode || langCode == 'ko') {
670        html += '<li class="prev">' +
671            '<a href="javascript:void(0);" title="이전 페이지로 이동" onclick="changePagePre()">' +
672            '<i class="icon"></i>' +
673            '</a>' +
674            '</li>';
675
676        paging.blockList.forEach(function (page) {
677            html += '<li>';
678            html += '<a href="javascript:void(0);" class="';
679            html += (page == paging.curPage) ? 'active' : '';
680            html += '" title="';
681            html += (page == paging.curPage) ? '현재 ' + page + '페이지' : page + '페이지로 이동';
682            html += '" onclick="changePage(' + page + ')">';
683            html += '<span>' + page + '</span>';
684            html += '</a>';
685            html += '</li>';
686        });
687
688        html += '<li class="next">' +
689            '<a href="javascript:void(0);" title="다음 페이지로 이동" onclick="changePageNext()">' +
690            '<i class="icon"></i>' +
691            '</a>' +
692            '</li>';
693    } else if (langCode === 'en') {
694        html += '<li class="prev">' +
695            '<a href="javascript:void(0);" title="prev" onclick="changePagePre()">' +
696            '<i class="icon"></i>' +
697            '</a>' +
698            '</li>';
699
700        paging.blockList.forEach(function (page) {
701            html += '<li>';
702            html += '<a href="javascript:void(0);" class="';
703            html += (page == paging.curPage) ? 'active' : '';
704            html += '" title="';
705            html += (page == paging.curPage) ? '현재 ' + page + '페이지' : page + '페이지로 이동';
706            html += '" onclick="changePage(' + page + ')">';
707            html += '<span>' + page + '</span>';
708            html += '</a>';
709            html += '</li>';
710        });
711
712        html += '<li class="next">' +
713            '<a href="javascript:void(0);" title="next" onclick="changePageNext()">' +
714            '<i class="icon"></i>' +
715            '</a>' +
716            '</li>';
717    }
718
719    $('.pagination').html(html);
720}
721
722function calculatePage() {
723    paging.totalPageCount = Math.ceil(paging.totalCount * 1.0 / paging.pageSize);
724    paging.totalBlockCount = Math.ceil(paging.totalPageCount * 1.0 / paging.blockSize);
725    paging.curBlock = Math.floor(((paging.curPage - 1) / paging.blockSize) + 1);
726    const startPage = (paging.curBlock - 1) * paging.blockSize + 1;
727    let endPage = startPage + paging.blockSize - 1;
728
729    if (endPage > paging.totalPageCount) {
730        endPage = paging.totalPageCount;
731    }
732
733    paging.blockList = [];
734    for (let i = startPage; i <= endPage; i++) {
735        paging.blockList.push(i);
736    }
737
738    paging.prePage = paging.curPage - 1;
739    paging.nextPage = paging.curPage + 1;
740}
741
742function changePage(page) {
743    paging.curPage = page;
744    drawTable(page - 1);
745}
746
747function changePagePre() {
748    if (paging.prePage === 0) {
749        return;
750    }
751
752    paging.curPage = paging.prePage;
753    drawTable(paging.curPage - 1);
754}
755
756function changePageNext() {
757    if (paging.nextPage > paging.totalPageCount) {
758        return;
759    }
760
761    paging.curPage = paging.nextPage;
762    drawTable(paging.curPage - 1);
763}
764
765var courseMixin = {
766    methods: {
767        getLevelString: function (level) {
768            if (!langCode || langCode == 'ko') {
769                switch (level) {
770                    case 1 :
771                        return "쉬움";
772                    case 2:
773                        return "보통";
774                    case 3:
775                        return "어려움";
776                }
777            } else if (langCode == 'en') {
778                switch (level) {
779                    case 1 :
780                        return "Easy";
781                    case 2:
782                        return "Average";
783                    case 3:
784                        return "Difficult";
785                }
786            }
787        },
788        getLevelString2: function (level) {
789            //TODO : langCode를 vue.js안으로 넣기 위해 임시 분기 추후 통합한다.
790            const $this = this;
791
792            if (!$this.langCode || $this.langCode == 'ko') {
793                switch (level) {
794                    case 1 :
795                        return "쉬움";
796                    case 2:
797                        return "보통";
798                    case 3:
799                        return "어려움";
800                }
801            } else if ($this.langCode == 'en') {
802                switch (level) {
803                    case 1 :
804                        return "Easy";
805                    case 2:
806                        return "Average";
807                    case 3:
808                        return "Difficult";
809                }
810            }
811        },
812        getDistanceString: function (hour, minute) {
813            if (!langCode || langCode == 'ko') {
814                return (hour > 0 ? (Math.floor(hour) + '시간') : '') + (minute > 0 ? (' ' + minute + '분') : '')
815            } else if (langCode == 'en') {
816                return (hour > 0 ? (Math.floor(hour) + 'h') : '') + (minute > 0 ? (' ' + minute + 'm') : '')
817            }
818        },
819        getDistanceString2: function (hour, minute) {
820            //TODO : langCode를 vue.js안으로 넣기 위해 임시 분기 추후 통합한다.
821            const $this = this;
822
823            if (!$this.langCode || $this.langCode == 'ko') {
824                return (hour > 0 ? (Math.floor(hour) + '시간') : '') + (minute > 0 ? (' ' + minute + '분') : '')
825            } else if ($this.langCode == 'en') {
826                return (hour > 0 ? (Math.floor(hour) + 'h') : '') + (minute > 0 ? (' ' + minute + 'm') : '')
827            }
828        },
829    }
830}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.