{"id":19865293,"url":"https://github.com/mnms/population","last_synced_at":"2025-06-14T12:06:41.156Z","repository":{"id":43826813,"uuid":"419193551","full_name":"mnms/population","owner":"mnms","description":"Visualization of the floating population","archived":false,"fork":false,"pushed_at":"2022-05-30T07:08:05.000Z","size":5067,"stargazers_count":0,"open_issues_count":8,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-29T20:47:15.429Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mnms.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-10-20T05:12:22.000Z","updated_at":"2021-12-23T01:27:23.000Z","dependencies_parsed_at":"2022-09-19T20:30:29.263Z","dependency_job_id":null,"html_url":"https://github.com/mnms/population","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mnms/population","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnms%2Fpopulation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnms%2Fpopulation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnms%2Fpopulation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnms%2Fpopulation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mnms","download_url":"https://codeload.github.com/mnms/population/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mnms%2Fpopulation/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259813014,"owners_count":22915199,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T15:22:05.639Z","updated_at":"2025-06-14T12:06:41.139Z","avatar_url":"https://github.com/mnms.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# population\nVisualization of the floating population\n\n\n## 환경설정 (개발 툴 포함)\n```\n- java v1.8 \n- node.js v12.16.2\n- npm v6.14.4\n- VS Code 또는 그외 Frontend 개발 툴\n- Spring Tool Suite 4 \n```\n\n## 프로젝트 기본 구성\n```\n  * 전체\n      frontend  // Client 웹 서비스 (node, npm, react 구성)\n      src       // backend 서비스 : java class (로그인 처리)\n      pom.xml   // maven dependencies : springframework 사용\n  \n  * Frontend (React App 기본 구성)\n      external          // Vector Tile 서비스 시 필요한 라이브러리\n      node_external     // node_module 관련 별도 커스텀한 라이브러리\n      public\n      src               // Web 로직\n        component\n          AuthenticatedRoute.jsx    // 로그인 인증 처리\n          InstructorApp.jsx         // 페이지 라우터 처리\n          LoginComponent.jsx        // 로그인 컴포넌트\n          LogoutComponent.jsx       // 로그아웃 컴포넌트\n          MenuComponent.jsx         // 최상단Bar 메뉴 컴포넌트\n          MainComponent.jsx         // 지도/차트 영역 컴포넌트\n          MapScript.js              // 지도기능 스크립트\n          ChartScript.js            // 차트기등 스크립트\n        css\n        js\n        redux                       // react-redux 사용 (상태 값 저장)\n        service\n          AuthenticationService.js  // 로그인 페이지에서 로그인 시 backend 통신 및 인증 처리 확인\n          CustomFunc.js             // 지도/차트 기능에 필요한 함수들\n        App.css                     // 커스텀 css 포함\n        App.js\n        index.css\n        index.js\n        server.json                 // HTTP API 서버에 Connect 하기 위한 정보\n        serviceWorker.js\n      package.json                  // npm, node 관련 설정\n      \n```\n\n## 빌드 및 실행\n### 1) npm 사용\n\n\nFrontend 실행 : cd /root/population/frontend\n\n```\n- 실행\n$ cd frontend\n$ npm start\n\n- 빌드\n$ cd frontend\n$ npm run build\n\n* 개발 환경 시\n  - package.json =\u003e \"proxy\": \"http://localhost:8066\" 옵션 확인. (server port와 맞는지 확인)\n```\n\nbackend 실행 : spring boot tool 사용\n\n```\n- resources/application.properties 확인\n   - H2 DB 경로 설정 변경 : spring.datasource.url -\u003e {로컬 경로}\n   - default port : 8066 (server.port 옵션으로 변경 가능) \n\n- 실행\n  - population 프로젝트 =\u003e Spring Boot App으로 실행\n\n- 빌드\n  - maven build -\u003e mvn clean install\n  - target 폴더 확인\n```\n\n\n### 2) jar 사용\n\n\n1. jar 배포 및 실행\n\n```\n - 배포할 특정 디렉토리 생성.\n - mvn build 한 target 폴더의 모든 파일 복사.\n - $ java -jar population-0.0.1-SNAPSHOT.jar 명령어로 실행\n - http://localhost:8066 URL로 정상 동작 확인\n```\n\n2. git clone 및 serve 방법\n\n```\n $ git clone https://github.com/bbbbbra/population.git\n $ cd population/frontend\n $ npm install\n $ npm run build\n $ serve -l 8066 -s build\n - http://localhost:8066 URL로 정상 동작 확인\n```\n\n## HTTP API 서버 설정 확인\n\n* VectorTile 및 Chart 데이터를 가져오기 위한 접속 정보\n\n```\n  경로 : cd population/frontend/src\n  접속정보 : server.json 파일 확인\n  \n  {\n    \"user\": \"ltdb\",\n    \"password\": \"ltdb\",\n    \"database\": \"default\",\n    \"protocol\": \"http\",\n    \"host\": \"fbg01\",\n    \"port\": [4762, 4763, 4764, 4765, 4766, 4767, 4768, 4769, 4770, 4771, 4772, 4773]\n  }\n  \n```\n\n## HTTP API 사용하기 위한 관련 테이블 정보\n  \n  * 테이블 DDL CREATE 관련해서는 HTTP API 서버 README 참고.\n  \n```\n  * ltdb_fp 테이블 : 유동인구 데이터 (지도/차트 구현 시 사용)\n  \n  CREATE table ltdb_fp (\n    adm_code string,\n    x double,\n    y double,\n    recordid integer,\n    block_cd long,\n    exist_m_00 double,\n    exist_m_10 double,\n    exist_m_20 double,\n    exist_m_30 double,\n    exist_m_40 double,\n    exist_m_50 double,\n    exist_m_60 double,\n    exist_m_70 double,\n    exist_m_80 double,\n    exist_m_90 double,\n    exist_f_00 double,\n    exist_f_10 double,\n    exist_f_20 double,\n    exist_f_30 double,\n    exist_f_40 double,\n    exist_f_50 double,\n    exist_f_60 double,\n    exist_f_70 double,\n    exist_f_80 double,\n    exist_f_90 double,\n    home_m_00 double,\n    home_m_10 double,\n    home_m_20 double,\n    home_m_30 double,\n    home_m_40 double,\n    home_m_50 double,\n    home_m_60 double,\n    home_m_70 double,\n    home_m_80 double,\n    home_m_90 double,\n    home_f_00 double,\n    home_f_10 double,\n    home_f_20 double,\n    home_f_30 double,\n    home_f_40 double,\n    home_f_50 double,\n    home_f_60 double,\n    home_f_70 double,\n    home_f_80 double,\n    home_f_90 double,\n    work_m_00 double,\n    work_m_10 double,\n    work_m_20 double,\n    work_m_30 double,\n    work_m_40 double,\n    work_m_50 double,\n    work_m_60 double,\n    work_m_70 double,\n    work_m_80 double,\n    work_m_90 double,\n    work_f_00 double,\n    work_f_10 double,\n    work_f_20 double,\n    work_f_30 double,\n    work_f_40 double,\n    work_f_50 double,\n    work_f_60 double,\n    work_f_70 double,\n    work_f_80 double,\n    work_f_90 double,\n    in_m_00 double,\n    in_m_10 double,\n    in_m_20 double,\n    in_m_30 double,\n    in_m_40 double,\n    in_m_50 double,\n    in_m_60 double,\n    in_m_70 double,\n    in_m_80 double,\n    in_m_90 double,\n    in_f_00 double,\n    in_f_10 double,\n    in_f_20 double,\n    in_f_30 double,\n    in_f_40 double,\n    in_f_50 double,\n    in_f_60 double,\n    in_f_70 double,\n    in_f_80 double,\n    in_f_90 double,\n    geohash string,\n    geometry string,\n    event_time string\n    )\n    USING r2 OPTIONS\n    (\n    table '900',\n    host 'fbg02',\n    port '18900',\n    partitions 'event_time geohash',\n    mode 'nvkvs',\n    rowstore 'false',\n    at_least_one_partition_enabled 'no',\n    group_query_enabled 'yes',\n    geometry_type 'point'\n  )\n\n\n  * ltdb_fp_history 테이블 : 날짜별 유동인구 히스토리 테이블 (최신날짜 업데이트(캘린더)에  ) \n  * login 및 새로고침 시 최신날짜는 'select max(event_time) from ltdb_fp_history'로 가져오므로, 데이터 적재 시 ltdb_fp_history 테이블에 데이터를 업데이트(추가)해주어야 한다.\n  \n  CREATE table ltdb_fp_history (\n    event_time string,\n    table_name string\n    )\n    USING r2 OPTIONS\n    (\n    table '910',\n    host 'fbg02',\n    port '18900',\n    partitions 'table_name event_time',\n    mode 'nvkvs',\n    rowstore 'false',\n    at_least_one_partition_enabled 'no'\n  )\n  \n```\n\n## 사용자 영역 크기 변경 (소스코드)\n```\n  - cd frontend/src/component\n  - ChartScript.js 34번째 code line\n  - MapScript.js 1100번째 code line\n  - circleRadius 변수 값 변경 =\u003e default = 2; (기본단위 Km)\n```\n\n## REST API Service\n* Service 관련 source code -\u003e population/src/main/java/kr/co/ltdb/controller/MemberController.java\n\n* javascript 상의 테스트가 아니라면 postman(https://www.postman.com/) 설치하여, URL 테스트하면 편리합니다.\n\n* 계정 리스트 조회\n```\n  - URL : localhost:{port}/api/members\n  - http request method : GET\n```\n\n* 계정 조회\n```\n  - URL : localhost:{port}/api/members\n  - http request method : GET\n  - form-data\n    - key value 형태\n    - name : {값}  \n```\n\n* 계정 생성\n```\n  - URL : localhost:{port}/api/members/create\n  - http request method : POST\n  - form-data\n    - key value 형태\n    - name : {값}, pw : {값}\n```\n\n\n## 운영 시 필요한 가이드\n\n1. HTTP API Connection / SQL 및 결과 확인\n  * 해당 서비스는 Web(Client) 환경에서 Thrift를 통한 내용입니다. (html/javascript 구현)\n```\n  1) Basic Query\n  - frontend/src/js 폴더의 browser-connector.js import 하여 사용\n  - Input Value : String (SQL문)\n  - Out Value : SQL문 결과에 대한 Json Data\n  \n  * MapdCon 객체를 이용한 접속 및 SQL 테스트\n  \n    new MapdCon() // API서버 접속\n        .host(\"fbg01\")\n        .port(\"4762\") \n        .dbName(\"default\") \n        .user(\"ltdb\")\n        .password(\"ltdb\")\n        .connectAsync()\n        .then(function (connector) { // 커넥션 객체\n            \n            var query = \"select max(event_time) from ltdb_fp_history where table_name='ltdb_fp'\"; // SQL문 작성\n            connector.queryAsync(query, {columnarResults: false}).then(function (result) { // 커넥션 객체를 이용한 SQL 요청\n               console.log(result); // 결과 값\n            });\n        })  \n        \n\n  2) Vector tile Query\n  * mapbox-gl api 숙지 필요\n  - 관련 라이브러리 Import 필요\n    - frontend/src/js 폴더의 mapbox-gl.js import 하여 사용\n    - frontend/external 또는 frontend/build/static/js 폴더의 global-mercator.js, pako.js, vectortile-utils.js import 하여 사용\n    \n  //mapboxgl 사용하기 위한 토큰 필요\n  mapboxgl.accessToken = {토큰값(String)}; //'pk.eyJ1IjoibGVlc2giLCJhIjoiY0thWXdQbyJ9.fPGnL5s0k8ptNPY7P1S1aA';\n  \n  //API서버에 Tile 요청 시 사용할 포트배열 필요.\n  var ports = [4762, 4763, 4764, 4765, 4766, 4767, 4768, 4769, 4770, 4771, 4772, 4773];\n  \n  //Map 객체 생성\n  var map = new mapboxgl.Map({\n            container: {html div id},\n            hash: true,\n            style: {\n                'version': 8,\n                'sources': {\n                    'raster-tiles': {\n                        'type': 'raster',\n                        'tiles': [\n                            'http://a.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png'\n                        ],\n                        'tileSize': 256\n                    }\n                },\n                'layers': [{\n                    'id': 'base-map',\n                    'type': 'raster',\n                    'source': 'raster-tiles',\n                    'minzoom': 0,\n                    'maxzoom': 22\n                }]\n            },\n            center: [127, 37.55], //126.986, 37.565\n            zoom: 11,\n            maxZoom: 16,\n            minZoom: 8.5,\n            tilesFunctionParams: function (tile) { // 커스텀 함수 : tile 요청 시 여러 port로 요청하기 위한 설정\n                const port = ports.shift();\n                ports.push(port);\n    \n                return {\n                    host: config.host,\n                    port: port,\n                    eventTime1: null,\n                    eventTime2: null\n                }\n            }            \n            //interactive: false\n   });  \n   \n   //Map load 및 필요 라이브러리 가져오기\n   //Vector layer 생성\n   map.on('load', function() {\n      map.style.dispatcher.broadcast('loadWorkerSource', { //broadcast를 이용한 라이브러리 import\n          name: \"pako\",\n          url: `http://${window.location.host}/static/js/pako.js`\n      }, function (e) {\n          if (e) {\n              console.log(e);\n          }\n      });   \n      \n      map.style.dispatcher.broadcast('loadWorkerSource', {\n          name: \"global-mercator\",\n          url: `http://${window.location.host}/static/js/global-mercator.js`\n      }, function (e) {\n          if (e) {\n              console.log(e);\n          }\n      });  \n      \n      map.style.dispatcher.broadcast('loadWorkerSource', {\n          name: \"vectortile-utils\",\n          url: `http://${window.location.host}/static/js/vectortile-utils.js`\n      }, function (e) {\n          if (e) {\n              console.log(e);\n          }\n      });      \n      \n      //Vector Source 생성\n      //renderSqlPost 함수 : SQL문 하나만 요청하여 결과값 리턴 ( ex)현재 유동인구 표현 시 사용 )\n      map.addSource('vector-tile', {\n          type: 'vector',\n          tilesFunction: `function (tile) { // 커스텀 함수\n                  var host = tile.tilesFunctionParams.host;\n                  var port = tile.tilesFunctionParams.port;  \n\n                  var sql = \"\"; //데이터를 가져올 Query문 작성\n                  var typeName = \"ltdb_fp\";\n                  var aggrType = \"sum\";\n                  var multiple = false;\n                  return renderSqlPost(host, port, tile, sql, typeName, aggrType, multiple, null);\n              }`,\n          minzoom: 0,\n          maxzoom: 16.1\n      });      \n      \n      //증감 유동인구 데이터 가져올 때 사용하는 함수\n      * 하나의 예이므로 같은 map객체 사용.\n      //renderSqlDiffPost 함수 : SQL문 2가지 요청하여 subtract한 결과값 리턴 ( ex)증감 유동인구 표현 시 사용 )\n      map.addSource('vector-tile', {\n          type: 'vector',\n          tilesFunction: `function (tile) { // 커스텀 함수\n                  var host = tile.tilesFunctionParams.host;\n                  var port = tile.tilesFunctionParams.port;  \n                  \n                  //컬럼 별 subtract은 sql1 - sql2 \n                  var sql1 = \"\"; //기준 데이터를 가져올 Query문 작성\n                  var sql2 = \"\"; //비교 데이터를 가져올 Query문 작성\n                  var typeName = \"ltdb_fp\";\n                  var aggrType = \"sum\";\n                  var multiple = false;\n                  return renderSqlDiffPost(host, port, tile, sql1, sql2, typeName, aggrType, multiple, null);\n              }`,\n          minzoom: 0,\n          maxzoom: 16.1\n      });          \n      \n      //Vector Layer 생성\n      map.addLayer({...});\n   \n   });\n```\n\n2. 구현된 Source의 HTTP API Service 사용 확인\n  \n  - 캘린더 관련하여, ltdb_fp_history 테이블의 최신 날짜 Query\n  ```\n    - 소스 경로 : frontend/src/component/MenuComponent.jsx\n    - 69번째 라인 확인\n    - 사용 SQL \n      - \"select max(event_time) from ltdb_fp_history where table_name='ltdb_fp' limit 1\"\n  ```\n  \n  - Vector Tile Query\n  ```\n    - 소스 경로 : frontend/src/component/MenuComponent.jsx\n    \n    1) 92번째 라인 확인\n    - 사용 SQL \n      - \"SELECT (exist_m_00 + exist_m_10 + exist_m_20 + exist_m_30 + exist_m_40 + exist_m_50 + exist_m_60 + exist_m_70 + exist_m_80 + exist_m_90 + exist_f_00 + exist_f_10 + exist_f_20 + exist_f_30 + exist_f_40 + exist_f_50 + exist_f_60 + exist_f_70 + exist_f_80 + exist_f_90) as exist, geometry FROM ltdb_fp WHERE event_time = '${currPrevDateString.curr}'\"\n    \n    2) 192번째 라인 확인\n      - \"SELECT (exist_m_00 + exist_m_10 + exist_m_20 + exist_m_30 + exist_m_40 + exist_m_50 + exist_m_60 + exist_m_70 + exist_m_80 + exist_m_90 + exist_f_00 + exist_f_10 + exist_f_20 + exist_f_30 + exist_f_40 + exist_f_50 + exist_f_60 + exist_f_70 + exist_f_80 + exist_f_90) as exist, geometry FROM ltdb_fp WHERE event_time = '${currPrevDateString.curr}'\"; //현재 날짜\n      - \"SELECT (exist_m_00 + exist_m_10 + exist_m_20 + exist_m_30 + exist_m_40 + exist_m_50 + exist_m_60 + exist_m_70 + exist_m_80 + exist_m_90 + exist_f_00 + exist_f_10 + exist_f_20 + exist_f_30 + exist_f_40 + exist_f_50 + exist_f_60 + exist_f_70 + exist_f_80 + exist_f_90) as exist, geometry FROM ltdb_fp WHERE event_time = '${currPrevDateString.prev}'\"; //이전 날짜\n\n  ```\n  \n  - Chart Query\n  ```\n    - 소스 경로 : frontend/src/service/CustomFunc.jsx\n    \n    1) 막대차트 - 현재날짜 데이터 가져오기. 329번째 라인 확인\n      - `SELECT\n            (sum(exist_m_00) + sum(exist_m_10)) as exist_m_10, sum(exist_m_20) as exist_m_20, sum(exist_m_30) as exist_m_30,\n            sum(exist_m_40) as exist_m_40, sum(exist_m_50) as exist_m_50, (sum(exist_m_60) + sum(exist_m_70) +\n            sum(exist_m_80) + sum(exist_m_90)) as exist_m_60,\n            (sum(exist_f_00) + sum(exist_f_10)) as exist_f_10, sum(exist_f_20) as exist_f_20, sum(exist_f_30) as exist_f_30,\n            sum(exist_f_40) as exist_f_40, sum(exist_f_50) as exist_f_50, (sum(exist_f_60) + sum(exist_f_70) +\n            sum(exist_f_80) + sum(exist_f_90)) as exist_f_60, event_time        \n        FROM ltdb_fp    \n        WHERE ST_CONTAINS(ST_GEOMFROMTEXT('${wkt}'), geometry) AND event_time = '${eventTime1}'\n        GROUP BY event_time ORDER BY event_time`\n        \n     1) 라인차트 - 24시간 기준 시간 별 데이터 가져오기. 341번째 라인 확인   \n       - `SELECT\n            (sum(exist_m_00) + sum(exist_m_10)) as exist_m_10, sum(exist_m_20) as exist_m_20, sum(exist_m_30) as exist_m_30,\n            sum(exist_m_40) as exist_m_40, sum(exist_m_50) as exist_m_50, (sum(exist_m_60) + sum(exist_m_70) +\n            sum(exist_m_80) + sum(exist_m_90)) as exist_m_60,\n            (sum(exist_f_00) + sum(exist_f_10)) as exist_f_10, sum(exist_f_20) as exist_f_20, sum(exist_f_30) as exist_f_30,\n            sum(exist_f_40) as exist_f_40, sum(exist_f_50) as exist_f_50, (sum(exist_f_60) + sum(exist_f_70) +\n            sum(exist_f_80) + sum(exist_f_90)) as exist_f_60,\n            substring(event_time, 0, ${eventTimeFormat.length - 2}) as event_time\n        FROM ltdb_fp\n        WHERE ST_CONTAINS(ST_GEOMFROMTEXT('${wkt}'), geometry) AND event_time IN(${QueryTimeArray.toString()})  GROUP BY event_time ORDER BY event_time`;\n  ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmnms%2Fpopulation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmnms%2Fpopulation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmnms%2Fpopulation/lists"}