iweather-gl 0.1.13 → 0.1.14

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.
@@ -1,8 +1,35 @@
1
1
  import { expose } from 'comlink';
2
- import { readImagWithExif } from './readImagWithExif';
3
2
 
4
3
  expose({
5
4
  async execReadImagWithExif(imgUrl) {
6
5
  return readImagWithExif(imgUrl);
7
6
  },
8
7
  });
8
+
9
+ async function readImagWithExif(imgUrl, signal) {
10
+ const res = await fetch(imgUrl, { signal });
11
+
12
+ const arrayBuffer = await res.arrayBuffer();
13
+
14
+ const exif = await readImagWithExif(arrayBuffer);
15
+
16
+ const blob = new Blob([arrayBuffer]);
17
+
18
+ const imageBitmap = await createImageBitmap(blob);
19
+
20
+ return { exif, imageBitmap };
21
+ }
22
+
23
+ export async function readExif(img) {
24
+ let arrayBuffer;
25
+ if (img instanceof ArrayBuffer) {
26
+ arrayBuffer = img;
27
+ } else {
28
+ const res = await fetch(img);
29
+ arrayBuffer = await res.arrayBuffer();
30
+ }
31
+
32
+ const exif = await exifr.parse(arrayBuffer);
33
+
34
+ return exif;
35
+ }
@@ -1,3 +1,3 @@
1
- import { ICreateMaskTextureParams } from './createMaskTexture';
1
+ import { ICreateMaskTextureParams } from './index';
2
2
  export declare function loadWorker(params: ICreateMaskTextureParams): Promise<ImageData>;
3
3
  //# sourceMappingURL=worker-load.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker-load.d.ts","sourceRoot":"","sources":["../../../src/fns/mask/worker-load.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,wBAAsB,UAAU,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,SAAS,CAAC,CAMrF"}
