@sk-global/js-msearch-gsi-jp 1.1.26 → 1.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.module.js +1 -1
- package/dist/index.module.js.map +1 -1
- package/dist/index.umd.js +1 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/m_reverse_geocode.d.ts +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var e=require("axios"),r=require("axios-cache-interceptor"),t=require("path"),n=require("japanmesh");function
|
|
1
|
+
var e=require("axios"),r=require("axios-cache-interceptor"),t=require("path"),n=require("japanmesh"),o=require("@geolonia/open-reverse-geocoder");function s(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function a(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach(function(t){if("default"!==t){var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,n.get?n:{enumerable:!0,get:function(){return e[t]}})}}),r.default=e,r}var i=/*#__PURE__*/s(e),u=/*#__PURE__*/a(t);function c(){return c=Object.assign?Object.assign.bind():function(e){for(var r=1;r<arguments.length;r++){var t=arguments[r];for(var n in t)({}).hasOwnProperty.call(t,n)&&(e[n]=t[n])}return e},c.apply(null,arguments)}var l=/GSI\.MUNI_ARRAY\["\d+"\]\s*=\s*'(.*?)';/g,p=r.setupCache(i.default.create({baseURL:"https://mreversegeocoder.gsi.go.jp",timeout:2e3}),{ttl:864e5});p.interceptors.request.use(function(e){var r=""+e.baseURL+e.url+"?"+new URLSearchParams(e.params).toString();return console.log("Full URL:",r),e});var d=function(e,r){try{return Promise.resolve(p.get("/general/dem/scripts/getelevation.php",{responseType:"json",params:{lat:e,lon:r}})).then(function(t){var n=parseFloat(t.data.elevation);return{longitude:r,latitude:e,elevation:n}})}catch(e){return Promise.reject(e)}};exports.getElevation=function(e,r){return d(e,r)},exports.getElevationFromGSI=d,exports.getElevationFromOpenAPI=function(e,r){try{return Promise.resolve(i.default.get("https://api.open-elevation.com/api/v1/lookup",{responseType:"json",timeout:2e3,params:{locations:e+","+r}})).then(function(e){var r=e.data;if(!r.results||0===r.results.length)return null;var t=r.results[0];return c({},t,{elevation:parseFloat(t.elevation)})})}catch(e){return Promise.reject(e)}},exports.getMuniMap=function(){try{return Promise.resolve(function(e,r){try{var t=Promise.resolve(i.default.get("https://maps.gsi.go.jp/js/muni.js",{responseType:"text",timeout:500})).then(function(e){return r={},e.data.split("\n").forEach(function(e){if(l.test(e)){var t=function(e){var r=e.replace(l,"$1"),t=r.split(",");if(4!==t.length)throw new Error("invalid muni record: "+r);var n=t[0],o=t[1],s=t[2],a=t[3];return s=s.padStart(5,"0"),{prefCode:n=n.padStart(2,"0"),prefName:o,cityCode:s,cityName:a}}(e);r[t.cityCode]=t}}),r;var r})}catch(e){return r(e)}return t&&t.then?t.then(void 0,r):t}(0,function(e){return console.log("Failed to get muni map: "+e),{}}))}catch(e){return Promise.reject(e)}},exports.latLonToAddress=function(e,r){return function(e,r){try{return Promise.resolve(o.openReverseGeocoder([r,e],{})).then(function(e){return e?{results:{muniCd:e.code,lv01Nm:e.city,mesh_code:"",notes:e.prefecture}}:null})}catch(e){return Promise.reject(e)}}(e,r)},exports.reverseGeocodeByGsi=function(e,r){try{return Promise.resolve(p.get("/reverse-geocoder/LonLatToAddress",{responseType:"json",params:{lat:e,lon:r}})).then(function(e){return e.data})}catch(e){return Promise.reject(e)}},exports.reverseGeocodeByLocal=function(e,r){try{var t=function(e,r){return n.japanmesh.toCode(e,r,1e3)}(e,r),o=t.slice(0,4);try{console.log("Mesh code:",t,"Prefix:",o);var s=u.join(__dirname,"data","mesh_data_"+o+".json"),a=require(s)[t];if(!a||0===a.length)return console.error("Mesh data not found for code "+t),Promise.resolve(null);var i=a.find(function(e){return e.smallest})||a[0];return Promise.resolve({results:{muniCd:null==i?void 0:i.city_code,lv01Nm:null==i?void 0:i.city_name,mesh_code:t,notes:null==i?void 0:i.notes}})}catch(e){return console.error("Error reading mesh data for prefix "+o+":",e),Promise.resolve(null)}}catch(e){return Promise.reject(e)}},exports.searchAddress=function(e){try{return Promise.resolve(i.default.get("https://msearch.gsi.go.jp/address-search/AddressSearch",{responseType:"json",params:{q:e}})).then(function(e){return e.data})}catch(e){return Promise.reject(e)}};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/muni.ts","../src/m_reverse_geocode.ts","../src/utils.ts","../src/msearch.ts"],"sourcesContent":["// Muni file url\nconst MuniURL = 'https://maps.gsi.go.jp/js/muni.js';\nconst MuniRegex = /GSI\\.MUNI_ARRAY\\[\"\\d+\"\\]\\s*=\\s*'(.*?)';/g;\n\nimport axios from 'axios';\nimport { AddressResults, MuniMap } from './types';\n\n/**\n * parse muni.js\n * @param muniMap\n */\nconst parseMuniMap = (muniMap: string) => {\n const muniMapObj: MuniMap = {};\n const lines = muniMap.split('\\n');\n lines.forEach((line) => {\n if (MuniRegex.test(line)) {\n const muniRecord = parseMuniRecord(line);\n muniMapObj[muniRecord.cityCode] = muniRecord;\n }\n });\n return muniMapObj;\n};\n\n/**\n * parse muni record\n * @param line\n */\nconst parseMuniRecord = (line: string) => {\n const muniRecord = line.replace(MuniRegex, '$1');\n\n const muniRecordArray = muniRecord.split(',');\n\n // validate muni record\n if (muniRecordArray.length !== 4) {\n throw new Error(`invalid muni record: ${muniRecord}`);\n }\n\n let [prefCode, prefName, cityCode, cityName] = muniRecordArray;\n\n // if cityCode is not 5 digits, add 0 to the beginning\n cityCode = cityCode.padStart(5, '0');\n\n // if prefCode is not 2 digits, add 0 to the beginning\n prefCode = prefCode.padStart(2, '0');\n\n return {\n prefCode: prefCode,\n prefName: prefName,\n cityCode: cityCode,\n cityName: cityName,\n };\n};\n\n/**\n * Get muni map (city or ward map by city code) from GSI\n */\nconst getMuniMap = async () => {\n try {\n const response = await axios.get(MuniURL, {\n responseType: 'text',\n timeout: 500,\n });\n\n const muniMap = response.data;\n return parseMuniMap(muniMap);\n } catch (error) {\n console.log(`Failed to get muni map: ${error}`);\n return {};\n }\n};\n\n/**\n * converts muni code to address name.\n *\n * @param muniMap\n * @param muniCode\n */\nconst muniCodeToAddressName = (muniMap: MuniMap, muniCode: string) => {\n const muniRecord = muniMap[muniCode];\n if (!muniRecord) {\n throw new Error(`muni code ${muniCode} not found`);\n }\n\n const add = `${muniRecord.prefName}${muniRecord.cityName}`;\n return add.replace(/ /g, '');\n};\n\n/**\n * converts address result to address name.\n * @param muniMap\n * @param addressResults\n */\nconst addressResultsToAddressName = (\n muniMap: MuniMap,\n addressResults: AddressResults\n) => {\n const mc = addressResults.muniCd;\n const muniName = muniCodeToAddressName(muniMap, mc);\n const addrName = `${muniName}${addressResults.lv01Nm}`;\n return addrName;\n};\n\nconst getMuniMapLocations = async () => {\n const muniMap = await getMuniMap();\n // muniMap is a map of all cities and wards in Japan\n // key: city code, value: { prefCode, prefName, cityCode, cityName }\n // we need to convert this to a map of all locations in Japan\n // key: prefCode , value: { prefName, cities: { key: cityCode, value: { cityCode, cityName, wards: { key: wardCode, value: { wardCode, wardName } } } } }\n\n const muniMapLocations = {};\n Object.keys(muniMap).forEach((cityCode) => {\n const muniRecord = muniMap[cityCode];\n const { prefCode, prefName, cityName } = muniRecord;\n if (!muniMapLocations[prefCode]) {\n muniMapLocations[prefCode] = { prefName, cities: {} };\n }\n\n // if cityName contains ' ', it is a ward\n // otherwise, it is a city\n if (cityName.includes(' ')) {\n // ward name is after ' '\n const [name, wardName] = cityName.split(' ');\n // find city has the same name\n const city: any = Object.values(muniMap).find(\n (c: any) => c.cityName === name\n );\n if (!city) {\n console.log(`City ${name} not found in prefCode ${prefCode}`);\n } else {\n // add ward to city\n muniMapLocations[prefCode].cities[city.cityCode].wards[cityCode] = {\n prefCode,\n cityCode: cityCode,\n cityName: `${name}${wardName}`,\n bigCityFlag: '1',\n bigCityCode: city.cityCode,\n };\n }\n } else {\n muniMapLocations[prefCode].cities[cityCode] = {\n prefCode,\n cityCode,\n cityName,\n wards: {},\n };\n }\n });\n\n // assign bigCityFlag to each city\n Object.keys(muniMapLocations).forEach((prefCode) => {\n const pref = muniMapLocations[prefCode];\n Object.keys(pref.cities).forEach((cityCode) => {\n const city = pref.cities[cityCode];\n const isBigCity = Object.values(city.wards).length > 0;\n if (isBigCity) {\n city.bigCityFlag = '2';\n } else {\n // delete wards\n delete city.wards;\n // if city is tokyo then bigCityFlag is 3, otherwise 0\n if (city.prefCode === '13') {\n city.bigCityFlag = '3';\n } else {\n city.bigCityFlag = '0';\n }\n }\n });\n });\n\n return muniMapLocations;\n};\n\nexport {\n getMuniMap,\n getMuniMapLocations,\n muniCodeToAddressName,\n addressResultsToAddressName,\n};\n","import axios from 'axios';\nimport { setupCache } from 'axios-cache-interceptor';\nimport * as path from 'path';\n\nimport { ReverseGeocodeResults } from './types';\nimport { getMuniMap } from './muni';\nimport { convertLatLonToMesh } from './utils';\n\nconst api = setupCache(\n axios.create({\n baseURL: 'https://mreversegeocoder.gsi.go.jp',\n timeout: 2000,\n }),\n {\n ttl: 1000 * 60 * 60 * 24, // 24 hours\n }\n);\n\napi.interceptors.request.use((config) => {\n const fullUrl = `${config.baseURL}${config.url}?${new URLSearchParams(\n config.params\n ).toString()}`;\n console.log('Full URL:', fullUrl);\n return config;\n});\n\n/**\n * Reverse geocodes a given latitude and longitude using the mreversegeocoder API.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the reverse geocode results or null if no results are found.\n */\nconst reverseGeocodeByGsi = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n // get address from mreversegeocoder API.\n const params = {\n lat,\n lon,\n };\n const response = await api.get('/reverse-geocoder/LonLatToAddress', {\n responseType: 'json',\n params,\n });\n return response.data;\n};\n\n/**\n * Reverse geocodes a given latitude and longitude by converting them to Tokyo coordinates,\n * calculating the corresponding mesh code, and retrieving the mesh data from the local file system.\n *\n * @param lat - The latitude to reverse geocode.\n * @param lon - The longitude to reverse geocode.\n * @returns A promise that resolves to the reverse geocode results or null if the mesh data is not found.\n *\n * @example\n * ```typescript\n * const results = await reverseGeocodeByLocal(35.6895, 139.6917);\n * if (results) {\n * console.log(results);\n * } else {\n * console.log('No data found for the given coordinates.');\n * }\n * ```\n */\nconst reverseGeocodeByLocal = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n const meshCode = convertLatLonToMesh(lat, lon);\n const prefix = meshCode.slice(0, 4);\n try {\n console.log('Mesh code:', meshCode, 'Prefix:', prefix);\n // Read the mesh data from the local file system using require\n const meshDataPath = path.join(\n __dirname,\n 'data',\n `mesh_data_${prefix}.json`\n );\n const meshData = require(meshDataPath);\n\n // Get the data for the specific mesh code\n const meshArray = meshData[meshCode];\n if (!meshArray || meshArray.length === 0) {\n console.error(`Mesh data not found for code ${meshCode}`);\n return null;\n }\n\n // some mesh code has multiple data, so we need to find the correct one\n // const meshCodeData = meshArray.find((data) => {\n // const [lat1, lon1, lat2, lon2] = data.bbox;\n // // Check if the Tokyo coordinates are within the bounding box\n // return Ntokyo >= lat1 && Ntokyo <= lat2 && Etokyo >= lon1 && Etokyo <= lon2;\n // }) || meshArray[0];\n\n // Acttually, we can use the smallest bbox to get the correct mesh code\n // but we have not bbox data in the mesh data, so we can't use it.\n // So, we just check flag smallest to get the correct mesh code\n // the flag smallest is set to true if the data is the smallest bbox\n // And this flag is set by the data creator.(correct by compare data from GSI)\n const meshCodeData =\n meshArray.find((data: any) => {\n const { smallest } = data;\n return smallest;\n }) || meshArray[0];\n return {\n results: {\n muniCd: meshCodeData?.city_code,\n lv01Nm: meshCodeData?.city_name,\n mesh_code: meshCode,\n notes: meshCodeData?.notes,\n },\n };\n } catch (error) {\n console.error(`Error reading mesh data for prefix ${prefix}:`, error);\n return null;\n }\n};\n\n/**\n * Converts latitude and longitude coordinates to an address.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the reverse geocode results or null.\n *\n * @remarks\n * This function attempts to get the address from a local reverse geocoding service.\n * The commented-out code shows an alternative approach where it first tries to get the address\n * from a GSI (Geospatial Information) service and falls back to the local service in case of an error.\n */\nconst latLonToAddress = (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n // try to get address from gsi local first\n // if there is an error, try to get address from GSI\n try {\n // return reverseGeocodeByLocal(lat, lon);\n return reverseGeocodeByGsi(lat, lon);\n } catch (e) {\n console.log('Error getting address from GS, falling back to local:', e);\n // return reverseGeocodeByGsi(lat, lon);\n return reverseGeocodeByLocal(lat, lon);\n }\n};\n\nconst getElevationFromOpenAPI = async (\n lat: number,\n lon: number\n): Promise<{\n elevation: number;\n longitude: number;\n latitude: number;\n} | null> => {\n // get elevation from OpenAPI\n // https://api.open-elevation.com/api/v1/lookup?locations=43.061434,141.353649\n const response = await axios.get(\n 'https://api.open-elevation.com/api/v1/lookup',\n {\n responseType: 'json',\n timeout: 2000,\n params: {\n locations: `${lat},${lon}`,\n },\n }\n );\n const data = response.data;\n if (!data.results || data.results.length === 0) {\n return null;\n }\n const [elevation] = data.results;\n return {\n ...elevation,\n elevation: parseFloat(elevation.elevation),\n };\n};\n\nconst getElevationFromGSI = async (\n lat: number,\n lon: number\n): Promise<{\n elevation: number;\n longitude: number;\n latitude: number;\n}> => {\n // get elevation from GSI API\n // https://mreversegeocoder.gsi.go.jp/general/dem/scripts/getelevation.php?lon=141.3536498&lat=43.061434\n const response = await api.get('/general/dem/scripts/getelevation.php', {\n responseType: 'json',\n params: {\n lat,\n lon,\n },\n });\n\n const elevation = parseFloat(response.data.elevation);\n return { longitude: lon, latitude: lat, elevation };\n};\n\n/**\n * Retrieves the elevation for a given latitude and longitude.\n *\n * This function first attempts to get the elevation data from the GSI (Geospatial Information Authority of Japan).\n * If there is an error during this process, it falls back to retrieving the elevation data from an OpenAPI.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the elevation data.\n * @throws Will log an error message if both GSI and OpenAPI requests fail.\n */\nconst getElevation = async (lat: number, lon: number) => {\n // try to get elevation from GSI first\n // if there is an error, try to get elevation from OpenAPI\n try {\n return await getElevationFromGSI(lat, lon);\n } catch (e) {\n console.log('Error getting elevation from GSI:', e);\n return await getElevationFromOpenAPI(lat, lon);\n }\n};\n\nexport {\n getMuniMap,\n latLonToAddress,\n reverseGeocodeByLocal,\n reverseGeocodeByGsi,\n getElevationFromOpenAPI,\n getElevationFromGSI,\n getElevation,\n};\n","import { japanmesh } from 'japanmesh';\n\nexport function convertLatLonToMesh(lat: number, lon: number) {\n return japanmesh.toCode(lat, lon, 1000); // 1000m is 3rd mesh code\n}\n","import axios from 'axios';\n\nimport { SearchResults } from './types';\n\n// base url for msearch api\nconst BaseURL = 'https://msearch.gsi.go.jp';\n\n/**\n * search address by query\n */\nconst searchAddress = async (q: string): Promise<SearchResults> => {\n const url = `${BaseURL}/address-search/AddressSearch`;\n const response = await axios.get(url, {\n responseType: 'json',\n params: {\n q,\n },\n });\n\n const res = response.data;\n return res;\n};\n\nexport { searchAddress };\n"],"names":["MuniRegex","api","setupCache","axios","create","baseURL","timeout","ttl","interceptors","request","use","config","fullUrl","url","URLSearchParams","params","toString","console","log","reverseGeocodeByGsi","lat","lon","Promise","resolve","get","responseType","then","response","data","e","reject","reverseGeocodeByLocal","meshCode","japanmesh","toCode","convertLatLonToMesh","prefix","slice","meshDataPath","path","join","__dirname","meshArray","require","length","error","meshCodeData","find","smallest","results","muniCd","city_code","lv01Nm","city_name","mesh_code","notes","getElevationFromOpenAPI","locations","elevation","_extends","parseFloat","getElevationFromGSI","longitude","latitude","_catch","muniMapObj","split","forEach","line","test","muniRecord","replace","muniRecordArray","Error","prefCode","prefName","cityCode","cityName","padStart","parseMuniRecord","q","BaseURL"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/muni.ts","../src/m_reverse_geocode.ts","../src/utils.ts","../src/msearch.ts"],"sourcesContent":["// Muni file url\nconst MuniURL = 'https://maps.gsi.go.jp/js/muni.js';\nconst MuniRegex = /GSI\\.MUNI_ARRAY\\[\"\\d+\"\\]\\s*=\\s*'(.*?)';/g;\n\nimport axios from 'axios';\nimport { AddressResults, MuniMap } from './types';\n\n/**\n * parse muni.js\n * @param muniMap\n */\nconst parseMuniMap = (muniMap: string) => {\n const muniMapObj: MuniMap = {};\n const lines = muniMap.split('\\n');\n lines.forEach((line) => {\n if (MuniRegex.test(line)) {\n const muniRecord = parseMuniRecord(line);\n muniMapObj[muniRecord.cityCode] = muniRecord;\n }\n });\n return muniMapObj;\n};\n\n/**\n * parse muni record\n * @param line\n */\nconst parseMuniRecord = (line: string) => {\n const muniRecord = line.replace(MuniRegex, '$1');\n\n const muniRecordArray = muniRecord.split(',');\n\n // validate muni record\n if (muniRecordArray.length !== 4) {\n throw new Error(`invalid muni record: ${muniRecord}`);\n }\n\n let [prefCode, prefName, cityCode, cityName] = muniRecordArray;\n\n // if cityCode is not 5 digits, add 0 to the beginning\n cityCode = cityCode.padStart(5, '0');\n\n // if prefCode is not 2 digits, add 0 to the beginning\n prefCode = prefCode.padStart(2, '0');\n\n return {\n prefCode: prefCode,\n prefName: prefName,\n cityCode: cityCode,\n cityName: cityName,\n };\n};\n\n/**\n * Get muni map (city or ward map by city code) from GSI\n */\nconst getMuniMap = async () => {\n try {\n const response = await axios.get(MuniURL, {\n responseType: 'text',\n timeout: 500,\n });\n\n const muniMap = response.data;\n return parseMuniMap(muniMap);\n } catch (error) {\n console.log(`Failed to get muni map: ${error}`);\n return {};\n }\n};\n\n/**\n * converts muni code to address name.\n *\n * @param muniMap\n * @param muniCode\n */\nconst muniCodeToAddressName = (muniMap: MuniMap, muniCode: string) => {\n const muniRecord = muniMap[muniCode];\n if (!muniRecord) {\n throw new Error(`muni code ${muniCode} not found`);\n }\n\n const add = `${muniRecord.prefName}${muniRecord.cityName}`;\n return add.replace(/ /g, '');\n};\n\n/**\n * converts address result to address name.\n * @param muniMap\n * @param addressResults\n */\nconst addressResultsToAddressName = (\n muniMap: MuniMap,\n addressResults: AddressResults\n) => {\n const mc = addressResults.muniCd;\n const muniName = muniCodeToAddressName(muniMap, mc);\n const addrName = `${muniName}${addressResults.lv01Nm}`;\n return addrName;\n};\n\nconst getMuniMapLocations = async () => {\n const muniMap = await getMuniMap();\n // muniMap is a map of all cities and wards in Japan\n // key: city code, value: { prefCode, prefName, cityCode, cityName }\n // we need to convert this to a map of all locations in Japan\n // key: prefCode , value: { prefName, cities: { key: cityCode, value: { cityCode, cityName, wards: { key: wardCode, value: { wardCode, wardName } } } } }\n\n const muniMapLocations = {};\n Object.keys(muniMap).forEach((cityCode) => {\n const muniRecord = muniMap[cityCode];\n const { prefCode, prefName, cityName } = muniRecord;\n if (!muniMapLocations[prefCode]) {\n muniMapLocations[prefCode] = { prefName, cities: {} };\n }\n\n // if cityName contains ' ', it is a ward\n // otherwise, it is a city\n if (cityName.includes(' ')) {\n // ward name is after ' '\n const [name, wardName] = cityName.split(' ');\n // find city has the same name\n const city: any = Object.values(muniMap).find(\n (c: any) => c.cityName === name\n );\n if (!city) {\n console.log(`City ${name} not found in prefCode ${prefCode}`);\n } else {\n // add ward to city\n muniMapLocations[prefCode].cities[city.cityCode].wards[cityCode] = {\n prefCode,\n cityCode: cityCode,\n cityName: `${name}${wardName}`,\n bigCityFlag: '1',\n bigCityCode: city.cityCode,\n };\n }\n } else {\n muniMapLocations[prefCode].cities[cityCode] = {\n prefCode,\n cityCode,\n cityName,\n wards: {},\n };\n }\n });\n\n // assign bigCityFlag to each city\n Object.keys(muniMapLocations).forEach((prefCode) => {\n const pref = muniMapLocations[prefCode];\n Object.keys(pref.cities).forEach((cityCode) => {\n const city = pref.cities[cityCode];\n const isBigCity = Object.values(city.wards).length > 0;\n if (isBigCity) {\n city.bigCityFlag = '2';\n } else {\n // delete wards\n delete city.wards;\n // if city is tokyo then bigCityFlag is 3, otherwise 0\n if (city.prefCode === '13') {\n city.bigCityFlag = '3';\n } else {\n city.bigCityFlag = '0';\n }\n }\n });\n });\n\n return muniMapLocations;\n};\n\nexport {\n getMuniMap,\n getMuniMapLocations,\n muniCodeToAddressName,\n addressResultsToAddressName,\n};\n","import axios from 'axios';\nimport { setupCache } from 'axios-cache-interceptor';\nimport * as path from 'path';\n\nimport { ReverseGeocodeResults } from './types';\nimport { getMuniMap } from './muni';\nimport { convertLatLonToMesh } from './utils';\nimport { openReverseGeocoder } from '@geolonia/open-reverse-geocoder';\n\nconst api = setupCache(\n axios.create({\n baseURL: 'https://mreversegeocoder.gsi.go.jp',\n timeout: 2000,\n }),\n {\n ttl: 1000 * 60 * 60 * 24, // 24 hours\n }\n);\n\napi.interceptors.request.use((config) => {\n const fullUrl = `${config.baseURL}${config.url}?${new URLSearchParams(\n config.params\n ).toString()}`;\n console.log('Full URL:', fullUrl);\n return config;\n});\n\n/**\n * Reverse geocodes a given latitude and longitude using the mreversegeocoder API.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the reverse geocode results or null if no results are found.\n */\nconst reverseGeocodeByGsi = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n // get address from mreversegeocoder API.\n const params = {\n lat,\n lon,\n };\n const response = await api.get('/reverse-geocoder/LonLatToAddress', {\n responseType: 'json',\n params,\n });\n return response.data;\n};\n\n/**\n * Reverse geocodes a given latitude and longitude by converting them to Tokyo coordinates,\n * calculating the corresponding mesh code, and retrieving the mesh data from the local file system.\n *\n * @param lat - The latitude to reverse geocode.\n * @param lon - The longitude to reverse geocode.\n * @returns A promise that resolves to the reverse geocode results or null if the mesh data is not found.\n *\n * @example\n * ```typescript\n * const results = await reverseGeocodeByLocal(35.6895, 139.6917);\n * if (results) {\n * console.log(results);\n * } else {\n * console.log('No data found for the given coordinates.');\n * }\n * ```\n */\nconst reverseGeocodeByLocal = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n const meshCode = convertLatLonToMesh(lat, lon);\n const prefix = meshCode.slice(0, 4);\n try {\n console.log('Mesh code:', meshCode, 'Prefix:', prefix);\n // Read the mesh data from the local file system using require\n const meshDataPath = path.join(\n __dirname,\n 'data',\n `mesh_data_${prefix}.json`\n );\n const meshData = require(meshDataPath);\n\n // Get the data for the specific mesh code\n const meshArray = meshData[meshCode];\n if (!meshArray || meshArray.length === 0) {\n console.error(`Mesh data not found for code ${meshCode}`);\n return null;\n }\n\n // some mesh code has multiple data, so we need to find the correct one\n // const meshCodeData = meshArray.find((data) => {\n // const [lat1, lon1, lat2, lon2] = data.bbox;\n // // Check if the Tokyo coordinates are within the bounding box\n // return Ntokyo >= lat1 && Ntokyo <= lat2 && Etokyo >= lon1 && Etokyo <= lon2;\n // }) || meshArray[0];\n\n // Acttually, we can use the smallest bbox to get the correct mesh code\n // but we have not bbox data in the mesh data, so we can't use it.\n // So, we just check flag smallest to get the correct mesh code\n // the flag smallest is set to true if the data is the smallest bbox\n // And this flag is set by the data creator.(correct by compare data from GSI)\n const meshCodeData =\n meshArray.find((data: any) => {\n const { smallest } = data;\n return smallest;\n }) || meshArray[0];\n return {\n results: {\n muniCd: meshCodeData?.city_code,\n lv01Nm: meshCodeData?.city_name,\n mesh_code: meshCode,\n notes: meshCodeData?.notes,\n },\n };\n } catch (error) {\n console.error(`Error reading mesh data for prefix ${prefix}:`, error);\n return null;\n }\n};\n\nconst reverseGeocodeByOpenReverseGeocoder = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n const result = await openReverseGeocoder([lon, lat], {});\n if (!result) {\n return null;\n }\n const { code, prefecture, city } = result;\n return {\n results: {\n muniCd: code,\n lv01Nm: city,\n mesh_code: '',\n notes: prefecture,\n },\n };\n};\n\n/**\n * Converts latitude and longitude coordinates to an address.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the reverse geocode results or null.\n *\n * @remarks\n * This function attempts to get the address from a local reverse geocoding service.\n * The commented-out code shows an alternative approach where it first tries to get the address\n * from a GSI (Geospatial Information) service and falls back to the local service in case of an error.\n */\nconst latLonToAddress = (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n // // try to get address from gsi local first\n // // if there is an error, try to get address from GSI\n // try {\n // // return reverseGeocodeByLocal(lat, lon);\n // return reverseGeocodeByGsi(lat, lon);\n // } catch (e) {\n // console.log('Error getting address from GS, falling back to local:', e);\n // // return reverseGeocodeByGsi(lat, lon);\n // return reverseGeocodeByOpenReverseGeocoder(lat, lon);\n // }\n return reverseGeocodeByOpenReverseGeocoder(lat, lon);\n};\n\nconst getElevationFromOpenAPI = async (\n lat: number,\n lon: number\n): Promise<{\n elevation: number;\n longitude: number;\n latitude: number;\n} | null> => {\n // get elevation from OpenAPI\n // https://api.open-elevation.com/api/v1/lookup?locations=43.061434,141.353649\n const response = await axios.get(\n 'https://api.open-elevation.com/api/v1/lookup',\n {\n responseType: 'json',\n timeout: 2000,\n params: {\n locations: `${lat},${lon}`,\n },\n }\n );\n const data = response.data;\n if (!data.results || data.results.length === 0) {\n return null;\n }\n const [elevation] = data.results;\n return {\n ...elevation,\n elevation: parseFloat(elevation.elevation),\n };\n};\n\nconst getElevationFromGSI = async (\n lat: number,\n lon: number\n): Promise<{\n elevation: number;\n longitude: number;\n latitude: number;\n}> => {\n // get elevation from GSI API\n // https://mreversegeocoder.gsi.go.jp/general/dem/scripts/getelevation.php?lon=141.3536498&lat=43.061434\n const response = await api.get('/general/dem/scripts/getelevation.php', {\n responseType: 'json',\n params: {\n lat,\n lon,\n },\n });\n\n const elevation = parseFloat(response.data.elevation);\n return { longitude: lon, latitude: lat, elevation };\n};\n\n/**\n * Retrieves the elevation for a given latitude and longitude.\n *\n * This function first attempts to get the elevation data from the GSI (Geospatial Information Authority of Japan).\n * If there is an error during this process, it falls back to retrieving the elevation data from an OpenAPI.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the elevation data.\n * @throws Will log an error message if both GSI and OpenAPI requests fail.\n */\nconst getElevation = async (lat: number, lon: number) => {\n return getElevationFromGSI(lat, lon);\n};\n\nexport {\n getMuniMap,\n latLonToAddress,\n reverseGeocodeByLocal,\n reverseGeocodeByGsi,\n getElevationFromOpenAPI,\n getElevationFromGSI,\n getElevation,\n};\n","import { japanmesh } from 'japanmesh';\n\nexport function convertLatLonToMesh(lat: number, lon: number) {\n return japanmesh.toCode(lat, lon, 1000); // 1000m is 3rd mesh code\n}\n","import axios from 'axios';\n\nimport { SearchResults } from './types';\n\n// base url for msearch api\nconst BaseURL = 'https://msearch.gsi.go.jp';\n\n/**\n * search address by query\n */\nconst searchAddress = async (q: string): Promise<SearchResults> => {\n const url = `${BaseURL}/address-search/AddressSearch`;\n const response = await axios.get(url, {\n responseType: 'json',\n params: {\n q,\n },\n });\n\n const res = response.data;\n return res;\n};\n\nexport { searchAddress };\n"],"names":["MuniRegex","api","setupCache","axios","create","baseURL","timeout","ttl","interceptors","request","use","config","fullUrl","url","URLSearchParams","params","toString","console","log","getElevationFromGSI","lat","lon","Promise","resolve","get","responseType","then","response","elevation","parseFloat","data","longitude","latitude","e","reject","locations","results","length","_extends","muniMapObj","split","forEach","line","test","muniRecord","replace","muniRecordArray","Error","prefCode","prefName","cityCode","cityName","padStart","parseMuniRecord","_catch","error","openReverseGeocoder","result","muniCd","code","lv01Nm","city","mesh_code","notes","prefecture","reverseGeocodeByOpenReverseGeocoder","meshCode","japanmesh","toCode","convertLatLonToMesh","prefix","slice","meshDataPath","path","join","__dirname","meshArray","require","meshCodeData","find","smallest","city_code","city_name","q","BaseURL"],"mappings":"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"}
|
package/dist/index.module.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"axios";import{setupCache as r}from"axios-cache-interceptor";import*as t from"path";import{japanmesh as
|
|
1
|
+
import e from"axios";import{setupCache as r}from"axios-cache-interceptor";import*as t from"path";import{japanmesh as n}from"japanmesh";import{openReverseGeocoder as o}from"@geolonia/open-reverse-geocoder";function s(){return s=Object.assign?Object.assign.bind():function(e){for(var r=1;r<arguments.length;r++){var t=arguments[r];for(var n in t)({}).hasOwnProperty.call(t,n)&&(e[n]=t[n])}return e},s.apply(null,arguments)}var a=/GSI\.MUNI_ARRAY\["\d+"\]\s*=\s*'(.*?)';/g,i=function(){try{return Promise.resolve(function(r,t){try{var n=Promise.resolve(e.get("https://maps.gsi.go.jp/js/muni.js",{responseType:"text",timeout:500})).then(function(e){return r={},e.data.split("\n").forEach(function(e){if(a.test(e)){var t=function(e){var r=e.replace(a,"$1"),t=r.split(",");if(4!==t.length)throw new Error("invalid muni record: "+r);var n=t[0],o=t[1],s=t[2],i=t[3];return s=s.padStart(5,"0"),{prefCode:n=n.padStart(2,"0"),prefName:o,cityCode:s,cityName:i}}(e);r[t.cityCode]=t}}),r;var r})}catch(e){return t(e)}return n&&n.then?n.then(void 0,t):n}(0,function(e){return console.log("Failed to get muni map: "+e),{}}))}catch(e){return Promise.reject(e)}},c=r(e.create({baseURL:"https://mreversegeocoder.gsi.go.jp",timeout:2e3}),{ttl:864e5});c.interceptors.request.use(function(e){var r=""+e.baseURL+e.url+"?"+new URLSearchParams(e.params).toString();return console.log("Full URL:",r),e});var u=function(e,r){try{return Promise.resolve(c.get("/reverse-geocoder/LonLatToAddress",{responseType:"json",params:{lat:e,lon:r}})).then(function(e){return e.data})}catch(e){return Promise.reject(e)}},l=function(e,r){try{var o=function(e,r){return n.toCode(e,r,1e3)}(e,r),s=o.slice(0,4);try{console.log("Mesh code:",o,"Prefix:",s);var a=t.join(__dirname,"data","mesh_data_"+s+".json"),i=require(a)[o];if(!i||0===i.length)return console.error("Mesh data not found for code "+o),Promise.resolve(null);var c=i.find(function(e){return e.smallest})||i[0];return Promise.resolve({results:{muniCd:null==c?void 0:c.city_code,lv01Nm:null==c?void 0:c.city_name,mesh_code:o,notes:null==c?void 0:c.notes}})}catch(e){return console.error("Error reading mesh data for prefix "+s+":",e),Promise.resolve(null)}}catch(e){return Promise.reject(e)}},m=function(e,r){return function(e,r){try{return Promise.resolve(o([r,e],{})).then(function(e){return e?{results:{muniCd:e.code,lv01Nm:e.city,mesh_code:"",notes:e.prefecture}}:null})}catch(e){return Promise.reject(e)}}(e,r)},p=function(r,t){try{return Promise.resolve(e.get("https://api.open-elevation.com/api/v1/lookup",{responseType:"json",timeout:2e3,params:{locations:r+","+t}})).then(function(e){var r=e.data;if(!r.results||0===r.results.length)return null;var t=r.results[0];return s({},t,{elevation:parseFloat(t.elevation)})})}catch(e){return Promise.reject(e)}},d=function(e,r){try{return Promise.resolve(c.get("/general/dem/scripts/getelevation.php",{responseType:"json",params:{lat:e,lon:r}})).then(function(t){var n=parseFloat(t.data.elevation);return{longitude:r,latitude:e,elevation:n}})}catch(e){return Promise.reject(e)}},f=function(e,r){return d(e,r)},v=function(r){try{return Promise.resolve(e.get("https://msearch.gsi.go.jp/address-search/AddressSearch",{responseType:"json",params:{q:r}})).then(function(e){return e.data})}catch(e){return Promise.reject(e)}};export{f as getElevation,d as getElevationFromGSI,p as getElevationFromOpenAPI,i as getMuniMap,m as latLonToAddress,u as reverseGeocodeByGsi,l as reverseGeocodeByLocal,v as searchAddress};
|
|
2
2
|
//# sourceMappingURL=index.module.js.map
|
package/dist/index.module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.module.js","sources":["../src/muni.ts","../src/m_reverse_geocode.ts","../src/utils.ts","../src/msearch.ts"],"sourcesContent":["// Muni file url\nconst MuniURL = 'https://maps.gsi.go.jp/js/muni.js';\nconst MuniRegex = /GSI\\.MUNI_ARRAY\\[\"\\d+\"\\]\\s*=\\s*'(.*?)';/g;\n\nimport axios from 'axios';\nimport { AddressResults, MuniMap } from './types';\n\n/**\n * parse muni.js\n * @param muniMap\n */\nconst parseMuniMap = (muniMap: string) => {\n const muniMapObj: MuniMap = {};\n const lines = muniMap.split('\\n');\n lines.forEach((line) => {\n if (MuniRegex.test(line)) {\n const muniRecord = parseMuniRecord(line);\n muniMapObj[muniRecord.cityCode] = muniRecord;\n }\n });\n return muniMapObj;\n};\n\n/**\n * parse muni record\n * @param line\n */\nconst parseMuniRecord = (line: string) => {\n const muniRecord = line.replace(MuniRegex, '$1');\n\n const muniRecordArray = muniRecord.split(',');\n\n // validate muni record\n if (muniRecordArray.length !== 4) {\n throw new Error(`invalid muni record: ${muniRecord}`);\n }\n\n let [prefCode, prefName, cityCode, cityName] = muniRecordArray;\n\n // if cityCode is not 5 digits, add 0 to the beginning\n cityCode = cityCode.padStart(5, '0');\n\n // if prefCode is not 2 digits, add 0 to the beginning\n prefCode = prefCode.padStart(2, '0');\n\n return {\n prefCode: prefCode,\n prefName: prefName,\n cityCode: cityCode,\n cityName: cityName,\n };\n};\n\n/**\n * Get muni map (city or ward map by city code) from GSI\n */\nconst getMuniMap = async () => {\n try {\n const response = await axios.get(MuniURL, {\n responseType: 'text',\n timeout: 500,\n });\n\n const muniMap = response.data;\n return parseMuniMap(muniMap);\n } catch (error) {\n console.log(`Failed to get muni map: ${error}`);\n return {};\n }\n};\n\n/**\n * converts muni code to address name.\n *\n * @param muniMap\n * @param muniCode\n */\nconst muniCodeToAddressName = (muniMap: MuniMap, muniCode: string) => {\n const muniRecord = muniMap[muniCode];\n if (!muniRecord) {\n throw new Error(`muni code ${muniCode} not found`);\n }\n\n const add = `${muniRecord.prefName}${muniRecord.cityName}`;\n return add.replace(/ /g, '');\n};\n\n/**\n * converts address result to address name.\n * @param muniMap\n * @param addressResults\n */\nconst addressResultsToAddressName = (\n muniMap: MuniMap,\n addressResults: AddressResults\n) => {\n const mc = addressResults.muniCd;\n const muniName = muniCodeToAddressName(muniMap, mc);\n const addrName = `${muniName}${addressResults.lv01Nm}`;\n return addrName;\n};\n\nconst getMuniMapLocations = async () => {\n const muniMap = await getMuniMap();\n // muniMap is a map of all cities and wards in Japan\n // key: city code, value: { prefCode, prefName, cityCode, cityName }\n // we need to convert this to a map of all locations in Japan\n // key: prefCode , value: { prefName, cities: { key: cityCode, value: { cityCode, cityName, wards: { key: wardCode, value: { wardCode, wardName } } } } }\n\n const muniMapLocations = {};\n Object.keys(muniMap).forEach((cityCode) => {\n const muniRecord = muniMap[cityCode];\n const { prefCode, prefName, cityName } = muniRecord;\n if (!muniMapLocations[prefCode]) {\n muniMapLocations[prefCode] = { prefName, cities: {} };\n }\n\n // if cityName contains ' ', it is a ward\n // otherwise, it is a city\n if (cityName.includes(' ')) {\n // ward name is after ' '\n const [name, wardName] = cityName.split(' ');\n // find city has the same name\n const city: any = Object.values(muniMap).find(\n (c: any) => c.cityName === name\n );\n if (!city) {\n console.log(`City ${name} not found in prefCode ${prefCode}`);\n } else {\n // add ward to city\n muniMapLocations[prefCode].cities[city.cityCode].wards[cityCode] = {\n prefCode,\n cityCode: cityCode,\n cityName: `${name}${wardName}`,\n bigCityFlag: '1',\n bigCityCode: city.cityCode,\n };\n }\n } else {\n muniMapLocations[prefCode].cities[cityCode] = {\n prefCode,\n cityCode,\n cityName,\n wards: {},\n };\n }\n });\n\n // assign bigCityFlag to each city\n Object.keys(muniMapLocations).forEach((prefCode) => {\n const pref = muniMapLocations[prefCode];\n Object.keys(pref.cities).forEach((cityCode) => {\n const city = pref.cities[cityCode];\n const isBigCity = Object.values(city.wards).length > 0;\n if (isBigCity) {\n city.bigCityFlag = '2';\n } else {\n // delete wards\n delete city.wards;\n // if city is tokyo then bigCityFlag is 3, otherwise 0\n if (city.prefCode === '13') {\n city.bigCityFlag = '3';\n } else {\n city.bigCityFlag = '0';\n }\n }\n });\n });\n\n return muniMapLocations;\n};\n\nexport {\n getMuniMap,\n getMuniMapLocations,\n muniCodeToAddressName,\n addressResultsToAddressName,\n};\n","import axios from 'axios';\nimport { setupCache } from 'axios-cache-interceptor';\nimport * as path from 'path';\n\nimport { ReverseGeocodeResults } from './types';\nimport { getMuniMap } from './muni';\nimport { convertLatLonToMesh } from './utils';\n\nconst api = setupCache(\n axios.create({\n baseURL: 'https://mreversegeocoder.gsi.go.jp',\n timeout: 2000,\n }),\n {\n ttl: 1000 * 60 * 60 * 24, // 24 hours\n }\n);\n\napi.interceptors.request.use((config) => {\n const fullUrl = `${config.baseURL}${config.url}?${new URLSearchParams(\n config.params\n ).toString()}`;\n console.log('Full URL:', fullUrl);\n return config;\n});\n\n/**\n * Reverse geocodes a given latitude and longitude using the mreversegeocoder API.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the reverse geocode results or null if no results are found.\n */\nconst reverseGeocodeByGsi = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n // get address from mreversegeocoder API.\n const params = {\n lat,\n lon,\n };\n const response = await api.get('/reverse-geocoder/LonLatToAddress', {\n responseType: 'json',\n params,\n });\n return response.data;\n};\n\n/**\n * Reverse geocodes a given latitude and longitude by converting them to Tokyo coordinates,\n * calculating the corresponding mesh code, and retrieving the mesh data from the local file system.\n *\n * @param lat - The latitude to reverse geocode.\n * @param lon - The longitude to reverse geocode.\n * @returns A promise that resolves to the reverse geocode results or null if the mesh data is not found.\n *\n * @example\n * ```typescript\n * const results = await reverseGeocodeByLocal(35.6895, 139.6917);\n * if (results) {\n * console.log(results);\n * } else {\n * console.log('No data found for the given coordinates.');\n * }\n * ```\n */\nconst reverseGeocodeByLocal = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n const meshCode = convertLatLonToMesh(lat, lon);\n const prefix = meshCode.slice(0, 4);\n try {\n console.log('Mesh code:', meshCode, 'Prefix:', prefix);\n // Read the mesh data from the local file system using require\n const meshDataPath = path.join(\n __dirname,\n 'data',\n `mesh_data_${prefix}.json`\n );\n const meshData = require(meshDataPath);\n\n // Get the data for the specific mesh code\n const meshArray = meshData[meshCode];\n if (!meshArray || meshArray.length === 0) {\n console.error(`Mesh data not found for code ${meshCode}`);\n return null;\n }\n\n // some mesh code has multiple data, so we need to find the correct one\n // const meshCodeData = meshArray.find((data) => {\n // const [lat1, lon1, lat2, lon2] = data.bbox;\n // // Check if the Tokyo coordinates are within the bounding box\n // return Ntokyo >= lat1 && Ntokyo <= lat2 && Etokyo >= lon1 && Etokyo <= lon2;\n // }) || meshArray[0];\n\n // Acttually, we can use the smallest bbox to get the correct mesh code\n // but we have not bbox data in the mesh data, so we can't use it.\n // So, we just check flag smallest to get the correct mesh code\n // the flag smallest is set to true if the data is the smallest bbox\n // And this flag is set by the data creator.(correct by compare data from GSI)\n const meshCodeData =\n meshArray.find((data: any) => {\n const { smallest } = data;\n return smallest;\n }) || meshArray[0];\n return {\n results: {\n muniCd: meshCodeData?.city_code,\n lv01Nm: meshCodeData?.city_name,\n mesh_code: meshCode,\n notes: meshCodeData?.notes,\n },\n };\n } catch (error) {\n console.error(`Error reading mesh data for prefix ${prefix}:`, error);\n return null;\n }\n};\n\n/**\n * Converts latitude and longitude coordinates to an address.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the reverse geocode results or null.\n *\n * @remarks\n * This function attempts to get the address from a local reverse geocoding service.\n * The commented-out code shows an alternative approach where it first tries to get the address\n * from a GSI (Geospatial Information) service and falls back to the local service in case of an error.\n */\nconst latLonToAddress = (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n // try to get address from gsi local first\n // if there is an error, try to get address from GSI\n try {\n // return reverseGeocodeByLocal(lat, lon);\n return reverseGeocodeByGsi(lat, lon);\n } catch (e) {\n console.log('Error getting address from GS, falling back to local:', e);\n // return reverseGeocodeByGsi(lat, lon);\n return reverseGeocodeByLocal(lat, lon);\n }\n};\n\nconst getElevationFromOpenAPI = async (\n lat: number,\n lon: number\n): Promise<{\n elevation: number;\n longitude: number;\n latitude: number;\n} | null> => {\n // get elevation from OpenAPI\n // https://api.open-elevation.com/api/v1/lookup?locations=43.061434,141.353649\n const response = await axios.get(\n 'https://api.open-elevation.com/api/v1/lookup',\n {\n responseType: 'json',\n timeout: 2000,\n params: {\n locations: `${lat},${lon}`,\n },\n }\n );\n const data = response.data;\n if (!data.results || data.results.length === 0) {\n return null;\n }\n const [elevation] = data.results;\n return {\n ...elevation,\n elevation: parseFloat(elevation.elevation),\n };\n};\n\nconst getElevationFromGSI = async (\n lat: number,\n lon: number\n): Promise<{\n elevation: number;\n longitude: number;\n latitude: number;\n}> => {\n // get elevation from GSI API\n // https://mreversegeocoder.gsi.go.jp/general/dem/scripts/getelevation.php?lon=141.3536498&lat=43.061434\n const response = await api.get('/general/dem/scripts/getelevation.php', {\n responseType: 'json',\n params: {\n lat,\n lon,\n },\n });\n\n const elevation = parseFloat(response.data.elevation);\n return { longitude: lon, latitude: lat, elevation };\n};\n\n/**\n * Retrieves the elevation for a given latitude and longitude.\n *\n * This function first attempts to get the elevation data from the GSI (Geospatial Information Authority of Japan).\n * If there is an error during this process, it falls back to retrieving the elevation data from an OpenAPI.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the elevation data.\n * @throws Will log an error message if both GSI and OpenAPI requests fail.\n */\nconst getElevation = async (lat: number, lon: number) => {\n // try to get elevation from GSI first\n // if there is an error, try to get elevation from OpenAPI\n try {\n return await getElevationFromGSI(lat, lon);\n } catch (e) {\n console.log('Error getting elevation from GSI:', e);\n return await getElevationFromOpenAPI(lat, lon);\n }\n};\n\nexport {\n getMuniMap,\n latLonToAddress,\n reverseGeocodeByLocal,\n reverseGeocodeByGsi,\n getElevationFromOpenAPI,\n getElevationFromGSI,\n getElevation,\n};\n","import { japanmesh } from 'japanmesh';\n\nexport function convertLatLonToMesh(lat: number, lon: number) {\n return japanmesh.toCode(lat, lon, 1000); // 1000m is 3rd mesh code\n}\n","import axios from 'axios';\n\nimport { SearchResults } from './types';\n\n// base url for msearch api\nconst BaseURL = 'https://msearch.gsi.go.jp';\n\n/**\n * search address by query\n */\nconst searchAddress = async (q: string): Promise<SearchResults> => {\n const url = `${BaseURL}/address-search/AddressSearch`;\n const response = await axios.get(url, {\n responseType: 'json',\n params: {\n q,\n },\n });\n\n const res = response.data;\n return res;\n};\n\nexport { searchAddress };\n"],"names":["MuniRegex","getMuniMap","Promise","resolve","axios","get","responseType","timeout","then","response","muniMapObj","data","split","forEach","line","test","muniRecord","replace","muniRecordArray","length","Error","prefCode","prefName","cityCode","cityName","padStart","parseMuniRecord","_catch","error","console","log","e","reject","api","setupCache","create","baseURL","ttl","interceptors","request","use","config","fullUrl","url","URLSearchParams","params","toString","reverseGeocodeByGsi","lat","lon","reverseGeocodeByLocal","meshCode","japanmesh","toCode","convertLatLonToMesh","prefix","slice","meshDataPath","path","join","__dirname","meshArray","require","meshCodeData","find","smallest","results","muniCd","city_code","lv01Nm","city_name","mesh_code","notes","latLonToAddress","getElevationFromOpenAPI","locations","elevation","_extends","parseFloat","getElevationFromGSI","longitude","latitude","getElevation","searchAddress","q","BaseURL"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.module.js","sources":["../src/muni.ts","../src/m_reverse_geocode.ts","../src/utils.ts","../src/msearch.ts"],"sourcesContent":["// Muni file url\nconst MuniURL = 'https://maps.gsi.go.jp/js/muni.js';\nconst MuniRegex = /GSI\\.MUNI_ARRAY\\[\"\\d+\"\\]\\s*=\\s*'(.*?)';/g;\n\nimport axios from 'axios';\nimport { AddressResults, MuniMap } from './types';\n\n/**\n * parse muni.js\n * @param muniMap\n */\nconst parseMuniMap = (muniMap: string) => {\n const muniMapObj: MuniMap = {};\n const lines = muniMap.split('\\n');\n lines.forEach((line) => {\n if (MuniRegex.test(line)) {\n const muniRecord = parseMuniRecord(line);\n muniMapObj[muniRecord.cityCode] = muniRecord;\n }\n });\n return muniMapObj;\n};\n\n/**\n * parse muni record\n * @param line\n */\nconst parseMuniRecord = (line: string) => {\n const muniRecord = line.replace(MuniRegex, '$1');\n\n const muniRecordArray = muniRecord.split(',');\n\n // validate muni record\n if (muniRecordArray.length !== 4) {\n throw new Error(`invalid muni record: ${muniRecord}`);\n }\n\n let [prefCode, prefName, cityCode, cityName] = muniRecordArray;\n\n // if cityCode is not 5 digits, add 0 to the beginning\n cityCode = cityCode.padStart(5, '0');\n\n // if prefCode is not 2 digits, add 0 to the beginning\n prefCode = prefCode.padStart(2, '0');\n\n return {\n prefCode: prefCode,\n prefName: prefName,\n cityCode: cityCode,\n cityName: cityName,\n };\n};\n\n/**\n * Get muni map (city or ward map by city code) from GSI\n */\nconst getMuniMap = async () => {\n try {\n const response = await axios.get(MuniURL, {\n responseType: 'text',\n timeout: 500,\n });\n\n const muniMap = response.data;\n return parseMuniMap(muniMap);\n } catch (error) {\n console.log(`Failed to get muni map: ${error}`);\n return {};\n }\n};\n\n/**\n * converts muni code to address name.\n *\n * @param muniMap\n * @param muniCode\n */\nconst muniCodeToAddressName = (muniMap: MuniMap, muniCode: string) => {\n const muniRecord = muniMap[muniCode];\n if (!muniRecord) {\n throw new Error(`muni code ${muniCode} not found`);\n }\n\n const add = `${muniRecord.prefName}${muniRecord.cityName}`;\n return add.replace(/ /g, '');\n};\n\n/**\n * converts address result to address name.\n * @param muniMap\n * @param addressResults\n */\nconst addressResultsToAddressName = (\n muniMap: MuniMap,\n addressResults: AddressResults\n) => {\n const mc = addressResults.muniCd;\n const muniName = muniCodeToAddressName(muniMap, mc);\n const addrName = `${muniName}${addressResults.lv01Nm}`;\n return addrName;\n};\n\nconst getMuniMapLocations = async () => {\n const muniMap = await getMuniMap();\n // muniMap is a map of all cities and wards in Japan\n // key: city code, value: { prefCode, prefName, cityCode, cityName }\n // we need to convert this to a map of all locations in Japan\n // key: prefCode , value: { prefName, cities: { key: cityCode, value: { cityCode, cityName, wards: { key: wardCode, value: { wardCode, wardName } } } } }\n\n const muniMapLocations = {};\n Object.keys(muniMap).forEach((cityCode) => {\n const muniRecord = muniMap[cityCode];\n const { prefCode, prefName, cityName } = muniRecord;\n if (!muniMapLocations[prefCode]) {\n muniMapLocations[prefCode] = { prefName, cities: {} };\n }\n\n // if cityName contains ' ', it is a ward\n // otherwise, it is a city\n if (cityName.includes(' ')) {\n // ward name is after ' '\n const [name, wardName] = cityName.split(' ');\n // find city has the same name\n const city: any = Object.values(muniMap).find(\n (c: any) => c.cityName === name\n );\n if (!city) {\n console.log(`City ${name} not found in prefCode ${prefCode}`);\n } else {\n // add ward to city\n muniMapLocations[prefCode].cities[city.cityCode].wards[cityCode] = {\n prefCode,\n cityCode: cityCode,\n cityName: `${name}${wardName}`,\n bigCityFlag: '1',\n bigCityCode: city.cityCode,\n };\n }\n } else {\n muniMapLocations[prefCode].cities[cityCode] = {\n prefCode,\n cityCode,\n cityName,\n wards: {},\n };\n }\n });\n\n // assign bigCityFlag to each city\n Object.keys(muniMapLocations).forEach((prefCode) => {\n const pref = muniMapLocations[prefCode];\n Object.keys(pref.cities).forEach((cityCode) => {\n const city = pref.cities[cityCode];\n const isBigCity = Object.values(city.wards).length > 0;\n if (isBigCity) {\n city.bigCityFlag = '2';\n } else {\n // delete wards\n delete city.wards;\n // if city is tokyo then bigCityFlag is 3, otherwise 0\n if (city.prefCode === '13') {\n city.bigCityFlag = '3';\n } else {\n city.bigCityFlag = '0';\n }\n }\n });\n });\n\n return muniMapLocations;\n};\n\nexport {\n getMuniMap,\n getMuniMapLocations,\n muniCodeToAddressName,\n addressResultsToAddressName,\n};\n","import axios from 'axios';\nimport { setupCache } from 'axios-cache-interceptor';\nimport * as path from 'path';\n\nimport { ReverseGeocodeResults } from './types';\nimport { getMuniMap } from './muni';\nimport { convertLatLonToMesh } from './utils';\nimport { openReverseGeocoder } from '@geolonia/open-reverse-geocoder';\n\nconst api = setupCache(\n axios.create({\n baseURL: 'https://mreversegeocoder.gsi.go.jp',\n timeout: 2000,\n }),\n {\n ttl: 1000 * 60 * 60 * 24, // 24 hours\n }\n);\n\napi.interceptors.request.use((config) => {\n const fullUrl = `${config.baseURL}${config.url}?${new URLSearchParams(\n config.params\n ).toString()}`;\n console.log('Full URL:', fullUrl);\n return config;\n});\n\n/**\n * Reverse geocodes a given latitude and longitude using the mreversegeocoder API.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the reverse geocode results or null if no results are found.\n */\nconst reverseGeocodeByGsi = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n // get address from mreversegeocoder API.\n const params = {\n lat,\n lon,\n };\n const response = await api.get('/reverse-geocoder/LonLatToAddress', {\n responseType: 'json',\n params,\n });\n return response.data;\n};\n\n/**\n * Reverse geocodes a given latitude and longitude by converting them to Tokyo coordinates,\n * calculating the corresponding mesh code, and retrieving the mesh data from the local file system.\n *\n * @param lat - The latitude to reverse geocode.\n * @param lon - The longitude to reverse geocode.\n * @returns A promise that resolves to the reverse geocode results or null if the mesh data is not found.\n *\n * @example\n * ```typescript\n * const results = await reverseGeocodeByLocal(35.6895, 139.6917);\n * if (results) {\n * console.log(results);\n * } else {\n * console.log('No data found for the given coordinates.');\n * }\n * ```\n */\nconst reverseGeocodeByLocal = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n const meshCode = convertLatLonToMesh(lat, lon);\n const prefix = meshCode.slice(0, 4);\n try {\n console.log('Mesh code:', meshCode, 'Prefix:', prefix);\n // Read the mesh data from the local file system using require\n const meshDataPath = path.join(\n __dirname,\n 'data',\n `mesh_data_${prefix}.json`\n );\n const meshData = require(meshDataPath);\n\n // Get the data for the specific mesh code\n const meshArray = meshData[meshCode];\n if (!meshArray || meshArray.length === 0) {\n console.error(`Mesh data not found for code ${meshCode}`);\n return null;\n }\n\n // some mesh code has multiple data, so we need to find the correct one\n // const meshCodeData = meshArray.find((data) => {\n // const [lat1, lon1, lat2, lon2] = data.bbox;\n // // Check if the Tokyo coordinates are within the bounding box\n // return Ntokyo >= lat1 && Ntokyo <= lat2 && Etokyo >= lon1 && Etokyo <= lon2;\n // }) || meshArray[0];\n\n // Acttually, we can use the smallest bbox to get the correct mesh code\n // but we have not bbox data in the mesh data, so we can't use it.\n // So, we just check flag smallest to get the correct mesh code\n // the flag smallest is set to true if the data is the smallest bbox\n // And this flag is set by the data creator.(correct by compare data from GSI)\n const meshCodeData =\n meshArray.find((data: any) => {\n const { smallest } = data;\n return smallest;\n }) || meshArray[0];\n return {\n results: {\n muniCd: meshCodeData?.city_code,\n lv01Nm: meshCodeData?.city_name,\n mesh_code: meshCode,\n notes: meshCodeData?.notes,\n },\n };\n } catch (error) {\n console.error(`Error reading mesh data for prefix ${prefix}:`, error);\n return null;\n }\n};\n\nconst reverseGeocodeByOpenReverseGeocoder = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n const result = await openReverseGeocoder([lon, lat], {});\n if (!result) {\n return null;\n }\n const { code, prefecture, city } = result;\n return {\n results: {\n muniCd: code,\n lv01Nm: city,\n mesh_code: '',\n notes: prefecture,\n },\n };\n};\n\n/**\n * Converts latitude and longitude coordinates to an address.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the reverse geocode results or null.\n *\n * @remarks\n * This function attempts to get the address from a local reverse geocoding service.\n * The commented-out code shows an alternative approach where it first tries to get the address\n * from a GSI (Geospatial Information) service and falls back to the local service in case of an error.\n */\nconst latLonToAddress = (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n // // try to get address from gsi local first\n // // if there is an error, try to get address from GSI\n // try {\n // // return reverseGeocodeByLocal(lat, lon);\n // return reverseGeocodeByGsi(lat, lon);\n // } catch (e) {\n // console.log('Error getting address from GS, falling back to local:', e);\n // // return reverseGeocodeByGsi(lat, lon);\n // return reverseGeocodeByOpenReverseGeocoder(lat, lon);\n // }\n return reverseGeocodeByOpenReverseGeocoder(lat, lon);\n};\n\nconst getElevationFromOpenAPI = async (\n lat: number,\n lon: number\n): Promise<{\n elevation: number;\n longitude: number;\n latitude: number;\n} | null> => {\n // get elevation from OpenAPI\n // https://api.open-elevation.com/api/v1/lookup?locations=43.061434,141.353649\n const response = await axios.get(\n 'https://api.open-elevation.com/api/v1/lookup',\n {\n responseType: 'json',\n timeout: 2000,\n params: {\n locations: `${lat},${lon}`,\n },\n }\n );\n const data = response.data;\n if (!data.results || data.results.length === 0) {\n return null;\n }\n const [elevation] = data.results;\n return {\n ...elevation,\n elevation: parseFloat(elevation.elevation),\n };\n};\n\nconst getElevationFromGSI = async (\n lat: number,\n lon: number\n): Promise<{\n elevation: number;\n longitude: number;\n latitude: number;\n}> => {\n // get elevation from GSI API\n // https://mreversegeocoder.gsi.go.jp/general/dem/scripts/getelevation.php?lon=141.3536498&lat=43.061434\n const response = await api.get('/general/dem/scripts/getelevation.php', {\n responseType: 'json',\n params: {\n lat,\n lon,\n },\n });\n\n const elevation = parseFloat(response.data.elevation);\n return { longitude: lon, latitude: lat, elevation };\n};\n\n/**\n * Retrieves the elevation for a given latitude and longitude.\n *\n * This function first attempts to get the elevation data from the GSI (Geospatial Information Authority of Japan).\n * If there is an error during this process, it falls back to retrieving the elevation data from an OpenAPI.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the elevation data.\n * @throws Will log an error message if both GSI and OpenAPI requests fail.\n */\nconst getElevation = async (lat: number, lon: number) => {\n return getElevationFromGSI(lat, lon);\n};\n\nexport {\n getMuniMap,\n latLonToAddress,\n reverseGeocodeByLocal,\n reverseGeocodeByGsi,\n getElevationFromOpenAPI,\n getElevationFromGSI,\n getElevation,\n};\n","import { japanmesh } from 'japanmesh';\n\nexport function convertLatLonToMesh(lat: number, lon: number) {\n return japanmesh.toCode(lat, lon, 1000); // 1000m is 3rd mesh code\n}\n","import axios from 'axios';\n\nimport { SearchResults } from './types';\n\n// base url for msearch api\nconst BaseURL = 'https://msearch.gsi.go.jp';\n\n/**\n * search address by query\n */\nconst searchAddress = async (q: string): Promise<SearchResults> => {\n const url = `${BaseURL}/address-search/AddressSearch`;\n const response = await axios.get(url, {\n responseType: 'json',\n params: {\n q,\n },\n });\n\n const res = response.data;\n return res;\n};\n\nexport { searchAddress };\n"],"names":["MuniRegex","getMuniMap","Promise","resolve","axios","get","responseType","timeout","then","response","muniMapObj","data","split","forEach","line","test","muniRecord","replace","muniRecordArray","length","Error","prefCode","prefName","cityCode","cityName","padStart","parseMuniRecord","_catch","error","console","log","e","reject","api","setupCache","create","baseURL","ttl","interceptors","request","use","config","fullUrl","url","URLSearchParams","params","toString","reverseGeocodeByGsi","lat","lon","reverseGeocodeByLocal","meshCode","japanmesh","toCode","convertLatLonToMesh","prefix","slice","meshDataPath","path","join","__dirname","meshArray","require","meshCodeData","find","smallest","results","muniCd","city_code","lv01Nm","city_name","mesh_code","notes","latLonToAddress","openReverseGeocoder","result","code","city","prefecture","reverseGeocodeByOpenReverseGeocoder","getElevationFromOpenAPI","locations","elevation","_extends","parseFloat","getElevationFromGSI","longitude","latitude","getElevation","searchAddress","q","BaseURL"],"mappings":"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"}
|
package/dist/index.umd.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("axios"),require("axios-cache-interceptor"),require("path"),require("japanmesh")):"function"==typeof define&&define.amd?define(["exports","axios","axios-cache-interceptor","path","japanmesh"],r):r((e||self).jsMsearchGsiJp={},e.axios,e.axiosCacheInterceptor,e.path,e.japanmesh)}(this,function(e,r,t,n,o){function
|
|
1
|
+
!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?r(exports,require("axios"),require("axios-cache-interceptor"),require("path"),require("japanmesh"),require("@geolonia/open-reverse-geocoder")):"function"==typeof define&&define.amd?define(["exports","axios","axios-cache-interceptor","path","japanmesh","@geolonia/open-reverse-geocoder"],r):r((e||self).jsMsearchGsiJp={},e.axios,e.axiosCacheInterceptor,e.path,e.japanmesh,e.openReverseGeocoder)}(this,function(e,r,t,n,o,a){function s(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}function i(e){if(e&&e.__esModule)return e;var r=Object.create(null);return e&&Object.keys(e).forEach(function(t){if("default"!==t){var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,n.get?n:{enumerable:!0,get:function(){return e[t]}})}}),r.default=e,r}var u=/*#__PURE__*/s(r),c=/*#__PURE__*/i(n);function l(){return l=Object.assign?Object.assign.bind():function(e){for(var r=1;r<arguments.length;r++){var t=arguments[r];for(var n in t)({}).hasOwnProperty.call(t,n)&&(e[n]=t[n])}return e},l.apply(null,arguments)}var d=/GSI\.MUNI_ARRAY\["\d+"\]\s*=\s*'(.*?)';/g,p=t.setupCache(u.default.create({baseURL:"https://mreversegeocoder.gsi.go.jp",timeout:2e3}),{ttl:864e5});p.interceptors.request.use(function(e){var r=""+e.baseURL+e.url+"?"+new URLSearchParams(e.params).toString();return console.log("Full URL:",r),e});var f=function(e,r){try{return Promise.resolve(p.get("/general/dem/scripts/getelevation.php",{responseType:"json",params:{lat:e,lon:r}})).then(function(t){var n=parseFloat(t.data.elevation);return{longitude:r,latitude:e,elevation:n}})}catch(e){return Promise.reject(e)}};e.getElevation=function(e,r){return f(e,r)},e.getElevationFromGSI=f,e.getElevationFromOpenAPI=function(e,r){try{return Promise.resolve(u.default.get("https://api.open-elevation.com/api/v1/lookup",{responseType:"json",timeout:2e3,params:{locations:e+","+r}})).then(function(e){var r=e.data;if(!r.results||0===r.results.length)return null;var t=r.results[0];return l({},t,{elevation:parseFloat(t.elevation)})})}catch(e){return Promise.reject(e)}},e.getMuniMap=function(){try{return Promise.resolve(function(e,r){try{var t=Promise.resolve(u.default.get("https://maps.gsi.go.jp/js/muni.js",{responseType:"text",timeout:500})).then(function(e){return r={},e.data.split("\n").forEach(function(e){if(d.test(e)){var t=function(e){var r=e.replace(d,"$1"),t=r.split(",");if(4!==t.length)throw new Error("invalid muni record: "+r);var n=t[0],o=t[1],a=t[2],s=t[3];return a=a.padStart(5,"0"),{prefCode:n=n.padStart(2,"0"),prefName:o,cityCode:a,cityName:s}}(e);r[t.cityCode]=t}}),r;var r})}catch(e){return r(e)}return t&&t.then?t.then(void 0,r):t}(0,function(e){return console.log("Failed to get muni map: "+e),{}}))}catch(e){return Promise.reject(e)}},e.latLonToAddress=function(e,r){return function(e,r){try{return Promise.resolve(a.openReverseGeocoder([r,e],{})).then(function(e){return e?{results:{muniCd:e.code,lv01Nm:e.city,mesh_code:"",notes:e.prefecture}}:null})}catch(e){return Promise.reject(e)}}(e,r)},e.reverseGeocodeByGsi=function(e,r){try{return Promise.resolve(p.get("/reverse-geocoder/LonLatToAddress",{responseType:"json",params:{lat:e,lon:r}})).then(function(e){return e.data})}catch(e){return Promise.reject(e)}},e.reverseGeocodeByLocal=function(e,r){try{var t=function(e,r){return o.japanmesh.toCode(e,r,1e3)}(e,r),n=t.slice(0,4);try{console.log("Mesh code:",t,"Prefix:",n);var a=c.join(__dirname,"data","mesh_data_"+n+".json"),s=require(a)[t];if(!s||0===s.length)return console.error("Mesh data not found for code "+t),Promise.resolve(null);var i=s.find(function(e){return e.smallest})||s[0];return Promise.resolve({results:{muniCd:null==i?void 0:i.city_code,lv01Nm:null==i?void 0:i.city_name,mesh_code:t,notes:null==i?void 0:i.notes}})}catch(e){return console.error("Error reading mesh data for prefix "+n+":",e),Promise.resolve(null)}}catch(e){return Promise.reject(e)}},e.searchAddress=function(e){try{return Promise.resolve(u.default.get("https://msearch.gsi.go.jp/address-search/AddressSearch",{responseType:"json",params:{q:e}})).then(function(e){return e.data})}catch(e){return Promise.reject(e)}}});
|
|
2
2
|
//# sourceMappingURL=index.umd.js.map
|
package/dist/index.umd.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.umd.js","sources":["../src/muni.ts","../src/m_reverse_geocode.ts","../src/utils.ts","../src/msearch.ts"],"sourcesContent":["// Muni file url\nconst MuniURL = 'https://maps.gsi.go.jp/js/muni.js';\nconst MuniRegex = /GSI\\.MUNI_ARRAY\\[\"\\d+\"\\]\\s*=\\s*'(.*?)';/g;\n\nimport axios from 'axios';\nimport { AddressResults, MuniMap } from './types';\n\n/**\n * parse muni.js\n * @param muniMap\n */\nconst parseMuniMap = (muniMap: string) => {\n const muniMapObj: MuniMap = {};\n const lines = muniMap.split('\\n');\n lines.forEach((line) => {\n if (MuniRegex.test(line)) {\n const muniRecord = parseMuniRecord(line);\n muniMapObj[muniRecord.cityCode] = muniRecord;\n }\n });\n return muniMapObj;\n};\n\n/**\n * parse muni record\n * @param line\n */\nconst parseMuniRecord = (line: string) => {\n const muniRecord = line.replace(MuniRegex, '$1');\n\n const muniRecordArray = muniRecord.split(',');\n\n // validate muni record\n if (muniRecordArray.length !== 4) {\n throw new Error(`invalid muni record: ${muniRecord}`);\n }\n\n let [prefCode, prefName, cityCode, cityName] = muniRecordArray;\n\n // if cityCode is not 5 digits, add 0 to the beginning\n cityCode = cityCode.padStart(5, '0');\n\n // if prefCode is not 2 digits, add 0 to the beginning\n prefCode = prefCode.padStart(2, '0');\n\n return {\n prefCode: prefCode,\n prefName: prefName,\n cityCode: cityCode,\n cityName: cityName,\n };\n};\n\n/**\n * Get muni map (city or ward map by city code) from GSI\n */\nconst getMuniMap = async () => {\n try {\n const response = await axios.get(MuniURL, {\n responseType: 'text',\n timeout: 500,\n });\n\n const muniMap = response.data;\n return parseMuniMap(muniMap);\n } catch (error) {\n console.log(`Failed to get muni map: ${error}`);\n return {};\n }\n};\n\n/**\n * converts muni code to address name.\n *\n * @param muniMap\n * @param muniCode\n */\nconst muniCodeToAddressName = (muniMap: MuniMap, muniCode: string) => {\n const muniRecord = muniMap[muniCode];\n if (!muniRecord) {\n throw new Error(`muni code ${muniCode} not found`);\n }\n\n const add = `${muniRecord.prefName}${muniRecord.cityName}`;\n return add.replace(/ /g, '');\n};\n\n/**\n * converts address result to address name.\n * @param muniMap\n * @param addressResults\n */\nconst addressResultsToAddressName = (\n muniMap: MuniMap,\n addressResults: AddressResults\n) => {\n const mc = addressResults.muniCd;\n const muniName = muniCodeToAddressName(muniMap, mc);\n const addrName = `${muniName}${addressResults.lv01Nm}`;\n return addrName;\n};\n\nconst getMuniMapLocations = async () => {\n const muniMap = await getMuniMap();\n // muniMap is a map of all cities and wards in Japan\n // key: city code, value: { prefCode, prefName, cityCode, cityName }\n // we need to convert this to a map of all locations in Japan\n // key: prefCode , value: { prefName, cities: { key: cityCode, value: { cityCode, cityName, wards: { key: wardCode, value: { wardCode, wardName } } } } }\n\n const muniMapLocations = {};\n Object.keys(muniMap).forEach((cityCode) => {\n const muniRecord = muniMap[cityCode];\n const { prefCode, prefName, cityName } = muniRecord;\n if (!muniMapLocations[prefCode]) {\n muniMapLocations[prefCode] = { prefName, cities: {} };\n }\n\n // if cityName contains ' ', it is a ward\n // otherwise, it is a city\n if (cityName.includes(' ')) {\n // ward name is after ' '\n const [name, wardName] = cityName.split(' ');\n // find city has the same name\n const city: any = Object.values(muniMap).find(\n (c: any) => c.cityName === name\n );\n if (!city) {\n console.log(`City ${name} not found in prefCode ${prefCode}`);\n } else {\n // add ward to city\n muniMapLocations[prefCode].cities[city.cityCode].wards[cityCode] = {\n prefCode,\n cityCode: cityCode,\n cityName: `${name}${wardName}`,\n bigCityFlag: '1',\n bigCityCode: city.cityCode,\n };\n }\n } else {\n muniMapLocations[prefCode].cities[cityCode] = {\n prefCode,\n cityCode,\n cityName,\n wards: {},\n };\n }\n });\n\n // assign bigCityFlag to each city\n Object.keys(muniMapLocations).forEach((prefCode) => {\n const pref = muniMapLocations[prefCode];\n Object.keys(pref.cities).forEach((cityCode) => {\n const city = pref.cities[cityCode];\n const isBigCity = Object.values(city.wards).length > 0;\n if (isBigCity) {\n city.bigCityFlag = '2';\n } else {\n // delete wards\n delete city.wards;\n // if city is tokyo then bigCityFlag is 3, otherwise 0\n if (city.prefCode === '13') {\n city.bigCityFlag = '3';\n } else {\n city.bigCityFlag = '0';\n }\n }\n });\n });\n\n return muniMapLocations;\n};\n\nexport {\n getMuniMap,\n getMuniMapLocations,\n muniCodeToAddressName,\n addressResultsToAddressName,\n};\n","import axios from 'axios';\nimport { setupCache } from 'axios-cache-interceptor';\nimport * as path from 'path';\n\nimport { ReverseGeocodeResults } from './types';\nimport { getMuniMap } from './muni';\nimport { convertLatLonToMesh } from './utils';\n\nconst api = setupCache(\n axios.create({\n baseURL: 'https://mreversegeocoder.gsi.go.jp',\n timeout: 2000,\n }),\n {\n ttl: 1000 * 60 * 60 * 24, // 24 hours\n }\n);\n\napi.interceptors.request.use((config) => {\n const fullUrl = `${config.baseURL}${config.url}?${new URLSearchParams(\n config.params\n ).toString()}`;\n console.log('Full URL:', fullUrl);\n return config;\n});\n\n/**\n * Reverse geocodes a given latitude and longitude using the mreversegeocoder API.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the reverse geocode results or null if no results are found.\n */\nconst reverseGeocodeByGsi = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n // get address from mreversegeocoder API.\n const params = {\n lat,\n lon,\n };\n const response = await api.get('/reverse-geocoder/LonLatToAddress', {\n responseType: 'json',\n params,\n });\n return response.data;\n};\n\n/**\n * Reverse geocodes a given latitude and longitude by converting them to Tokyo coordinates,\n * calculating the corresponding mesh code, and retrieving the mesh data from the local file system.\n *\n * @param lat - The latitude to reverse geocode.\n * @param lon - The longitude to reverse geocode.\n * @returns A promise that resolves to the reverse geocode results or null if the mesh data is not found.\n *\n * @example\n * ```typescript\n * const results = await reverseGeocodeByLocal(35.6895, 139.6917);\n * if (results) {\n * console.log(results);\n * } else {\n * console.log('No data found for the given coordinates.');\n * }\n * ```\n */\nconst reverseGeocodeByLocal = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n const meshCode = convertLatLonToMesh(lat, lon);\n const prefix = meshCode.slice(0, 4);\n try {\n console.log('Mesh code:', meshCode, 'Prefix:', prefix);\n // Read the mesh data from the local file system using require\n const meshDataPath = path.join(\n __dirname,\n 'data',\n `mesh_data_${prefix}.json`\n );\n const meshData = require(meshDataPath);\n\n // Get the data for the specific mesh code\n const meshArray = meshData[meshCode];\n if (!meshArray || meshArray.length === 0) {\n console.error(`Mesh data not found for code ${meshCode}`);\n return null;\n }\n\n // some mesh code has multiple data, so we need to find the correct one\n // const meshCodeData = meshArray.find((data) => {\n // const [lat1, lon1, lat2, lon2] = data.bbox;\n // // Check if the Tokyo coordinates are within the bounding box\n // return Ntokyo >= lat1 && Ntokyo <= lat2 && Etokyo >= lon1 && Etokyo <= lon2;\n // }) || meshArray[0];\n\n // Acttually, we can use the smallest bbox to get the correct mesh code\n // but we have not bbox data in the mesh data, so we can't use it.\n // So, we just check flag smallest to get the correct mesh code\n // the flag smallest is set to true if the data is the smallest bbox\n // And this flag is set by the data creator.(correct by compare data from GSI)\n const meshCodeData =\n meshArray.find((data: any) => {\n const { smallest } = data;\n return smallest;\n }) || meshArray[0];\n return {\n results: {\n muniCd: meshCodeData?.city_code,\n lv01Nm: meshCodeData?.city_name,\n mesh_code: meshCode,\n notes: meshCodeData?.notes,\n },\n };\n } catch (error) {\n console.error(`Error reading mesh data for prefix ${prefix}:`, error);\n return null;\n }\n};\n\n/**\n * Converts latitude and longitude coordinates to an address.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the reverse geocode results or null.\n *\n * @remarks\n * This function attempts to get the address from a local reverse geocoding service.\n * The commented-out code shows an alternative approach where it first tries to get the address\n * from a GSI (Geospatial Information) service and falls back to the local service in case of an error.\n */\nconst latLonToAddress = (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n // try to get address from gsi local first\n // if there is an error, try to get address from GSI\n try {\n // return reverseGeocodeByLocal(lat, lon);\n return reverseGeocodeByGsi(lat, lon);\n } catch (e) {\n console.log('Error getting address from GS, falling back to local:', e);\n // return reverseGeocodeByGsi(lat, lon);\n return reverseGeocodeByLocal(lat, lon);\n }\n};\n\nconst getElevationFromOpenAPI = async (\n lat: number,\n lon: number\n): Promise<{\n elevation: number;\n longitude: number;\n latitude: number;\n} | null> => {\n // get elevation from OpenAPI\n // https://api.open-elevation.com/api/v1/lookup?locations=43.061434,141.353649\n const response = await axios.get(\n 'https://api.open-elevation.com/api/v1/lookup',\n {\n responseType: 'json',\n timeout: 2000,\n params: {\n locations: `${lat},${lon}`,\n },\n }\n );\n const data = response.data;\n if (!data.results || data.results.length === 0) {\n return null;\n }\n const [elevation] = data.results;\n return {\n ...elevation,\n elevation: parseFloat(elevation.elevation),\n };\n};\n\nconst getElevationFromGSI = async (\n lat: number,\n lon: number\n): Promise<{\n elevation: number;\n longitude: number;\n latitude: number;\n}> => {\n // get elevation from GSI API\n // https://mreversegeocoder.gsi.go.jp/general/dem/scripts/getelevation.php?lon=141.3536498&lat=43.061434\n const response = await api.get('/general/dem/scripts/getelevation.php', {\n responseType: 'json',\n params: {\n lat,\n lon,\n },\n });\n\n const elevation = parseFloat(response.data.elevation);\n return { longitude: lon, latitude: lat, elevation };\n};\n\n/**\n * Retrieves the elevation for a given latitude and longitude.\n *\n * This function first attempts to get the elevation data from the GSI (Geospatial Information Authority of Japan).\n * If there is an error during this process, it falls back to retrieving the elevation data from an OpenAPI.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the elevation data.\n * @throws Will log an error message if both GSI and OpenAPI requests fail.\n */\nconst getElevation = async (lat: number, lon: number) => {\n // try to get elevation from GSI first\n // if there is an error, try to get elevation from OpenAPI\n try {\n return await getElevationFromGSI(lat, lon);\n } catch (e) {\n console.log('Error getting elevation from GSI:', e);\n return await getElevationFromOpenAPI(lat, lon);\n }\n};\n\nexport {\n getMuniMap,\n latLonToAddress,\n reverseGeocodeByLocal,\n reverseGeocodeByGsi,\n getElevationFromOpenAPI,\n getElevationFromGSI,\n getElevation,\n};\n","import { japanmesh } from 'japanmesh';\n\nexport function convertLatLonToMesh(lat: number, lon: number) {\n return japanmesh.toCode(lat, lon, 1000); // 1000m is 3rd mesh code\n}\n","import axios from 'axios';\n\nimport { SearchResults } from './types';\n\n// base url for msearch api\nconst BaseURL = 'https://msearch.gsi.go.jp';\n\n/**\n * search address by query\n */\nconst searchAddress = async (q: string): Promise<SearchResults> => {\n const url = `${BaseURL}/address-search/AddressSearch`;\n const response = await axios.get(url, {\n responseType: 'json',\n params: {\n q,\n },\n });\n\n const res = response.data;\n return res;\n};\n\nexport { searchAddress };\n"],"names":["MuniRegex","api","setupCache","axios","create","baseURL","timeout","ttl","interceptors","request","use","config","fullUrl","url","URLSearchParams","params","toString","console","log","reverseGeocodeByGsi","lat","lon","Promise","resolve","get","responseType","then","response","data","e","reject","reverseGeocodeByLocal","meshCode","japanmesh","toCode","convertLatLonToMesh","prefix","slice","meshDataPath","path","join","__dirname","meshArray","require","length","error","meshCodeData","find","smallest","results","muniCd","city_code","lv01Nm","city_name","mesh_code","notes","getElevationFromOpenAPI","locations","elevation","_extends","parseFloat","getElevationFromGSI","longitude","latitude","_catch","muniMapObj","split","forEach","line","test","muniRecord","replace","muniRecordArray","Error","prefCode","prefName","cityCode","cityName","padStart","parseMuniRecord","q","BaseURL"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.umd.js","sources":["../src/muni.ts","../src/m_reverse_geocode.ts","../src/utils.ts","../src/msearch.ts"],"sourcesContent":["// Muni file url\nconst MuniURL = 'https://maps.gsi.go.jp/js/muni.js';\nconst MuniRegex = /GSI\\.MUNI_ARRAY\\[\"\\d+\"\\]\\s*=\\s*'(.*?)';/g;\n\nimport axios from 'axios';\nimport { AddressResults, MuniMap } from './types';\n\n/**\n * parse muni.js\n * @param muniMap\n */\nconst parseMuniMap = (muniMap: string) => {\n const muniMapObj: MuniMap = {};\n const lines = muniMap.split('\\n');\n lines.forEach((line) => {\n if (MuniRegex.test(line)) {\n const muniRecord = parseMuniRecord(line);\n muniMapObj[muniRecord.cityCode] = muniRecord;\n }\n });\n return muniMapObj;\n};\n\n/**\n * parse muni record\n * @param line\n */\nconst parseMuniRecord = (line: string) => {\n const muniRecord = line.replace(MuniRegex, '$1');\n\n const muniRecordArray = muniRecord.split(',');\n\n // validate muni record\n if (muniRecordArray.length !== 4) {\n throw new Error(`invalid muni record: ${muniRecord}`);\n }\n\n let [prefCode, prefName, cityCode, cityName] = muniRecordArray;\n\n // if cityCode is not 5 digits, add 0 to the beginning\n cityCode = cityCode.padStart(5, '0');\n\n // if prefCode is not 2 digits, add 0 to the beginning\n prefCode = prefCode.padStart(2, '0');\n\n return {\n prefCode: prefCode,\n prefName: prefName,\n cityCode: cityCode,\n cityName: cityName,\n };\n};\n\n/**\n * Get muni map (city or ward map by city code) from GSI\n */\nconst getMuniMap = async () => {\n try {\n const response = await axios.get(MuniURL, {\n responseType: 'text',\n timeout: 500,\n });\n\n const muniMap = response.data;\n return parseMuniMap(muniMap);\n } catch (error) {\n console.log(`Failed to get muni map: ${error}`);\n return {};\n }\n};\n\n/**\n * converts muni code to address name.\n *\n * @param muniMap\n * @param muniCode\n */\nconst muniCodeToAddressName = (muniMap: MuniMap, muniCode: string) => {\n const muniRecord = muniMap[muniCode];\n if (!muniRecord) {\n throw new Error(`muni code ${muniCode} not found`);\n }\n\n const add = `${muniRecord.prefName}${muniRecord.cityName}`;\n return add.replace(/ /g, '');\n};\n\n/**\n * converts address result to address name.\n * @param muniMap\n * @param addressResults\n */\nconst addressResultsToAddressName = (\n muniMap: MuniMap,\n addressResults: AddressResults\n) => {\n const mc = addressResults.muniCd;\n const muniName = muniCodeToAddressName(muniMap, mc);\n const addrName = `${muniName}${addressResults.lv01Nm}`;\n return addrName;\n};\n\nconst getMuniMapLocations = async () => {\n const muniMap = await getMuniMap();\n // muniMap is a map of all cities and wards in Japan\n // key: city code, value: { prefCode, prefName, cityCode, cityName }\n // we need to convert this to a map of all locations in Japan\n // key: prefCode , value: { prefName, cities: { key: cityCode, value: { cityCode, cityName, wards: { key: wardCode, value: { wardCode, wardName } } } } }\n\n const muniMapLocations = {};\n Object.keys(muniMap).forEach((cityCode) => {\n const muniRecord = muniMap[cityCode];\n const { prefCode, prefName, cityName } = muniRecord;\n if (!muniMapLocations[prefCode]) {\n muniMapLocations[prefCode] = { prefName, cities: {} };\n }\n\n // if cityName contains ' ', it is a ward\n // otherwise, it is a city\n if (cityName.includes(' ')) {\n // ward name is after ' '\n const [name, wardName] = cityName.split(' ');\n // find city has the same name\n const city: any = Object.values(muniMap).find(\n (c: any) => c.cityName === name\n );\n if (!city) {\n console.log(`City ${name} not found in prefCode ${prefCode}`);\n } else {\n // add ward to city\n muniMapLocations[prefCode].cities[city.cityCode].wards[cityCode] = {\n prefCode,\n cityCode: cityCode,\n cityName: `${name}${wardName}`,\n bigCityFlag: '1',\n bigCityCode: city.cityCode,\n };\n }\n } else {\n muniMapLocations[prefCode].cities[cityCode] = {\n prefCode,\n cityCode,\n cityName,\n wards: {},\n };\n }\n });\n\n // assign bigCityFlag to each city\n Object.keys(muniMapLocations).forEach((prefCode) => {\n const pref = muniMapLocations[prefCode];\n Object.keys(pref.cities).forEach((cityCode) => {\n const city = pref.cities[cityCode];\n const isBigCity = Object.values(city.wards).length > 0;\n if (isBigCity) {\n city.bigCityFlag = '2';\n } else {\n // delete wards\n delete city.wards;\n // if city is tokyo then bigCityFlag is 3, otherwise 0\n if (city.prefCode === '13') {\n city.bigCityFlag = '3';\n } else {\n city.bigCityFlag = '0';\n }\n }\n });\n });\n\n return muniMapLocations;\n};\n\nexport {\n getMuniMap,\n getMuniMapLocations,\n muniCodeToAddressName,\n addressResultsToAddressName,\n};\n","import axios from 'axios';\nimport { setupCache } from 'axios-cache-interceptor';\nimport * as path from 'path';\n\nimport { ReverseGeocodeResults } from './types';\nimport { getMuniMap } from './muni';\nimport { convertLatLonToMesh } from './utils';\nimport { openReverseGeocoder } from '@geolonia/open-reverse-geocoder';\n\nconst api = setupCache(\n axios.create({\n baseURL: 'https://mreversegeocoder.gsi.go.jp',\n timeout: 2000,\n }),\n {\n ttl: 1000 * 60 * 60 * 24, // 24 hours\n }\n);\n\napi.interceptors.request.use((config) => {\n const fullUrl = `${config.baseURL}${config.url}?${new URLSearchParams(\n config.params\n ).toString()}`;\n console.log('Full URL:', fullUrl);\n return config;\n});\n\n/**\n * Reverse geocodes a given latitude and longitude using the mreversegeocoder API.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the reverse geocode results or null if no results are found.\n */\nconst reverseGeocodeByGsi = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n // get address from mreversegeocoder API.\n const params = {\n lat,\n lon,\n };\n const response = await api.get('/reverse-geocoder/LonLatToAddress', {\n responseType: 'json',\n params,\n });\n return response.data;\n};\n\n/**\n * Reverse geocodes a given latitude and longitude by converting them to Tokyo coordinates,\n * calculating the corresponding mesh code, and retrieving the mesh data from the local file system.\n *\n * @param lat - The latitude to reverse geocode.\n * @param lon - The longitude to reverse geocode.\n * @returns A promise that resolves to the reverse geocode results or null if the mesh data is not found.\n *\n * @example\n * ```typescript\n * const results = await reverseGeocodeByLocal(35.6895, 139.6917);\n * if (results) {\n * console.log(results);\n * } else {\n * console.log('No data found for the given coordinates.');\n * }\n * ```\n */\nconst reverseGeocodeByLocal = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n const meshCode = convertLatLonToMesh(lat, lon);\n const prefix = meshCode.slice(0, 4);\n try {\n console.log('Mesh code:', meshCode, 'Prefix:', prefix);\n // Read the mesh data from the local file system using require\n const meshDataPath = path.join(\n __dirname,\n 'data',\n `mesh_data_${prefix}.json`\n );\n const meshData = require(meshDataPath);\n\n // Get the data for the specific mesh code\n const meshArray = meshData[meshCode];\n if (!meshArray || meshArray.length === 0) {\n console.error(`Mesh data not found for code ${meshCode}`);\n return null;\n }\n\n // some mesh code has multiple data, so we need to find the correct one\n // const meshCodeData = meshArray.find((data) => {\n // const [lat1, lon1, lat2, lon2] = data.bbox;\n // // Check if the Tokyo coordinates are within the bounding box\n // return Ntokyo >= lat1 && Ntokyo <= lat2 && Etokyo >= lon1 && Etokyo <= lon2;\n // }) || meshArray[0];\n\n // Acttually, we can use the smallest bbox to get the correct mesh code\n // but we have not bbox data in the mesh data, so we can't use it.\n // So, we just check flag smallest to get the correct mesh code\n // the flag smallest is set to true if the data is the smallest bbox\n // And this flag is set by the data creator.(correct by compare data from GSI)\n const meshCodeData =\n meshArray.find((data: any) => {\n const { smallest } = data;\n return smallest;\n }) || meshArray[0];\n return {\n results: {\n muniCd: meshCodeData?.city_code,\n lv01Nm: meshCodeData?.city_name,\n mesh_code: meshCode,\n notes: meshCodeData?.notes,\n },\n };\n } catch (error) {\n console.error(`Error reading mesh data for prefix ${prefix}:`, error);\n return null;\n }\n};\n\nconst reverseGeocodeByOpenReverseGeocoder = async (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n const result = await openReverseGeocoder([lon, lat], {});\n if (!result) {\n return null;\n }\n const { code, prefecture, city } = result;\n return {\n results: {\n muniCd: code,\n lv01Nm: city,\n mesh_code: '',\n notes: prefecture,\n },\n };\n};\n\n/**\n * Converts latitude and longitude coordinates to an address.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the reverse geocode results or null.\n *\n * @remarks\n * This function attempts to get the address from a local reverse geocoding service.\n * The commented-out code shows an alternative approach where it first tries to get the address\n * from a GSI (Geospatial Information) service and falls back to the local service in case of an error.\n */\nconst latLonToAddress = (\n lat: number,\n lon: number\n): Promise<ReverseGeocodeResults | null> => {\n // // try to get address from gsi local first\n // // if there is an error, try to get address from GSI\n // try {\n // // return reverseGeocodeByLocal(lat, lon);\n // return reverseGeocodeByGsi(lat, lon);\n // } catch (e) {\n // console.log('Error getting address from GS, falling back to local:', e);\n // // return reverseGeocodeByGsi(lat, lon);\n // return reverseGeocodeByOpenReverseGeocoder(lat, lon);\n // }\n return reverseGeocodeByOpenReverseGeocoder(lat, lon);\n};\n\nconst getElevationFromOpenAPI = async (\n lat: number,\n lon: number\n): Promise<{\n elevation: number;\n longitude: number;\n latitude: number;\n} | null> => {\n // get elevation from OpenAPI\n // https://api.open-elevation.com/api/v1/lookup?locations=43.061434,141.353649\n const response = await axios.get(\n 'https://api.open-elevation.com/api/v1/lookup',\n {\n responseType: 'json',\n timeout: 2000,\n params: {\n locations: `${lat},${lon}`,\n },\n }\n );\n const data = response.data;\n if (!data.results || data.results.length === 0) {\n return null;\n }\n const [elevation] = data.results;\n return {\n ...elevation,\n elevation: parseFloat(elevation.elevation),\n };\n};\n\nconst getElevationFromGSI = async (\n lat: number,\n lon: number\n): Promise<{\n elevation: number;\n longitude: number;\n latitude: number;\n}> => {\n // get elevation from GSI API\n // https://mreversegeocoder.gsi.go.jp/general/dem/scripts/getelevation.php?lon=141.3536498&lat=43.061434\n const response = await api.get('/general/dem/scripts/getelevation.php', {\n responseType: 'json',\n params: {\n lat,\n lon,\n },\n });\n\n const elevation = parseFloat(response.data.elevation);\n return { longitude: lon, latitude: lat, elevation };\n};\n\n/**\n * Retrieves the elevation for a given latitude and longitude.\n *\n * This function first attempts to get the elevation data from the GSI (Geospatial Information Authority of Japan).\n * If there is an error during this process, it falls back to retrieving the elevation data from an OpenAPI.\n *\n * @param lat - The latitude coordinate.\n * @param lon - The longitude coordinate.\n * @returns A promise that resolves to the elevation data.\n * @throws Will log an error message if both GSI and OpenAPI requests fail.\n */\nconst getElevation = async (lat: number, lon: number) => {\n return getElevationFromGSI(lat, lon);\n};\n\nexport {\n getMuniMap,\n latLonToAddress,\n reverseGeocodeByLocal,\n reverseGeocodeByGsi,\n getElevationFromOpenAPI,\n getElevationFromGSI,\n getElevation,\n};\n","import { japanmesh } from 'japanmesh';\n\nexport function convertLatLonToMesh(lat: number, lon: number) {\n return japanmesh.toCode(lat, lon, 1000); // 1000m is 3rd mesh code\n}\n","import axios from 'axios';\n\nimport { SearchResults } from './types';\n\n// base url for msearch api\nconst BaseURL = 'https://msearch.gsi.go.jp';\n\n/**\n * search address by query\n */\nconst searchAddress = async (q: string): Promise<SearchResults> => {\n const url = `${BaseURL}/address-search/AddressSearch`;\n const response = await axios.get(url, {\n responseType: 'json',\n params: {\n q,\n },\n });\n\n const res = response.data;\n return res;\n};\n\nexport { searchAddress };\n"],"names":["MuniRegex","api","setupCache","axios","create","baseURL","timeout","ttl","interceptors","request","use","config","fullUrl","url","URLSearchParams","params","toString","console","log","getElevationFromGSI","lat","lon","Promise","resolve","get","responseType","then","response","elevation","parseFloat","data","longitude","latitude","e","reject","locations","results","length","_extends","muniMapObj","split","forEach","line","test","muniRecord","replace","muniRecordArray","Error","prefCode","prefName","cityCode","cityName","padStart","parseMuniRecord","_catch","error","openReverseGeocoder","result","muniCd","code","lv01Nm","city","mesh_code","notes","prefecture","reverseGeocodeByOpenReverseGeocoder","meshCode","japanmesh","toCode","convertLatLonToMesh","prefix","slice","meshDataPath","path","join","__dirname","meshArray","require","meshCodeData","find","smallest","city_code","city_name","q","BaseURL"],"mappings":"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"}
|
|
@@ -65,5 +65,5 @@ declare const getElevation: (lat: number, lon: number) => Promise<{
|
|
|
65
65
|
elevation: number;
|
|
66
66
|
longitude: number;
|
|
67
67
|
latitude: number;
|
|
68
|
-
}
|
|
68
|
+
}>;
|
|
69
69
|
export { getMuniMap, latLonToAddress, reverseGeocodeByLocal, reverseGeocodeByGsi, getElevationFromOpenAPI, getElevationFromGSI, getElevation, };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sk-global/js-msearch-gsi-jp",
|
|
3
3
|
"description": "A client library for APIs that presented by Geospatial Information Authority of Japan",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.27",
|
|
5
5
|
"source": "src/index.ts",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.module.js",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"author": "SK-Global",
|
|
52
52
|
"dependencies": {
|
|
53
|
+
"@geolonia/open-reverse-geocoder": "^0.1.0",
|
|
53
54
|
"axios": "^1.7.3",
|
|
54
55
|
"axios-cache-interceptor": "^1.6.0",
|
|
55
56
|
"csv-parser": "^3.0.0",
|