PageSourceSearch

https://www.fbo.or.kr/js/gis/nearbyTrade.js

js fbo.or.kr collected 2026-10-07 19:42:35 UTC 19,308 bytes, 552 lines download raw bytes

1
2////////////////////////////////// 주변 거래/이슈
3
4const NearByManager = {
5     nearbyTradeChartEvent : function(){
6        const tab4Button = document.getElementById('pop_tab1_btn_04');
7        if (tab4Button) {
8            tab4Button.removeEventListener('click', NearByManager.handleTab4Click);
9            tab4Button.addEventListener('click', NearByManager.handleTab4Click);
10            initNearbyTradeChart();
11        }
12    },
13    initButton : function (){
14        //주변 거래량 변동 토글 초기화
15        const realLndcgrCAllButtons = document.querySelectorAll(".lndcgrC_near");
16        realLndcgrCAllButtons.forEach((button => button.classList.remove('on')));
17        document.getElementById("lndcgrC_nearAll").classList.add("on");
18    },
19    handleTab4Click : function() {
20        showLoading();
21
22        NearByManager.initButton();
23
24        NearByManager.nearbyTradeChange(null);
25        NearByManager.nearbyRealTradeSearchAddList();
26        NearByManager.nearbyFlndSellSearchAddList();
27
28        hideLoading();
29    },
30    /*주변 실거래 파라미터 셋팅*/
31    createNearByTradeParam: function (lndcgrC,paramType) {
32        let info = {
33            "pnu": document.getElementById("pnu").value
34            , "schLndcgrC": lndcgrC
35            , "bizclidType": document.getElementById("bizclidType").value
36        }
37
38        if(paramType === 'sell'){
39            info.currentPageNo = document.getElementById("sellCurrentPageNo").value;
40        }else if(paramType === 'trade'){
41            info.currentPageNo = document.getElementById("tradeCurrentPageNo").value;
42        }
43
44
45        return info;
46    },
47    //주변 거래량 변동
48    nearbyTradeChange : function (lndcgrcode){
49        console.log("nearbyTradeChange");
50        const info = NearByManager.createNearByTradeParam(lndcgrcode,null);
51        info.currentPageNo = 1;
52
53        HttpUtils.post('/gis/nearbyTradeChange.do',info).then((response) => {
54            document.getElementById("nearbyTradeChangeJson").value = response.nearbyTradeChangeJson;
55
56            const nearbyTradeChangeJson = document.getElementById('nearbyTradeChangeJson');
57            const gisVOList = JSON.parse(nearbyTradeChangeJson.value);
58
59            const existingData = {
60                cnrtYm: [],
61                cnrtCntMm: [],
62                cnrtSamtMn: []
63            };
64
65            // 기존 데이터 추출
66            for (const gisVOListElement of gisVOList) {
67                existingData.cnrtYm.push(gisVOListElement.cnrtYm);
68                existingData.cnrtCntMm.push(gisVOListElement.cnrtCntMm || 0);
69                const amountInMillion = (gisVOListElement.cnrtSamtMn || 0) / 1_000_000;
70                existingData.cnrtSamtMn.push(Number(amountInMillion.toFixed(1)));
71            }
72
73            // 전체 월 범위 생성 및 빈 데이터 0으로 채우기
74            const allMonths = generateMonthlyRange();
75            const filledData = fillMissingMonths(existingData, allMonths);
76
77            const chart = updateChart2WithData(filledData);
78            return chart;
79        });
80    },
81    // 현위치 실거래
82    tradeSearchAddList: function (schLndcgrC) {
83        const info = NearByManager.createNearByTradeParam(schLndcgrC,'trade');
84
85        HttpUtils.postHtml('/gis/selectCurrentLocationRealTradeList.do', info).then(response => {
86            document.getElementById("currentRealTradeAddList").innerHTML = response;
87        });
88    },
89    // 주변 실거래
90    nearbyRealTradeSearchAddList: function (schLndcgrC) {
91        const info = NearByManager.createNearByTradeParam(schLndcgrC,'trade');
92
93        // 활성화된 탭에 따라 데이터 로드
94        let nearbyRealTradeAddList = document.getElementById("nearbyRealTradeAddList");
95
96        if(nearbyRealTradeAddList  == null){
97            return;
98        }
99
100        HttpUtils.postHtml('/gis/selectnearbyRealTradeList.do', info).then(response => {
101            if(response.indexOf("홈페이지 서비스 이용 문의") != -1){
102                alert("주변 실거래 내부 오류")
103                return;
104            }
105
106            document.getElementById("nearbyRealTradeAddList").innerHTML = response;
107
108            document.querySelectorAll('.badge[data-lndcgr]').forEach(el => {
109                el.classList.add(GISApp.getLndcgrBadgeClass(el.dataset.lndcgr));
110            });
111
112            waiAriaTab();
113        });
114    },
115    // 주변 거래/이슈 > 주변농지
116    nearbyFlndSellSearchAddList: function (schLndcgrC) {
117
118        console.log("nearbyFlndSellSearchAddList");
119        const info = NearByManager.createNearByTradeParam(schLndcgrC,'sell');
120
121        HttpUtils.postHtml('/gis/selectNearbyFlndSellList.do', info).then(response => {
122            if(response.indexOf("홈페이지 서비스 이용 문의") != -1){
123                alert("주변 거래/이슈 주변농지 내부 오류")
124                return;
125            }
126
127            document.getElementById("nearbyFlndSellAddList").innerHTML = response;
128
129            document.querySelectorAll('.badge[data-lndcgr]').forEach(el => {
130                el.classList.add(GISApp.getLndcgrBadgeClass(el.dataset.lndcgr));
131            });
132
133            let legalnm = document.getElementById("legalnm").value;
134            let addr = document.querySelectorAll("#nearbyFlndSellAddList .board_list .addr");
135
136            // legalnm의 텍스트가 있으면 addr 요소들에서 제거
137            if (legalnm) {
138                addr.forEach(el => {
139                    el.innerText = el.innerText.replace(legalnm, '').trim();
140                });
141            }
142
143            // 툴팁 이벤트 초기화
144            NearByManager.initNearbyTooltips();
145            waiAriaTab();
146        });
147    },
148    // 주변농지 툴팁 이벤트 초기화
149    initNearbyTooltips: function() {
150        const addrElements = document.querySelectorAll("#nearbyFlndSellAddList .board_list .addr[data-full-text]");
151
152        addrElements.forEach(el => {
153            // 기존 이벤트 제거 (중복 방지)
154            el.removeEventListener('mouseenter', el._tooltipEnter);
155            el.removeEventListener('mousemove', el._tooltipMove);
156            el.removeEventListener('mouseleave', el._tooltipLeave);
157
158            // 이벤트 핸들러 저장
159            el._tooltipEnter = function(e) {
160                const tooltip = document.getElementById('customTooltip2');
161                const fullText = this.getAttribute('data-full-text');
162                if (fullText && tooltip) {
163                    tooltip.textContent = fullText;
164                    tooltip.style.display = 'block';
165                    HoverUitls.updateTooltipPosition(e, tooltip);
166                }
167            };
168
169            el._tooltipMove = function(e) {
170                const tooltip = document.getElementById('customTooltip2');
171                if (tooltip && tooltip.style.display === 'block') {
172                    HoverUitls.updateTooltipPosition(e, tooltip);
173                }
174            };
175
176            el._tooltipLeave = function() {
177                const tooltip = document.getElementById('customTooltip2');
178                if (tooltip) {
179                    tooltip.style.display = 'none';
180                }
181            };
182
183            // 이벤트 등록
184            el.addEventListener('mouseenter', el._tooltipEnter);
185            el.addEventListener('mousemove', el._tooltipMove);
186            el.addEventListener('mouseleave', el._tooltipLeave);
187        });
188    },
189    nearbyRealPage: function (currentPageNo) {
190        document.getElementById("tradeCurrentPageNo").value = currentPageNo;
191
192        NearByManager.nearbyRealTradeSearchAddList();
193        return false;
194    },
195    nearbyFlndPage: function (currentPageNo) {
196        document.getElementById("sellCurrentPageNo").value = currentPageNo;
197
198        NearByManager.nearbyFlndSellSearchAddList();
199        return false;
200    }
201
202}
203
204
205function generateMonthlyRange() {
206    const months = [];
207    const currentDate = new Date(2025, 6); // 2025년 7월 (0-based index)
208
209    for (let i = 0; i < 13; i++) { // 13개월 (24.07 ~ 25.07)
210        const date = new Date(currentDate.getFullYear(), currentDate.getMonth() - (12 - i));
211        const year = date.getFullYear().toString().slice(-2);
212        const month = String(date.getMonth() + 1).padStart(2, '0');
213        months.push(`${year}.${month}`);
214    }
215
216    return months;
217}
218
219// 데이터를 전체 월 범위에 맞춰 0으로 채우는 함수
220function fillMissingMonths(existingData, allMonths) {
221    const filledData = {
222        cnrtYm: allMonths,
223        cnrtCntMm: [],
224        cnrtSamtMn: []
225    };
226
227    // 각 월에 대해 데이터가 있으면 사용하고, 없으면 0으로 설정
228    allMonths.forEach(month => {
229        const existingIndex = existingData.cnrtYm ? existingData.cnrtYm.indexOf(month) : -1;
230
231        if (existingIndex !== -1) {
232            filledData.cnrtCntMm.push(existingData.cnrtCntMm[existingIndex] || 0);
233            filledData.cnrtSamtMn.push(existingData.cnrtSamtMn[existingIndex] || 0);
234        } else {
235            filledData.cnrtCntMm.push(0);
236            filledData.cnrtSamtMn.push(0);
237        }
238    });
239
240    // 실제 데이터가 있는지 체크 (0이 아닌 값이 하나라도 있는지 확인)
241    const hasNonZeroData = filledData.cnrtCntMm.some(val => val > 0) ||
242                           filledData.cnrtSamtMn.some(val => val > 0);
243
244    // 0이 아닌 값이 없으면 isEmpty 플래그 추가
245    if (!hasNonZeroData) {
246        filledData.isEmpty = true;
247    }
248
249    return filledData;
250}
251
252// 주변 거래량 변동 차트 데이터
253function getChartDataFromHidden() {
254    try {
255        const nearbyTradeChangeJson = document.getElementById('nearbyTradeChangeJson');
256
257        if (nearbyTradeChangeJson && nearbyTradeChangeJson.value) {
258            const gisVOList = JSON.parse(nearbyTradeChangeJson.value);
259
260            const existingData = {
261                cnrtYm: [],
262                cnrtCntMm: [],
263                cnrtSamtMn: []
264            };
265
266            // 기존 데이터 추출
267            for (const gisVOListElement of gisVOList) {
268                existingData.cnrtYm.push(gisVOListElement.cnrtYm);
269                existingData.cnrtCntMm.push(gisVOListElement.cnrtCntMm || 0);
270                const amountInMillion = (gisVOListElement.cnrtSamtMn || 0) / 1_000_000;
271                existingData.cnrtSamtMn.push(Number(amountInMillion.toFixed(1)));
272            }
273
274            // 전체 월 범위 생성 및 빈 데이터 0으로 채우기
275            const allMonths = generateMonthlyRange();
276            const filledData = fillMissingMonths(existingData, allMonths);
277
278            return filledData;
279
280        } else {
281            // 빈 데이터라도 전체 월 범위는 표시
282            const allMonths = generateMonthlyRange();
283            return {
284                cnrtYm: allMonths,
285                cnrtCntMm: new Array(allMonths.length).fill(0),
286                cnrtSamtMn: new Array(allMonths.length).fill(0),
287                isEmpty: true  // 빈 데이터 플래그
288            };
289        }
290    } catch (e) {
291        console.error('Hidden input 데이터 파싱 오류:', e);
292        console.error('오류 위치:', e.message);
293
294        // 오류 발생 시에도 기본 구조는 유지
295        const allMonths = generateMonthlyRange();
296        return {
297            cnrtYm: allMonths,
298            cnrtCntMm: new Array(allMonths.length).fill(0),
299            cnrtSamtMn: new Array(allMonths.length).fill(0)
300        };
301    }
302}
303
304// 차트 초기화
305function initNearbyTradeChart() {
306    const chart2Div = document.getElementById('chart2');
307
308    if (!chart2Div) {
309        console.warn('chart2 div 요소를 찾을 수 없습니다.');
310        return;
311    }
312
313    if (typeof echarts === 'undefined') {
314        console.warn('echarts 라이브러리가 로드되지 않았습니다.');
315        return;
316    }
317
318    const chartData = getChartDataFromHidden();
319
320    if (chartData) {
321        const chart = updateChart2WithData(chartData);
322        return chart;
323    } else {
324        console.error('차트 데이터 로드 실패');
325        return null;
326    }
327}
328
329// 주변 거래량 변동 차트 그리기
330function updateChart2WithData(chartData) {
331    const chartDom2 = document.getElementById('chart2');
332    if (!chartDom2) {
333        console.error('chart2 DOM 요소를 찾을 수 없습니다.');
334        return;
335    }
336    // 기존 차트 정리
337    if (chartDom2._echarts_instance_) {
338        echarts.dispose(chartDom2);
339    }
340    const chart2 = echarts.init(chartDom2);
341
342    const option = {
343        tooltip: {
344            trigger: 'axis',
345            axisPointer: {
346                type: 'cross',
347                crossStyle: {
348                    color: '#999'
349                }
350            },
351            formatter: function(params) {
352                let result = '20' + params[0].name + '<br/>';
353                params.forEach(function(item) {
354                    if (item.seriesType === 'bar') {
355                        result += item.marker + item.seriesName + ': ' + (item.value || 0) + 'ê±´<br/>';
356                    } else {
357                        result += item.marker + item.seriesName + ': ' + (item.value || 0) + '백만원<br/>';
358                    }
359                });
360                return result;
361            }
362        },
363        legend: {
364            show : true,
365            data: ['거래량', '거래금액'],
366            bottom: 5,
367            textStyle: {
368                fontSize: 10
369            }
370        },
371        grid: {
372            top: '15%',
373            left: '5%',
374            right: '5%',
375            bottom: '20%',
376            containLabel: true
377        },
378        xAxis: [
379            {
380                type: 'category',
381                data: chartData.cnrtYm,
382                axisPointer: {
383                    type: 'shadow'
384                },
385                axisLabel: {
386                    fontSize: 9
387                }
388            }
389        ],
390        yAxis: [
391            {
392                type: 'value',
393                name: '(ê±´)',
394                position: 'left',
395                alignTicks: true,
396                axisLabel: {
397                    formatter: '{value}',
398                    color: '#000000'
399                },
400                splitLine: {
401                    show: false,
402                    lineStyle: {
403                        type: 'dashed',
404                        opacity: 0.3
405                    }
406                }
407            },
408            {
409                type: 'value',
410                name: '(백만원)',
411                position: 'right',
412                alignTicks: true,
413                axisLabel: {
414                    formatter: '{value}',
415                    color: '#000000'
416                },
417            }
418        ],
419        series: [
420            {
421                name: '거래량',
422                type: 'bar',
423                yAxisIndex: 0,
424                data: chartData.cnrtCntMm,
425                itemStyle: {
426                    color: '#00b2ff',
427                    borderRadius: [2, 4, 0, 0] // 모서리 둥글게
428                },
429                barWidth: '50%',
430                emphasis: {
431                    itemStyle: {
432                        color: '#00b2ff',
433                        shadowBlur: 10,
434                        shadowColor: 'rgba(0, 0, 0, 0.3)'
435                    }
436                },
437            },
438            {
439                name: '거래금액',
440                type: 'line',
441                yAxisIndex: 1,
442                data: chartData.cnrtSamtMn,
443                lineStyle: {
444                    color: '#F5A623',
445                    width: 2
446                },
447                itemStyle: {
448                    color: '#F5A623',
449                    borderWidth: 0,
450                    borderColor: '#fff',
451                    shadowBlur: 5,
452                    shadowColor: 'rgba(245, 166, 35, 0.3)'
453                },
454                symbol: 'circle',
455                symbolSize: 10,
456                smooth: false,
457                // 라인 위에 값 표시
458                label: {
459                    show: false,
460                    formatter: function(params) {
461                        return params.value > 0 ? params.value : '';
462                    },
463                    fontSize: 10,
464                    color: '#F5A623'
465                }
466            }
467        ],
468        // 빈 데이터일 때 메시지 표시
469        /*graphic: chartData.isEmpty ? [
470            {
471                type: 'rect',
472                left: 0,
473                top: 0,
474                shape: {
475                    width: 9999,
476                    height: 9999
477                },
478                style: {
479                    fill: 'rgba(255, 255, 255, 0.85)'
480                },
481                z: 98
482            },
483            {
484                type: 'rect',
485                left: 'center',
486                top: 'middle',
487                shape: {
488                    width: 350,
489                    height: 80
490                },
491                style: {
492                    fill: 'rgba(255, 255, 255, 0.95)',
493                    stroke: '#e0e0e0',
494                    lineWidth: 1,
495                    shadowBlur: 40,
496                    shadowColor: 'rgba(0, 0, 0, 0.25)',
497                    shadowOffsetX: 0,
498                    shadowOffsetY: 3
499                },
500                z: 99
501            },
502            {
503                type: 'text',
504                left: 'center',
505                top: 'middle',
506                style: {
507                    text: '거래량 변동이 존재하지 않습니다',
508                    fontSize: 16,
509                    fontWeight: 'bold',
510                    fill: '#666',
511                    textAlign: 'center'
512                },
513                z: 100
514            }
515        ] : [],*/
516        // 애니메이션 효과
517        animationDuration: 1500,
518        animationEasing: 'cubicOut'
519    };
520
521    chart2.setOption(option, true); // true로 설정하여 기존 옵션 완전 교체
522
523    chart2.setOption(option, {
524        notMerge: true,  // 기존 옵션과 병합하지 않고 완전 교체
525        replaceMerge: ['series'], // series 완전 교체
526        silent: false    // 이벤트 발생 허용
527    });
528
529    setTimeout(function() {
530        if (chart2 && !chart2.isDisposed()) {
531            chart2.resize();
532            console.log('차트 리사이즈 완료');
533        }
534    }, 100);
535
536    // 반응형 처리
537    const resizeHandler = function() {
538        if (chart2 && !chart2.isDisposed()) {
539            chart2.resize();
540        }
541    };
542
543    // 기존 리스너 제거 후 새로 등록
544    window.removeEventListener('resize', resizeHandler);
545    window.addEventListener('resize', resizeHandler);
546
547    return chart2;
548}
549
550
551
552

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.