From 867d3588df7c0403c6801f897de5fbd71ff0a88d Mon Sep 17 00:00:00 2001 From: Leath Cooper Date: Tue, 30 Oct 2018 00:22:33 -0700 Subject: [PATCH] proposal (to myself looool) for rtree indexing with React Hooks API --- package.json | 4 +- src/IndexedEngine.js | 122 +++++++++++++++ stories/HexEngine.js | 42 +++++- test/src/HexEngine.test.js | 27 ++++ test/src/__snapshots__/HexEngine.test.js.snap | 142 ++++++++++++++++++ yarn.lock | 14 +- 6 files changed, 344 insertions(+), 7 deletions(-) create mode 100644 src/IndexedEngine.js diff --git a/package.json b/package.json index df16aba..507b8dc 100644 --- a/package.json +++ b/package.json @@ -28,8 +28,8 @@ "@babel/preset-react": "^7.0.0", "@babel/runtime": "^7.1.2", "@storybook/addon-centered": "^3.4.11", - "@storybook/addon-knobs": "^4.0.0-rc.6", "@storybook/addon-info": "^4.0.0-rc.6", + "@storybook/addon-knobs": "^4.0.0-rc.6", "@storybook/addon-notes": "^4.0.0-rc.6", "@storybook/addon-options": "^4.0.0-rc.6", "@storybook/addon-storysource": "^4.0.0-rc.6", @@ -61,7 +61,7 @@ }, "dependencies": { "classnames": "^2.2.5", - "memoize-one": "^4.0.2" + "flatbush": "^3.1.0" }, "files": [ "lib/**/*" diff --git a/src/IndexedEngine.js b/src/IndexedEngine.js new file mode 100644 index 0000000..1f25b44 --- /dev/null +++ b/src/IndexedEngine.js @@ -0,0 +1,122 @@ +import React, { useMutationEffect, useState } from "react"; +import PropTypes from "prop-types"; +import Flatbush from "flatbush"; +import Hex from "./models/Hex"; +import HexEngine from "./HexEngine"; +import HexUtils from "./HexUtils"; +import Orientation from "./models/Orientation"; +import Point from "./models/Point"; + +const IndexedEngine = ({ + children, + flat, + map, + origin, + size, + spacing, + viewBox, + ...props +}) => { + const orientation = flat ? Orientation.Flat : Orientation.Pointy; + const layout = { orientation, origin, size, spacing }; + const [visible, updateVisible] = useState([]); + const [index, setIndex] = useState(() => new Flatbush(map.length)); + + useMutationEffect( + () => { + console.log("new index effect"); + setIndex(() => new Flatbush(map.length)); + }, + [map.length, orientation, origin, spacing, size] + ); + useMutationEffect( + () => { + console.log("populate index effect"); + map.forEach(hex => { + const point = HexUtils.hexToPixel(hex, layout); + index.add( + point.x - layout.size.x / 2, + point.y - layout.size.y / 2 - 1, + point.x + layout.size.x / 2 + 1, + point.y + layout.size.y / 2 + 1 + ); + }); + index.finish(); + }, + [index] + ); + useMutationEffect( + () => { + console.log("update visible effect"); + updateVisible(() => + index + .search( + viewBox.x, + viewBox.y, + viewBox.x + viewBox.width, + viewBox.y + viewBox.height + ) + .map(i => map[i]) + ); + console.log(visible.length); + }, + [viewBox, index] + ); + + return ( + + {children(visible)} + + ); +}; + +IndexedEngine.propTypes = { + children: PropTypes.func.isRequired, + /** Determines if the hexagons are oriented with a point or an edge facing up */ + flat: PropTypes.bool, + map: PropTypes.arrayOf(PropTypes.instanceOf(Hex)).isRequired, + /** Origin of the grid */ + origin: PropTypes.oneOfType([ + PropTypes.instanceOf(Point), + PropTypes.shape({ + x: PropTypes.number.isRequired, + y: PropTypes.number.isRequired + }) + ]), + /** Size of the hexagons in each dimension */ + size: PropTypes.oneOfType([ + PropTypes.instanceOf(Point), + PropTypes.shape({ + x: PropTypes.number.isRequired, + y: PropTypes.number.isRequired + }) + ]), + /** Space between hexagons */ + spacing: PropTypes.number, + /** The viewBox {x,y,width,height} of the svg view area */ + viewBox: PropTypes.shape({ + height: PropTypes.number.isRequired, + width: PropTypes.number.isRequired, + x: PropTypes.number.isRequired, + y: PropTypes.number.isRequired + }) +}; + +IndexedEngine.defaultProps = { + classes: { grid: "", layout: "" }, + flat: true, + height: 480, + origin: new Point(0, 0), + size: new Point(10, 10), + spacing: 1.0, + width: 640, + viewBox: { + height: 100, + width: 100, + x: -50, + y: -50 + } +}; + +export const IndexedEngine_ = IndexedEngine; +export default IndexedEngine_; diff --git a/stories/HexEngine.js b/stories/HexEngine.js index efffa32..d2aa378 100644 --- a/stories/HexEngine.js +++ b/stories/HexEngine.js @@ -6,6 +6,8 @@ import GridGenerator from "../src/GridGenerator"; import Hexagon, { Hexagon_ } from "../src/Hexagon"; import HexEngine from "../src/HexEngine"; import Point from "../src/models/Point"; +import IndexedEngine from "../src/IndexedEngine"; +import "./Hexagon.css"; Hexagon.displayName = "Hexagon"; Hexagon_.displayName = "Hexagon"; @@ -129,4 +131,42 @@ stories - )); + )) + .add("indexed", () => { + const viewBox = object( + "viewBox", + { x: -50, y: -50, width: 100, height: 100 }, + "HexEngine" + ); + const map = GridGenerator.hexagon(50); + const classes = { + hexagon: "showCoordinates text", + highlighted: "highlighted", + hovered: "hovered", + selected: "selected", + q: "axis", + r: "axis", + s: "axis", + text: "text" + }; + return ( + + {hexes => + hexes.map(hex => ( + 0.5} + /> + )) + } + + ); + }); diff --git a/test/src/HexEngine.test.js b/test/src/HexEngine.test.js index c14e04f..a368175 100644 --- a/test/src/HexEngine.test.js +++ b/test/src/HexEngine.test.js @@ -1,7 +1,9 @@ import React from "react"; import renderer from "react-test-renderer"; +import Hex from "../../src//models/Hex"; import Hexagon from "../../src/Hexagon"; import HexEngine from "../../src/HexEngine"; +import IndexedEngine from "../../src/IndexedEngine"; describe("HexEngine", () => { it("HexEngine should render correctly with default props", () => { @@ -26,3 +28,28 @@ describe("HexEngine", () => { expect(tree).toMatchSnapshot(); }); }); + +describe("IndexedEngine", () => { + it("IndexedEngine should render correctly with default props", () => { + const map = [ + new Hex(-4, 0, 0), + new Hex(-3, 0, 0), + new Hex(-2, 0, 0), + new Hex(-1, 0, 0), + new Hex(0, 0, 0), + new Hex(1, 0, 0), + new Hex(2, 0, 0), + new Hex(3, 0, 0), + new Hex(4, 0, 0) + ]; + + const tree = renderer + .create( + + {hexes => hexes.map(hex => )} + + ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/test/src/__snapshots__/HexEngine.test.js.snap b/test/src/__snapshots__/HexEngine.test.js.snap index f812d97..02b4e5c 100644 --- a/test/src/__snapshots__/HexEngine.test.js.snap +++ b/test/src/__snapshots__/HexEngine.test.js.snap @@ -67,3 +67,145 @@ exports[`HexEngine HexEngine should render correctly with pointy orientation 1`] `; + +exports[`IndexedEngine IndexedEngine should render correctly with default props 1`] = ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +`; diff --git a/yarn.lock b/yarn.lock index a70f463..c2262f0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3608,6 +3608,16 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" +flatbush@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/flatbush/-/flatbush-3.1.0.tgz#ccd6957685a7db95d2fc27f5d4f24b7131d46553" + dependencies: + flatqueue "^1.1.0" + +flatqueue@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/flatqueue/-/flatqueue-1.1.0.tgz#bc03140d40940c4cb799d18d45eaced176c3ef2d" + flush-write-stream@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" @@ -5262,10 +5272,6 @@ mem@^1.1.0: dependencies: mimic-fn "^1.0.0" -memoize-one@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-4.0.2.tgz#3fb8db695aa14ab9c0f1644e1585a8806adc1aee" - memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"