序論
javascript で、proj4jsライブラリを利用し、EPSGコードの座標の変換を行う方法を示す。
ここで想定しているEPSGコードは、proj4jがデフォルトでサポートしていないもの(例えば 平面直角座標系(EPSG:30161~30179))。
proj4j側でサポートされているものについては、proj4js公式の「Named Projections」を参照。
結論
- EPSG公式でEPSGコードを検索し、「proj.4 string」を取得する。具体的には以下のURLをGETする。
https://epsg.io/{epsgのコード部分}.proj4
(例えば 「EPSG:30169」なら「https://epsg.io/30169.proj4」)
2. 取得した「proj.4 string」を引数(fromProjection、toProjection)として、proj4jsのproj4関数を実行する。
(例えば平面直角座標系第9系での(x, y)=(10, 20)を、緯度経度での座標に変換するなら以下のようになる。
const [lon, lat] = proj4(
"+proj=tmerc +lat_0=36 +lon_0=139.833333333333 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs",
"WGS84",
[10, 20]
);
)
付録
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>サンプル</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.19.10/proj4.min.js"></script>
<script>
window.onload = async () => {
convertXY();
document.getElementById("fromEpsg").addEventListener("change", () => { convertXY() });
document.getElementById("fromX").addEventListener("input", () => { convertXY() });
document.getElementById("fromY").addEventListener("input", () => { convertXY() });
document.getElementById("toEpsg").addEventListener("change", () => { convertXY() });
};
function convertXY() {
const fromEpsgStr = document.getElementById("fromEpsg").value;
const fromXStr = document.getElementById("fromX").value;
const fromYStr = document.getElementById("fromY").value;
const toEpsgStr = document.getElementById("toEpsg").value;
const fromPoint = [Number(fromXStr), Number(fromYStr)];
// const from = await (await fetch(`https://epsg.io/${codeOfEpsgCode}.proj4`)).text();
const from = projMap.get(fromEpsgStr);
const to = projMap.get(toEpsgStr)
const [toX, toY] = proj4(from, to, fromPoint);
document.getElementById("toXY").value = `${toX}\n${toY}`;
}
const projMap = new Map([
["3857", "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crs"],
["4326", "+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees"],
["30161", "+proj=tmerc +lat_0=33 +lon_0=129.5 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30162", "+proj=tmerc +lat_0=33 +lon_0=131 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30163", "+proj=tmerc +lat_0=36 +lon_0=132.166666666667 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30164", "+proj=tmerc +lat_0=33 +lon_0=133.5 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30165", "+proj=tmerc +lat_0=36 +lon_0=134.333333333333 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30166", "+proj=tmerc +lat_0=36 +lon_0=136 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30167", "+proj=tmerc +lat_0=36 +lon_0=137.166666666667 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30168", "+proj=tmerc +lat_0=36 +lon_0=138.5 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30169", "+proj=tmerc +lat_0=36 +lon_0=139.833333333333 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30170", "+proj=tmerc +lat_0=40 +lon_0=140.833333333333 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30171", "+proj=tmerc +lat_0=44 +lon_0=140.25 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30172", "+proj=tmerc +lat_0=44 +lon_0=142.25 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30173", "+proj=tmerc +lat_0=44 +lon_0=144.25 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30174", "+proj=tmerc +lat_0=26 +lon_0=142 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30175", "+proj=tmerc +lat_0=26 +lon_0=127.5 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30176", "+proj=tmerc +lat_0=26 +lon_0=124 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30177", "+proj=tmerc +lat_0=26 +lon_0=131 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30178", "+proj=tmerc +lat_0=20 +lon_0=136 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30179", "+proj=tmerc +lat_0=26 +lon_0=154 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
]);
</script>
</head>
<body>
<div>
<div>
<div>
<label>from</label>
</div>
<div style="margin:10px">
<label>EPSG:</label>
<select id="fromEpsg">
<option value="3857">3857(WebMercator)</option>
<option value="4326">4326(WGS48)</option>
<option value="30161">30161(Japan Plane Rectangular CS I)</option>
<option value="30162">30162(Japan Plane Rectangular CS II)</option>
<option value="30163">30163(Japan Plane Rectangular CS III)</option>
<option value="30164">30164(Japan Plane Rectangular CS IV)</option>
<option value="30165">30165(Japan Plane Rectangular CS V)</option>
<option value="30166">30166(Japan Plane Rectangular CS VI)</option>
<option value="30167">30167(Japan Plane Rectangular CS VII)</option>
<option value="30168">30168(Japan Plane Rectangular CS VIII)</option>
<option value="30169">30169(Japan Plane Rectangular CS IX)</option>
<option value="30170">30170(Japan Plane Rectangular CS X)</option>
<option value="30171">30171(Japan Plane Rectangular CS XI)</option>
<option value="30172">30172(Japan Plane Rectangular CS XII)</option>
<option value="30173">30173(Japan Plane Rectangular CS XIII)</option>
<option value="30174">30174(Japan Plane Rectangular CS XIV)</option>
<option value="30175">30175(Japan Plane Rectangular CS XV)</option>
<option value="30176">30176(Japan Plane Rectangular CS XVI)</option>
<option value="30177">30177(Japan Plane Rectangular CS XVII)</option>
<option value="30178">30178(Japan Plane Rectangular CS XVIII)</option>
<option value="30179">30179(Japan Plane Rectangular CS XIX)</option>
</select>
</div>
<div style="margin:10px">
<label>x, y(longitude, latitude): </label>
<input id="fromX" type="number" placeholder="0" />
<label>,</label>
<input id="fromY" type="number" placeholder="0" />
</div>
</div>
<div>
<div>
<label>to</label>
</div>
<div style="margin:10px">
<label>EPSG:</label>
<select id="toEpsg">
<option value="3857">3857(WebMercator)</option>
<option value="4326">4326(WGS48)</option>
<option value="30161">30161(Japan Plane Rectangular CS I)</option>
<option value="30162">30162(Japan Plane Rectangular CS II)</option>
<option value="30163">30163(Japan Plane Rectangular CS III)</option>
<option value="30164">30164(Japan Plane Rectangular CS IV)</option>
<option value="30165">30165(Japan Plane Rectangular CS V)</option>
<option value="30166">30166(Japan Plane Rectangular CS VI)</option>
<option value="30167">30167(Japan Plane Rectangular CS VII)</option>
<option value="30168">30168(Japan Plane Rectangular CS VIII)</option>
<option value="30169">30169(Japan Plane Rectangular CS IX)</option>
<option value="30170">30170(Japan Plane Rectangular CS X)</option>
<option value="30171">30171(Japan Plane Rectangular CS XI)</option>
<option value="30172">30172(Japan Plane Rectangular CS XII)</option>
<option value="30173">30173(Japan Plane Rectangular CS XIII)</option>
<option value="30174">30174(Japan Plane Rectangular CS XIV)</option>
<option value="30175">30175(Japan Plane Rectangular CS XV)</option>
<option value="30176">30176(Japan Plane Rectangular CS XVI)</option>
<option value="30177">30177(Japan Plane Rectangular CS XVII)</option>
<option value="30178">30178(Japan Plane Rectangular CS XVIII)</option>
<option value="30179">30179(Japan Plane Rectangular CS XIX)</option>
</select>
</div>
<div style="margin:10px">
<label>x, y(longitude, latitude): </label>
<textarea id="toXY" readonly style="width:200px;height:50px;"></textarea>
</div>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>サンプル</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.19.10/proj4.min.js"></script>
<style>
body {
padding: 0;
margin: 0
}
html,
body,
#map {
height: 100%;
width: 100%;
}
</style>
<script>
window.onload = async () => {
const map = L.map('map');
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
}).addTo(map);
map.setView(
[36.0031693, 138.4968616],
5
);
addOriginPoint(map, "30161");
addOriginPoint(map, "30162");
addOriginPoint(map, "30163");
addOriginPoint(map, "30164");
addOriginPoint(map, "30165");
addOriginPoint(map, "30166");
addOriginPoint(map, "30167");
addOriginPoint(map, "30168");
addOriginPoint(map, "30169");
addOriginPoint(map, "30170");
addOriginPoint(map, "30171");
addOriginPoint(map, "30172");
addOriginPoint(map, "30173");
addOriginPoint(map, "30174");
addOriginPoint(map, "30175");
addOriginPoint(map, "30176");
addOriginPoint(map, "30177");
addOriginPoint(map, "30178");
addOriginPoint(map, "30179");
};
const projMap = new Map([
["30161", "+proj=tmerc +lat_0=33 +lon_0=129.5 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30162", "+proj=tmerc +lat_0=33 +lon_0=131 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30163", "+proj=tmerc +lat_0=36 +lon_0=132.166666666667 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30164", "+proj=tmerc +lat_0=33 +lon_0=133.5 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30165", "+proj=tmerc +lat_0=36 +lon_0=134.333333333333 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30166", "+proj=tmerc +lat_0=36 +lon_0=136 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30167", "+proj=tmerc +lat_0=36 +lon_0=137.166666666667 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30168", "+proj=tmerc +lat_0=36 +lon_0=138.5 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30169", "+proj=tmerc +lat_0=36 +lon_0=139.833333333333 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30170", "+proj=tmerc +lat_0=40 +lon_0=140.833333333333 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30171", "+proj=tmerc +lat_0=44 +lon_0=140.25 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30172", "+proj=tmerc +lat_0=44 +lon_0=142.25 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30173", "+proj=tmerc +lat_0=44 +lon_0=144.25 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30174", "+proj=tmerc +lat_0=26 +lon_0=142 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30175", "+proj=tmerc +lat_0=26 +lon_0=127.5 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30176", "+proj=tmerc +lat_0=26 +lon_0=124 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30177", "+proj=tmerc +lat_0=26 +lon_0=131 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30178", "+proj=tmerc +lat_0=20 +lon_0=136 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
["30179", "+proj=tmerc +lat_0=26 +lon_0=154 +k=0.9999 +x_0=0 +y_0=0 +ellps=bessel +towgs84=-146.414,507.337,680.507,0,0,0,0 +units=m +no_defs +type=crs"],
]);
function addOriginPoint(map, codeOfEpsgCode) {
const originPoint = [0, 0];
// const from = await (await fetch(`https://epsg.io/${codeOfEpsgCode}.proj4`)).text();
const from = projMap.get(codeOfEpsgCode);
const [lon, lat] = proj4(from, "WGS84", originPoint);
L.marker([lat, lon])
.addTo(map)
.bindPopup(`EPSG:${codeOfEpsgCode}, (${lat}, ${lon})`);
}
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>