diff --git a/README.md b/README.md index ef0dac6..dd41fac 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ You could display a hexagon for each non-empty bin as follows: svg.selectAll("path") .data(hexbin(points)) .enter().append("path") - .attr("d", function(d) { return "M" + d.x + "," + d.y + hexbin.hexagon(); }); + .attr("d", function(d) { return hexbin.hexagon([d.x, d.y]); }); ``` Alternatively, using a transform: @@ -61,9 +61,25 @@ svg.selectAll("path") This method ignores the hexbin’s [extent](#hexbin_extent); it may return bins outside the extent if necessary to contain the specified points. -# hexbin.hexagon([radius]) +# hexbin.add(point) -Returns the SVG path string for the hexagon centered at the origin ⟨0,0⟩. The path string is defined with relative coordinates such that you can easily translate the hexagon to the desired position. If *radius* is not specified, the hexbin’s [current radius](#hexbin_radius) is used. If *radius* is specified, a hexagon with the specified radius is returned; this is useful for area-encoded bivariate hexbins. +Adds the *point* and returns the hexbin generator. + +# hexbin.addAll(points) + +Adds the *points* and returns the hexbin generator. + +# hexbin.remove(point) + +Removes the *point*, and returns the hexbin generator. Empty bins are pruned. + +# hexbin.removeAll(points) + +Removes all the *points* and returns the hexbin generator. Empty bins are pruned. + +# hexbin.hexagon([radius][, translate]) + +Returns the SVG path string for the hexagon centered at the origin ⟨0,0⟩. If *translate* is specified, the path is translated. Otherwise, the path string is defined with relative coordinates. If *radius* is not specified, the hexbin’s [current radius](#hexbin_radius) is used. If *radius* is specified, a hexagon with the specified radius is returned; this is useful for area-encoded bivariate hexbins. # hexbin.centers() @@ -97,9 +113,17 @@ function y(d) { The *y*-coordinate accessor is used by [*hexbin*](#_hexbin) to compute the *y*-coordinate of each point. The default value assumes each point is specified as a two-element array of numbers [*x*, *y*]. +# hexbin.angle([angle]) + +If *angle* is specified, sets the angle of the hexagonal grid to the specified number, in degrees. If *angle* is not specified, returns the current angle, which defaults to 0 (pointy-topped hexagons). + +# hexbin.translate([translate]) + +If *translate* is specified, translates the hexagonal grid to the specified value [tx, ty]. If *translate* is not specified, returns the current translate, which defaults to [0, 0]. + # hexbin.radius([radius]) -If *radius* is specified, sets the radius of the hexagon to the specified number. If *radius* is not specified, returns the current radius, which defaults to 1. The hexagons are pointy-topped (rather than flat-topped); the width of each hexagon is *radius* × 2 × sin(π / 3) and the height of each hexagon is *radius* × 3 / 2. +If *radius* is specified, sets the radius of the hexagon to the specified number. If *radius* is not specified, returns the current radius, which defaults to 1. The width of each hexagon is *radius* × 2 × sin(π / 3) and the height of each hexagon is *radius* × 3 / 2. # hexbin.extent([extent]) @@ -113,3 +137,17 @@ If *size* is specified, sets the [extent](#hexbin_extent) to the specified bound hexbin.extent([[0, 0], [width, height]]); hexbin.size([width, height]); ``` + +# hexbin.context([context]) [<>](https://github.com/d3/d3-hexbin/blob/master/src/hexbin.js "Source") + +If *context* is specified, sets the current render context and returns the hexbin. If the *context* is null, hexbin.mesh and hexbin.hexagon will return SVG path strings; if the context is non-null, hexbin.mesh and hexbin.hexagon will instead call methods on the specified context to render geometry. The context must implement the following subset of the [CanvasRenderingContext2D API](https://www.w3.org/TR/2dcontext/#canvasrenderingcontext2d): + +* *context*.moveTo(*x*, *y*) +* *context*.lineTo(*x*, *y*) + +If a *context* is not specified, returns the current render context which defaults to null. + + +# hexbin.bin(point) [<>](https://github.com/d3/d3-hexbin/blob/master/src/hexbin.js "Source") + +Returns the bin that would contain the point if we added it. If there is no such bin, returns an empty array with properties *x* and *y*. That bin is not guaranteed to keep in sync with data additions and removals, or changes of parameters such as radius, angle and translate. \ No newline at end of file diff --git a/img/hexagons.png b/img/hexagons.png new file mode 100644 index 0000000..f9ee416 Binary files /dev/null and b/img/hexagons.png differ diff --git a/package.json b/package.json index abeff4b..20ee78c 100644 --- a/package.json +++ b/package.json @@ -30,10 +30,11 @@ "scripts": { "pretest": "rollup -c", "test": "tape 'test/**/*-test.js' && eslint src test", - "prepublishOnly": "rm -rf dist && yarn test", + "prepublishOnly": "rm -rf dist && yarn test && mkdir -p test/output && test/compare-images", "postpublish": "git push && git push --tags && cd ../d3.github.com && git pull && cp ../${npm_package_name}/dist/${npm_package_name}.js ${npm_package_name}.v${npm_package_version%%.*}.js && cp ../${npm_package_name}/dist/${npm_package_name}.min.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git add ${npm_package_name}.v${npm_package_version%%.*}.js ${npm_package_name}.v${npm_package_version%%.*}.min.js && git commit -m \"${npm_package_name} ${npm_package_version}\" && git push && cd - && zip -j dist/${npm_package_name}.zip -- LICENSE README.md dist/${npm_package_name}.js dist/${npm_package_name}.min.js" }, "devDependencies": { + "canvas": "1", "eslint": "6", "rollup": "1", "rollup-plugin-terser": "5", diff --git a/src/hexbin.js b/src/hexbin.js index c898b7f..913ba95 100644 --- a/src/hexbin.js +++ b/src/hexbin.js @@ -18,86 +18,206 @@ export default function() { y = pointY, r, dx, - dy; + dy, + tx = 0, + ty = 0, + angle = 0, + ca = 1, + sa = 0, + context = null, + binsById = {}, + bins = [], + unbinned = [], + dirty = false; + + // from pixels to grid + function transform(x, y) { + x -= tx; + y -= ty; + if (ca === 1) return [x, y]; + return [x * ca - y * sa, x * sa + y * ca]; + } + + // from grid to pixels + function untransform(x, y) { + if (ca === 1) return [x + tx, y + ty]; + return [x * ca + y * sa + tx, - x * sa + y * ca + ty]; + } function hexbin(points) { - var binsById = {}, bins = [], i, n = points.length; + if (points) { + binsById = {}; + bins.splice(0, bins.length); + unbinned.splice(0, unbinned.length); + addAll(points); + } else if (dirty) { + bins.forEach(function(bin) { + bin.forEach(function(d) { + unbinned.push(d); + }); + }); + binsById = {}; + bins.splice(0, bins.length); + } + addAll(unbinned); + unbinned.splice(0, unbinned.length); + dirty = false; + return bins; + } + + function getBin(px, py) { + var u = transform(px, py); + px = u[0]; + py = u[1]; + var pj = Math.round(py = py / dy), + pi = Math.round(px = px / dx - (pj & 1) / 2), + py1 = py - pj; + + if (Math.abs(py1) * 3 > 1) { + var px1 = px - pi, + pi2 = pi + (px < pi ? -1 : 1) / 2, + pj2 = pj + (py < pj ? -1 : 1), + px2 = px - pi2, + py2 = py - pj2; + if (px1 * px1 + py1 * py1 > px2 * px2 + py2 * py2) pi = pi2 + (pj & 1 ? 1 : -1) / 2, pj = pj2; + } + return [pi, pj]; + } + + function addOne(point, px, py) { + var b = getBin(px, py), pi = b[0], pj = b[1], id = b[0] + "-" + b[1], bin = binsById[id]; + if (bin) bin.push(point); + else { + bins.push(bin = binsById[id] = [point]); + var u = untransform((pi + (pj & 1) / 2) * dx, pj * dy); + bin.x = u[0]; + bin.y = u[1]; + } + } + + function addAll(points) { + var i, point, px, py, n = points.length; for (i = 0; i < n; ++i) { if (isNaN(px = +x.call(null, point = points[i], i, points)) || isNaN(py = +y.call(null, point, i, points))) continue; + addOne(point, px, py); + } + } - var point, - px, - py, - pj = Math.round(py = py / dy), - pi = Math.round(px = px / dx - (pj & 1) / 2), - py1 = py - pj; - - if (Math.abs(py1) * 3 > 1) { - var px1 = px - pi, - pi2 = pi + (px < pi ? -1 : 1) / 2, - pj2 = pj + (py < pj ? -1 : 1), - px2 = px - pi2, - py2 = py - pj2; - if (px1 * px1 + py1 * py1 > px2 * px2 + py2 * py2) pi = pi2 + (pj & 1 ? 1 : -1) / 2, pj = pj2; - } + function removeFromBin(point, bin) { + var i = bin.indexOf(point); + if (i > -1) { + bin.splice(i, 1); + } + } - var id = pi + "-" + pj, bin = binsById[id]; - if (bin) bin.push(point); - else { - bins.push(bin = binsById[id] = [point]); - bin.x = (pi + (pj & 1) / 2) * dx; - bin.y = pj * dy; + function remove(point) { + var px, py; + if (isNaN(px = +x.call(null, point)) + || isNaN(py = +y.call(null, point))) return; + var b = getBin(px, py), id = b[0] + "-" + b[1], bin = binsById[id]; + removeFromBin(point, unbinned); + if (bin) { + removeFromBin(point, bin); + if (bin.length == 0) { + var i = bins.indexOf(bin); + if (i > -1) { + bins.splice(i, 1); + delete binsById[id]; + } } } - - return bins; } function hexagon(radius) { - var x0 = 0, y0 = 0; - return angles.map(function(angle) { - var x1 = Math.sin(angle) * radius, - y1 = -Math.cos(angle) * radius, - dx = x1 - x0, - dy = y1 - y0; - x0 = x1, y0 = y1; - return [dx, dy]; + return angles.map(function(a) { + a -= angle / 180 * Math.PI; + return [ Math.sin(a) * radius, -Math.cos(a) * radius ]; }); } + + function vectors(points) { + for (var i = points.length - 1; i > 0; i--) { + points[i][0] -= points[i-1][0]; + points[i][1] -= points[i-1][1]; + } + } - hexbin.hexagon = function(radius) { - return "m" + hexagon(radius == null ? r : +radius).join("l") + "z"; + hexbin.hexagon = function(radius, translate) { + if (typeof radius == "object") { + var tmp = translate; + translate = radius; + radius = tmp; + } + var points = hexagon(radius == null ? r : +radius); + if (!context) { + vectors(points); + return (translate ? "M" + translate : "") + "m" + points.join("l") + "z"; + } + if (translate == null) translate = [0, 0]; + context.moveTo(translate[0] + points[0][0], translate[1] + points[0][1]); + for (var i = 1; i < 6; i++) + context.lineTo(translate[0] + points[i][0], translate[1] + points[i][1]); }; hexbin.centers = function() { - var centers = [], - j = Math.round(y0 / dy), - i = Math.round(x0 / dx); - for (var y = j * dy; y < y1 + r; y += dy, ++j) { - for (var x = i * dx + (j & 1) * dx / 2; x < x1 + dx / 2; x += dx) { - centers.push([x, y]); + var u00 = transform(x0, y0), tx00 = u00[0], ty00 = u00[1], + u10 = transform(x1, y0), tx10 = u10[0], ty10 = u10[1], + u01 = transform(x0, y1), tx01 = u01[0], ty01 = u01[1], + u11 = transform(x1, y1), tx11 = u11[0], ty11 = u11[1], + tx0 = Math.min(tx00, tx01, tx10, tx11), + ty0 = Math.min(ty00, ty01, ty10, ty11), + tx1 = Math.max(tx00, tx01, tx10, tx11), + ty1 = Math.max(ty00, ty01, ty10, ty11), + centers = [], + j = Math.floor(ty0 / dy), + i = Math.floor(tx0 / dx); + + for (var y = j * dy; y < ty1 + r; y += dy, ++j) { + for (var x = i * dx + (j & 1) * dx / 2; x < tx1 + dx / 2; x += dx) { + var u = untransform(x, y), ux = u[0], uy = u[1]; + if (ux >= x0 - dx && ux <= x1 + dx && uy >= y0 - dy && uy <= y1 + dy) + centers.push([ux, uy]); } } return centers; }; hexbin.mesh = function() { - var fragment = hexagon(r).slice(0, 4).join("l"); - return hexbin.centers().map(function(p) { return "M" + p + "m" + fragment; }).join(""); + var points = hexagon(r).slice(0, 4), + centers = hexbin.centers(); + if (!context) { + vectors(points); + var fragment = points.join("l"); + return centers.map(function(p) { return "M" + p + "m" + fragment; }).join(""); + } + for (var i = 0, l = centers.length; i < l; i++) { + var x0 = centers[i][0], y0 = centers[i][1]; + context.moveTo(x0 + points[0][0], y0 + points[0][1]); + for (var j = 1; j < 4; j++) + context.lineTo(x0 + points[j][0], y0 + points[j][1]); + } + }; + + hexbin.angle = function(_) { + return arguments.length ? (angle = _, ca = Math.cos(angle * Math.PI/180), sa = Math.sin(angle * Math.PI/180), dirty = true, hexbin) : angle; + }; + + hexbin.translate = function(_) { + return arguments.length ? (tx = _[0], ty = _[1], dirty = true, hexbin) : [tx, ty]; }; hexbin.x = function(_) { - return arguments.length ? (x = _, hexbin) : x; + return arguments.length ? (x = _, dirty = true, hexbin) : x; }; hexbin.y = function(_) { - return arguments.length ? (y = _, hexbin) : y; + return arguments.length ? (y = _, dirty = true, hexbin) : y; }; hexbin.radius = function(_) { - return arguments.length ? (r = +_, dx = r * 2 * Math.sin(thirdPi), dy = r * 1.5, hexbin) : r; + return arguments.length ? (r = +_, dx = r * 2 * Math.sin(thirdPi), dy = r * 1.5, dirty = true, hexbin) : r; }; hexbin.size = function(_) { @@ -108,5 +228,47 @@ export default function() { return arguments.length ? (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1], hexbin) : [[x0, y0], [x1, y1]]; }; + hexbin.context = function(_) { + return arguments.length ? (context = _, hexbin) : context; + } + + hexbin.bin = function(point) { + var px, py; + if (isNaN(px = +x.call(null, point)) + || isNaN(py = +y.call(null, point))) return; + var b = getBin(px, py), pi = b[0], pj = b[1], id = b[0] + "-" + b[1], bin = binsById[id]; + if (!bin) { + bin = []; + var u = untransform((pi + (pj & 1) / 2) * dx, pj * dy); + bin.x = u[0]; + bin.y = u[1]; + } + return bin; + } + + hexbin.add = function(point) { + unbinned.push(point); + dirty = true; + return hexbin; + } + + hexbin.addAll = function(points) { + points.forEach(function(point) { + unbinned.push(point); + }); + dirty = true; + return hexbin; + } + + hexbin.remove = function(point) { + remove(point); + return hexbin; + } + + hexbin.removeAll = function(points) { + for (var i = 0, l = points.length; i < l; i++) remove(points[i]); + return hexbin; + } + return hexbin.radius(1); } diff --git a/test/compare-images b/test/compare-images new file mode 100755 index 0000000..fd7628a --- /dev/null +++ b/test/compare-images @@ -0,0 +1,16 @@ +#!/bin/bash + +for i in hexagons; do + test/render-canvas $i > test/output/$i.png \ + && [ "$(gm compare -metric rmse img/$i.png test/output/$i.png 2>&1)" = "Image Difference (RootMeanSquaredError): + Normalized Absolute + ============ ========== + Red: 0.0000000000 0.0 + Green: 0.0000000000 0.0 + Blue: 0.0000000000 0.0 + Total: 0.0000000000 0.0" ] \ + && echo -e "\x1B[1;32m✓ $2\x1B[0mtest/output/$i.png" \ + && rm -f -- test/output/$i-difference.png \ + || (gm compare -type TrueColor -highlight-style assign -highlight-color red -file test/output/$i-difference.png test/output/$i.png img/$i.png; \ + echo -e "\x1B[1;31m✗ $2\x1B[0mtest/output/$i.png\n test/output/$i-difference.png") +done diff --git a/test/hexbin-test.js b/test/hexbin-test.js index 4626e8a..67c0581 100644 --- a/test/hexbin-test.js +++ b/test/hexbin-test.js @@ -153,20 +153,7 @@ tape("hexbin.centers() observes the current bin radius", function(test) { }); tape("hexbin.centers() observes the current extent", function(test) { - test.deepEqual(d3.hexbin().radius(0.5).extent([[-1.1, -1.1], [1.1, 1.1]]).centers(), [ - [-0.4330127018922193, -0.75], - [0.4330127018922193, -0.75], - [1.299038105676658, -0.75], - [-0.8660254037844386, 0], - [0, 0], - [0.8660254037844386, 0], - [-0.4330127018922193, 0.75], - [0.4330127018922193, 0.75], - [1.299038105676658, 0.75], - [-0.8660254037844386, 1.5], - [0, 1.5], - [0.8660254037844386, 1.5] - ]); + test.deepEqual(d3.hexbin().radius(0.5).extent([[-1.1, -1.1], [1.1, 1.1]]).centers(), [ [ -1.7320508075688772, -1.5 ], [ -0.8660254037844386, -1.5 ], [ 0, -1.5 ], [ 0.8660254037844386, -1.5 ], [ -1.299038105676658, -0.75 ], [ -0.4330127018922194, -0.75 ], [ 0.4330127018922192, -0.75 ], [ 1.2990381056766578, -0.75 ], [ -1.7320508075688772, 0 ], [ -0.8660254037844386, 0 ], [ 0, 0 ], [ 0.8660254037844386, 0 ], [ -1.299038105676658, 0.75 ], [ -0.4330127018922194, 0.75 ], [ 0.4330127018922192, 0.75 ], [ 1.2990381056766578, 0.75 ], [ -1.7320508075688772, 1.5 ], [ -0.8660254037844386, 1.5 ], [ 0, 1.5 ], [ 0.8660254037844386, 1.5 ] ]); test.end(); }); @@ -181,7 +168,66 @@ tape("hexbin.mesh() observes the bin radius", function(test) { }); tape("hexbin.mesh() observes the extent", function(test) { - test.pathEqual(d3.hexbin().radius(0.5).extent([[-1.1, -1.1], [1.1, 1.1]]).mesh(), "M-0.433013,-0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0.433013,-0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M1.299038,-0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M-0.866025,0m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0,0m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0.866025,0m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M-0.433013,0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0.433013,0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M1.299038,0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M-0.866025,1.500000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0,1.500000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0.866025,1.500000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000"); + test.pathEqual(d3.hexbin().radius(0.5).extent([[-1.1, -1.1], [1.1, 1.1]]).mesh(), "M-1.732051,-1.500000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M-0.866025,-1.500000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0,-1.500000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0.866025,-1.500000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M-1.299038,-0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M-0.433013,-0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0.433013,-0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M1.299038,-0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M-1.732051,0m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M-0.866025,0m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0,0m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0.866025,0m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M-1.299038,0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M-0.433013,0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0.433013,0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M1.299038,0.750000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M-1.732051,1.500000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M-0.866025,1.500000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0,1.500000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000M0.866025,1.500000m0,-0.500000l0.433013,0.250000l0,0.500000l-0.433013,0.250000"); + test.end(); +}); + +tape("hexbin.add() adds a point", function(test) { + var bins = d3.hexbin().add([0,0]).addAll([[0.1,0.1], [10,10]]).add([2,2])(), + expected = [[[0,0],[0.1,0.1]],[[10,10]],[[2,2]]]; + test.equal(JSON.stringify(bins), JSON.stringify(expected)); + test.end(); +}); + +tape("hexbin.remove() removes a point", function(test) { + var points = [[0,0], [1,1], [2,2]]; + var hexbin = d3.hexbin(), + expected = [ [[0,0]], [[2,2]] ]; + hexbin(points); + hexbin.remove(points[1]); + test.equal(JSON.stringify(hexbin()), JSON.stringify(expected)); + test.end(); +}); + +tape("hexbin.remove() doesn't remove a point that isn't there", function(test) { + var points = [[0,0], [1,1], [2,2]]; + var hexbin = d3.hexbin(), + expected = [ [[0,0]], [[1,1]] ]; + hexbin(points.slice(0,2)); + hexbin.remove(points[2]); + test.equal(JSON.stringify(hexbin()), JSON.stringify(expected)); + test.end(); +}); + +tape("hexbin.removeAll() removes several points", function(test) { + var points = [[0,0], [1,1], [2,2]]; + var hexbin = d3.hexbin(), + expected = [[[2,2]]]; + hexbin(points); + hexbin.removeAll(points.slice(0,2)); + test.equal(JSON.stringify(hexbin()), JSON.stringify(expected)); + test.end(); +}); + +tape("hexbin.removeAll() removes unbinned points", function(test) { + var points = [[0,0], [1,1], [2,2]]; + var hexbin = d3.hexbin().addAll(points).removeAll(points.slice(0,2)), + expected = [[[2,2]]]; + test.equal(JSON.stringify(hexbin()), JSON.stringify(expected)); + hexbin = d3.hexbin(); + hexbin(points) + hexbin.removeAll(points.slice(0,2)); + test.equal(JSON.stringify(hexbin()), JSON.stringify(expected)); + test.end(); +}); + +tape("hexbin.angle(…) returns the expected centers", function(test) { + test.deepEqual(d3.hexbin().radius(0.5).extent([[-1.1, -1.1], [1.1, 1.1]]).angle(90).centers().map(function(c) { + return c.map(function(p) { return +p.toFixed(4); }) + }), [ [ -1.5, 1.7321 ], [ -1.5, 0.866 ], [ -1.5, -0 ], [ -1.5, -0.866 ], [ -0.75, 1.299 ], [ -0.75, 0.433 ], [ -0.75, -0.433 ], [ -0.75, -1.299 ], [ -0, 1.7321 ], [ -0, 0.866 ], [ 0, 0 ], [ 0, -0.866 ], [ 0.75, 1.299 ], [ 0.75, 0.433 ], [ 0.75, -0.433 ], [ 0.75, -1.299 ], [ 1.5, 1.7321 ], [ 1.5, 0.866 ], [ 1.5, 0 ], [ 1.5, -0.866 ] ]); + test.deepEqual(d3.hexbin().radius(0.5).extent([[-1.1, -1.1], [1.1, 1.1]]).angle(45).centers().map(function(c) { + return c.map(function(p) { return +p.toFixed(4); }) + }), [ [ -1.8972, -1.2848 ], [ -1.673, -0.4483 ], [ -1.0607, -1.0607 ], [ -0.4483, -1.673 ], [ -1.4489, 0.3882 ], [ -0.8365, -0.2241 ], [ -0.2241, -0.8365 ], [ 0.3882, -1.4489 ], [ -1.2247, 1.2247 ], [ -0.6124, 0.6124 ], [ 0, 0 ], [ 0.6124, -0.6124 ], [ 1.2247, -1.2247 ], [ -0.3882, 1.4489 ], [ 0.2241, 0.8365 ], [ 0.8365, 0.2241 ], [ 1.4489, -0.3882 ], [ 0.4483, 1.673 ], [ 1.0607, 1.0607 ], [ 1.673, 0.4483 ] ]); test.end(); }); diff --git a/test/render-canvas b/test/render-canvas new file mode 100755 index 0000000..68ef42b --- /dev/null +++ b/test/render-canvas @@ -0,0 +1,39 @@ +#!/usr/bin/env node + +var width = 960, + height = 500, + Canvas = require("canvas"), + d3 = require("../"); + +var canvas = new Canvas(width, height), + context = canvas.getContext("2d"); + +var hexbin = d3.hexbin() + .radius(15) + .context(context) + .size([width, height]); + +const data = Array.from({length: 1000}, (_,i) => [ + width * (i * 96.367866757 % 1), + Math.floor(i * 96.367866757) % height +]); + +const bins = hexbin(data); + + +context.fillStyle = "#fff"; +context.fillRect(0, 0, width, height); + +context.beginPath(); +hexbin.mesh(); +context.stroke(); + +context.fillStyle = "#ddd"; +context.beginPath(); +for (var i = 0; i < bins.length; i++) { + var bin = bins[i]; + hexbin.hexagon(6 * Math.sqrt(bin.length), [bin.x, bin.y]); +} +context.fill(); + +canvas.pngStream().pipe(process.stdout); diff --git a/yarn.lock b/yarn.lock index 9990f59..34457ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,20 +23,20 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== -"@types/node@^12.6.2": - version "12.6.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.8.tgz#e469b4bf9d1c9832aee4907ba8a051494357c12c" - integrity sha512-aX+gFgA5GHcDi89KG5keey2zf0WfZk/HAQotEamsK2kbey+8yGKcson0hbK8E+v0NArlCJQCqMP161YhV6ZXLg== +"@types/node@^12.7.2": + version "12.7.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.3.tgz#27b3f40addaf2f580459fdb405222685542f907a" + integrity sha512-3SiLAIBkDWDg6vFo0+5YJyHPWU9uwu40Qe+v+0MH8wRKYBimHvvAOyk3EzMrD/TrIlLYfXrqDqrg913PynrMJQ== -acorn-jsx@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" - integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== +acorn-jsx@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f" + integrity sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw== -acorn@^6.0.7, acorn@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.1.tgz#3ed8422d6dec09e6121cc7a843ca86a330a86b51" - integrity sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q== +acorn@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.0.0.tgz#26b8d1cd9a9b700350b71c0905546f64d1284e7a" + integrity sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ== ajv@^6.10.0, ajv@^6.10.2: version "6.10.2" @@ -105,6 +105,13 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +canvas@1: + version "1.6.13" + resolved "https://registry.yarnpkg.com/canvas/-/canvas-1.6.13.tgz#8cb4e9abbea9e615a377890ffac50277a1167c73" + integrity sha512-XAfzfEOHZ3JIPjEV+WSI6PpISgUta3dgmndWbsajotz+0TQOX/jDpp2kawjRERatOGv9sMMzk5auB3GKEKA6hg== + dependencies: + nan "^2.10.0" + chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -153,11 +160,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -211,16 +213,20 @@ emoji-regex@^7.0.1: integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== es-abstract@^1.5.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9" - integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg== + version "1.14.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.14.0.tgz#f59d9d44278ea8f90c8ff3de1552537c2fd739b4" + integrity sha512-lri42nNq1tIohUuwFBYEM3wKwcrcJa78jukGDdWsuaNxTtxBFGFkKUQ15nc9J+ipje4mhbQR6JwABb4VvawR3A== dependencies: es-to-primitive "^1.2.0" function-bind "^1.1.1" has "^1.0.3" + has-symbols "^1.0.0" is-callable "^1.1.4" is-regex "^1.0.4" - object-keys "^1.0.12" + object-inspect "^1.6.0" + object-keys "^1.1.1" + string.prototype.trimleft "^2.0.0" + string.prototype.trimright "^2.0.0" es-to-primitive@^1.2.0: version "1.2.0" @@ -244,22 +250,22 @@ eslint-scope@^5.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-utils@^1.3.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.0.tgz#e2c3c8dba768425f897cf0f9e51fe2e241485d4c" - integrity sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ== +eslint-utils@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" + integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q== dependencies: eslint-visitor-keys "^1.0.0" -eslint-visitor-keys@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" - integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ== +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" + integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== eslint@6: - version "6.1.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.1.0.tgz#06438a4a278b1d84fb107d24eaaa35471986e646" - integrity sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ== + version "6.3.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.3.0.tgz#1f1a902f67bfd4c354e7288b81e40654d927eb6a" + integrity sha512-ZvZTKaqDue+N8Y9g0kp6UPZtS4FSY3qARxBs7p4f0H0iof381XHduqVerFWtK8DPtKmemqbqCFENWSQgPR/Gow== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -268,9 +274,9 @@ eslint@6: debug "^4.0.1" doctrine "^3.0.0" eslint-scope "^5.0.0" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^6.0.0" + eslint-utils "^1.4.2" + eslint-visitor-keys "^1.1.0" + espree "^6.1.1" esquery "^1.0.1" esutils "^2.0.2" file-entry-cache "^5.0.1" @@ -299,14 +305,14 @@ eslint@6: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.0.0.tgz#716fc1f5a245ef5b9a7fdb1d7b0d3f02322e75f6" - integrity sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q== +espree@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de" + integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ== dependencies: - acorn "^6.0.7" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" + acorn "^7.0.0" + acorn-jsx "^5.0.2" + eslint-visitor-keys "^1.1.0" esprima@^4.0.0: version "4.0.1" @@ -328,9 +334,9 @@ esrecurse@^4.1.0: estraverse "^4.1.0" estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estree-walker@^0.6.1: version "0.6.1" @@ -338,9 +344,9 @@ estree-walker@^0.6.1: integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== esutils@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" - integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== external-editor@^3.0.3: version "3.1.0" @@ -490,15 +496,15 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@~2.0.3, inherits@~2.0.4: +inherits@2, inherits@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== inquirer@^6.4.1: - version "6.5.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42" - integrity sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA== + version "6.5.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== dependencies: ansi-escapes "^3.2.0" chalk "^2.4.2" @@ -560,22 +566,17 @@ is-symbol@^1.0.2: dependencies: has-symbols "^1.0.0" -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= jest-worker@^24.6.0: - version "24.6.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.6.0.tgz#7f81ceae34b7cde0c9827a6980c35b7cdc0161b3" - integrity sha512-jDwgW5W9qGNvpI1tNnvajh0a5IE/PuGLFmHk6aR/BZFz8tSgGw17GsDPXAJ6p91IvYDjOw8GpFbvvZGAK+DPQQ== + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" + integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== dependencies: - merge-stream "^1.0.1" + merge-stream "^2.0.0" supports-color "^6.1.0" js-tokens@^4.0.0: @@ -614,12 +615,10 @@ lodash@^4.17.12, lodash@^4.17.14: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== -merge-stream@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" - integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE= - dependencies: - readable-stream "^2.0.1" +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== mimic-fn@^1.0.0: version "1.2.0" @@ -660,6 +659,11 @@ mute-stream@0.0.7: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= +nan@^2.10.0: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -670,12 +674,12 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -object-inspect@~1.6.0: +object-inspect@^1.6.0, object-inspect@~1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== -object-keys@^1.0.12: +object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== @@ -738,11 +742,6 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -753,19 +752,6 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -readable-stream@^2.0.1: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" @@ -824,13 +810,13 @@ rollup-pluginutils@^2.8.1: estree-walker "^0.6.1" rollup@1: - version "1.17.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.17.0.tgz#47ee8b04514544fc93b39bae06271244c8db7dfa" - integrity sha512-k/j1m0NIsI4SYgCJR4MWPstGJOWfJyd6gycKoMhyoKPVXxm+L49XtbUwZyFsrSU2YXsOkM4u1ll9CS/ZgJBUpw== + version "1.20.3" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-1.20.3.tgz#6243f6c118ca05f56b2d9433112400cd834a1eb8" + integrity sha512-/OMCkY0c6E8tleeVm4vQVDz24CkVgvueK3r8zTYu2AQNpjrcaPwO9hE+pWj5LTFrvvkaxt4MYIp2zha4y0lRvg== dependencies: "@types/estree" "0.0.39" - "@types/node" "^12.6.2" - acorn "^6.2.0" + "@types/node" "^12.7.2" + acorn "^7.0.0" run-async@^2.2.0: version "2.3.0" @@ -846,20 +832,15 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - "safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== semver@^5.5.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" - integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== semver@^6.1.2: version "6.3.0" @@ -867,9 +848,9 @@ semver@^6.1.2: integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== serialize-javascript@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65" - integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA== + version "1.9.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.9.0.tgz#5b77019d7c3b85fe91b33ae424c53dcbfb6618bd" + integrity sha512-UkGlcYMtw4d9w7YfCtJFgdRTps8N4L0A48R+SmcGL57ki1+yHwJXnalk5bjgrw+ljv6SfzjzPjhohod2qllg/Q== shebang-command@^1.2.0: version "1.2.0" @@ -898,9 +879,9 @@ slice-ansi@^2.1.0: is-fullwidth-code-point "^2.0.0" source-map-support@~0.5.12: - version "0.5.12" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599" - integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ== + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -941,12 +922,21 @@ string.prototype.trim@~1.1.2: es-abstract "^1.5.0" function-bind "^1.0.2" -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== +string.prototype.trimleft@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.0.0.tgz#68b6aa8e162c6a80e76e3a8a0c2e747186e271ff" + integrity sha1-aLaqjhYsaoDnbjqKDC50cYbicf8= + dependencies: + define-properties "^1.1.2" + function-bind "^1.0.2" + +string.prototype.trimright@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.0.0.tgz#ab4a56d802a01fbe7293e11e84f24dc8164661dd" + integrity sha1-q0pW2AKgH75yk+EehPJNyBZGYd0= dependencies: - safe-buffer "~5.1.0" + define-properties "^1.1.2" + function-bind "^1.0.2" strip-ansi@^4.0.0: version "4.0.0" @@ -982,9 +972,9 @@ supports-color@^6.1.0: has-flag "^3.0.0" table@^5.2.3: - version "5.4.4" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.4.tgz#6e0f88fdae3692793d1077fd172a4667afe986a6" - integrity sha512-IIfEAUx5QlODLblLrGTTLJA7Tk0iLSGBvgY8essPRVNGHAzThujww1YqHLs6h3HfTg55h++RzLHH5Xw/rfv+mg== + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== dependencies: ajv "^6.10.2" lodash "^4.17.14" @@ -1011,9 +1001,9 @@ tape@4: through "~2.3.8" terser@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.1.2.tgz#b2656c8a506f7ce805a3f300a2ff48db022fa391" - integrity sha512-jvNoEQSPXJdssFwqPSgWjsOrb+ELoE+ILpHPKXC83tIxOlh2U75F1KuB2luLD/3a6/7K3Vw5pDn+hvu0C4AzSw== + version "4.2.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.2.1.tgz#1052cfe17576c66e7bc70fcc7119f22b155bdac1" + integrity sha512-cGbc5utAcX4a9+2GGVX4DsenG6v0x3glnDi5hx8816X1McEAwPlPgRtXPJzSBsbpILxZ8MQMT0KvArLuE0HP5A== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -1055,15 +1045,10 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - v8-compile-cache@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" - integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== + version "2.1.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" + integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== which@^1.2.9: version "1.3.1"