flocc 0.5.20 → 0.5.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/environments/Environment.d.ts +38 -0
- package/dist/flocc.es.js +377 -89
- package/dist/flocc.js +377 -89
- package/dist/renderers/CanvasRenderer.d.ts +58 -0
- package/package.json +1 -1
- package/dist/environments/NewEnvironment.d.ts +0 -76
- package/dist/helpers/BS.d.ts +0 -6
- package/dist/types/instanceOfPoint.d.ts +0 -2
- package/dist/types/isAgent.d.ts +0 -2
- package/dist/utils/copyArray.d.ts +0 -10
- package/dist/utils/lcg.d.ts +0 -1
- package/dist/utils/randomizeOrder.d.ts +0 -12
package/dist/flocc.js
CHANGED
|
@@ -3218,6 +3218,15 @@
|
|
|
3218
3218
|
* such as a {@linkcode LineChartRenderer}, {@linkcode Histogram}, etc.
|
|
3219
3219
|
*/
|
|
3220
3220
|
_this.renderers = [];
|
|
3221
|
+
/**
|
|
3222
|
+
* Whether the `Environment` tick cycle is currently playing.
|
|
3223
|
+
* Use {@linkcode pause}, {@linkcode resume}, or {@linkcode toggle}
|
|
3224
|
+
* to control playback.
|
|
3225
|
+
* @since 0.5.22
|
|
3226
|
+
*/
|
|
3227
|
+
_this.playing = true;
|
|
3228
|
+
/** @hidden */
|
|
3229
|
+
_this._tickIntervalId = null;
|
|
3221
3230
|
/**
|
|
3222
3231
|
* This property will always equal the number of tick cycles that
|
|
3223
3232
|
* have passed since the `Environment` was created. If you call
|
|
@@ -3387,6 +3396,9 @@
|
|
|
3387
3396
|
* @since 0.0.5
|
|
3388
3397
|
*/
|
|
3389
3398
|
Environment.prototype.tick = function (opts) {
|
|
3399
|
+
// If paused, skip the tick cycle (use `step()` to advance manually)
|
|
3400
|
+
if (!this.playing)
|
|
3401
|
+
return;
|
|
3390
3402
|
var _a = this._getTickOptions(opts), activation = _a.activation, activationCount = _a.activationCount, count = _a.count, randomizeOrder = _a.randomizeOrder;
|
|
3391
3403
|
// for uniform activation, every agent is always activated
|
|
3392
3404
|
if (activation === "uniform") {
|
|
@@ -3454,6 +3466,47 @@
|
|
|
3454
3466
|
}
|
|
3455
3467
|
this.renderers.forEach(function (r) { return r.render(); });
|
|
3456
3468
|
};
|
|
3469
|
+
/**
|
|
3470
|
+
* Pause the tick cycle. While paused, calling {@linkcode tick} will
|
|
3471
|
+
* be a no-op unless you use {@linkcode step} to advance manually.
|
|
3472
|
+
* @since 0.5.22
|
|
3473
|
+
*/
|
|
3474
|
+
Environment.prototype.pause = function () {
|
|
3475
|
+
this.playing = false;
|
|
3476
|
+
};
|
|
3477
|
+
/**
|
|
3478
|
+
* Resume the tick cycle after it has been paused.
|
|
3479
|
+
* @since 0.5.22
|
|
3480
|
+
*/
|
|
3481
|
+
Environment.prototype.resume = function () {
|
|
3482
|
+
this.playing = true;
|
|
3483
|
+
};
|
|
3484
|
+
/**
|
|
3485
|
+
* Toggle the tick cycle between playing and paused.
|
|
3486
|
+
* @since 0.5.22
|
|
3487
|
+
*/
|
|
3488
|
+
Environment.prototype.toggle = function () {
|
|
3489
|
+
this.playing = !this.playing;
|
|
3490
|
+
};
|
|
3491
|
+
/**
|
|
3492
|
+
* Advance the `Environment` by exactly one tick, regardless of whether
|
|
3493
|
+
* it is paused. This is useful for stepping through the simulation
|
|
3494
|
+
* frame-by-frame while paused.
|
|
3495
|
+
*
|
|
3496
|
+
* ```js
|
|
3497
|
+
* environment.pause();
|
|
3498
|
+
* environment.step(); // advances one tick
|
|
3499
|
+
* ```
|
|
3500
|
+
*
|
|
3501
|
+
* @since 0.5.22
|
|
3502
|
+
*/
|
|
3503
|
+
Environment.prototype.step = function (opts) {
|
|
3504
|
+
// Temporarily mark as playing so tick executes, then restore
|
|
3505
|
+
var wasPlaying = this.playing;
|
|
3506
|
+
this.playing = true;
|
|
3507
|
+
this.tick(opts);
|
|
3508
|
+
this.playing = wasPlaying;
|
|
3509
|
+
};
|
|
3457
3510
|
/**
|
|
3458
3511
|
* Use a helper with this environment. A helper can be one of:
|
|
3459
3512
|
* - {@linkcode KDTree}
|
|
@@ -3990,7 +4043,10 @@
|
|
|
3990
4043
|
width: 500,
|
|
3991
4044
|
height: 500,
|
|
3992
4045
|
scale: 1,
|
|
3993
|
-
trace: false
|
|
4046
|
+
trace: false,
|
|
4047
|
+
interactive: false,
|
|
4048
|
+
zoomMin: 0.1,
|
|
4049
|
+
zoomMax: 10
|
|
3994
4050
|
};
|
|
3995
4051
|
/**
|
|
3996
4052
|
* A `CanvasRenderer` renders an {@linkcode Environment} spatially in two dimensions.
|
|
@@ -4010,6 +4066,12 @@
|
|
|
4010
4066
|
* - `"triangle"` — Draws a triangle centered at the `Agent`'s `"x"` / `"y"` values.
|
|
4011
4067
|
* - Also uses the `"size"` value.
|
|
4012
4068
|
*
|
|
4069
|
+
* When `interactive` is set to `true` in the options, the renderer supports:
|
|
4070
|
+
* - **Click/hover detection** — Use {@linkcode on} to listen for `"click"`, `"hover"`, and `"unhover"` events on agents.
|
|
4071
|
+
* - **Agent selection** — Clicking an agent selects it (highlighted with a stroke). Access selected agents via {@linkcode selected}.
|
|
4072
|
+
* - **Pan** — Click and drag on empty space to pan.
|
|
4073
|
+
* - **Zoom** — Scroll to zoom in/out (bounded by `zoomMin` / `zoomMax`).
|
|
4074
|
+
*
|
|
4013
4075
|
* @since 0.0.11
|
|
4014
4076
|
*/
|
|
4015
4077
|
var CanvasRenderer = /** @class */ (function (_super) {
|
|
@@ -4025,15 +4087,33 @@
|
|
|
4025
4087
|
* - `connectionOpacity` (*number* = `1`) — For `Environment`s using a `Network`, the opacity of lines
|
|
4026
4088
|
* - `connectionWidth` (*number* = `1`) — For `Environment`s using a `Network`, the width of lines
|
|
4027
4089
|
* - `height` (*number* = `500`) — The height, in pixels, of the canvas on which to render
|
|
4090
|
+
* - `interactive` (*boolean* = `false`) — Enables interactive features (click/hover detection, selection, pan, zoom)
|
|
4091
|
+
* - `onSelect` (*function*) — Optional callback when an agent is selected or deselected
|
|
4028
4092
|
* - `origin` (*{ x: number; y: number }* = `{ x: 0, y: 0 }`) — The coordinate of the upper-left point of the space to be rendered
|
|
4029
4093
|
* - `scale` (*number* = `1`) — The scale at which to render (the larger the scale, the smaller the size of the space that is actually rendered)
|
|
4030
4094
|
* - `trace` (*boolean* = `false`) — If `true`, the renderer will not clear old drawings, causing the `Agent`s to appear to *trace* their paths across space
|
|
4031
4095
|
* - `width` (*number* = `500`) — The width, in pixels, of the canvas on which to render
|
|
4096
|
+
* - `zoomMin` (*number* = `0.1`) — Minimum scale when zooming
|
|
4097
|
+
* - `zoomMax` (*number* = `10`) — Maximum scale when zooming
|
|
4032
4098
|
*/
|
|
4033
4099
|
function CanvasRenderer(environment, opts) {
|
|
4034
4100
|
var _this = _super.call(this) || this;
|
|
4035
4101
|
/** @hidden */
|
|
4036
4102
|
_this.terrainBuffer = document.createElement("canvas");
|
|
4103
|
+
/** The currently selected agents (only used when `interactive` is `true`). */
|
|
4104
|
+
_this.selected = [];
|
|
4105
|
+
/** @hidden */
|
|
4106
|
+
_this._listeners = new Map();
|
|
4107
|
+
/** @hidden */
|
|
4108
|
+
_this._hoveredAgent = null;
|
|
4109
|
+
/** @hidden */
|
|
4110
|
+
_this._isPanning = false;
|
|
4111
|
+
/** @hidden */
|
|
4112
|
+
_this._panStart = null;
|
|
4113
|
+
/** @hidden */
|
|
4114
|
+
_this._panOriginStart = null;
|
|
4115
|
+
/** @hidden */
|
|
4116
|
+
_this._boundHandlers = {};
|
|
4037
4117
|
_this.environment = environment;
|
|
4038
4118
|
environment.renderers.push(_this);
|
|
4039
4119
|
_this.opts = Object.assign({}, defaultOptions);
|
|
@@ -4050,9 +4130,158 @@
|
|
|
4050
4130
|
_this.terrainBuffer.width = width;
|
|
4051
4131
|
_this.terrainBuffer.height = height;
|
|
4052
4132
|
_this.context.fillStyle = opts.background;
|
|
4053
|
-
_this.context.fillRect(0, 0, width, height);
|
|
4133
|
+
_this.context.fillRect(0, 0, _this.width, _this.height);
|
|
4134
|
+
if (_this.opts.interactive) {
|
|
4135
|
+
_this._setupInteractiveListeners();
|
|
4136
|
+
}
|
|
4054
4137
|
return _this;
|
|
4055
4138
|
}
|
|
4139
|
+
/**
|
|
4140
|
+
* Register a callback for an interactive event.
|
|
4141
|
+
* Supported event names: `"click"`, `"hover"`, `"unhover"`.
|
|
4142
|
+
*
|
|
4143
|
+
* ```js
|
|
4144
|
+
* renderer.on("click", (agent, event) => {
|
|
4145
|
+
* console.log("Clicked agent:", agent.id);
|
|
4146
|
+
* });
|
|
4147
|
+
* ```
|
|
4148
|
+
*
|
|
4149
|
+
* @param eventName - The event to listen for.
|
|
4150
|
+
* @param callback - The callback, invoked with the `Agent` and the `MouseEvent`.
|
|
4151
|
+
*/
|
|
4152
|
+
CanvasRenderer.prototype.on = function (eventName, callback) {
|
|
4153
|
+
if (!this._listeners.has(eventName)) {
|
|
4154
|
+
this._listeners.set(eventName, []);
|
|
4155
|
+
}
|
|
4156
|
+
this._listeners.get(eventName).push(callback);
|
|
4157
|
+
};
|
|
4158
|
+
/** @hidden */
|
|
4159
|
+
CanvasRenderer.prototype._emit = function (eventName, agent, event) {
|
|
4160
|
+
var callbacks = this._listeners.get(eventName);
|
|
4161
|
+
if (callbacks) {
|
|
4162
|
+
callbacks.forEach(function (cb) { return cb(agent, event); });
|
|
4163
|
+
}
|
|
4164
|
+
};
|
|
4165
|
+
/**
|
|
4166
|
+
* Given a mouse event, return the agent at that position (if any).
|
|
4167
|
+
* Hit-testing accounts for the agent's shape and size.
|
|
4168
|
+
* @hidden
|
|
4169
|
+
*/
|
|
4170
|
+
CanvasRenderer.prototype._agentAtPoint = function (clientX, clientY) {
|
|
4171
|
+
var rect = this.canvas.getBoundingClientRect();
|
|
4172
|
+
var dpr = window.devicePixelRatio;
|
|
4173
|
+
var canvasX = (clientX - rect.left) * dpr;
|
|
4174
|
+
var canvasY = (clientY - rect.top) * dpr;
|
|
4175
|
+
var agents = this.environment.getAgents();
|
|
4176
|
+
// Iterate in reverse so topmost-drawn agent is found first
|
|
4177
|
+
for (var i = agents.length - 1; i >= 0; i--) {
|
|
4178
|
+
var agent = agents[i];
|
|
4179
|
+
var data = agent.getData();
|
|
4180
|
+
var ax = this.x(data.x);
|
|
4181
|
+
var ay = this.y(data.y);
|
|
4182
|
+
var shape = data.shape;
|
|
4183
|
+
var size = (data.size || 1) * dpr;
|
|
4184
|
+
if (shape === "rect") {
|
|
4185
|
+
var w = (data.width || 1) * dpr;
|
|
4186
|
+
var h = (data.height || 1) * dpr;
|
|
4187
|
+
var rx = ax - w / 2;
|
|
4188
|
+
var ry = ay - h / 2;
|
|
4189
|
+
if (canvasX >= rx && canvasX <= rx + w && canvasY >= ry && canvasY <= ry + h) {
|
|
4190
|
+
return agent;
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4193
|
+
else if (shape === "triangle") {
|
|
4194
|
+
// Simple bounding-box hit test for triangles
|
|
4195
|
+
var halfSize = size / 2;
|
|
4196
|
+
if (canvasX >= ax - halfSize &&
|
|
4197
|
+
canvasX <= ax + halfSize &&
|
|
4198
|
+
canvasY >= ay - halfSize &&
|
|
4199
|
+
canvasY <= ay + halfSize) {
|
|
4200
|
+
return agent;
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
else {
|
|
4204
|
+
// Default: circle (and arrow) — distance-based hit test
|
|
4205
|
+
var dx = canvasX - ax;
|
|
4206
|
+
var dy = canvasY - ay;
|
|
4207
|
+
var hitRadius = Math.max(size, 4 * dpr); // minimum hit area for tiny agents
|
|
4208
|
+
if (dx * dx + dy * dy <= hitRadius * hitRadius) {
|
|
4209
|
+
return agent;
|
|
4210
|
+
}
|
|
4211
|
+
}
|
|
4212
|
+
}
|
|
4213
|
+
return null;
|
|
4214
|
+
};
|
|
4215
|
+
/** @hidden */
|
|
4216
|
+
CanvasRenderer.prototype._setupInteractiveListeners = function () {
|
|
4217
|
+
var _this = this;
|
|
4218
|
+
var onMouseDown = function (e) {
|
|
4219
|
+
var agent = _this._agentAtPoint(e.clientX, e.clientY);
|
|
4220
|
+
if (agent) {
|
|
4221
|
+
// Agent click — select it
|
|
4222
|
+
_this.selected = [agent];
|
|
4223
|
+
if (_this.opts.onSelect)
|
|
4224
|
+
_this.opts.onSelect(agent);
|
|
4225
|
+
_this._emit("click", agent, e);
|
|
4226
|
+
_this.render();
|
|
4227
|
+
}
|
|
4228
|
+
else {
|
|
4229
|
+
// Empty space — deselect and start panning
|
|
4230
|
+
if (_this.selected.length > 0) {
|
|
4231
|
+
_this.selected = [];
|
|
4232
|
+
if (_this.opts.onSelect)
|
|
4233
|
+
_this.opts.onSelect(null);
|
|
4234
|
+
_this.render();
|
|
4235
|
+
}
|
|
4236
|
+
_this._isPanning = true;
|
|
4237
|
+
_this._panStart = { x: e.clientX, y: e.clientY };
|
|
4238
|
+
_this._panOriginStart = { x: _this.opts.origin.x, y: _this.opts.origin.y };
|
|
4239
|
+
}
|
|
4240
|
+
};
|
|
4241
|
+
var onMouseMove = function (e) {
|
|
4242
|
+
if (_this._isPanning && _this._panStart && _this._panOriginStart) {
|
|
4243
|
+
var dpr = window.devicePixelRatio;
|
|
4244
|
+
var dx = e.clientX - _this._panStart.x;
|
|
4245
|
+
var dy = e.clientY - _this._panStart.y;
|
|
4246
|
+
_this.opts.origin = {
|
|
4247
|
+
x: _this._panOriginStart.x - dx / (_this.opts.scale * dpr),
|
|
4248
|
+
y: _this._panOriginStart.y - dy / (_this.opts.scale * dpr)
|
|
4249
|
+
};
|
|
4250
|
+
_this.render();
|
|
4251
|
+
return;
|
|
4252
|
+
}
|
|
4253
|
+
// Hover detection
|
|
4254
|
+
var agent = _this._agentAtPoint(e.clientX, e.clientY);
|
|
4255
|
+
if (agent !== _this._hoveredAgent) {
|
|
4256
|
+
if (_this._hoveredAgent) {
|
|
4257
|
+
_this._emit("unhover", _this._hoveredAgent, e);
|
|
4258
|
+
}
|
|
4259
|
+
if (agent) {
|
|
4260
|
+
_this._emit("hover", agent, e);
|
|
4261
|
+
}
|
|
4262
|
+
_this._hoveredAgent = agent;
|
|
4263
|
+
}
|
|
4264
|
+
};
|
|
4265
|
+
var onMouseUp = function (e) {
|
|
4266
|
+
_this._isPanning = false;
|
|
4267
|
+
_this._panStart = null;
|
|
4268
|
+
_this._panOriginStart = null;
|
|
4269
|
+
};
|
|
4270
|
+
var onWheel = function (e) {
|
|
4271
|
+
e.preventDefault();
|
|
4272
|
+
var _a = _this.opts, zoomMin = _a.zoomMin, zoomMax = _a.zoomMax;
|
|
4273
|
+
var delta = e.deltaY > 0 ? 0.9 : 1.1;
|
|
4274
|
+
var newScale = _this.opts.scale * delta;
|
|
4275
|
+
newScale = Math.max(zoomMin, Math.min(zoomMax, newScale));
|
|
4276
|
+
_this.opts.scale = newScale;
|
|
4277
|
+
_this.render();
|
|
4278
|
+
};
|
|
4279
|
+
this._boundHandlers = { mousedown: onMouseDown, mousemove: onMouseMove, mouseup: onMouseUp, wheel: onWheel };
|
|
4280
|
+
this.canvas.addEventListener("mousedown", onMouseDown);
|
|
4281
|
+
this.canvas.addEventListener("mousemove", onMouseMove);
|
|
4282
|
+
this.canvas.addEventListener("mouseup", onMouseUp);
|
|
4283
|
+
this.canvas.addEventListener("wheel", onWheel, { passive: false });
|
|
4284
|
+
};
|
|
4056
4285
|
/** @hidden */
|
|
4057
4286
|
CanvasRenderer.prototype.x = function (v) {
|
|
4058
4287
|
var _a = this.opts, origin = _a.origin, scale = _a.scale;
|
|
@@ -4089,21 +4318,21 @@
|
|
|
4089
4318
|
};
|
|
4090
4319
|
/** @hidden */
|
|
4091
4320
|
CanvasRenderer.prototype.drawPathWrap = function (points) {
|
|
4092
|
-
var _this = this;
|
|
4093
4321
|
var _a = this, width = _a.width, height = _a.height;
|
|
4094
4322
|
var right = false;
|
|
4095
4323
|
var left = false;
|
|
4096
4324
|
var lower = false;
|
|
4097
4325
|
var upper = false;
|
|
4326
|
+
// points are already in DPR-scaled pixel space, so compare directly
|
|
4098
4327
|
points.forEach(function (_a) {
|
|
4099
4328
|
var px = _a[0], py = _a[1];
|
|
4100
|
-
if (
|
|
4329
|
+
if (px >= width)
|
|
4101
4330
|
right = true;
|
|
4102
|
-
if (
|
|
4331
|
+
if (px < 0)
|
|
4103
4332
|
left = true;
|
|
4104
|
-
if (
|
|
4333
|
+
if (py >= height)
|
|
4105
4334
|
lower = true;
|
|
4106
|
-
if (
|
|
4335
|
+
if (py < 0)
|
|
4107
4336
|
upper = true;
|
|
4108
4337
|
});
|
|
4109
4338
|
if (right)
|
|
@@ -4132,24 +4361,26 @@
|
|
|
4132
4361
|
/** @hidden */
|
|
4133
4362
|
CanvasRenderer.prototype.drawCircleWrap = function (x, y, size) {
|
|
4134
4363
|
var _a = this, width = _a.width, height = _a.height;
|
|
4364
|
+
var worldWidth = this.opts.width;
|
|
4365
|
+
var worldHeight = this.opts.height;
|
|
4135
4366
|
if (this.x(x + size) >= width) {
|
|
4136
|
-
this.drawCircle(x -
|
|
4367
|
+
this.drawCircle(x - worldWidth, y, size);
|
|
4137
4368
|
if (this.y(y + size) >= height)
|
|
4138
|
-
this.drawCircle(x -
|
|
4369
|
+
this.drawCircle(x - worldWidth, y - worldHeight, size);
|
|
4139
4370
|
if (this.y(y - size) < 0)
|
|
4140
|
-
this.drawCircle(x -
|
|
4371
|
+
this.drawCircle(x - worldWidth, y + worldHeight, size);
|
|
4141
4372
|
}
|
|
4142
4373
|
if (this.x(x - size) < 0) {
|
|
4143
|
-
this.drawCircle(x +
|
|
4374
|
+
this.drawCircle(x + worldWidth, y, size);
|
|
4144
4375
|
if (this.y(y + size) >= height)
|
|
4145
|
-
this.drawCircle(x +
|
|
4376
|
+
this.drawCircle(x + worldWidth, y - worldHeight, size);
|
|
4146
4377
|
if (this.y(y - size) < 0)
|
|
4147
|
-
this.drawCircle(x +
|
|
4378
|
+
this.drawCircle(x + worldWidth, y + worldHeight, size);
|
|
4148
4379
|
}
|
|
4149
4380
|
if (this.y(y + size) > height)
|
|
4150
|
-
this.drawCircle(x, y -
|
|
4381
|
+
this.drawCircle(x, y - worldHeight, size);
|
|
4151
4382
|
if (this.y(y - size) < 0)
|
|
4152
|
-
this.drawCircle(x, y +
|
|
4383
|
+
this.drawCircle(x, y + worldHeight, size);
|
|
4153
4384
|
};
|
|
4154
4385
|
/**
|
|
4155
4386
|
* Draw a rectangle centered at (x, y). Automatically calculates the offset
|
|
@@ -4163,25 +4394,55 @@
|
|
|
4163
4394
|
};
|
|
4164
4395
|
/** @hidden */
|
|
4165
4396
|
CanvasRenderer.prototype.drawRectWrap = function (x, y, w, h) {
|
|
4166
|
-
var _a = this
|
|
4397
|
+
var _a = this, width = _a.width, height = _a.height;
|
|
4398
|
+
var worldWidth = this.opts.width;
|
|
4399
|
+
var worldHeight = this.opts.height;
|
|
4167
4400
|
if (this.x(x + w / 2) >= width) {
|
|
4168
|
-
this.drawRect(x -
|
|
4401
|
+
this.drawRect(x - worldWidth, y, w, h);
|
|
4169
4402
|
if (this.y(y + h / 2) >= height)
|
|
4170
|
-
this.drawRect(x -
|
|
4171
|
-
if (this.y(y -
|
|
4172
|
-
this.drawRect(x -
|
|
4403
|
+
this.drawRect(x - worldWidth, y - worldHeight, w, h);
|
|
4404
|
+
if (this.y(y - h / 2) < 0)
|
|
4405
|
+
this.drawRect(x - worldWidth, y + worldHeight, w, h);
|
|
4173
4406
|
}
|
|
4174
4407
|
if (this.x(x - w / 2) < 0) {
|
|
4175
|
-
this.drawRect(x +
|
|
4408
|
+
this.drawRect(x + worldWidth, y, w, h);
|
|
4176
4409
|
if (this.y(y + h / 2) >= height)
|
|
4177
|
-
this.drawRect(x +
|
|
4178
|
-
if (this.y(y -
|
|
4179
|
-
this.drawRect(x +
|
|
4410
|
+
this.drawRect(x + worldWidth, y - worldHeight, w, h);
|
|
4411
|
+
if (this.y(y - h / 2) < 0)
|
|
4412
|
+
this.drawRect(x + worldWidth, y + worldHeight, w, h);
|
|
4180
4413
|
}
|
|
4181
4414
|
if (this.y(y + h / 2) > height)
|
|
4182
|
-
this.drawRect(x, y -
|
|
4183
|
-
if (this.y(y -
|
|
4184
|
-
this.drawRect(x, y +
|
|
4415
|
+
this.drawRect(x, y - worldHeight, w, h);
|
|
4416
|
+
if (this.y(y - h / 2) < 0)
|
|
4417
|
+
this.drawRect(x, y + worldHeight, w, h);
|
|
4418
|
+
};
|
|
4419
|
+
/**
|
|
4420
|
+
* Draw a selection highlight around the given agent.
|
|
4421
|
+
* @hidden
|
|
4422
|
+
*/
|
|
4423
|
+
CanvasRenderer.prototype._drawSelectionHighlight = function (agent) {
|
|
4424
|
+
var bufferContext = this.buffer.getContext("2d");
|
|
4425
|
+
var dpr = window.devicePixelRatio;
|
|
4426
|
+
var data = agent.getData();
|
|
4427
|
+
var ax = this.x(data.x);
|
|
4428
|
+
var ay = this.y(data.y);
|
|
4429
|
+
var shape = data.shape;
|
|
4430
|
+
var size = (data.size || 1) * dpr;
|
|
4431
|
+
bufferContext.save();
|
|
4432
|
+
bufferContext.strokeStyle = "#0af";
|
|
4433
|
+
bufferContext.lineWidth = 2 * dpr;
|
|
4434
|
+
if (shape === "rect") {
|
|
4435
|
+
var w = (data.width || 1) * dpr;
|
|
4436
|
+
var h = (data.height || 1) * dpr;
|
|
4437
|
+
bufferContext.strokeRect(ax - w / 2 - 2 * dpr, ay - h / 2 - 2 * dpr, w + 4 * dpr, h + 4 * dpr);
|
|
4438
|
+
}
|
|
4439
|
+
else {
|
|
4440
|
+
bufferContext.beginPath();
|
|
4441
|
+
var highlightRadius = Math.max(size, 4 * dpr) + 3 * dpr;
|
|
4442
|
+
bufferContext.arc(ax, ay, highlightRadius, 0, 2 * Math.PI);
|
|
4443
|
+
bufferContext.stroke();
|
|
4444
|
+
}
|
|
4445
|
+
bufferContext.restore();
|
|
4185
4446
|
};
|
|
4186
4447
|
CanvasRenderer.prototype.render = function () {
|
|
4187
4448
|
var _this = this;
|
|
@@ -4194,22 +4455,24 @@
|
|
|
4194
4455
|
// if "trace" is truthy, don't clear the canvas with every frame
|
|
4195
4456
|
// to trace the paths of agents
|
|
4196
4457
|
if (!trace) {
|
|
4197
|
-
context.clearRect(0, 0, width
|
|
4458
|
+
context.clearRect(0, 0, width, height);
|
|
4198
4459
|
context.fillStyle = opts.background;
|
|
4199
|
-
context.fillRect(0, 0, width
|
|
4460
|
+
context.fillRect(0, 0, width, height);
|
|
4200
4461
|
}
|
|
4201
4462
|
// automatically position agents in an environment that uses a network helper
|
|
4202
4463
|
if (opts.autoPosition && environment.helpers.network) {
|
|
4203
4464
|
environment.getAgents().forEach(function (agent) {
|
|
4204
4465
|
var network = _this.environment.helpers.network;
|
|
4205
|
-
|
|
4466
|
+
// Use CSS pixel dimensions (opts), not the DPI-scaled canvas dimensions,
|
|
4467
|
+
// since x() and y() already apply the devicePixelRatio transform.
|
|
4468
|
+
var _a = _this.opts, w = _a.width, h = _a.height;
|
|
4206
4469
|
// only set once
|
|
4207
4470
|
if ((agent.get("x") === null || agent.get("y") === null) &&
|
|
4208
4471
|
network.isInNetwork(agent)) {
|
|
4209
4472
|
var idx = network.indexOf(agent);
|
|
4210
4473
|
var angle = idx / network.agents.length;
|
|
4211
|
-
var x =
|
|
4212
|
-
var y =
|
|
4474
|
+
var x = w / 2 + 0.4 * w * Math.cos(2 * Math.PI * angle);
|
|
4475
|
+
var y = h / 2 + 0.4 * h * Math.sin(2 * Math.PI * angle);
|
|
4213
4476
|
agent.set({ x: x, y: y });
|
|
4214
4477
|
}
|
|
4215
4478
|
});
|
|
@@ -4254,8 +4517,8 @@
|
|
|
4254
4517
|
context.globalAlpha = _this.opts.connectionOpacity;
|
|
4255
4518
|
context.strokeStyle = _this.opts.connectionColor;
|
|
4256
4519
|
context.lineWidth = _this.opts.connectionWidth;
|
|
4257
|
-
context.moveTo(_this.x(x), _this.
|
|
4258
|
-
context.lineTo(_this.x(nx), _this.
|
|
4520
|
+
context.moveTo(_this.x(x), _this.y(y));
|
|
4521
|
+
context.lineTo(_this.x(nx), _this.y(ny));
|
|
4259
4522
|
context.stroke();
|
|
4260
4523
|
context.closePath();
|
|
4261
4524
|
context.restore();
|
|
@@ -4287,10 +4550,11 @@
|
|
|
4287
4550
|
}
|
|
4288
4551
|
else if (shape === "triangle") {
|
|
4289
4552
|
bufferContext.beginPath();
|
|
4553
|
+
var scaledSize = size * dpr;
|
|
4290
4554
|
var points = [
|
|
4291
|
-
[_this.x(x), _this.y(y) -
|
|
4292
|
-
[_this.x(x) +
|
|
4293
|
-
[_this.x(x) -
|
|
4555
|
+
[_this.x(x), _this.y(y) - scaledSize / 2],
|
|
4556
|
+
[_this.x(x) + scaledSize / 2, _this.y(y) + scaledSize / 2],
|
|
4557
|
+
[_this.x(x) - scaledSize / 2, _this.y(y) + scaledSize / 2]
|
|
4294
4558
|
];
|
|
4295
4559
|
_this.drawPath(points);
|
|
4296
4560
|
if (environment.opts.torus)
|
|
@@ -4316,6 +4580,12 @@
|
|
|
4316
4580
|
bufferContext.restore();
|
|
4317
4581
|
}
|
|
4318
4582
|
});
|
|
4583
|
+
// Draw selection highlights for selected agents
|
|
4584
|
+
if (opts.interactive && this.selected.length > 0) {
|
|
4585
|
+
this.selected.forEach(function (agent) {
|
|
4586
|
+
_this._drawSelectionHighlight(agent);
|
|
4587
|
+
});
|
|
4588
|
+
}
|
|
4319
4589
|
context.drawImage(buffer, 0, 0);
|
|
4320
4590
|
};
|
|
4321
4591
|
return CanvasRenderer;
|
|
@@ -4406,11 +4676,13 @@
|
|
|
4406
4676
|
};
|
|
4407
4677
|
Histogram.prototype.x = function (value) {
|
|
4408
4678
|
var _a = this, width = _a.width, markerWidth = _a.markerWidth;
|
|
4409
|
-
|
|
4679
|
+
var dpr = window.devicePixelRatio;
|
|
4680
|
+
return remap(value, 0, width, markerWidth + PADDING_AT_LEFT * dpr, width - PADDING_AT_RIGHT * dpr);
|
|
4410
4681
|
};
|
|
4411
4682
|
Histogram.prototype.y = function (value) {
|
|
4412
4683
|
var _a = this, height = _a.height, maxValue = _a.maxValue;
|
|
4413
|
-
|
|
4684
|
+
var dpr = window.devicePixelRatio;
|
|
4685
|
+
return remap(value, 0, maxValue, height - PADDING_AT_BOTTOM * dpr, 0);
|
|
4414
4686
|
};
|
|
4415
4687
|
Histogram.prototype.setMaxValue = function () {
|
|
4416
4688
|
var _this = this;
|
|
@@ -4439,11 +4711,12 @@
|
|
|
4439
4711
|
var context = this.canvas.getContext("2d");
|
|
4440
4712
|
var _a = this, height = _a.height, width = _a.width;
|
|
4441
4713
|
var _b = this.opts, aboveMax = _b.aboveMax, belowMin = _b.belowMin, buckets = _b.buckets, min = _b.min, max$1 = _b.max;
|
|
4714
|
+
var dpr = window.devicePixelRatio;
|
|
4442
4715
|
var yMin = 0;
|
|
4443
4716
|
var yMax = this.maxValue;
|
|
4444
4717
|
var markers = extractRoundNumbers({ min: yMin, max: yMax });
|
|
4445
4718
|
context.fillStyle = "black";
|
|
4446
|
-
context.font = 14 *
|
|
4719
|
+
context.font = 14 * dpr + "px Helvetica";
|
|
4447
4720
|
// determine the width of the longest marker
|
|
4448
4721
|
this.markerWidth = max(markers.map(function (marker) { return context.measureText(marker.toLocaleString()).width; }));
|
|
4449
4722
|
// draw horizontal lines
|
|
@@ -4452,9 +4725,9 @@
|
|
|
4452
4725
|
context.textBaseline = "middle";
|
|
4453
4726
|
context.fillText(marker.toLocaleString(), _this.markerWidth, _this.y(marker));
|
|
4454
4727
|
context.beginPath();
|
|
4455
|
-
context.moveTo(_this.markerWidth + 10, _this.y(marker));
|
|
4728
|
+
context.moveTo(_this.markerWidth + 10 * dpr, _this.y(marker));
|
|
4456
4729
|
context.lineTo(_this.width, _this.y(marker));
|
|
4457
|
-
context.setLineDash(LINE_DASH);
|
|
4730
|
+
context.setLineDash(LINE_DASH.map(function (v) { return v * dpr; }));
|
|
4458
4731
|
context.stroke();
|
|
4459
4732
|
});
|
|
4460
4733
|
var numBuckets = bucketValues.length - (aboveMax ? 1 : 0) - (belowMin ? 1 : 0);
|
|
@@ -4477,9 +4750,9 @@
|
|
|
4477
4750
|
.forEach(function (label, i) {
|
|
4478
4751
|
context.save();
|
|
4479
4752
|
context.translate(_this.x((i * width) / bucketValues.length +
|
|
4480
|
-
(0.5 * width) / bucketValues.length), height - 50);
|
|
4753
|
+
(0.5 * width) / bucketValues.length), height - 50 * dpr);
|
|
4481
4754
|
context.rotate(Math.PI / 4);
|
|
4482
|
-
context.font = 12 *
|
|
4755
|
+
context.font = 12 * dpr + "px Helvetica";
|
|
4483
4756
|
context.textAlign = "left";
|
|
4484
4757
|
context.textBaseline = "middle";
|
|
4485
4758
|
context.fillText(label, 0, 0);
|
|
@@ -4489,22 +4762,23 @@
|
|
|
4489
4762
|
Histogram.prototype.drawBuckets = function (bucketValues, offset) {
|
|
4490
4763
|
var _this = this;
|
|
4491
4764
|
if (offset === void 0) { offset = 0; }
|
|
4492
|
-
var canvas =
|
|
4765
|
+
var _a = this, canvas = _a.canvas, width = _a.width, height = _a.height;
|
|
4493
4766
|
var metric = this._metric;
|
|
4494
4767
|
var numMetrics = Array.isArray(metric) ? metric.length : 1;
|
|
4495
|
-
var
|
|
4768
|
+
var _b = this.opts, aboveMax = _b.aboveMax, belowMin = _b.belowMin, color = _b.color;
|
|
4769
|
+
var dpr = window.devicePixelRatio;
|
|
4496
4770
|
var context = canvas.getContext("2d");
|
|
4497
4771
|
context.fillStyle = Array.isArray(color)
|
|
4498
4772
|
? color[offset % color.length]
|
|
4499
4773
|
: color;
|
|
4500
4774
|
var numBuckets = bucketValues.length;
|
|
4501
|
-
var barWidth = (width - PADDING_AT_LEFT - PADDING_AT_RIGHT - this.markerWidth) /
|
|
4775
|
+
var barWidth = (width - PADDING_AT_LEFT * dpr - PADDING_AT_RIGHT * dpr - this.markerWidth) /
|
|
4502
4776
|
numBuckets;
|
|
4503
4777
|
barWidth *= 0.8;
|
|
4504
4778
|
bucketValues.forEach(function (value, i) {
|
|
4505
4779
|
var mappedValue = remap(value, 0, _this.maxValue, 0, 1);
|
|
4506
4780
|
var x = _this.x(((0.1 + i) * width) / numBuckets);
|
|
4507
|
-
context.fillRect(x + (offset * barWidth - (numMetrics - 1)) / numMetrics + offset, remap(mappedValue, 0, 1, height - PADDING_AT_BOTTOM, 0), barWidth / numMetrics, remap(mappedValue, 0, 1, 0, height - PADDING_AT_BOTTOM));
|
|
4781
|
+
context.fillRect(x + (offset * barWidth - (numMetrics - 1)) / numMetrics + offset, remap(mappedValue, 0, 1, height - PADDING_AT_BOTTOM * dpr, 0), barWidth / numMetrics, remap(mappedValue, 0, 1, 0, height - PADDING_AT_BOTTOM * dpr));
|
|
4508
4782
|
});
|
|
4509
4783
|
};
|
|
4510
4784
|
Histogram.prototype.getBucketValues = function (metric) {
|
|
@@ -4632,7 +4906,7 @@
|
|
|
4632
4906
|
if (opts.autoScroll && t >= width) {
|
|
4633
4907
|
x -= t - width;
|
|
4634
4908
|
}
|
|
4635
|
-
else if (opts.autoScale
|
|
4909
|
+
else if (opts.autoScale) {
|
|
4636
4910
|
x *= width / t;
|
|
4637
4911
|
}
|
|
4638
4912
|
return x | 0;
|
|
@@ -4641,12 +4915,16 @@
|
|
|
4641
4915
|
var height = this.height;
|
|
4642
4916
|
var range = this.opts.range;
|
|
4643
4917
|
var min = range.min, max = range.max;
|
|
4644
|
-
var
|
|
4645
|
-
|
|
4918
|
+
var dpr = window.devicePixelRatio;
|
|
4919
|
+
var paddingBottom = PADDING_BOTTOM * dpr;
|
|
4920
|
+
var pxPerUnit = (height - 2 * paddingBottom) / (max - min);
|
|
4921
|
+
return Math.round(height - (value - min) * pxPerUnit) - 2 * paddingBottom;
|
|
4646
4922
|
};
|
|
4647
4923
|
LineChartRenderer.prototype.drawBackground = function () {
|
|
4648
4924
|
var _this = this;
|
|
4649
4925
|
var _a = this, context = _a.context, width = _a.width, height = _a.height, opts = _a.opts, t = _a.t;
|
|
4926
|
+
var dpr = window.devicePixelRatio;
|
|
4927
|
+
var paddingBottom = PADDING_BOTTOM * dpr;
|
|
4650
4928
|
// draw background and lines
|
|
4651
4929
|
context.fillStyle = this.opts.background;
|
|
4652
4930
|
context.fillRect(0, 0, width, height);
|
|
@@ -4654,33 +4932,33 @@
|
|
|
4654
4932
|
var markers = extractRoundNumbers(range);
|
|
4655
4933
|
var textMaxWidth = 0;
|
|
4656
4934
|
// write values on vertical axis
|
|
4657
|
-
context.font = 14 *
|
|
4935
|
+
context.font = 14 * dpr + "px Helvetica";
|
|
4658
4936
|
context.fillStyle = "#000";
|
|
4659
4937
|
context.textBaseline = "middle";
|
|
4660
4938
|
markers.forEach(function (marker) {
|
|
4661
|
-
if (_this.y(marker) < 10 || _this.y(marker) + 10 > height)
|
|
4939
|
+
if (_this.y(marker) < 10 * dpr || _this.y(marker) + 10 * dpr > height)
|
|
4662
4940
|
return;
|
|
4663
4941
|
var width = context.measureText(marker.toLocaleString()).width;
|
|
4664
4942
|
if (width > textMaxWidth)
|
|
4665
4943
|
textMaxWidth = width;
|
|
4666
|
-
context.fillText(marker.toLocaleString(), 5, _this.y(marker));
|
|
4944
|
+
context.fillText(marker.toLocaleString(), 5 * dpr, _this.y(marker));
|
|
4667
4945
|
});
|
|
4668
4946
|
// draw horizontal lines for vertical axis
|
|
4669
4947
|
context.save();
|
|
4670
4948
|
context.strokeStyle = "#999";
|
|
4671
4949
|
markers.forEach(function (marker) {
|
|
4672
|
-
if (_this.y(marker) >= height -
|
|
4950
|
+
if (_this.y(marker) >= height - paddingBottom)
|
|
4673
4951
|
return;
|
|
4674
4952
|
context.beginPath();
|
|
4675
|
-
context.moveTo(textMaxWidth + 10, _this.y(marker));
|
|
4953
|
+
context.moveTo(textMaxWidth + 10 * dpr, _this.y(marker));
|
|
4676
4954
|
context.lineTo(_this.x(Math.max(width, _this.environment.time)), _this.y(marker));
|
|
4677
|
-
context.setLineDash(lineDash);
|
|
4955
|
+
context.setLineDash(lineDash.map(function (v) { return v * dpr; }));
|
|
4678
4956
|
context.stroke();
|
|
4679
4957
|
});
|
|
4680
4958
|
context.restore();
|
|
4681
4959
|
// draw time values for horizontal axis
|
|
4682
4960
|
var min = opts.autoScroll && t >= width ? t - width : 0;
|
|
4683
|
-
var max = opts.autoScale
|
|
4961
|
+
var max = opts.autoScale ? Math.max(t, 5) : width;
|
|
4684
4962
|
var timeRange = { min: min, max: max };
|
|
4685
4963
|
var timeMarkers = extractRoundNumbers(timeRange);
|
|
4686
4964
|
context.save();
|
|
@@ -4691,12 +4969,12 @@
|
|
|
4691
4969
|
_this.x(marker) - width / 2 < textMaxWidth) {
|
|
4692
4970
|
return;
|
|
4693
4971
|
}
|
|
4694
|
-
context.font = 11 *
|
|
4695
|
-
context.fillText(marker.toLocaleString(), _this.x(marker), height -
|
|
4972
|
+
context.font = 11 * dpr + "px Helvetica";
|
|
4973
|
+
context.fillText(marker.toLocaleString(), _this.x(marker), height - paddingBottom);
|
|
4696
4974
|
context.strokeStyle = "black";
|
|
4697
4975
|
context.lineWidth = 1;
|
|
4698
4976
|
context.beginPath();
|
|
4699
|
-
context.moveTo(_this.x(marker), height - 4);
|
|
4977
|
+
context.moveTo(_this.x(marker), height - 4 * dpr);
|
|
4700
4978
|
context.lineTo(_this.x(marker), height);
|
|
4701
4979
|
context.stroke();
|
|
4702
4980
|
});
|
|
@@ -5044,7 +5322,8 @@
|
|
|
5044
5322
|
*/
|
|
5045
5323
|
Heatmap.prototype.x = function (value) {
|
|
5046
5324
|
var width = this.width;
|
|
5047
|
-
|
|
5325
|
+
var dpr = window.devicePixelRatio;
|
|
5326
|
+
return remap(value, this.getMin("x"), this.getMax("x"), PADDING_AT_LEFT$1 * dpr, width);
|
|
5048
5327
|
};
|
|
5049
5328
|
/**
|
|
5050
5329
|
* Map a value (on the range y-min to y-max) onto canvas space to draw it along the y-axis.
|
|
@@ -5052,7 +5331,8 @@
|
|
|
5052
5331
|
*/
|
|
5053
5332
|
Heatmap.prototype.y = function (value) {
|
|
5054
5333
|
var height = this.height;
|
|
5055
|
-
|
|
5334
|
+
var dpr = window.devicePixelRatio;
|
|
5335
|
+
return remap(value, this.getMin("y"), this.getMax("y"), height - PADDING_AT_BOTTOM$1 * dpr, 0);
|
|
5056
5336
|
};
|
|
5057
5337
|
/** @hidden */
|
|
5058
5338
|
Heatmap.prototype.getKey = function (axis) {
|
|
@@ -5095,52 +5375,55 @@
|
|
|
5095
5375
|
Heatmap.prototype.drawMarkers = function () {
|
|
5096
5376
|
var _a = this, context = _a.context, width = _a.width, height = _a.height;
|
|
5097
5377
|
var _b = this.opts, from = _b.from, to = _b.to;
|
|
5378
|
+
var dpr = window.devicePixelRatio;
|
|
5379
|
+
var padLeft = PADDING_AT_LEFT$1 * dpr;
|
|
5380
|
+
var padBottom = PADDING_AT_BOTTOM$1 * dpr;
|
|
5098
5381
|
context.strokeStyle = "black";
|
|
5099
5382
|
context.lineWidth = 1;
|
|
5100
|
-
context.moveTo(
|
|
5101
|
-
context.lineTo(
|
|
5102
|
-
context.lineTo(width, height -
|
|
5383
|
+
context.moveTo(padLeft - 1, 0);
|
|
5384
|
+
context.lineTo(padLeft - 1, height - padBottom + 1);
|
|
5385
|
+
context.lineTo(width, height - padBottom + 1);
|
|
5103
5386
|
context.stroke();
|
|
5104
5387
|
context.lineWidth = 0;
|
|
5105
|
-
var gradient = context.createLinearGradient(10, 0,
|
|
5388
|
+
var gradient = context.createLinearGradient(10 * dpr, 0, padLeft - 10 * dpr, 0);
|
|
5106
5389
|
gradient.addColorStop(0, from);
|
|
5107
5390
|
gradient.addColorStop(1, to);
|
|
5108
5391
|
context.fillStyle = gradient;
|
|
5109
|
-
context.fillRect(10, height -
|
|
5392
|
+
context.fillRect(10 * dpr, height - padBottom + 20 * dpr, padLeft - 24 * dpr, 20 * dpr);
|
|
5110
5393
|
context.fillStyle = "black";
|
|
5111
5394
|
var step = (this.getMax("x") - this.getMin("x")) / this.getBuckets("x");
|
|
5112
5395
|
var originalStep = step;
|
|
5113
|
-
while (Math.abs(this.x(step) - this.x(0)) < 35)
|
|
5396
|
+
while (Math.abs(this.x(step) - this.x(0)) < 35 * dpr)
|
|
5114
5397
|
step *= 2;
|
|
5115
5398
|
for (var marker = this.getMin("x"); marker <= this.getMax("x"); marker += originalStep) {
|
|
5116
|
-
if (this.x(marker) + 10 > width)
|
|
5399
|
+
if (this.x(marker) + 10 * dpr > width)
|
|
5117
5400
|
continue;
|
|
5118
|
-
context.moveTo(this.x(marker), height -
|
|
5119
|
-
context.lineTo(this.x(marker), height -
|
|
5401
|
+
context.moveTo(this.x(marker), height - padBottom);
|
|
5402
|
+
context.lineTo(this.x(marker), height - padBottom + 10 * dpr);
|
|
5120
5403
|
context.stroke();
|
|
5121
5404
|
if (Math.abs(((marker - this.getMin("x")) / step) % 1) < 0.001 ||
|
|
5122
5405
|
Math.abs((((marker - this.getMin("x")) / step) % 1) - 1) < 0.001) {
|
|
5123
|
-
context.font = 12 *
|
|
5406
|
+
context.font = 12 * dpr + "px Helvetica";
|
|
5124
5407
|
context.textAlign = "center";
|
|
5125
|
-
context.fillText(marker.toLocaleString(), this.x(marker), height -
|
|
5408
|
+
context.fillText(marker.toLocaleString(), this.x(marker), height - padBottom + 24 * dpr);
|
|
5126
5409
|
}
|
|
5127
5410
|
}
|
|
5128
5411
|
step = (this.getMax("y") - this.getMin("y")) / this.getBuckets("y");
|
|
5129
5412
|
originalStep = step;
|
|
5130
|
-
while (Math.abs(this.y(step) - this.y(0)) < 20)
|
|
5413
|
+
while (Math.abs(this.y(step) - this.y(0)) < 20 * dpr)
|
|
5131
5414
|
step *= 2;
|
|
5132
5415
|
for (var marker = this.getMin("y"); marker <= this.getMax("y"); marker += originalStep) {
|
|
5133
|
-
if (this.y(marker) - 10 < 0)
|
|
5416
|
+
if (this.y(marker) - 10 * dpr < 0)
|
|
5134
5417
|
continue;
|
|
5135
|
-
context.moveTo(
|
|
5136
|
-
context.lineTo(
|
|
5418
|
+
context.moveTo(padLeft, this.y(marker));
|
|
5419
|
+
context.lineTo(padLeft - 10 * dpr, this.y(marker));
|
|
5137
5420
|
context.stroke();
|
|
5138
5421
|
if (Math.abs(((marker - this.getMin("y")) / step) % 1) < 0.001 ||
|
|
5139
5422
|
Math.abs((((marker - this.getMin("y")) / step) % 1) - 1) < 0.001) {
|
|
5140
|
-
context.font = 12 *
|
|
5423
|
+
context.font = 12 * dpr + "px Helvetica";
|
|
5141
5424
|
context.textAlign = "right";
|
|
5142
5425
|
context.textBaseline = "middle";
|
|
5143
|
-
context.fillText(marker.toLocaleString(),
|
|
5426
|
+
context.fillText(marker.toLocaleString(), padLeft - 14 * dpr, this.y(marker));
|
|
5144
5427
|
}
|
|
5145
5428
|
}
|
|
5146
5429
|
};
|
|
@@ -5148,6 +5431,8 @@
|
|
|
5148
5431
|
Heatmap.prototype.updateScale = function () {
|
|
5149
5432
|
var _a = this, context = _a.context, environment = _a.environment, height = _a.height;
|
|
5150
5433
|
var scale = this.opts.scale;
|
|
5434
|
+
var dpr = window.devicePixelRatio;
|
|
5435
|
+
var padLeft = PADDING_AT_LEFT$1 * dpr;
|
|
5151
5436
|
var max = scale === "relative" ? this.localMax : this.opts.max;
|
|
5152
5437
|
if (max === undefined) {
|
|
5153
5438
|
if (!this.lastUpdatedScale) {
|
|
@@ -5156,13 +5441,13 @@
|
|
|
5156
5441
|
max = environment.getAgents().length;
|
|
5157
5442
|
}
|
|
5158
5443
|
if (!this.lastUpdatedScale || +new Date() - +this.lastUpdatedScale > 250) {
|
|
5159
|
-
context.clearRect(0, height - 20,
|
|
5444
|
+
context.clearRect(0, height - 20 * dpr, padLeft, 20 * dpr);
|
|
5160
5445
|
context.fillStyle = "black";
|
|
5161
|
-
context.font = 12 *
|
|
5446
|
+
context.font = 12 * dpr + "px Helvetica";
|
|
5162
5447
|
context.textAlign = "center";
|
|
5163
5448
|
context.textBaseline = "bottom";
|
|
5164
|
-
context.fillText("0", 10, height - 5);
|
|
5165
|
-
context.fillText(max.toString(),
|
|
5449
|
+
context.fillText("0", 10 * dpr, height - 5 * dpr);
|
|
5450
|
+
context.fillText(max.toString(), padLeft - 16 * dpr, height - 5 * dpr);
|
|
5166
5451
|
this.lastUpdatedScale = new Date();
|
|
5167
5452
|
}
|
|
5168
5453
|
};
|
|
@@ -5170,6 +5455,9 @@
|
|
|
5170
5455
|
Heatmap.prototype.drawRectangles = function () {
|
|
5171
5456
|
var _a = this, canvas = _a.canvas, environment = _a.environment, width = _a.width, height = _a.height;
|
|
5172
5457
|
var _b = this.opts, scale = _b.scale, from = _b.from, to = _b.to;
|
|
5458
|
+
var dpr = window.devicePixelRatio;
|
|
5459
|
+
var padLeft = PADDING_AT_LEFT$1 * dpr;
|
|
5460
|
+
var padBottom = PADDING_AT_BOTTOM$1 * dpr;
|
|
5173
5461
|
var context = canvas.getContext("2d");
|
|
5174
5462
|
var xBuckets = this.getBuckets("x");
|
|
5175
5463
|
var yBuckets = this.getBuckets("y");
|
|
@@ -5178,9 +5466,9 @@
|
|
|
5178
5466
|
max = environment.getAgents().length;
|
|
5179
5467
|
// clear background by drawing background rectangle
|
|
5180
5468
|
context.fillStyle = from;
|
|
5181
|
-
context.fillRect(
|
|
5182
|
-
var w = width / xBuckets;
|
|
5183
|
-
var h = height / yBuckets;
|
|
5469
|
+
context.fillRect(padLeft, 0, width - padLeft, height - padBottom);
|
|
5470
|
+
var w = (width - padLeft) / xBuckets;
|
|
5471
|
+
var h = (height - padBottom) / yBuckets;
|
|
5184
5472
|
for (var row = 0; row < yBuckets; row++) {
|
|
5185
5473
|
for (var column = 0; column < xBuckets; column++) {
|
|
5186
5474
|
var index = row * xBuckets + column;
|
|
@@ -5188,7 +5476,7 @@
|
|
|
5188
5476
|
var a = clamp(remap(this.buckets[index], 0, max, 0, 1), 0, 1);
|
|
5189
5477
|
context.fillStyle = to;
|
|
5190
5478
|
context.globalAlpha = a;
|
|
5191
|
-
context.fillRect(this.x(remap(column, 0, xBuckets, this.getMin("x"), this.getMax("x"))), this.y(remap(row, -1, yBuckets - 1, this.getMin("y"), this.getMax("y"))),
|
|
5479
|
+
context.fillRect(this.x(remap(column, 0, xBuckets, this.getMin("x"), this.getMax("x"))), this.y(remap(row, -1, yBuckets - 1, this.getMin("y"), this.getMax("y"))), w, h);
|
|
5192
5480
|
}
|
|
5193
5481
|
}
|
|
5194
5482
|
context.globalAlpha = 1;
|
|
@@ -5244,7 +5532,7 @@
|
|
|
5244
5532
|
/**
|
|
5245
5533
|
* The current version of the Flocc library.
|
|
5246
5534
|
*/
|
|
5247
|
-
var version = "0.5.
|
|
5535
|
+
var version = "0.5.22";
|
|
5248
5536
|
|
|
5249
5537
|
exports.ASCIIRenderer = ASCIIRenderer;
|
|
5250
5538
|
exports.Agent = Agent;
|