Skip to content

Commit

Permalink
adopt InternMap for ordinal scales (#237)
Browse files Browse the repository at this point in the history
* adopt InternMap for ordinal scales

* optimize

* order imports

Co-authored-by: Mike Bostock <mbostock@gmail.com>
  • Loading branch information
Fil and mbostock authored Jun 5, 2021
1 parent ac30873 commit 120ad7a
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 21 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
},
"sideEffects": false,
"dependencies": {
"d3-array": "2.3.0 - 3",
"d3-array": "2.10.0 - 3",
"d3-format": "1 - 3",
"d3-interpolate": "1.2.0 - 3",
"d3-time": "2.1.1 - 3",
Expand Down
18 changes: 9 additions & 9 deletions src/ordinal.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
import {InternMap} from "d3-array";
import {initRange} from "./init.js";

export const implicit = Symbol("implicit");

export default function ordinal() {
var index = new Map(),
var index = new InternMap(),
domain = [],
range = [],
unknown = implicit;

function scale(d) {
var key = d + "", i = index.get(key);
if (!i) {
let i = index.get(d);
if (i === undefined) {
if (unknown !== implicit) return unknown;
index.set(key, i = domain.push(d));
index.set(d, i = domain.push(d) - 1);
}
return range[(i - 1) % range.length];
return range[i % range.length];
}

scale.domain = function(_) {
if (!arguments.length) return domain.slice();
domain = [], index = new Map();
domain = [], index = new InternMap();
for (const value of _) {
const key = value + "";
if (index.has(key)) continue;
index.set(key, domain.push(value));
if (index.has(value)) continue;
index.set(value, domain.push(value) - 1);
}
return scale;
};
Expand Down
48 changes: 38 additions & 10 deletions test/ordinal-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ it("scaleOrdinal() has the expected defaults", () => {
});

it("ordinal(x) maps a unique name x in the domain to the corresponding value y in the range", () => {
const s = scaleOrdinal().domain([0, 1]).range(["foo", "bar"]);
const s = scaleOrdinal().domain([0, 1]).range(["foo", "bar"]).unknown(undefined);
assert.strictEqual(s(0), "foo");
assert.strictEqual(s(1), "bar");
s.range(["a", "b", "c"]);
assert.strictEqual(s(0), "a");
assert.strictEqual(s("0"), "a");
assert.strictEqual(s([0]), "a");
assert.strictEqual(s("0"), undefined);
assert.strictEqual(s([0]), undefined);
assert.strictEqual(s(1), "b");
assert.strictEqual(s(2.0), "c");
assert.strictEqual(s(new Number(2)), "c");
assert.strictEqual(s(new Number(1)), "b");
assert.strictEqual(s(2), undefined);
});

it("ordinal(x) implicitly extends the domain when a range is explicitly specified", () => {
Expand Down Expand Up @@ -59,16 +59,16 @@ it("ordinal.domain() replaces previous domain values", () => {
assert.strictEqual(s(0), "bar");
assert.deepStrictEqual(s.domain(), [1, 0]);
s.domain(["0", "1"]);
assert.strictEqual(s(0), "foo"); // it changed!
assert.strictEqual(s(1), "bar");
assert.strictEqual(s("0"), "foo"); // it changed!
assert.strictEqual(s("1"), "bar");
assert.deepStrictEqual(s.domain(), ["0", "1"]);
});

it("ordinal.domain() uniqueness is based on string coercion", () => {
it("ordinal.domain() uniqueness is based on primitive coercion", () => {
const s = scaleOrdinal().domain(["foo"]).range([42, 43, 44]);
assert.strictEqual(s(new String("foo")), 42);
assert.strictEqual(s({toString: function() { return "foo"; }}), 42);
assert.strictEqual(s({toString: function() { return "bar"; }}), 43);
assert.strictEqual(s({valueOf: function() { return "foo"; }}), 42);
assert.strictEqual(s({valueOf: function() { return "bar"; }}), 43);
});

it("ordinal.domain() does not coerce domain values to strings", () => {
Expand All @@ -85,6 +85,34 @@ it("ordinal.domain() does not barf on object built-ins", () => {
assert.deepStrictEqual(s.domain(), ["__proto__", "hasOwnProperty"]);
});

it("ordinal() accepts dates", () => {
const s = scaleOrdinal();
s(new Date(1970, 2, 1));
s(new Date(2001, 4, 13));
s(new Date(1970, 2, 1));
s(new Date(2001, 4, 13));
assert.deepStrictEqual(s.domain(), [new Date(1970, 2, 1), new Date(2001, 4, 13)]);
});

it("ordinal.domain() accepts dates", () => {
const s = scaleOrdinal().domain([
new Date(1970, 2, 1),
new Date(2001, 4, 13),
new Date(1970, 2, 1),
new Date(2001, 4, 13)
]);
s(new Date(1970, 2, 1));
s(new Date(1999, 11, 31));
assert.deepStrictEqual(s.domain(), [new Date(1970, 2, 1), new Date(2001, 4, 13), new Date(1999, 11, 31)]);
});

it("ordinal.domain() does not barf on object built-ins", () => {
const s = scaleOrdinal().domain(["__proto__", "hasOwnProperty"]).range([42, 43]);
assert.strictEqual(s("__proto__"), 42);
assert.strictEqual(s("hasOwnProperty"), 43);
assert.deepStrictEqual(s.domain(), ["__proto__", "hasOwnProperty"]);
});

it("ordinal.domain() is ordered by appearance", () => {
const s = scaleOrdinal();
s("foo");
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ cross-spawn@^7.0.2:
shebang-command "^2.0.0"
which "^2.0.1"

"d3-array@2 - 3", "d3-array@2.3.0 - 3":
"d3-array@2 - 3", "d3-array@2.10.0 - 3":
version "3.0.1"
resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.0.1.tgz#ca45c263f5bb780ab5a34a6e1d3d5883fe4a8d14"
integrity sha512-l3Bh5o8RSoC3SBm5ix6ogaFW+J6rOUm42yOtZ2sQPCEvCqUMepeX7zgrlLLGIemxgOyo9s2CsWEidnLv5PwwRw==
Expand Down

0 comments on commit 120ad7a

Please sign in to comment.