From ddbfc458d7ef77a807b987da16f3bb29062c49aa Mon Sep 17 00:00:00 2001 From: Matt Weiden <538456+mweiden@users.noreply.github.com> Date: Tue, 14 Jan 2020 13:46:53 -0800 Subject: [PATCH] Remove d3 dependency in crossfilter (#1108) * Remove d3 dependency in crossfilter Fixes https://github.com/chanzuckerberg/cellxgene/issues/648 * Revert "Remove d3 dependency in crossfilter" This reverts commit 03b478f7dc9bfa0a097e530bb84322fce224beb4. * Remove d3 dependency in crossfilter Fixes https://github.com/chanzuckerberg/cellxgene/issues/648 * Fix typo in docstring --- .../util/typedCrossfilter/crossfilter.test.js | 18 ++++++----- client/src/reducers/undoable.js | 4 +-- .../src/util/typedCrossfilter/crossfilter.js | 30 ++++++++++++++++--- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/client/__tests__/util/typedCrossfilter/crossfilter.test.js b/client/__tests__/util/typedCrossfilter/crossfilter.test.js index 0558741c..9fd4e298 100644 --- a/client/__tests__/util/typedCrossfilter/crossfilter.test.js +++ b/client/__tests__/util/typedCrossfilter/crossfilter.test.js @@ -1,5 +1,4 @@ import _ from "lodash"; -import { polygonContains } from "d3"; import Crossfilter from "../../../src/util/typedCrossfilter"; @@ -334,12 +333,17 @@ describe("ImmutableTypedCrossfilter", () => { ); test.each([ - [[[0, 0], [0, 1], [1, 1], [1, 0]]], - [[[0, 0], [0, 0.5], [0.5, 0.5], [0.5, 0]]] - ])("within-polygon %p", polygon => { - expect( - p.select("coords", { mode: "within-polygon", polygon }).allSelected() - ).toEqual(_.filter(someData, d => polygonContains(polygon, d.coords))); + [ + [[0, 0], [0, 1], [1, 1], [1, 0]], + [true, true, true, true, true, false, true, true, true, true, true, true] + ], + [ + [[0, 0], [0, 0.5], [0.5, 0.5], [0.5, 0]], + [true, true, true, true, false, false, false, true, true, true, false, false] + ] + ])("within-polygon %p", (polygon, expected) => { + expect(p.select("coords", { mode: "within-polygon", polygon }).allSelected()) + .toEqual(_.zip(someData, expected).filter(x => x[1]).map(x => x[0])); }); }); diff --git a/client/src/reducers/undoable.js b/client/src/reducers/undoable.js index 3a435f34..803b74e0 100644 --- a/client/src/reducers/undoable.js +++ b/client/src/reducers/undoable.js @@ -1,9 +1,9 @@ /* -A redo/undo meta reducer for Redux. Designed to work well with the cascadeReducer(). +A redo/undo meta reducer for Redux. Designed to work well with the cascadeReducer(). Requires three parameters: * reducer - a reducer, which MUST return an object as state. -* undoableKeys - an array of object keys (strings). If any of these keys +* undoableKeys - an array of object keys (strings). If any of these keys are in the object/state returned by the reducer, they will be treated as state to be made "undoable". * options - an optional object, which may contain the following parameters: diff --git a/client/src/util/typedCrossfilter/crossfilter.js b/client/src/util/typedCrossfilter/crossfilter.js index 67a2b487..9d6976a7 100644 --- a/client/src/util/typedCrossfilter/crossfilter.js +++ b/client/src/util/typedCrossfilter/crossfilter.js @@ -1,5 +1,3 @@ -import { polygonContains } from "d3"; - import PositiveIntervals from "./positiveIntervals"; import BitArray from "./bitArray"; import { @@ -662,7 +660,31 @@ function polygonBoundingBox(polygon) { return [minX, minY, maxX, maxY]; } +/** + * withinPolygon determines if a point is within a polygon + * Code adapted from https://github.com/d3/d3-polygon/blob/master/src/contains.js + * @param {array} polygon - is an array of point arrays of format [[x1, y1], [x2, y2], ...] + * @param {float} x - point x coordinate + * @param {float} y - point y coordinate + * @type {boolean} + */ function withinPolygon(polygon, x, y) { - // TODO XXX replace - return polygonContains(polygon, [x, y]); + const n = polygon.length; + let p = polygon[n - 1]; + let x0 = p[0]; + let y0 = p[1]; + let x1; + let y1; + let inside = false; + + for (let i = 0; i < n; i += 1) { + p = polygon[i]; + x1 = p[0]; + y1 = p[1]; + + if (((y1 > y) !== (y0 > y)) && (x < (x0 - x1) * (y - y1) / (y0 - y1) + x1)) inside = !inside; + x0 = x1; + y0 = y1; + } + return inside; }