Skip to content

Commit

Permalink
perf: Speed up hit tests for points and markers
Browse files Browse the repository at this point in the history
If the range tree returns multiple points or markers that might be
within the search area, we were sorting them to maintain a stable
response order.  Javascript sort defaults to a lexical sort which casts
all values to strings, so we had been doing `points.sort((a, b) => a
- b)` to do a numerical sort, but this has a lot of function call
overhead and probably is casting each value between strings and numeric
datatypes.  Instead, we do `points = Uint32Array.from(points).sort();`
which uses native javascript functions and is much faster.
  • Loading branch information
manthey committed Dec 10, 2024
1 parent 0bf0d76 commit 901921f
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 9 deletions.
18 changes: 11 additions & 7 deletions src/markerFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ var markerFeature = function (arg) {
// Find markers inside the bounding box
idx = m_rangeTree.range(min.x, min.y, max.x, max.y);

idx.sort((a, b) => a - b);
idx = Uint32Array.from(idx).sort();
// Filter by circular region
idx.forEach(function (i) {
var d = data[i],
Expand Down Expand Up @@ -353,16 +353,20 @@ var markerFeature = function (arg) {
};
// Find markers inside the bounding box. Only these could be in the polygon
idx = m_rangeTree.range(min.x, min.y, max.x, max.y);
// sort by index
idx.sort((a, b) => a - b);
/* sort by index. This had been
* idx.sort((a, b) => a - b);
* but this requires continual casting from int to str and back, so using
* a Uint32Array is faster, though potentially limits the maximum number of
* markers. */
idx = Uint32Array.from(idx).sort();
// filter markers within the polygon
idx.forEach(function (i) {
var d = data[i];
let p = m_this.position()(d, i);
let rad = radius(data[i], i),
swz = scaleWithZoom(data[i], i);
const so = strokeOffset(data[i], i),
s = swz ? strokeWidth(data[i], i) : 0;
let rad = radius(d, i),
swz = scaleWithZoom(d, i);
const so = strokeOffset(d, i),
s = swz ? strokeWidth(d, i) : 0;
let ris = radiusIncludesStroke(d, i);
ris = ris === undefined ? true : ris;
const rwos = ris ? rad + s * (so - 1) / 2 : rad; // radius without stroke
Expand Down
4 changes: 2 additions & 2 deletions src/pointFeature.js
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ var pointFeature = function (arg) {
// Find points inside the bounding box
idx = m_rangeTree.range(min.x, min.y, max.x, max.y);

idx.sort((a, b) => a - b);
idx = Uint32Array.from(idx).sort();
// Filter by circular region
idx.forEach(function (i) {
var d = data[i],
Expand Down Expand Up @@ -434,7 +434,7 @@ var pointFeature = function (arg) {
// Find points inside the bounding box. Only these could be in the polygon
idx = m_rangeTree.range(min.x, min.y, max.x, max.y);
// sort by index
idx.sort((a, b) => a - b);
idx = Uint32Array.from(idx).sort();
// filter points within the polygon
idx.forEach(function (i) {
var d = data[i],
Expand Down

0 comments on commit 901921f

Please sign in to comment.