From 4eb6b24b5c6c08f82fb7e65bbc8dbb1aea691fda Mon Sep 17 00:00:00 2001 From: dariaterekhovaae <98411986+dariaterekhovaae@users.noreply.github.com> Date: Fri, 4 Nov 2022 17:45:45 +0200 Subject: [PATCH] [Chore] dependencies update + publish process update (#1978) * Duplicate imports removed * Middleware moved into reducers Signed-off-by: Daria Terekhova * Build fix Signed-off-by: Ihor Dykhta --- .github/workflows/npmpublish.yml | 3 +- UPGRADE-GUIDE.md | 52 + contributing/DEVELOPERS.md | 2 +- .../cloud-providers/carto/carto-provider.js | 2 +- package.json | 139 +- src/actions/package.json | 16 + src/actions/src/vis-state-actions.ts | 2 +- src/cloud-providers/package.json | 4 + src/cloud-providers/src/index.ts | 2 +- src/cloud-providers/src/provider.ts | 4 +- src/components/package.json | 89 ++ .../src/common/data-table/cell-size.ts | 3 +- .../src/common/data-table/index.tsx | 3 +- .../common/item-selector/item-selector.tsx | 10 +- .../src/common/styled-components.tsx | 6 +- src/components/src/editor/editor.tsx | 9 +- src/components/src/filters/polygon-filter.tsx | 3 +- src/components/src/map-container.tsx | 11 +- src/components/src/map/map-legend.tsx | 7 +- src/components/src/modal-container.tsx | 3 +- .../export-map-modal/export-html-map.tsx | 6 +- .../export-map-modal/export-map-modal.tsx | 6 +- .../notification-panel/notification-item.tsx | 5 +- src/components/src/side-panel/common/types.ts | 4 +- .../interaction-panel/interaction-panel.tsx | 3 +- .../tooltip-config/tooltip-chicklet.tsx | 7 +- .../layer-panel/layer-configurator.tsx | 10 +- .../layer-panel/vis-config-slider.tsx | 3 +- src/constants/package.json | 7 +- src/constants/src/layers.ts | 23 + src/deckgl-layers/package.json | 16 +- src/index.js | 5 +- src/layers/package.json | 21 +- src/layers/src/arc-layer/arc-layer.ts | 4 +- src/layers/src/base-layer.ts | 16 +- src/layers/src/geojson-layer/geojson-layer.ts | 3 +- .../src/h3-hexagon-layer/h3-hexagon-layer.ts | 14 +- src/layers/src/h3-hexagon-layer/index.ts | 1 - src/layers/src/heatmap-layer/heatmap-layer.ts | 6 +- src/layers/src/hexagon-layer/hexagon-utils.ts | 2 +- src/layers/src/icon-layer/icon-layer.ts | 3 +- src/layers/src/index.ts | 5 +- src/layers/src/line-layer/line-layer.ts | 9 +- src/layers/src/point-layer/point-layer.ts | 3 +- .../s2-geometry-layer/s2-geometry-layer.ts | 7 +- .../src/scenegraph-layer/scenegraph-layer.ts | 3 +- src/layers/src/trip-layer/trip-layer.ts | 3 +- src/layers/src/trip-layer/trip-utils.ts | 12 +- src/layers/src/types.ts | 25 - src/localization/package.json | 21 +- src/localization/src/locales.ts | 2 +- src/localization/src/messages.ts | 16 +- src/middleware/babel.config.js | 65 - src/middleware/package.json | 65 - src/middleware/tsconfig.production.json | 32 - src/middleware/webpack/umd.js | 120 -- src/processors/package.json | 18 +- src/reducers/package.json | 36 + src/reducers/src/export-utils.ts | 10 +- src/reducers/src/index.ts | 2 + src/reducers/src/interaction-utils.ts | 2 +- src/reducers/src/layer-utils.ts | 4 +- src/reducers/src/map-style-updaters.ts | 8 +- .../index.ts => reducers/src/middleware.ts} | 0 src/reducers/src/ui-state-updaters.ts | 15 +- src/reducers/src/vis-state-merger.ts | 20 +- src/reducers/src/vis-state-updaters.ts | 37 +- src/schemas/package.json | 16 +- src/schemas/src/vis-state-schema.ts | 4 +- src/styles/package.json | 19 +- src/table/package.json | 12 + src/table/src/filter-utils.ts | 1172 ---------------- src/table/src/gpu-filter-utils.ts | 3 +- src/table/src/index.ts | 8 +- src/table/src/kepler-table.ts | 43 +- src/tasks/package.json | 5 + src/types/reducers.d.ts | 14 + src/utils/package.json | 48 +- .../src/data-container-interface.ts | 0 .../src/data-container-utils.ts | 0 src/{table => utils}/src/data-row.ts | 0 src/{table => utils}/src/data-scale-utils.ts | 2 +- src/utils/src/filter-utils.ts | 1205 ++++++++++++++++- .../src}/h3-utils.ts | 2 +- src/utils/src/index.ts | 76 +- .../src/indexed-data-container.ts | 0 .../map-style-utils/mapbox-gl-style-editor.ts | 3 +- .../src/row-data-container.ts | 0 test/browser/components/kepler-gl-test.js | 3 +- .../modals/data-table-modal-test.js | 2 +- .../components/modals/share-map-modal-test.js | 7 +- .../layer-tests/geojson-layer-specs.js | 10 +- .../layer-tests/h3-hexagon-layer-specs.js | 7 +- .../points-with-polygon-filter-map.js | 2 +- test/fixtures/test-hex-id-data.js | 2 +- test/helpers/mock-state.js | 5 +- test/node/reducers/vis-state-merger-test.js | 2 +- test/node/reducers/vis-state-test.js | 9 +- test/node/utils/aggregate-utils-test.js | 2 +- test/node/utils/color-util-test.js | 2 +- test/node/utils/data-container-test.js | 2 +- test/node/utils/data-processor-test.js | 4 +- test/node/utils/data-scale-utils-test.js | 2 +- test/node/utils/data-utils-test.js | 2 +- test/node/utils/dataset-utils-test.js | 2 +- test/node/utils/filter-utils-test.js | 8 +- test/node/utils/kepler-table-test.js | 4 +- test/node/utils/layer-utils-test.js | 8 +- test/node/utils/map-info-utils-test.js | 2 +- .../node/utils/mapbox-gl-style-editor-test.js | 2 +- test/node/utils/mapbox-utils-test.js | 2 +- test/node/utils/notifications-utils-test.js | 2 +- test/node/utils/util-test.js | 2 +- yarn.lock | 10 +- 114 files changed, 1881 insertions(+), 1931 deletions(-) delete mode 100644 src/layers/src/types.ts delete mode 100644 src/middleware/babel.config.js delete mode 100644 src/middleware/package.json delete mode 100644 src/middleware/tsconfig.production.json delete mode 100644 src/middleware/webpack/umd.js rename src/{middleware/src/index.ts => reducers/src/middleware.ts} (100%) delete mode 100644 src/table/src/filter-utils.ts rename src/{table => utils}/src/data-container-interface.ts (100%) rename src/{table => utils}/src/data-container-utils.ts (100%) rename src/{table => utils}/src/data-row.ts (100%) rename src/{table => utils}/src/data-scale-utils.ts (97%) rename src/{layers/src/h3-hexagon-layer => utils/src}/h3-utils.ts (97%) rename src/{table => utils}/src/indexed-data-container.ts (100%) rename src/{table => utils}/src/row-data-container.ts (100%) diff --git a/.github/workflows/npmpublish.yml b/.github/workflows/npmpublish.yml index bfc3808c38..790a9b8b0a 100644 --- a/.github/workflows/npmpublish.yml +++ b/.github/workflows/npmpublish.yml @@ -15,6 +15,7 @@ jobs: registry-url: https://registry.npmjs.org/ - run: npm install -g yarn - run: yarn - - run: npm publish + - run: npm install npm@8.19.2 + - run: npm publish --workspaces --access public env: NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/UPGRADE-GUIDE.md b/UPGRADE-GUIDE.md index 67159d4a27..c20a657679 100644 --- a/UPGRADE-GUIDE.md +++ b/UPGRADE-GUIDE.md @@ -92,3 +92,55 @@ ### Bug Fixes - __Cluster Layer__: Fix incorrect cluster point count. Fix cluster layer missing in exported image. + +### Moved from `kepler.gl/utils` to `@kepler.gl/table` +- `maybeToDate` +- `getNewDatasetColor` +- `createNewDataEntry` +- `setFilterGpuMode` +- `assignGpuChannels` +- `assignGpuChannel` +- `resetFilterGpuMode` +- `getGpuFilterProps` +- `getDatasetFieldIndexForFilter` + +### Moved from `kepler.gl/utils` to `@kepler.gl/reducers` +- `findMapBounds` +- `exportData` +- `TOOLTIP_MINUS_SIGN` +- `getDefaultInteraction` +- `BRUSH_CONFIG` +- `findFieldsToShow` +- `getTooltipDisplayDeltaValue` +- `getTooltipDisplayValue` +- `LayersToRender` +- `AggregationLayerHoverData` +- `LayerHoverProp` +- `findDefaultLayer` +- `calculateLayerData` +- `getLayerHoverProp` +- `renderDeckGlLayer` +- `isLayerRenderable` +- `isLayerVisible` +- `prepareLayersForDeck` +- `prepareLayersToRender` +- `getCustomDeckLayers` +- `ComputeDeckLayersProps` +- `computeDeckLayers` + +### Moved from `kepler.gl/processors` to `@kepler.gl/utils` +- `ACCEPTED_ANALYZER_TYPES` +- `validateInputData` +- `getSampleForTypeAnalyze` +- `getFieldsFromData` +- `renameDuplicateFields` +- `analyzerTypeToFieldType` + +### Moved from `kepler.gl/templates` to `@kepler.gl/utils` +- `exportMapToHTML` + +### Moved from `kepler.gl/layers` to `@kepler.gl/utils` +- `getCentroid` +- `idToPolygonGeo` +- `h3IsValid` +- `getHexFields` diff --git a/contributing/DEVELOPERS.md b/contributing/DEVELOPERS.md index 0cd96f9961..f7c7027e16 100644 --- a/contributing/DEVELOPERS.md +++ b/contributing/DEVELOPERS.md @@ -290,7 +290,7 @@ In order to publish a new version of kepler.gl a developer must perform the foll 3. Create a new PR for review. 4. Once the PR is reviewed and merged, pull the latest changes locally. 5. Run ```gh-release```: this command will create a new Github Release with the new updated CHANGELOG.md section. -6. Once the new Github Release is created, Github will automatically trgger a new Github Action flow that will automatically build and publish the new package version to NPM registry. +6. Once the new Github Release is created, Github will automatically trigger a new Github Action flow that will automatically build and publish the new package version to NPM registry. __After Release is completed and pushed__ * Update each of the example folder package.json kepler.gl dependency with the newer. To update all examples, run diff --git a/examples/demo-app/src/cloud-providers/carto/carto-provider.js b/examples/demo-app/src/cloud-providers/carto/carto-provider.js index c414bf52c1..782a2a713e 100644 --- a/examples/demo-app/src/cloud-providers/carto/carto-provider.js +++ b/examples/demo-app/src/cloud-providers/carto/carto-provider.js @@ -22,7 +22,7 @@ import {OAuthApp} from '@carto/toolkit'; import Console from 'global/console'; import CartoIcon from './carto-icon'; import {Provider} from '@kepler.gl/cloud-providers'; -import {createDataContainer} from '@kepler.gl/table'; +import {createDataContainer} from '@kepler.gl/utils'; import {formatCsv} from 'reducers'; const NAME = 'carto'; diff --git a/package.json b/package.json index b569e04cc8..58c5c2c3fd 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,6 @@ "./src/utils", "./src/styles", "./src/localization", - "./src/middleware", "./src/deckgl-layers", "./src/layers", "./src/schemas", @@ -65,14 +64,14 @@ "start:web": "yarn install-and-start -- website start", "start:https": "yarn install-and-start -- examples/demo-app start-local-https", "start:e2e": "yarn install-and-start -- examples/demo-app start-local-e2e", - "build": "rm -fr dist && babel src/{actions,components,middleware,reducers,cloud-providers,localization,tasks} --out-dir dist --source-maps inline --extensions '.ts,.tsx,.js,.jsx' --ignore '**/*.d.ts'", + "build": "rm -fr dist && babel src/{actions,components,reducers,cloud-providers,localization,tasks} --out-dir dist --source-maps inline --extensions '.ts,.tsx,.js,.jsx' --ignore '**/*.d.ts'", "build:umd": "webpack --config ./webpack/umd.js --progress --env.prod", "build:types": "tsc --project tsconfig.production.json", "analyze": "yarn analyze:bundle", "analyze:bundle": "webpack --config ./webpack/bundle.js --progress --env.prod", "check-licence": "uber-licence --dry", "add-licence": "uber-licence", - "prepublish": "yarn workspaces run stab && yarn workspaces run prepublish && uber-licence && yarn build && yarn build:umd && yarn build:types", + "prepublish": "yarn workspaces run stab && yarn workspaces run prepublish && uber-licence && yarn build:umd && yarn build:types", "docs": "babel-node ./scripts/documentation.js", "typedoc": "typedoc --theme markdown --out typedoc --inputFiles ./src/reducers --inputFiles ./src/actions --excludeExternals --excludeNotExported --excludePrivate", "example-version": "babel-node ./scripts/edit-version.js", @@ -102,128 +101,18 @@ "umd" ], "dependencies": { - "@danmarshall/deckgl-typings": "4.9.22", - "@deck.gl/aggregation-layers": "8.6.0", - "@deck.gl/core": "^8.6.0", - "@deck.gl/extensions": "^8.6.0", - "@deck.gl/geo-layers": "^8.6.0", - "@deck.gl/layers": "^8.6.0", - "@deck.gl/mapbox": "^8.6.0", - "@deck.gl/mesh-layers": "^8.6.0", - "@deck.gl/react": "^8.6.0", - "@hubble.gl/core": "1.2.0-alpha.6", - "@hubble.gl/react": "1.2.0-alpha.6", - "@loaders.gl/core": "^3.0.9", - "@loaders.gl/csv": "^3.0.9", - "@loaders.gl/gltf": "^3.0.9", - "@loaders.gl/json": "^3.0.9", - "@loaders.gl/loader-utils": "^3.0.9", - "@loaders.gl/polyfills": "^3.0.9", - "@loaders.gl/shapefile": "^3.0.9", - "@luma.gl/constants": "^8.5.10", - "@luma.gl/core": "^8.5.10", - "@mapbox/geo-viewport": "^0.4.1", - "@mapbox/geojson-normalize": "0.0.1", - "@mapbox/vector-tile": "^1.3.1", - "@reduxjs/toolkit": "^1.7.2", - "@tippyjs/react": "^4.2.0", - "@turf/bbox": "^6.0.1", - "@turf/boolean-within": "^6.0.1", - "@turf/helpers": "^6.1.4", - "@types/classnames": "^2.3.1", - "@types/d3-brush": "^3.0.1", - "@types/d3-selection": "^3.0.2", - "@types/exenv": "^1.2.0", - "@types/keymirror": "^0.1.1", - "@types/lodash.clonedeep": "^4.5.7", - "@types/lodash.curry": "^4.1.7", - "@types/lodash.debounce": "^4.0.7", - "@types/lodash.flattendeep": "^4.4.7", - "@types/lodash.get": "^4.4.6", - "@types/lodash.isequal": "^4.5.5", - "@types/lodash.memoize": "^4.1.7", - "@types/lodash.pick": "^4.4.6", - "@types/lodash.throttle": "^4.1.7", - "@types/lodash.uniq": "^4.5.7", - "@types/lodash.uniqby": "^4.7.7", - "@types/lodash.xor": "^4.5.7", - "@types/mapbox__geo-viewport": "^0.4.1", - "@types/react-copy-to-clipboard": "^5.0.2", - "@types/react-dom": "^18.0.0", - "@types/react-lifecycles-compat": "^3.0.1", - "@types/react-map-gl": "^6.1.2", - "@types/react-modal": "^3.13.1", - "@types/react-onclickoutside": "^6.7.4", - "@types/react-redux": "^7.1.23", - "@types/react-virtualized": "^9.21.20", - "@types/react-vis": "^1.8.0", - "@types/styled-components": "^5.1.25", - "@typescript-eslint/parser": "^5.27.0", - "classnames": "^2.2.1", - "colorbrewer": "^1.5.0", - "copy-to-clipboard": "^3.3.1", - "d3-array": "^2.8.0", - "d3-axis": "^2.0.0", - "d3-brush": "^2.1.0", - "d3-color": "^2.0.0", - "d3-dsv": "^2.0.0", - "d3-format": "^2.0.0", - "d3-hexbin": "^0.2.2", - "d3-request": "^1.0.6", - "d3-scale": "^3.2.3", - "decimal.js": "^10.2.0", - "eslint-config-developit": "^1.2.0", - "exenv": "^1.2.2", - "fuzzy": "^0.1.3", - "global": "^4.3.0", - "h3-js": "^3.1.0", - "html-webpack-plugin": "^4.3.0", - "keymirror": "^0.1.1", - "lodash.clonedeep": "^4.0.1", - "lodash.curry": "^4.1.1", - "lodash.debounce": "^4.0.8", - "lodash.flattendeep": "^4.2.0", - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", - "lodash.memoize": "^4.1.2", - "lodash.pick": "^4.4.0", - "lodash.throttle": "^4.1.1", - "lodash.uniq": "^4.0.1", - "lodash.uniqby": "^4.7.0", - "lodash.xor": "^4.5.0", - "long": "^4.0.0", - "mapbox": "^1.0.0-beta10", - "mini-svg-data-uri": "^1.0.3", - "moment": "^2.10.6", - "moment-timezone": "^0.5.32", - "pbf": "^3.1.0", - "prop-types": "^15.6.0", - "react-color": "^2.17.3", - "react-copy-to-clipboard": "^5.0.2", - "react-intl": "^3.12.0", - "react-json-pretty": "^2.2.0", - "react-lifecycles-compat": "^3.0.4", - "react-map-gl": "^5.0.3", - "react-map-gl-draw": "0.14.8", - "react-markdown": "^5.0.2", - "react-modal": "^3.8.1", - "react-onclickoutside": "^6.7.1", - "react-palm": "^3.3.7", - "react-redux": "^7.1.3", - "react-sortable-hoc": "^1.8.3", - "react-tooltip": "^4.2.17", - "react-virtualized": "^9.21.1", - "react-vis": "^1.8.0", - "redux": "^4.0.5", - "redux-actions": "^2.2.1", - "reselect": "^4.0.0", - "resize-observer-polyfill": "^1.5.1", - "s2-geometry": "^1.2.10", - "supercluster": "^7.1.0", - "type-analyzer": "0.3.0", - "typedoc": "^0.19.2", - "viewport-mercator-project": "^6.0.0", - "wellknown": "^0.5.0" + "@deck.gl/mapbox":"^8.6.0", + "@hubble.gl/core":"1.2.0-alpha.6", + "@hubble.gl/react":"1.2.0-alpha.6", + "@kepler.gl/components":"2.5.5", + "@loaders.gl/polyfills":"^3.0.9", + "@loaders.gl/shapefile":"^3.0.9", + "@types/mapbox__geo-viewport":"^0.4.1", + "@typescript-eslint/parser":"^5.27.0", + "d3-hexbin":"^0.2.2", + "eslint-config-developit":"^1.2.0", + "html-webpack-plugin":"^4.3.0", + "typedoc":"^0.19.2" }, "devDependencies": { "@babel/cli": "^7.12.1", diff --git a/src/actions/package.json b/src/actions/package.json index 1d1ed2ce17..7f7741e1ff 100644 --- a/src/actions/package.json +++ b/src/actions/package.json @@ -29,6 +29,22 @@ "dist", "umd" ], + "dependencies": { + "@kepler.gl/cloud-providers": "2.5.5", + "@kepler.gl/constants": "2.5.5", + "@kepler.gl/layers": "2.5.5", + "@kepler.gl/processors": "2.5.5", + "@kepler.gl/types": "2.5.5", + "@reduxjs/toolkit": "^1.7.2", + "@types/lodash.curry": "^4.1.7", + "@types/react-redux": "^7.1.23", + "@types/redux-actions": "^2.6.2", + "lodash.curry": "^4.1.1", + "react-palm": "^3.3.7", + "react-redux": "^7.1.3", + "redux": "^4.0.5", + "redux-actions": "^2.2.1" + }, "nyc": { "sourceMap": false, "instrument": false diff --git a/src/actions/src/vis-state-actions.ts b/src/actions/src/vis-state-actions.ts index 688b9f11f1..5a2a9594c5 100644 --- a/src/actions/src/vis-state-actions.ts +++ b/src/actions/src/vis-state-actions.ts @@ -21,9 +21,9 @@ // vis-state-reducer import {default as ActionTypes} from './action-types'; import {FileCacheItem} from '@kepler.gl/processors'; -import {AddDataToMapPayload} from '@kepler.gl/types'; import {Layer, LayerBaseConfig} from '@kepler.gl/layers'; import { + AddDataToMapPayload, ValueOf, Merge, RGBColor, diff --git a/src/cloud-providers/package.json b/src/cloud-providers/package.json index 1dda33c58b..c359835bc8 100644 --- a/src/cloud-providers/package.json +++ b/src/cloud-providers/package.json @@ -29,6 +29,10 @@ "dist", "umd" ], + "dependencies": { + "@kepler.gl/types": "2.5.5", + "react": "^16.8.4" + }, "nyc": { "sourceMap": false, "instrument": false diff --git a/src/cloud-providers/src/index.ts b/src/cloud-providers/src/index.ts index 7ce74f8873..fe0d21264d 100644 --- a/src/cloud-providers/src/index.ts +++ b/src/cloud-providers/src/index.ts @@ -20,5 +20,5 @@ export {default as Provider, FILE_CONFLICT_MSG} from './provider'; // eslint-disable-next-line prettier/prettier -export type {MapListItem, Millisecond, Thumbnail, ProviderProps, IconProps} from './provider'; +export type {MapListItem, Thumbnail, ProviderProps, IconProps} from './provider'; export {default as Upload} from './upload'; diff --git a/src/cloud-providers/src/provider.ts b/src/cloud-providers/src/provider.ts index 52ad26ed10..98a4922189 100644 --- a/src/cloud-providers/src/provider.ts +++ b/src/cloud-providers/src/provider.ts @@ -19,11 +19,9 @@ // THE SOFTWARE. import Upload from './upload'; -import {MapData, ExportFileOptions} from '@kepler.gl/types'; +import {MapData, ExportFileOptions, Millisecond} from '@kepler.gl/types'; import {ComponentType} from 'react'; -export type Millisecond = number; - export type MapListItem = { id: string; title: string; diff --git a/src/components/package.json b/src/components/package.json index bd1b0454ff..4a236760a7 100644 --- a/src/components/package.json +++ b/src/components/package.json @@ -29,6 +29,95 @@ "dist", "umd" ], + "dependencies": { + "@deck.gl/core": "^8.6.0", + "@deck.gl/react": "^8.6.0", + "@kepler.gl/actions": "2.5.5", + "@kepler.gl/cloud-providers": "2.5.5", + "@kepler.gl/constants": "2.5.5", + "@kepler.gl/layers": "2.5.5", + "@kepler.gl/localization": "2.5.5", + "@kepler.gl/processors": "2.5.5", + "@kepler.gl/reducers": "2.5.5", + "@kepler.gl/schemas": "2.5.5", + "@kepler.gl/styles": "2.5.5", + "@kepler.gl/table": "2.5.5", + "@kepler.gl/types": "2.5.5", + "@kepler.gl/utils": "2.5.5", + "@nebula.gl/edit-modes": "0.14.0", + "@tippyjs/react": "^4.2.0", + "@types/classnames": "^2.3.1", + "@types/d3-array": "^2.0.0", + "@types/d3-brush": "^3.0.1", + "@types/d3-scale": "^3.2.2", + "@types/d3-selection": "^3.0.2", + "@types/exenv": "^1.2.0", + "@types/lodash.debounce": "^4.0.7", + "@types/lodash.get": "^4.4.6", + "@types/lodash.isequal": "^4.5.5", + "@types/lodash.memoize": "^4.1.7", + "@types/lodash.pick": "^4.4.6", + "@types/lodash.throttle": "^4.1.7", + "@types/lodash.uniq": "^4.5.7", + "@types/lodash.uniqby": "^4.7.7", + "@types/react-copy-to-clipboard": "^5.0.2", + "@types/react-dom": "^18.0.0", + "@types/react-lifecycles-compat": "^3.0.1", + "@types/react-map-gl": "^6.1.2", + "@types/react-modal": "^3.13.1", + "@types/react-onclickoutside": "^6.7.4", + "@types/react-redux": "^7.1.23", + "@types/react-virtualized": "^9.21.20", + "@types/react-vis": "^1.8.0", + "@types/styled-components": "^5.1.25", + "classnames": "^2.2.1", + "copy-to-clipboard": "^3.3.1", + "d3-array": "^2.8.0", + "d3-axis": "^2.0.0", + "d3-brush": "^2.1.0", + "d3-color": "^2.0.0", + "d3-format": "^2.0.0", + "d3-scale": "^3.2.3", + "d3-selection": "^2.0.0", + "exenv": "^1.2.2", + "fuzzy": "^0.1.3", + "global": "^4.3.0", + "lodash.debounce": "^4.0.8", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", + "lodash.memoize": "^4.1.2", + "lodash.pick": "^4.4.0", + "lodash.throttle": "^4.1.1", + "lodash.uniq": "^4.0.1", + "lodash.uniqby": "^4.7.0", + "mapbox": "^1.0.0-beta10", + "mapbox-gl": "^1.0.0", + "mjolnir.js": "^2.5.0", + "moment": "^2.10.6", + "moment-timezone": "^0.5.32", + "prop-types": "^15.6.0", + "react": "^16.8.4", + "react-color": "^2.17.3", + "react-copy-to-clipboard": "^5.0.2", + "react-dom": "^16.8.4", + "react-intl": "^3.12.0", + "react-json-pretty": "^2.2.0", + "react-lifecycles-compat": "^3.0.4", + "react-map-gl": "^5.0.3", + "react-map-gl-draw": "0.14.8", + "react-markdown": "^5.0.2", + "react-modal": "^3.8.1", + "react-onclickoutside": "^6.7.1", + "react-redux": "^7.1.3", + "react-sortable-hoc": "^1.8.3", + "react-tooltip": "^4.2.17", + "react-virtualized": "^9.21.1", + "react-vis": "^1.8.0", + "redux": "^4.0.5", + "reselect": "^4.0.0", + "styled-components": "^4.1.3", + "viewport-mercator-project": "^6.0.0" + }, "nyc": { "sourceMap": false, "instrument": false diff --git a/src/components/src/common/data-table/cell-size.ts b/src/components/src/common/data-table/cell-size.ts index c9d7e3e50d..07d5baacbe 100644 --- a/src/components/src/common/data-table/cell-size.ts +++ b/src/components/src/common/data-table/cell-size.ts @@ -19,8 +19,7 @@ // THE SOFTWARE. import document from 'global/document'; -import {DataContainerInterface} from '@kepler.gl/table'; -import {parseFieldValue} from '@kepler.gl/utils'; +import {DataContainerInterface, parseFieldValue} from '@kepler.gl/utils'; const MIN_GHOST_CELL_SIZE: number = 200; const MIN_CELL_SIZE = 45; diff --git a/src/components/src/common/data-table/index.tsx b/src/components/src/common/data-table/index.tsx index d1300fc303..d0a40e4a6d 100644 --- a/src/components/src/common/data-table/index.tsx +++ b/src/components/src/common/data-table/index.tsx @@ -31,11 +31,10 @@ import {CellSizeCache} from './cell-size'; import Grid from './grid'; import HeaderCellFactory from './header-cell'; -import {parseFieldValue} from '@kepler.gl/utils'; +import {parseFieldValue, DataContainerInterface} from '@kepler.gl/utils'; import {adjustCellsToContainer} from './cell-size'; import {ALL_FIELD_TYPES} from '@kepler.gl/constants'; -import {DataContainerInterface} from '@kepler.gl/table'; const defaultHeaderRowHeight = 55; const defaultRowHeight = 32; diff --git a/src/components/src/common/item-selector/item-selector.tsx b/src/components/src/common/item-selector/item-selector.tsx index 1b1cdeaa17..9b5e4b7292 100644 --- a/src/components/src/common/item-selector/item-selector.tsx +++ b/src/components/src/common/item-selector/item-selector.tsx @@ -29,19 +29,19 @@ import Typeahead from './typeahead'; import {Delete, ArrowDown} from '../icons'; import DropdownList, {ListItem} from './dropdown-list'; import Portaled from '../../common/portaled'; -import {toArray} from '@kepler.gl/utils'; -import {observeDimensions, unobserveDimensions} from '@kepler.gl/utils'; +import {toArray, observeDimensions, unobserveDimensions} from '@kepler.gl/utils'; import {injectIntl, IntlShape} from 'react-intl'; import {FormattedMessage} from '@kepler.gl/localization'; interface StyledDropdownSelectProps { inputTheme?: string; size?: string; + className?: string; } -export const StyledDropdownSelect = styled.div.attrs({ - className: 'item-selector__dropdown' -})` +export const StyledDropdownSelect = styled.div.attrs(props => ({ + className: classnames('item-selector__dropdown', props.className) +}))` ${props => props.inputTheme === 'secondary' ? props.theme.secondaryInput diff --git a/src/components/src/common/styled-components.tsx b/src/components/src/common/styled-components.tsx index 4317b81df4..b291ff8063 100644 --- a/src/components/src/common/styled-components.tsx +++ b/src/components/src/common/styled-components.tsx @@ -696,9 +696,9 @@ interface MapControlButtonProps { active?: boolean; } -export const MapControlButton = styled(Button).attrs({ - className: 'map-control-button' -})` +export const MapControlButton = styled(Button).attrs(props => ({ + className: classnames('map-control-button', props.className) +}))` box-shadow: 0 6px 12px 0 rgba(0, 0, 0, 0.16); height: 32px; width: 32px; diff --git a/src/components/src/editor/editor.tsx b/src/components/src/editor/editor.tsx index ab1fc290a3..123b1e94e1 100644 --- a/src/components/src/editor/editor.tsx +++ b/src/components/src/editor/editor.tsx @@ -27,8 +27,13 @@ import get from 'lodash.get'; import {createSelector} from 'reselect'; import FeatureActionPanelFactory, {FeatureActionPanelProps} from './feature-action-panel'; -import {FILTER_TYPES, EDITOR_MODES, KeyEvent} from '@kepler.gl/constants'; -import {EDITOR_AVAILABLE_LAYERS, Layer} from '@kepler.gl/layers'; +import { + EDITOR_AVAILABLE_LAYERS, + FILTER_TYPES, + EDITOR_MODES, + KeyEvent +} from '@kepler.gl/constants'; +import {Layer} from '@kepler.gl/layers'; import {DEFAULT_RADIUS, getStyle as getFeatureStyle} from './feature-styles'; import {getStyle as getEditHandleStyle, getEditHandleShape} from './handle-style'; diff --git a/src/components/src/filters/polygon-filter.tsx b/src/components/src/filters/polygon-filter.tsx index 4e47fa32c7..e1448caa78 100644 --- a/src/components/src/filters/polygon-filter.tsx +++ b/src/components/src/filters/polygon-filter.tsx @@ -20,7 +20,8 @@ import React, {useMemo, useCallback} from 'react'; import ItemSelector from '../common/item-selector/item-selector'; -import {Layer, LAYER_TYPES} from '@kepler.gl/layers'; +import {Layer} from '@kepler.gl/layers'; +import {LAYER_TYPES} from '@kepler.gl/constants'; import {PolygonFilterProps} from './types'; import {StyledFilterPanel} from './components'; diff --git a/src/components/src/map-container.tsx b/src/components/src/map-container.tsx index e851f66200..74b420664c 100644 --- a/src/components/src/map-container.tsx +++ b/src/components/src/map-container.tsx @@ -50,16 +50,21 @@ import { transformRequest, observeDimensions, unobserveDimensions, - hasMobileWidth + hasMobileWidth, + getMapLayersFromSplitMaps, + onViewPortChange } from '@kepler.gl/utils'; import {breakPointValues} from '@kepler.gl/styles'; // default-settings -import {FILTER_TYPES, GEOCODER_LAYER_ID, THROTTLE_NOTIFICATION_TIME} from '@kepler.gl/constants'; +import { + FILTER_TYPES, + GEOCODER_LAYER_ID, + THROTTLE_NOTIFICATION_TIME +} from '@kepler.gl/constants'; import ErrorBoundary from './common/error-boundary'; import {LOCALE_CODES} from '@kepler.gl/localization'; -import {getMapLayersFromSplitMaps, onViewPortChange} from '@kepler.gl/utils'; import {MapView} from '@deck.gl/core'; import { MapStyle, diff --git a/src/components/src/map/map-legend.tsx b/src/components/src/map/map-legend.tsx index d7e33fdf8d..e7269655b8 100644 --- a/src/components/src/map/map-legend.tsx +++ b/src/components/src/map/map-legend.tsx @@ -24,7 +24,12 @@ import {rgb} from 'd3-color'; import ColorLegend from '../common/color-legend'; import {CHANNEL_SCALES, DIMENSIONS} from '@kepler.gl/constants'; import {FormattedMessage} from '@kepler.gl/localization'; -import {Layer, LayerBaseConfig, VisualChannel, VisualChannelDescription} from '@kepler.gl/layers'; +import { + Layer, + LayerBaseConfig, + VisualChannel, + VisualChannelDescription +} from '@kepler.gl/layers'; interface StyledMapControlLegendProps { width?: number; diff --git a/src/components/src/modal-container.tsx b/src/components/src/modal-container.tsx index 0a07b8803c..e46be586fd 100644 --- a/src/components/src/modal-container.tsx +++ b/src/components/src/modal-container.tsx @@ -24,7 +24,6 @@ import {createSelector} from 'reselect'; import get from 'lodash.get'; import document from 'global/document'; -import {EXPORT_DATA_TYPE_OPTIONS, EXPORT_MAP_FORMATS} from '@kepler.gl/constants'; import ModalDialogFactory from './modals/modal-dialog'; import {exportHtml, isValidMapInfo, exportMap, exportJson} from '@kepler.gl/utils'; import { @@ -52,6 +51,8 @@ import {media} from '@kepler.gl/styles'; // Template import { + EXPORT_DATA_TYPE_OPTIONS, + EXPORT_MAP_FORMATS, KeyEvent, ADD_DATA_ID, DATA_TABLE_ID, diff --git a/src/components/src/modals/export-map-modal/export-html-map.tsx b/src/components/src/modals/export-map-modal/export-html-map.tsx index c715cf6df6..4c04fc04ed 100644 --- a/src/components/src/modals/export-map-modal/export-html-map.tsx +++ b/src/components/src/modals/export-map-modal/export-html-map.tsx @@ -31,7 +31,11 @@ import {injectIntl} from 'react-intl'; import {FormattedMessage} from '@kepler.gl/localization'; import {IntlShape} from 'react-intl'; -import {setUserMapboxAccessToken, setExportHTMLMapMode, ActionHandler} from '@kepler.gl/actions'; +import { + setUserMapboxAccessToken, + setExportHTMLMapMode, + ActionHandler +} from '@kepler.gl/actions'; const ExportMapStyledExportSection = styled(StyledExportSection)` .disclaimer { diff --git a/src/components/src/modals/export-map-modal/export-map-modal.tsx b/src/components/src/modals/export-map-modal/export-map-modal.tsx index c3d10f19e3..b582f03219 100644 --- a/src/components/src/modals/export-map-modal/export-map-modal.tsx +++ b/src/components/src/modals/export-map-modal/export-map-modal.tsx @@ -27,7 +27,11 @@ import {StyledExportMapSection} from './components'; import ExportHtmlMapFactory from './export-html-map'; import ExportJsonMapFactory from './export-json-map'; import {FormattedMessage} from '@kepler.gl/localization'; -import {ActionHandler, setExportHTMLMapMode, setUserMapboxAccessToken} from '@kepler.gl/actions'; +import { + ActionHandler, + setExportHTMLMapMode, + setUserMapboxAccessToken +} from '@kepler.gl/actions'; interface ExportMapModalFactoryProps { options?: {format: string}; diff --git a/src/components/src/notification-panel/notification-item.tsx b/src/components/src/notification-panel/notification-item.tsx index b6ea2994dd..fa7e53a06d 100644 --- a/src/components/src/notification-panel/notification-item.tsx +++ b/src/components/src/notification-panel/notification-item.tsx @@ -22,7 +22,10 @@ import React, {Component} from 'react'; import styled from 'styled-components'; import {Delete, Info, Warning, Checkmark} from '../common/icons'; import ReactMarkdown from 'react-markdown'; -import {ActionHandler, removeNotification as removeNotificationActions} from '@kepler.gl/actions'; +import { + ActionHandler, + removeNotification as removeNotificationActions +} from '@kepler.gl/actions'; interface NotificationItemContentProps { type: string; diff --git a/src/components/src/side-panel/common/types.ts b/src/components/src/side-panel/common/types.ts index e41e8de5cc..b4ad640e09 100644 --- a/src/components/src/side-panel/common/types.ts +++ b/src/components/src/side-panel/common/types.ts @@ -1,7 +1,5 @@ import React, {MouseEvent} from 'react'; -import {openDeleteModal} from '@kepler.gl/actions'; -import {VisStateActions} from '@kepler.gl/actions'; -import {ActionHandler} from '@kepler.gl/actions'; +import {openDeleteModal, VisStateActions, ActionHandler} from '@kepler.gl/actions'; import {RGBColor} from '@kepler.gl/types'; import KeplerTable, {Datasets} from '@kepler.gl/table'; diff --git a/src/components/src/side-panel/interaction-panel/interaction-panel.tsx b/src/components/src/side-panel/interaction-panel/interaction-panel.tsx index 04b2c3a3d6..444d3c172a 100644 --- a/src/components/src/side-panel/interaction-panel/interaction-panel.tsx +++ b/src/components/src/side-panel/interaction-panel/interaction-panel.tsx @@ -25,7 +25,7 @@ import Switch from '../../common/switch'; import BrushConfigFactory from './brush-config'; import TooltipConfigFactory from './tooltip-config'; import {Datasets} from '@kepler.gl/table'; -import {InteractionConfig} from '@kepler.gl/types'; +import {InteractionConfig, ValueOf} from '@kepler.gl/types'; import { StyledPanelHeader, @@ -36,7 +36,6 @@ import { import {Messages, Crosshairs, CursorClick, Pin} from '../../common/icons'; import {FormattedMessage} from '@kepler.gl/localization'; -import {ValueOf} from '@kepler.gl/types'; interface InteractionPanelProps { datasets: Datasets; diff --git a/src/components/src/side-panel/interaction-panel/tooltip-config/tooltip-chicklet.tsx b/src/components/src/side-panel/interaction-panel/tooltip-config/tooltip-chicklet.tsx index cf657cf439..1cdb615ea1 100644 --- a/src/components/src/side-panel/interaction-panel/tooltip-config/tooltip-chicklet.tsx +++ b/src/components/src/side-panel/interaction-panel/tooltip-config/tooltip-chicklet.tsx @@ -25,7 +25,12 @@ import {Hash, Delete} from '../../../common/icons'; import DropdownList from '../../../common/item-selector/dropdown-list'; import {FormattedMessage} from '@kepler.gl/localization'; import onClickOutside from 'react-onclickoutside'; -import {FIELD_OPTS, TOOLTIP_FORMATS, TOOLTIP_FORMAT_TYPES, TOOLTIP_KEY} from '@kepler.gl/constants'; +import { + FIELD_OPTS, + TOOLTIP_FORMATS, + TOOLTIP_FORMAT_TYPES, + TOOLTIP_KEY +} from '@kepler.gl/constants'; import {getFormatter} from '@kepler.gl/utils'; import TippyTooltip from '../../../common/tippy-tooltip'; diff --git a/src/components/src/side-panel/layer-panel/layer-configurator.tsx b/src/components/src/side-panel/layer-panel/layer-configurator.tsx index 94f447759c..09388f9c79 100644 --- a/src/components/src/side-panel/layer-panel/layer-configurator.tsx +++ b/src/components/src/side-panel/layer-panel/layer-configurator.tsx @@ -40,14 +40,8 @@ import HowToButton from './how-to-button'; import {capitalizeFirstLetter} from '@kepler.gl/utils'; -import {CHANNEL_SCALE_SUPPORTED_FIELDS, ColorRange} from '@kepler.gl/constants'; -import { - Layer, - LayerBaseConfig, - LAYER_TYPES, - VisualChannel, - AggregationLayer -} from '@kepler.gl/layers'; +import {CHANNEL_SCALE_SUPPORTED_FIELDS, LAYER_TYPES, ColorRange} from '@kepler.gl/constants'; +import {Layer, LayerBaseConfig, VisualChannel, AggregationLayer} from '@kepler.gl/layers'; import {NestedPartial, RGBColor, LayerVisConfig, ColorUI, Field} from '@kepler.gl/types'; import {toggleModal, ActionHandler} from '@kepler.gl/actions'; diff --git a/src/components/src/side-panel/layer-panel/vis-config-slider.tsx b/src/components/src/side-panel/layer-panel/vis-config-slider.tsx index 716fc01f77..9de219b6e6 100644 --- a/src/components/src/side-panel/layer-panel/vis-config-slider.tsx +++ b/src/components/src/side-panel/layer-panel/vis-config-slider.tsx @@ -27,8 +27,7 @@ import {FormattedMessage} from '@kepler.gl/localization'; import {KeyEvent} from '@kepler.gl/constants'; import {Checkbox} from '../..'; import {Layer, LayerBaseConfig} from '@kepler.gl/layers'; -import {isInRange} from '@kepler.gl/table'; -import {clamp} from '@kepler.gl/utils'; +import {isInRange, clamp} from '@kepler.gl/utils'; type LazyInputProps = { value: string | [string, string]; diff --git a/src/constants/package.json b/src/constants/package.json index 6ba27af727..e461ee1cbf 100644 --- a/src/constants/package.json +++ b/src/constants/package.json @@ -30,13 +30,14 @@ "umd" ], "dependencies": { - "@babel/runtime": "^7.12.1", + "@kepler.gl/types": "2.5.5", + "@types/d3-scale": "^3.2.2", + "@types/keymirror": "^0.1.1", "colorbrewer": "^1.5.0", "d3-scale": "^3.2.3", "global": "^4.3.0", "keymirror": "^0.1.1", - "react-map-gl-draw": "0.14.8", - "@kepler.gl/types": "2.5.5" + "react-map-gl-draw": "0.14.8" }, "nyc": { "sourceMap": false, diff --git a/src/constants/src/layers.ts b/src/constants/src/layers.ts index d4754a5cf1..0478a7d088 100644 --- a/src/constants/src/layers.ts +++ b/src/constants/src/layers.ts @@ -475,3 +475,26 @@ export const LAYER_TEXT_CONFIGS: LayerTextConfig = { searchable: false } }; +export const LAYER_TYPES = keyMirror({ + point: null, + arc: null, + line: null, + grid: null, + hexagon: null, + geojson: null, + cluster: null, + icon: null, + heatmap: null, + hexagonId: null, + '3D': null, + trip: null, + s2: null +}); + +export const EDITOR_AVAILABLE_LAYERS: string[] = [ + LAYER_TYPES.point, + LAYER_TYPES.hexagon, + LAYER_TYPES.arc, + LAYER_TYPES.line, + LAYER_TYPES.hexagonId +]; diff --git a/src/deckgl-layers/package.json b/src/deckgl-layers/package.json index 31733c9fbb..ca82bae969 100644 --- a/src/deckgl-layers/package.json +++ b/src/deckgl-layers/package.json @@ -33,21 +33,25 @@ "@danmarshall/deckgl-typings": "4.9.22", "@deck.gl/aggregation-layers": "8.6.0", "@deck.gl/core": "^8.6.0", - "@deck.gl/extensions": "^8.6.0", "@deck.gl/geo-layers": "^8.6.0", "@deck.gl/layers": "^8.6.0", - "@deck.gl/mesh-layers": "^8.6.0", - "@deck.gl/react": "^8.6.0", + "@kepler.gl/constants": "2.5.5", + "@kepler.gl/types": "2.5.5", + "@kepler.gl/utils": "2.5.5", "@luma.gl/constants": "^8.5.10", "@luma.gl/core": "^8.5.10", "@mapbox/geo-viewport": "^0.4.1", "@mapbox/vector-tile": "^1.3.1", + "@types/d3-array": "^2.0.0", "@types/geojson": "^7946.0.7", + "@types/lodash.memoize": "^4.1.7", + "@types/supercluster": "^7.1.0", "d3-array": "^2.8.0", "global": "^4.3.0", - "keymirror": "^0.1.1", - "@kepler.gl/constants": "2.5.5", - "lodash.memoize": "^4.1.2" + "lodash.memoize": "^4.1.2", + "pbf": "^3.1.0", + "supercluster": "^7.1.0", + "viewport-mercator-project": "^6.0.0" }, "nyc": { "sourceMap": false, diff --git a/src/index.js b/src/index.js index ae3b36b7a8..7b2196022b 100644 --- a/src/index.js +++ b/src/index.js @@ -42,11 +42,8 @@ export * from '@kepler.gl/layers'; // Styles export * from '@kepler.gl/styles'; -// Middleware -export * from '@kepler.gl/middleware'; - // Utils export * from '@kepler.gl/utils'; // Default export -export {default} from './components'; +export {default} from '@kepler.gl/components'; diff --git a/src/layers/package.json b/src/layers/package.json index 4cdd01a9e5..e51840fc1c 100644 --- a/src/layers/package.json +++ b/src/layers/package.json @@ -30,27 +30,38 @@ "umd" ], "dependencies": { + "@danmarshall/deckgl-typings": "4.9.22", "@deck.gl/core": "^8.6.0", "@deck.gl/extensions": "^8.6.0", "@deck.gl/geo-layers": "^8.6.0", "@deck.gl/layers": "^8.6.0", "@deck.gl/mesh-layers": "^8.6.0", - "@kepler.gl/deckgl-layers": "^2.5.5", - "@kepler.gl/layers": "^2.5.5", - "@kepler.gl/constants": "^2.5.5", - "@kepler.gl/types": "^2.5.5", + "@kepler.gl/constants": "2.5.5", + "@kepler.gl/deckgl-layers": "2.5.5", + "@kepler.gl/localization": "2.5.5", + "@kepler.gl/table": "2.5.5", + "@kepler.gl/types": "2.5.5", + "@kepler.gl/utils": "2.5.5", "@loaders.gl/core": "^3.0.9", "@loaders.gl/gltf": "^3.0.9", + "@luma.gl/constants": "^8.5.10", "@mapbox/geojson-normalize": "0.0.1", "@turf/bbox": "^6.0.1", + "@turf/helpers": "^6.1.4", "@types/geojson": "^7946.0.7", + "@types/keymirror": "^0.1.1", + "@types/lodash.memoize": "^4.1.7", + "@types/lodash.uniq": "^4.5.7", + "@types/styled-components": "^5.1.25", + "d3-shape": "^1.2.0", "global": "^4.3.0", - "h3-js": "^3.1.0", "keymirror": "^0.1.1", "lodash.memoize": "^4.1.2", "lodash.uniq": "^4.0.1", "long": "^4.0.0", + "prop-types": "^15.6.0", "react": "^16.8.4", + "reselect": "^4.0.0", "s2-geometry": "^1.2.10", "styled-components": "^4.1.3", "type-analyzer": "0.3.0", diff --git a/src/layers/src/arc-layer/arc-layer.ts b/src/layers/src/arc-layer/arc-layer.ts index 21bb9645ba..e2af8b4def 100644 --- a/src/layers/src/arc-layer/arc-layer.ts +++ b/src/layers/src/arc-layer/arc-layer.ts @@ -28,7 +28,7 @@ import Layer, { import {BrushingExtension} from '@deck.gl/extensions'; import {ArcLayer as DeckArcLayer} from '@deck.gl/layers'; -import {hexToRgb} from '@kepler.gl/utils'; +import {hexToRgb, DataContainerInterface} from '@kepler.gl/utils'; import ArcLayerIcon from './arc-layer-icon'; import { DEFAULT_LAYER_COLOR, @@ -44,7 +44,7 @@ import { VisConfigNumber, VisConfigRange } from '@kepler.gl/types'; -import {KeplerTable, DataContainerInterface} from '@kepler.gl/table'; +import {KeplerTable} from '@kepler.gl/table'; export type ArcLayerVisConfigSettings = { opacity: VisConfigNumber; diff --git a/src/layers/src/base-layer.ts b/src/layers/src/base-layer.ts index 5bf52746fe..f41b604e47 100644 --- a/src/layers/src/base-layer.ts +++ b/src/layers/src/base-layer.ts @@ -49,7 +49,17 @@ import { PROJECTED_PIXEL_SIZE_MULTIPLIER } from '@kepler.gl/constants'; -import {generateHashId, getColorGroupByName, reverseColorRange, hexToRgb} from '@kepler.gl/utils'; +import { + generateHashId, + getColorGroupByName, + reverseColorRange, + hexToRgb, + getLatLngBounds, + isPlainObject, + notNullorUndefined, + DataContainerInterface, + getSampleContainerData +} from '@kepler.gl/utils'; import { RGBColor, @@ -64,9 +74,7 @@ import { MapState, Filter } from '@kepler.gl/types'; -import {KeplerTable, Datasets, GpuFilter, DataContainerInterface} from '@kepler.gl/table'; -import {getLatLngBounds, isPlainObject, notNullorUndefined} from '@kepler.gl/utils'; -import {getSampleContainerData} from '@kepler.gl/table'; +import {KeplerTable, Datasets, GpuFilter} from '@kepler.gl/table'; export type LayerColumn = {value: string | null; fieldIdx: number; optional?: boolean}; diff --git a/src/layers/src/geojson-layer/geojson-layer.ts b/src/layers/src/geojson-layer/geojson-layer.ts index 3cec155253..75b0bd351b 100644 --- a/src/layers/src/geojson-layer/geojson-layer.ts +++ b/src/layers/src/geojson-layer/geojson-layer.ts @@ -55,7 +55,8 @@ import { Merge, RGBColor } from '@kepler.gl/types'; -import {KeplerTable, DataContainerInterface} from '@kepler.gl/table'; +import {KeplerTable} from '@kepler.gl/table'; +import {DataContainerInterface} from '@kepler.gl/utils'; const SUPPORTED_ANALYZER_TYPES = { [DATA_TYPES.GEOMETRY]: true, diff --git a/src/layers/src/h3-hexagon-layer/h3-hexagon-layer.ts b/src/layers/src/h3-hexagon-layer/h3-hexagon-layer.ts index eb84b4c602..c4cc8aee0f 100644 --- a/src/layers/src/h3-hexagon-layer/h3-hexagon-layer.ts +++ b/src/layers/src/h3-hexagon-layer/h3-hexagon-layer.ts @@ -28,7 +28,16 @@ import Layer, { import {GeoJsonLayer} from '@deck.gl/layers'; import {H3HexagonLayer} from '@deck.gl/geo-layers'; import {EnhancedColumnLayer} from '@kepler.gl/deckgl-layers'; -import {getCentroid, idToPolygonGeo, h3IsValid, getHexFields, Centroid} from './h3-utils'; +import { + getCentroid, + idToPolygonGeo, + h3IsValid, + getHexFields, + Centroid, + findDefaultColorField, + DataContainerInterface, + createDataContainer +} from '@kepler.gl/utils'; import H3HexagonLayerIcon from './h3-hexagon-layer-icon'; import {CHANNEL_SCALES, HIGHLIGH_COLOR_3D, ColorRange} from '@kepler.gl/constants'; @@ -39,8 +48,7 @@ import { VisConfigRange, Merge } from '@kepler.gl/types'; -import {KeplerTable, DataContainerInterface, createDataContainer} from '@kepler.gl/table'; -import {findDefaultColorField} from '@kepler.gl/utils'; +import {KeplerTable} from '@kepler.gl/table'; export type HexagonIdLayerColumnsConfig = { hex_id: LayerColumn; diff --git a/src/layers/src/h3-hexagon-layer/index.ts b/src/layers/src/h3-hexagon-layer/index.ts index c3f5092d31..cfcc72e0f9 100644 --- a/src/layers/src/h3-hexagon-layer/index.ts +++ b/src/layers/src/h3-hexagon-layer/index.ts @@ -1,3 +1,2 @@ export {default as H3HexagonLayerIcon} from './h3-hexagon-layer-icon'; export * from './h3-hexagon-layer'; -export * from './h3-utils'; diff --git a/src/layers/src/heatmap-layer/heatmap-layer.ts b/src/layers/src/heatmap-layer/heatmap-layer.ts index 1b46b747f9..305dd1f7a8 100644 --- a/src/layers/src/heatmap-layer/heatmap-layer.ts +++ b/src/layers/src/heatmap-layer/heatmap-layer.ts @@ -21,13 +21,11 @@ import {createSelector} from 'reselect'; import memoize from 'lodash.memoize'; import {CHANNEL_SCALES, SCALE_FUNC, ALL_FIELD_TYPES, ColorRange} from '@kepler.gl/constants'; -import {hexToRgb} from '@kepler.gl/utils'; import MapboxGLLayer, {MapboxLayerGLConfig} from '../mapboxgl-layer'; import HeatmapLayerIcon from './heatmap-layer-icon'; import {LayerColumn, LayerWeightConfig, VisualChannels} from '../base-layer'; -import {VisConfigColorRange, VisConfigNumber} from '@kepler.gl/types'; -import {HexColor, Merge} from '@kepler.gl/types'; -import {DataContainerInterface} from '@kepler.gl/table'; +import {VisConfigColorRange, VisConfigNumber, HexColor, Merge} from '@kepler.gl/types'; +import {hexToRgb, DataContainerInterface} from '@kepler.gl/utils'; export type HeatmapLayerVisConfigSettings = { opacity: VisConfigNumber; diff --git a/src/layers/src/hexagon-layer/hexagon-utils.ts b/src/layers/src/hexagon-layer/hexagon-utils.ts index 09ba3a75da..bb67e124d5 100644 --- a/src/layers/src/hexagon-layer/hexagon-utils.ts +++ b/src/layers/src/hexagon-layer/hexagon-utils.ts @@ -20,7 +20,7 @@ import {WebMercatorViewport} from '@deck.gl/core'; import Console from 'global/console'; -import {Centroid} from '../h3-hexagon-layer/h3-utils'; +import {Centroid} from '@kepler.gl/utils'; export function hexagonToPolygonGeo(object, properties, radius, mapState) { const viewport = new WebMercatorViewport(mapState); diff --git a/src/layers/src/icon-layer/icon-layer.ts b/src/layers/src/icon-layer/icon-layer.ts index 01d70479aa..44abb476ab 100644 --- a/src/layers/src/icon-layer/icon-layer.ts +++ b/src/layers/src/icon-layer/icon-layer.ts @@ -29,7 +29,8 @@ import IconInfoModalFactory from './icon-info-modal'; import Layer, {LayerBaseConfig, LayerColumn} from '../base-layer'; import {assignPointPairToLayerColumn} from '../layer-utils'; import {getTextOffsetByRadius, formatTextLabelData} from '../layer-text-label'; -import {default as KeplerTable, DataContainerInterface} from '@kepler.gl/table'; +import {default as KeplerTable} from '@kepler.gl/table'; +import {DataContainerInterface} from '@kepler.gl/utils'; import { VisConfigBoolean, VisConfigColorRange, diff --git a/src/layers/src/index.ts b/src/layers/src/index.ts index d6bf2d7411..e46bd7c996 100644 --- a/src/layers/src/index.ts +++ b/src/layers/src/index.ts @@ -39,7 +39,6 @@ import {default as HeatmapLayer} from './heatmap-layer/heatmap-layer'; export {MAX_ZOOM_LEVEL} from './heatmap-layer/heatmap-layer'; import {default as H3Layer} from './h3-hexagon-layer/h3-hexagon-layer'; export {defaultElevation as h3DefaultElevation} from './h3-hexagon-layer/h3-hexagon-layer'; -export {getCentroid, h3IsValid, getHexFields} from './h3-hexagon-layer/h3-utils'; import {default as ScenegraphLayer} from './scenegraph-layer/scenegraph-layer'; import {default as TripLayer} from './trip-layer/trip-layer'; export {defaultLineWidth as tripDefaultLineWidth} from './trip-layer/trip-layer'; @@ -48,8 +47,7 @@ import {default as S2GeometryLayer} from './s2-geometry-layer/s2-geometry-layer' export {defaultElevation as s2DefaultElevation} from './s2-geometry-layer/s2-geometry-layer'; export {getS2Center} from './s2-geometry-layer/s2-utils'; export {default as AggregationLayer} from './aggregation-layer'; -import {LAYER_TYPES} from './types'; -export {LAYER_TYPES, EDITOR_AVAILABLE_LAYERS} from './types'; +import {LAYER_TYPES} from '@kepler.gl/constants'; // base layer // eslint-disable-next-line prettier/prettier export type { @@ -101,6 +99,5 @@ export const LayerClasses = { export type OVERLAY_TYPE = {[key: string]: string}; export * from './mapbox-utils'; -export * from './types'; export * from './h3-hexagon-layer'; export {default as Table} from './table'; diff --git a/src/layers/src/line-layer/line-layer.ts b/src/layers/src/line-layer/line-layer.ts index f44dac0613..abcb834500 100644 --- a/src/layers/src/line-layer/line-layer.ts +++ b/src/layers/src/line-layer/line-layer.ts @@ -24,7 +24,11 @@ import {EnhancedLineLayer} from '@kepler.gl/deckgl-layers'; import LineLayerIcon from './line-layer-icon'; import ArcLayer, {ArcLayerConfig} from '../arc-layer/arc-layer'; import {LayerColumn} from '../base-layer'; -import {LAYER_VIS_CONFIGS, ColorRange, PROJECTED_PIXEL_SIZE_MULTIPLIER} from '@kepler.gl/constants'; +import { + LAYER_VIS_CONFIGS, + ColorRange, + PROJECTED_PIXEL_SIZE_MULTIPLIER +} from '@kepler.gl/constants'; import { Merge, RGBColor, @@ -33,7 +37,8 @@ import { VisConfigNumber, VisConfigRange } from '@kepler.gl/types'; -import {default as KeplerTable, DataContainerInterface} from '@kepler.gl/table'; +import {default as KeplerTable} from '@kepler.gl/table'; +import {DataContainerInterface} from '@kepler.gl/utils'; export type LineLayerVisConfigSettings = { opacity: VisConfigNumber; diff --git a/src/layers/src/point-layer/point-layer.ts b/src/layers/src/point-layer/point-layer.ts index ca6b3c0a44..a4dc9ce8bd 100644 --- a/src/layers/src/point-layer/point-layer.ts +++ b/src/layers/src/point-layer/point-layer.ts @@ -28,9 +28,8 @@ import Layer, { LayerSizeConfig, LayerStrokeColorConfig } from '../base-layer'; -import {hexToRgb} from '@kepler.gl/utils'; +import {hexToRgb, findDefaultColorField} from '@kepler.gl/utils'; import {default as KeplerTable} from '@kepler.gl/table'; -import {findDefaultColorField} from '@kepler.gl/utils'; import PointLayerIcon from './point-layer-icon'; import { LAYER_VIS_CONFIGS, diff --git a/src/layers/src/s2-geometry-layer/s2-geometry-layer.ts b/src/layers/src/s2-geometry-layer/s2-geometry-layer.ts index 9057f26f15..0cc6fa7380 100644 --- a/src/layers/src/s2-geometry-layer/s2-geometry-layer.ts +++ b/src/layers/src/s2-geometry-layer/s2-geometry-layer.ts @@ -25,11 +25,7 @@ import { ColorRange, LAYER_VIS_CONFIGS } from '@kepler.gl/constants'; -import { - default as KeplerTable, - DataContainerInterface, - createDataContainer -} from '@kepler.gl/table'; +import {default as KeplerTable} from '@kepler.gl/table'; import Layer, { LayerBaseConfig, LayerColorConfig, @@ -49,6 +45,7 @@ import { } from '@kepler.gl/types'; import S2LayerIcon from './s2-layer-icon'; import {getS2Center, validS2Token} from './s2-utils'; +import {DataContainerInterface, createDataContainer} from '@kepler.gl/utils'; export type S2GeometryLayerVisConfigSettings = { opacity: VisConfigNumber; diff --git a/src/layers/src/scenegraph-layer/scenegraph-layer.ts b/src/layers/src/scenegraph-layer/scenegraph-layer.ts index a861bed947..ecedc7b68c 100644 --- a/src/layers/src/scenegraph-layer/scenegraph-layer.ts +++ b/src/layers/src/scenegraph-layer/scenegraph-layer.ts @@ -27,7 +27,8 @@ import ScenegraphLayerIcon from './scenegraph-layer-icon'; import ScenegraphInfoModalFactory from './scenegraph-info-modal'; import {LAYER_VIS_CONFIGS, ColorRange} from '@kepler.gl/constants'; import {Merge, VisConfigColorRange, VisConfigNumber} from '@kepler.gl/types'; -import {default as KeplerTable, DataContainerInterface} from '@kepler.gl/table'; +import {default as KeplerTable} from '@kepler.gl/table'; +import {DataContainerInterface} from '@kepler.gl/utils'; export type ScenegraphLayerVisConfigSettings = { opacity: VisConfigNumber; diff --git a/src/layers/src/trip-layer/trip-layer.ts b/src/layers/src/trip-layer/trip-layer.ts index 70defdb70e..e2f59937c1 100644 --- a/src/layers/src/trip-layer/trip-layer.ts +++ b/src/layers/src/trip-layer/trip-layer.ts @@ -36,7 +36,8 @@ import { import {isTripGeoJsonField, parseTripGeoJsonTimestamp} from './trip-utils'; import TripInfoModalFactory from './trip-info-modal'; import {Merge, VisConfigColorRange, VisConfigNumber, VisConfigRange} from '@kepler.gl/types'; -import {default as KeplerTable, DataContainerInterface} from '@kepler.gl/table'; +import {default as KeplerTable} from '@kepler.gl/table'; +import {DataContainerInterface} from '@kepler.gl/utils'; export type TripLayerVisConfigSettings = { opacity: VisConfigNumber; diff --git a/src/layers/src/trip-layer/trip-utils.ts b/src/layers/src/trip-layer/trip-utils.ts index 2fe7987176..784941f59f 100644 --- a/src/layers/src/trip-layer/trip-utils.ts +++ b/src/layers/src/trip-layer/trip-utils.ts @@ -23,8 +23,12 @@ import {Analyzer, DATA_TYPES} from 'type-analyzer'; import {Field} from '@kepler.gl/types'; import {parseGeoJsonRawFeature, getGeojsonFeatureTypes} from '../geojson-layer/geojson-utils'; -import {DataContainerInterface, getSampleData} from '@kepler.gl/table'; -import {notNullorUndefined, timeToUnixMilli} from '@kepler.gl/utils'; +import { + DataContainerInterface, + getSampleContainerData, + notNullorUndefined, + timeToUnixMilli +} from '@kepler.gl/utils'; import {Feature} from '@turf/helpers'; import {GeoJsonProperties, Geometry} from 'geojson'; @@ -80,7 +84,9 @@ export function isTripGeoJsonField(dataContainer: DataContainerInterface, field) const maxCount = 10000; const sampleRawFeatures = - dataContainer.numRows() > maxCount ? getSampleData(dataContainer, maxCount) : dataContainer; + dataContainer.numRows() > maxCount + ? getSampleContainerData(dataContainer, maxCount) + : dataContainer; const features: Feature[] = sampleRawFeatures .mapIndex(field.valueAccessor) diff --git a/src/layers/src/types.ts b/src/layers/src/types.ts deleted file mode 100644 index 860038769d..0000000000 --- a/src/layers/src/types.ts +++ /dev/null @@ -1,25 +0,0 @@ -import keyMirror from 'keymirror'; - -export const LAYER_TYPES = keyMirror({ - point: null, - arc: null, - line: null, - grid: null, - hexagon: null, - geojson: null, - cluster: null, - icon: null, - heatmap: null, - hexagonId: null, - '3D': null, - trip: null, - s2: null -}); - -export const EDITOR_AVAILABLE_LAYERS: string[] = [ - LAYER_TYPES.point, - LAYER_TYPES.hexagon, - LAYER_TYPES.arc, - LAYER_TYPES.line, - LAYER_TYPES.hexagonId -]; diff --git a/src/localization/package.json b/src/localization/package.json index 5ae684dd49..da01824e04 100644 --- a/src/localization/package.json +++ b/src/localization/package.json @@ -30,24 +30,9 @@ "umd" ], "dependencies": { - "@danmarshall/deckgl-typings": "4.9.22", - "@deck.gl/aggregation-layers": "8.6.0", - "@deck.gl/core": "^8.6.0", - "@deck.gl/extensions": "^8.6.0", - "@deck.gl/geo-layers": "^8.6.0", - "@deck.gl/layers": "^8.6.0", - "@deck.gl/mesh-layers": "^8.6.0", - "@deck.gl/react": "^8.6.0", - "@luma.gl/constants": "^8.5.10", - "@luma.gl/core": "^8.5.10", - "@mapbox/geo-viewport": "^0.4.1", - "@mapbox/vector-tile": "^1.3.1", - "@types/geojson": "^7946.0.7", - "d3-array": "^2.8.0", - "global": "^4.3.0", - "keymirror": "^0.1.1", - "@kepler.gl/constants": "2.5.5", - "lodash.memoize": "^4.1.2" + "react": "^16.8.4", + "react-intl": "^3.12.0", + "redux": "^4.0.5" }, "nyc": { "sourceMap": false, diff --git a/src/localization/src/locales.ts b/src/localization/src/locales.ts index 0103b777ce..7e97664bd1 100644 --- a/src/localization/src/locales.ts +++ b/src/localization/src/locales.ts @@ -37,7 +37,7 @@ export const LOCALES = { * @example * ```js * import {combineReducers} from 'redux'; - * import {LOCALE_CODES} from 'kepler.gl/localization/locales'; + * import {LOCALE_CODES} from 'kepler.gl/localization'; * * const customizedKeplerGlReducer = keplerGlReducer * .initialState({ diff --git a/src/localization/src/messages.ts b/src/localization/src/messages.ts index e86943379e..0562f3b463 100644 --- a/src/localization/src/messages.ts +++ b/src/localization/src/messages.ts @@ -55,13 +55,13 @@ export const messages: { }; } = {}; -messages['en'] = enFlat; -messages['fi'] = {...enFlat, ...flattenMessages(fi)}; -messages['pt'] = {...enFlat, ...flattenMessages(pt)}; -messages['es'] = {...enFlat, ...flattenMessages(es)}; -messages['ca'] = {...enFlat, ...flattenMessages(ca)}; -messages['cn'] = {...enFlat, ...flattenMessages(cn)}; -messages['ja'] = {...enFlat, ...flattenMessages(ja)}; -messages['ru'] = {...enFlat, ...flattenMessages(ru)}; +messages.en = enFlat; +messages.fi = {...enFlat, ...flattenMessages(fi)}; +messages.pt = {...enFlat, ...flattenMessages(pt)}; +messages.es = {...enFlat, ...flattenMessages(es)}; +messages.ca = {...enFlat, ...flattenMessages(ca)}; +messages.cn = {...enFlat, ...flattenMessages(cn)}; +messages.ja = {...enFlat, ...flattenMessages(ja)}; +messages.ru = {...enFlat, ...flattenMessages(ru)}; export default messages; diff --git a/src/middleware/babel.config.js b/src/middleware/babel.config.js deleted file mode 100644 index 7aec54a783..0000000000 --- a/src/middleware/babel.config.js +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2022 Uber Technologies, Inc. -// -// 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. - -const KeplerPackage = require('./package'); - -const PRESETS = ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript']; -const PLUGINS = [ - ['@babel/plugin-transform-typescript', {isTSX: true, allowDeclareFields: true}], - '@babel/plugin-transform-modules-commonjs', - '@babel/plugin-proposal-export-namespace-from', - '@babel/plugin-proposal-optional-chaining', - [ - '@babel/transform-runtime', - { - regenerator: true - } - ], - [ - 'search-and-replace', - { - rules: [ - { - search: '__PACKAGE_VERSION__', - replace: KeplerPackage.version - } - ] - } - ] -]; -const ENV = { - test: { - plugins: ['istanbul'] - }, - debug: { - sourceMaps: 'inline', - retainLines: true - } -}; - -module.exports = function babel(api) { - api.cache(true); - - return { - presets: PRESETS, - plugins: PLUGINS, - env: ENV - }; -}; diff --git a/src/middleware/package.json b/src/middleware/package.json deleted file mode 100644 index 70815ae759..0000000000 --- a/src/middleware/package.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "@kepler.gl/middleware", - "author": "Shan He ", - "version": "2.5.5", - "description": "kepler.gl middleware used by kepler.gl components, actions and reducers", - "license": "MIT", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "keywords": [ - "babel", - "es6", - "react", - "webgl", - "visualization", - "deck.gl" - ], - "repository": { - "type": "git", - "url": "https://github.com/keplergl/kepler.gl.git" - }, - "scripts": { - "build": "rm -fr dist && babel src --out-dir dist --source-maps inline --extensions '.ts,.tsx,.js,.jsx' --ignore '**/*.d.ts'", - "build:umd": "webpack --config ./webpack/umd.js --progress --env.prod", - "build:types": "tsc --project ./tsconfig.production.json", - "prepublish": "uber-licence && yarn build && yarn build:umd && yarn build:types", - "stab": "mkdir -p dist && touch dist/index.js" - }, - "files": [ - "dist", - "umd" - ], - "dependencies": { - "@babel/runtime": "^7.12.1", - "colorbrewer": "^1.5.0", - "d3-scale": "^3.2.3", - "global": "^4.3.0", - "keymirror": "^0.1.1", - "react-map-gl-draw": "0.14.8", - "@kepler.gl/types": "2.5.5" - }, - "exports": { - ".": "./dist/index.js", - "./*": "./dist/*" - }, - "typesVersions": { - "*": { - "*": ["dist/*"] - } - }, - "nyc": { - "sourceMap": false, - "instrument": false - }, - "engines": { - "node": ">=12.0.0" - }, - "maintainers": [ - "Shan He ", - "Giuseppe Macri " - ], - "volta": { - "node": "12.22.0", - "yarn": "1.22.17" - } -} diff --git a/src/middleware/tsconfig.production.json b/src/middleware/tsconfig.production.json deleted file mode 100644 index 6eb6672124..0000000000 --- a/src/middleware/tsconfig.production.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "compilerOptions": { - "target": "es2020", - "allowJs": false, - "checkJs": false, - "jsx": "react", - "module": "esnext", - "moduleResolution": "node", - "declaration": true, - "emitDeclarationOnly": true, - "noImplicitAny": false, - "noImplicitReturns": true, - "noImplicitThis": true, - "noUnusedLocals": true, - "outDir": "dist", - "sourceMap": true, - "strictNullChecks": true, - "suppressImplicitAnyIndexErrors": false, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "skipLibCheck": true, - "strict": true, - "resolveJsonModule": true, - "isolatedModules": true, - "baseUrl": "./src", - "paths": { - "*": ["*"] - } - }, - "include": ["src"], - "exclude": ["*/actions/**/*", "*/utils/**/*", "../components/**/*"] -} diff --git a/src/middleware/webpack/umd.js b/src/middleware/webpack/umd.js deleted file mode 100644 index 3eb025d5e4..0000000000 --- a/src/middleware/webpack/umd.js +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2022 Uber Technologies, Inc. -// -// 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. - -const resolve = require('path').resolve; -const join = require('path').join; - -// Import package.json to read version -const KeplerPackage = require('../package'); - -const SRC_DIR = resolve(__dirname, '../src'); -const OUTPUT_DIR = resolve(__dirname, '../umd'); - -const LIBRARY_BUNDLE_CONFIG = env => ({ - entry: { - KeplerGl: join(SRC_DIR, 'index.ts') - }, - - // Silence warnings about big bundles - stats: { - warnings: false - }, - - output: { - // Generate the bundle in dist folder - path: OUTPUT_DIR, - filename: 'keplergl.min.js', - globalObject: 'this', - library: '[name]', - libraryTarget: 'umd' - }, - - // let's put everything in - externals: { - react: { - root: 'React', - commonjs2: 'react', - commonjs: 'react', - amd: 'react', - umd: 'react' - }, - 'react-dom': { - root: 'ReactDOM', - commonjs2: 'react-dom', - commonjs: 'react-dom', - amd: 'react-dom', - umd: 'react-dom' - }, - redux: { - root: 'Redux', - commonjs2: 'redux', - commonjs: 'redux', - amd: 'redux', - umd: 'redux' - }, - 'react-redux': { - root: 'ReactRedux', - commonjs2: 'react-redux', - commonjs: 'react-redux', - amd: 'react-redux', - umd: 'react-redux' - }, - 'styled-components': { - commonjs: 'styled-components', - commonjs2: 'styled-components', - amd: 'styled-components', - root: 'styled' - } - }, - resolve: { - extensions: ['.tsx', '.ts', '.js'], - modules: ['node_modules', SRC_DIR] - }, - module: { - rules: [ - { - test: /\.(js|ts|tsx)$/, - loader: 'babel-loader', - include: [SRC_DIR], - options: { - plugins: [ - [ - 'search-and-replace', - { - rules: [ - { - search: '__PACKAGE_VERSION__', - replace: KeplerPackage.version - } - ] - } - ] - ] - } - } - ] - }, - - node: { - fs: 'empty' - } -}); - -module.exports = env => LIBRARY_BUNDLE_CONFIG(env); diff --git a/src/processors/package.json b/src/processors/package.json index 3e4b8f1ff6..be982e894d 100644 --- a/src/processors/package.json +++ b/src/processors/package.json @@ -30,11 +30,19 @@ "umd" ], "dependencies": { - "colorbrewer": "^1.5.0", - "d3-scale": "^3.2.3", - "global": "^4.3.0", - "keymirror": "^0.1.1", - "react-map-gl-draw": "0.14.8" + "@danmarshall/deckgl-typings": "4.9.22", + "@kepler.gl/constants": "2.5.5", + "@kepler.gl/schemas": "2.5.5", + "@kepler.gl/types": "2.5.5", + "@kepler.gl/utils": "2.5.5", + "@loaders.gl/core": "^3.0.9", + "@loaders.gl/csv": "^3.0.9", + "@loaders.gl/json": "^3.0.9", + "@loaders.gl/loader-utils": "^3.0.9", + "@mapbox/geojson-normalize": "0.0.1", + "@nebula.gl/edit-modes": "0.14.0", + "@turf/helpers": "^6.1.4", + "d3-dsv": "^2.0.0" }, "nyc": { "sourceMap": false, diff --git a/src/reducers/package.json b/src/reducers/package.json index 72de905753..77f77e05e6 100644 --- a/src/reducers/package.json +++ b/src/reducers/package.json @@ -29,6 +29,42 @@ "dist", "umd" ], + "dependencies": { + "@kepler.gl/actions": "2.5.5", + "@kepler.gl/cloud-providers": "2.5.5", + "@kepler.gl/constants": "2.5.5", + "@kepler.gl/deckgl-layers": "2.5.5", + "@kepler.gl/layers": "2.5.5", + "@kepler.gl/localization": "2.5.5", + "@kepler.gl/processors": "2.5.5", + "@kepler.gl/schemas": "2.5.5", + "@kepler.gl/table": "2.5.5", + "@kepler.gl/tasks": "2.5.5", + "@kepler.gl/types": "2.5.5", + "@kepler.gl/utils": "2.5.5", + "@loaders.gl/loader-utils": "^3.0.9", + "@types/lodash.clonedeep": "^4.5.7", + "@types/lodash.flattendeep": "^4.4.7", + "@types/lodash.get": "^4.4.6", + "@types/lodash.pick": "^4.4.6", + "@types/lodash.uniq": "^4.5.7", + "@types/lodash.xor": "^4.5.7", + "@types/redux-actions": "^2.6.2", + "copy-to-clipboard": "^3.3.1", + "d3-color": "^2.0.0", + "d3-dsv": "^2.0.0", + "global": "^4.3.0", + "lodash.clonedeep": "^4.0.1", + "lodash.flattendeep": "^4.2.0", + "lodash.get": "^4.4.2", + "lodash.pick": "^4.4.0", + "lodash.uniq": "^4.0.1", + "lodash.xor": "^4.5.0", + "react-palm": "^3.3.7", + "redux": "^4.0.5", + "redux-actions": "^2.2.1", + "reselect": "^4.0.0" + }, "nyc": { "sourceMap": false, "instrument": false diff --git a/src/reducers/src/export-utils.ts b/src/reducers/src/export-utils.ts index f6317c1e16..103840607e 100644 --- a/src/reducers/src/export-utils.ts +++ b/src/reducers/src/export-utils.ts @@ -23,15 +23,15 @@ import {csvFormatRows} from 'd3-dsv'; import {EXPORT_DATA_TYPE} from '@kepler.gl/constants'; import {Field} from '@kepler.gl/types'; +import KeplerTable, {Datasets} from '@kepler.gl/table'; import { createIndexedDataContainer, DataContainerInterface, - Datasets, - KeplerTable -} from '@kepler.gl/table'; -import {parseFieldValue} from '@kepler.gl/utils'; -import {downloadFile, DEFAULT_DATA_NAME} from '@kepler.gl/utils'; + parseFieldValue, + downloadFile, + DEFAULT_DATA_NAME +} from '@kepler.gl/utils'; interface StateType { visState: {datasets: Datasets}; diff --git a/src/reducers/src/index.ts b/src/reducers/src/index.ts index aebfc1d483..13bd051fc3 100644 --- a/src/reducers/src/index.ts +++ b/src/reducers/src/index.ts @@ -85,3 +85,5 @@ export * from './export-utils'; export * from './interaction-utils'; export * from './layer-utils'; export * as providerStateUpdaters from './provider-state-updaters'; + +export {enhanceReduxMiddleware} from './middleware'; diff --git a/src/reducers/src/interaction-utils.ts b/src/reducers/src/interaction-utils.ts index c260e1157d..c60d353f9a 100644 --- a/src/reducers/src/interaction-utils.ts +++ b/src/reducers/src/interaction-utils.ts @@ -27,9 +27,9 @@ import { COMPARE_TYPES } from '@kepler.gl/constants'; -import {DataRow} from '@kepler.gl/table'; import {Field, TooltipField, CompareType} from '@kepler.gl/types'; import { + DataRow, parseFieldValue, getFormatter, isNumber, diff --git a/src/reducers/src/layer-utils.ts b/src/reducers/src/layer-utils.ts index 3116d578f5..74ae58dccb 100644 --- a/src/reducers/src/layer-utils.ts +++ b/src/reducers/src/layer-utils.ts @@ -33,9 +33,9 @@ import { OVERLAY_TYPE_CONST } from '@kepler.gl/layers'; -import KeplerTable, {DataRow, Datasets} from '@kepler.gl/table'; +import KeplerTable, {Datasets} from '@kepler.gl/table'; import {VisState} from '@kepler.gl/schemas'; -import {isFunction, getMapLayersFromSplitMaps} from '@kepler.gl/utils'; +import {isFunction, getMapLayersFromSplitMaps, DataRow} from '@kepler.gl/utils'; import {ThreeDBuildingLayer} from '@kepler.gl/deckgl-layers'; export type LayersToRender = { diff --git a/src/reducers/src/map-style-updaters.ts b/src/reducers/src/map-style-updaters.ts index 47d2231866..da447c545c 100644 --- a/src/reducers/src/map-style-updaters.ts +++ b/src/reducers/src/map-style-updaters.ts @@ -41,7 +41,13 @@ import { import {LOAD_MAP_STYLE_TASK} from '@kepler.gl/tasks'; import {rgb} from 'd3-color'; -import {RGBColor, LayerGroup, MapStyles, InputStyle, VisibleLayerGroups} from '@kepler.gl/types'; +import { + RGBColor, + LayerGroup, + MapStyles, + InputStyle, + VisibleLayerGroups +} from '@kepler.gl/types'; import { ActionTypes, ReceiveMapConfigPayload, diff --git a/src/middleware/src/index.ts b/src/reducers/src/middleware.ts similarity index 100% rename from src/middleware/src/index.ts rename to src/reducers/src/middleware.ts diff --git a/src/reducers/src/ui-state-updaters.ts b/src/reducers/src/ui-state-updaters.ts index b2f1edc446..a2c7a57450 100644 --- a/src/reducers/src/ui-state-updaters.ts +++ b/src/reducers/src/ui-state-updaters.ts @@ -31,12 +31,20 @@ import { MAP_CONTROLS, ExportImage } from '@kepler.gl/constants'; -import {ActionTypes} from '@kepler.gl/actions'; import {LOCALE_CODES} from '@kepler.gl/localization'; -import {createNotification, errorNotification, calculateExportImageSize} from '@kepler.gl/utils'; +import { + createNotification, + errorNotification, + calculateExportImageSize +} from '@kepler.gl/utils'; import {payload_, apply_, compose_} from './composer-helpers'; -import {KeplerGlInitPayload, LoadFilesErrUpdaterAction} from '@kepler.gl/actions'; +import { + ActionTypes, + KeplerGlInitPayload, + LoadFilesErrUpdaterAction, + UIStateActions +} from '@kepler.gl/actions'; import { ExportData, ExportHtml, @@ -46,7 +54,6 @@ import { MapControls, UiState } from '@kepler.gl/types'; -import {UIStateActions} from '@kepler.gl/actions'; export const DEFAULT_ACTIVE_SIDE_PANEL = 'layer'; export const DEFAULT_MODAL = ADD_DATA_ID; diff --git a/src/reducers/src/vis-state-merger.ts b/src/reducers/src/vis-state-merger.ts index 49302bd69e..7a2ad57cb1 100644 --- a/src/reducers/src/vis-state-merger.ts +++ b/src/reducers/src/vis-state-merger.ts @@ -21,7 +21,13 @@ import uniq from 'lodash.uniq'; import pick from 'lodash.pick'; import flattenDeep from 'lodash.flattendeep'; -import {isObject, arrayInsert, getInitialMapLayersForSplitMap} from '@kepler.gl/utils'; +import { + isObject, + arrayInsert, + getInitialMapLayersForSplitMap, + applyFiltersToDatasets, + validateFiltersUpdateDatasets +} from '@kepler.gl/utils'; import {LayerColumns, LayerColumn, Layer} from '@kepler.gl/layers'; import {LAYER_BLENDINGS} from '@kepler.gl/constants'; @@ -30,18 +36,12 @@ import { Merger, VisState, VisStateMergers, - visStateSchema + visStateSchema, + ParsedConfig } from '@kepler.gl/schemas'; -import {ParsedConfig} from '@kepler.gl/schemas'; import {ParsedLayer, SavedInteractionConfig, TooltipInfo} from '@kepler.gl/types'; -import {KeplerTable, Datasets} from '@kepler.gl/table'; -import { - applyFiltersToDatasets, - validateFiltersUpdateDatasets, - assignGpuChannels, - resetFilterGpuMode -} from '@kepler.gl/table'; +import {KeplerTable, Datasets, assignGpuChannels, resetFilterGpuMode} from '@kepler.gl/table'; /** * Merge loaded filters with current state, if no fields or data are loaded diff --git a/src/reducers/src/vis-state-updaters.ts b/src/reducers/src/vis-state-updaters.ts index 0806c95e47..7959536933 100644 --- a/src/reducers/src/vis-state-updaters.ts +++ b/src/reducers/src/vis-state-updaters.ts @@ -51,7 +51,21 @@ import { computeSplitMapLayers, removeLayerFromSplitMaps, isRgbColor, - parseFieldValue + parseFieldValue, + applyFilterFieldName, + applyFiltersToDatasets, + featureToFilterValue, + filterDatasetCPU, + FILTER_UPDATER_PROPS, + generatePolygonFilter, + getDefaultFilter, + getFilterIdInFeature, + getTimeWidgetTitleFormatter, + isInRange, + LIMITED_FILTER_EFFECT_PROPS, + updateFilterDataId, + getFilterPlot, + getDefaultFilterPlotType } from '@kepler.gl/utils'; import { @@ -78,26 +92,15 @@ import KeplerGLSchema, {VisState} from '@kepler.gl/schemas'; import {Filter, InteractionConfig, AnimationConfig, Editor} from '@kepler.gl/types'; import {Loader} from '@loaders.gl/loader-utils'; -import {copyTableAndUpdate, Datasets, pinTableColumns, sortDatasetByColumn} from '@kepler.gl/table'; import {calculateLayerData, findDefaultLayer} from './layer-utils'; import { - applyFilterFieldName, - applyFiltersToDatasets, - featureToFilterValue, - filterDatasetCPU, - FILTER_UPDATER_PROPS, - generatePolygonFilter, - getDefaultFilter, - getFilterIdInFeature, - getTimeWidgetTitleFormatter, - isInRange, - LIMITED_FILTER_EFFECT_PROPS, - updateFilterDataId, + copyTableAndUpdate, + Datasets, + pinTableColumns, + sortDatasetByColumn, assignGpuChannel, setFilterGpuMode, - createNewDataEntry, - getFilterPlot, - getDefaultFilterPlotType + createNewDataEntry } from '@kepler.gl/table'; import {findFieldsToShow} from './interaction-utils'; diff --git a/src/schemas/package.json b/src/schemas/package.json index c4a9788f86..7ed2be1909 100644 --- a/src/schemas/package.json +++ b/src/schemas/package.json @@ -30,13 +30,19 @@ "umd" ], "dependencies": { - "@babel/runtime": "^7.12.1", - "colorbrewer": "^1.5.0", - "d3-scale": "^3.2.3", + "@kepler.gl/constants": "2.5.5", + "@kepler.gl/layers": "2.5.5", + "@kepler.gl/table": "2.5.5", + "@kepler.gl/types": "2.5.5", + "@kepler.gl/utils": "2.5.5", + "@loaders.gl/loader-utils": "^3.0.9", + "@types/keymirror": "^0.1.1", + "@types/lodash.clonedeep": "^4.5.7", + "@types/lodash.pick": "^4.4.6", "global": "^4.3.0", "keymirror": "^0.1.1", - "react-map-gl-draw": "0.14.8", - "@kepler.gl/types": "2.5.5" + "lodash.clonedeep": "^4.0.1", + "lodash.pick": "^4.4.0" }, "nyc": { "sourceMap": false, diff --git a/src/schemas/src/vis-state-schema.ts b/src/schemas/src/vis-state-schema.ts index 8519be80cf..c4a7354263 100644 --- a/src/schemas/src/vis-state-schema.ts +++ b/src/schemas/src/vis-state-schema.ts @@ -21,7 +21,7 @@ import pick from 'lodash.pick'; import {VERSIONS} from './versions'; import {LAYER_VIS_CONFIGS} from '@kepler.gl/constants'; -import {notNullorUndefined} from '@kepler.gl/utils'; +import {isFilterValidToSave, notNullorUndefined} from '@kepler.gl/utils'; import Schema from './schema'; import cloneDeep from 'lodash.clonedeep'; import { @@ -41,7 +41,7 @@ import { SavedVisState, SplitMap } from '@kepler.gl/types'; -import {isFilterValidToSave, Datasets} from '@kepler.gl/table'; +import {Datasets} from '@kepler.gl/table'; import {Layer, LayerClassesType} from '@kepler.gl/layers'; import {Loader} from '@loaders.gl/loader-utils'; import KeplerGLSchema from './schema-manager'; diff --git a/src/styles/package.json b/src/styles/package.json index 839cda44df..40768ca809 100644 --- a/src/styles/package.json +++ b/src/styles/package.json @@ -30,24 +30,9 @@ "umd" ], "dependencies": { - "@danmarshall/deckgl-typings": "4.9.22", - "@deck.gl/aggregation-layers": "8.6.0", - "@deck.gl/core": "^8.6.0", - "@deck.gl/extensions": "^8.6.0", - "@deck.gl/geo-layers": "^8.6.0", - "@deck.gl/layers": "^8.6.0", - "@deck.gl/mesh-layers": "^8.6.0", - "@deck.gl/react": "^8.6.0", - "@luma.gl/constants": "^8.5.10", - "@luma.gl/core": "^8.5.10", - "@mapbox/geo-viewport": "^0.4.1", - "@mapbox/vector-tile": "^1.3.1", - "@types/geojson": "^7946.0.7", - "d3-array": "^2.8.0", - "global": "^4.3.0", - "keymirror": "^0.1.1", "@kepler.gl/constants": "2.5.5", - "lodash.memoize": "^4.1.2" + "@types/styled-components": "^5.1.25", + "styled-components": "^4.1.3" }, "nyc": { "sourceMap": false, diff --git a/src/table/package.json b/src/table/package.json index a569fff2bf..7a7f2339a0 100644 --- a/src/table/package.json +++ b/src/table/package.json @@ -29,6 +29,18 @@ "dist", "umd" ], + "dependencies": { + "@kepler.gl/constants": "2.5.5", + "@kepler.gl/layers": "2.5.5", + "@kepler.gl/types": "2.5.5", + "@kepler.gl/utils": "2.5.5", + "@types/d3-array": "^2.0.0", + "@types/lodash.uniq": "^4.5.7", + "d3-array": "^2.8.0", + "global": "^4.3.0", + "lodash.uniq": "^4.0.1", + "moment": "^2.10.6" + }, "nyc": { "sourceMap": false, "instrument": false diff --git a/src/table/src/filter-utils.ts b/src/table/src/filter-utils.ts deleted file mode 100644 index d6dbdbe778..0000000000 --- a/src/table/src/filter-utils.ts +++ /dev/null @@ -1,1172 +0,0 @@ -// Copyright (c) 2022 Uber Technologies, Inc. -// -// 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. - -import {ascending, extent, histogram as d3Histogram, ticks} from 'd3-array'; -import keyMirror from 'keymirror'; -import Console from 'global/console'; -import get from 'lodash.get'; -import isEqual from 'lodash.isequal'; - -import booleanWithin from '@turf/boolean-within'; -import {point as turfPoint} from '@turf/helpers'; -import {Decimal} from 'decimal.js'; -import {ALL_FIELD_TYPES, FILTER_TYPES, ANIMATION_WINDOW, PLOT_TYPES} from '@kepler.gl/constants'; -import {Layer} from '@kepler.gl/layers'; -import {notNullorUndefined, unique, timeToUnixMilli} from '@kepler.gl/utils'; -import * as ScaleUtils from './data-scale-utils'; -import {generateHashId, set, toArray} from '@kepler.gl/utils'; -import {h3IsValid} from 'h3-js'; - -import {Millisecond, Entries, Field, ParsedFilter} from '@kepler.gl/types'; -import { - Filter, - FilterBase, - PolygonFilter, - FieldDomain, - TimeRangeFieldDomain, - HistogramBin, - Feature, - FeatureValue, - LineChart, - TimeRangeFilter, - RangeFieldDomain -} from '@kepler.gl/types'; - -import {LAYER_TYPES, getCentroid} from '@kepler.gl/layers'; -import KeplerTable, {Datasets, FilterDatasetOpt, FilterRecord} from './kepler-table'; -import {DataContainerInterface} from './data-container-interface'; -import {isValidTimeDomain, durationYear, durationDay} from '@kepler.gl/utils'; - -export type FilterResult = { - filteredIndexForDomain?: number[]; - filteredIndex?: number[]; -}; - -export type FilterChanged = { - // eslint-disable-next-line no-unused-vars - [key in keyof FilterRecord]: { - [key: string]: 'added' | 'deleted' | 'name_changed' | 'value_changed' | 'dataId_changed'; - } | null; -}; - -export type dataValueAccessor = (data: {index: number}) => number | null; - -export const TimestampStepMap = [ - {max: 1, step: 0.05}, - {max: 10, step: 0.1}, - {max: 100, step: 1}, - {max: 500, step: 5}, - {max: 1000, step: 10}, - {max: 5000, step: 50}, - {max: Number.POSITIVE_INFINITY, step: 1000} -]; - -export const histogramBins = 30; -export const enlargedHistogramBins = 100; - -export const FILTER_UPDATER_PROPS = keyMirror({ - dataId: null, - name: null, - layerId: null -}); - -export const LIMITED_FILTER_EFFECT_PROPS = keyMirror({ - [FILTER_UPDATER_PROPS.name]: null -}); -/** - * Max number of filter value buffers that deck.gl provides - */ - -const SupportedPlotType = { - [FILTER_TYPES.timeRange]: { - default: 'histogram', - [ALL_FIELD_TYPES.integer]: 'lineChart', - [ALL_FIELD_TYPES.real]: 'lineChart' - }, - [FILTER_TYPES.range]: { - default: 'histogram', - [ALL_FIELD_TYPES.integer]: 'lineChart', - [ALL_FIELD_TYPES.real]: 'lineChart' - } -}; - -export const FILTER_COMPONENTS = { - [FILTER_TYPES.select]: 'SingleSelectFilter', - [FILTER_TYPES.multiSelect]: 'MultiSelectFilter', - [FILTER_TYPES.timeRange]: 'TimeRangeFilter', - [FILTER_TYPES.range]: 'RangeFilter', - [FILTER_TYPES.polygon]: 'PolygonFilter' -}; - -export const DEFAULT_FILTER_STRUCTURE = { - dataId: [], // [string] - freeze: false, - id: null, - - // time range filter specific - fixedDomain: false, - enlarged: false, - isAnimating: false, - animationWindow: ANIMATION_WINDOW.free, - speed: 1, - - // field specific - name: [], // string - type: null, - fieldIdx: [], // [integer] - domain: null, - value: null, - - // plot - plotType: PLOT_TYPES.histogram, - yAxis: null, - interval: null, - - // mode - gpu: false -}; - -export const FILTER_ID_LENGTH = 4; - -export const LAYER_FILTERS = [FILTER_TYPES.polygon]; - -/** - * Generates a filter with a dataset id as dataId - */ -export function getDefaultFilter(dataId: string | null | string[]): FilterBase { - return { - ...DEFAULT_FILTER_STRUCTURE, - // store it as dataId and it could be one or many - dataId: toArray(dataId), - id: generateHashId(FILTER_ID_LENGTH) - }; -} - -/** - * Check if a filter is valid based on the given dataId - * @param filter to validate - * @param datasetId id to validate filter against - * @return true if a filter is valid, false otherwise - */ -export function shouldApplyFilter(filter: Filter, datasetId: string): boolean { - const dataIds = toArray(filter.dataId); - return dataIds.includes(datasetId) && filter.value !== null; -} - -/** - * Validates and modifies polygon filter structure - * @param dataset - * @param filter - * @param layers - * @return - {filter, dataset} - */ -export function validatePolygonFilter( - dataset: KeplerTable, - filter: PolygonFilter, - layers: Layer[] -): {filter: PolygonFilter | null; dataset: KeplerTable} { - const failed = {dataset, filter: null}; - const {value, layerId, type, dataId} = filter; - - if (!layerId || !isValidFilterValue(type, value)) { - return failed; - } - - const isValidDataset = dataId.includes(dataset.id); - - if (!isValidDataset) { - return failed; - } - - const layer = layers.find(l => layerId.includes(l.id)); - - if (!layer) { - return failed; - } - - return { - filter: { - ...filter, - freeze: true, - fieldIdx: [] - }, - dataset - }; -} - -/** - * Custom filter validators - */ -const filterValidators = { - [FILTER_TYPES.polygon]: validatePolygonFilter -}; - -/** - * Default validate filter function - * @param dataset - * @param filter - * @return - {filter, dataset} - */ -export function validateFilter( - dataset: KeplerTable, - filter: ParsedFilter -): {filter: Filter | null; dataset: KeplerTable} { - // match filter.dataId - const failed = {dataset, filter: null}; - const filterDataId = toArray(filter.dataId); - - const filterDatasetIndex = filterDataId.indexOf(dataset.id); - if (filterDatasetIndex < 0 || !toArray(filter.name)[filterDatasetIndex]) { - // the current filter is not mapped against the current dataset - return failed; - } - - const initializeFilter: Filter = { - // @ts-expect-error - ...getDefaultFilter(filter.dataId), - ...filter, - dataId: filterDataId, - name: toArray(filter.name) - }; - - const fieldName = initializeFilter.name[filterDatasetIndex]; - const {filter: updatedFilter, dataset: updatedDataset} = applyFilterFieldName( - initializeFilter, - dataset, - fieldName, - filterDatasetIndex, - {mergeDomain: true} - ); - - if (!updatedFilter) { - return failed; - } - - updatedFilter.value = adjustValueToFilterDomain(filter.value, updatedFilter); - updatedFilter.enlarged = - typeof filter.enlarged === 'boolean' ? filter.enlarged : updatedFilter.enlarged; - - if (updatedFilter.value === null) { - // cannot adjust saved value to filter - return failed; - } - - return { - filter: validateFilterYAxis(updatedFilter, updatedDataset), - dataset: updatedDataset - }; -} - -/** - * Validate saved filter config with new data, - * calculate domain and fieldIdx based new fields and data - * - * @param dataset - * @param filter - filter to be validate - * @param layers - layers - * @return validated filter - */ -export function validateFilterWithData( - dataset: KeplerTable, - filter: ParsedFilter, - layers: Layer[] -): {filter: Filter; dataset: KeplerTable} { - return filter.type && filterValidators.hasOwnProperty(filter.type) - ? filterValidators[filter.type](dataset, filter, layers) - : validateFilter(dataset, filter); -} - -/** - * Validate YAxis - * @param filter - * @param dataset - * @return {*} - */ -function validateFilterYAxis(filter, dataset) { - // TODO: validate yAxis against other datasets - - const {fields} = dataset; - const {yAxis} = filter; - // TODO: validate yAxis against other datasets - if (yAxis) { - const matchedAxis = fields.find(({name, type}) => name === yAxis.name && type === yAxis.type); - - filter = matchedAxis - ? { - ...filter, - yAxis: matchedAxis, - ...getFilterPlot({...filter, yAxis: matchedAxis}, dataset) - } - : filter; - } - - return filter; -} - -/** - * Get default filter prop based on field type - * - * @param field - * @param fieldDomain - * @returns default filter - */ -export function getFilterProps( - field: Field, - fieldDomain: FieldDomain -): Partial & {fieldType: string} { - const filterProps = { - ...fieldDomain, - fieldType: field.type - }; - - switch (field.type) { - case ALL_FIELD_TYPES.real: - case ALL_FIELD_TYPES.integer: - return { - ...filterProps, - value: fieldDomain.domain, - type: FILTER_TYPES.range, - // @ts-expect-error - typeOptions: [FILTER_TYPES.range], - gpu: true - }; - - case ALL_FIELD_TYPES.boolean: - // @ts-expect-error - return { - ...filterProps, - type: FILTER_TYPES.select, - value: true, - gpu: false - }; - - case ALL_FIELD_TYPES.string: - case ALL_FIELD_TYPES.date: - // @ts-expect-error - return { - ...filterProps, - type: FILTER_TYPES.multiSelect, - value: [], - gpu: false - }; - - case ALL_FIELD_TYPES.timestamp: - // @ts-expect-error - return { - ...filterProps, - type: FILTER_TYPES.timeRange, - enlarged: true, - fixedDomain: true, - value: filterProps.domain, - gpu: true - }; - - default: - // @ts-expect-error - return {}; - } -} - -export const getPolygonFilterFunctor = (layer, filter, dataContainer) => { - const getPosition = layer.getPositionAccessor(dataContainer); - - switch (layer.type) { - case LAYER_TYPES.point: - case LAYER_TYPES.icon: - return data => { - const pos = getPosition(data); - return pos.every(Number.isFinite) && isInPolygon(pos, filter.value); - }; - case LAYER_TYPES.arc: - case LAYER_TYPES.line: - return data => { - const pos = getPosition(data); - return ( - pos.every(Number.isFinite) && - [ - [pos[0], pos[1]], - [pos[3], pos[4]] - ].every(point => isInPolygon(point, filter.value)) - ); - }; - case LAYER_TYPES.hexagonId: - if (layer.dataToFeature && layer.dataToFeature.centroids) { - return data => { - // null or getCentroid({id}) - const centroid = layer.dataToFeature.centroids[data.index]; - return centroid && isInPolygon(centroid, filter.value); - }; - } - return data => { - const id = getPosition(data); - if (!h3IsValid(id)) { - return false; - } - const pos = getCentroid({id}); - return pos.every(Number.isFinite) && isInPolygon(pos, filter.value); - }; - default: - return () => true; - } -}; - -/** - * @param param An object that represents a row record. - * @param param.index Index of the row in data container. - * @returns Returns true to keep the element, or false otherwise. - */ -type filterFunction = (data: {index: number}) => boolean; -/** - * @param field dataset Field - * @param dataId Dataset id - * @param filter Filter object - * @param layers list of layers to filter upon - * @param dataContainer Data container - * @return filterFunction - */ -/* eslint-disable complexity */ -export function getFilterFunction( - field: Field | null, - dataId: string, - filter: Filter, - layers: Layer[], - dataContainer: DataContainerInterface -): filterFunction { - // field could be null in polygon filter - const valueAccessor = field ? field.valueAccessor : data => null; - const defaultFunc = d => true; - - switch (filter.type) { - case FILTER_TYPES.range: - return data => isInRange(valueAccessor(data), filter.value); - case FILTER_TYPES.multiSelect: - return data => filter.value.includes(valueAccessor(data)); - case FILTER_TYPES.select: - return data => valueAccessor(data) === filter.value; - case FILTER_TYPES.timeRange: - if (!field) { - return defaultFunc; - } - const mappedValue = get(field, ['filterProps', 'mappedValue']); - const accessor = Array.isArray(mappedValue) - ? data => mappedValue[data.index] - : data => timeToUnixMilli(valueAccessor(data), field.format); - return data => isInRange(accessor(data), filter.value); - case FILTER_TYPES.polygon: - if (!layers || !layers.length || !filter.layerId) { - return defaultFunc; - } - const layerFilterFunctions = filter.layerId - .map(id => layers.find(l => l.id === id)) - .filter(l => l && l.config.dataId === dataId) - .map(layer => getPolygonFilterFunctor(layer, filter, dataContainer)); - - return data => layerFilterFunctions.every(filterFunc => filterFunc(data)); - default: - return defaultFunc; - } -} - -export function updateFilterDataId(dataId: string): FilterBase { - return getDefaultFilter(dataId); -} - -export function filterDataByFilterTypes( - { - dynamicDomainFilters, - cpuFilters, - filterFuncs - }: { - dynamicDomainFilters: Filter[] | null; - cpuFilters: Filter[] | null; - filterFuncs: { - [key: string]: filterFunction; - }; - }, - dataContainer: DataContainerInterface -): FilterResult { - const filteredIndexForDomain: number[] = []; - const filteredIndex: number[] = []; - - const filterContext = {index: -1, dataContainer}; - const filterFuncCaller = (filter: Filter) => filterFuncs[filter.id](filterContext); - - const numRows = dataContainer.numRows(); - for (let i = 0; i < numRows; ++i) { - filterContext.index = i; - - const matchForDomain = dynamicDomainFilters && dynamicDomainFilters.every(filterFuncCaller); - if (matchForDomain) { - filteredIndexForDomain.push(filterContext.index); - } - - const matchForRender = cpuFilters && cpuFilters.every(filterFuncCaller); - if (matchForRender) { - filteredIndex.push(filterContext.index); - } - } - - return { - ...(dynamicDomainFilters ? {filteredIndexForDomain} : {}), - ...(cpuFilters ? {filteredIndex} : {}) - }; -} - -/** - * Get a record of filters based on domain type and gpu / cpu - */ -export function getFilterRecord( - dataId: string, - filters: Filter[], - opt: FilterDatasetOpt = {} -): FilterRecord { - const filterRecord: FilterRecord = { - dynamicDomain: [], - fixedDomain: [], - cpu: [], - gpu: [] - }; - - filters.forEach(f => { - if (isValidFilterValue(f.type, f.value) && toArray(f.dataId).includes(dataId)) { - (f.fixedDomain || opt.ignoreDomain - ? filterRecord.fixedDomain - : filterRecord.dynamicDomain - ).push(f); - - (f.gpu && !opt.cpuOnly ? filterRecord.gpu : filterRecord.cpu).push(f); - } - }); - - return filterRecord; -} - -/** - * Compare filter records to get what has changed - */ -export function diffFilters( - filterRecord: FilterRecord, - oldFilterRecord: FilterRecord | {} = {} -): FilterChanged { - let filterChanged: Partial = {}; - - (Object.entries(filterRecord) as Entries).forEach(([record, items]) => { - items.forEach(filter => { - const oldFilter: Filter = (oldFilterRecord[record] || []).find( - (f: Filter) => f.id === filter.id - ); - - if (!oldFilter) { - // added - filterChanged = set([record, filter.id], 'added', filterChanged); - } else { - // check what has changed - ['name', 'value', 'dataId'].forEach(prop => { - if (filter[prop] !== oldFilter[prop]) { - filterChanged = set([record, filter.id], `${prop}_changed`, filterChanged); - } - }); - } - }); - - (oldFilterRecord[record] || []).forEach((oldFilter: Filter) => { - // deleted - if (!items.find(f => f.id === oldFilter.id)) { - filterChanged = set([record, oldFilter.id], 'deleted', filterChanged); - } - }); - }); - - return {...{dynamicDomain: null, fixedDomain: null, cpu: null, gpu: null}, ...filterChanged}; -} -/** - * Call by parsing filters from URL - * Check if value of filter within filter domain, if not adjust it to match - * filter domain - * - * @returns value - adjusted value to match filter or null to remove filter - */ -// eslint-disable-next-line complexity -export function adjustValueToFilterDomain(value: Filter['value'], {domain, type}) { - if (!type) { - return false; - } - // if the current filter is a polygon it will not have any domain - // all other filter types require domain - if (type !== FILTER_TYPES.polygon && !domain) { - return false; - } - - switch (type) { - case FILTER_TYPES.range: - case FILTER_TYPES.timeRange: - if (!Array.isArray(value) || value.length !== 2) { - return domain.map(d => d); - } - - return value.map((d, i) => (notNullorUndefined(d) && isInRange(d, domain) ? d : domain[i])); - - case FILTER_TYPES.multiSelect: - if (!Array.isArray(value)) { - return []; - } - const filteredValue = value.filter(d => domain.includes(d)); - return filteredValue.length ? filteredValue : []; - - case FILTER_TYPES.select: - return domain.includes(value) ? value : true; - case FILTER_TYPES.polygon: - return value; - - default: - return null; - } -} -/* eslint-enable complexity */ - -/** - * Calculate numeric domain and suitable step - */ -export function getNumericFieldDomain( - dataContainer: DataContainerInterface, - valueAccessor: dataValueAccessor -): RangeFieldDomain { - let domain: [number, number] = [0, 1]; - let step = 0.1; - - const mappedValue = dataContainer.mapIndex(valueAccessor); - - if (dataContainer.numRows() > 1) { - domain = ScaleUtils.getLinearDomain(mappedValue); - const diff = domain[1] - domain[0]; - - // in case equal domain, [96, 96], which will break quantize scale - if (!diff) { - domain[1] = domain[0] + 1; - } - - step = getNumericStepSize(diff) || step; - domain[0] = formatNumberByStep(domain[0], step, 'floor'); - domain[1] = formatNumberByStep(domain[1], step, 'ceil'); - } - - const {histogram, enlargedHistogram} = getHistogram(domain, mappedValue); - - return {domain, step, histogram, enlargedHistogram}; -} - -/** - * Calculate step size for range and timerange filter - */ -export function getNumericStepSize(diff: number): number { - diff = Math.abs(diff); - - if (diff > 100) { - return 1; - } else if (diff > 3) { - return 0.01; - } else if (diff > 1) { - return 0.001; - } - // Try to get at least 1000 steps - and keep the step size below that of - // the (diff > 1) case. - const x = diff / 1000; - // Find the exponent and truncate to 10 to the power of that exponent - - const exponentialForm = x.toExponential(); - const exponent = parseFloat(exponentialForm.split('e')[1]); - - // Getting ready for node 12 - // this is why we need decimal.js - // Math.pow(10, -5) = 0.000009999999999999999 - // the above result shows in browser and node 10 - // node 12 behaves correctly - return new Decimal(10).pow(exponent).toNumber(); -} - -/** - * Calculate timestamp domain and suitable step - */ -export function getTimestampFieldDomain( - dataContainer: DataContainerInterface, - valueAccessor: dataValueAccessor -): TimeRangeFieldDomain { - // to avoid converting string format time to epoch - // every time we compare we store a value mapped to int in filter domain - - const mappedValue = dataContainer.mapIndex(valueAccessor); - const domain = ScaleUtils.getLinearDomain(mappedValue); - const defaultTimeFormat = getTimeWidgetTitleFormatter(domain); - - let step = 0.01; - - const diff = domain[1] - domain[0]; - const entry = TimestampStepMap.find(f => f.max >= diff); - if (entry) { - step = entry.step; - } - - const {histogram, enlargedHistogram} = getHistogram(domain, mappedValue); - - return { - domain, - step, - mappedValue, - histogram, - enlargedHistogram, - defaultTimeFormat - }; -} - -export function histogramConstruct( - domain: [number, number], - mappedValue: (Millisecond | number)[], - bins: number -): HistogramBin[] { - return d3Histogram() - .thresholds(ticks(domain[0], domain[1], bins)) - .domain(domain)(mappedValue) - .map(bin => ({ - count: bin.length, - bin, - x0: bin.x0, - x1: bin.x1 - })); -} -/** - * Calculate histogram from domain and array of values - */ -export function getHistogram( - domain: [number, number], - mappedValue: (Millisecond | number)[] -): {histogram: HistogramBin[]; enlargedHistogram: HistogramBin[]} { - const histogram = histogramConstruct(domain, mappedValue, histogramBins); - const enlargedHistogram = histogramConstruct(domain, mappedValue, enlargedHistogramBins); - - return {histogram, enlargedHistogram}; -} - -/** - * round number based on step - * - * @param {Number} val - * @param {Number} step - * @param {string} bound - * @returns {Number} rounded number - */ -export function formatNumberByStep(val: number, step: number, bound: 'floor' | 'ceil'): number { - if (bound === 'floor') { - return Math.floor(val * (1 / step)) / (1 / step); - } - - return Math.ceil(val * (1 / step)) / (1 / step); -} - -export function isInRange(val: any, domain: number[]): boolean { - if (!Array.isArray(domain)) { - return false; - } - - return val >= domain[0] && val <= domain[1]; -} - -/** - * Determines whether a point is within the provided polygon - * - * @param point as input search [lat, lng] - * @param polygon Points must be within these (Multi)Polygon(s) - * @return {boolean} - */ -export function isInPolygon(point: number[], polygon: any): boolean { - return booleanWithin(turfPoint(point), polygon); -} -export function getTimeWidgetTitleFormatter(domain: [number, number]): string | null { - if (!isValidTimeDomain(domain)) { - return null; - } - - const diff = domain[1] - domain[0]; - - // Local aware formats - // https://momentjs.com/docs/#/parsing/string-format - return diff > durationYear ? 'L' : diff > durationDay ? 'L LT' : 'L LTS'; -} - -/** - * Sanity check on filters to prepare for save - * @type {typeof import('./filter-utils').isFilterValidToSave} - */ -export function isFilterValidToSave(filter: any): boolean { - return ( - filter?.type && - Array.isArray(filter?.name) && - (filter?.name.length || filter?.layerId.length) && - isValidFilterValue(filter?.type, filter?.value) - ); -} - -/** - * Sanity check on filters to prepare for save - * @type {typeof import('./filter-utils').isValidFilterValue} - */ -/* eslint-disable complexity */ -export function isValidFilterValue(type: string | null, value: any): boolean { - if (!type) { - return false; - } - switch (type) { - case FILTER_TYPES.select: - return value === true || value === false; - - case FILTER_TYPES.range: - case FILTER_TYPES.timeRange: - return Array.isArray(value) && value.every(v => v !== null && !isNaN(v)); - - case FILTER_TYPES.multiSelect: - return Array.isArray(value) && Boolean(value.length); - - case FILTER_TYPES.input: - return Boolean(value.length); - - case FILTER_TYPES.polygon: - const coordinates = get(value, ['geometry', 'coordinates']); - return Boolean(value && value.id && coordinates); - - default: - return true; - } -} - -export function getFilterPlot( - filter: Filter, - dataset: KeplerTable -): {lineChart: LineChart; yAxs: Field} | {} { - if (filter.plotType === PLOT_TYPES.histogram || !filter.yAxis) { - // histogram should be calculated when create filter - return {}; - } - - const {mappedValue = []} = filter; - const {yAxis} = filter; - const fieldIdx = dataset.getColumnFieldIdx(yAxis.name); - if (fieldIdx < 0) { - Console.warn(`yAxis ${yAxis.name} does not exist in dataset`); - return {lineChart: {}, yAxis}; - } - - // return lineChart - const series = dataset.dataContainer - .map( - (row, rowIndex) => ({ - x: mappedValue[rowIndex], - y: row.valueAt(fieldIdx) - }), - true - ) - .filter(({x, y}) => Number.isFinite(x) && Number.isFinite(y)) - .sort((a, b) => ascending(a.x, b.x)); - - const yDomain = extent(series, d => d.y); - const xDomain = [series[0].x, series[series.length - 1].x]; - - return {lineChart: {series, yDomain, xDomain}, yAxis}; -} - -export function getDefaultFilterPlotType(filter: Filter): string | null { - const filterPlotTypes: typeof SupportedPlotType[keyof typeof SupportedPlotType] | null = - filter.type && SupportedPlotType[filter.type]; - if (!filterPlotTypes) { - return null; - } - - if (!filter.yAxis) { - return filterPlotTypes.default; - } - - return filterPlotTypes[filter.yAxis.type] || null; -} - -/** - * - * @param datasetIds list of dataset ids to be filtered - * @param datasets all datasets - * @param filters all filters to be applied to datasets - * @return datasets - new updated datasets - */ -export function applyFiltersToDatasets( - datasetIds: string[], - datasets: Datasets, - filters: Filter[], - layers?: Layer[] -): Datasets { - const dataIds = toArray(datasetIds); - return dataIds.reduce((acc, dataId) => { - const layersToFilter = (layers || []).filter(l => l.config.dataId === dataId); - const appliedFilters = filters.filter(d => shouldApplyFilter(d, dataId)); - const table = datasets[dataId]; - - return { - ...acc, - [dataId]: table.filterTable(appliedFilters, layersToFilter, {}) - }; - }, datasets); -} - -/** - * Applies a new field name value to fielter and update both filter and dataset - * @param filter - to be applied the new field name on - * @param dataset - dataset the field belongs to - * @param fieldName - field.name - * @param filterDatasetIndex - field.name - * @param option - * @return - {filter, datasets} - */ -export function applyFilterFieldName( - filter: Filter, - dataset: KeplerTable, - fieldName: string, - filterDatasetIndex = 0, - option?: {mergeDomain: boolean} -): { - filter: Filter | null; - dataset: KeplerTable; -} { - // using filterDatasetIndex we can filter only the specified dataset - const mergeDomain = option && option.hasOwnProperty('mergeDomain') ? option.mergeDomain : false; - - const fieldIndex = dataset.getColumnFieldIdx(fieldName); - // if no field with same name is found, move to the next datasets - if (fieldIndex === -1) { - // throw new Error(`fieldIndex not found. Dataset must contain a property with name: ${fieldName}`); - return {filter: null, dataset}; - } - - // TODO: validate field type - const filterProps = dataset.getColumnFilterProps(fieldName); - - const newFilter = { - ...(mergeDomain ? mergeFilterDomainStep(filter, filterProps) : {...filter, ...filterProps}), - name: Object.assign([...toArray(filter.name)], {[filterDatasetIndex]: fieldName}), - fieldIdx: Object.assign([...toArray(filter.fieldIdx)], { - [filterDatasetIndex]: fieldIndex - }), - // TODO, since we allow to add multiple fields to a filter we can no longer freeze the filter - freeze: true - }; - - return { - filter: newFilter, - dataset - }; -} - -/** - * Merge one filter with other filter prop domain - */ -/* eslint-disable complexity */ -export function mergeFilterDomainStep( - filter: Filter, - filterProps?: Partial -): (Filter & {step?: number}) | null { - if (!filter) { - return null; - } - - if (!filterProps) { - return filter; - } - - if ((filter.fieldType && filter.fieldType !== filterProps.fieldType) || !filterProps.domain) { - return filter; - } - - const combinedDomain = !filter.domain - ? filterProps.domain - : [...(filter.domain || []), ...(filterProps.domain || [])].sort((a, b) => a - b); - - const newFilter = { - ...filter, - ...filterProps, - domain: [combinedDomain[0], combinedDomain[combinedDomain.length - 1]] - }; - - switch (filterProps.fieldType) { - case ALL_FIELD_TYPES.string: - case ALL_FIELD_TYPES.date: - return { - ...newFilter, - domain: unique(combinedDomain).sort() - }; - - case ALL_FIELD_TYPES.timestamp: - const step = - (filter as TimeRangeFilter).step < (filterProps as TimeRangeFieldDomain).step - ? (filter as TimeRangeFilter).step - : (filterProps as TimeRangeFieldDomain).step; - - return { - ...newFilter, - step - }; - case ALL_FIELD_TYPES.real: - case ALL_FIELD_TYPES.integer: - default: - return newFilter; - } -} -/* eslint-enable complexity */ - -/** - * Generates polygon filter - */ -export const featureToFilterValue = ( - feature: Feature, - filterId: string, - properties?: {} -): FeatureValue => ({ - ...feature, - id: feature.id, - properties: { - ...feature.properties, - ...properties, - filterId - } -}); - -export const getFilterIdInFeature = (f: FeatureValue): string => get(f, ['properties', 'filterId']); - -/** - * Generates polygon filter - */ -export function generatePolygonFilter(layers: Layer[], feature: Feature): PolygonFilter { - const dataId = layers.map(l => l.config.dataId).filter(notNullorUndefined); - const layerId = layers.map(l => l.id); - const name = layers.map(l => l.config.label); - const filter = getDefaultFilter(dataId); - return { - ...filter, - fixedDomain: true, - type: FILTER_TYPES.polygon, - name, - layerId, - value: featureToFilterValue(feature, filter.id, {isVisible: true}) - }; -} - -/** - * Run filter entirely on CPU - */ -interface StateType { - layers: Layer[]; - filters: Filter[]; - datasets: Datasets; -} - -export function filterDatasetCPU(state: T, dataId: string): T { - const datasetFilters = state.filters.filter(f => f.dataId.includes(dataId)); - const dataset = state.datasets[dataId]; - - if (!dataset) { - return state; - } - - const cpuFilteredDataset = dataset.filterTableCPU(datasetFilters, state.layers); - - return set(['datasets', dataId], cpuFilteredDataset, state); -} - -/** - * Validate parsed filters with datasets and add filterProps to field - */ -export function validateFiltersUpdateDatasets( - state: S, - filtersToValidate: ParsedFilter[] = [] -): { - validated: Filter[]; - failed: Filter[]; - updatedDatasets: S['datasets']; -} { - // TODO Better Typings here - const validated: any[] = []; - const failed: any[] = []; - const {datasets} = state; - let updatedDatasets = datasets; - - // merge filters - filtersToValidate.forEach(filter => { - // we can only look for datasets define in the filter dataId - const datasetIds = toArray(filter.dataId); - - // we can merge a filter only if all datasets in filter.dataId are loaded - if (datasetIds.every(d => datasets[d])) { - // all datasetIds in filter must be present the state datasets - const {filter: validatedFilter, applyToDatasets, augmentedDatasets} = datasetIds.reduce( - (acc, datasetId) => { - const dataset = updatedDatasets[datasetId]; - const layers = state.layers.filter(l => l.config.dataId === dataset.id); - const {filter: updatedFilter, dataset: updatedDataset} = validateFilterWithData( - acc.augmentedDatasets[datasetId] || dataset, - filter, - layers - ); - - if (updatedFilter) { - return { - ...acc, - // merge filter props - filter: acc.filter - ? { - ...acc.filter, - ...mergeFilterDomainStep(acc, updatedFilter) - } - : updatedFilter, - - applyToDatasets: [...acc.applyToDatasets, datasetId], - - augmentedDatasets: { - ...acc.augmentedDatasets, - [datasetId]: updatedDataset - } - }; - } - - return acc; - }, - { - filter: null, - applyToDatasets: [], - augmentedDatasets: {} - } - ); - - if (validatedFilter && isEqual(datasetIds, applyToDatasets)) { - validated.push(validatedFilter); - updatedDatasets = { - ...updatedDatasets, - ...augmentedDatasets - }; - } - } else { - failed.push(filter); - } - }); - - return {validated, failed, updatedDatasets}; -} diff --git a/src/table/src/gpu-filter-utils.ts b/src/table/src/gpu-filter-utils.ts index ab8e33704b..41f30bfdb8 100644 --- a/src/table/src/gpu-filter-utils.ts +++ b/src/table/src/gpu-filter-utils.ts @@ -22,8 +22,7 @@ import moment from 'moment'; import {MAX_GPU_FILTERS, FILTER_TYPES} from '@kepler.gl/constants'; import {Field, Filter} from '@kepler.gl/types'; -import {set, toArray, notNullorUndefined} from '@kepler.gl/utils'; -import {DataContainerInterface} from './data-container-interface'; +import {set, toArray, notNullorUndefined, DataContainerInterface} from '@kepler.gl/utils'; import {GpuFilter} from './kepler-table'; /** diff --git a/src/table/src/index.ts b/src/table/src/index.ts index 6870c9a04e..c050629706 100644 --- a/src/table/src/index.ts +++ b/src/table/src/index.ts @@ -29,12 +29,6 @@ export { maybeToDate } from './kepler-table'; /* eslint-disable prettier/prettier */ - export type {GpuFilter, Datasets, FilterRecord, FilterDatasetOpt} from './kepler-table'; - export {createDataContainer, createIndexedDataContainer, getSampleData as getSampleContainerData} from './data-container-utils'; - export type {DataContainerInterface} from './data-container-interface'; - export * from './data-container-utils'; - export * from './data-row'; + export type {GpuFilter, Datasets} from './kepler-table'; export * from './gpu-filter-utils'; export * from './dataset-utils'; - export * from './filter-utils'; - export * from './data-scale-utils'; diff --git a/src/table/src/kepler-table.ts b/src/table/src/kepler-table.ts index 6156324832..45c2a8b44d 100644 --- a/src/table/src/kepler-table.ts +++ b/src/table/src/kepler-table.ts @@ -21,7 +21,6 @@ import {console as Console} from 'global/console'; import {ascending, descending} from 'd3-array'; -// import {validateInputData} from 'processors/data-processor'; import { TRIP_POINT_FIELDS, SORT_ORDER, @@ -29,15 +28,25 @@ import { ALTITUDE_FIELDS, SCALE_TYPES } from '@kepler.gl/constants'; -import {RGBColor, Field, FieldPair, FieldDomain, Filter, ProtoDataset} from '@kepler.gl/types'; +import { + RGBColor, + Field, + FieldPair, + FieldDomain, + Filter, + ProtoDataset, + FilterRecord, + FilterDatasetOpt +} from '@kepler.gl/types'; -import {generateHashId, getSortingFunction, timeToUnixMilli} from '@kepler.gl/utils'; import {getGpuFilterProps, getDatasetFieldIndexForFilter} from './gpu-filter-utils'; -import {createDataContainer} from './data-container-utils'; - import {Layer} from '@kepler.gl/layers'; import { + generateHashId, + getSortingFunction, + timeToUnixMilli, + createDataContainer, diffFilters, filterDataByFilterTypes, FilterResult, @@ -45,15 +54,13 @@ import { getFilterProps, getFilterRecord, getNumericFieldDomain, - getTimestampFieldDomain -} from './filter-utils'; -import { + getTimestampFieldDomain, getLinearDomain, getLogDomain, getOrdinalDomain, - getQuantileDomain -} from './data-scale-utils'; -import {DataContainerInterface} from './data-container-interface'; + getQuantileDomain, + DataContainerInterface +} from '@kepler.gl/utils'; export type GpuFilter = { filterRange: number[][]; @@ -66,20 +73,6 @@ export type GpuFilter = { ) => (d: any) => number; }; -export type FilterRecord = { - dynamicDomain: Filter[]; - fixedDomain: Filter[]; - cpu: Filter[]; - gpu: Filter[]; -}; - -export type FilterDatasetOpt = { - // only allow cpu filtering - cpuOnly?: boolean; - // ignore filter for domain calculation - ignoreDomain?: boolean; -}; - // Unique identifier of each field const FID_KEY = 'name'; diff --git a/src/tasks/package.json b/src/tasks/package.json index e97be47517..49965d3c2d 100644 --- a/src/tasks/package.json +++ b/src/tasks/package.json @@ -29,6 +29,11 @@ "dist", "umd" ], + "dependencies": { + "@kepler.gl/processors": "2.5.5", + "d3-request": "^1.0.6", + "react-palm": "^3.3.7" + }, "nyc": { "sourceMap": false, "instrument": false diff --git a/src/types/reducers.d.ts b/src/types/reducers.d.ts index 091f0d8468..68e32c65ef 100644 --- a/src/types/reducers.d.ts +++ b/src/types/reducers.d.ts @@ -395,3 +395,17 @@ export type InputStyle = { icon: string | null; custom: boolean; }; + +export type FilterRecord = { + dynamicDomain: Filter[]; + fixedDomain: Filter[]; + cpu: Filter[]; + gpu: Filter[]; +}; + +export type FilterDatasetOpt = { + // only allow cpu filtering + cpuOnly?: boolean; + // ignore filter for domain calculation + ignoreDomain?: boolean; +}; diff --git a/src/utils/package.json b/src/utils/package.json index 61b62ff4f5..fbc66225fc 100644 --- a/src/utils/package.json +++ b/src/utils/package.json @@ -30,33 +30,37 @@ "umd" ], "dependencies": { - "@deck.gl/geo-layers": "^8.6.0", - "@deck.gl/core": "^8.6.0", - "@deck.gl/extensions": "^8.6.0", - "@deck.gl/layers": "^8.6.0", - "@deck.gl/mesh-layers": "^8.6.0", - "@kepler.gl/deckgl-layers": "^2.5.5", - "@kepler.gl/layers": "^2.5.5", - "@kepler.gl/constants": "^2.5.5", - "@kepler.gl/types": "^2.5.5", - "@loaders.gl/core": "^3.0.9", - "@loaders.gl/gltf": "^3.0.9", - "@mapbox/geojson-normalize": "0.0.1", - "@turf/bbox": "^6.0.1", - "@types/geojson": "^7946.0.7", + "@kepler.gl/constants": "2.5.5", + "@kepler.gl/types": "2.5.5", + "@luma.gl/constants": "^8.5.10", + "@luma.gl/core": "^8.5.10", + "@mapbox/geo-viewport": "^0.4.1", + "@turf/boolean-within": "^6.0.1", + "@turf/helpers": "^6.1.4", + "@types/d3-array": "^2.0.0", + "@types/keymirror": "^0.1.1", + "@types/lodash.clonedeep": "^4.5.7", + "@types/lodash.get": "^4.4.6", + "@types/lodash.isequal": "^4.5.5", + "@types/lodash.memoize": "^4.1.7", + "@types/lodash.throttle": "^4.1.7", + "d3-array": "^2.8.0", + "d3-format": "^2.0.0", + "decimal.js": "^10.2.0", "global": "^4.3.0", "h3-js": "^3.1.0", "keymirror": "^0.1.1", + "lodash.clonedeep": "^4.0.1", + "lodash.get": "^4.4.2", + "lodash.isequal": "^4.5.0", "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.0.1", - "long": "^4.0.0", + "lodash.throttle": "^4.1.1", + "mini-svg-data-uri": "^1.0.3", + "moment-timezone": "^0.5.32", "react": "^16.8.4", - "s2-geometry": "^1.2.10", - "styled-components": "^4.1.3", - "type-analyzer": "0.3.0", - "viewport-mercator-project": "^6.0.0", - "wellknown": "^0.5.0" - }, + "resize-observer-polyfill": "^1.5.1", + "type-analyzer": "0.3.0" +}, "nyc": { "sourceMap": false, "instrument": false diff --git a/src/table/src/data-container-interface.ts b/src/utils/src/data-container-interface.ts similarity index 100% rename from src/table/src/data-container-interface.ts rename to src/utils/src/data-container-interface.ts diff --git a/src/table/src/data-container-utils.ts b/src/utils/src/data-container-utils.ts similarity index 100% rename from src/table/src/data-container-utils.ts rename to src/utils/src/data-container-utils.ts diff --git a/src/table/src/data-row.ts b/src/utils/src/data-row.ts similarity index 100% rename from src/table/src/data-row.ts rename to src/utils/src/data-row.ts diff --git a/src/table/src/data-scale-utils.ts b/src/utils/src/data-scale-utils.ts similarity index 97% rename from src/table/src/data-scale-utils.ts rename to src/utils/src/data-scale-utils.ts index c0d2ca1fb3..5c5bf3cbf3 100644 --- a/src/table/src/data-scale-utils.ts +++ b/src/utils/src/data-scale-utils.ts @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import {notNullorUndefined, unique} from '@kepler.gl/utils'; +import {notNullorUndefined, unique} from './data-utils'; import {extent} from 'd3-array'; import {DataContainerInterface} from './data-container-interface'; diff --git a/src/utils/src/filter-utils.ts b/src/utils/src/filter-utils.ts index 0696195d0a..ff41ef4e2a 100644 --- a/src/utils/src/filter-utils.ts +++ b/src/utils/src/filter-utils.ts @@ -1,6 +1,66 @@ -import {FILTER_TYPES} from '@kepler.gl/constants'; +// Copyright (c) 2022 Uber Technologies, Inc. +// +// 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. + +import {ascending, extent, histogram as d3Histogram, ticks} from 'd3-array'; +import keyMirror from 'keymirror'; +import Console from 'global/console'; import get from 'lodash.get'; -import {TimeRangeFilter} from '@kepler.gl/types'; +import isEqual from 'lodash.isequal'; + +import booleanWithin from '@turf/boolean-within'; +import {point as turfPoint} from '@turf/helpers'; +import {Decimal} from 'decimal.js'; +import { + ALL_FIELD_TYPES, + FILTER_TYPES, + ANIMATION_WINDOW, + PLOT_TYPES, + LAYER_TYPES +} from '@kepler.gl/constants'; +import * as ScaleUtils from './data-scale-utils'; +import {h3IsValid} from 'h3-js'; + +import { + Millisecond, + Entries, + Field, + ParsedFilter, + Filter, + FilterBase, + PolygonFilter, + FieldDomain, + TimeRangeFieldDomain, + HistogramBin, + Feature, + FeatureValue, + LineChart, + TimeRangeFilter, + RangeFieldDomain, + FilterDatasetOpt, + FilterRecord +} from '@kepler.gl/types'; + +import {DataContainerInterface} from './data-container-interface'; +import {generateHashId, set, toArray} from './utils'; +import {notNullorUndefined, timeToUnixMilli, unique} from './data-utils'; +import {getCentroid} from './h3-utils'; export const durationSecond = 1000; export const durationMinute = durationSecond * 60; @@ -9,10 +69,787 @@ export const durationDay = durationHour * 24; export const durationWeek = durationDay * 7; export const durationYear = durationDay * 365; +export type FilterResult = { + filteredIndexForDomain?: number[]; + filteredIndex?: number[]; +}; + +export type FilterChanged = { + // eslint-disable-next-line no-unused-vars + [key in keyof FilterRecord]: { + [key: string]: 'added' | 'deleted' | 'name_changed' | 'value_changed' | 'dataId_changed'; + } | null; +}; + +export type dataValueAccessor = (data: {index: number}) => number | null; + +export const TimestampStepMap = [ + {max: 1, step: 0.05}, + {max: 10, step: 0.1}, + {max: 100, step: 1}, + {max: 500, step: 5}, + {max: 1000, step: 10}, + {max: 5000, step: 50}, + {max: Number.POSITIVE_INFINITY, step: 1000} +]; + +export const histogramBins = 30; +export const enlargedHistogramBins = 100; + +export const FILTER_UPDATER_PROPS = keyMirror({ + dataId: null, + name: null, + layerId: null +}); + +export const LIMITED_FILTER_EFFECT_PROPS = keyMirror({ + [FILTER_UPDATER_PROPS.name]: null +}); +/** + * Max number of filter value buffers that deck.gl provides + */ + +const SupportedPlotType = { + [FILTER_TYPES.timeRange]: { + default: 'histogram', + [ALL_FIELD_TYPES.integer]: 'lineChart', + [ALL_FIELD_TYPES.real]: 'lineChart' + }, + [FILTER_TYPES.range]: { + default: 'histogram', + [ALL_FIELD_TYPES.integer]: 'lineChart', + [ALL_FIELD_TYPES.real]: 'lineChart' + } +}; + +export const FILTER_COMPONENTS = { + [FILTER_TYPES.select]: 'SingleSelectFilter', + [FILTER_TYPES.multiSelect]: 'MultiSelectFilter', + [FILTER_TYPES.timeRange]: 'TimeRangeFilter', + [FILTER_TYPES.range]: 'RangeFilter', + [FILTER_TYPES.polygon]: 'PolygonFilter' +}; + +export const DEFAULT_FILTER_STRUCTURE = { + dataId: [], // [string] + freeze: false, + id: null, + + // time range filter specific + fixedDomain: false, + enlarged: false, + isAnimating: false, + animationWindow: ANIMATION_WINDOW.free, + speed: 1, + + // field specific + name: [], // string + type: null, + fieldIdx: [], // [integer] + domain: null, + value: null, + + // plot + plotType: PLOT_TYPES.histogram, + yAxis: null, + interval: null, + + // mode + gpu: false +}; + +export const FILTER_ID_LENGTH = 4; + +export const LAYER_FILTERS = [FILTER_TYPES.polygon]; + +/** + * Generates a filter with a dataset id as dataId + */ +export function getDefaultFilter(dataId: string | null | string[]): FilterBase { + return { + ...DEFAULT_FILTER_STRUCTURE, + // store it as dataId and it could be one or many + dataId: toArray(dataId), + id: generateHashId(FILTER_ID_LENGTH) + }; +} + +/** + * Check if a filter is valid based on the given dataId + * @param filter to validate + * @param datasetId id to validate filter against + * @return true if a filter is valid, false otherwise + */ +export function shouldApplyFilter(filter: Filter, datasetId: string): boolean { + const dataIds = toArray(filter.dataId); + return dataIds.includes(datasetId) && filter.value !== null; +} + +interface KeplerTableModel { + id: string; + getColumnFieldIdx(columnName: string): number; + filterTable(filters: Filter[], layers: L[], opt?: FilterDatasetOpt): K; + getColumnFilterProps(columnName: string): Field['filterProps'] | null | undefined; + dataContainer: DataContainerInterface; + filterTableCPU(filters: Filter[], layers: L[]): K; +} + +/** + * Validates and modifies polygon filter structure + * @param dataset + * @param filter + * @param layers + * @return - {filter, dataset} + */ +export function validatePolygonFilter, L extends {id: string}>( + dataset: K, + filter: PolygonFilter, + layers: L[] +): {filter: PolygonFilter | null; dataset: K} { + const failed = {dataset, filter: null}; + const {value, layerId, type, dataId} = filter; + + if (!layerId || !isValidFilterValue(type, value)) { + return failed; + } + + const isValidDataset = dataId.includes(dataset.id); + + if (!isValidDataset) { + return failed; + } + + const layer = layers.find(l => layerId.includes(l.id)); + + if (!layer) { + return failed; + } + + return { + filter: { + ...filter, + freeze: true, + fieldIdx: [] + }, + dataset + }; +} + +/** + * Custom filter validators + */ +const filterValidators = { + [FILTER_TYPES.polygon]: validatePolygonFilter +}; + +/** + * Default validate filter function + * @param dataset + * @param filter + * @return - {filter, dataset} + */ +export function validateFilter, L>( + dataset: K, + filter: ParsedFilter +): {filter: Filter | null; dataset: K} { + // match filter.dataId + const failed = {dataset, filter: null}; + const filterDataId = toArray(filter.dataId); + + const filterDatasetIndex = filterDataId.indexOf(dataset.id); + if (filterDatasetIndex < 0 || !toArray(filter.name)[filterDatasetIndex]) { + // the current filter is not mapped against the current dataset + return failed; + } + + const initializeFilter: Filter = { + // @ts-expect-error + ...getDefaultFilter(filter.dataId), + ...filter, + dataId: filterDataId, + name: toArray(filter.name) + }; + + const fieldName = initializeFilter.name[filterDatasetIndex]; + const {filter: updatedFilter, dataset: updatedDataset} = applyFilterFieldName( + initializeFilter, + dataset, + fieldName, + filterDatasetIndex, + {mergeDomain: true} + ); + + if (!updatedFilter) { + return failed; + } + + updatedFilter.value = adjustValueToFilterDomain(filter.value, updatedFilter); + updatedFilter.enlarged = + typeof filter.enlarged === 'boolean' ? filter.enlarged : updatedFilter.enlarged; + + if (updatedFilter.value === null) { + // cannot adjust saved value to filter + return failed; + } + + return { + filter: validateFilterYAxis(updatedFilter, updatedDataset), + dataset: updatedDataset + }; +} + +/** + * Validate saved filter config with new data, + * calculate domain and fieldIdx based new fields and data + * + * @param dataset + * @param filter - filter to be validate + * @param layers - layers + * @return validated filter + */ +export function validateFilterWithData, L>( + dataset: K, + filter: ParsedFilter, + layers: L[] +): {filter: Filter; dataset: K} { + return filter.type && filterValidators.hasOwnProperty(filter.type) + ? filterValidators[filter.type](dataset, filter, layers) + : validateFilter(dataset, filter); +} + +/** + * Validate YAxis + * @param filter + * @param dataset + * @return {*} + */ +function validateFilterYAxis(filter, dataset) { + // TODO: validate yAxis against other datasets + + const {fields} = dataset; + const {yAxis} = filter; + // TODO: validate yAxis against other datasets + if (yAxis) { + const matchedAxis = fields.find(({name, type}) => name === yAxis.name && type === yAxis.type); + + filter = matchedAxis + ? { + ...filter, + yAxis: matchedAxis, + ...getFilterPlot({...filter, yAxis: matchedAxis}, dataset) + } + : filter; + } + + return filter; +} + +/** + * Get default filter prop based on field type + * + * @param field + * @param fieldDomain + * @returns default filter + */ +export function getFilterProps( + field: Field, + fieldDomain: FieldDomain +): Partial & {fieldType: string} { + const filterProps = { + ...fieldDomain, + fieldType: field.type + }; + + switch (field.type) { + case ALL_FIELD_TYPES.real: + case ALL_FIELD_TYPES.integer: + return { + ...filterProps, + value: fieldDomain.domain, + type: FILTER_TYPES.range, + // @ts-expect-error + typeOptions: [FILTER_TYPES.range], + gpu: true + }; + + case ALL_FIELD_TYPES.boolean: + // @ts-expect-error + return { + ...filterProps, + type: FILTER_TYPES.select, + value: true, + gpu: false + }; + + case ALL_FIELD_TYPES.string: + case ALL_FIELD_TYPES.date: + // @ts-expect-error + return { + ...filterProps, + type: FILTER_TYPES.multiSelect, + value: [], + gpu: false + }; + + case ALL_FIELD_TYPES.timestamp: + // @ts-expect-error + return { + ...filterProps, + type: FILTER_TYPES.timeRange, + enlarged: true, + fixedDomain: true, + value: filterProps.domain, + gpu: true + }; + + default: + // @ts-expect-error + return {}; + } +} + +export const getPolygonFilterFunctor = (layer, filter, dataContainer) => { + const getPosition = layer.getPositionAccessor(dataContainer); + + switch (layer.type) { + case LAYER_TYPES.point: + case LAYER_TYPES.icon: + return data => { + const pos = getPosition(data); + return pos.every(Number.isFinite) && isInPolygon(pos, filter.value); + }; + case LAYER_TYPES.arc: + case LAYER_TYPES.line: + return data => { + const pos = getPosition(data); + return ( + pos.every(Number.isFinite) && + [ + [pos[0], pos[1]], + [pos[3], pos[4]] + ].every(point => isInPolygon(point, filter.value)) + ); + }; + case LAYER_TYPES.hexagonId: + if (layer.dataToFeature && layer.dataToFeature.centroids) { + return data => { + // null or getCentroid({id}) + const centroid = layer.dataToFeature.centroids[data.index]; + return centroid && isInPolygon(centroid, filter.value); + }; + } + return data => { + const id = getPosition(data); + if (!h3IsValid(id)) { + return false; + } + const pos = getCentroid({id}); + return pos.every(Number.isFinite) && isInPolygon(pos, filter.value); + }; + default: + return () => true; + } +}; + +/** + * @param param An object that represents a row record. + * @param param.index Index of the row in data container. + * @returns Returns true to keep the element, or false otherwise. + */ +type filterFunction = (data: {index: number}) => boolean; +/** + * @param field dataset Field + * @param dataId Dataset id + * @param filter Filter object + * @param layers list of layers to filter upon + * @param dataContainer Data container + * @return filterFunction + */ +/* eslint-disable complexity */ +export function getFilterFunction( + field: Field | null, + dataId: string, + filter: Filter, + layers: L[], + dataContainer: DataContainerInterface +): filterFunction { + // field could be null in polygon filter + const valueAccessor = field ? field.valueAccessor : data => null; + const defaultFunc = d => true; + + switch (filter.type) { + case FILTER_TYPES.range: + return data => isInRange(valueAccessor(data), filter.value); + case FILTER_TYPES.multiSelect: + return data => filter.value.includes(valueAccessor(data)); + case FILTER_TYPES.select: + return data => valueAccessor(data) === filter.value; + case FILTER_TYPES.timeRange: + if (!field) { + return defaultFunc; + } + const mappedValue = get(field, ['filterProps', 'mappedValue']); + const accessor = Array.isArray(mappedValue) + ? data => mappedValue[data.index] + : data => timeToUnixMilli(valueAccessor(data), field.format); + return data => isInRange(accessor(data), filter.value); + case FILTER_TYPES.polygon: + if (!layers || !layers.length || !filter.layerId) { + return defaultFunc; + } + const layerFilterFunctions = filter.layerId + .map(id => layers.find(l => l.id === id)) + .filter(l => l && l.config.dataId === dataId) + .map(layer => getPolygonFilterFunctor(layer, filter, dataContainer)); + + return data => layerFilterFunctions.every(filterFunc => filterFunc(data)); + default: + return defaultFunc; + } +} + +export function updateFilterDataId(dataId: string): FilterBase { + return getDefaultFilter(dataId); +} + +export function filterDataByFilterTypes( + { + dynamicDomainFilters, + cpuFilters, + filterFuncs + }: { + dynamicDomainFilters: Filter[] | null; + cpuFilters: Filter[] | null; + filterFuncs: { + [key: string]: filterFunction; + }; + }, + dataContainer: DataContainerInterface +): FilterResult { + const filteredIndexForDomain: number[] = []; + const filteredIndex: number[] = []; + + const filterContext = {index: -1, dataContainer}; + const filterFuncCaller = (filter: Filter) => filterFuncs[filter.id](filterContext); + + const numRows = dataContainer.numRows(); + for (let i = 0; i < numRows; ++i) { + filterContext.index = i; + + const matchForDomain = dynamicDomainFilters && dynamicDomainFilters.every(filterFuncCaller); + if (matchForDomain) { + filteredIndexForDomain.push(filterContext.index); + } + + const matchForRender = cpuFilters && cpuFilters.every(filterFuncCaller); + if (matchForRender) { + filteredIndex.push(filterContext.index); + } + } + + return { + ...(dynamicDomainFilters ? {filteredIndexForDomain} : {}), + ...(cpuFilters ? {filteredIndex} : {}) + }; +} + +/** + * Get a record of filters based on domain type and gpu / cpu + */ +export function getFilterRecord( + dataId: string, + filters: Filter[], + opt: FilterDatasetOpt = {} +): FilterRecord { + const filterRecord: FilterRecord = { + dynamicDomain: [], + fixedDomain: [], + cpu: [], + gpu: [] + }; + + filters.forEach(f => { + if (isValidFilterValue(f.type, f.value) && toArray(f.dataId).includes(dataId)) { + (f.fixedDomain || opt.ignoreDomain + ? filterRecord.fixedDomain + : filterRecord.dynamicDomain + ).push(f); + + (f.gpu && !opt.cpuOnly ? filterRecord.gpu : filterRecord.cpu).push(f); + } + }); + + return filterRecord; +} + +/** + * Compare filter records to get what has changed + */ +export function diffFilters( + filterRecord: FilterRecord, + oldFilterRecord: FilterRecord | {} = {} +): FilterChanged { + let filterChanged: Partial = {}; + + (Object.entries(filterRecord) as Entries).forEach(([record, items]) => { + items.forEach(filter => { + const oldFilter: Filter = (oldFilterRecord[record] || []).find( + (f: Filter) => f.id === filter.id + ); + + if (!oldFilter) { + // added + filterChanged = set([record, filter.id], 'added', filterChanged); + } else { + // check what has changed + ['name', 'value', 'dataId'].forEach(prop => { + if (filter[prop] !== oldFilter[prop]) { + filterChanged = set([record, filter.id], `${prop}_changed`, filterChanged); + } + }); + } + }); + + (oldFilterRecord[record] || []).forEach((oldFilter: Filter) => { + // deleted + if (!items.find(f => f.id === oldFilter.id)) { + filterChanged = set([record, oldFilter.id], 'deleted', filterChanged); + } + }); + }); + + return {...{dynamicDomain: null, fixedDomain: null, cpu: null, gpu: null}, ...filterChanged}; +} +/** + * Call by parsing filters from URL + * Check if value of filter within filter domain, if not adjust it to match + * filter domain + * + * @returns value - adjusted value to match filter or null to remove filter + */ +// eslint-disable-next-line complexity +export function adjustValueToFilterDomain(value: Filter['value'], {domain, type}) { + if (!type) { + return false; + } + // if the current filter is a polygon it will not have any domain + // all other filter types require domain + if (type !== FILTER_TYPES.polygon && !domain) { + return false; + } + + switch (type) { + case FILTER_TYPES.range: + case FILTER_TYPES.timeRange: + if (!Array.isArray(value) || value.length !== 2) { + return domain.map(d => d); + } + + return value.map((d, i) => (notNullorUndefined(d) && isInRange(d, domain) ? d : domain[i])); + + case FILTER_TYPES.multiSelect: + if (!Array.isArray(value)) { + return []; + } + const filteredValue = value.filter(d => domain.includes(d)); + return filteredValue.length ? filteredValue : []; + + case FILTER_TYPES.select: + return domain.includes(value) ? value : true; + case FILTER_TYPES.polygon: + return value; + + default: + return null; + } +} +/* eslint-enable complexity */ + +/** + * Calculate numeric domain and suitable step + */ +export function getNumericFieldDomain( + dataContainer: DataContainerInterface, + valueAccessor: dataValueAccessor +): RangeFieldDomain { + let domain: [number, number] = [0, 1]; + let step = 0.1; + + const mappedValue = dataContainer.mapIndex(valueAccessor); + + if (dataContainer.numRows() > 1) { + domain = ScaleUtils.getLinearDomain(mappedValue); + const diff = domain[1] - domain[0]; + + // in case equal domain, [96, 96], which will break quantize scale + if (!diff) { + domain[1] = domain[0] + 1; + } + + step = getNumericStepSize(diff) || step; + domain[0] = formatNumberByStep(domain[0], step, 'floor'); + domain[1] = formatNumberByStep(domain[1], step, 'ceil'); + } + + const {histogram, enlargedHistogram} = getHistogram(domain, mappedValue); + + return {domain, step, histogram, enlargedHistogram}; +} + +/** + * Calculate step size for range and timerange filter + */ +export function getNumericStepSize(diff: number): number { + diff = Math.abs(diff); + + if (diff > 100) { + return 1; + } else if (diff > 3) { + return 0.01; + } else if (diff > 1) { + return 0.001; + } + // Try to get at least 1000 steps - and keep the step size below that of + // the (diff > 1) case. + const x = diff / 1000; + // Find the exponent and truncate to 10 to the power of that exponent + + const exponentialForm = x.toExponential(); + const exponent = parseFloat(exponentialForm.split('e')[1]); + + // Getting ready for node 12 + // this is why we need decimal.js + // Math.pow(10, -5) = 0.000009999999999999999 + // the above result shows in browser and node 10 + // node 12 behaves correctly + return new Decimal(10).pow(exponent).toNumber(); +} + +/** + * Calculate timestamp domain and suitable step + */ +export function getTimestampFieldDomain( + dataContainer: DataContainerInterface, + valueAccessor: dataValueAccessor +): TimeRangeFieldDomain { + // to avoid converting string format time to epoch + // every time we compare we store a value mapped to int in filter domain + + const mappedValue = dataContainer.mapIndex(valueAccessor); + const domain = ScaleUtils.getLinearDomain(mappedValue); + const defaultTimeFormat = getTimeWidgetTitleFormatter(domain); + + let step = 0.01; + + const diff = domain[1] - domain[0]; + const entry = TimestampStepMap.find(f => f.max >= diff); + if (entry) { + step = entry.step; + } + + const {histogram, enlargedHistogram} = getHistogram(domain, mappedValue); + + return { + domain, + step, + mappedValue, + histogram, + enlargedHistogram, + defaultTimeFormat + }; +} + +export function histogramConstruct( + domain: [number, number], + mappedValue: (Millisecond | number)[], + bins: number +): HistogramBin[] { + return d3Histogram() + .thresholds(ticks(domain[0], domain[1], bins)) + .domain(domain)(mappedValue) + .map(bin => ({ + count: bin.length, + bin, + x0: bin.x0, + x1: bin.x1 + })); +} +/** + * Calculate histogram from domain and array of values + */ +export function getHistogram( + domain: [number, number], + mappedValue: (Millisecond | number)[] +): {histogram: HistogramBin[]; enlargedHistogram: HistogramBin[]} { + const histogram = histogramConstruct(domain, mappedValue, histogramBins); + const enlargedHistogram = histogramConstruct(domain, mappedValue, enlargedHistogramBins); + + return {histogram, enlargedHistogram}; +} + +/** + * round number based on step + * + * @param {Number} val + * @param {Number} step + * @param {string} bound + * @returns {Number} rounded number + */ +export function formatNumberByStep(val: number, step: number, bound: 'floor' | 'ceil'): number { + if (bound === 'floor') { + return Math.floor(val * (1 / step)) / (1 / step); + } + + return Math.ceil(val * (1 / step)) / (1 / step); +} + +export function isInRange(val: any, domain: number[]): boolean { + if (!Array.isArray(domain)) { + return false; + } + + return val >= domain[0] && val <= domain[1]; +} + +/** + * Determines whether a point is within the provided polygon + * + * @param point as input search [lat, lng] + * @param polygon Points must be within these (Multi)Polygon(s) + * @return {boolean} + */ +export function isInPolygon(point: number[], polygon: any): boolean { + return booleanWithin(turfPoint(point), polygon); +} +export function getTimeWidgetTitleFormatter(domain: [number, number]): string | null { + if (!isValidTimeDomain(domain)) { + return null; + } + + const diff = domain[1] - domain[0]; + + // Local aware formats + // https://momentjs.com/docs/#/parsing/string-format + return diff > durationYear ? 'L' : diff > durationDay ? 'L LT' : 'L LTS'; +} + /** * Sanity check on filters to prepare for save + * @type {typeof import('./filter-utils').isFilterValidToSave} */ +export function isFilterValidToSave(filter: any): boolean { + return ( + filter?.type && + Array.isArray(filter?.name) && + (filter?.name.length || filter?.layerId.length) && + isValidFilterValue(filter?.type, filter?.value) + ); +} +/** + * Sanity check on filters to prepare for save + * @type {typeof import('./filter-utils').isValidFilterValue} + */ /* eslint-disable complexity */ export function isValidFilterValue(type: string | null, value: any): boolean { if (!type) { @@ -41,6 +878,370 @@ export function isValidFilterValue(type: string | null, value: any): boolean { } } +export function getColumnFilterProps, L>( + filter: Filter, + dataset: K +): {lineChart: LineChart; yAxs: Field} | {} { + if (filter.plotType === PLOT_TYPES.histogram || !filter.yAxis) { + // histogram should be calculated when create filter + return {}; + } + + const {mappedValue = []} = filter; + const {yAxis} = filter; + const fieldIdx = dataset.getColumnFieldIdx(yAxis.name); + if (fieldIdx < 0) { + Console.warn(`yAxis ${yAxis.name} does not exist in dataset`); + return {lineChart: {}, yAxis}; + } + + // return lineChart + const series = dataset.dataContainer + .map( + (row, rowIndex) => ({ + x: mappedValue[rowIndex], + y: row.valueAt(fieldIdx) + }), + true + ) + .filter(({x, y}) => Number.isFinite(x) && Number.isFinite(y)) + .sort((a, b) => ascending(a.x, b.x)); + + const yDomain = extent(series, d => d.y); + const xDomain = [series[0].x, series[series.length - 1].x]; + + return {lineChart: {series, yDomain, xDomain}, yAxis}; +} + +export function getDefaultFilterPlotType(filter: Filter): string | null { + const filterPlotTypes: typeof SupportedPlotType[keyof typeof SupportedPlotType] | null = + filter.type && SupportedPlotType[filter.type]; + if (!filterPlotTypes) { + return null; + } + + if (!filter.yAxis) { + return filterPlotTypes.default; + } + + return filterPlotTypes[filter.yAxis.type] || null; +} + +/** + * + * @param datasetIds list of dataset ids to be filtered + * @param datasets all datasets + * @param filters all filters to be applied to datasets + * @return datasets - new updated datasets + */ +export function applyFiltersToDatasets< + K extends KeplerTableModel, + L extends {config: {dataId: string | null}} +>( + datasetIds: string[], + datasets: {[id: string]: K}, + filters: Filter[], + layers?: L[] +): {[id: string]: K} { + const dataIds = toArray(datasetIds); + return dataIds.reduce((acc, dataId) => { + const layersToFilter = (layers || []).filter(l => l.config.dataId === dataId); + const appliedFilters = filters.filter(d => shouldApplyFilter(d, dataId)); + const table = datasets[dataId]; + + return { + ...acc, + [dataId]: table.filterTable(appliedFilters, layersToFilter, {}) + }; + }, datasets); +} + +/** + * Applies a new field name value to fielter and update both filter and dataset + * @param filter - to be applied the new field name on + * @param dataset - dataset the field belongs to + * @param fieldName - field.name + * @param filterDatasetIndex - field.name + * @param option + * @return - {filter, datasets} + */ +export function applyFilterFieldName, L>( + filter: Filter, + dataset: K, + fieldName: string, + filterDatasetIndex = 0, + option?: {mergeDomain: boolean} +): { + filter: Filter | null; + dataset: K; +} { + // using filterDatasetIndex we can filter only the specified dataset + const mergeDomain = option && option.hasOwnProperty('mergeDomain') ? option.mergeDomain : false; + + const fieldIndex = dataset.getColumnFieldIdx(fieldName); + // if no field with same name is found, move to the next datasets + if (fieldIndex === -1) { + // throw new Error(`fieldIndex not found. Dataset must contain a property with name: ${fieldName}`); + return {filter: null, dataset}; + } + + // TODO: validate field type + const filterProps = dataset.getColumnFilterProps(fieldName); + + const newFilter = { + ...(mergeDomain ? mergeFilterDomainStep(filter, filterProps) : {...filter, ...filterProps}), + name: Object.assign([...toArray(filter.name)], {[filterDatasetIndex]: fieldName}), + fieldIdx: Object.assign([...toArray(filter.fieldIdx)], { + [filterDatasetIndex]: fieldIndex + }), + // TODO, since we allow to add multiple fields to a filter we can no longer freeze the filter + freeze: true + }; + + return { + filter: newFilter, + dataset + }; +} + +/** + * Merge one filter with other filter prop domain + */ +/* eslint-disable complexity */ +export function mergeFilterDomainStep( + filter: Filter, + filterProps?: Partial +): (Filter & {step?: number}) | null { + if (!filter) { + return null; + } + + if (!filterProps) { + return filter; + } + + if ((filter.fieldType && filter.fieldType !== filterProps.fieldType) || !filterProps.domain) { + return filter; + } + + const combinedDomain = !filter.domain + ? filterProps.domain + : [...(filter.domain || []), ...(filterProps.domain || [])].sort((a, b) => a - b); + + const newFilter = { + ...filter, + ...filterProps, + domain: [combinedDomain[0], combinedDomain[combinedDomain.length - 1]] + }; + + switch (filterProps.fieldType) { + case ALL_FIELD_TYPES.string: + case ALL_FIELD_TYPES.date: + return { + ...newFilter, + domain: unique(combinedDomain).sort() + }; + + case ALL_FIELD_TYPES.timestamp: + const step = + (filter as TimeRangeFilter).step < (filterProps as TimeRangeFieldDomain).step + ? (filter as TimeRangeFilter).step + : (filterProps as TimeRangeFieldDomain).step; + + return { + ...newFilter, + step + }; + case ALL_FIELD_TYPES.real: + case ALL_FIELD_TYPES.integer: + default: + return newFilter; + } +} +/* eslint-enable complexity */ + +/** + * Generates polygon filter + */ +export const featureToFilterValue = ( + feature: Feature, + filterId: string, + properties?: {} +): FeatureValue => ({ + ...feature, + id: feature.id, + properties: { + ...feature.properties, + ...properties, + filterId + } +}); + +export const getFilterIdInFeature = (f: FeatureValue): string => get(f, ['properties', 'filterId']); + +/** + * Generates polygon filter + */ +export function generatePolygonFilter< + L extends {config: {dataId: string | null; label: string}; id: string} +>(layers: L[], feature: Feature): PolygonFilter { + const dataId = layers.map(l => l.config.dataId).filter(notNullorUndefined); + const layerId = layers.map(l => l.id); + const name = layers.map(l => l.config.label); + const filter = getDefaultFilter(dataId); + return { + ...filter, + fixedDomain: true, + type: FILTER_TYPES.polygon, + name, + layerId, + value: featureToFilterValue(feature, filter.id, {isVisible: true}) + }; +} + +/** + * Run filter entirely on CPU + */ +interface StateType, L> { + layers: L[]; + filters: Filter[]; + datasets: {[id: string]: K}; +} + +export function filterDatasetCPU, K extends KeplerTableModel, L>( + state: T, + dataId: string +): T { + const datasetFilters = state.filters.filter(f => f.dataId.includes(dataId)); + const dataset = state.datasets[dataId]; + + if (!dataset) { + return state; + } + + const cpuFilteredDataset = dataset.filterTableCPU(datasetFilters, state.layers); + + return set(['datasets', dataId], cpuFilteredDataset, state); +} + +/** + * Validate parsed filters with datasets and add filterProps to field + */ +export function validateFiltersUpdateDatasets< + S extends {datasets: {[id: string]: K}; layers: L[]}, + K extends KeplerTableModel, + L extends {config: {dataId: string | null; label: string}; id: string} +>( + state: S, + filtersToValidate: ParsedFilter[] = [] +): { + validated: Filter[]; + failed: Filter[]; + updatedDatasets: S['datasets']; +} { + // TODO Better Typings here + const validated: any[] = []; + const failed: any[] = []; + const {datasets} = state; + let updatedDatasets = datasets; + + // merge filters + filtersToValidate.forEach(filter => { + // we can only look for datasets define in the filter dataId + const datasetIds = toArray(filter.dataId); + + // we can merge a filter only if all datasets in filter.dataId are loaded + if (datasetIds.every(d => datasets[d])) { + // all datasetIds in filter must be present the state datasets + const {filter: validatedFilter, applyToDatasets, augmentedDatasets} = datasetIds.reduce( + (acc, datasetId) => { + const dataset = updatedDatasets[datasetId]; + const layers = state.layers.filter(l => l.config.dataId === dataset.id); + const {filter: updatedFilter, dataset: updatedDataset} = validateFilterWithData( + acc.augmentedDatasets[datasetId] || dataset, + filter, + layers + ); + + if (updatedFilter) { + return { + ...acc, + // merge filter props + filter: acc.filter + ? { + ...acc.filter, + ...mergeFilterDomainStep(acc, updatedFilter) + } + : updatedFilter, + + applyToDatasets: [...acc.applyToDatasets, datasetId], + + augmentedDatasets: { + ...acc.augmentedDatasets, + [datasetId]: updatedDataset + } + }; + } + + return acc; + }, + { + filter: null, + applyToDatasets: [], + augmentedDatasets: {} + } + ); + + if (validatedFilter && isEqual(datasetIds, applyToDatasets)) { + validated.push(validatedFilter); + updatedDatasets = { + ...updatedDatasets, + ...augmentedDatasets + }; + } + } else { + failed.push(filter); + } + }); + + return {validated, failed, updatedDatasets}; +} + +export function getFilterPlot, L>( + filter: Filter, + dataset: K +): {lineChart: LineChart; yAxs: Field} | {} { + if (filter.plotType === PLOT_TYPES.histogram || !filter.yAxis) { + // histogram should be calculated when create filter + return {}; + } + + const {mappedValue = []} = filter; + const {yAxis} = filter; + const fieldIdx = dataset.getColumnFieldIdx(yAxis.name); + if (fieldIdx < 0) { + Console.warn(`yAxis ${yAxis.name} does not exist in dataset`); + return {lineChart: {}, yAxis}; + } + + // return lineChart + const series = dataset.dataContainer + .map( + (row, rowIndex) => ({ + x: mappedValue[rowIndex], + y: row.valueAt(fieldIdx) + }), + true + ) + .filter(({x, y}) => Number.isFinite(x) && Number.isFinite(y)) + .sort((a, b) => ascending(a.x, b.x)); + + const yDomain = extent(series, d => d.y); + const xDomain = [series[0].x, series[series.length - 1].x]; + + return {lineChart: {series, yDomain, xDomain}, yAxis}; +} + /** * Retrieve interval bins for time filter */ diff --git a/src/layers/src/h3-hexagon-layer/h3-utils.ts b/src/utils/src/h3-utils.ts similarity index 97% rename from src/layers/src/h3-hexagon-layer/h3-utils.ts rename to src/utils/src/h3-utils.ts index cff998b3f6..b84a61eb7e 100644 --- a/src/layers/src/h3-hexagon-layer/h3-utils.ts +++ b/src/utils/src/h3-utils.ts @@ -20,7 +20,7 @@ import {h3GetResolution, H3Index, h3IsValid, h3ToGeo, h3ToGeoBoundary} from 'h3-js'; import {ALL_FIELD_TYPES} from '@kepler.gl/constants'; -import {notNullorUndefined} from '@kepler.gl/utils'; +import {notNullorUndefined} from './data-utils'; export {h3GetResolution, h3IsValid}; diff --git a/src/utils/src/index.ts b/src/utils/src/index.ts index 00d1e192ef..247e157d9f 100644 --- a/src/utils/src/index.ts +++ b/src/utils/src/index.ts @@ -95,18 +95,6 @@ export { exportMap, default as exporters } from './export-utils'; -export { - isValidFilterValue, - isValidTimeDomain, - getIntervalBins, - getTimeWidgetHintFormatter, - durationSecond, - durationMinute, - durationHour, - durationDay, - durationWeek, - durationYear -} from './filter-utils'; export {setLayerBlending} from './gl-utils'; export {flattenMessages, mergeMessages} from './locale-utils'; export type {Dimensions} from './observe-dimensions'; @@ -158,3 +146,67 @@ export {transformRequest, isStyleUsingMapboxTiles} from './map-style-utils/mapbo // Map export {onViewPortChange, getMapLayersFromSplitMaps} from './map-utils'; + +export {createDataContainer, createIndexedDataContainer, getSampleData as getSampleContainerData} from './data-container-utils'; +export type {DataContainerInterface} from './data-container-interface'; +export type {FilterResult, FilterChanged, dataValueAccessor} from './filter-utils' +export { + TimestampStepMap, + histogramBins, + enlargedHistogramBins, + FILTER_UPDATER_PROPS, + LIMITED_FILTER_EFFECT_PROPS, + FILTER_COMPONENTS, + DEFAULT_FILTER_STRUCTURE, + FILTER_ID_LENGTH, + LAYER_FILTERS, + getDefaultFilter, + shouldApplyFilter, + validatePolygonFilter, + validateFilter, + validateFilterWithData, + getFilterProps, + getPolygonFilterFunctor, + getFilterFunction, + updateFilterDataId, + filterDataByFilterTypes, + getFilterRecord, + diffFilters, + adjustValueToFilterDomain, + getNumericFieldDomain, + getNumericStepSize, + getTimestampFieldDomain, + histogramConstruct, + getHistogram, + formatNumberByStep, + isInRange, + isInPolygon, + isValidTimeDomain, + getTimeWidgetTitleFormatter, + getTimeWidgetHintFormatter, + isFilterValidToSave, + isValidFilterValue, + getFilterPlot, + getDefaultFilterPlotType, + applyFiltersToDatasets, + applyFilterFieldName, + mergeFilterDomainStep, + featureToFilterValue, + getFilterIdInFeature, + generatePolygonFilter, + filterDatasetCPU, + validateFiltersUpdateDatasets, + getIntervalBins +} from "./filter-utils"; + +export { + getQuantileDomain, + getOrdinalDomain, + getLinearDomain, + getLogDomain +} from "./data-scale-utils"; + +export {DataRow} from './data-row'; + +export type {Centroid} from './h3-utils'; +export {getCentroid, idToPolygonGeo, h3IsValid, getHexFields} from './h3-utils'; \ No newline at end of file diff --git a/src/table/src/indexed-data-container.ts b/src/utils/src/indexed-data-container.ts similarity index 100% rename from src/table/src/indexed-data-container.ts rename to src/utils/src/indexed-data-container.ts diff --git a/src/utils/src/map-style-utils/mapbox-gl-style-editor.ts b/src/utils/src/map-style-utils/mapbox-gl-style-editor.ts index 18b86cf84b..48ee4c8ac9 100644 --- a/src/utils/src/map-style-utils/mapbox-gl-style-editor.ts +++ b/src/utils/src/map-style-utils/mapbox-gl-style-editor.ts @@ -21,8 +21,7 @@ import memoize from 'lodash.memoize'; import clondDeep from 'lodash.clonedeep'; import {DEFAULT_LAYER_GROUPS, DEFAULT_MAPBOX_API_URL} from '@kepler.gl/constants'; -import {BaseMapStyle, LayerGroup} from '@kepler.gl/types'; -import {MapState} from '@kepler.gl/types'; +import {BaseMapStyle, LayerGroup, MapState} from '@kepler.gl/types'; const mapUrlRg = /^mapbox:\/\/styles\/[-a-z0-9]{2,256}\/[-a-z0-9]{2,256}/; const httpRg = /^(?=(http:|https:))/; diff --git a/src/table/src/row-data-container.ts b/src/utils/src/row-data-container.ts similarity index 100% rename from src/table/src/row-data-container.ts rename to src/utils/src/row-data-container.ts diff --git a/test/browser/components/kepler-gl-test.js b/test/browser/components/kepler-gl-test.js index d3203989a7..09ceac44bd 100644 --- a/test/browser/components/kepler-gl-test.js +++ b/test/browser/components/kepler-gl-test.js @@ -39,8 +39,7 @@ import { GeocoderPanelFactory, NotificationPanelFactory } from '@kepler.gl/components'; -import {DEFAULT_MAP_STYLES, EXPORT_IMAGE_ID} from '@kepler.gl/constants'; -import {GEOCODER_DATASET_NAME} from '@kepler.gl/constants'; +import {DEFAULT_MAP_STYLES, EXPORT_IMAGE_ID, GEOCODER_DATASET_NAME} from '@kepler.gl/constants'; // mock state import {StateWithGeocoderDataset} from 'test/helpers/mock-state'; diff --git a/test/browser/components/modals/data-table-modal-test.js b/test/browser/components/modals/data-table-modal-test.js index 8f242c081e..e0329ec925 100644 --- a/test/browser/components/modals/data-table-modal-test.js +++ b/test/browser/components/modals/data-table-modal-test.js @@ -42,7 +42,7 @@ import {testFields, testAllData} from 'test/fixtures/test-csv-data'; import {geoStyleFields, geoStyleRows} from 'test/fixtures/geojson'; import {StateWFiles, testCsvDataId, testGeoJsonDataId} from 'test/helpers/mock-state'; -import {createDataContainer} from '@kepler.gl/table'; +import {createDataContainer} from '@kepler.gl/utils'; const {VertThreeDots} = Icons; const DataTableModal = appInjector.get(DataTableModalFactory); diff --git a/test/browser/components/modals/share-map-modal-test.js b/test/browser/components/modals/share-map-modal-test.js index 41f29e6ab0..0e3d399eaf 100644 --- a/test/browser/components/modals/share-map-modal-test.js +++ b/test/browser/components/modals/share-map-modal-test.js @@ -22,7 +22,12 @@ import React from 'react'; import test from 'tape'; import {IntlWrapper, mountWithTheme} from 'test/helpers/component-utils'; import sinon from 'sinon'; -import {ShareMapUrlModalFactory, SharingUrl, CloudTile, StatusPanel} from '@kepler.gl/components'; +import { + ShareMapUrlModalFactory, + SharingUrl, + CloudTile, + StatusPanel +} from '@kepler.gl/components'; const ShareMapUrlModal = ShareMapUrlModalFactory(); test('Components -> ShareMapUrlModal.mount', t => { diff --git a/test/browser/layer-tests/geojson-layer-specs.js b/test/browser/layer-tests/geojson-layer-specs.js index 40694a2954..f85372384e 100644 --- a/test/browser/layer-tests/geojson-layer-specs.js +++ b/test/browser/layer-tests/geojson-layer-specs.js @@ -19,8 +19,13 @@ // THE SOFTWARE. import test from 'tape'; -import {defaultElevation, defaultLineWidth, defaultRadius, KeplerGlLayers} from '@kepler.gl/layers'; -import {copyTableAndUpdate} from '@kepler.gl/table'; +import { + defaultElevation, + defaultLineWidth, + defaultRadius, + KeplerGlLayers +} from '@kepler.gl/layers'; +import {copyTableAndUpdate, createNewDataEntry} from '@kepler.gl/table'; const {GeojsonLayer} = KeplerGlLayers; @@ -42,7 +47,6 @@ import { geoStyleMeta } from 'test/fixtures/geojson'; import {processGeojson} from '@kepler.gl/processors'; -import {createNewDataEntry} from '@kepler.gl/table'; test('#GeojsonLayer -> constructor', t => { const TEST_CASES = { diff --git a/test/browser/layer-tests/h3-hexagon-layer-specs.js b/test/browser/layer-tests/h3-hexagon-layer-specs.js index 5ea8c7d928..2cb24924dc 100644 --- a/test/browser/layer-tests/h3-hexagon-layer-specs.js +++ b/test/browser/layer-tests/h3-hexagon-layer-specs.js @@ -31,11 +31,8 @@ import { preparedFilterDomain0, hexagonIdLayerMeta } from 'test/helpers/layer-utils'; -import { - getCentroid, - KeplerGlLayers, - h3DefaultElevation as defaultElevation -} from '@kepler.gl/layers'; +import {KeplerGlLayers, h3DefaultElevation as defaultElevation} from '@kepler.gl/layers'; +import {getCentroid} from '@kepler.gl/utils'; import {copyTableAndUpdate} from '@kepler.gl/table'; diff --git a/test/fixtures/points-with-polygon-filter-map.js b/test/fixtures/points-with-polygon-filter-map.js index 0929bd38fe..10bd4a1afe 100644 --- a/test/fixtures/points-with-polygon-filter-map.js +++ b/test/fixtures/points-with-polygon-filter-map.js @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import {processKeplerglJSON} from 'processors'; +import {processKeplerglJSON} from '@kepler.gl/processors'; import CloneDeep from 'lodash.clonedeep'; import {keplerGlReducerCore as coreReducer} from '@kepler.gl/reducers'; import {addDataToMap} from '@kepler.gl/actions'; diff --git a/test/fixtures/test-hex-id-data.js b/test/fixtures/test-hex-id-data.js index 527023c6fe..baf9d2109a 100644 --- a/test/fixtures/test-hex-id-data.js +++ b/test/fixtures/test-hex-id-data.js @@ -19,7 +19,7 @@ // THE SOFTWARE. import {KeplerGlLayers} from '@kepler.gl/layers'; -import {createDataContainer} from '@kepler.gl/table'; +import {createDataContainer} from '@kepler.gl/utils'; import {DEFAULT_COLOR_UI} from '@kepler.gl/constants'; const {H3Layer} = KeplerGlLayers; diff --git a/test/helpers/mock-state.js b/test/helpers/mock-state.js index 08a4fa4aec..6e54d2e57e 100644 --- a/test/helpers/mock-state.js +++ b/test/helpers/mock-state.js @@ -22,7 +22,10 @@ import test from 'tape-catch'; import cloneDeep from 'lodash.clonedeep'; import {drainTasksForTesting} from 'react-palm/tasks'; -import {getInitialInputStyle, keplerGlReducerCore as keplerGlReducer} from '@kepler.gl/reducers'; +import { + getInitialInputStyle, + keplerGlReducerCore as keplerGlReducer +} from '@kepler.gl/reducers'; import { VizColorPalette, diff --git a/test/node/reducers/vis-state-merger-test.js b/test/node/reducers/vis-state-merger-test.js index 77af02026d..5a5bb224c0 100644 --- a/test/node/reducers/vis-state-merger-test.js +++ b/test/node/reducers/vis-state-merger-test.js @@ -37,7 +37,7 @@ import SchemaManager from '@kepler.gl/schemas'; import {processKeplerglJSON} from '@kepler.gl/processors'; import {updateVisData, receiveMapConfig, addDataToMap} from '@kepler.gl/actions'; -import {createDataContainer} from '@kepler.gl/table'; +import {createDataContainer} from '@kepler.gl/utils'; // fixtures import { diff --git a/test/node/reducers/vis-state-test.js b/test/node/reducers/vis-state-test.js index 21efbae448..63069e98dc 100644 --- a/test/node/reducers/vis-state-test.js +++ b/test/node/reducers/vis-state-test.js @@ -37,13 +37,8 @@ import { import {processCsvData, processGeojson} from '@kepler.gl/processors'; import {Layer, KeplerGlLayers} from '@kepler.gl/layers'; -import { - KeplerTable, - createDataContainer, - createNewDataEntry, - maybeToDate, - getDefaultFilter -} from '@kepler.gl/table'; +import {KeplerTable, createNewDataEntry, maybeToDate} from '@kepler.gl/table'; +import {createDataContainer, getDefaultFilter} from '@kepler.gl/utils'; import { ALL_FIELD_TYPES, EDITOR_MODES, diff --git a/test/node/utils/aggregate-utils-test.js b/test/node/utils/aggregate-utils-test.js index 17585faf27..4dbd86b0af 100644 --- a/test/node/utils/aggregate-utils-test.js +++ b/test/node/utils/aggregate-utils-test.js @@ -19,7 +19,7 @@ // THE SOFTWARE. import test from 'tape'; -import {getFrequency, getMode, aggregate} from '../../../src/utils'; +import {getFrequency, getMode, aggregate} from '@kepler.gl/utils'; import {AGGREGATION_TYPES} from '@kepler.gl/constants'; test('AggregateUtils - GetFrequency', t => { diff --git a/test/node/utils/color-util-test.js b/test/node/utils/color-util-test.js index af4fe62c33..ebd267e883 100644 --- a/test/node/utils/color-util-test.js +++ b/test/node/utils/color-util-test.js @@ -19,7 +19,7 @@ // THE SOFTWARE. import test from 'tape'; -import {createLinearGradient} from '../../../src/utils'; +import {createLinearGradient} from '@kepler.gl/utils'; test('createLinearGradient', t => { let colors = [[100, 100, 100]]; diff --git a/test/node/utils/data-container-test.js b/test/node/utils/data-container-test.js index d2b7cc203c..d71918f245 100644 --- a/test/node/utils/data-container-test.js +++ b/test/node/utils/data-container-test.js @@ -20,7 +20,7 @@ import test from 'tape'; -import {createDataContainer, createIndexedDataContainer} from '@kepler.gl/table'; +import {createDataContainer, createIndexedDataContainer} from '@kepler.gl/utils'; const data = [ [10, 20], // 0 diff --git a/test/node/utils/data-processor-test.js b/test/node/utils/data-processor-test.js index 595a8e377c..51010ba69e 100644 --- a/test/node/utils/data-processor-test.js +++ b/test/node/utils/data-processor-test.js @@ -54,10 +54,10 @@ import { analyzerTypeToFieldType, getSampleForTypeAnalyze, validateInputData, - getFieldsFromData + getFieldsFromData, + createDataContainer } from '@kepler.gl/utils'; -import {createDataContainer} from '@kepler.gl/table'; import {formatCsv} from '@kepler.gl/reducers'; import {ALL_FIELD_TYPES} from '@kepler.gl/constants'; diff --git a/test/node/utils/data-scale-utils-test.js b/test/node/utils/data-scale-utils-test.js index 25009936e9..3fcc59bc0a 100644 --- a/test/node/utils/data-scale-utils-test.js +++ b/test/node/utils/data-scale-utils-test.js @@ -26,7 +26,7 @@ import { getLinearDomain, getLogDomain, createDataContainer -} from '@kepler.gl/table'; +} from '@kepler.gl/utils'; function numberSort(a, b) { return a - b; diff --git a/test/node/utils/data-utils-test.js b/test/node/utils/data-utils-test.js index 1ee2d4ea2c..c35d9c370a 100644 --- a/test/node/utils/data-utils-test.js +++ b/test/node/utils/data-utils-test.js @@ -31,7 +31,7 @@ import { getFormatter, defaultFormatter } from '@kepler.gl/utils'; -import {ALL_FIELD_TYPES} from 'constants'; +import {ALL_FIELD_TYPES} from '@kepler.gl/constants'; test('dataUtils -> clamp', t => { t.equal(clamp([0, 1], 2), 1, 'should clamp 2 to 1 for [0,1]'); diff --git a/test/node/utils/dataset-utils-test.js b/test/node/utils/dataset-utils-test.js index aedca43ca7..d856a83c3b 100644 --- a/test/node/utils/dataset-utils-test.js +++ b/test/node/utils/dataset-utils-test.js @@ -19,7 +19,7 @@ // THE SOFTWARE. import test from 'tape'; -import {findDefaultColorField, createNewDataEntry} from '../../../src/utils'; +import {findDefaultColorField, createNewDataEntry} from '@kepler.gl/utils'; import {processCsvData} from '@kepler.gl/processors'; diff --git a/test/node/utils/filter-utils-test.js b/test/node/utils/filter-utils-test.js index 987cb1800c..ecb1ac2bc5 100644 --- a/test/node/utils/filter-utils-test.js +++ b/test/node/utils/filter-utils-test.js @@ -21,9 +21,10 @@ import test from 'tape'; import moment from 'moment'; -import {isValidFilterValue} from '@kepler.gl/utils'; +import {getDatasetFieldIndexForFilter} from '@kepler.gl/table'; import { + isValidFilterValue, adjustValueToFilterDomain, getFilterFunction, getDefaultFilter, @@ -33,9 +34,8 @@ import { diffFilters, getHistogram, getTimestampFieldDomain, - createDataContainer, - getDatasetFieldIndexForFilter -} from '@kepler.gl/table'; + createDataContainer +} from '@kepler.gl/utils'; import {FILTER_TYPES} from '@kepler.gl/constants'; import {mockPolygonFeature, mockPolygonData} from '../../fixtures/polygon'; diff --git a/test/node/utils/kepler-table-test.js b/test/node/utils/kepler-table-test.js index d4a89315bc..2a1e84b300 100644 --- a/test/node/utils/kepler-table-test.js +++ b/test/node/utils/kepler-table-test.js @@ -22,8 +22,8 @@ import test from 'tape'; import moment from 'moment'; import testData, {numericRangesCsv, testFields} from 'test/fixtures/test-csv-data'; -import {preciseRound} from '@kepler.gl/utils'; -import {createNewDataEntry, getFilterFunction, findPointFieldPairs} from '@kepler.gl/table'; +import {preciseRound, getFilterFunction} from '@kepler.gl/utils'; +import {createNewDataEntry, findPointFieldPairs} from '@kepler.gl/table'; import {processCsvData} from '@kepler.gl/processors'; import {cmpFields} from '../../helpers/comparison-utils'; diff --git a/test/node/utils/layer-utils-test.js b/test/node/utils/layer-utils-test.js index 1909132721..9da532822c 100644 --- a/test/node/utils/layer-utils-test.js +++ b/test/node/utils/layer-utils-test.js @@ -33,12 +33,8 @@ import {cmpLayers} from 'test/helpers/comparison-utils'; import {getNextColorMakerValue} from 'test/helpers/layer-utils'; import tripGeojson, {timeStampDomain, tripBounds} from 'test/fixtures/trip-geojson'; import {geoJsonWithStyle} from 'test/fixtures/geojson'; -import { - KeplerTable, - findPointFieldPairs, - createDataContainer, - createNewDataEntry -} from '@kepler.gl/table'; +import {KeplerTable, findPointFieldPairs, createNewDataEntry} from '@kepler.gl/table'; +import {createDataContainer} from '@kepler.gl/utils'; test('layerUtils -> findDefaultLayer.1', t => { const inputFields = [ diff --git a/test/node/utils/map-info-utils-test.js b/test/node/utils/map-info-utils-test.js index 612f9e0498..feb9326b07 100644 --- a/test/node/utils/map-info-utils-test.js +++ b/test/node/utils/map-info-utils-test.js @@ -19,7 +19,7 @@ // THE SOFTWARE. import test from 'tape'; -import {isValidMapInfo} from '../../../src/utils'; +import {isValidMapInfo} from '@kepler.gl/utils'; test('mapInfoUtils -> isValidMapInfo', t => { t.equal( diff --git a/test/node/utils/mapbox-gl-style-editor-test.js b/test/node/utils/mapbox-gl-style-editor-test.js index 47bc2a5db1..49e2febc3e 100644 --- a/test/node/utils/mapbox-gl-style-editor-test.js +++ b/test/node/utils/mapbox-gl-style-editor-test.js @@ -19,7 +19,7 @@ // THE SOFTWARE. import test from 'tape'; -import {mergeLayerGroupVisibility} from '../../../src/utils'; +import {mergeLayerGroupVisibility} from '@kepler.gl/utils'; test('mapbox.gl Style Editor -> mergeLayerGroupVisibility', t => { const defaultLG = { diff --git a/test/node/utils/mapbox-utils-test.js b/test/node/utils/mapbox-utils-test.js index 8722d3c707..799ad8bcd3 100644 --- a/test/node/utils/mapbox-utils-test.js +++ b/test/node/utils/mapbox-utils-test.js @@ -19,7 +19,7 @@ // THE SOFTWARE. import test from 'tape'; -import {isStyleUsingMapboxTiles} from '../../../src/utils'; +import {isStyleUsingMapboxTiles} from '@kepler.gl/utils'; test('mapbox-utils -> isStyleUsingMapboxTiles', t => { t.notOk(isStyleUsingMapboxTiles({}), 'Empty style does not reference Mapbox'); diff --git a/test/node/utils/notifications-utils-test.js b/test/node/utils/notifications-utils-test.js index b767e164e0..0f195e12cb 100644 --- a/test/node/utils/notifications-utils-test.js +++ b/test/node/utils/notifications-utils-test.js @@ -19,7 +19,7 @@ // THE SOFTWARE. import test from 'tape'; -import {errorNotification, successNotification} from '../../../src/utils'; +import {errorNotification, successNotification} from '@kepler.gl/utils'; test('#notificationsUtils -> errorNotification', t => { const notification = errorNotification({message: 'test', id: 'test-1'}); diff --git a/test/node/utils/util-test.js b/test/node/utils/util-test.js index 082bdc6099..89532d9094 100644 --- a/test/node/utils/util-test.js +++ b/test/node/utils/util-test.js @@ -27,7 +27,7 @@ import { camelize, capitalizeFirstLetter, arrayInsert -} from '../../../src/utils'; +} from '@kepler.gl/utils'; test('Utils -> set', t => { const obj1 = {map: {map1: 'world'}}; diff --git a/yarn.lock b/yarn.lock index a5756eb429..fcebb3a3cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1998,7 +1998,7 @@ "@probe.gl/log" "^3.5.0" "@types/offscreencanvas" "^2019.7.0" -"@luma.gl/shadertools@8.5.16", "@luma.gl/shadertools@^8.5.10", "@luma.gl/shadertools@^8.5.16": +"@luma.gl/shadertools@8.5.16", "@luma.gl/shadertools@^8.5.16": version "8.5.16" resolved "https://registry.yarnpkg.com/@luma.gl/shadertools/-/shadertools-8.5.16.tgz#90eeed64fc4dfce9e87cd096238988cff06dda30" integrity sha512-L3M3v6bQhIT8McCeqLvHnLJBmBXYDog1QblF4PVszuIB/WH+cHxZ0I26X2a1eEsVCvdeCrxRBxr42743oyfUNA== @@ -2192,14 +2192,6 @@ "@babel/runtime" "^7.12.0" gl-matrix "^3.0.0" -"@math.gl/web-mercator@^3.5.4": - version "3.5.4" - resolved "https://registry.yarnpkg.com/@math.gl/web-mercator/-/web-mercator-3.5.4.tgz#2eca3136d33a66be665c08de01671c2ebd46867b" - integrity sha512-oSicpji8Rdyil2xWC5G3UrVVONl3vEvH8F0f6HgZHyQDw1LDiauthnTNIUbdWIvm6TF+WGd+GZ/mMLCmlKs+6w== - dependencies: - "@babel/runtime" "^7.12.0" - gl-matrix "^3.0.0" - "@math.gl/web-mercator@^3.5.5": version "3.6.2" resolved "https://registry.yarnpkg.com/@math.gl/web-mercator/-/web-mercator-3.6.2.tgz#1fd8fc2f1dfa794e5fe03eed328d53f69e7bf932"