1
+ {"version":3,"file":"worker-load.d.ts","sourceRoot":"","sources":["../../../src/fns/mask/worker-load.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAEnD,wBAAsB,UAAU,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,SAAS,CAAC,CAMrF"}
@@ -28,7 +28,7 @@
28
28
  "import { wrap } from 'comlink';\nimport { IReadImageInfo } from './readImagWithExif';\n\nexport async function loadWorker(imgUrl: string): Promise<IReadImageInfo> {\n const worker = new Worker(new URL('./exif-worker.js', import.meta.url), { type: 'module' });\n\n const obj = wrap<{ execReadImagWithExif: (imgUrl: string) => IReadImageInfo }>(worker);\n\n return await obj.execReadImagWithExif(imgUrl);\n}\n",
29
29
  "import { parseExifBounds, parseExifDataRange, parseExifDataRangeWithWind } from './parseExif';\nimport { readImagWithExif } from './readImagWithExif';\nimport { loadWorker } from './worker-load';\n\nexport interface IReadImageWithExifOptions {\n isWorker?: boolean;\n signal?: AbortSignal;\n}\n\nexport async function readImageWithCommonExif(imgUrl: string, options?: IReadImageWithExifOptions) {\n const imageWithExif = options?.isWorker ? await loadWorker(imgUrl) : await readImagWithExif(imgUrl, options?.signal);\n\n const { exif, ...attr } = imageWithExif;\n\n const dataRange = parseExifDataRange(exif.dataRange);\n\n const bounds = parseExifBounds(exif.bounds);\n\n return {\n ...attr,\n dataRange,\n bounds,\n };\n}\n\nexport async function readImageWithWindExif(imgUrl: string, options?: IReadImageWithExifOptions) {\n const imageWithExif = options?.isWorker ? await loadWorker(imgUrl) : await readImagWithExif(imgUrl, options?.signal);\n\n const { exif, ...attr } = imageWithExif;\n\n const dataRange = parseExifDataRangeWithWind(exif.dataRange);\n\n const bounds = parseExifBounds(exif.bounds);\n\n return {\n ...attr,\n dataRange,\n bounds,\n };\n}\n",
30
30
  "import { IMap } from '../types/map';\n\nfunction mod(x: number, y: number): number {\n return ((x % y) + y) % y;\n}\n\nexport function wrapLongitude(lng: number, minLng?: number): number {\n let wrappedLng = mod(lng + 180, 360) - 180;\n if (typeof minLng === 'number' && wrappedLng < minLng) {\n wrappedLng += 360;\n }\n return wrappedLng;\n}\n\n/**\n * 包装bounds\n * @param bounds\n * @returns\n */\nexport function wrapBounds(bounds: GeoJSON.BBox): GeoJSON.BBox {\n const minLng = bounds[2] - bounds[0] < 360 ? wrapLongitude(bounds[0]) : -180;\n const maxLng = bounds[2] - bounds[0] < 360 ? wrapLongitude(bounds[2], minLng) : 180;\n\n const minLat = Math.max(bounds[1], -85.051129);\n const maxLat = Math.min(bounds[3], 85.051129);\n\n const mercatorBounds = [minLng, minLat, maxLng, maxLat] as GeoJSON.BBox;\n return mercatorBounds;\n}\n\n/**\n * 将map的bounds转换成包装好的bounds\n * @param map\n * @returns\n */\nexport function getViewportBounds(map: IMap): GeoJSON.BBox {\n const viewportBounds = map.getBounds().toArray().flat() as GeoJSON.BBox;\n return wrapBounds(viewportBounds);\n}\n",
31
- "import { wrap } from 'comlink';\nimport { ICreateMaskTextureParams } from './createMaskTexture';\n\nexport async function loadWorker(params: ICreateMaskTextureParams): Promise<ImageData> {\n const worker = new Worker(new URL('./mask-worker.js', import.meta.url), { type: 'module' });\n\n const obj = wrap<{ createMaskTexture: (params: ICreateMaskTextureParams) => ImageData }>(worker);\n\n return await obj.createMaskTexture(params);\n}\n",
31
+ "import { wrap } from 'comlink';\nimport { ICreateMaskTextureParams } from './index';\n\nexport async function loadWorker(params: ICreateMaskTextureParams): Promise<ImageData> {\n const worker = new Worker(new URL('./mask-worker.js', import.meta.url), { type: 'module' });\n\n const obj = wrap<{ createMaskTexture: (params: ICreateMaskTextureParams) => ImageData }>(worker);\n\n return await obj.createMaskTexture(params);\n}\n",
32
32
  "import { Bounds } from '../../types/map';\nimport { loadWorker } from './worker-load';\n\nexport interface ICreateMaskTextureParams {\n data: string | GeoJSON.FeatureCollection | GeoJSON.Feature;\n viewportBounds?: Bounds;\n projection?: d3.GeoProjection;\n width?: number;\n}\n\nexport async function createMaskTexture(params: ICreateMaskTextureParams) {\n return await loadWorker(params);\n}\n",
33
33
  "import china_province from './file/china_province.json';\nimport china_city from './file/chain_city.json';\nimport china_province_names from './file/china_province_names.json';\nimport china_shuixi from './file/china_shuixi.json';\nimport china from './file/china.json';\nimport land from './file/land.json';\nimport { produce } from 'immer';\nimport * as turf from '@turf/turf';\n\nexport type IProvinceGeoJSON = GeoJSON.Feature<GeoJSON.MultiPolygon, { name: string; gb: string }>;\n\nexport type IProvincesGeoJSON = GeoJSON.FeatureCollection<GeoJSON.MultiPolygon, { name: string; gb: string }>;\n\nexport type ICityGeoJSON = GeoJSON.FeatureCollection<GeoJSON.MultiPolygon, { name: string; gb: string }>;\n\nexport type IProvinceNamesGeoJSON = GeoJSON.FeatureCollection<\n GeoJSON.Point,\n { province: string; abbreviation: string; capital: string }\n>;\n\nexport class ChinaGeoJSONMgr {\n public static getProvince(gb: string): {\n province: IProvinceGeoJSON;\n citys: ICityGeoJSON;\n } {\n const china_province_geojson = china_province as unknown as ICityGeoJSON;\n const china_city_geojson = china_city as unknown as ICityGeoJSON;\n\n const province = china_province_geojson.features.find(e => e.properties.gb === gb)!;\n\n const citys = turf.featureCollection(\n china_city_geojson.features.filter(e => {\n const province_gb = parseInt(province.properties.gb);\n const city_gb = parseInt(e.properties.gb);\n return city_gb >= province_gb && city_gb < province_gb + 10000;\n }),\n );\n\n return {\n province,\n citys,\n };\n }\n\n public static getChinaProvinces(): IProvincesGeoJSON {\n const data = china_province as unknown as IProvincesGeoJSON;\n return produce(data, draft => {\n draft.features.forEach(e => {\n e.id = e.properties.gb;\n });\n });\n }\n\n public static getChinaProvinceNames(): IProvinceNamesGeoJSON {\n return china_province_names as IProvinceNamesGeoJSON;\n }\n\n public static getChinaShuiXi(): GeoJSON.FeatureCollection {\n return china_shuixi as GeoJSON.FeatureCollection;\n }\n\n public static getChina(): GeoJSON.FeatureCollection {\n return china as GeoJSON.FeatureCollection;\n }\n\n public static getLand(): GeoJSON.FeatureCollection {\n return land as GeoJSON.FeatureCollection;\n }\n}\n",
34
34
  "import { INFINITY_VALUE } from '../config/colorPalette';\nimport { IColorPaletteConfig } from '../types/colorPalette';\n\nexport interface IColorPaletteFns {\n toColor: (val: number) => string | undefined;\n values: number[];\n min: number;\n max: number;\n}\n\nexport function toColorPaletteFns(colorPalette: IColorPaletteConfig): IColorPaletteFns {\n const sortedColorPalette = colorPalette.sort((a, b) => a.value - b.value);\n const values = sortedColorPalette.flatMap(e => e.value).filter(e => e !== INFINITY_VALUE);\n const min = Math.min(...values);\n const max = Math.max(...values);\n return {\n values,\n min,\n max,\n toColor: (val: number) => {\n let outColor: string | undefined;\n if (val >= sortedColorPalette[sortedColorPalette.length - 1].value) {\n outColor = sortedColorPalette[sortedColorPalette.length - 1].color!;\n } else {\n for (let i = 0; i < colorPalette.length; i++) {\n if (val >= sortedColorPalette[i].value && val < sortedColorPalette[i + 1].value) {\n outColor = sortedColorPalette[i].color!;\n break;\n }\n }\n }\n return outColor;\n },\n };\n}\n",
@@ -28,7 +28,7 @@
28
28
  "import { wrap } from 'comlink';\nimport { IReadImageInfo } from './readImagWithExif';\n\nexport async function loadWorker(imgUrl: string): Promise<IReadImageInfo> {\n const worker = new Worker(new URL('./exif-worker.js', import.meta.url), { type: 'module' });\n\n const obj = wrap<{ execReadImagWithExif: (imgUrl: string) => IReadImageInfo }>(worker);\n\n return await obj.execReadImagWithExif(imgUrl);\n}\n",
29
29
  "import { parseExifBounds, parseExifDataRange, parseExifDataRangeWithWind } from './parseExif';\nimport { readImagWithExif } from './readImagWithExif';\nimport { loadWorker } from './worker-load';\n\nexport interface IReadImageWithExifOptions {\n isWorker?: boolean;\n signal?: AbortSignal;\n}\n\nexport async function readImageWithCommonExif(imgUrl: string, options?: IReadImageWithExifOptions) {\n const imageWithExif = options?.isWorker ? await loadWorker(imgUrl) : await readImagWithExif(imgUrl, options?.signal);\n\n const { exif, ...attr } = imageWithExif;\n\n const dataRange = parseExifDataRange(exif.dataRange);\n\n const bounds = parseExifBounds(exif.bounds);\n\n return {\n ...attr,\n dataRange,\n bounds,\n };\n}\n\nexport async function readImageWithWindExif(imgUrl: string, options?: IReadImageWithExifOptions) {\n const imageWithExif = options?.isWorker ? await loadWorker(imgUrl) : await readImagWithExif(imgUrl, options?.signal);\n\n const { exif, ...attr } = imageWithExif;\n\n const dataRange = parseExifDataRangeWithWind(exif.dataRange);\n\n const bounds = parseExifBounds(exif.bounds);\n\n return {\n ...attr,\n dataRange,\n bounds,\n };\n}\n",
30
30
  "import { IMap } from '../types/map';\n\nfunction mod(x: number, y: number): number {\n return ((x % y) + y) % y;\n}\n\nexport function wrapLongitude(lng: number, minLng?: number): number {\n let wrappedLng = mod(lng + 180, 360) - 180;\n if (typeof minLng === 'number' && wrappedLng < minLng) {\n wrappedLng += 360;\n }\n return wrappedLng;\n}\n\n/**\n * 包装bounds\n * @param bounds\n * @returns\n */\nexport function wrapBounds(bounds: GeoJSON.BBox): GeoJSON.BBox {\n const minLng = bounds[2] - bounds[0] < 360 ? wrapLongitude(bounds[0]) : -180;\n const maxLng = bounds[2] - bounds[0] < 360 ? wrapLongitude(bounds[2], minLng) : 180;\n\n const minLat = Math.max(bounds[1], -85.051129);\n const maxLat = Math.min(bounds[3], 85.051129);\n\n const mercatorBounds = [minLng, minLat, maxLng, maxLat] as GeoJSON.BBox;\n return mercatorBounds;\n}\n\n/**\n * 将map的bounds转换成包装好的bounds\n * @param map\n * @returns\n */\nexport function getViewportBounds(map: IMap): GeoJSON.BBox {\n const viewportBounds = map.getBounds().toArray().flat() as GeoJSON.BBox;\n return wrapBounds(viewportBounds);\n}\n",
31
- "import { wrap } from 'comlink';\nimport { ICreateMaskTextureParams } from './createMaskTexture';\n\nexport async function loadWorker(params: ICreateMaskTextureParams): Promise<ImageData> {\n const worker = new Worker(new URL('./mask-worker.js', import.meta.url), { type: 'module' });\n\n const obj = wrap<{ createMaskTexture: (params: ICreateMaskTextureParams) => ImageData }>(worker);\n\n return await obj.createMaskTexture(params);\n}\n",
31
+ "import { wrap } from 'comlink';\nimport { ICreateMaskTextureParams } from './index';\n\nexport async function loadWorker(params: ICreateMaskTextureParams): Promise<ImageData> {\n const worker = new Worker(new URL('./mask-worker.js', import.meta.url), { type: 'module' });\n\n const obj = wrap<{ createMaskTexture: (params: ICreateMaskTextureParams) => ImageData }>(worker);\n\n return await obj.createMaskTexture(params);\n}\n",
32
32
  "import { Bounds } from '../../types/map';\nimport { loadWorker } from './worker-load';\n\nexport interface ICreateMaskTextureParams {\n data: string | GeoJSON.FeatureCollection | GeoJSON.Feature;\n viewportBounds?: Bounds;\n projection?: d3.GeoProjection;\n width?: number;\n}\n\nexport async function createMaskTexture(params: ICreateMaskTextureParams) {\n return await loadWorker(params);\n}\n",
33
33
  "import china_province from './file/china_province.json';\nimport china_city from './file/chain_city.json';\nimport china_province_names from './file/china_province_names.json';\nimport china_shuixi from './file/china_shuixi.json';\nimport china from './file/china.json';\nimport land from './file/land.json';\nimport { produce } from 'immer';\nimport * as turf from '@turf/turf';\n\nexport type IProvinceGeoJSON = GeoJSON.Feature<GeoJSON.MultiPolygon, { name: string; gb: string }>;\n\nexport type IProvincesGeoJSON = GeoJSON.FeatureCollection<GeoJSON.MultiPolygon, { name: string; gb: string }>;\n\nexport type ICityGeoJSON = GeoJSON.FeatureCollection<GeoJSON.MultiPolygon, { name: string; gb: string }>;\n\nexport type IProvinceNamesGeoJSON = GeoJSON.FeatureCollection<\n GeoJSON.Point,\n { province: string; abbreviation: string; capital: string }\n>;\n\nexport class ChinaGeoJSONMgr {\n public static getProvince(gb: string): {\n province: IProvinceGeoJSON;\n citys: ICityGeoJSON;\n } {\n const china_province_geojson = china_province as unknown as ICityGeoJSON;\n const china_city_geojson = china_city as unknown as ICityGeoJSON;\n\n const province = china_province_geojson.features.find(e => e.properties.gb === gb)!;\n\n const citys = turf.featureCollection(\n china_city_geojson.features.filter(e => {\n const province_gb = parseInt(province.properties.gb);\n const city_gb = parseInt(e.properties.gb);\n return city_gb >= province_gb && city_gb < province_gb + 10000;\n }),\n );\n\n return {\n province,\n citys,\n };\n }\n\n public static getChinaProvinces(): IProvincesGeoJSON {\n const data = china_province as unknown as IProvincesGeoJSON;\n return produce(data, draft => {\n draft.features.forEach(e => {\n e.id = e.properties.gb;\n });\n });\n }\n\n public static getChinaProvinceNames(): IProvinceNamesGeoJSON {\n return china_province_names as IProvinceNamesGeoJSON;\n }\n\n public static getChinaShuiXi(): GeoJSON.FeatureCollection {\n return china_shuixi as GeoJSON.FeatureCollection;\n }\n\n public static getChina(): GeoJSON.FeatureCollection {\n return china as GeoJSON.FeatureCollection;\n }\n\n public static getLand(): GeoJSON.FeatureCollection {\n return land as GeoJSON.FeatureCollection;\n }\n}\n",
34
34
  "import { INFINITY_VALUE } from '../config/colorPalette';\nimport { IColorPaletteConfig } from '../types/colorPalette';\n\nexport interface IColorPaletteFns {\n toColor: (val: number) => string | undefined;\n values: number[];\n min: number;\n max: number;\n}\n\nexport function toColorPaletteFns(colorPalette: IColorPaletteConfig): IColorPaletteFns {\n const sortedColorPalette = colorPalette.sort((a, b) => a.value - b.value);\n const values = sortedColorPalette.flatMap(e => e.value).filter(e => e !== INFINITY_VALUE);\n const min = Math.min(...values);\n const max = Math.max(...values);\n return {\n values,\n min,\n max,\n toColor: (val: number) => {\n let outColor: string | undefined;\n if (val >= sortedColorPalette[sortedColorPalette.length - 1].value) {\n outColor = sortedColorPalette[sortedColorPalette.length - 1].color!;\n } else {\n for (let i = 0; i < colorPalette.length; i++) {\n if (val >= sortedColorPalette[i].value && val < sortedColorPalette[i + 1].value) {\n outColor = sortedColorPalette[i].color!;\n break;\n }\n }\n }\n return outColor;\n },\n };\n}\n",
@@ -2,8 +2,6 @@ import { expose } from 'comlink';
2
2
 
3
3
  expose({
4
4
  async createMaskTexture(params) {
5
- // return await createMaskTexture(params);
6
-
7
5
  const { data, width = 1000, projection = d3.geoMercator(), viewportBounds } = params;
8
6
 
9
7
  const offscreenCanvas = new OffscreenCanvas(width, width);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iweather-gl",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "工具函数包",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -1,10 +0,0 @@
1
- import * as d3 from 'd3';
2
- import { Bounds } from 'iweather-gl';
3
- export interface ICreateMaskTextureParams {
4
- data: string | GeoJSON.FeatureCollection | GeoJSON.Feature;
5
- viewportBounds?: Bounds;
6
- projection?: d3.GeoProjection;
7
- width?: number;
8
- }
9
- export declare function createMaskTexture(params: ICreateMaskTextureParams): Promise<ImageData>;
10
- //# sourceMappingURL=createMaskTexture.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createMaskTexture.d.ts","sourceRoot":"","sources":["../../../src/fns/mask/createMaskTexture.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC;IAC3D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,wBAAwB,GAAG,OAAO,CAAC,SAAS,CAAC,CAmD5F"}
@@ -1,41 +0,0 @@
1
- import * as d3 from 'd3';
2
- import * as turf from '@turf/turf';
3
- export async function createMaskTexture(params) {
4
- const { data, width = 1000, projection = d3.geoMercator(), viewportBounds } = params;
5
- const offscreenCanvas = new OffscreenCanvas(width, width);
6
- const ctx = offscreenCanvas.getContext('2d', { willReadFrequently: false });
7
- const viewportGeojson = typeof data === 'string' ? (await d3.json(data)) : data;
8
- const bbox = viewportBounds ?? turf.bbox(viewportGeojson);
9
- // 设置投影
10
- projection.fitWidth(width, viewportGeojson);
11
- const path = d3.geoPath().projection(projection).context(ctx);
12
- // 显示区域的形状
13
- const viewportPolygon = turf.polygon([
14
- [
15
- [bbox[0], bbox[1]],
16
- [bbox[0], bbox[3]],
17
- [bbox[2], bbox[3]],
18
- [bbox[2], bbox[1]],
19
- [bbox[0], bbox[1]],
20
- ],
21
- ]);
22
- // 计算画布尺寸
23
- const projectedBounds = path.bounds(viewportPolygon);
24
- const projectedWidth = projectedBounds[1][0] - projectedBounds[0][0];
25
- const projectedHeight = projectedBounds[1][1] - projectedBounds[0][1];
26
- offscreenCanvas.width = width;
27
- offscreenCanvas.height = (width / projectedWidth) * projectedHeight;
28
- projection.fitExtent([
29
- [0, 0],
30
- [offscreenCanvas.width, offscreenCanvas.height],
31
- ], viewportPolygon);
32
- path.projection(projection);
33
- // 绘制
34
- ctx.save();
35
- (ctx.beginPath(), path(viewportGeojson), (ctx.fillStyle = '#000'), ctx.fill());
36
- ctx.restore();
37
- // 输出ImageData
38
- const rgba = ctx.getImageData(0, 0, offscreenCanvas.width, offscreenCanvas.height).data;
39
- return new ImageData(rgba, offscreenCanvas.width, offscreenCanvas.height);
40
- }
41
- //# sourceMappingURL=createMaskTexture.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"createMaskTexture.js","sourceRoot":"","sources":["../../../src/fns/mask/createMaskTexture.ts"],"names":[],"mappings":"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"}