@allmaps/stdlib
Advanced tools
Comparing version 1.0.0-beta.27 to 1.0.0-beta.28
@@ -10,3 +10,3 @@ import type { Point } from '@allmaps/types'; | ||
}; | ||
export declare function getImageData(imageElement: HTMLImageElement, mask?: Point[]): ImageData; | ||
export declare function getImageData(imageBitmap: ImageBitmap, mask?: Point[]): ImageData; | ||
export declare function getColorsArray(imageData: ImageData, resolution?: number): Color[]; | ||
@@ -13,0 +13,0 @@ export declare function getColorHistogram(colors: Color[], binSize?: number): Histogram; |
const DEFAULT_BIN_SIZE = 5; | ||
const DEFAULT_RESOLUTION = 2; | ||
export function getImageData(imageElement, mask) { | ||
const canvas = document.createElement('canvas'); | ||
export function getImageData(imageBitmap, mask) { | ||
const canvas = new OffscreenCanvas(imageBitmap.width, imageBitmap.height); | ||
const context = canvas.getContext('2d'); | ||
if (context) { | ||
canvas.width = imageElement.width; | ||
canvas.height = imageElement.height; | ||
if (mask) { | ||
context.fillStyle = 'rgba(0, 0, 0, 0)'; | ||
context.fillRect(0, 0, imageElement.width, imageElement.height); | ||
context.beginPath(); | ||
context.moveTo(mask[0][0], mask[0][1]); | ||
mask.slice(1).forEach((point) => context.lineTo(point[0], point[1])); | ||
context.closePath(); | ||
context.clip(); | ||
} | ||
context.drawImage(imageElement, 0, 0); | ||
return context.getImageData(0, 0, imageElement.width, imageElement.height); | ||
if (!context) { | ||
throw new Error('Could not create OffscreenCanvas context'); | ||
} | ||
else { | ||
throw new Error('Unable to get canvas context'); | ||
if (mask) { | ||
context.fillStyle = 'rgba(0, 0, 0, 0)'; | ||
context.fillRect(0, 0, imageBitmap.width, imageBitmap.height); | ||
context.beginPath(); | ||
context.moveTo(mask[0][0], mask[0][1]); | ||
mask.slice(1).forEach((point) => context.lineTo(point[0], point[1])); | ||
context.closePath(); | ||
context.clip(); | ||
} | ||
context.drawImage(imageBitmap, 0, 0); | ||
return context.getImageData(0, 0, imageBitmap.width, imageBitmap.height); | ||
} | ||
@@ -25,0 +21,0 @@ export function getColorsArray(imageData, resolution = DEFAULT_RESOLUTION) { |
@@ -1,2 +0,2 @@ | ||
import type { Point, Polygon, Geometry, Line, Rectangle, Bbox, Size, GeojsonGeometry } from '@allmaps/types'; | ||
import type { Point, Polygon, Geometry, Line, Rectangle, Bbox, Size, Fit, GeojsonGeometry } from '@allmaps/types'; | ||
export declare function computeMinMax(values: number[]): [number, number]; | ||
@@ -10,2 +10,3 @@ export declare function computeBbox(points: Geometry | GeojsonGeometry): Bbox; | ||
export declare function bboxToLine(bbox: Bbox): Line; | ||
export declare function bboxToPoint(bbox: Bbox): Point; | ||
export declare function bboxToDiameter(bbox: Bbox): number; | ||
@@ -16,4 +17,4 @@ export declare function geometryToDiameter(geometry: Geometry | GeojsonGeometry): number; | ||
export declare function rectangleToSize(rectangle: Rectangle): Size; | ||
export declare function sizesToScale(size0: Size, size1: Size): number; | ||
export declare function sizesToScale(size0: Size, size1: Size, fit?: Fit): number; | ||
export declare function bboxesToScale(bbox0: Bbox, bbox1: Bbox): number; | ||
export declare function rectanglesToScale(rectangle0: Rectangle, rectangle1: Rectangle): number; |
@@ -78,2 +78,5 @@ import { isGeojsonGeometry, convertGeojsonGeometryToGeometry } from './geojson.js'; | ||
} | ||
export function bboxToPoint(bbox) { | ||
return [bbox[0], bbox[1]]; | ||
} | ||
export function bboxToDiameter(bbox) { | ||
@@ -91,3 +94,5 @@ return distance(bboxToLine(bbox)); | ||
} | ||
// Approximate results, for rectangles coming from bboxes. A more precise result would require a minimal-covering-rectangle algorithm | ||
// Approximate results, for rectangles coming from bboxes. | ||
// A more precise result would require a minimal-covering-rectangle algorithm | ||
// Or computing and comparing rectangle surfaces | ||
export function rectangleToSize(rectangle) { | ||
@@ -104,4 +109,12 @@ return [ | ||
// Scales | ||
export function sizesToScale(size0, size1) { | ||
return Math.sqrt((size0[0] * size0[1]) / (size1[0] * size1[1])); | ||
export function sizesToScale(size0, size1, fit) { | ||
if (!fit) { | ||
return Math.sqrt((size0[0] * size0[1]) / (size1[0] * size1[1])); | ||
} | ||
else if (fit === 'contain') { | ||
return size1[0] >= size1[1] ? size0[0] / size1[0] : size0[1] / size1[1]; | ||
} | ||
else { | ||
return size1[0] >= size1[1] ? size0[1] / size1[1] : size0[0] / size1[0]; | ||
} | ||
} | ||
@@ -108,0 +121,0 @@ export function bboxesToScale(bbox0, bbox1) { |
@@ -1,9 +0,5 @@ | ||
type FetchOptions = { | ||
abortSignal?: AbortSignal; | ||
cache?: Cache; | ||
}; | ||
export declare function fetchUrl(url: string, options?: FetchOptions): Promise<Response>; | ||
export declare function fetchJson(url: string, options?: FetchOptions): Promise<unknown>; | ||
export declare function fetchImageInfo(imageUri: string, options?: FetchOptions): Promise<unknown>; | ||
export declare function fetchImage(url: string, abortSignal?: AbortSignal): Promise<HTMLImageElement>; | ||
export {}; | ||
import type { FetchFn } from '@allmaps/types'; | ||
export declare function fetchUrl(input: RequestInfo | URL, init?: RequestInit, fetchFn?: FetchFn): Promise<Response>; | ||
export declare function fetchJson(input: RequestInfo | URL, init?: RequestInit, fetchFn?: FetchFn): Promise<unknown>; | ||
export declare function fetchImageInfo(imageUri: string, init?: RequestInit, fetchFn?: FetchFn): Promise<unknown>; | ||
export declare function fetchImageBitmap(input: RequestInfo | URL, init?: RequestInit, fetchFn?: FetchFn): Promise<ImageBitmap>; |
@@ -1,13 +0,8 @@ | ||
export async function fetchUrl(url, options = {}) { | ||
export async function fetchUrl(input, init, fetchFn) { | ||
let response; | ||
if (options.cache) { | ||
response = await options.cache.match(url); | ||
if (typeof fetchFn === 'function') { | ||
response = await fetchFn(input, init); | ||
} | ||
if (!response) { | ||
response = await fetch(url, { | ||
signal: options.abortSignal | ||
}); | ||
if (options.cache) { | ||
options.cache.put(url, response.clone()); | ||
} | ||
else { | ||
response = await fetch(input, init); | ||
} | ||
@@ -19,43 +14,13 @@ if (!response.ok) { | ||
} | ||
export async function fetchJson(url, options = {}) { | ||
const response = await fetchUrl(url, options); | ||
export async function fetchJson(input, init, fetchFn) { | ||
const response = await fetchUrl(input, init, fetchFn); | ||
return await response.json(); | ||
} | ||
export async function fetchImageInfo(imageUri, options = {}) { | ||
const json = await fetchJson(`${imageUri}/info.json`, options); | ||
return json; | ||
export async function fetchImageInfo(imageUri, init, fetchFn) { | ||
return await fetchJson(`${imageUri}/info.json`, init, fetchFn); | ||
} | ||
export function fetchImage(url, abortSignal) { | ||
return new Promise((resolve, reject) => { | ||
const image = new Image(); | ||
let aborted = false; | ||
image.addEventListener('load', () => resolve(image)); | ||
image.addEventListener('error', async () => { | ||
if (!aborted) { | ||
// image.src errors are not at all descriptive | ||
// load image again using fetch | ||
try { | ||
await fetchUrl(url, { abortSignal }); | ||
throw new Error('Image failed to load by setting Image src but downloaded successfully using fetch'); | ||
} | ||
catch (err) { | ||
reject(err); | ||
} | ||
} | ||
else { | ||
reject(new DOMException('Loading image aborted by user', 'AbortError')); | ||
} | ||
}); | ||
image.crossOrigin = 'anonymous'; | ||
image.src = url; | ||
if (abortSignal) { | ||
abortSignal.addEventListener('abort', () => { | ||
// abort event received from AbortController | ||
// Set image.src to '' to cancel the fetch | ||
// https://stackoverflow.com/questions/5278304/how-to-cancel-an-image-from-loading | ||
aborted = true; | ||
image.src = ''; | ||
}); | ||
} | ||
}); | ||
export async function fetchImageBitmap(input, init, fetchFn) { | ||
const response = await fetchUrl(input, init, fetchFn); | ||
const blob = await response.blob(); | ||
return await createImageBitmap(blob); | ||
} |
@@ -28,5 +28,4 @@ import type { Point, LineString, Ring, Polygon, MultiPoint, MultiLineString, MultiPolygon, Geometry, GeojsonPoint, GeojsonLineString, GeojsonPolygon, GeojsonMultiPoint, GeojsonMultiLineString, GeojsonMultiPolygon, GeojsonGeometry, GeojsonFeature, GeojsonFeatureCollection, SvgGeometry } from '@allmaps/types'; | ||
export declare function featuresToFeatureCollection(features: GeojsonFeature | GeojsonFeature[]): GeojsonFeatureCollection; | ||
export declare function geometriesToFeatureCollection(geometries: GeojsonGeometry[], properties?: unknown[]): { | ||
type: string; | ||
features: GeojsonFeature[]; | ||
}; | ||
export declare function geometriesToFeatureCollection(geometries: GeojsonGeometry[], properties?: unknown[]): GeojsonFeatureCollection; | ||
export declare function featureToGeometry(feature: GeojsonFeature): GeojsonGeometry; | ||
export declare function featureCollectionToGeometries(featureCollection: GeojsonFeatureCollection): GeojsonGeometry[]; |
@@ -228,1 +228,7 @@ import { isPoint, isLineString, isPolygon, isMultiPoint, isMultiLineString, isMultiPolygon, conformLineString, conformRing, conformPolygon, conformMultiLineString, conformMultiPolygon } from './geometry.js'; | ||
} | ||
export function featureToGeometry(feature) { | ||
return feature.geometry; | ||
} | ||
export function featureCollectionToGeometries(featureCollection) { | ||
return featureCollection.features.map(featureToGeometry); | ||
} |
@@ -1,2 +0,2 @@ | ||
import type { Point, LineString, Line, Ring, Polygon, MultiPoint, MultiLineString, MultiPolygon, Geometry, GeojsonPoint, GeojsonLineString, GeojsonPolygon, GeojsonMultiPoint, GeojsonMultiLineString, GeojsonMultiPolygon, GeojsonGeometry } from '@allmaps/types'; | ||
import type { Point, LineString, Line, Ring, Polygon, MultiPoint, MultiLineString, MultiPolygon, Geometry, GeojsonPoint, GeojsonLineString, GeojsonPolygon, GeojsonMultiPoint, GeojsonMultiLineString, GeojsonMultiPolygon, GeojsonGeometry, Size } from '@allmaps/types'; | ||
export declare function isPoint(input: any): input is Point; | ||
@@ -23,8 +23,11 @@ export declare function isLineString(input: any): input is LineString; | ||
export declare function isClosed(input: Point[]): boolean; | ||
export declare function isEqualPoint(point1: Point, point: Point): boolean; | ||
export declare function isEqualPointArray(pointArray1: Point[], pointArray2: Point[]): boolean; | ||
export declare function isEqualPointArrayArray(pointArrayArray1: Point[][], pointArrayArray2: Point[][]): boolean; | ||
export declare function isEqualPoint(point0: Point, point1: Point): boolean; | ||
export declare function isEqualPointArray(pointArray0: Point[], pointArray1: Point[]): boolean; | ||
export declare function isEqualPointArrayArray(pointArrayArray0: Point[][], pointArrayArray1: Point[][]): boolean; | ||
export declare function pointToPixel(point: Point, translate?: Point, size?: Size): Point; | ||
export declare function pixelToIntArrayIndex(pixel: Point, size: Size, channels: number, flipY?: boolean): number; | ||
export declare function flipX(point: Point): Point; | ||
export declare function flipY(point: Point): Point; | ||
export declare function midPoint(point0: Point, point1: Point): Point; | ||
export declare function mixNumbers(number0: number, number1: number, t: number): number; | ||
export declare function mixPoints(point0: Point, point1: Point, t: number): Point; | ||
@@ -31,0 +34,0 @@ export declare function distance(line: Line): number; |
@@ -18,3 +18,3 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ | ||
return (Array.isArray(input) && input.every(isPoint) | ||
// && isClosed(input) == closed // Possible addition if we want to check for closedness, with closed an input parameter with default false | ||
// && isClosed(input) === closed // Possible addition if we want to check for closedness, with closed an input parameter with default false | ||
); | ||
@@ -161,18 +161,18 @@ } | ||
} | ||
export function isEqualPoint(point1, point) { | ||
if (point1 === point) | ||
export function isEqualPoint(point0, point1) { | ||
if (point0 === point1) | ||
return true; | ||
if (point1 == null || point == null) | ||
if (point0 === null || point1 === null) | ||
return false; | ||
return point1[0] == point[0] && point1[1] == point[1]; | ||
return point0[0] === point1[0] && point0[1] === point1[1]; | ||
} | ||
export function isEqualPointArray(pointArray1, pointArray2) { | ||
if (pointArray1 === pointArray2) | ||
export function isEqualPointArray(pointArray0, pointArray1) { | ||
if (pointArray0 === pointArray1) | ||
return true; | ||
if (pointArray1 == null || pointArray2 == null) | ||
if (!pointArray0 || !pointArray1) | ||
return false; | ||
if (pointArray1.length !== pointArray2.length) | ||
if (pointArray0.length !== pointArray1.length) | ||
return false; | ||
for (let i = 0; i < pointArray1.length; ++i) { | ||
if (isEqualPoint(pointArray1[i], pointArray2[i])) | ||
for (let i = 0; i < pointArray0.length; ++i) { | ||
if (isEqualPoint(pointArray0[i], pointArray1[i])) | ||
return false; | ||
@@ -182,11 +182,11 @@ } | ||
} | ||
export function isEqualPointArrayArray(pointArrayArray1, pointArrayArray2) { | ||
if (pointArrayArray1 === pointArrayArray2) | ||
export function isEqualPointArrayArray(pointArrayArray0, pointArrayArray1) { | ||
if (pointArrayArray0 === pointArrayArray1) | ||
return true; | ||
if (pointArrayArray1 == null || pointArrayArray2 == null) | ||
if (!pointArrayArray0 || !pointArrayArray1) | ||
return false; | ||
if (pointArrayArray1.length !== pointArrayArray2.length) | ||
if (pointArrayArray0.length !== pointArrayArray1.length) | ||
return false; | ||
for (let i = 0; i < pointArrayArray1.length; ++i) { | ||
if (isEqualPointArray(pointArrayArray1[i], pointArrayArray2[i])) | ||
for (let i = 0; i < pointArrayArray0.length; ++i) { | ||
if (isEqualPointArray(pointArrayArray0[i], pointArrayArray1[i])) | ||
return false; | ||
@@ -197,2 +197,17 @@ } | ||
// Compute | ||
export function pointToPixel(point, translate = [0, 0], size) { | ||
return point.map((coordinate, index) => { | ||
let result = Math.floor(coordinate + translate[index]); | ||
if (size) { | ||
result = Math.max(result, 0); | ||
result = Math.min(result, size[index] - 1); | ||
} | ||
return result; | ||
}); | ||
} | ||
export function pixelToIntArrayIndex(pixel, size, channels, flipY = false) { | ||
const column = pixel[0]; | ||
const row = flipY ? size[1] - 1 - pixel[1] : pixel[1]; | ||
return (row * size[0] + column) * channels; | ||
} | ||
export function flipX(point) { | ||
@@ -210,2 +225,5 @@ return [-point[0], point[1]]; | ||
} | ||
export function mixNumbers(number0, number1, t) { | ||
return number0 * t + number1 * (1 - t); | ||
} | ||
export function mixPoints(point0, point1, t) { | ||
@@ -218,3 +236,3 @@ return [ | ||
export function distance(from, to) { | ||
if (isLineString(from) && from.length == 2) { | ||
if (isLineString(from) && from.length === 2) { | ||
return distance(from[0], from[1]); | ||
@@ -221,0 +239,0 @@ } |
export * from './api.js'; | ||
export * from './background-color.js'; | ||
export * from './bbox.js'; | ||
export * from './cache.js'; | ||
export * from './color.js'; | ||
@@ -5,0 +6,0 @@ export * from './fetch.js'; |
export * from './api.js'; | ||
export * from './background-color.js'; | ||
export * from './bbox.js'; | ||
export * from './cache.js'; | ||
export * from './color.js'; | ||
@@ -5,0 +6,0 @@ export * from './fetch.js'; |
import { degreesToRadians } from './geometry.js'; | ||
// From: | ||
// https://gis.stackexchange.com/questions/156035/calculating-mercator-coordinates-from-lat-lon | ||
// From: https://gis.stackexchange.com/questions/156035/calculating-mercator-coordinates-from-lat-lon | ||
export function lonLatToWebMecator([lon, lat]) { | ||
@@ -5,0 +4,0 @@ const rMajor = 6378137.0; |
{ | ||
"name": "@allmaps/stdlib", | ||
"version": "1.0.0-beta.27", | ||
"version": "1.0.0-beta.28", | ||
"contributors": [ | ||
@@ -54,5 +54,5 @@ { | ||
"dependencies": { | ||
"@allmaps/annotation": "^1.0.0-beta.26", | ||
"@allmaps/iiif-parser": "^1.0.0-beta.36", | ||
"@allmaps/types": "^1.0.0-beta.12", | ||
"@allmaps/annotation": "^1.0.0-beta.27", | ||
"@allmaps/iiif-parser": "^1.0.0-beta.37", | ||
"@allmaps/types": "^1.0.0-beta.13", | ||
"@placemarkio/geojson-rewind": "^1.0.2", | ||
@@ -62,8 +62,10 @@ "svg-parser": "^2.0.4" | ||
"devDependencies": { | ||
"@types/eslint": "^8.56.0", | ||
"@types/svg-parser": "^2.0.3", | ||
"@typescript-eslint/eslint-plugin": "^5.45.0", | ||
"@typescript-eslint/parser": "^5.45.0", | ||
"@typescript-eslint/eslint-plugin": "^7.0.0", | ||
"@typescript-eslint/parser": "^7.0.0", | ||
"chai": "^4.3.6", | ||
"chai-shallow-deep-equal": "^1.4.6", | ||
"eslint": "^8.35.0", | ||
"eslint": "^8.56.0", | ||
"eslint-config-prettier": "^9.1.0", | ||
"mocha": "^8.4.0", | ||
@@ -73,3 +75,3 @@ "prettier": "^2.8.0", | ||
}, | ||
"gitHead": "c3a51a2359687465691b99b8c21fb9c20289064c" | ||
"gitHead": "2cd1595a894c77557a492e61371508d615d9f6b8" | ||
} |
50426
36
1277
11