팡이네

JSON 배열을 일종의 목록이라고 보고 특정 열 전체를 삭제하고 싶을 때 아래와 같이 간단하게 처리 가능

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const arr = [
    {
        XXX: "2",
        YYY: "3",
        ZZZ: "4"
    },
    {
        XXX: "5",
        YYY: "6",
        ZZZ: "7"
    },
    {
        XXX: "1",
        YYY: "2",
        ZZZ: "3"
    }
]
 
// destructure 'YYY' and return the other props only
const newArray = arr.map(({YYY, ...rest}) => rest)
 
console.log(newArray)

[참고]

https://stackoverflow.com/questions/24770887/remove-key-value-pair-from-json-object

전에 올린 마커 클러스터링 문서와 이어지는 내용

마커 목록에서 마커를 선택했을 경우 지도 상에 표시된 해당 마커의 디자인을 변경해서 표시

 

[CSS 추가]

1
2
3
4
5
6
7
8
9
10
11
12
//--------------------------------------
// CSS 추가
//--------------------------------------
// 마커용 css
.list > ol > li { display: flex; align-items: center; }
.list > ol > li:hover { background-color: rgba(3, 133, 255, 0.5); }
.list > ol > li > input { margin-right: 5px; }
 
.cm { display: flex; font-weight: bold; align-items: center; text-align: center; }
.cm > div:nth-child(1) { width: 32px; height: 32px; }
.cm > div:nth-child(2) { position: absolute; background-color: #2f96fc; width: 32px; height: 32px; border-radius: 28px; line-height: 32px; margin-bottom: 8px; z-index: 9; }
.cm > div:nth-child(3) { position: absolute; background-color: #ffffff; width: 24px; height: 24px; border-radius: 24px; line-height: 24px; margin-left: 4px; margin-bottom: 8px; z-index: 10; }

[마커 설정]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//--------------------------------------
// 마커 설정
//--------------------------------------
var markers = [];
 
for (var i = 0, ii = options.length; i < ii; i++) {
    markers.push(new naver.maps.Marker({
        position: new naver.maps.LatLng(options[i].pos[0], options[i].pos[1]),
        zIndex: 100,
        icon: {
            content: [
                '<div>',
                '   <div><img src="marker.png" /></div>',
                '</div>',
            ].join(''),
            anchor: new naver.maps.Point(11, 33),
        }
    }));
}

[마커 표시]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//--------------------------------------
// 마커 표시
//--------------------------------------
// 마커 info 속성 표시
function showMarkerInfo(marker) {
    var img = $(marker.getIcon().content).find('img');
    var chk = img.attr('choose');
    var json = attr2json(img.attr('info'));
    var li = $('마커 : code = '+ json.code +', name = '+ json.name +'');
    $('#list').append(li);
     
    //체크박스 change 이벤트 설정
    li.on('change', chooseMarker.bind(this, json.code, marker));
}

[선택한 마커 아이콘 변경]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//--------------------------------------
// 선택한 마커 아이콘 변경
//--------------------------------------
var _cCount = 0;
 
//체크한 마커 아이콘 변경
function chooseMarker(c, marker) {
    var img = $(marker.getIcon().content).find('img');
     
    if ($('#cb'+ c).prop('checked')) {
        _cCount++;
         
        var icon = {
            content: [
                '<div class="cm">',
                '   <div><img src="marker.png" /></div>',
                '   <div> </div>',
                '   <div>'+ _cCount +'</div>',
                '</div>',
            ].join(''),
            anchor: new naver.maps.Point(16, 33),
        };
    } else {
        _cCount--;
         
        var icon = {
            content: [
                '<div>',
                '   <div><img src="marker.png" /></div>',
                '</div>',
            ].join(''),
            anchor: new naver.maps.Point(11, 33),
        };
    }
     
    marker.setIcon(icon);
}

네이버 지도에서 마커를 표시할 때 지도가 축소되면 마커를 묶어서 표시

네이버에서는 마커를 묶어서 표시하기 위해 예제를 제공하고 있다.(아래 참고)

그 예제를 약간 수정하여 마커 클러스터링을 구현한 소스

 

준비물: jquery-3.5.1.min.js, MarkerClustering.js

 

[지도 html]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//--------------------------------------
// 지도 html
//--------------------------------------
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>마커 클러스터링</title>
    <script type="text/javascript" src="jquery-3.5.1.min.js"></script>
    <script type="text/javascript" src="marker-clustering-custom.js"></script>
    <style type="text/css">
    body { font-size: 12px; font-family: dotum; }
    input { height: 22px; background-color: #efefef; border: 1px solid #333333; border-radius: 4px; }
     
    .div_map { display:flex; flex-direction: row; }
    .map { width: 1000px; height: 600px; border: 1px solid #c0c0c0; border-radius: 4px; }
     
    .div_list { height: 600px; }
    .list_title { height: 30px; line-height: 30px; background-color: #efefef; border: 1px solid #c0c0c0; border-radius: 4px; margin: 0 0 5px 5px; font-weight: bold; padding-left: 10px; }
    .list { width: 320px; height: 563px; border: 1px solid #c0c0c0; border-radius: 4px; margin-left: 5px; overflow-y: auto; }
    .list > ol { line-height: 1.7em; }
     
    .ctl { display: flex; flex-direction: row; justify-content: space-between; width:1000px; margin-top: 5px; }
    .pos { display: flex; flex-direction: row; justify-content: space-between; }
    .ctl input {  text-align: center; }
    .pos button { height: 26px; border: 1px solid #333333; border-radius: 4px; }
    .pos > div:nth-child(2) { margin-left: 6px; }
    </style>
</head>
<body>
<div>
    <div class="div_map">
        <div id="map" class="map"> </div>
        <div class="div_list">
            <div class="list_title">마커 목록</div>
            <div class="list"> </div>
        </div>
    </div>
    <div class="ctl">
        <div><input id="info" readonly="readonly" size="40" type="text" value="" /></div>
        <div class="pos">
            <div>
                <input id="lat" readonly="readonly" size="20" type="text" value="" />
                <input id="lng" readonly="readonly" size="20" type="text" value="" />
            </div>
            <div>
                <button type="button">좌표 복사</button>
                <button type="button">원위치</button>
            </div>
        </div>
    </div>
</div>
</body>
</html>

[지도 및 이벤트 설정]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//-----------------------------------------------
// 지도 및 이벤트 설정
//-----------------------------------------------
var _BASE = new naver.maps.LatLng(37.566605, 126.9783931);  // 서울시청
var _ZOOM = 16;     // 지도 표시 레벨
var _list = [];     // 현재 화면에 표시된 마커 목록
var marker1 = null; // 좌표 조회용 마커
 
// 지도 옵션
var mapOptions = {
    center: _BASE,
    zoom: _ZOOM,
    zoomControl: true,      // 확대,축소
    zoomControlOptions:  { position : naver.maps.Position.TOP_RIGHT },
    //logoControlOptions:  { position : naver.maps.Position.BOTTOM_RIGHT }, // 네이버로고
    scaleControl: true,     // 축척
    scaleControlOptions: { position : naver.maps.Position.BOTTOM_RIGHT },
    mapDataControl: false// 저작권
};
 
// 지도 표시
var map = new naver.maps.Map('map', mapOptions);
 
// 지도 이벤트 설정
naver.maps.Event.addListener(map, 'zoom_changed', function(e) {
    if (e > 15) {
        marker1.setMap(map);    // 마커1 표시
    } else {
        marker1.setMap(null);   // 마커1 삭제
    }
});
 
// 마커 목록 삭제
function clearList() {
    $('#list').empty();
}
 
// 마커 목록 표시
function showList() {
    _list.forEach(function(item) {
        showMarkerInfo(item);
    });
     
    _list = [];
}
 
// 현재 위치 표시
showPosition(_BASE);
 
// 위도 경도 표시
function showPosition(latlng) {
    $('#lat').val(latlng.lat());
    $('#lng').val(latlng.lng());
}
 
// 원위치 버튼 클릭
function resetPosition() {
    map.setCenter(_BASE);
    map.setZoom(_ZOOM);
     
    if (marker1) {
        marker1.setPosition(_BASE);
    }
     
    showPosition(_BASE);
    $('#info').val(null);
}
 
// 좌표를 클립보드에 복사
function copyPosition() {
    var info = $('#info');
     
    info.val($('#lat').val() +', '+ $('#lng').val());
     
    info.select();
    document.execCommand('copy');
}
 
// 주소 변경
function changeAddr(code) {
    if (code == '') {
        map.setCenter(_BASE);
    } else {
        showArea(code);
    }
}
 
// 마커1(기본 마커)
marker1 = new naver.maps.Marker({
    position: _BASE,
    map: map,
    zIndex: 200,
    draggable: true,    // 마커1 드래그 허용
});
 
// 마커1 드래그 허용
//marker1.setDraggable(true);
 
// 마커1 드래그 이벤트 설정
naver.maps.Event.addListener(marker1, 'drag', function(e) {
    showPosition(e.coord);
});

[마커 데이터]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//-----------------------------------------------
// 마커 데이터
//-----------------------------------------------
var options = [
    { pos: [ 37.5675575, 126.9778996 ], info: "code: '1001', name: '1001 사무실'", type: '사무실' },
    { pos: [ 37.5674628, 126.9777064 ], info: "code: '1002', name: '1002 사무실'", type: '사무실' },
    { pos: [ 37.56749,   126.9779417 ], info: "code: '1003', name: '1003 사무실'", type: '사무실' },
    { pos: [ 37.5673746, 126.9778567 ], info: "code: '1004', name: '1004 사무실'", type: '사무실' },
    { pos: [ 37.5671748, 126.9780283 ], info: "code: '1005', name: '1005 사무실'", type: '사무실' },
    { pos: [ 37.5679912, 126.9779639 ], info: "code: '1006', name: '1006 사무실'", type: '사무실' },
    { pos: [ 37.567515,  126.9781677 ], info: "code: '1007', name: '1007 사무실'", type: '사무실' },
     
    { pos: [ 37.5696834, 126.980453  ], info: "code: '1011', name: '1011 사무실'", type: '사무실' },
    { pos: [ 37.5698195, 126.9811396 ], info: "code: '1012', name: '1012 사무실'", type: '사무실' },
    { pos: [ 37.5693093, 126.9813327 ], info: "code: '1013', name: '1013 사무실'", type: '사무실' },
     
    { pos: [ 37.5698535, 126.9739299 ], info: "code: '1021', name: '1021 공실'", type: '공실' },
    { pos: [ 37.56976,   126.9731896 ], info: "code: '1022', name: '1022 공실'", type: '공실' },
     
    { pos: [ 37.5683143, 126.9765907 ], info: "code: '1031', name: '1031 호텔'", type: '호텔' },
    { pos: [ 37.5685609, 126.9760328 ], info: "code: '1032', name: '1032 호텔'", type: '호텔' },
    { pos: [ 37.5686204, 126.9764405 ], info: "code: '1033', name: '1033 호텔'", type: '호텔' },
    { pos: [ 37.5680676, 126.9758611 ], info: "code: '1034', name: '1034 호텔'", type: '호텔' },
    { pos: [ 37.5679315, 126.9765048 ], info: "code: '1035', name: '1035 호텔'", type: '호텔' },
     
    { pos: [ 37.5670727, 126.9817405 ], info: "code: '1041', name: '1041 맛집'", type: '맛집' },
    { pos: [ 37.5677275, 126.9823842 ], info: "code: '1042', name: '1042 맛집'", type: '맛집' },
    { pos: [ 37.5678721, 126.9819122 ], info: "code: '1043', name: '1043 맛집'", type: '맛집' },
     
    { pos: [ 37.5643939, 126.9755392 ], info: "code: '1051', name: '1051 공공기관'", type: '공공기관' },
    { pos: [ 37.5643939, 126.9750028 ], info: "code: '1052', name: '1052 공공기관'", type: '공공기관' },
     
    { pos: [ 37.5649382, 126.9818692 ], info: "code: '1061', name: '1061 쇼핑'", type: '쇼핑' },
    { pos: [ 37.5647001, 126.9830279 ], info: "code: '1062', name: '1062 쇼핑'", type: '쇼핑' },
    { pos: [ 37.5647001, 126.9838862 ], info: "code: '1063', name: '1063 쇼핑'", type: '쇼핑' },
    { pos: [ 37.5651763, 126.9813972 ], info: "code: '1064', name: '1064 쇼핑'", type: '쇼핑' },
    { pos: [ 37.5651678, 126.983146  ], info: "code: '1065', name: '1065 쇼핑'", type: '쇼핑' },
    { pos: [ 37.5653294, 126.9837575 ], info: "code: '1066', name: '1066 쇼핑'", type: '쇼핑' },
     
    { pos: [ 37.5657886, 126.9713335 ], info: "code: '1071', name: '1071 학교'", type: '학교' },
    { pos: [ 37.5661118, 126.9706469 ], info: "code: '1072', name: '1072 학교'", type: '학교' },
    { pos: [ 37.5656355, 126.9718056 ], info: "code: '1073', name: '1073 학교'", type: '학교' },
     
    { pos: [ 37.5694623, 126.9856243 ], info: "code: '1081', name: '1081 은행'", type: '은행' },
    { pos: [ 37.5693178, 126.9850128 ], info: "code: '1082', name: '1082 은행'", type: '은행' },
    { pos: [ 37.5695133, 126.9862465 ], info: "code: '1083', name: '1083 은행'", type: '은행' },
    { pos: [ 37.568782,  126.9859676 ], info: "code: '1084', name: '1084 은행'", type: '은행' },
];

[마커 등록 및 이벤트 설정]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//-----------------------------------------------
// 마커 등록 및 이벤트 설정
//-----------------------------------------------
var markers = [];
 
for (var i = 0, ii = options.length; i &lt; ii; i++) {
    // info, text 속성을 넣기 위해 HTML 마커 사용
    markers.push(new naver.maps.Marker({
        position: new naver.maps.LatLng(options[i].pos[0], options[i].pos[1]),
        zIndex: 100,
        icon: {
            content: '',
            anchor: new naver.maps.Point(11, 33),
        }
    }));
}
 
// 마커 클릭 이벤트 설정
for (var i = 0, ii = markers.length; i < ii; i++) {
    naver.maps.Event.addListener(markers[i], 'click', getClickHandler(i));
}
 
// 마커 클릭 이벤트
function getClickHandler(seq) {
    return function(e) {
        clearList();
        showMarkerInfo(markers[seq]);
    }
}
 
// html 속성값을 json 변환
function attr2json(attr) {
    var json = {};
    var s = attr.trim().split(',');
     
    for (var i = 0, ii = s.length; i &lt; ii; i++) {
        var a = s[i].split(':');
        json[a[0].trim()] = a[1].trim().replace(/''/g,'');
    }
     
    return json;
}

[클러스터 마커 생성, 변경]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//-----------------------------------------------
// 클러스터 마커 생성, 변경
//-----------------------------------------------
// 클러스터 마커 생성(HTML 마커)
function newMarker(radius, count, name) {
    var cvs = document.createElement('canvas');
     
    return changeMarker(cvs, radius, count, name);
}
 
// 클러스터 마커 변경(HTML 마커)
function changeMarker(cvs, radius, count, name) {
    cvs.width = radius * 2;
    cvs.height = radius * 2;
 
    var ctx = cvs.getContext('2d');
     
    // 원 표시
    ctx.beginPath();
 
    ctx.arc(radius, radius, radius, 0, Math.PI * 2);
    ctx.fillStyle = 'rgba(3, 133, 255, 0.5)';   //#0385ff
    //ctx.fillStyle = hex2rgba(fillColor, fillOpacity);
    ctx.fill();
 
    ctx.closePath();
     
    // 텍스트 표시
    ctx.textAlign = 'center';
    ctx.fillStyle = 'white';            // text color
     
    if (name != null) {
        ctx.font = '16px dotum bold';
        ctx.fillText(name, radius, radius - 4);
        y = radius + 20 - 4;
    } else {
        ctx.textBaseline = 'middle';    // 텍스트가 1줄일 경우 사용
        y = radius;
    }
     
    if (count != null) {
        ctx.font = '20px dotum bold';
        ctx.fillText(count, radius, y);
    }
 
    return {
        content: cvs,
        anchor: naver.maps.Point(radius, radius),
    }
}

[클러스터 마커 설정]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//-----------------------------------------------
// 클러스터 마커 설정
//-----------------------------------------------
var cMarker1 = newMarker(50, 'm1', 0);
var cMarker2 = newMarker(50, 'm2', 0);
var cMarker3 = newMarker(50, 'm3', 0);
 
// 마커 클러스터링
var markerClustering = new MarkerClustering({
    minClusterSize: 2,                      // 클러스터 마커를 표시할 최소 마커 개수
    maxZoom: 17,                            // 최대 지도 확대 레벨(maxZoom &gt; map zoom, 클러스터 마커 표시)
    map: map,                               // 클러스터 마커 표시할 지도
    markers: markers,                       // 클러스터 마커에서 사용할 마커 목록
    disableClickZoom: true,                 // 클러스터 마커 클릭 시 지도 확대여부
    //averageCenter: true,                  // 마커들의 중간 좌표를 계산하여 클러스터 마커 표시여부
    gridSize: 100,                          // 클러스터 마커 그리드 크기(단위: 픽셀)
    icons: [cMarker1, cMarker2, cMarker3],  // 클러스터 마커용 아이콘
    indexGenerator: [10, 50, 100],          // 아이콘 표시용 마커 개수 설정
    stylingFunction: function(clusterMarker, count, name) { // 클러스터 마커 갱신 시 호출
        _list = _list.concat(members);
         
        var radius = getRadius(count);
         
        // 클러스터 마커 표시
        clusterMarker.setIcon(newMarker(radius, count, name));
         
        // 클러스터 마커 이벤트 설정
        naver.maps.Event.addListener(clusterMarker, 'mouseover', function(e) {
            var cvs = clusterMarker.getIcon().content;
            clusterMarker.setIcon(changeMarker(cvs, radius + 15, count, name));
        });
 
        naver.maps.Event.addListener(clusterMarker, 'mouseout', function(e) {  
            var cvs = clusterMarker.getIcon().content;
            clusterMarker.setIcon(changeMarker(cvs, radius, count, name));
        });
         
        naver.maps.Event.addListener(clusterMarker, 'click', function(e) {
            clearList();
             
            members.forEach(function(item) {
                showMarkerInfo(item);
            });
        });
    }
});
 
// 마커 개수에 따라 반지름 변경
function getRadius(c) {
    var r = 50;
     
    switch (true) {
        case (c <  3): r = 30; break;
        case (c <  5): r = 40; break;
        case (c < 10): r = 50; break;
        case (c < 20): r = 60; break;
        case (c < 50): r = 70; break;
        case (c <100): r = 80; break;
    }
     
    return r;
}
 
// 마커 info 속성 표시
function showMarkerInfo(marker) {
    var info = $(marker.getIcon().content).attr('info');
    var json = attr2json(info);
    $('#list').append('마커 : code = '+ json.code +', name = '+ json.name +'');
}

[MarkerClustering.js 수정 부분]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//-----------------------------------------------
// MarkerClustering.js 수정 부분
//-----------------------------------------------
    /**
     * 클러스터의 아이콘, 텍스트를 갱신합니다.
     * @private
     */
    _updateClusters: function() {
        var clusters = this._clusters;
         
        clearList();    //추가
         
        for (var i = 0, ii = clusters.length; i < ii; i++) {
            clusters[i].updateCluster();
        }
         
        showList();     //추가
    },
     
    /**
     * 클러스터를 구성하는 마커 수를 갱신합니다.
     */
    updateCount: function() {
        var stylingFunction = this._markerClusterer.getStylingFunction();
         
        //추가
        var name = null;
         
        if (this._clusterMember.length > 0) {
            var cZoom = this._markerClusterer.getMaxZoom();
            var mZoom = this._markerClusterer.getMap().getZoom();
         
            //지도의 줌 레벨이 클러스터 마커 표시 최대 레벨일 때만 명칭 표시
            if (cZoom - 1 == mZoom) {
                //첫번째 HTML 마커의 text 속성 조회
                //문제점: 마커의 명칭이 여러 종류일 경우 명칭 표기에 혼선
                name = $(this._clusterMember[0].getIcon().content).attr('text');
            }
        }
        //추가
         
        stylingFunction && stylingFunction(this._clusterMarker, this.getCount(), name, this._clusterMember);    //추가
    },

[참고]

https://github.com/navermaps/marker-tools.js

네이버 지도 마커에 원 도형과 텍스트를 함께 표시하기 위해 사용자 정의 오버레이를 사용해보자.

 

[사용자 정의 오버레이 설정]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//--------------------------------------
// 사용자 정의 오버레이 설정
//--------------------------------------
// 사용자 정의 오버레이
var CustomOverlay = function(options) {
    this._element = $('');
     
    this._code = options.code || null;
    this._position = options.position;
    this._radius = options.radius || 50;
    this._fillColor = options.fillColor || '#0385ff';
    this._fillOpacity = options.fillOpacity || 0.6;
    this._strokeColor = options.strokeColor || '#0385ff';
    this._strokeOpacity = options.strokeOpacity || 0.6;
    this._strokeWeight = 1;
     
    this._textColor = options.textColor || 'white';
};
 
// CustomOverlay는 OverlayView를 상속받습니다.
CustomOverlay.prototype = new naver.maps.OverlayView();
CustomOverlay.prototype.constructor = CustomOverlay;

[필수 메소드 재정의] onAdd(), onRemove(), draw()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//--------------------------------------
// 필수 메소드 재정의
//--------------------------------------
CustomOverlay.prototype.onAdd = function() {
    // 오버레이 표시 레이어(floatPane(정보 레이어, 상단)/overlayImage(마커 레이어, 중단)/overlayLayer(도형 레이어, 하단)
    var overlayLayer = this.getPanes().floatPane;
     
    this._element.appendTo(overlayLayer);
};
 
CustomOverlay.prototype.draw = function() {
    // 지도 객체가 설정되지 않았으면 draw 기능을 하지 않습니다.
    if (!this.getMap()) {
        return;
    }
 
    // projection 객체를 통해 LatLng 좌표를 화면 좌표로 변경합니다.
    var projection = this.getProjection();
    var position = this.getPosition();
    var pixelPosition = projection.fromCoordToOffset(position);
     
    var radius = this._radius;
     
    this._element.css('left', pixelPosition.x - radius);
    this._element.css('top', pixelPosition.y - radius);
     
    var cvs = this._element[0];
    cvs.width = radius * 2;
    cvs.height = radius * 2;
     
    var ctx = cvs.getContext('2d');
     
    // 원 그리기
    ctx.beginPath();
     
    ctx.arc(radius, radius, radius - this._strokeWeight, 0, Math.PI * 2);   // 반지름 = radius - this._strokeWeight
    ctx.fillStyle = hex2rgba(this._fillColor, this._fillOpacity);   //rgba(3, 133, 255, 0.5) #0385ff
    ctx.fill();
     
    ctx.lineWidth = this._strokeWeight;         // 기본값: lineWidth = 1
    ctx.strokeStyle = hex2rgba(this._strokeColor, this._strokeOpacity); //기본값: strokeStyle = '#000000'
    ctx.stroke();
     
    ctx.closePath();
     
    // 원 내부에 텍스트 표시
    ctx.textAlign = 'center';
    //ctx.textBaseline = 'middle';                      // 텍스트가 1줄일 경우 사용
    ctx.fillStyle = hex2rgba(this._textColor, null);    // text color
    ctx.font = '14px dotum bold';
    ctx.fillText(this._code.name, radius, radius - 4);      // 글꼴의 크기에 따라 세로 출력 위치 조정
    ctx.font = '20px dotum bold';
    ctx.fillText(this._code.count, radius, radius + 20 - 4);    // 글꼴의 크기에 따라 세로 출력 위치 조정
};
 
CustomOverlay.prototype.onRemove = function() {
    this._element.remove();
     
    // 이벤트 핸들러를 설정했다면 정리합니다.
    this._element.off();
};

[속성 메소드 정의]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//--------------------------------------
// 속성 메소드 정의
//--------------------------------------
CustomOverlay.prototype.getCode = function() {
    return this._code;
};
 
CustomOverlay.prototype.setCode = function(code) {
    this._code = code;
};
 
CustomOverlay.prototype.getPosition = function() {
    return this._position;
};
 
CustomOverlay.prototype.setPosition = function(position) {
    this._position = position;
};
 
CustomOverlay.prototype.getRadius = function() {
    return this._radius;
};
 
CustomOverlay.prototype.setRadius = function(radius) {
    this._radius = radius;
};
 
CustomOverlay.prototype.getFillColor = function() {
    return this._fillColor;
};
 
CustomOverlay.prototype.setFillColor = function(color) {
    this._fillColor = color;
};

[hex to rgb, colorname to hex]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//--------------------------------------
// hex to rgb, colorname to hex
//--------------------------------------
// 색깔코드를 rgba로 변경(color, opacity)
function hex2rgba(c, o) {
    if (c.charAt(0) == '#') {
        c = c.substr(1);
    } else {
        return colorName2Hex(c);    //색깔명 사용할 경우 opacity 무시
    }
     
    if (o == null || o > 1.0 || o < 0) o = 1.0;
     
    if (c.length == 3) {
        c = c.substr(0,1) + c.substr(0,1) + c.substr(1,2) + c.substr(1,2) + c.substr(2,3) + c.substr(2,3);
    }
     
    var r = c.charAt(0) + '' + c.charAt(1); r = parseInt(r, 16);
    var g = c.charAt(2) + '' + c.charAt(3); g = parseInt(g, 16);
    var b = c.charAt(4) + '' + c.charAt(5); b = parseInt(b, 16);
     
    return 'rgba(' + r + ',' + g + ',' + b + ','+ o +')';
}
 
// 색깔명을 색깔코드로 변경
function colorName2Hex(color) {
    var colors = {"aliceblue":"#f0f8ff","antiquewhite":"#faebd7","aqua":"#00ffff","aquamarine":"#7fffd4","azure":"#f0ffff",
    "beige":"#f5f5dc","bisque":"#ffe4c4","black":"#000000","blanchedalmond":"#ffebcd","blue":"#0000ff","blueviolet":"#8a2be2","brown":"#a52a2a","burlywood":"#deb887",
    "cadetblue":"#5f9ea0","chartreuse":"#7fff00","chocolate":"#d2691e","coral":"#ff7f50","cornflowerblue":"#6495ed","cornsilk":"#fff8dc","crimson":"#dc143c","cyan":"#00ffff",
    "darkblue":"#00008b","darkcyan":"#008b8b","darkgoldenrod":"#b8860b","darkgray":"#a9a9a9","darkgreen":"#006400","darkkhaki":"#bdb76b","darkmagenta":"#8b008b","darkolivegreen":"#556b2f",
    "darkorange":"#ff8c00","darkorchid":"#9932cc","darkred":"#8b0000","darksalmon":"#e9967a","darkseagreen":"#8fbc8f","darkslateblue":"#483d8b","darkslategray":"#2f4f4f","darkturquoise":"#00ced1",
    "darkviolet":"#9400d3","deeppink":"#ff1493","deepskyblue":"#00bfff","dimgray":"#696969","dodgerblue":"#1e90ff",
    "firebrick":"#b22222","floralwhite":"#fffaf0","forestgreen":"#228b22","fuchsia":"#ff00ff",
    "gainsboro":"#dcdcdc","ghostwhite":"#f8f8ff","gold":"#ffd700","goldenrod":"#daa520","gray":"#808080","green":"#008000","greenyellow":"#adff2f",
    "honeydew":"#f0fff0","hotpink":"#ff69b4",
    "indianred ":"#cd5c5c","indigo":"#4b0082","ivory":"#fffff0","khaki":"#f0e68c",
    "lavender":"#e6e6fa","lavenderblush":"#fff0f5","lawngreen":"#7cfc00","lemonchiffon":"#fffacd","lightblue":"#add8e6","lightcoral":"#f08080","lightcyan":"#e0ffff","lightgoldenrodyellow":"#fafad2",
    "lightgrey":"#d3d3d3","lightgreen":"#90ee90","lightpink":"#ffb6c1","lightsalmon":"#ffa07a","lightseagreen":"#20b2aa","lightskyblue":"#87cefa","lightslategray":"#778899","lightsteelblue":"#b0c4de",
    "lightyellow":"#ffffe0","lime":"#00ff00","limegreen":"#32cd32","linen":"#faf0e6",
    "magenta":"#ff00ff","maroon":"#800000","mediumaquamarine":"#66cdaa","mediumblue":"#0000cd","mediumorchid":"#ba55d3","mediumpurple":"#9370d8","mediumseagreen":"#3cb371","mediumslateblue":"#7b68ee",
    "mediumspringgreen":"#00fa9a","mediumturquoise":"#48d1cc","mediumvioletred":"#c71585","midnightblue":"#191970","mintcream":"#f5fffa","mistyrose":"#ffe4e1","moccasin":"#ffe4b5",
    "navajowhite":"#ffdead","navy":"#000080",
    "oldlace":"#fdf5e6","olive":"#808000","olivedrab":"#6b8e23","orange":"#ffa500","orangered":"#ff4500","orchid":"#da70d6",
    "palegoldenrod":"#eee8aa","palegreen":"#98fb98","paleturquoise":"#afeeee","palevioletred":"#d87093","papayawhip":"#ffefd5","peachpuff":"#ffdab9","peru":"#cd853f","pink":"#ffc0cb","plum":"#dda0dd","powderblue":"#b0e0e6","purple":"#800080",
    "rebeccapurple":"#663399","red":"#ff0000","rosybrown":"#bc8f8f","royalblue":"#4169e1",
    "saddlebrown":"#8b4513","salmon":"#fa8072","sandybrown":"#f4a460","seagreen":"#2e8b57","seashell":"#fff5ee","sienna":"#a0522d","silver":"#c0c0c0","skyblue":"#87ceeb","slateblue":"#6a5acd","slategray":"#708090","snow":"#fffafa","springgreen":"#00ff7f","steelblue":"#4682b4",
    "tan":"#d2b48c","teal":"#008080","thistle":"#d8bfd8","tomato":"#ff6347","turquoise":"#40e0d0",
    "violet":"#ee82ee",
    "wheat":"#f5deb3","white":"#ffffff","whitesmoke":"#f5f5f5",
    "yellow":"#ffff00","yellowgreen":"#9acd32"};
 
    if (typeof colors[color.toLowerCase()] != 'undefined')
        return colors[color.toLowerCase()];
 
    return false;
}

[오버레이 표시 및 이벤트 설정]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//--------------------------------------
// 오버레이 표시 및 이벤트 설정
//--------------------------------------
var options = [
    { position: TEST1, radius: 50, code: { name: '숙소',   count: '5',  city: '11', sig: '11290', emd: '11200104', text: '테스트1' } },
    { position: TEST2, radius: 50, code: { name: '사무실', count: '99', city: '11', sig: '11290', emd: '11200104', text: '테스트2' } },
    { position: TEST3, radius: 50, code: { name: '맛집',   count: '3',  city: '11', sig: '11290', emd: '11200104', text: '테스트3' } },
];
 
var markers = [];
 
// 오버레이 생성
for (var idx in options) {
    markers.push(new CustomOverlay(options[idx]));
}
 
// 오버레이 표시, 이벤트 설정
for (var idx in markers) {
    markers[idx].setMap(map);
     
    markers[idx]._element.on('mouseover', changeRadius(idx, 100));
    markers[idx]._element.on('mouseout',  changeRadius(idx, 50));
    markers[idx]._element.on('click',     clickMarker(idx));
}
 
function changeRadius(idx, r) {
    return function(e) {
        var marker = markers[idx];
        marker.setRadius(r);
        marker.draw();
    }
}
 
function clickMarker(idx) {
    return function(e) {
        console.log(markers[idx].getCode());
    }
}

[참고]

https://navermaps.github.io/maps.js.ncp/docs/naver.maps.OverlayView.html

https://navermaps.github.io/maps.js.ncp/docs/tutorial-6-CustomOverlay.html

https://navermaps.github.io/maps.js.ncp/docs/tutorial-custom-overlay.example.html

 

준비물: 시도 shp, 시군구 shp, 읍면동 shp

프로그램: mapshaper, QGIS, python 3.9.1

 

국내 행정구역 shp 파일은 용량도 크고 너무 세밀하게 표현된 부분이 많아서

웹에 단순한 행정구역을 표시할 때 용량과 속도 등에서 제약사항이 발생한다.

 

국내 행정구역 shp 파일에서 사용된 좌표계는 GRS80 (EPSG: 5179) 이므로

네이버 지도에서 사용하는 위도와 경도 좌표계 WGS84 (EPSG: 4326)로 변환해야 한다.

 

변환 과정 요약

1. mapshaper 등의 프로그램으로 simplify 과정을 거쳐 단순화(shp ▶ shp)

2. QGIS 등의 프로그램을 이용하여 WGS 84 좌표로 변환(shp ▶ json(geojson))

3. python 등을 이용해 전체 geojson 파일에서 필요한 행정구역 파일로 분할 저장(json ▶ json(geojson))

 

[시군구 geojson 분할 저장] python 3.9.1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//--------------------------------------
// 시군구 geojson 분할 저장
//--------------------------------------
#python 3.9.1
import json
 
#json 파일 읽기
with open('d:\\sig_202005_wgs84.geojson', 'r', encoding='UTF8') as rf:
    geojson = json.load(rf)
 
#시군구 반복
for item in geojson['features']:
    code = item['properties']['SIG_CD']     #행정구역코드
    name = item['properties']['SIG_KOR_NM'] #행정구역명
    item['id'] = code;                      #네이버 지도용 id 설정
 
    #json 파일 저장 경로
    path = 'd:\\sig\\'+ code +'.json'
    print(path +' '+ name)
 
    #json 객체 생성
    geo = dict()
    geo['type'] = 'FeatureCollection'
    geo['features'] = []            #features는 배열
    geo['features'].append(item)
 
    #json 파일 저장
    with open(path, 'w', encoding='UTF8') as wf:
        json.dump(geo, wf, ensure_ascii=False#한글 유니코드 저장 방지

[행정구역 json 파일 로드]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//--------------------------------------
// 행정구역 json 파일 로드
//--------------------------------------
var HOME_PATH = window.HOME_PATH || '.',
    urlPrefix = HOME_PATH +'/data/region',
    urlSuffix = '.json',
    regionGeoJson = [],
    loadCount = 0;
 
// 행정구역 json 파일 로드
naver.maps.Event.once(map, 'init_stylemap', function () {
    for (var i = 1; i < 18; i++) {
        var keyword = i +'';
 
        if (keyword.length === 1) {
            keyword = '0'+ keyword;
        }
 
        $.ajax({
            url: urlPrefix + keyword + urlSuffix,
            success: function(idx) {
                return function(geojson) {
                    regionGeoJson[idx] = geojson;
 
                    loadCount++;
 
                    if (loadCount === 17) {
                        startDataLayer();
                    }
                }
            }(i - 1)
        });
    }
});

[Geojson 파일 형태]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//--------------------------------------
// Geojson 파일 형태
//--------------------------------------
// 툴팁 설정
var tooltip = $('<div style="position: absolute; z-index: 1000; padding: 5px 10px; background-color: #fff; border: solid 2px #000; font-size: 14px; pointer-events: none; display: none;"> </div>');
tooltip.appendTo(map.getPanes().floatPane);
 
// 로드된 행정구역은 아래와 같은 형태
regionGeoJson.push({
    "type": "FeatureCollection",
    "features": [{
        "id": "11140",
        "type": "Feature",
        "properties": {"SIG_CD": "11140", "SIG_ENG_NM": "Jung-gu", "SIG_KOR_NM": "중구"},
        "geometry": {
            "type": "MultiPolygon",
            "coordinates": [[[
                [127.0233653, 37.5719143], [127.0233917, 37.5719073], [127.0235305, 37.5671585], [127.0235359, 37.5669135], [127.0235319, 37.5668462],
                [127.0235326, 37.5668336], [127.0217938, 37.5575103], [127.0217328, 37.5575278], [127.0195773, 37.5574955], [127.0196807, 37.5572629],
                [127.0180939, 37.5568746], [127.0178901, 37.5567028], [127.0162301, 37.5528015], [127.0159829, 37.552589], [127.015938, 37.5525498],
                [127.015858, 37.552471], [127.0089881, 37.5441349], [127.0050173, 37.5461716], [127.0061278, 37.5481932], [127.0046885, 37.5486851],
                [127.0045604, 37.5498499], [127.0043733, 37.5501537], [127.0043557, 37.5501974], [127.0043362, 37.5502112], [127.0042094, 37.5501507],
                [127.0034213, 37.5500195], [127.0028642, 37.5496416], [127.0016841, 37.5500597], [126.9983251, 37.5496954], [126.9944593, 37.547488],
                [126.9787954, 37.5540872], [126.9724082, 37.5548773], [126.96571, 37.5541518], [126.963376, 37.552259], [126.962778, 37.551848],
                [126.9626113, 37.5517331], [126.9623428, 37.5515489], [126.9623691, 37.5516032], [126.962376, 37.5516286], [126.9624048, 37.5516477],
                [126.9623107, 37.55277], [126.9620066, 37.5540349], [126.9619314, 37.554448], [126.9617737, 37.5547951], [126.9617773, 37.554982],
                [126.9619781, 37.5551268], [126.9621418, 37.5555309], [126.9624769, 37.5559106], [126.9627196, 37.5559726], [126.9631727, 37.5565488],
                [126.9633575, 37.5566854], [126.9634369, 37.5568535], [126.9634273, 37.5569479], [126.9634093, 37.5569943], [126.963052, 37.5574148],
                [126.9630411, 37.5580298], [126.9620761, 37.5584566], [126.9615951, 37.5584184], [126.9617358, 37.5588129], [126.961711, 37.5589526],
                [126.9616892, 37.5589824], [126.9616726, 37.5590258], [126.962956, 37.5591763], [126.9632096, 37.5591958], [126.9633065, 37.5592155],
                [126.9668376, 37.561274], [126.9674439, 37.5615089], [126.9681526, 37.5616215], [126.969265, 37.5619273], [126.9694319, 37.5619679],
                [126.9694641, 37.5619758], [126.9693301, 37.5622305], [126.9689586, 37.5629149], [126.967562, 37.5648787], [126.9666982, 37.56582],
                [126.9668651, 37.5659861], [126.9668874, 37.5660078], [126.9966167, 37.5686865], [126.9968368, 37.5687099], [126.997025, 37.5687315],
                [127.0007881, 37.5693806], [127.0013078, 37.5694769], [127.014613, 37.5697183], [127.0147018, 37.5697206], [127.0176066, 37.5702101],
                [127.0177723, 37.5702912], [127.0233653, 37.5719143]
            ]]]
        }
    }]
});

[행정구역 표시]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
//--------------------------------------
// 행정구역 표시
//--------------------------------------
function startDataLayer() {
    map.data.setStyle(function(feature) {
        var styleOptions = {
            fillColor: '#ff0000',
            fillOpacity: 0.0001,
            strokeColor: '#ff0000',
            strokeWeight: 4,
            strokeOpacity: 0.4
        };
 
        if (feature.getProperty('focus')) {
            styleOptions.fillOpacity = 0.6;
            styleOptions.fillColor = '#0f0';
            styleOptions.strokeColor = '#0f0';
            styleOptions.strokeWeight = 4;
            styleOptions.strokeOpacity = 1;
        }
 
        return styleOptions;
    });
 
    regionGeoJson.forEach(function(geojson) {
        map.data.addGeoJson(geojson);
    });
 
    map.data.addListener('click', function(e) {
        var feature = e.feature;
 
        if (feature.getProperty('focus') !== true) {
            feature.setProperty('focus', true);
        } else {
            feature.setProperty('focus', false);
        }
    });
 
    map.data.addListener('mouseover', function(e) {
        var feature = e.feature;
        var regionName = feature.getProperty('SIG_KOR_NM');
 
        tooltip.css({
            display: '',
            left: e.offset.x,
            top: e.offset.y
        }).text(regionName);
 
        map.data.overrideStyle(feature, {
            fillOpacity: 0.6,
            strokeWeight: 4,
            strokeOpacity: 1
        });
    });
 
    map.data.addListener('mouseout', function(e) {
        tooltip.hide().empty();
        map.data.revertStyle();
    });
}
 
startDataLayer();

참고

https://blog.hkwon.me/draw-korean-map-chart-with-geojson/

http://www.gisdeveloper.co.kr/?p=2332

아래의 파일을 업로드

~/styles 폴더의 shCore.css 및 테마(shTheme*.css) 파일
~/scripts 폴더의 shCore.js 및 브러시(shBrush*.js) 파일


HTML head 태그 부분에 아래의 문장 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<head>
    ...
    <link rel="stylesheet" media="screen" type="text/css" href="./images/shCore.css">
    <link rel="stylesheet" media="screen" type="text/css" href="./images/shThemeRDark.css"> //테마
    <script type="text/javascript" src="./images/shCore.js"></script>
    <script type="text/javascript" src="./images/shBrushCss.js"></script>
    <script type="text/javascript" src="./images/shBrushJava.js"></script>
    <script type="text/javascript" src="./images/shBrushJScript.js"></script>
    <script type="text/javascript" src="./images/shBrushCSharp.js"></script>
    <script type="text/javascript" src="./images/shBrushSql.js"></script>
    <script type="text/javascript" src="./images/shBrushXml.js"></script>
    <script type="text/javascript">SyntaxHighlighter.all();</script>
    ...
</head>

사용법

html 편집모드에서
1
2
3
<pre class="brush:언어별 브러시명">
    ... 코드 ...
</pre>

언어별 브러시명 및 사용 js 파일은 아래의 페이지를 참조

언어별 브러시

날짜 관련 유틸리티

Java2018. 10. 23. 14:12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * 지정한 시간(min) 뒤의 시각 반환
 * @param min
 * @return
 */
public static Date addMin(Integer min) {
    Calendar c = Calendar.getInstance();
    c.add(Calendar.MINUTE, min);
    return c.getTime();
}
 
/**
 * 오늘 23:59:59 시각 반환
 * @return
 */
public static Date getTodayMidnight() {
    Calendar c = Calendar.getInstance();
    c.set(c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DATE), 23, 59, 59);
    return c.getTime();
}

윈도우 운영체제에 독립 이클립스 개발환경을 구축하려면 JDK를 인스톨해야 한다.

하지만 윈도우 운영체제에 JDK를 인스톨 없이 이용하고자 한다면 아래와 같이 해보자.


1. 오라클 사이트에서 윈도우용 JDK 8u191 버전을 다운로드 한다.


jdk-8u191-windows-x64.exe


2. 7zip 과 같은 압축 해제 유틸리티로 다운받은 파일을 설치하지 않고 압축을 해제한다.


3. ~/.rsrc/1033/JAVA_CAB10 폴더 안의 111 파일을 오른쪽 버튼을 눌러

'여기에 압축 풀기'를 선택하면 tools.zip 파일이 생긴다.


3.1. tools.zip 파일 압축을 풀어 폴더명을 jdk-8u191-x64 같이 바꿔준다.


3.2. 명령 프롬프트를 실행하여 압축을 푼 폴더로 가서 아래와 같은 명령을 실행한다.


for /r %i in (*.pack) do .\bin\unpack200.exe %i %~pi%~ni.jar


4. ~/.rsrc/1033/JAVA_CAB9 폴더 안의 110 파일을 오른쪽 버튼을 눌러

'여기에 압축 풀기'를 선택하면 src.zip 파일이 생긴다. 3.1.에서 만든 폴더에 넣어준다.


5. ~/.rsrc/1033/JAVA_CAB11 폴더 안의 112 파일을 오른쪽 버튼을 눌러

'여기에 압축 풀기'를 선택하면 COPYRIGHT 파일이 생긴다. 3.1.에서 만든 폴더에 넣어준다.


6.  이 폴더를 이클립스 환경설정에서 사용하면 된다.


출처: http://linux.systemv.pe.kr/windows-jdk-1-8-portable/

'Java' 카테고리의 다른 글

List 다중 컬럼 정렬  (0) 2021.05.21
날짜 관련 유틸리티  (0) 2018.10.23
사진 이미지 크기 변경 후 Base64 문자열 변환  (0) 2018.04.26
POI, Excel 셀 생성  (0) 2015.06.30
POI, Excel 숫자 셀 생성  (0) 2015.06.30

택배 조회 URL

기타2018. 9. 18. 13:29

아래의 택배 배송 조회 URL은


다음 배송조회 화면을 통해서 현재(2018.09.18) 확인된 URL 입니다.


아래 URL은 택배사의 사정에 따라 언제든지 변경될 수 있으니 확인하고 사용하세요.


CJ 대한통운

https://www.doortodoor.co.kr/parcel/doortodoor.do?fsp_action=PARC_ACT_002&fsp_cmd=retrieveInvNoACT&invc_no=운송장번호


우체국택배

https://service.epost.go.kr/trace.RetrieveEmsRigiTraceList.comm?POST_CODE=운송장번호


롯데택배https://www.lotteglogis.com/personalService/tracking/06/tracking_goods_result.jsp?InvNo=운송장번호


로젠택배

http://www.ilogen.com/iLOGEN.Web.New/TRACE/TraceView.aspx?gubun=slipno&slipno=운송장번호


한진택배

http://www.hanjin.co.kr/Delivery_html/inquiry/result_waybill.jsp?wbl_num=운송장번호


드림택배(구KG로지스)

http://www.idreamlogis.com/delivery/delivery_result.jsp?item_no=운송장번호

Angular 5 file upload using primeng fileupload component
1
2
3
4
5
6
7
8
9
10
11
12
13
14
uploadImage(event, fu: FileUpload) {
    // file.name, file.size, file.type, file.objectURL
    const file: File = event.files[0];
    const reader: FileReader = new FileReader();
 
    reader.onloadend = (e) => {
        this.image = reader.result as string;  // Base64 문자열 이미지 데이터 저장
        fu.clear();     // 다시 업로드 가능하게 초기화
    };
 
    if (file) {
        reader.readAsDataURL(file);     // Base64 문자열 변환
    }
}