Repository: dkaoster/taiwan-atlas
Branch: master
Commit: 60ac5fdae46c
Files: 18
Total size: 55.7 KB
Directory structure:
gitextract_6wpgu_11/
├── .eslintignore
├── .eslintrc.js
├── .github/
│ └── workflows/
│ ├── eslint.yml
│ └── npm-publish.yml
├── .gitignore
├── LICENSE
├── README.md
├── compBordersGeo.js
├── generateimg.sh
├── package.json
├── prepublish.sh
├── properties.js
├── rollup.config.js
├── src/
│ ├── bounds.js
│ ├── fit.js
│ ├── math.js
│ └── mercatorTw.js
└── utils/
└── districts.json
================================================
FILE CONTENTS
================================================
================================================
FILE: .eslintignore
================================================
node_modules
*.cjs.js
*.es.js
================================================
FILE: .eslintrc.js
================================================
module.exports = {
parserOptions: {
ecmaVersion: 2019,
sourceType: 'module',
},
env: {
es6: true,
},
extends: ['eslint-config-airbnb-base'],
rules: {
'no-nested-ternary': 0,
'import/no-extraneous-dependencies': 0,
'no-param-reassign': 0,
},
};
================================================
FILE: .github/workflows/eslint.yml
================================================
name: Lint
on: push
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Check out Git repository
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v1
with:
node-version: 14
# ESLint and Prettier must be in `package.json`
- name: Install Node.js dependencies
run: npm install
- name: Run linters
uses: wearerequired/lint-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# Enable linters
eslint: true
================================================
FILE: .github/workflows/npm-publish.yml
================================================
name: Publish to NPM
on:
push:
tags:
- '*'
jobs:
publish:
name: Publish to NPM
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: 14
- run: npm install
- uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_TOKEN }}
================================================
FILE: .gitignore
================================================
build/
node_modules
*-10t.json
base*.json
*.es.js
*.cjs.js
*.svg
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2020 Daniel Kao
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Taiwan Atlas TopoJSON
Similar to the [topojson/us-atlas](https://github.com/topojson/us-atlas) project, this repository provides a topojson redistribution of the shapefiles provided by Taiwan's Ministry of the Interior. See [the demo](https://observablehq.com/@dkaoster/taiwan-map) for usage example.
All of these files are provided at a scale of 1:10 thousand.
## File Reference
<a href="#villages-10t.json" name="villages-10t.json">#</a> <b>villages-10t.json</b> · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/villages-10t.json "Source")
A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections <i>villages</i>, <i>towns</i>, <i>counties</i>, and <i>nation</i>. The geometry is quantized and simplified, but not projected. This topology is derived from the Ministry of the Interior’s [村里界圖(TWD97經緯度)](https://data.gov.tw/dataset/7438). The town boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) villages, the county boundaries by merging towns, and the nation boundary is computed by merging counties, ensuring a consistent topology.
<a href="#villages-mercator-10t.json" name="villages-mercator-10t.json">#</a> <b>villages-mercator-10t.json</b> · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/villages-mercator-10t.json "Source")
A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections <i>villages</i>, <i>towns</i>, <i>counties</i>, and <i>nation</i>. The geometry is quantized, simplified, and projected with the mercatorTw projection. This topology is derived from the Ministry of the Interior’s [村里界圖(TWD97經緯度)](https://data.gov.tw/dataset/7438). The town boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) villages, the county boundaries by merging towns, and the nation boundary is computed by merging counties, ensuring a consistent topology. This file also contains a compBorders object for optionally drawing the borders of the composed areas.
<a href="#towns-10t.json" name="towns-10t.json">#</a> <b>towns-10t.json</b> · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/towns-10t.json "Source")
A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections <i>towns</i>, <i>counties</i>, and <i>nation</i>. The geometry is quantized and simplified, but not projected. This topology is derived from the Ministry of the Interior’s [鄉鎮市區界線(TWD97經緯度)](https://data.gov.tw/dataset/7441). The county boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) towns and the nation boundaries by merging counties, ensuring a consistent topology.
<a href="#towns-mercator-10t.json" name="towns-mercator-10t.json">#</a> <b>towns-mercator-10t.json</b> · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/towns-mercator-10t.json "Source")
A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections <i>towns</i>, <i>counties</i>, and <i>nation</i>. The geometry is quantized, simplified, and projected with the mercatorTw projection. This topology is derived from the Ministry of the Interior’s [鄉鎮市區界線(TWD97經緯度)](https://data.gov.tw/dataset/7441). The county boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) towns and the nation boundaries by merging counties, ensuring a consistent topology. This file also contains a compBorders object for optionally drawing the borders of the composed areas.
<a href="#districts-10t.json" name="districts-10t.json">#</a> <b>districts-10t.json</b> · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/districts-10t.json "Source")
A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections <i>districts</i> specifying legislative districts, <i>counties</i>, and <i>nation</i>. The geometry is quantized and simplified, but not projected. This topology is derived from the Ministry of the Interior’s [鄉鎮市區界線(TWD97經緯度)](https://data.gov.tw/dataset/7441) and combined via the districts specified in [this json file](https://github.com/dkaoster/taiwan-atlas/blob/master/utils/districts.json). The county boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) districts and the nation boundaries by merging counties, ensuring a consistent topology.
<a href="#districts-mercator-10t.json" name="districts-mercator-10t.json">#</a> <b>districts-mercator-10t.json</b> · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/districts-mercator-10t.json "Source")
A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections <i>districts</i> specifying legislative districts, <i>counties</i>, and <i>nation</i>. The geometry is quantized, simplified, and projected with the mercatorTw projection. This topology is derived from the Ministry of the Interior’s [鄉鎮市區界線(TWD97經緯度)](https://data.gov.tw/dataset/7441) and combined via the districts specified in [this json file](https://github.com/dkaoster/taiwan-atlas/blob/master/utils/districts.json). The county boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) districts and the nation boundaries by merging counties, ensuring a consistent topology. This file also contains a compBorders object for optionally drawing the borders of the composed areas.
<a href="#counties-10t.json" name="counties-10t.json">#</a> <b>counties-10t.json</b> · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/counties-10t.json "Source")
A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections <i>counties</i>, and <i>nation</i>. The geometry is quantized and simplified, but not projected. This topology is derived from the Ministry of the Interior’s [直轄市、縣市界線(TWD97經緯度)](https://data.gov.tw/dataset/7442). The nation boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) counties, ensuring a consistent topology.
<a href="#counties-mercator-10t.json" name="counties-mercator-10t.json">#</a> <b>counties-mercator-10t.json</b> · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/counties-mercator-10t.json "Source")
A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections <i>counties</i> and <i>nation</i>. The geometry is quantized, simplified, and projected with the mercatorTw projection. This topology is derived from the Ministry of the Interior’s [直轄市、縣市界線(TWD97經緯度)](https://data.gov.tw/dataset/7442). The nation boundaries are computed by [merging](https://github.com/topojson/topojson-client/blob/master/README.md#merge) counties, ensuring a consistent topology. This file also contains a compBorders object for optionally drawing the borders of the composed areas.
<a href="#nation-10t.json" name="nation-10t.json">#</a> <b>nation-10t.json</b> · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/nation-10t.json "Source")
A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections <i>nation</i>. The geometry is quantized and simplified, but not projected. This topology is derived from the Ministry of the Interior’s [直轄市、縣市界線(TWD97經緯度)](https://data.gov.tw/dataset/7442).
<a href="#nation-mercator-10t.json" name="nation-mercator-10t.json">#</a> <b>nation-mercator-10t.json</b> · [Download](https://cdn.jsdelivr.net/npm/taiwan-atlas/nation-mercator-10t.json "Source")
A [TopoJSON file](https://github.com/topojson/topojson-specification/blob/master/README.md#21-topology-objects) containing the geometry collections <i>nation</i>. The geometry is quantized, simplified, and projected with the mercatorTw projection. This topology is derived from the Ministry of the Interior’s [直轄市、縣市界線(TWD97經緯度)](https://data.gov.tw/dataset/7442). This file also contains a compBorders object for optionally drawing the borders of the composed areas.
<a href="#tw.objects.nation" name="tw.objects.nation">#</a> tw.objects<b>.nation</b>
<img src="https://raw.githubusercontent.com/dkaoster/taiwan-atlas/master/img/nation.png" width="50%">
The nation object has two fields:
- nation.properties.ID - "TW"
- nation.properties.NAME - "Taiwan"
<a href="#tw.objects.counties" name="tw.objects.counties">#</a> tw.objects<b>.counties</b>
<img src="https://raw.githubusercontent.com/dkaoster/taiwan-atlas/master/img/counties.png" width="50%">
The county object has the following fields:
- county.properties.COUNTYNAME - The name of the county in Chinese
- county.properties.COUNTYENG - The name of the county in English
- county.properties.COUNTYID - The character specifying id
- county.properties.COUNTYCODE - The five digit county code
<a href="#tw.objects.towns" name="tw.objects.towns">#</a> tw.objects<b>.towns</b>
<img src="https://raw.githubusercontent.com/dkaoster/taiwan-atlas/master/img/towns.png" width="50%">
The town object has the following fields in addition to the county fields:
- town.properties.TOWNNAME - The name of the county in Chinese
- town.properties.TOWNENG - The name of the county in English
- town.properties.TOWNID - The character specifying id
- town.properties.TOWNCODE - The eight digit county code
<a href="#tw.objects.districts" name="tw.objects.districts">#</a> tw.objects<b>.districts</b>
<img src="https://raw.githubusercontent.com/dkaoster/taiwan-atlas/master/img/districts.png" width="50%">
The district object has the following fields in addition to the county fields:
- district.properties.DISTRICTCODE - The eight digit county code dash (-) the district number
<a href="#tw.objects.villages" name="tw.objects.villages">#</a> tw.objects<b>.villages</b>
<img src="https://raw.githubusercontent.com/dkaoster/taiwan-atlas/master/img/villages.png" width="50%">
The village object has the following fields in addition to the town and county fields:
- village.properties.VILLNAME - The name of the village in Chinese
- village.properties.VILLENG - The name of the village in English
- village.properties.VILLID - The village specifying id
- village.properties.VILLCODE - The 11 digit county code
The compBorders object has the following fields:
- compBorders.properties.BORDERLEVEL - The administrative level that this border encompasses.
- compBorders.properties.NAME - The name in Chinese of the administrative area that this border encompasses.
- compBorders.properties.ID - The id of the administrative area that this border encompasses.
- compBorders.properties.CODE - The name of the administrative area that this border encompasses.
- compBorders.properties.ENG - The name in English of the administrative area that this border encompasses.
## MercatorTw Projection
`mercatorTw.js` uses a Taiwan-centric composite projection of four [d3.geoMercator](https://github.com/d3/d3-geo#geoMercator) projections: One for the main island, and one for each of Penghu, Kinmen, Lienchiang, and Wuqiu respectively.
`mercatorTw.getCompositionBorders()` returns a svg path string of the borders, given the current scale and translation.
This package exports the mercatorTw projection and can be used in your own projects.
```js
import mercatorTw from 'taiwan-atlas';
```
## License
MIT
================================================
FILE: compBordersGeo.js
================================================
// eslint-disable-next-line import/no-unresolved
const mercatorTw = require('./mercatorTw.cjs.js');
// Initialize Projection
let merc = mercatorTw();
// Read center from first argument or from defaultCenter
const translate = process.argv[2] && JSON.parse(process.argv[2]);
if (translate) merc = merc.translate(translate);
// Read scale from second argument or from defaultScale
const scale = process.argv[3] && parseInt(process.argv[3], 10);
if (scale) merc = merc.scale(scale);
// The properties that we will add to the box
const properties = {
lienchiang: {
BORDERLEVEL: 'COUNTY', NAME: '連江縣', ID: 'Z', CODE: '09007', ENG: 'Lienchiang County',
},
penghu: {
BORDERLEVEL: 'COUNTY', NAME: '澎湖縣', ID: 'X', CODE: '10016', ENG: 'Penghu County',
},
kinmen: {
BORDERLEVEL: 'COUNTY', NAME: '金門縣', ID: 'W', CODE: '09020', ENG: 'Kinmen County',
},
wuqiu: {
BORDERLEVEL: 'TOWN', NAME: '烏坵鄉', ID: 'W06', CODE: '09020060', ENG: 'Wuqiu Township',
},
};
// Generate the features
const features = merc.compositionBorderPoints()
.map((border) => ({
type: 'Feature',
geometry: { type: 'Polygon', coordinates: [border.coords] },
properties: properties[border.name],
}));
// Print to stdout
features.forEach((feature) => {
process.stdout.write(JSON.stringify(feature));
process.stdout.write('\n');
});
================================================
FILE: generateimg.sh
================================================
#!/bin/bash
# Create the border json
topo2geo compBorders=- < nation-mercator-10t.json > img/base-border.json
# Villages
topo2geo villages=- < villages-mercator-10t.json > img/base-villages.json
geojson-merge img/base-villages.json img/base-border.json | geo2svg -o img/villages.svg -w 450 -h 600
svgexport img/villages.svg img/villages.png 2x "path {stroke-width: 0.3px;}"
# Districts
topo2geo districts=- < districts-mercator-10t.json > img/base-districts.json
geojson-merge img/base-districts.json img/base-border.json | geo2svg -o img/districts.svg -w 450 -h 600
svgexport img/districts.svg img/districts.png 2x "path {stroke-width: 0.5px;}"
# Towns
topo2geo towns=- < towns-mercator-10t.json > img/base-towns.json
geojson-merge img/base-towns.json img/base-border.json | geo2svg -o img/towns.svg -w 450 -h 600
svgexport img/towns.svg img/towns.png 2x "path {stroke-width: 0.5px;}"
# Counties
topo2geo counties=- < counties-mercator-10t.json > img/base-counties.json
geojson-merge img/base-counties.json img/base-border.json | geo2svg -o img/counties.svg -w 450 -h 600
svgexport img/counties.svg img/counties.png 2x
# Nation
topo2geo nation=- < nation-mercator-10t.json > img/base-nation.json
geojson-merge img/base-nation.json img/base-border.json | geo2svg -o img/nation.svg -w 450 -h 600
svgexport img/nation.svg img/nation.png 2x
================================================
FILE: package.json
================================================
{
"name": "taiwan-atlas",
"version": "2021.9.20",
"description": "Pre-built TopoJSON from the Ministry of the Interior.",
"main": "mercatorTw.cjs.js",
"jsnext:main": "mercatorTw.es.js",
"files": [
"*-10t.json",
"mercatorTw.cjs.js",
"mercatorTw.es.js",
"README.md"
],
"scripts": {
"lint": "eslint .",
"generate:img": "npm run build && bash prepublish.sh && bash generateimg.sh",
"clean": "rimraf mercatorTw.cjs.js mercatorTw.es.js",
"build": "npm run clean && npm run build:cjs && npm run build:es",
"build:cjs": "rollup -c -o mercatorTw.cjs.js -f cjs",
"build:es": "rollup -c -o mercatorTw.es.js -f es",
"prepublishOnly": "npm run build && bash prepublish.sh"
},
"repository": {
"type": "git",
"url": "git+https://github.com/dkaoster/taiwan-atlas.git"
},
"author": {
"name": "Daniel Kao",
"url": "https://www.diplateevo.com/"
},
"license": "MIT",
"keywords": [
"topojson",
"geojson",
"shapefile"
],
"bugs": {
"url": "https://github.com/dkaoster/taiwan-atlas/issues"
},
"homepage": "https://github.com/dkaoster/taiwan-atlas#readme",
"devDependencies": {
"@mapbox/geojson-merge": "^1.1.1",
"d3-geo-projection": "^3.0.0",
"eslint": "^7.14.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-plugin-import": "^2.22.1",
"globby": "^11.0.1",
"mapshaper": "^0.6.44",
"ndjson-cli": "^0.3.1",
"rimraf": "^3.0.2",
"rollup": "^2.33.3",
"shapefile": "^0.6.6",
"svgexport": "^0.4.1",
"topojson-client": "^3.1.0",
"topojson-server": "^3.0.1",
"topojson-simplify": "^3.0.3"
},
"dependencies": {
"d3-geo": "^2.0.1",
"d3-path": "^2.0.0"
}
}
================================================
FILE: prepublish.sh
================================================
#!/bin/bash
set -e
rm -rvf *-10t.json base.json
mkdir -p build
# Crawl the data pages for the download links
# Village URL
villageShpUrl=$(curl -Ls https://data.gov.tw/dataset/7438 | \
# Find the link that has the SHP tag
grep -io '"SHP","contentUrl":[^}]*"}' | \
# get the href tag
sed -E 's/.*contentUrl":"([^"]+).*/\1/g')
# Town URL
townShpUrl=$(curl -Ls https://data.gov.tw/dataset/7441 | \
# Find the link that has the SHP tag
grep -io '"SHP","contentUrl":[^}]*"}' | \
# get the href tag
sed -E 's/.*contentUrl":"([^"]+).*/\1/g')
# County URL
countyShpUrl=$(curl -Ls https://data.gov.tw/dataset/7442 | \
# Find the link that has the SHP tag
grep -io '"SHP","contentUrl":[^}]*"}' | \
# get the href tag
sed -E 's/.*contentUrl":"([^"]+).*/\1/g')
# Download and extract the archives
if [ ! -f build/village.zip ]; then
curl -Lo build/village.zip "${villageShpUrl}"
unzip -od build build/village.zip
fi
# Download and extract the archives
if [ ! -f build/town.zip ]; then
curl -Lo build/town.zip "${townShpUrl}"
unzip -od build build/town.zip
fi
# Download and extract the archives
if [ ! -f build/county.zip ]; then
curl -Lo build/county.zip "${countyShpUrl}"
unzip -od build build/county.zip
fi
###############################################################################
# Generate topojson files
# Boundaries for everything we care about
bbox=117.663,21.577,122.0202,26.671
# Village file
geo2topo -q 1e10 -n villages=<( \
shp2json -n --encoding=UTF-8 build/VILLAGE*.shp \
| ndjson-filter '!!d.properties.VILLNAME') \
| topomerge towns=villages -k 'd.properties.TOWNCODE' \
| topomerge counties=towns -k 'd.properties.COUNTYCODE' \
| topomerge nation=counties \
| toposimplify -f -s 1e-10 \
| node ./properties.js \
> villages-10t.json
# Use mapshaper to remove extra slivers and islands outside of the boundaries.
mapshaper -i villages-10t.json -clip bbox=${bbox} -filter-slivers -o force format=topojson villages-10t.json
mapshaper -i villages-10t.json -clean target=* -o force format=topojson villages-10t.json
# Town file
geo2topo -q 1e10 -n towns=<( \
shp2json -n --encoding=UTF-8 build/TOWN*.shp \
| ndjson-filter '!!d.properties.TOWNNAME') \
| topomerge counties=towns -k 'd.properties.COUNTYCODE' \
| topomerge nation=counties \
| toposimplify -f -s 1e-10 \
| node ./properties.js \
> towns-10t.json
# Use mapshaper to remove extra slivers and islands outside of the boundaries.
mapshaper -i towns-10t.json -clip bbox=${bbox} -filter-slivers -o force format=topojson towns-10t.json
mapshaper -i towns-10t.json -clean target=* -o force format=topojson towns-10t.json
# County file
geo2topo -q 1e10 -n counties=<( \
shp2json -n --encoding=UTF-8 build/COUNTY*.shp \
| ndjson-filter '!!d.properties.COUNTYNAME') \
| topomerge nation=counties \
| toposimplify -f -s 1e-10 \
| node ./properties.js \
> counties-10t.json
# Use mapshaper to remove extra slivers and islands outside of the boundaries.
mapshaper -i counties-10t.json -clip bbox=${bbox} -filter-slivers -o force format=topojson counties-10t.json
mapshaper -i counties-10t.json -clean target=* -o force format=topojson counties-10t.json
# Use mapshaper to remove layers of detail we don't want for nation
mapshaper -i counties-10t.json -drop target=counties -o format=topojson target=* nation-10t.json
# District file
geo2topo -q 1e10 -n villages=<( \
shp2json -n --encoding=UTF-8 build/VILLAGE*.shp \
| ndjson-filter '!!d.properties.VILLNAME') \
| DISTRICTS="true" node ./properties.js \
| topomerge districts=villages -k 'd.properties.DISTRICTCODE' \
| topomerge counties=districts -k 'd.properties.COUNTYCODE' \
| topomerge nation=counties \
| toposimplify -f -s 1e-10 \
> districts-10t.json
# Use mapshaper to remove extra slivers and islands outside of the boundaries.
mapshaper -i districts-10t.json -clip bbox=${bbox} -filter-slivers -o force format=topojson districts-10t.json
mapshaper -i districts-10t.json -clean target=* -o force format=topojson districts-10t.json
# Use mapshaper to remove layers of detail we don't want for district
mapshaper -i districts-10t.json -drop target=villages -o force format=topojson target=* districts-10t.json
# Village mercator projections
geo2topo -q 1e7 -n \
villages=<(shp2json -n --encoding=UTF-8 build/VILLAGE*.shp \
| ndjson-filter '!!d.properties.VILLNAME' \
| geoproject --require mercatorTw='./mercatorTw.cjs' -n 'mercatorTw()') \
compBorders=<(node compBordersGeo.js) \
| topomerge towns=villages -k 'd.properties.TOWNCODE' \
| topomerge counties=towns -k 'd.properties.COUNTYCODE' \
| topomerge nation=counties \
| toposimplify -f -s 1e-6 \
| node ./properties.js \
> villages-mercator-10t.json
# Use mapshaper to remove extra slivers and islands outside of the boundaries.
mapshaper -i villages-mercator-10t.json -filter-slivers -o force format=topojson villages-mercator-10t.json
mapshaper -i villages-mercator-10t.json -clean target=* -o force format=topojson villages-mercator-10t.json
# Town mercator projections
geo2topo -q 1e7 -n \
towns=<(shp2json -n --encoding=UTF-8 build/TOWN*.shp \
| ndjson-filter '!!d.properties.TOWNNAME' \
| geoproject --require mercatorTw='./mercatorTw.cjs' -n 'mercatorTw()') \
compBorders=<(node compBordersGeo.js) \
| topomerge counties=towns -k 'd.properties.COUNTYCODE' \
| topomerge nation=counties \
| toposimplify -f -s 1e-6 \
| node ./properties.js \
> towns-mercator-10t.json
# Use mapshaper to remove extra slivers and islands outside of the boundaries.
mapshaper -i towns-mercator-10t.json -filter-slivers -o force format=topojson towns-mercator-10t.json
mapshaper -i towns-mercator-10t.json -clean target=* -o force format=topojson towns-mercator-10t.json
# County mercator projections
geo2topo -q 1e7 -n \
counties=<(shp2json -n --encoding=UTF-8 build/COUNTY*.shp \
| ndjson-filter '!!d.properties.COUNTYNAME' \
| geoproject --require mercatorTw='./mercatorTw.cjs' -n 'mercatorTw()') \
compBorders=<(node compBordersGeo.js) \
| topomerge nation=counties \
| toposimplify -f -s 1e-6 \
| node ./properties.js \
> counties-mercator-10t.json
# Use mapshaper to remove extra slivers and islands outside of the boundaries.
mapshaper -i counties-mercator-10t.json -filter-slivers -o force format=topojson counties-mercator-10t.json
mapshaper -i counties-mercator-10t.json -clean target=* -o force format=topojson counties-mercator-10t.json
# Use mapshaper to remove layers of detail we don't want for nation
mapshaper -i counties-mercator-10t.json -drop target=counties -o format=topojson target=* nation-mercator-10t.json
# District mercator projections
geo2topo -q 1e7 -n \
villages=<(shp2json -n --encoding=UTF-8 build/VILLAGE*.shp \
| ndjson-filter '!!d.properties.VILLNAME' \
| geoproject --require mercatorTw='./mercatorTw.cjs' -n 'mercatorTw()') \
compBorders=<(node compBordersGeo.js) \
| DISTRICTS="true" node ./properties.js \
| topomerge districts=villages -k 'd.properties.DISTRICTCODE' \
| topomerge counties=districts -k 'd.properties.COUNTYCODE' \
| topomerge nation=counties \
| toposimplify -f -s 1e-6 \
> districts-mercator-10t.json
# Use mapshaper to remove extra slivers and islands outside of the boundaries.
mapshaper -i districts-mercator-10t.json -filter-slivers -o force format=topojson districts-mercator-10t.json
mapshaper -i districts-mercator-10t.json -clean target=* -o force format=topojson districts-mercator-10t.json
# Use mapshaper to remove layers of detail we don't want for district
mapshaper -i districts-mercator-10t.json -drop target=villages -o force format=topojson target=* districts-mercator-10t.json
================================================
FILE: properties.js
================================================
const shapefile = require('shapefile');
const globby = require('globby');
const districts = require('./utils/districts.json');
// Parse the piped in topojson
function parseInput() {
return new Promise((resolve, reject) => {
const chunks = [];
process.stdin
.on('data', (chunk) => chunks.push(chunk))
.on('end', () => {
try { resolve(JSON.parse(chunks.join(''))); } catch (error) { reject(error); }
})
.setEncoding('utf8');
});
}
// 臺 > 台
function fixTai(obj) {
return { ...obj, COUNTYNAME: obj.COUNTYNAME.replace('臺', '台') };
}
// Generated modified properties
function output([topology, towns, counties]) {
const townsMap = new Map(
towns.features.map((d) => [d.properties.TOWNCODE, d.properties]),
);
const countiesMap = new Map(
counties.features.map((d) => [d.properties.COUNTYCODE, d.properties]),
);
// Process village properties
if (topology.objects.villages) {
// eslint-disable-next-line no-restricted-syntax
for (const village of topology.objects.villages.geometries) {
village.properties = fixTai(village.properties);
village.properties.TOWNENG = townsMap.get(village.properties.TOWNCODE).TOWNENG;
village.properties.COUNTYENG = countiesMap.get(village.properties.COUNTYCODE).COUNTYENG;
// If we are generating districts, add DISTRICTCODE into properties
if (process.env.DISTRICTS === 'true') {
Object.keys(districts).forEach((countyId) => {
Object.keys(districts[countyId]).forEach((districtId) => {
if (
districts[countyId][districtId].indexOf(village.properties.VILLCODE) >= 0
|| districts[countyId][districtId].indexOf(village.properties.TOWNCODE) >= 0
|| districts[countyId][districtId].indexOf(village.properties.COUNTYCODE) >= 0
) village.properties.DISTRICTCODE = `${countyId}-${districtId}`;
});
});
}
delete village.properties.NOTE;
}
}
// Process town properties
if (topology.objects.towns) {
// eslint-disable-next-line no-restricted-syntax
for (const town of topology.objects.towns.geometries) {
town.properties = fixTai(town.properties);
town.properties.TOWNENG = townsMap.get(town.properties.TOWNCODE).TOWNENG;
town.properties.COUNTYENG = countiesMap.get(town.properties.COUNTYCODE).COUNTYENG;
delete town.properties.NOTE;
}
}
// Process county properties
if (topology.objects.counties) {
// eslint-disable-next-line no-restricted-syntax
for (const county of topology.objects.counties.geometries) {
county.properties = fixTai(county.properties);
county.properties.COUNTYENG = countiesMap.get(county.properties.COUNTYCODE).COUNTYENG;
delete county.properties.NOTE;
}
}
// Add nation properties
if (topology.objects.nation && topology.objects.nation.geometries) {
topology.objects.nation.geometries[0].properties = { ID: 'TW', NAME: 'Taiwan' };
}
process.stdout.write(JSON.stringify(topology));
process.stdout.write('\n');
}
// Read the data out of the shp files.
Promise.all([
globby('build/TOWN*.shp'),
globby('build/COUNTY*.shp'),
]).then(([townShp, countyShp]) => Promise.all([
parseInput(),
shapefile.read(townShp[0]),
shapefile.read(countyShp[0]),
]).then(output));
================================================
FILE: rollup.config.js
================================================
export default {
input: 'src/mercatorTw.js',
};
================================================
FILE: src/bounds.js
================================================
function noop() {}
let x0 = Infinity;
let y0 = x0;
let x1 = -x0;
let y1 = x1;
function boundsPoint(x, y) {
if (x < x0) x0 = x;
if (x > x1) x1 = x;
if (y < y0) y0 = y;
if (y > y1) y1 = y;
}
const boundsStream = {
point: boundsPoint,
lineStart: noop,
lineEnd: noop,
polygonStart: noop,
polygonEnd: noop,
result() {
const bounds = [[x0, y0], [x1, y1]];
// eslint-disable-next-line no-multi-assign
x1 = y1 = -(y0 = x0 = Infinity);
return bounds;
},
};
export default boundsStream;
================================================
FILE: src/fit.js
================================================
import { geoStream } from 'd3-geo';
import boundsStream from './bounds';
export function fitExtent(projection, extent, object) {
const w = extent[1][0] - extent[0][0];
const h = extent[1][1] - extent[0][1];
const clip = projection.clipExtent && projection.clipExtent();
projection
.scale(150)
.translate([0, 0]);
if (clip != null) projection.clipExtent(null);
geoStream(object, projection.stream(boundsStream));
const b = boundsStream.result();
const k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1]));
const x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2;
const y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
if (clip != null) projection.clipExtent(clip);
return projection
.scale(k * 150)
.translate([x, y]);
}
export function fitSize(projection, size, object) {
return fitExtent(projection, [[0, 0], size], object);
}
================================================
FILE: src/math.js
================================================
// eslint-disable-next-line import/prefer-default-export
export const epsilon = 1e-6;
================================================
FILE: src/mercatorTw.js
================================================
/* eslint-disable no-plusplus */
import { geoMercator } from 'd3-geo';
import { path } from 'd3-path';
import { epsilon } from './math';
import { fitExtent, fitSize } from './fit';
const defaultScale = 10000;
const defaultCenter = [275, 300];
// Geo coordinates for projection boxes given defaultScale of 10000.
const geoCoordinates = {
mainland: {
width: 360, height: 600, offsetX: 0, offsetY: 0,
},
penghu: {
width: 90, height: 130, offsetX: -210, offsetY: 200,
},
kinmen: {
width: 120, height: 60, offsetX: -195, offsetY: -110,
},
lienchiang: {
width: 120, height: 120, offsetX: -195, offsetY: -220,
},
wuqiu: {
width: 30, height: 30, offsetX: -150, offsetY: -125,
},
};
// The projections must have mutually exclusive clip regions on the sphere,
// as this will avoid emitting interleaving lines and polygons.
function multiplex(streams) {
const n = streams.length;
return {
point(x, y) { let i = -1; while (++i < n) streams[i].point(x, y); },
sphere() { let i = -1; while (++i < n) streams[i].sphere(); },
lineStart() { let i = -1; while (++i < n) streams[i].lineStart(); },
lineEnd() { let i = -1; while (++i < n) streams[i].lineEnd(); },
polygonStart() { let i = -1; while (++i < n) streams[i].polygonStart(); },
polygonEnd() { let i = -1; while (++i < n) streams[i].polygonEnd(); },
};
}
// A composite projection for Taiwan, configured by default for 450x600.
export default () => {
let cache;
let cacheStream;
// Longitude and latitude coordinates of their centers
const mainland = geoMercator().rotate([-120.97, -23.60]); let mainlandPoint;
const penghu = geoMercator().rotate([-119.53, -23.47]); let penghuPoint;
const kinmen = geoMercator().rotate([-118.38, -24.44]); let kinmenPoint;
const lienchiang = geoMercator().rotate([-120.22, -26.16]); let lienchiangPoint;
const wuqiu = geoMercator().rotate([-119.45, -24.98]); let wuqiuPoint;
let point;
const pointStream = { point(x, y) { point = [x, y]; } };
const mercatorTw = (coordinates) => {
const x = coordinates[0];
const y = coordinates[1];
point = null;
return (mainlandPoint.point(x, y), point)
|| (penghuPoint.point(x, y), point)
|| (kinmenPoint.point(x, y), point)
|| (lienchiangPoint.point(x, y), point)
|| (wuqiuPoint.point(x, y), point);
};
const reset = () => {
cache = null;
cacheStream = null;
return mercatorTw;
};
mercatorTw.invert = (coordinates) => {
const k = mainland.scale();
const t = mainland.translate();
const x = (coordinates[0] - t[0]) / k;
const y = (coordinates[1] - t[1]) / k;
const isInBounds = (obj) => y >= (obj.offsetY - obj.height / 2) / defaultScale
&& y < (obj.offsetY + obj.height / 2) / defaultScale
&& x >= (obj.offsetX - obj.width / 2) / defaultScale
&& x < (obj.offsetX + obj.width / 2) / defaultScale;
if (isInBounds(geoCoordinates.wuqiu)) return wuqiu.invert(coordinates);
if (isInBounds(geoCoordinates.kinmen)) return kinmen.invert(coordinates);
if (isInBounds(geoCoordinates.lienchiang)) return lienchiang.invert(coordinates);
if (isInBounds(geoCoordinates.penghu)) return penghu.invert(coordinates);
return mainland.invert(coordinates);
};
// eslint-disable-next-line no-return-assign
mercatorTw.stream = (stream) => (cache && cacheStream === stream
? cache
: cache = multiplex([
mainland.stream(cacheStream = stream),
penghu.stream(stream),
kinmen.stream(stream),
lienchiang.stream(stream),
wuqiu.stream(stream),
]));
mercatorTw.precision = (...args) => {
if (!args.length) return mainland.precision();
mainland.precision(args[0]);
penghu.precision(args[0]);
kinmen.precision(args[0]);
lienchiang.precision(args[0]);
wuqiu.precision(args[0]);
return reset();
};
mercatorTw.scale = (...args) => {
if (!args.length) return mainland.scale();
mainland.scale(args[0]);
penghu.scale(args[0]);
kinmen.scale(args[0]);
lienchiang.scale(args[0]);
wuqiu.scale(args[0]);
return mercatorTw.translate(mainland.translate());
};
mercatorTw.translate = (...args) => {
if (!args.length) return mainland.translate();
const k = mainland.scale();
const x = +args[0][0];
const y = +args[0][1];
const genTranslate = (obj) => [
x + (obj.offsetX / defaultScale) * k,
y + (obj.offsetY / defaultScale) * k,
];
const genClipExtent = (obj) => [
[
x - (((obj.width / 2) - obj.offsetX) / defaultScale) * k + epsilon,
y - (((obj.height / 2) - obj.offsetY) / defaultScale) * k + epsilon,
],
[
x + (((obj.width / 2) + obj.offsetX) / defaultScale) * k - epsilon,
y + (((obj.height / 2) + obj.offsetY) / defaultScale) * k - epsilon,
],
];
// Takes the bbox difference between the corner and the center to
// determine where to clip.
mainlandPoint = mainland
.translate(genTranslate(geoCoordinates.mainland))
.clipExtent(genClipExtent(geoCoordinates.mainland))
.stream(pointStream);
penghuPoint = penghu
.translate(genTranslate(geoCoordinates.penghu))
.clipExtent(genClipExtent(geoCoordinates.penghu))
.stream(pointStream);
kinmenPoint = kinmen
.translate(genTranslate(geoCoordinates.kinmen))
.clipExtent(genClipExtent(geoCoordinates.kinmen))
.stream(pointStream);
lienchiangPoint = lienchiang
.translate(genTranslate(geoCoordinates.lienchiang))
.clipExtent(genClipExtent(geoCoordinates.lienchiang))
.stream(pointStream);
wuqiuPoint = wuqiu
.translate(genTranslate(geoCoordinates.wuqiu))
.clipExtent(genClipExtent(geoCoordinates.wuqiu))
.stream(pointStream);
return reset();
};
mercatorTw.fitExtent = (extent, object) => fitExtent(mercatorTw, extent, object);
mercatorTw.fitSize = (size, object) => fitSize(mercatorTw, size, object);
// Get the compositionBorderPoints because we want to export these
// for use as generating geojson.
mercatorTw.compositionBorderPoints = () => {
const k = mainland.scale();
const t = mainland.translate();
const x = t[0];
const y = t[1];
// Points from top left to bottom left, clockwise.
const points = (areaKey) => {
const areaCenterX = geoCoordinates[areaKey].offsetX;
const areaCenterY = geoCoordinates[areaKey].offsetY;
const dx = geoCoordinates[areaKey].width / 2;
const dy = geoCoordinates[areaKey].height / 2;
return [
[
x + ((areaCenterX - dx) / defaultScale) * k,
y + ((areaCenterY - dy) / defaultScale) * k,
],
[
x + ((areaCenterX + dx) / defaultScale) * k,
y + ((areaCenterY - dy) / defaultScale) * k,
],
[
x + ((areaCenterX + dx) / defaultScale) * k,
y + ((areaCenterY + dy) / defaultScale) * k,
],
[
x + ((areaCenterX - dx) / defaultScale) * k,
y + ((areaCenterY + dy) / defaultScale) * k,
],
];
};
return ['penghu', 'lienchiang', 'kinmen', 'wuqiu'].map((areaKey) => {
const areaPoints = points(areaKey);
// Kinmen borders wrap under wuqiu borders.
if (areaKey === 'kinmen') {
const wuqiuPoints = points('wuqiu');
return {
name: areaKey,
coords: [
areaPoints[0], wuqiuPoints[0], wuqiuPoints[3], wuqiuPoints[2],
areaPoints[2], areaPoints[3], areaPoints[0],
],
};
}
return {
name: areaKey,
coords: [...areaPoints, areaPoints[0]],
};
});
};
// Given a context, draw the borders
mercatorTw.drawCompositionBorders = (context) => {
mercatorTw.compositionBorderPoints().forEach((areaBorder) => {
areaBorder.coords.forEach((coords, i) => {
if (i === 0) context.moveTo(...coords);
else context.lineTo(...coords);
});
});
};
// Returns the compositionBorders as an svg path.
mercatorTw.getCompositionBorders = () => {
const context = path();
mercatorTw.drawCompositionBorders(context);
return context.toString();
};
return mercatorTw.scale(defaultScale).translate(defaultCenter);
};
================================================
FILE: utils/districts.json
================================================
{
"10002": {
"1": ["10002"]
},
"10007": {
"1": ["10007030", "10007040", "10007050", "10007070", "10007020", "10007060"],
"2": ["10007010", "10007080", "10007090"],
"3": ["10007110", "10007140", "10007150", "10007200", "10007220", "10007230", "10007240", "10007250", "10007260", "10007190"],
"4": ["10007120", "10007170", "10007100", "10007130", "10007160", "10007180", "10007210"]
},
"10010": {
"1": ["10010010", "10010120", "10010090", "10010020", "10010080", "10010100", "10010110", "10010030"],
"2": ["10010130", "10010160", "10010040", "10010050", "10010060", "10010070", "10010140", "10010150", "10010170", "10010180"]
},
"10015": {
"1": ["10015"]
},
"10018": {
"1": ["10018"]
},
"64000": {
"1": ["64000150", "64000160", "64000210", "64000220", "64000230", "64000300", "64000310", "64000320", "64000330", "64000340", "64000350", "64000360", "64000370", "64000380"],
"2": ["64000190", "64000200", "64000240", "64000250", "64000260", "64000270", "64000280", "64000290"],
"3": ["64000040", "64000030"],
"4": ["64000140", "64000170", "64000180", "64000130"],
"5": ["64000050", "64000080037", "64000080041", "64000080042", "64000080062", "64000080063", "64000080064", "64000080067", "64000080068"],
"6": ["64000010", "64000060", "64000070", "64000020", "64000080S01", "64000080001", "64000080007", "64000080009", "64000080008", "64000080054", "64000080056", "64000080051", "64000080055", "64000080052", "64000080049", "64000080040", "64000080053", "64000080039", "64000080057", "64000080050", "64000080026", "64000080015", "64000080011", "64000080020", "64000080017", "64000080036", "64000080025", "64000080043", "64000080023", "64000080006", "64000080003", "64000080044", "64000080005", "64000080004", "64000080002", "64000080028", "64000080047", "64000080032", "64000080031", "64000080045", "64000080024", "64000080029", "64000080027", "64000080030", "64000080016", "64000080022", "64000080019", "64000080021", "64000080013", "64000080014", "64000080018", "64000080034", "64000080012", "64000080035", "64000080069", "64000080010", "64000080046", "64000080058", "64000080048", "64000080061", "64000080066", "64000080059", "64000080060", "64000080065", "64000080033", "64000080038"],
"7": ["64000120"],
"8": ["64000100", "64000110", "64000090"]
},
"67000": {
"1": ["67000010", "67000020", "67000030", "67000040", "67000050", "67000060", "67000080", "67000090", "67000130", "67000160", "67000170"],
"2": ["67000070", "67000100", "67000110", "67000120", "67000140", "67000190", "67000210", "67000220", "67000230", "67000240", "67000250", "67000260", "67000150"],
"3": ["67000340", "67000350"],
"4": ["67000180", "67000200", "67000310"],
"5": ["67000330", "67000360", "67000370", "67000320037", "67000320023", "67000320021", "67000320036", "67000320010", "67000320011", "67000320038", "67000320005", "67000320024", "67000320015", "67000320029", "67000320039", "67000320040", "67000320016", "67000320004", "67000320028"],
"6": ["67000270", "67000280", "67000290", "67000300", "67000320022", "67000320027", "67000320007", "67000320031", "67000320008", "67000320030", "67000320002", "67000320020", "67000320034", "67000320044", "67000320018", "67000320009", "67000320001", "67000320017", "67000320013", "67000320045", "67000320042", "67000320043", "67000320025", "67000320019", "67000320014", "67000320032", "67000320012", "67000320035", "67000320041", "67000320006", "67000320026", "67000320033", "67000320003"]
},
"09007": {
"1": ["09007"]
},
"10004": {
"1": ["10004030", "10004040", "10004050", "10004070", "10004120", "10004060", "10004010020", "10004010018", "10004010017", "10004010019", "10004010016", "10004010015", "10004010013", "10004010012", "10004010023", "10004010014", "10004010022", "10004010011"],
"2": ["10004110", "10004020", "10004080", "10004090", "10004100", "10004130", "10004010010", "10004010007", "10004010009", "10004010025", "10004010026", "10004010008", "10004010030", "10004010024", "10004010029", "10004010028", "10004010021", "10004010031", "10004010001", "10004010002", "10004010027", "10004010006", "10004010004", "10004010005", "10004010003"]
},
"10008": {
"1": ["10008020", "10008030", "10008080", "10008090", "10008100", "10008130"],
"2": ["10008010", "10008040", "10008050", "10008060", "10008070", "10008110", "10008120"]
},
"10013": {
"1": ["10013010", "10013060", "10013070", "10013080", "10013090", "10013100", "10013110", "10013130", "10013260", "10013270", "10013280"],
"2": ["10013210", "10013140", "10013050", "10013020", "10013120", "10013150", "10013180", "10013200", "10013220", "10013290", "10013300", "10013310", "10013320", "10013030", "10013040", "10013160", "10013170", "10013190", "10013230", "10013240", "10013250", "10013330"]
},
"10016": {
"1": ["10016"]
},
"10020": {
"1": ["10020"]
},
"65000": {
"1": ["65000100", "65000170", "65000210", "65000230", "65000160", "65000220"],
"2": ["65000140", "65000150", "65000020108", "65000020101", "65000020098", "65000020102", "65000020100", "65000020099", "65000020103", "65000020107", "65000020105", "65000020106", "65000020118", "65000020096", "65000020104", "65000020089", "65000020090", "65000020114"],
"3": ["65000020075", "65000020110", "65000020024", "65000020056", "65000020064", "65000020062", "65000020058", "65000020063", "65000020061", "65000020080", "65000020007", "65000020082", "65000020012", "65000020046", "65000020044", "65000020031", "65000020060", "65000020028", "65000020001", "65000020042", "65000020006", "65000020003", "65000020002", "65000020073", "65000020111", "65000020117", "65000020038", "65000020094", "65000020009", "65000020016", "65000020037", "65000020008", "65000020057", "65000020036", "65000020020", "65000020035", "65000020013", "65000020014", "65000020021", "65000020043", "65000020010", "65000020004", "65000020083", "65000020065", "65000020027", "65000020055", "65000020067", "65000020011", "65000020054", "65000020059", "65000020116", "65000020078", "65000020077", "65000020068", "65000020069", "65000020045", "65000020086", "65000020030", "65000020039", "65000020032", "65000020034", "65000020097", "65000020081", "65000020072", "65000020019", "65000020085", "65000020053", "65000020079", "65000020018", "65000020015", "65000020017", "65000020022", "65000020023", "65000020066", "65000020084", "65000020051", "65000020095", "65000020109", "65000020119", "65000020093", "65000020074", "65000020076", "65000020070", "65000020071", "65000020091", "65000020025", "65000020087", "65000020113", "65000020115", "65000020092", "65000020112", "65000020088", "65000020040", "65000020049", "65000020047", "65000020048", "65000020029", "65000020041", "65000020033", "65000020005", "65000020052", "65000020026", "65000020050", "65000020R01"],
"4": ["65000050012", "65000050074", "65000050063", "65000050064", "65000050073", "65000050071", "65000050043", "65000050006", "65000050024", "65000050005", "65000050078", "65000050072", "65000050068", "65000050003", "65000050001", "65000050046", "65000050008", "65000050033", "65000050069", "65000050009", "65000050036", "65000050070", "65000050056", "65000050029", "65000050034", "65000050062", "65000050026", "65000050059", "65000050076", "65000050031", "65000050037", "65000050067", "65000050050", "65000050079", "65000050081", "65000050027", "65000050018", "65000050004", "65000050060", "65000050028", "65000050061", "65000050016", "65000050048", "65000050055", "65000050039", "65000050025", "65000050077", "65000050002", "65000050066", "65000050019", "65000050010", "65000050022", "65000050065", "65000050080", "65000050047", "65000050013", "65000050030", "65000050040", "65000050021", "65000050020", "65000050023", "65000050014", "65000050057", "65000050051", "65000050052", "65000050011", "65000050075", "65000050058", "65000050017", "65000050007", "65000050054", "65000050053", "65000050045", "65000050042", "65000050049"],
"5": ["65000080", "65000070", "65000050084", "65000050038", "65000050044", "65000050041", "65000050083", "65000050032", "65000050035", "65000050082", "65000050015"],
"6": ["65000010025", "65000010041", "65000010117", "65000010003", "65000010030", "65000010037", "65000010049", "65000010017", "65000010015", "65000010050", "65000010021", "65000010013", "65000010114", "65000010014", "65000010020", "65000010033", "65000010043", "65000010048", "65000010028", "65000010004", "65000010029", "65000010019", "65000010036", "65000010026", "65000010016", "65000010106", "65000010045", "65000010032", "65000010002", "65000010001", "65000010042", "65000010038", "65000010115", "65000010039", "65000010018", "65000010006", "65000010061", "65000010047", "65000010034", "65000010008", "65000010118", "65000010040", "65000010046", "65000010103", "65000010104", "65000010119", "65000010009", "65000010101", "65000010035", "65000010023", "65000010105", "65000010022", "65000010027", "65000010102", "65000010007", "65000010031", "65000010116", "65000010005", "65000010062", "65000010024", "65000010044", "65000010010", "65000010121", "65000010012", "65000010011"],
"7": ["65000010069", "65000010055", "65000010113", "65000010080", "65000010094", "65000010079", "65000010125", "65000010122", "65000010068", "65000010095", "65000010074", "65000010107", "65000010071", "65000010070", "65000010056", "65000010093", "65000010076", "65000010089", "65000010078", "65000010083", "65000010053", "65000010060", "65000010064", "65000010073", "65000010057", "65000010082", "65000010110", "65000010086", "65000010087", "65000010111", "65000010085", "65000010084", "65000010090", "65000010075", "65000010058", "65000010096", "65000010120", "65000010098", "65000010097", "65000010109", "65000010072", "65000010054", "65000010091", "65000010081", "65000010065", "65000010063", "65000010112", "65000010123", "65000010067", "65000010066", "65000010077", "65000010100", "65000010124", "65000010088", "65000010099", "65000010059", "65000010108", "65000010051", "65000010052", "65000010092", "65000010126"],
"8": ["65000030062", "65000030084", "65000030039", "65000030067", "65000030073", "65000030034", "65000030036", "65000030010", "65000030018", "65000030015", "65000030080", "65000030014", "65000030016", "65000030045", "65000030013", "65000030090", "65000030069", "65000030091", "65000030041", "65000030046", "65000030037", "65000030035", "65000030054", "65000030019", "65000030006", "65000030089", "65000030058", "65000030060", "65000030053", "65000030050", "65000030079", "65000030049", "65000030040", "65000030047", "65000030051", "65000030048", "65000030052", "65000030086", "65000030085", "65000030055", "65000030082", "65000030008", "65000030007", "65000030009", "65000030012", "65000030061", "65000030071", "65000030064", "65000030068", "65000030056", "65000030087", "65000030026", "65000030042", "65000030002", "65000030065", "65000030004", "65000030063", "65000030070", "65000030043", "65000030044", "65000030017", "65000030059", "65000030078", "65000030003", "65000030025", "65000030088", "65000030057", "65000030011", "65000030092", "65000030093", "65000030083", "65000030038", "65000030081", "65000030001", "65000030005", "65000030066"],
"9": ["65000040", "65000030021", "65000030020", "65000030022", "65000030075", "65000030024", "65000030028", "65000030029", "65000030030", "65000030031", "65000030033", "65000030027", "65000030077", "65000030072", "65000030076", "65000030074", "65000030023", "65000030032"],
"10": ["65000130", "65000090"],
"11": ["65000060", "65000200", "65000290", "65000180", "65000190"],
"12": ["65000240", "65000120", "65000250", "65000260", "65000110", "65000280", "65000270"]
},
"68000": {
"1": ["68000050", "68000070", "68000010010", "68000010047", "68000010006", "68000010057", "68000010058", "68000010046", "68000010078", "68000010005", "68000010079", "68000010076", "68000010038", "68000010045", "68000010015"],
"2": ["68000120", "68000060", "68000110", "68000040"],
"3": ["68000020006", "68000020069", "68000020021", "68000020058", "68000020056", "68000020033", "68000020007", "68000020043", "68000020059", "68000020042", "68000020076", "68000020079", "68000020085", "68000020045", "68000020084", "68000020002", "68000020082", "68000020065", "68000020039", "68000020029", "68000020001", "68000020011", "68000020062", "68000020051", "68000020027", "68000020005", "68000020061", "68000020053", "68000020016", "68000020017", "68000020060", "68000020022", "68000020032", "68000020072", "68000020012", "68000020070", "68000020048", "68000020049", "68000020038", "68000020031", "68000020034", "68000020064", "68000020044", "68000020073", "68000020035", "68000020054", "68000020041", "68000020080", "68000020014", "68000020024", "68000020025", "68000020037", "68000020074", "68000020055", "68000020004", "68000020047", "68000020066", "68000020052", "68000020046", "68000020063", "68000020036", "68000020040", "68000020028", "68000020050", "68000020057", "68000020081", "68000020015", "68000020018", "68000020026", "68000020077", "68000020008", "68000020083", "68000020078"],
"4": ["68000010074", "68000010068", "68000010031", "68000010069", "68000010016", "68000010063", "68000010007", "68000010037", "68000010024", "68000010043", "68000010004", "68000010077", "68000010013", "68000010012", "68000010014", "68000010041", "68000010044", "68000010033", "68000010034", "68000010042", "68000010060", "68000010059", "68000010036", "68000010035", "68000010071", "68000010056", "68000010073", "68000010008", "68000010027", "68000010026", "68000010067", "68000010075", "68000010053", "68000010050", "68000010072", "68000010021", "68000010001", "68000010002", "68000010052", "68000010003", "68000010025", "68000010019", "68000010048", "68000010022", "68000010018", "68000010011", "68000010009", "68000010032", "68000010028", "68000010039", "68000010029", "68000010055", "68000010020", "68000010054", "68000010049", "68000010064", "68000010017", "68000010023", "68000010070", "68000010066", "68000010062", "68000010040", "68000010065", "68000010030", "68000010051", "68000010061"],
"5": ["68000090", "68000100"],
"6": ["68000130", "68000030", "68000080", "68000020020", "68000020020", "68000020019", "68000020068", "68000020023", "68000020013", "68000020075", "68000020030", "68000020071", "68000020003", "68000020010", "68000020067"]
},
"09020": {
"1": ["09020"]
},
"10005": {
"1": ["10005100", "10005130", "10005140", "10005150", "10005020", "10005030", "10005040", "10005060"],
"2": ["10005160", "10005110", "10005010", "10005070", "10005080", "10005090", "10005120", "10005170", "10005180", "10005050"]
},
"10009": {
"1": ["10009130", "10009030", "10009050", "10009060", "10009140", "10009150", "10009170", "10009200", "10009160", "10009180", "10009190"],
"2": ["10009010", "10009020", "10009040", "10009070", "10009080", "10009090", "10009100", "10009110", "10009120"]
},
"10014": {
"1": ["10014"]
},
"10017": {
"1": ["10017"]
},
"63000": {
"1": ["63000120", "63000110042", "63000110033", "63000110036", "63000110037", "63000110038", "63000110040", "63000110039", "63000110041", "63000110027", "63000110028", "63000110030", "63000110034", "63000110035"],
"2": ["63000060", "63000110001", "63000110002", "63000110003", "63000110004", "63000110005", "63000110006", "63000110007", "63000110008", "63000110009", "63000110010", "63000110011", "63000110012", "63000110013", "63000110014", "63000110015", "63000110016", "63000110017", "63000110018", "63000110019", "63000110020", "63000110021", "63000110022", "63000110023", "63000110024", "63000110025", "63000110026", "63000110029", "63000110031", "63000110032", "63000110043", "63000110044", "63000110045", "63000110046", "63000110047", "63000110048", "63000110049", "63000110050", "63000110051"],
"3": ["63000040", "63000010010", "63000010011", "63000010012", "63000010013", "63000010014", "63000010015", "63000010016", "63000010017", "63000010035", "63000010002", "63000010003", "63000010005", "63000010007", "63000010009", "63000010004", "63000010006", "63000010008", "63000010021", "63000010020", "63000010019"],
"4": ["63000100", "63000090"],
"5": ["63000070", "63000050017", "63000050021", "63000050020", "63000050019", "63000050016", "63000050015", "63000050014", "63000050011", "63000050012", "63000050013", "63000050018", "63000050024", "63000050023", "63000050022", "63000050028", "63000050026", "63000050025", "63000050027", "63000050029", "63000050030", "63000050031"],
"6": ["63000030"],
"7": ["63000020", "63000010018", "63000010022", "63000010024", "63000010025", "63000010026", "63000010027", "63000010028", "63000010029", "63000010030", "63000010031", "63000010032", "63000010033", "63000010034"],
"8": ["63000080", "63000050001", "63000050002", "63000050003", "63000050004", "63000050005", "63000050009", "63000050007", "63000050008", "63000050006", "63000050010"]
},
"66000": {
"1": ["66000210", "66000110", "66000220", "66000120", "66000140"],
"2": ["66000230", "66000130", "66000240", "66000260", "66000250"],
"3": ["66000150", "66000160", "66000170", "66000180"],
"4": ["66000070", "66000060"],
"5": ["66000050", "66000080"],
"6": ["66000010", "66000020", "66000030", "66000040"],
"7": ["66000270", "66000280"],
"8": ["66000090", "66000100", "66000190", "66000200", "66000290"]
}
}
gitextract_6wpgu_11/
├── .eslintignore
├── .eslintrc.js
├── .github/
│ └── workflows/
│ ├── eslint.yml
│ └── npm-publish.yml
├── .gitignore
├── LICENSE
├── README.md
├── compBordersGeo.js
├── generateimg.sh
├── package.json
├── prepublish.sh
├── properties.js
├── rollup.config.js
├── src/
│ ├── bounds.js
│ ├── fit.js
│ ├── math.js
│ └── mercatorTw.js
└── utils/
└── districts.json
SYMBOL INDEX (10 symbols across 4 files)
FILE: properties.js
function parseInput (line 6) | function parseInput() {
function fixTai (line 19) | function fixTai(obj) {
function output (line 24) | function output([topology, towns, counties]) {
FILE: src/bounds.js
function noop (line 1) | function noop() {}
function boundsPoint (line 8) | function boundsPoint(x, y) {
method result (line 21) | result() {
FILE: src/fit.js
function fitExtent (line 4) | function fitExtent(projection, extent, object) {
function fitSize (line 29) | function fitSize(projection, size, object) {
FILE: src/mercatorTw.js
function multiplex (line 31) | function multiplex(streams) {
method point (line 56) | point(x, y) { point = [x, y]; }
Condensed preview — 18 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (62K chars).
[
{
"path": ".eslintignore",
"chars": 30,
"preview": "node_modules\n*.cjs.js\n*.es.js\n"
},
{
"path": ".eslintrc.js",
"chars": 282,
"preview": "module.exports = {\n parserOptions: {\n ecmaVersion: 2019,\n sourceType: 'module',\n },\n env: {\n es6: true,\n },"
},
{
"path": ".github/workflows/eslint.yml",
"chars": 578,
"preview": "name: Lint\n\non: push\n\njobs:\n lint:\n name: Lint\n runs-on: ubuntu-latest\n\n steps:\n - name: Check out Git re"
},
{
"path": ".github/workflows/npm-publish.yml",
"chars": 370,
"preview": "name: Publish to NPM\n\non:\n push:\n tags:\n - '*'\n\njobs:\n publish:\n name: Publish to NPM\n runs-on: ubuntu-l"
},
{
"path": ".gitignore",
"chars": 65,
"preview": "build/\nnode_modules\n*-10t.json\nbase*.json\n*.es.js\n*.cjs.js\n*.svg\n"
},
{
"path": "LICENSE",
"chars": 1067,
"preview": "MIT License\n\nCopyright (c) 2020 Daniel Kao\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
},
{
"path": "README.md",
"chars": 11844,
"preview": "# Taiwan Atlas TopoJSON\n\nSimilar to the [topojson/us-atlas](https://github.com/topojson/us-atlas) project, this reposito"
},
{
"path": "compBordersGeo.js",
"chars": 1341,
"preview": "// eslint-disable-next-line import/no-unresolved\nconst mercatorTw = require('./mercatorTw.cjs.js');\n\n// Initialize Proje"
},
{
"path": "generateimg.sh",
"chars": 1344,
"preview": "#!/bin/bash\n\n# Create the border json\ntopo2geo compBorders=- < nation-mercator-10t.json > img/base-border.json\n\n# Villag"
},
{
"path": "package.json",
"chars": 1714,
"preview": "{\n \"name\": \"taiwan-atlas\",\n \"version\": \"2021.9.20\",\n \"description\": \"Pre-built TopoJSON from the Ministry of the Inte"
},
{
"path": "prepublish.sh",
"chars": 7750,
"preview": "#!/bin/bash\n\nset -e\n\nrm -rvf *-10t.json base.json\nmkdir -p build\n\n# Crawl the data pages for the download links\n# Villag"
},
{
"path": "properties.js",
"chars": 3332,
"preview": "const shapefile = require('shapefile');\nconst globby = require('globby');\nconst districts = require('./utils/districts.j"
},
{
"path": "rollup.config.js",
"chars": 50,
"preview": "export default {\n input: 'src/mercatorTw.js',\n};\n"
},
{
"path": "src/bounds.js",
"chars": 519,
"preview": "function noop() {}\n\nlet x0 = Infinity;\nlet y0 = x0;\nlet x1 = -x0;\nlet y1 = x1;\n\nfunction boundsPoint(x, y) {\n if (x < x"
},
{
"path": "src/fit.js",
"chars": 898,
"preview": "import { geoStream } from 'd3-geo';\nimport boundsStream from './bounds';\n\nexport function fitExtent(projection, extent, "
},
{
"path": "src/math.js",
"chars": 86,
"preview": "// eslint-disable-next-line import/prefer-default-export\nexport const epsilon = 1e-6;\n"
},
{
"path": "src/mercatorTw.js",
"chars": 8295,
"preview": "/* eslint-disable no-plusplus */\nimport { geoMercator } from 'd3-geo';\nimport { path } from 'd3-path';\nimport { epsilon "
},
{
"path": "utils/districts.json",
"chars": 17428,
"preview": "{\n \"10002\": {\n \"1\": [\"10002\"]\n },\n \"10007\": {\n \"1\": [\"10007030\", \"10007040\", \"10007050\", \"10007070\", \"10007020\""
}
]
About this extraction
This page contains the full source code of the dkaoster/taiwan-atlas GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 18 files (55.7 KB), approximately 18.7k tokens, and a symbol index with 10 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.