@mapcomponents/react-maplibre 0.1.79 → 0.1.81

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Change Log
2
2
 
3
+ ## [v0.1.81] - 2023-06-12
4
+
5
+ ### Added
6
+
7
+ - 2ba02ba: add useAddProtocol hook
8
+ - 2ba02ba: add mbTilesProtocolHandler
9
+
10
+ ## [v0.1.80] - 2023-06-01
11
+
12
+ ### Added
13
+
14
+ - bea7ecc: add a test, add thumbnail (#112) …
15
+
16
+ ### Fixed
17
+
18
+ - f423ada: fix layerContext moveUp moveDown functions (#114) …
19
+
3
20
  ## [v0.1.79] - 2023-05-31
4
21
 
5
22
  ### Added
@@ -491,4 +508,4 @@
491
508
  - adjust MlImageMarkerLayer to make use of the new useMap hook
492
509
 
493
510
  ### Fixed
494
-
511
+
package/README.md CHANGED
@@ -20,7 +20,7 @@ Use our Codesandbox template to quickly try out this library without any setup r
20
20
 
21
21
  ### **... a new project**
22
22
 
23
- The easiest way to start a new project using this framework is to bootstrap a react application using our [create-react-app-template](https://github.com/mapcomponents/react-map-components-maplibre-cra-template).
23
+ The easiest way to start a new project using this framework is to bootstrap a react application using our [vite-template](https://github.com/mapcomponents/template).
24
24
 
25
25
  **Requirements:**
26
26
 
@@ -29,12 +29,12 @@ The easiest way to start a new project using this framework is to bootstrap a re
29
29
 
30
30
  Run the following commands in the terminal:
31
31
 
32
- 1. `npx create-react-app {your-app-name} --template @mapcomponents/cra-template`
32
+ 1. `npx degit mapcomponents/template {your-app-name}`
33
33
  2. `cd {your-app-name}`
34
34
  3. `yarn`
35
- 4. `yarn start`
35
+ 4. `yarn dev`
36
36
 
37
- This will start a development server that serves the mapcomponents app on port 3000 of your local machine as well as a browser tab with live reload enabled. This reloads the affected parts of the application if changes are detected to the corresponding files in the filesystem. Open the project folder in the IDE of your choice and start building your map client.
37
+ This will start a development server that serves the mapcomponents app on port 5174 of your local machine as well as a browser tab with live reload enabled. This reloads the affected parts of the application if changes are detected to the corresponding files in the filesystem. Open the project folder in the IDE of your choice and start building your map client.
38
38
 
39
39
  ### **... an existing react project**
40
40
 
@@ -0,0 +1,23 @@
1
+ import { Cancelable, RequestParameters, ResponseCallback } from 'maplibre-gl';
2
+ export interface useAddProtocolProps {
3
+ /**
4
+ * the protocol string, for example `mbtiles`
5
+ * In this example the handler function is called for all tile requests that start with the string `mbtiles://`
6
+ */
7
+ protocol: string;
8
+ /**
9
+ * Custom load tile function that will be called when using a source that starts with a custom url schema.
10
+ */
11
+ handler: (requestParameters: RequestParameters, callback: ResponseCallback<any>) => Cancelable;
12
+ }
13
+ /**
14
+ * Enables the use of custom protocols (basically custom tile load functions) in the maplibre-gl-js library.
15
+ *
16
+ */
17
+ declare const useAddProtocol: {
18
+ (props: useAddProtocolProps): {};
19
+ defaultProps: {
20
+ mapId: undefined;
21
+ };
22
+ };
23
+ export default useAddProtocol;
@@ -0,0 +1,14 @@
1
+ /// <reference types="react" />
2
+ declare const storyoptions: {
3
+ title: string;
4
+ component: {
5
+ (props: import("./useAddProtocol").useAddProtocolProps): {};
6
+ defaultProps: {
7
+ mapId: undefined;
8
+ };
9
+ };
10
+ argTypes: {};
11
+ decorators: ((Story: any, context: any) => JSX.Element)[];
12
+ };
13
+ export default storyoptions;
14
+ export declare const ExampleConfig: any;
package/dist/index.d.ts CHANGED
@@ -49,6 +49,8 @@ export { default as useWms } from "./hooks/useWms";
49
49
  export { default as useFilterData } from "./components/MlTemporalController/utils/useFilterData";
50
50
  export { default as useLayerContext } from "./hooks/useLayerContext";
51
51
  export { default as useFeatureEditor } from "./hooks/useFeatureEditor";
52
+ export { default as useAddProtocol } from "./hooks/useAddProtocol/useAddProtocol";
53
+ export { mbTilesProtocolHandler } from "./protocol_handlers/mbtiles";
52
54
  export { MapComponentsProvider } from "./contexts/MapContext";
53
55
  export { default as MapContext } from "./contexts/MapContext";
54
56
  export { default as SimpleDataProvider } from "./contexts/SimpleDataProvider";
package/dist/index.esm.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- var maplibreGl = require('maplibre-gl');
5
+ var maplibregl = require('maplibre-gl');
6
6
  var React = require('react');
7
7
  var styles = require('@mui/material/styles');
8
8
  var uuid = require('uuid');
@@ -46,6 +46,8 @@ var PauseIcon = require('@mui/icons-material/Pause');
46
46
  var StopIcon = require('@mui/icons-material/Stop');
47
47
  var FastForwardIcon = require('@mui/icons-material/FastForward');
48
48
  var FastRewindIcon = require('@mui/icons-material/FastRewind');
49
+ var initSqlJs = require('sql.js');
50
+ var pako = require('pako');
49
51
  var d3 = require('d3');
50
52
  var TuneIcon = require('@mui/icons-material/Tune');
51
53
  var reactColor = require('react-color');
@@ -90,6 +92,7 @@ function _interopNamespace(e) {
90
92
  return Object.freeze(n);
91
93
  }
92
94
 
95
+ var maplibregl__default = /*#__PURE__*/_interopDefaultLegacy(maplibregl);
93
96
  var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
94
97
  var React__namespace = /*#__PURE__*/_interopNamespace(React);
95
98
  var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
@@ -126,6 +129,8 @@ var PauseIcon__default = /*#__PURE__*/_interopDefaultLegacy(PauseIcon);
126
129
  var StopIcon__default = /*#__PURE__*/_interopDefaultLegacy(StopIcon);
127
130
  var FastForwardIcon__default = /*#__PURE__*/_interopDefaultLegacy(FastForwardIcon);
128
131
  var FastRewindIcon__default = /*#__PURE__*/_interopDefaultLegacy(FastRewindIcon);
132
+ var initSqlJs__default = /*#__PURE__*/_interopDefaultLegacy(initSqlJs);
133
+ var pako__namespace = /*#__PURE__*/_interopNamespace(pako);
129
134
  var d3__namespace = /*#__PURE__*/_interopNamespace(d3);
130
135
  var TuneIcon__default = /*#__PURE__*/_interopDefaultLegacy(TuneIcon);
131
136
  var ArrowCircleDownIcon__default = /*#__PURE__*/_interopDefaultLegacy(ArrowCircleDownIcon);
@@ -738,7 +743,7 @@ var MapLibreGlWrapper = /** @class */ (function () {
738
743
  _a.sent();
739
744
  _a.label = 2;
740
745
  case 2:
741
- self.map = new maplibreGl.Map(props.mapOptions);
746
+ self.map = new maplibregl.Map(props.mapOptions);
742
747
  self.addNativeMaplibreFunctionsAndProps();
743
748
  self.wrapper.refreshViewport();
744
749
  self.wrapper.fire('viewportchange');
@@ -951,34 +956,27 @@ function LayerContextProvider(props) {
951
956
  setLayers(_layers);
952
957
  }
953
958
  }, [layers]);
954
- var moveDown = React.useCallback(function (layerId) {
959
+ var moveLayer = React.useCallback(function (layerId, getNewPos) {
955
960
  var _a;
956
961
  var targetLayer = (_a = layers === null || layers === void 0 ? void 0 : layers.filter) === null || _a === void 0 ? void 0 : _a.call(layers, function (el) { return el.id === layerId; });
957
962
  if (targetLayer.length > 0) {
958
963
  var newLayers = __spreadArray([], layers, true);
959
964
  var element = targetLayer[0];
960
965
  var idx = layers.indexOf(element);
961
- if (idx + 1 <= layers.length - 1) {
966
+ var newPos = getNewPos(idx);
967
+ if (newPos >= 0 && newPos <= layers.length - 1) {
962
968
  newLayers.splice(idx, 1);
963
- newLayers.splice(idx + 1, 0, element);
969
+ newLayers.splice(newPos, 0, element);
964
970
  setLayers(newLayers);
965
971
  }
966
972
  }
967
973
  }, [layers]);
974
+ var moveDown = React.useCallback(function (layerId) {
975
+ moveLayer(layerId, function (idx) { return idx + 1; });
976
+ }, [moveLayer]);
968
977
  var moveUp = React.useCallback(function (layerId) {
969
- var _a;
970
- var targetLayer = (_a = layers === null || layers === void 0 ? void 0 : layers.filter) === null || _a === void 0 ? void 0 : _a.call(layers, function (el) { return el.id === layerId; });
971
- if (targetLayer.length > 0) {
972
- var newLayers = JSON.parse(JSON.stringify(layers));
973
- var element = targetLayer[0];
974
- var idx = layers.indexOf(element);
975
- if (idx - 1 >= 0) {
976
- newLayers.splice(idx, 1);
977
- newLayers.splice(idx - 1, 0, element);
978
- setLayers(newLayers);
979
- }
980
- }
981
- }, [layers]);
978
+ moveLayer(layerId, function (idx) { return idx - 1; });
979
+ }, [moveLayer]);
982
980
  var value = {
983
981
  layers: layers,
984
982
  setLayers: setLayers,
@@ -1446,7 +1444,7 @@ var createExport = function (options) {
1446
1444
  _loop_1(name_1);
1447
1445
  }
1448
1446
  // Create a new MapLibre-gl instance
1449
- var renderMap = new maplibreGl.Map({
1447
+ var renderMap = new maplibregl.Map({
1450
1448
  container: container,
1451
1449
  center: options.map.map.getCenter(),
1452
1450
  zoom: options.map.map.getZoom(),
@@ -4198,7 +4196,7 @@ var useLayerHoverPopup = function (props) {
4198
4196
  mapId: props.mapId,
4199
4197
  waitForLayer: props.layerId,
4200
4198
  });
4201
- var popup = React.useRef(new maplibreGl.Popup({
4199
+ var popup = React.useRef(new maplibregl.Popup({
4202
4200
  closeButton: false,
4203
4201
  closeOnClick: true,
4204
4202
  }));
@@ -5947,7 +5945,7 @@ var MlTerrainLayer = function (props) {
5947
5945
  if (!mapHook.map)
5948
5946
  return;
5949
5947
  if (!mapHook.map.map.getSource('terrain')) {
5950
- mapHook.map.map.addSource('terrain', __assign({ type: 'raster-dem', encoding: 'mapbox', maxzoom: 14, minzoom: 4 }, props.sourceOptions));
5948
+ mapHook.map.map.addSource('terrain', __assign({ type: 'raster-dem', encoding: 'mapbox', maxzoom: 12, minzoom: 4 }, props.sourceOptions));
5951
5949
  }
5952
5950
  mapHook.map.map.setTerrain(__assign({ source: 'terrain', exaggeration: 1 }, props.terrainOptions));
5953
5951
  mapHook.map.addLayer({
@@ -6195,6 +6193,147 @@ var useLayerContext = function () {
6195
6193
  return layerContext;
6196
6194
  };
6197
6195
 
6196
+ /**
6197
+ * Enables the use of custom protocols (basically custom tile load functions) in the maplibre-gl-js library.
6198
+ *
6199
+ */
6200
+ var useAddProtocol = function (props) {
6201
+ React.useEffect(function () {
6202
+ if (!props.protocol || typeof props.handler !== 'function')
6203
+ return;
6204
+ maplibregl__default["default"].addProtocol(props.protocol, props.handler);
6205
+ return function () {
6206
+ maplibregl__default["default"].removeProtocol(props.protocol);
6207
+ };
6208
+ }, []);
6209
+ return {};
6210
+ };
6211
+ useAddProtocol.defaultProps = {
6212
+ mapId: undefined,
6213
+ };
6214
+
6215
+ var loadedMbtiles = {};
6216
+ var parseParams = function (url) {
6217
+ var urlParts = url.split('://');
6218
+ var mbtilesUrl = urlParts[1];
6219
+ var mbtilesParts = mbtilesUrl.split('/');
6220
+ var mbtilesPartsLength = mbtilesParts.length;
6221
+ var y = mbtilesParts.splice(mbtilesPartsLength - 1, 1)[0];
6222
+ var x = mbtilesParts.splice(mbtilesPartsLength - 2, 1)[0];
6223
+ var z = mbtilesParts.splice(mbtilesPartsLength - 3, 1)[0];
6224
+ var filename = mbtilesParts.join('/');
6225
+ return {
6226
+ filename: filename,
6227
+ z: z,
6228
+ x: x,
6229
+ y: y,
6230
+ };
6231
+ };
6232
+ // mbtiles files are sqlite databases. This function loads the database and returns a handler
6233
+ // to work with sqlite databases in javascript we need to use sql.js.
6234
+ // to make this work in your project make sure to copy sql-wasm.wasm to the file root of your public folder and
6235
+ // add the following config to the externals prop of your webpack config
6236
+ // {externals: { fs: 'fs' }};
6237
+ var getMbtilesDbHandler = function (_a) {
6238
+ var filename = _a.filename;
6239
+ return __awaiter(void 0, void 0, void 0, function () {
6240
+ var SQL, fetched, buf, db;
6241
+ return __generator(this, function (_b) {
6242
+ switch (_b.label) {
6243
+ case 0:
6244
+ if (!!loadedMbtiles[filename]) return [3 /*break*/, 4];
6245
+ return [4 /*yield*/, initSqlJs__default["default"]()];
6246
+ case 1:
6247
+ SQL = _b.sent();
6248
+ return [4 /*yield*/, fetch(filename)];
6249
+ case 2:
6250
+ fetched = _b.sent();
6251
+ return [4 /*yield*/, fetched.arrayBuffer()];
6252
+ case 3:
6253
+ buf = _b.sent();
6254
+ db = new SQL.Database(new Uint8Array(buf));
6255
+ loadedMbtiles[filename] = db;
6256
+ _b.label = 4;
6257
+ case 4: return [2 /*return*/, loadedMbtiles[filename]];
6258
+ }
6259
+ });
6260
+ });
6261
+ };
6262
+ /**
6263
+ * Example usage:
6264
+ * getBufferFromMbtiles({ filename: 'mbtiles/countries.mbtiles', z: '0', x: '0', y: '0' }).then(
6265
+ * (result) => {
6266
+ * console.log(result);
6267
+ * }
6268
+ * );
6269
+ */
6270
+ function getBufferFromMbtiles(params) {
6271
+ return __awaiter(this, void 0, void 0, function () {
6272
+ var db, query;
6273
+ return __generator(this, function (_a) {
6274
+ switch (_a.label) {
6275
+ case 0: return [4 /*yield*/, getMbtilesDbHandler(params)];
6276
+ case 1:
6277
+ db = _a.sent();
6278
+ query = 'SELECT tile_data FROM tiles WHERE zoom_level = ' +
6279
+ params.z +
6280
+ ' AND tile_column = ' +
6281
+ params.x +
6282
+ ' AND tile_row = ' +
6283
+ (Math.pow(2, parseInt(params.z)) - parseInt(params.y) - 1);
6284
+ return [2 /*return*/, new Promise(function (resolve, reject) {
6285
+ try {
6286
+ // some of the logic here was heavily inspired by
6287
+ // https://github.com/IsraelHikingMap/Site/blob/6aa2ec0cfb8891fa048b1d9e2a4fc7d4cbcc8c97/IsraelHiking.Web/src/application/services/database.service.ts
6288
+ var result = db.exec(query);
6289
+ if (result.length !== 1) {
6290
+ reject(new Error('Tile not found.'));
6291
+ return;
6292
+ }
6293
+ var resultData = result[0].values[0][0];
6294
+ var binData = void 0;
6295
+ var isGzipped = resultData[0] === 0x1f && resultData[1] === 0x8b;
6296
+ if (isGzipped) {
6297
+ binData = pako__namespace.inflate(resultData);
6298
+ }
6299
+ else {
6300
+ binData = resultData;
6301
+ }
6302
+ if (binData === null || binData === void 0 ? void 0 : binData.buffer) {
6303
+ resolve(binData.buffer);
6304
+ }
6305
+ else {
6306
+ reject(new Error('Tile not found.'));
6307
+ return;
6308
+ }
6309
+ }
6310
+ catch (error) {
6311
+ reject(error);
6312
+ }
6313
+ })];
6314
+ }
6315
+ });
6316
+ });
6317
+ }
6318
+ /**
6319
+ * Expects a tile url in the following format:
6320
+ *
6321
+ * 'mbtiles://mbtiles/countries.mbtiles/{z}/{x}/{y}'
6322
+ */
6323
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
6324
+ var mbTilesProtocolHandler = function (params, callback) {
6325
+ var parsedParams = parseParams(params.url);
6326
+ getBufferFromMbtiles(parsedParams).then(function (result) {
6327
+ if (result) {
6328
+ callback(null, result, null, null);
6329
+ }
6330
+ else {
6331
+ callback(new Error('Tile not found'));
6332
+ }
6333
+ });
6334
+ return { cancel: function () { } };
6335
+ };
6336
+
6198
6337
  var SimpleDataContext = /*#__PURE__*/React__default["default"].createContext({});
6199
6338
  var SimpleDataContextProvider = SimpleDataContext.Provider;
6200
6339
 
@@ -19865,7 +20004,7 @@ var SpeedDial = function () {
19865
20004
  width: '100px',
19866
20005
  zIndex: '1000',
19867
20006
  } },
19868
- React__default["default"].createElement(MuiSpeedDial__default["default"], { ariaLabel: "SpeedDial tooltip example", sx: { position: 'absolute', bottom: 16, right: 16 }, icon: open ? React__default["default"].createElement(CloseIcon__default["default"], null) : React__default["default"].createElement(MoreVertIcon__default["default"], null), onClick: open ? handleClose : handleOpen, onOpen: handleOpen, open: open }, actions.map(function (action) { return (React__default["default"].createElement(SpeedDialAction__default["default"], { key: action.name, icon: action.icon, tooltipTitle: action.name, tooltipOpen: true, onClick: handleClose, FabProps: { sx: { color: theme.palette.secondary.main } } })); }))));
20007
+ React__default["default"].createElement(MuiSpeedDial__default["default"], { ariaLabel: "SpeedDial tooltip example", sx: { position: 'absolute', bottom: 16, right: 16 }, icon: open ? React__default["default"].createElement(CloseIcon__default["default"], { fontSize: "large" }) : React__default["default"].createElement(MoreVertIcon__default["default"], { fontSize: "large" }), onClick: open ? handleClose : handleOpen, onOpen: handleOpen, open: open }, actions.map(function (action) { return (React__default["default"].createElement(SpeedDialAction__default["default"], { key: action.name, icon: action.icon, tooltipTitle: action.name, tooltipOpen: true, onClick: handleClose, FabProps: { sx: { color: theme.palette.secondary.main } } })); }))));
19869
20008
  };
19870
20009
  SpeedDial.defaultProps = {
19871
20010
  mapId: undefined,
@@ -19939,6 +20078,8 @@ exports.TopToolbar = TopToolbar;
19939
20078
  exports.UploadButton = UploadButton;
19940
20079
  exports.WmsLayerForm = WmsLayerForm;
19941
20080
  exports.getTheme = getTheme;
20081
+ exports.mbTilesProtocolHandler = mbTilesProtocolHandler;
20082
+ exports.useAddProtocol = useAddProtocol;
19942
20083
  exports.useCameraFollowPath = useCameraFollowPath;
19943
20084
  exports.useExportMap = useExportMap;
19944
20085
  exports.useFeatureEditor = useFeatureEditor;