kimai-plugin-heatmap/Resources/public/heatmap.js
Christopher Mühl 12e734a911
fix(07): uniform control sizing, min cell 13px, center week view
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 16:56:34 +02:00

2562 lines
91 KiB
JavaScript

"use strict";
var KimaiHeatmap = (() => {
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// assets/src/heatmap.ts
var heatmap_exports = {};
__export(heatmap_exports, {
init: () => init
});
// assets/src/state.ts
function createInitialState(weekStart) {
return {
mode: "year",
metric: "hours",
filters: { projectId: null, customerId: null, activityId: null },
weekStart,
data: null
};
}
// assets/src/renderers/registry.ts
var renderers = /* @__PURE__ */ new Map();
function registerRenderer(renderer) {
renderers.set(renderer.mode, renderer);
}
function getRenderer(mode) {
const r = renderers.get(mode);
if (!r) throw new Error(`Unknown heatmap mode: ${mode}`);
return r;
}
// node_modules/d3-selection/src/namespaces.js
var xhtml = "http://www.w3.org/1999/xhtml";
var namespaces_default = {
svg: "http://www.w3.org/2000/svg",
xhtml,
xlink: "http://www.w3.org/1999/xlink",
xml: "http://www.w3.org/XML/1998/namespace",
xmlns: "http://www.w3.org/2000/xmlns/"
};
// node_modules/d3-selection/src/namespace.js
function namespace_default(name) {
var prefix = name += "", i = prefix.indexOf(":");
if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
return namespaces_default.hasOwnProperty(prefix) ? { space: namespaces_default[prefix], local: name } : name;
}
// node_modules/d3-selection/src/creator.js
function creatorInherit(name) {
return function() {
var document2 = this.ownerDocument, uri = this.namespaceURI;
return uri === xhtml && document2.documentElement.namespaceURI === xhtml ? document2.createElement(name) : document2.createElementNS(uri, name);
};
}
function creatorFixed(fullname) {
return function() {
return this.ownerDocument.createElementNS(fullname.space, fullname.local);
};
}
function creator_default(name) {
var fullname = namespace_default(name);
return (fullname.local ? creatorFixed : creatorInherit)(fullname);
}
// node_modules/d3-selection/src/selector.js
function none() {
}
function selector_default(selector) {
return selector == null ? none : function() {
return this.querySelector(selector);
};
}
// node_modules/d3-selection/src/selection/select.js
function select_default(select) {
if (typeof select !== "function") select = selector_default(select);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
if ("__data__" in node) subnode.__data__ = node.__data__;
subgroup[i] = subnode;
}
}
}
return new Selection(subgroups, this._parents);
}
// node_modules/d3-selection/src/array.js
function array(x) {
return x == null ? [] : Array.isArray(x) ? x : Array.from(x);
}
// node_modules/d3-selection/src/selectorAll.js
function empty() {
return [];
}
function selectorAll_default(selector) {
return selector == null ? empty : function() {
return this.querySelectorAll(selector);
};
}
// node_modules/d3-selection/src/selection/selectAll.js
function arrayAll(select) {
return function() {
return array(select.apply(this, arguments));
};
}
function selectAll_default(select) {
if (typeof select === "function") select = arrayAll(select);
else select = selectorAll_default(select);
for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
if (node = group[i]) {
subgroups.push(select.call(node, node.__data__, i, group));
parents.push(node);
}
}
}
return new Selection(subgroups, parents);
}
// node_modules/d3-selection/src/matcher.js
function matcher_default(selector) {
return function() {
return this.matches(selector);
};
}
function childMatcher(selector) {
return function(node) {
return node.matches(selector);
};
}
// node_modules/d3-selection/src/selection/selectChild.js
var find = Array.prototype.find;
function childFind(match) {
return function() {
return find.call(this.children, match);
};
}
function childFirst() {
return this.firstElementChild;
}
function selectChild_default(match) {
return this.select(match == null ? childFirst : childFind(typeof match === "function" ? match : childMatcher(match)));
}
// node_modules/d3-selection/src/selection/selectChildren.js
var filter = Array.prototype.filter;
function children() {
return Array.from(this.children);
}
function childrenFilter(match) {
return function() {
return filter.call(this.children, match);
};
}
function selectChildren_default(match) {
return this.selectAll(match == null ? children : childrenFilter(typeof match === "function" ? match : childMatcher(match)));
}
// node_modules/d3-selection/src/selection/filter.js
function filter_default(match) {
if (typeof match !== "function") match = matcher_default(match);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
subgroup.push(node);
}
}
}
return new Selection(subgroups, this._parents);
}
// node_modules/d3-selection/src/selection/sparse.js
function sparse_default(update) {
return new Array(update.length);
}
// node_modules/d3-selection/src/selection/enter.js
function enter_default() {
return new Selection(this._enter || this._groups.map(sparse_default), this._parents);
}
function EnterNode(parent, datum2) {
this.ownerDocument = parent.ownerDocument;
this.namespaceURI = parent.namespaceURI;
this._next = null;
this._parent = parent;
this.__data__ = datum2;
}
EnterNode.prototype = {
constructor: EnterNode,
appendChild: function(child) {
return this._parent.insertBefore(child, this._next);
},
insertBefore: function(child, next) {
return this._parent.insertBefore(child, next);
},
querySelector: function(selector) {
return this._parent.querySelector(selector);
},
querySelectorAll: function(selector) {
return this._parent.querySelectorAll(selector);
}
};
// node_modules/d3-selection/src/constant.js
function constant_default(x) {
return function() {
return x;
};
}
// node_modules/d3-selection/src/selection/data.js
function bindIndex(parent, group, enter, update, exit, data) {
var i = 0, node, groupLength = group.length, dataLength = data.length;
for (; i < dataLength; ++i) {
if (node = group[i]) {
node.__data__ = data[i];
update[i] = node;
} else {
enter[i] = new EnterNode(parent, data[i]);
}
}
for (; i < groupLength; ++i) {
if (node = group[i]) {
exit[i] = node;
}
}
}
function bindKey(parent, group, enter, update, exit, data, key) {
var i, node, nodeByKeyValue = /* @__PURE__ */ new Map(), groupLength = group.length, dataLength = data.length, keyValues = new Array(groupLength), keyValue;
for (i = 0; i < groupLength; ++i) {
if (node = group[i]) {
keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + "";
if (nodeByKeyValue.has(keyValue)) {
exit[i] = node;
} else {
nodeByKeyValue.set(keyValue, node);
}
}
}
for (i = 0; i < dataLength; ++i) {
keyValue = key.call(parent, data[i], i, data) + "";
if (node = nodeByKeyValue.get(keyValue)) {
update[i] = node;
node.__data__ = data[i];
nodeByKeyValue.delete(keyValue);
} else {
enter[i] = new EnterNode(parent, data[i]);
}
}
for (i = 0; i < groupLength; ++i) {
if ((node = group[i]) && nodeByKeyValue.get(keyValues[i]) === node) {
exit[i] = node;
}
}
}
function datum(node) {
return node.__data__;
}
function data_default(value, key) {
if (!arguments.length) return Array.from(this, datum);
var bind = key ? bindKey : bindIndex, parents = this._parents, groups = this._groups;
if (typeof value !== "function") value = constant_default(value);
for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
var parent = parents[j], group = groups[j], groupLength = group.length, data = arraylike(value.call(parent, parent && parent.__data__, j, parents)), dataLength = data.length, enterGroup = enter[j] = new Array(dataLength), updateGroup = update[j] = new Array(dataLength), exitGroup = exit[j] = new Array(groupLength);
bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
if (previous = enterGroup[i0]) {
if (i0 >= i1) i1 = i0 + 1;
while (!(next = updateGroup[i1]) && ++i1 < dataLength) ;
previous._next = next || null;
}
}
}
update = new Selection(update, parents);
update._enter = enter;
update._exit = exit;
return update;
}
function arraylike(data) {
return typeof data === "object" && "length" in data ? data : Array.from(data);
}
// node_modules/d3-selection/src/selection/exit.js
function exit_default() {
return new Selection(this._exit || this._groups.map(sparse_default), this._parents);
}
// node_modules/d3-selection/src/selection/join.js
function join_default(onenter, onupdate, onexit) {
var enter = this.enter(), update = this, exit = this.exit();
if (typeof onenter === "function") {
enter = onenter(enter);
if (enter) enter = enter.selection();
} else {
enter = enter.append(onenter + "");
}
if (onupdate != null) {
update = onupdate(update);
if (update) update = update.selection();
}
if (onexit == null) exit.remove();
else onexit(exit);
return enter && update ? enter.merge(update).order() : update;
}
// node_modules/d3-selection/src/selection/merge.js
function merge_default(context) {
var selection2 = context.selection ? context.selection() : context;
for (var groups0 = this._groups, groups1 = selection2._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
if (node = group0[i] || group1[i]) {
merge[i] = node;
}
}
}
for (; j < m0; ++j) {
merges[j] = groups0[j];
}
return new Selection(merges, this._parents);
}
// node_modules/d3-selection/src/selection/order.js
function order_default() {
for (var groups = this._groups, j = -1, m = groups.length; ++j < m; ) {
for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0; ) {
if (node = group[i]) {
if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
next = node;
}
}
}
return this;
}
// node_modules/d3-selection/src/selection/sort.js
function sort_default(compare) {
if (!compare) compare = ascending;
function compareNode(a, b) {
return a && b ? compare(a.__data__, b.__data__) : !a - !b;
}
for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
if (node = group[i]) {
sortgroup[i] = node;
}
}
sortgroup.sort(compareNode);
}
return new Selection(sortgroups, this._parents).order();
}
function ascending(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
// node_modules/d3-selection/src/selection/call.js
function call_default() {
var callback = arguments[0];
arguments[0] = this;
callback.apply(null, arguments);
return this;
}
// node_modules/d3-selection/src/selection/nodes.js
function nodes_default() {
return Array.from(this);
}
// node_modules/d3-selection/src/selection/node.js
function node_default() {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
var node = group[i];
if (node) return node;
}
}
return null;
}
// node_modules/d3-selection/src/selection/size.js
function size_default() {
let size = 0;
for (const node of this) ++size;
return size;
}
// node_modules/d3-selection/src/selection/empty.js
function empty_default() {
return !this.node();
}
// node_modules/d3-selection/src/selection/each.js
function each_default(callback) {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
if (node = group[i]) callback.call(node, node.__data__, i, group);
}
}
return this;
}
// node_modules/d3-selection/src/selection/attr.js
function attrRemove(name) {
return function() {
this.removeAttribute(name);
};
}
function attrRemoveNS(fullname) {
return function() {
this.removeAttributeNS(fullname.space, fullname.local);
};
}
function attrConstant(name, value) {
return function() {
this.setAttribute(name, value);
};
}
function attrConstantNS(fullname, value) {
return function() {
this.setAttributeNS(fullname.space, fullname.local, value);
};
}
function attrFunction(name, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.removeAttribute(name);
else this.setAttribute(name, v);
};
}
function attrFunctionNS(fullname, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
else this.setAttributeNS(fullname.space, fullname.local, v);
};
}
function attr_default(name, value) {
var fullname = namespace_default(name);
if (arguments.length < 2) {
var node = this.node();
return fullname.local ? node.getAttributeNS(fullname.space, fullname.local) : node.getAttribute(fullname);
}
return this.each((value == null ? fullname.local ? attrRemoveNS : attrRemove : typeof value === "function" ? fullname.local ? attrFunctionNS : attrFunction : fullname.local ? attrConstantNS : attrConstant)(fullname, value));
}
// node_modules/d3-selection/src/window.js
function window_default(node) {
return node.ownerDocument && node.ownerDocument.defaultView || node.document && node || node.defaultView;
}
// node_modules/d3-selection/src/selection/style.js
function styleRemove(name) {
return function() {
this.style.removeProperty(name);
};
}
function styleConstant(name, value, priority) {
return function() {
this.style.setProperty(name, value, priority);
};
}
function styleFunction(name, value, priority) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.style.removeProperty(name);
else this.style.setProperty(name, v, priority);
};
}
function style_default(name, value, priority) {
return arguments.length > 1 ? this.each((value == null ? styleRemove : typeof value === "function" ? styleFunction : styleConstant)(name, value, priority == null ? "" : priority)) : styleValue(this.node(), name);
}
function styleValue(node, name) {
return node.style.getPropertyValue(name) || window_default(node).getComputedStyle(node, null).getPropertyValue(name);
}
// node_modules/d3-selection/src/selection/property.js
function propertyRemove(name) {
return function() {
delete this[name];
};
}
function propertyConstant(name, value) {
return function() {
this[name] = value;
};
}
function propertyFunction(name, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) delete this[name];
else this[name] = v;
};
}
function property_default(name, value) {
return arguments.length > 1 ? this.each((value == null ? propertyRemove : typeof value === "function" ? propertyFunction : propertyConstant)(name, value)) : this.node()[name];
}
// node_modules/d3-selection/src/selection/classed.js
function classArray(string) {
return string.trim().split(/^|\s+/);
}
function classList(node) {
return node.classList || new ClassList(node);
}
function ClassList(node) {
this._node = node;
this._names = classArray(node.getAttribute("class") || "");
}
ClassList.prototype = {
add: function(name) {
var i = this._names.indexOf(name);
if (i < 0) {
this._names.push(name);
this._node.setAttribute("class", this._names.join(" "));
}
},
remove: function(name) {
var i = this._names.indexOf(name);
if (i >= 0) {
this._names.splice(i, 1);
this._node.setAttribute("class", this._names.join(" "));
}
},
contains: function(name) {
return this._names.indexOf(name) >= 0;
}
};
function classedAdd(node, names) {
var list = classList(node), i = -1, n = names.length;
while (++i < n) list.add(names[i]);
}
function classedRemove(node, names) {
var list = classList(node), i = -1, n = names.length;
while (++i < n) list.remove(names[i]);
}
function classedTrue(names) {
return function() {
classedAdd(this, names);
};
}
function classedFalse(names) {
return function() {
classedRemove(this, names);
};
}
function classedFunction(names, value) {
return function() {
(value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
};
}
function classed_default(name, value) {
var names = classArray(name + "");
if (arguments.length < 2) {
var list = classList(this.node()), i = -1, n = names.length;
while (++i < n) if (!list.contains(names[i])) return false;
return true;
}
return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value));
}
// node_modules/d3-selection/src/selection/text.js
function textRemove() {
this.textContent = "";
}
function textConstant(value) {
return function() {
this.textContent = value;
};
}
function textFunction(value) {
return function() {
var v = value.apply(this, arguments);
this.textContent = v == null ? "" : v;
};
}
function text_default(value) {
return arguments.length ? this.each(value == null ? textRemove : (typeof value === "function" ? textFunction : textConstant)(value)) : this.node().textContent;
}
// node_modules/d3-selection/src/selection/html.js
function htmlRemove() {
this.innerHTML = "";
}
function htmlConstant(value) {
return function() {
this.innerHTML = value;
};
}
function htmlFunction(value) {
return function() {
var v = value.apply(this, arguments);
this.innerHTML = v == null ? "" : v;
};
}
function html_default(value) {
return arguments.length ? this.each(value == null ? htmlRemove : (typeof value === "function" ? htmlFunction : htmlConstant)(value)) : this.node().innerHTML;
}
// node_modules/d3-selection/src/selection/raise.js
function raise() {
if (this.nextSibling) this.parentNode.appendChild(this);
}
function raise_default() {
return this.each(raise);
}
// node_modules/d3-selection/src/selection/lower.js
function lower() {
if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
}
function lower_default() {
return this.each(lower);
}
// node_modules/d3-selection/src/selection/append.js
function append_default(name) {
var create = typeof name === "function" ? name : creator_default(name);
return this.select(function() {
return this.appendChild(create.apply(this, arguments));
});
}
// node_modules/d3-selection/src/selection/insert.js
function constantNull() {
return null;
}
function insert_default(name, before) {
var create = typeof name === "function" ? name : creator_default(name), select = before == null ? constantNull : typeof before === "function" ? before : selector_default(before);
return this.select(function() {
return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
});
}
// node_modules/d3-selection/src/selection/remove.js
function remove() {
var parent = this.parentNode;
if (parent) parent.removeChild(this);
}
function remove_default() {
return this.each(remove);
}
// node_modules/d3-selection/src/selection/clone.js
function selection_cloneShallow() {
var clone = this.cloneNode(false), parent = this.parentNode;
return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
}
function selection_cloneDeep() {
var clone = this.cloneNode(true), parent = this.parentNode;
return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
}
function clone_default(deep) {
return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
}
// node_modules/d3-selection/src/selection/datum.js
function datum_default(value) {
return arguments.length ? this.property("__data__", value) : this.node().__data__;
}
// node_modules/d3-selection/src/selection/on.js
function contextListener(listener) {
return function(event) {
listener.call(this, event, this.__data__);
};
}
function parseTypenames(typenames) {
return typenames.trim().split(/^|\s+/).map(function(t) {
var name = "", i = t.indexOf(".");
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
return { type: t, name };
});
}
function onRemove(typename) {
return function() {
var on = this.__on;
if (!on) return;
for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
this.removeEventListener(o.type, o.listener, o.options);
} else {
on[++i] = o;
}
}
if (++i) on.length = i;
else delete this.__on;
};
}
function onAdd(typename, value, options) {
return function() {
var on = this.__on, o, listener = contextListener(value);
if (on) for (var j = 0, m = on.length; j < m; ++j) {
if ((o = on[j]).type === typename.type && o.name === typename.name) {
this.removeEventListener(o.type, o.listener, o.options);
this.addEventListener(o.type, o.listener = listener, o.options = options);
o.value = value;
return;
}
}
this.addEventListener(typename.type, listener, options);
o = { type: typename.type, name: typename.name, value, listener, options };
if (!on) this.__on = [o];
else on.push(o);
};
}
function on_default(typename, value, options) {
var typenames = parseTypenames(typename + ""), i, n = typenames.length, t;
if (arguments.length < 2) {
var on = this.node().__on;
if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
for (i = 0, o = on[j]; i < n; ++i) {
if ((t = typenames[i]).type === o.type && t.name === o.name) {
return o.value;
}
}
}
return;
}
on = value ? onAdd : onRemove;
for (i = 0; i < n; ++i) this.each(on(typenames[i], value, options));
return this;
}
// node_modules/d3-selection/src/selection/dispatch.js
function dispatchEvent(node, type, params) {
var window2 = window_default(node), event = window2.CustomEvent;
if (typeof event === "function") {
event = new event(type, params);
} else {
event = window2.document.createEvent("Event");
if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
else event.initEvent(type, false, false);
}
node.dispatchEvent(event);
}
function dispatchConstant(type, params) {
return function() {
return dispatchEvent(this, type, params);
};
}
function dispatchFunction(type, params) {
return function() {
return dispatchEvent(this, type, params.apply(this, arguments));
};
}
function dispatch_default(type, params) {
return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type, params));
}
// node_modules/d3-selection/src/selection/iterator.js
function* iterator_default() {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
if (node = group[i]) yield node;
}
}
}
// node_modules/d3-selection/src/selection/index.js
var root = [null];
function Selection(groups, parents) {
this._groups = groups;
this._parents = parents;
}
function selection() {
return new Selection([[document.documentElement]], root);
}
function selection_selection() {
return this;
}
Selection.prototype = selection.prototype = {
constructor: Selection,
select: select_default,
selectAll: selectAll_default,
selectChild: selectChild_default,
selectChildren: selectChildren_default,
filter: filter_default,
data: data_default,
enter: enter_default,
exit: exit_default,
join: join_default,
merge: merge_default,
selection: selection_selection,
order: order_default,
sort: sort_default,
call: call_default,
nodes: nodes_default,
node: node_default,
size: size_default,
empty: empty_default,
each: each_default,
attr: attr_default,
style: style_default,
property: property_default,
classed: classed_default,
text: text_default,
html: html_default,
raise: raise_default,
lower: lower_default,
append: append_default,
insert: insert_default,
remove: remove_default,
clone: clone_default,
datum: datum_default,
on: on_default,
dispatch: dispatch_default,
[Symbol.iterator]: iterator_default
};
// node_modules/d3-selection/src/select.js
function select_default2(selector) {
return typeof selector === "string" ? new Selection([[document.querySelector(selector)]], [document.documentElement]) : new Selection([[selector]], root);
}
// node_modules/d3-time/src/interval.js
var t0 = /* @__PURE__ */ new Date();
var t1 = /* @__PURE__ */ new Date();
function timeInterval(floori, offseti, count, field) {
function interval(date) {
return floori(date = arguments.length === 0 ? /* @__PURE__ */ new Date() : /* @__PURE__ */ new Date(+date)), date;
}
interval.floor = (date) => {
return floori(date = /* @__PURE__ */ new Date(+date)), date;
};
interval.ceil = (date) => {
return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;
};
interval.round = (date) => {
const d0 = interval(date), d1 = interval.ceil(date);
return date - d0 < d1 - date ? d0 : d1;
};
interval.offset = (date, step) => {
return offseti(date = /* @__PURE__ */ new Date(+date), step == null ? 1 : Math.floor(step)), date;
};
interval.range = (start, stop, step) => {
const range = [];
start = interval.ceil(start);
step = step == null ? 1 : Math.floor(step);
if (!(start < stop) || !(step > 0)) return range;
let previous;
do
range.push(previous = /* @__PURE__ */ new Date(+start)), offseti(start, step), floori(start);
while (previous < start && start < stop);
return range;
};
interval.filter = (test) => {
return timeInterval((date) => {
if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1);
}, (date, step) => {
if (date >= date) {
if (step < 0) while (++step <= 0) {
while (offseti(date, -1), !test(date)) {
}
}
else while (--step >= 0) {
while (offseti(date, 1), !test(date)) {
}
}
}
});
};
if (count) {
interval.count = (start, end) => {
t0.setTime(+start), t1.setTime(+end);
floori(t0), floori(t1);
return Math.floor(count(t0, t1));
};
interval.every = (step) => {
step = Math.floor(step);
return !isFinite(step) || !(step > 0) ? null : !(step > 1) ? interval : interval.filter(field ? (d) => field(d) % step === 0 : (d) => interval.count(0, d) % step === 0);
};
}
return interval;
}
// node_modules/d3-time/src/duration.js
var durationSecond = 1e3;
var durationMinute = durationSecond * 60;
var durationHour = durationMinute * 60;
var durationDay = durationHour * 24;
var durationWeek = durationDay * 7;
var durationMonth = durationDay * 30;
var durationYear = durationDay * 365;
// node_modules/d3-time/src/day.js
var timeDay = timeInterval(
(date) => date.setHours(0, 0, 0, 0),
(date, step) => date.setDate(date.getDate() + step),
(start, end) => (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay,
(date) => date.getDate() - 1
);
var timeDays = timeDay.range;
var utcDay = timeInterval((date) => {
date.setUTCHours(0, 0, 0, 0);
}, (date, step) => {
date.setUTCDate(date.getUTCDate() + step);
}, (start, end) => {
return (end - start) / durationDay;
}, (date) => {
return date.getUTCDate() - 1;
});
var utcDays = utcDay.range;
var unixDay = timeInterval((date) => {
date.setUTCHours(0, 0, 0, 0);
}, (date, step) => {
date.setUTCDate(date.getUTCDate() + step);
}, (start, end) => {
return (end - start) / durationDay;
}, (date) => {
return Math.floor(date / durationDay);
});
var unixDays = unixDay.range;
// node_modules/d3-time/src/week.js
function timeWeekday(i) {
return timeInterval((date) => {
date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
date.setHours(0, 0, 0, 0);
}, (date, step) => {
date.setDate(date.getDate() + step * 7);
}, (start, end) => {
return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek;
});
}
var timeSunday = timeWeekday(0);
var timeMonday = timeWeekday(1);
var timeTuesday = timeWeekday(2);
var timeWednesday = timeWeekday(3);
var timeThursday = timeWeekday(4);
var timeFriday = timeWeekday(5);
var timeSaturday = timeWeekday(6);
var timeSundays = timeSunday.range;
var timeMondays = timeMonday.range;
var timeTuesdays = timeTuesday.range;
var timeWednesdays = timeWednesday.range;
var timeThursdays = timeThursday.range;
var timeFridays = timeFriday.range;
var timeSaturdays = timeSaturday.range;
function utcWeekday(i) {
return timeInterval((date) => {
date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
date.setUTCHours(0, 0, 0, 0);
}, (date, step) => {
date.setUTCDate(date.getUTCDate() + step * 7);
}, (start, end) => {
return (end - start) / durationWeek;
});
}
var utcSunday = utcWeekday(0);
var utcMonday = utcWeekday(1);
var utcTuesday = utcWeekday(2);
var utcWednesday = utcWeekday(3);
var utcThursday = utcWeekday(4);
var utcFriday = utcWeekday(5);
var utcSaturday = utcWeekday(6);
var utcSundays = utcSunday.range;
var utcMondays = utcMonday.range;
var utcTuesdays = utcTuesday.range;
var utcWednesdays = utcWednesday.range;
var utcThursdays = utcThursday.range;
var utcFridays = utcFriday.range;
var utcSaturdays = utcSaturday.range;
// node_modules/d3-time/src/month.js
var timeMonth = timeInterval((date) => {
date.setDate(1);
date.setHours(0, 0, 0, 0);
}, (date, step) => {
date.setMonth(date.getMonth() + step);
}, (start, end) => {
return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
}, (date) => {
return date.getMonth();
});
var timeMonths = timeMonth.range;
var utcMonth = timeInterval((date) => {
date.setUTCDate(1);
date.setUTCHours(0, 0, 0, 0);
}, (date, step) => {
date.setUTCMonth(date.getUTCMonth() + step);
}, (start, end) => {
return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;
}, (date) => {
return date.getUTCMonth();
});
var utcMonths = utcMonth.range;
// node_modules/d3-time/src/year.js
var timeYear = timeInterval((date) => {
date.setMonth(0, 1);
date.setHours(0, 0, 0, 0);
}, (date, step) => {
date.setFullYear(date.getFullYear() + step);
}, (start, end) => {
return end.getFullYear() - start.getFullYear();
}, (date) => {
return date.getFullYear();
});
timeYear.every = (k) => {
return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => {
date.setFullYear(Math.floor(date.getFullYear() / k) * k);
date.setMonth(0, 1);
date.setHours(0, 0, 0, 0);
}, (date, step) => {
date.setFullYear(date.getFullYear() + step * k);
});
};
var timeYears = timeYear.range;
var utcYear = timeInterval((date) => {
date.setUTCMonth(0, 1);
date.setUTCHours(0, 0, 0, 0);
}, (date, step) => {
date.setUTCFullYear(date.getUTCFullYear() + step);
}, (start, end) => {
return end.getUTCFullYear() - start.getUTCFullYear();
}, (date) => {
return date.getUTCFullYear();
});
utcYear.every = (k) => {
return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : timeInterval((date) => {
date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);
date.setUTCMonth(0, 1);
date.setUTCHours(0, 0, 0, 0);
}, (date, step) => {
date.setUTCFullYear(date.getUTCFullYear() + step * k);
});
};
var utcYears = utcYear.range;
// node_modules/d3-array/src/ascending.js
function ascending2(a, b) {
return a == null || b == null ? NaN : a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
// node_modules/d3-array/src/descending.js
function descending(a, b) {
return a == null || b == null ? NaN : b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
}
// node_modules/d3-array/src/bisector.js
function bisector(f) {
let compare1, compare2, delta;
if (f.length !== 2) {
compare1 = ascending2;
compare2 = (d, x) => ascending2(f(d), x);
delta = (d, x) => f(d) - x;
} else {
compare1 = f === ascending2 || f === descending ? f : zero;
compare2 = f;
delta = f;
}
function left(a, x, lo = 0, hi = a.length) {
if (lo < hi) {
if (compare1(x, x) !== 0) return hi;
do {
const mid = lo + hi >>> 1;
if (compare2(a[mid], x) < 0) lo = mid + 1;
else hi = mid;
} while (lo < hi);
}
return lo;
}
function right(a, x, lo = 0, hi = a.length) {
if (lo < hi) {
if (compare1(x, x) !== 0) return hi;
do {
const mid = lo + hi >>> 1;
if (compare2(a[mid], x) <= 0) lo = mid + 1;
else hi = mid;
} while (lo < hi);
}
return lo;
}
function center(a, x, lo = 0, hi = a.length) {
const i = left(a, x, lo, hi - 1);
return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;
}
return { left, center, right };
}
function zero() {
return 0;
}
// node_modules/d3-array/src/number.js
function number(x) {
return x === null ? NaN : +x;
}
// node_modules/d3-array/src/bisect.js
var ascendingBisect = bisector(ascending2);
var bisectRight = ascendingBisect.right;
var bisectLeft = ascendingBisect.left;
var bisectCenter = bisector(number).center;
var bisect_default = bisectRight;
// node_modules/d3-array/src/ticks.js
var e10 = Math.sqrt(50);
var e5 = Math.sqrt(10);
var e2 = Math.sqrt(2);
function tickSpec(start, stop, count) {
const step = (stop - start) / Math.max(0, count), power = Math.floor(Math.log10(step)), error = step / Math.pow(10, power), factor = error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1;
let i1, i2, inc;
if (power < 0) {
inc = Math.pow(10, -power) / factor;
i1 = Math.round(start * inc);
i2 = Math.round(stop * inc);
if (i1 / inc < start) ++i1;
if (i2 / inc > stop) --i2;
inc = -inc;
} else {
inc = Math.pow(10, power) * factor;
i1 = Math.round(start / inc);
i2 = Math.round(stop / inc);
if (i1 * inc < start) ++i1;
if (i2 * inc > stop) --i2;
}
if (i2 < i1 && 0.5 <= count && count < 2) return tickSpec(start, stop, count * 2);
return [i1, i2, inc];
}
function ticks(start, stop, count) {
stop = +stop, start = +start, count = +count;
if (!(count > 0)) return [];
if (start === stop) return [start];
const reverse = stop < start, [i1, i2, inc] = reverse ? tickSpec(stop, start, count) : tickSpec(start, stop, count);
if (!(i2 >= i1)) return [];
const n = i2 - i1 + 1, ticks2 = new Array(n);
if (reverse) {
if (inc < 0) for (let i = 0; i < n; ++i) ticks2[i] = (i2 - i) / -inc;
else for (let i = 0; i < n; ++i) ticks2[i] = (i2 - i) * inc;
} else {
if (inc < 0) for (let i = 0; i < n; ++i) ticks2[i] = (i1 + i) / -inc;
else for (let i = 0; i < n; ++i) ticks2[i] = (i1 + i) * inc;
}
return ticks2;
}
function tickIncrement(start, stop, count) {
stop = +stop, start = +start, count = +count;
return tickSpec(start, stop, count)[2];
}
function tickStep(start, stop, count) {
stop = +stop, start = +start, count = +count;
const reverse = stop < start, inc = reverse ? tickIncrement(stop, start, count) : tickIncrement(start, stop, count);
return (reverse ? -1 : 1) * (inc < 0 ? 1 / -inc : inc);
}
// node_modules/d3-array/src/max.js
function max(values, valueof) {
let max2;
if (valueof === void 0) {
for (const value of values) {
if (value != null && (max2 < value || max2 === void 0 && value >= value)) {
max2 = value;
}
}
} else {
let index = -1;
for (let value of values) {
if ((value = valueof(value, ++index, values)) != null && (max2 < value || max2 === void 0 && value >= value)) {
max2 = value;
}
}
}
return max2;
}
// assets/src/shared/tooltip.ts
function createTooltip() {
document.querySelectorAll(".heatmap-tooltip").forEach((el) => el.remove());
const tip = document.createElement("div");
tip.className = "heatmap-tooltip";
tip.style.display = "none";
tip.style.position = "fixed";
document.body.appendChild(tip);
return tip;
}
function showTooltip(tip, html, anchorRect, cellSize) {
tip.innerHTML = html;
tip.style.display = "block";
tip.style.left = `${anchorRect.left + cellSize / 2}px`;
tip.style.top = `${anchorRect.top - tip.offsetHeight - 8}px`;
}
function hideTooltip(tip) {
tip.style.display = "none";
}
// node_modules/d3-scale/src/init.js
function initRange(domain, range) {
switch (arguments.length) {
case 0:
break;
case 1:
this.range(domain);
break;
default:
this.range(range).domain(domain);
break;
}
return this;
}
// node_modules/d3-format/src/formatDecimal.js
function formatDecimal_default(x) {
return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString("en").replace(/,/g, "") : x.toString(10);
}
function formatDecimalParts(x, p) {
if (!isFinite(x) || x === 0) return null;
var i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e"), coefficient = x.slice(0, i);
return [
coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
+x.slice(i + 1)
];
}
// node_modules/d3-format/src/exponent.js
function exponent_default(x) {
return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
}
// node_modules/d3-format/src/formatGroup.js
function formatGroup_default(grouping, thousands) {
return function(value, width) {
var i = value.length, t = [], j = 0, g = grouping[0], length = 0;
while (i > 0 && g > 0) {
if (length + g + 1 > width) g = Math.max(1, width - length);
t.push(value.substring(i -= g, i + g));
if ((length += g + 1) > width) break;
g = grouping[j = (j + 1) % grouping.length];
}
return t.reverse().join(thousands);
};
}
// node_modules/d3-format/src/formatNumerals.js
function formatNumerals_default(numerals) {
return function(value) {
return value.replace(/[0-9]/g, function(i) {
return numerals[+i];
});
};
}
// node_modules/d3-format/src/formatSpecifier.js
var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
function formatSpecifier(specifier) {
if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
var match;
return new FormatSpecifier({
fill: match[1],
align: match[2],
sign: match[3],
symbol: match[4],
zero: match[5],
width: match[6],
comma: match[7],
precision: match[8] && match[8].slice(1),
trim: match[9],
type: match[10]
});
}
formatSpecifier.prototype = FormatSpecifier.prototype;
function FormatSpecifier(specifier) {
this.fill = specifier.fill === void 0 ? " " : specifier.fill + "";
this.align = specifier.align === void 0 ? ">" : specifier.align + "";
this.sign = specifier.sign === void 0 ? "-" : specifier.sign + "";
this.symbol = specifier.symbol === void 0 ? "" : specifier.symbol + "";
this.zero = !!specifier.zero;
this.width = specifier.width === void 0 ? void 0 : +specifier.width;
this.comma = !!specifier.comma;
this.precision = specifier.precision === void 0 ? void 0 : +specifier.precision;
this.trim = !!specifier.trim;
this.type = specifier.type === void 0 ? "" : specifier.type + "";
}
FormatSpecifier.prototype.toString = function() {
return this.fill + this.align + this.sign + this.symbol + (this.zero ? "0" : "") + (this.width === void 0 ? "" : Math.max(1, this.width | 0)) + (this.comma ? "," : "") + (this.precision === void 0 ? "" : "." + Math.max(0, this.precision | 0)) + (this.trim ? "~" : "") + this.type;
};
// node_modules/d3-format/src/formatTrim.js
function formatTrim_default(s) {
out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {
switch (s[i]) {
case ".":
i0 = i1 = i;
break;
case "0":
if (i0 === 0) i0 = i;
i1 = i;
break;
default:
if (!+s[i]) break out;
if (i0 > 0) i0 = 0;
break;
}
}
return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
}
// node_modules/d3-format/src/formatPrefixAuto.js
var prefixExponent;
function formatPrefixAuto_default(x, p) {
var d = formatDecimalParts(x, p);
if (!d) return prefixExponent = void 0, x.toPrecision(p);
var coefficient = d[0], exponent = d[1], i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1, n = coefficient.length;
return i === n ? coefficient : i > n ? coefficient + new Array(i - n + 1).join("0") : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i) : "0." + new Array(1 - i).join("0") + formatDecimalParts(x, Math.max(0, p + i - 1))[0];
}
// node_modules/d3-format/src/formatRounded.js
function formatRounded_default(x, p) {
var d = formatDecimalParts(x, p);
if (!d) return x + "";
var coefficient = d[0], exponent = d[1];
return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1) : coefficient + new Array(exponent - coefficient.length + 2).join("0");
}
// node_modules/d3-format/src/formatTypes.js
var formatTypes_default = {
"%": (x, p) => (x * 100).toFixed(p),
"b": (x) => Math.round(x).toString(2),
"c": (x) => x + "",
"d": formatDecimal_default,
"e": (x, p) => x.toExponential(p),
"f": (x, p) => x.toFixed(p),
"g": (x, p) => x.toPrecision(p),
"o": (x) => Math.round(x).toString(8),
"p": (x, p) => formatRounded_default(x * 100, p),
"r": formatRounded_default,
"s": formatPrefixAuto_default,
"X": (x) => Math.round(x).toString(16).toUpperCase(),
"x": (x) => Math.round(x).toString(16)
};
// node_modules/d3-format/src/identity.js
function identity_default(x) {
return x;
}
// node_modules/d3-format/src/locale.js
var map = Array.prototype.map;
var prefixes = ["y", "z", "a", "f", "p", "n", "\xB5", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"];
function locale_default(locale3) {
var group = locale3.grouping === void 0 || locale3.thousands === void 0 ? identity_default : formatGroup_default(map.call(locale3.grouping, Number), locale3.thousands + ""), currencyPrefix = locale3.currency === void 0 ? "" : locale3.currency[0] + "", currencySuffix = locale3.currency === void 0 ? "" : locale3.currency[1] + "", decimal = locale3.decimal === void 0 ? "." : locale3.decimal + "", numerals = locale3.numerals === void 0 ? identity_default : formatNumerals_default(map.call(locale3.numerals, String)), percent = locale3.percent === void 0 ? "%" : locale3.percent + "", minus = locale3.minus === void 0 ? "\u2212" : locale3.minus + "", nan = locale3.nan === void 0 ? "NaN" : locale3.nan + "";
function newFormat(specifier, options) {
specifier = formatSpecifier(specifier);
var fill = specifier.fill, align = specifier.align, sign = specifier.sign, symbol = specifier.symbol, zero2 = specifier.zero, width = specifier.width, comma = specifier.comma, precision = specifier.precision, trim = specifier.trim, type = specifier.type;
if (type === "n") comma = true, type = "g";
else if (!formatTypes_default[type]) precision === void 0 && (precision = 12), trim = true, type = "g";
if (zero2 || fill === "0" && align === "=") zero2 = true, fill = "0", align = "=";
var prefix = (options && options.prefix !== void 0 ? options.prefix : "") + (symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : ""), suffix = (symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : "") + (options && options.suffix !== void 0 ? options.suffix : "");
var formatType = formatTypes_default[type], maybeSuffix = /[defgprs%]/.test(type);
precision = precision === void 0 ? 6 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision));
function format2(value) {
var valuePrefix = prefix, valueSuffix = suffix, i, n, c;
if (type === "c") {
valueSuffix = formatType(value) + valueSuffix;
value = "";
} else {
value = +value;
var valueNegative = value < 0 || 1 / value < 0;
value = isNaN(value) ? nan : formatType(Math.abs(value), precision);
if (trim) value = formatTrim_default(value);
if (valueNegative && +value === 0 && sign !== "+") valueNegative = false;
valuePrefix = (valueNegative ? sign === "(" ? sign : minus : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
valueSuffix = (type === "s" && !isNaN(value) && prefixExponent !== void 0 ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : "");
if (maybeSuffix) {
i = -1, n = value.length;
while (++i < n) {
if (c = value.charCodeAt(i), 48 > c || c > 57) {
valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
value = value.slice(0, i);
break;
}
}
}
}
if (comma && !zero2) value = group(value, Infinity);
var length = valuePrefix.length + value.length + valueSuffix.length, padding = length < width ? new Array(width - length + 1).join(fill) : "";
if (comma && zero2) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
switch (align) {
case "<":
value = valuePrefix + value + valueSuffix + padding;
break;
case "=":
value = valuePrefix + padding + value + valueSuffix;
break;
case "^":
value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
break;
default:
value = padding + valuePrefix + value + valueSuffix;
break;
}
return numerals(value);
}
format2.toString = function() {
return specifier + "";
};
return format2;
}
function formatPrefix2(specifier, value) {
var e = Math.max(-8, Math.min(8, Math.floor(exponent_default(value) / 3))) * 3, k = Math.pow(10, -e), f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier), { suffix: prefixes[8 + e / 3] });
return function(value2) {
return f(k * value2);
};
}
return {
format: newFormat,
formatPrefix: formatPrefix2
};
}
// node_modules/d3-format/src/defaultLocale.js
var locale;
var format;
var formatPrefix;
defaultLocale({
thousands: ",",
grouping: [3],
currency: ["$", ""]
});
function defaultLocale(definition) {
locale = locale_default(definition);
format = locale.format;
formatPrefix = locale.formatPrefix;
return locale;
}
// node_modules/d3-format/src/precisionFixed.js
function precisionFixed_default(step) {
return Math.max(0, -exponent_default(Math.abs(step)));
}
// node_modules/d3-format/src/precisionPrefix.js
function precisionPrefix_default(step, value) {
return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent_default(value) / 3))) * 3 - exponent_default(Math.abs(step)));
}
// node_modules/d3-format/src/precisionRound.js
function precisionRound_default(step, max2) {
step = Math.abs(step), max2 = Math.abs(max2) - step;
return Math.max(0, exponent_default(max2) - exponent_default(step)) + 1;
}
// node_modules/d3-scale/src/tickFormat.js
function tickFormat(start, stop, count, specifier) {
var step = tickStep(start, stop, count), precision;
specifier = formatSpecifier(specifier == null ? ",f" : specifier);
switch (specifier.type) {
case "s": {
var value = Math.max(Math.abs(start), Math.abs(stop));
if (specifier.precision == null && !isNaN(precision = precisionPrefix_default(step, value))) specifier.precision = precision;
return formatPrefix(specifier, value);
}
case "":
case "e":
case "g":
case "p":
case "r": {
if (specifier.precision == null && !isNaN(precision = precisionRound_default(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
break;
}
case "f":
case "%": {
if (specifier.precision == null && !isNaN(precision = precisionFixed_default(step))) specifier.precision = precision - (specifier.type === "%") * 2;
break;
}
}
return format(specifier);
}
// node_modules/d3-scale/src/linear.js
function linearish(scale) {
var domain = scale.domain;
scale.ticks = function(count) {
var d = domain();
return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
};
scale.tickFormat = function(count, specifier) {
var d = domain();
return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
};
scale.nice = function(count) {
if (count == null) count = 10;
var d = domain();
var i0 = 0;
var i1 = d.length - 1;
var start = d[i0];
var stop = d[i1];
var prestep;
var step;
var maxIter = 10;
if (stop < start) {
step = start, start = stop, stop = step;
step = i0, i0 = i1, i1 = step;
}
while (maxIter-- > 0) {
step = tickIncrement(start, stop, count);
if (step === prestep) {
d[i0] = start;
d[i1] = stop;
return domain(d);
} else if (step > 0) {
start = Math.floor(start / step) * step;
stop = Math.ceil(stop / step) * step;
} else if (step < 0) {
start = Math.ceil(start * step) / step;
stop = Math.floor(stop * step) / step;
} else {
break;
}
prestep = step;
}
return scale;
};
return scale;
}
// node_modules/d3-scale/src/quantize.js
function quantize() {
var x0 = 0, x1 = 1, n = 1, domain = [0.5], range = [0, 1], unknown;
function scale(x) {
return x != null && x <= x ? range[bisect_default(domain, x, 0, n)] : unknown;
}
function rescale() {
var i = -1;
domain = new Array(n);
while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
return scale;
}
scale.domain = function(_) {
return arguments.length ? ([x0, x1] = _, x0 = +x0, x1 = +x1, rescale()) : [x0, x1];
};
scale.range = function(_) {
return arguments.length ? (n = (range = Array.from(_)).length - 1, rescale()) : range.slice();
};
scale.invertExtent = function(y) {
var i = range.indexOf(y);
return i < 0 ? [NaN, NaN] : i < 1 ? [x0, domain[0]] : i >= n ? [domain[n - 1], x1] : [domain[i - 1], domain[i]];
};
scale.unknown = function(_) {
return arguments.length ? (unknown = _, scale) : scale;
};
scale.thresholds = function() {
return domain.slice();
};
scale.copy = function() {
return quantize().domain([x0, x1]).range(range).unknown(unknown);
};
return initRange.apply(linearish(scale), arguments);
}
// node_modules/d3-time-format/src/locale.js
function localDate(d) {
if (0 <= d.y && d.y < 100) {
var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L);
date.setFullYear(d.y);
return date;
}
return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L);
}
function utcDate(d) {
if (0 <= d.y && d.y < 100) {
var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L));
date.setUTCFullYear(d.y);
return date;
}
return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));
}
function newDate(y, m, d) {
return { y, m, d, H: 0, M: 0, S: 0, L: 0 };
}
function formatLocale(locale3) {
var locale_dateTime = locale3.dateTime, locale_date = locale3.date, locale_time = locale3.time, locale_periods = locale3.periods, locale_weekdays = locale3.days, locale_shortWeekdays = locale3.shortDays, locale_months = locale3.months, locale_shortMonths = locale3.shortMonths;
var periodRe = formatRe(locale_periods), periodLookup = formatLookup(locale_periods), weekdayRe = formatRe(locale_weekdays), weekdayLookup = formatLookup(locale_weekdays), shortWeekdayRe = formatRe(locale_shortWeekdays), shortWeekdayLookup = formatLookup(locale_shortWeekdays), monthRe = formatRe(locale_months), monthLookup = formatLookup(locale_months), shortMonthRe = formatRe(locale_shortMonths), shortMonthLookup = formatLookup(locale_shortMonths);
var formats = {
"a": formatShortWeekday,
"A": formatWeekday,
"b": formatShortMonth,
"B": formatMonth,
"c": null,
"d": formatDayOfMonth,
"e": formatDayOfMonth,
"f": formatMicroseconds,
"g": formatYearISO,
"G": formatFullYearISO,
"H": formatHour24,
"I": formatHour12,
"j": formatDayOfYear,
"L": formatMilliseconds,
"m": formatMonthNumber,
"M": formatMinutes,
"p": formatPeriod,
"q": formatQuarter,
"Q": formatUnixTimestamp,
"s": formatUnixTimestampSeconds,
"S": formatSeconds,
"u": formatWeekdayNumberMonday,
"U": formatWeekNumberSunday,
"V": formatWeekNumberISO,
"w": formatWeekdayNumberSunday,
"W": formatWeekNumberMonday,
"x": null,
"X": null,
"y": formatYear,
"Y": formatFullYear,
"Z": formatZone,
"%": formatLiteralPercent
};
var utcFormats = {
"a": formatUTCShortWeekday,
"A": formatUTCWeekday,
"b": formatUTCShortMonth,
"B": formatUTCMonth,
"c": null,
"d": formatUTCDayOfMonth,
"e": formatUTCDayOfMonth,
"f": formatUTCMicroseconds,
"g": formatUTCYearISO,
"G": formatUTCFullYearISO,
"H": formatUTCHour24,
"I": formatUTCHour12,
"j": formatUTCDayOfYear,
"L": formatUTCMilliseconds,
"m": formatUTCMonthNumber,
"M": formatUTCMinutes,
"p": formatUTCPeriod,
"q": formatUTCQuarter,
"Q": formatUnixTimestamp,
"s": formatUnixTimestampSeconds,
"S": formatUTCSeconds,
"u": formatUTCWeekdayNumberMonday,
"U": formatUTCWeekNumberSunday,
"V": formatUTCWeekNumberISO,
"w": formatUTCWeekdayNumberSunday,
"W": formatUTCWeekNumberMonday,
"x": null,
"X": null,
"y": formatUTCYear,
"Y": formatUTCFullYear,
"Z": formatUTCZone,
"%": formatLiteralPercent
};
var parses = {
"a": parseShortWeekday,
"A": parseWeekday,
"b": parseShortMonth,
"B": parseMonth,
"c": parseLocaleDateTime,
"d": parseDayOfMonth,
"e": parseDayOfMonth,
"f": parseMicroseconds,
"g": parseYear,
"G": parseFullYear,
"H": parseHour24,
"I": parseHour24,
"j": parseDayOfYear,
"L": parseMilliseconds,
"m": parseMonthNumber,
"M": parseMinutes,
"p": parsePeriod,
"q": parseQuarter,
"Q": parseUnixTimestamp,
"s": parseUnixTimestampSeconds,
"S": parseSeconds,
"u": parseWeekdayNumberMonday,
"U": parseWeekNumberSunday,
"V": parseWeekNumberISO,
"w": parseWeekdayNumberSunday,
"W": parseWeekNumberMonday,
"x": parseLocaleDate,
"X": parseLocaleTime,
"y": parseYear,
"Y": parseFullYear,
"Z": parseZone,
"%": parseLiteralPercent
};
formats.x = newFormat(locale_date, formats);
formats.X = newFormat(locale_time, formats);
formats.c = newFormat(locale_dateTime, formats);
utcFormats.x = newFormat(locale_date, utcFormats);
utcFormats.X = newFormat(locale_time, utcFormats);
utcFormats.c = newFormat(locale_dateTime, utcFormats);
function newFormat(specifier, formats2) {
return function(date) {
var string = [], i = -1, j = 0, n = specifier.length, c, pad2, format2;
if (!(date instanceof Date)) date = /* @__PURE__ */ new Date(+date);
while (++i < n) {
if (specifier.charCodeAt(i) === 37) {
string.push(specifier.slice(j, i));
if ((pad2 = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);
else pad2 = c === "e" ? " " : "0";
if (format2 = formats2[c]) c = format2(date, pad2);
string.push(c);
j = i + 1;
}
}
string.push(specifier.slice(j, i));
return string.join("");
};
}
function newParse(specifier, Z) {
return function(string) {
var d = newDate(1900, void 0, 1), i = parseSpecifier(d, specifier, string += "", 0), week, day;
if (i != string.length) return null;
if ("Q" in d) return new Date(d.Q);
if ("s" in d) return new Date(d.s * 1e3 + ("L" in d ? d.L : 0));
if (Z && !("Z" in d)) d.Z = 0;
if ("p" in d) d.H = d.H % 12 + d.p * 12;
if (d.m === void 0) d.m = "q" in d ? d.q : 0;
if ("V" in d) {
if (d.V < 1 || d.V > 53) return null;
if (!("w" in d)) d.w = 1;
if ("Z" in d) {
week = utcDate(newDate(d.y, 0, 1)), day = week.getUTCDay();
week = day > 4 || day === 0 ? utcMonday.ceil(week) : utcMonday(week);
week = utcDay.offset(week, (d.V - 1) * 7);
d.y = week.getUTCFullYear();
d.m = week.getUTCMonth();
d.d = week.getUTCDate() + (d.w + 6) % 7;
} else {
week = localDate(newDate(d.y, 0, 1)), day = week.getDay();
week = day > 4 || day === 0 ? timeMonday.ceil(week) : timeMonday(week);
week = timeDay.offset(week, (d.V - 1) * 7);
d.y = week.getFullYear();
d.m = week.getMonth();
d.d = week.getDate() + (d.w + 6) % 7;
}
} else if ("W" in d || "U" in d) {
if (!("w" in d)) d.w = "u" in d ? d.u % 7 : "W" in d ? 1 : 0;
day = "Z" in d ? utcDate(newDate(d.y, 0, 1)).getUTCDay() : localDate(newDate(d.y, 0, 1)).getDay();
d.m = 0;
d.d = "W" in d ? (d.w + 6) % 7 + d.W * 7 - (day + 5) % 7 : d.w + d.U * 7 - (day + 6) % 7;
}
if ("Z" in d) {
d.H += d.Z / 100 | 0;
d.M += d.Z % 100;
return utcDate(d);
}
return localDate(d);
};
}
function parseSpecifier(d, specifier, string, j) {
var i = 0, n = specifier.length, m = string.length, c, parse;
while (i < n) {
if (j >= m) return -1;
c = specifier.charCodeAt(i++);
if (c === 37) {
c = specifier.charAt(i++);
parse = parses[c in pads ? specifier.charAt(i++) : c];
if (!parse || (j = parse(d, string, j)) < 0) return -1;
} else if (c != string.charCodeAt(j++)) {
return -1;
}
}
return j;
}
function parsePeriod(d, string, i) {
var n = periodRe.exec(string.slice(i));
return n ? (d.p = periodLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
}
function parseShortWeekday(d, string, i) {
var n = shortWeekdayRe.exec(string.slice(i));
return n ? (d.w = shortWeekdayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
}
function parseWeekday(d, string, i) {
var n = weekdayRe.exec(string.slice(i));
return n ? (d.w = weekdayLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
}
function parseShortMonth(d, string, i) {
var n = shortMonthRe.exec(string.slice(i));
return n ? (d.m = shortMonthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
}
function parseMonth(d, string, i) {
var n = monthRe.exec(string.slice(i));
return n ? (d.m = monthLookup.get(n[0].toLowerCase()), i + n[0].length) : -1;
}
function parseLocaleDateTime(d, string, i) {
return parseSpecifier(d, locale_dateTime, string, i);
}
function parseLocaleDate(d, string, i) {
return parseSpecifier(d, locale_date, string, i);
}
function parseLocaleTime(d, string, i) {
return parseSpecifier(d, locale_time, string, i);
}
function formatShortWeekday(d) {
return locale_shortWeekdays[d.getDay()];
}
function formatWeekday(d) {
return locale_weekdays[d.getDay()];
}
function formatShortMonth(d) {
return locale_shortMonths[d.getMonth()];
}
function formatMonth(d) {
return locale_months[d.getMonth()];
}
function formatPeriod(d) {
return locale_periods[+(d.getHours() >= 12)];
}
function formatQuarter(d) {
return 1 + ~~(d.getMonth() / 3);
}
function formatUTCShortWeekday(d) {
return locale_shortWeekdays[d.getUTCDay()];
}
function formatUTCWeekday(d) {
return locale_weekdays[d.getUTCDay()];
}
function formatUTCShortMonth(d) {
return locale_shortMonths[d.getUTCMonth()];
}
function formatUTCMonth(d) {
return locale_months[d.getUTCMonth()];
}
function formatUTCPeriod(d) {
return locale_periods[+(d.getUTCHours() >= 12)];
}
function formatUTCQuarter(d) {
return 1 + ~~(d.getUTCMonth() / 3);
}
return {
format: function(specifier) {
var f = newFormat(specifier += "", formats);
f.toString = function() {
return specifier;
};
return f;
},
parse: function(specifier) {
var p = newParse(specifier += "", false);
p.toString = function() {
return specifier;
};
return p;
},
utcFormat: function(specifier) {
var f = newFormat(specifier += "", utcFormats);
f.toString = function() {
return specifier;
};
return f;
},
utcParse: function(specifier) {
var p = newParse(specifier += "", true);
p.toString = function() {
return specifier;
};
return p;
}
};
}
var pads = { "-": "", "_": " ", "0": "0" };
var numberRe = /^\s*\d+/;
var percentRe = /^%/;
var requoteRe = /[\\^$*+?|[\]().{}]/g;
function pad(value, fill, width) {
var sign = value < 0 ? "-" : "", string = (sign ? -value : value) + "", length = string.length;
return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
}
function requote(s) {
return s.replace(requoteRe, "\\$&");
}
function formatRe(names) {
return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i");
}
function formatLookup(names) {
return new Map(names.map((name, i) => [name.toLowerCase(), i]));
}
function parseWeekdayNumberSunday(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 1));
return n ? (d.w = +n[0], i + n[0].length) : -1;
}
function parseWeekdayNumberMonday(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 1));
return n ? (d.u = +n[0], i + n[0].length) : -1;
}
function parseWeekNumberSunday(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.U = +n[0], i + n[0].length) : -1;
}
function parseWeekNumberISO(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.V = +n[0], i + n[0].length) : -1;
}
function parseWeekNumberMonday(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.W = +n[0], i + n[0].length) : -1;
}
function parseFullYear(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 4));
return n ? (d.y = +n[0], i + n[0].length) : -1;
}
function parseYear(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2e3), i + n[0].length) : -1;
}
function parseZone(d, string, i) {
var n = /^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(string.slice(i, i + 6));
return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || "00")), i + n[0].length) : -1;
}
function parseQuarter(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 1));
return n ? (d.q = n[0] * 3 - 3, i + n[0].length) : -1;
}
function parseMonthNumber(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.m = n[0] - 1, i + n[0].length) : -1;
}
function parseDayOfMonth(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.d = +n[0], i + n[0].length) : -1;
}
function parseDayOfYear(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 3));
return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1;
}
function parseHour24(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.H = +n[0], i + n[0].length) : -1;
}
function parseMinutes(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.M = +n[0], i + n[0].length) : -1;
}
function parseSeconds(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.S = +n[0], i + n[0].length) : -1;
}
function parseMilliseconds(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 3));
return n ? (d.L = +n[0], i + n[0].length) : -1;
}
function parseMicroseconds(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 6));
return n ? (d.L = Math.floor(n[0] / 1e3), i + n[0].length) : -1;
}
function parseLiteralPercent(d, string, i) {
var n = percentRe.exec(string.slice(i, i + 1));
return n ? i + n[0].length : -1;
}
function parseUnixTimestamp(d, string, i) {
var n = numberRe.exec(string.slice(i));
return n ? (d.Q = +n[0], i + n[0].length) : -1;
}
function parseUnixTimestampSeconds(d, string, i) {
var n = numberRe.exec(string.slice(i));
return n ? (d.s = +n[0], i + n[0].length) : -1;
}
function formatDayOfMonth(d, p) {
return pad(d.getDate(), p, 2);
}
function formatHour24(d, p) {
return pad(d.getHours(), p, 2);
}
function formatHour12(d, p) {
return pad(d.getHours() % 12 || 12, p, 2);
}
function formatDayOfYear(d, p) {
return pad(1 + timeDay.count(timeYear(d), d), p, 3);
}
function formatMilliseconds(d, p) {
return pad(d.getMilliseconds(), p, 3);
}
function formatMicroseconds(d, p) {
return formatMilliseconds(d, p) + "000";
}
function formatMonthNumber(d, p) {
return pad(d.getMonth() + 1, p, 2);
}
function formatMinutes(d, p) {
return pad(d.getMinutes(), p, 2);
}
function formatSeconds(d, p) {
return pad(d.getSeconds(), p, 2);
}
function formatWeekdayNumberMonday(d) {
var day = d.getDay();
return day === 0 ? 7 : day;
}
function formatWeekNumberSunday(d, p) {
return pad(timeSunday.count(timeYear(d) - 1, d), p, 2);
}
function dISO(d) {
var day = d.getDay();
return day >= 4 || day === 0 ? timeThursday(d) : timeThursday.ceil(d);
}
function formatWeekNumberISO(d, p) {
d = dISO(d);
return pad(timeThursday.count(timeYear(d), d) + (timeYear(d).getDay() === 4), p, 2);
}
function formatWeekdayNumberSunday(d) {
return d.getDay();
}
function formatWeekNumberMonday(d, p) {
return pad(timeMonday.count(timeYear(d) - 1, d), p, 2);
}
function formatYear(d, p) {
return pad(d.getFullYear() % 100, p, 2);
}
function formatYearISO(d, p) {
d = dISO(d);
return pad(d.getFullYear() % 100, p, 2);
}
function formatFullYear(d, p) {
return pad(d.getFullYear() % 1e4, p, 4);
}
function formatFullYearISO(d, p) {
var day = d.getDay();
d = day >= 4 || day === 0 ? timeThursday(d) : timeThursday.ceil(d);
return pad(d.getFullYear() % 1e4, p, 4);
}
function formatZone(d) {
var z = d.getTimezoneOffset();
return (z > 0 ? "-" : (z *= -1, "+")) + pad(z / 60 | 0, "0", 2) + pad(z % 60, "0", 2);
}
function formatUTCDayOfMonth(d, p) {
return pad(d.getUTCDate(), p, 2);
}
function formatUTCHour24(d, p) {
return pad(d.getUTCHours(), p, 2);
}
function formatUTCHour12(d, p) {
return pad(d.getUTCHours() % 12 || 12, p, 2);
}
function formatUTCDayOfYear(d, p) {
return pad(1 + utcDay.count(utcYear(d), d), p, 3);
}
function formatUTCMilliseconds(d, p) {
return pad(d.getUTCMilliseconds(), p, 3);
}
function formatUTCMicroseconds(d, p) {
return formatUTCMilliseconds(d, p) + "000";
}
function formatUTCMonthNumber(d, p) {
return pad(d.getUTCMonth() + 1, p, 2);
}
function formatUTCMinutes(d, p) {
return pad(d.getUTCMinutes(), p, 2);
}
function formatUTCSeconds(d, p) {
return pad(d.getUTCSeconds(), p, 2);
}
function formatUTCWeekdayNumberMonday(d) {
var dow = d.getUTCDay();
return dow === 0 ? 7 : dow;
}
function formatUTCWeekNumberSunday(d, p) {
return pad(utcSunday.count(utcYear(d) - 1, d), p, 2);
}
function UTCdISO(d) {
var day = d.getUTCDay();
return day >= 4 || day === 0 ? utcThursday(d) : utcThursday.ceil(d);
}
function formatUTCWeekNumberISO(d, p) {
d = UTCdISO(d);
return pad(utcThursday.count(utcYear(d), d) + (utcYear(d).getUTCDay() === 4), p, 2);
}
function formatUTCWeekdayNumberSunday(d) {
return d.getUTCDay();
}
function formatUTCWeekNumberMonday(d, p) {
return pad(utcMonday.count(utcYear(d) - 1, d), p, 2);
}
function formatUTCYear(d, p) {
return pad(d.getUTCFullYear() % 100, p, 2);
}
function formatUTCYearISO(d, p) {
d = UTCdISO(d);
return pad(d.getUTCFullYear() % 100, p, 2);
}
function formatUTCFullYear(d, p) {
return pad(d.getUTCFullYear() % 1e4, p, 4);
}
function formatUTCFullYearISO(d, p) {
var day = d.getUTCDay();
d = day >= 4 || day === 0 ? utcThursday(d) : utcThursday.ceil(d);
return pad(d.getUTCFullYear() % 1e4, p, 4);
}
function formatUTCZone() {
return "+0000";
}
function formatLiteralPercent() {
return "%";
}
function formatUnixTimestamp(d) {
return +d;
}
function formatUnixTimestampSeconds(d) {
return Math.floor(+d / 1e3);
}
// node_modules/d3-time-format/src/defaultLocale.js
var locale2;
var timeFormat;
var timeParse;
var utcFormat;
var utcParse;
defaultLocale2({
dateTime: "%x, %X",
date: "%-m/%-d/%Y",
time: "%-I:%M:%S %p",
periods: ["AM", "PM"],
days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
});
function defaultLocale2(definition) {
locale2 = formatLocale(definition);
timeFormat = locale2.format;
timeParse = locale2.parse;
utcFormat = locale2.utcFormat;
utcParse = locale2.utcParse;
return locale2;
}
// assets/src/shared/color-scale.ts
var FALLBACK_COLORS = ["#9be9a8", "#40c463", "#30a14e", "#216e39"];
function buildColorScale(days, metric = "hours") {
const accessor = metric === "hours" ? (d) => d.hours : (d) => d.count;
const maxVal = max(days, accessor) || 1;
return quantize().domain([0, maxVal]).range(FALLBACK_COLORS);
}
// assets/src/shared/date-utils.ts
var DAY_LABELS_MONDAY = ["Mon", "", "Wed", "", "Fri", "", ""];
var DAY_LABELS_SUNDAY = ["Sun", "", "Tue", "", "Thu", "", "Sat"];
function getDayLabels(weekStart) {
return weekStart === "sunday" ? DAY_LABELS_SUNDAY : DAY_LABELS_MONDAY;
}
var MONTH_FORMAT = timeFormat("%b");
var DATE_FORMAT = timeFormat("%Y-%m-%d");
var DISPLAY_FORMAT = timeFormat("%a, %b %-d, %Y");
function buildDateMap(days) {
const map2 = /* @__PURE__ */ new Map();
for (const d of days) {
map2.set(d.date, d);
}
return map2;
}
function getWeekInterval(weekStart) {
return weekStart === "sunday" ? timeSunday : timeMonday;
}
function generateCells(begin, end, dateMap, weekStart = "monday") {
const weekInterval = getWeekInterval(weekStart);
const firstWeekDay = weekInterval.floor(begin);
const cells = [];
let current = new Date(begin);
while (current <= end) {
const dateStr = DATE_FORMAT(current);
const weeksSinceStart = weekInterval.count(firstWeekDay, current);
const jsDay = current.getDay();
const dayOfWeek = weekStart === "sunday" ? jsDay : (jsDay + 6) % 7;
const isWeekend = jsDay === 0 || jsDay === 6;
cells.push({
date: new Date(current),
dateStr,
entry: dateMap.get(dateStr) || null,
week: weeksSinceStart,
day: dayOfWeek,
isWeekend
});
current = timeDay.offset(current, 1);
}
return cells;
}
// assets/src/renderers/year.ts
var YearModeRenderer = class {
mode = "year";
tooltip = null;
render(ctx) {
ctx.container.innerHTML = "";
if (!ctx.data.days || ctx.data.days.length === 0) {
const msg = document.createElement("div");
msg.textContent = ctx.emptyMessage || "No tracking data available";
msg.style.padding = "1rem";
msg.style.color = "var(--tblr-secondary, #6c757d)";
ctx.container.appendChild(msg);
return;
}
this.destroy();
this.tooltip = createTooltip();
const weekStart = ctx.state.weekStart;
const dateMap = buildDateMap(ctx.data.days);
const begin = new Date(ctx.data.range.begin);
const end = new Date(ctx.data.range.end);
const cells = generateCells(begin, end, dateMap, weekStart);
const colorScale = buildColorScale(ctx.data.days, ctx.state.metric);
const { cellGap, marginTop, marginLeft, marginBottom } = ctx.config;
const numWeeks = (max(cells, (c) => c.week) ?? 0) + 1;
const containerWidth = ctx.container.clientWidth || 800;
const maxCellSize = 22;
const minCellSize = 13;
const cellSize = Math.min(maxCellSize, Math.max(minCellSize, Math.floor((containerWidth - marginLeft) / numWeeks) - cellGap));
const step = cellSize + cellGap;
const svgWidth = marginLeft + numWeeks * step;
const svgHeight = marginTop + 7 * step + marginBottom;
const wrapper = document.createElement("div");
wrapper.style.maxWidth = `${svgWidth}px`;
wrapper.style.margin = "0 auto";
ctx.container.appendChild(wrapper);
const svg = select_default2(wrapper).append("svg").attr("width", svgWidth).attr("height", svgHeight).attr("class", "heatmap-svg");
const weekInterval = getWeekInterval(weekStart);
const months = [];
const firstWeekDay = weekInterval.floor(begin);
timeMonth.range(timeMonth.ceil(begin), end).forEach((m) => {
months.push({ date: m, week: weekInterval.count(firstWeekDay, m) });
});
svg.selectAll(".month-label").data(months).join("text").attr("class", "heatmap-label month-label").attr("x", (d) => marginLeft + d.week * step).attr("y", marginTop - 6).text((d) => MONTH_FORMAT(d.date));
svg.selectAll(".day-label").data(getDayLabels(weekStart)).join("text").attr("class", "heatmap-label day-label").attr("x", marginLeft - 6).attr("y", (_d, i) => marginTop + i * step + cellSize - 2).attr("text-anchor", "end").text((d) => d);
const tooltip = this.tooltip;
svg.selectAll(".heatmap-cell").data(cells).join("rect").attr("class", (d) => {
let cls = "heatmap-cell";
if (!d.entry) cls += " heatmap-empty";
if (d.isWeekend) cls += " heatmap-weekend";
return cls;
}).attr("x", (d) => marginLeft + d.week * step).attr("y", (d) => marginTop + d.day * step).attr("width", cellSize).attr("height", cellSize).attr("fill", (d) => {
if (!d.entry) return "";
const val = ctx.state.metric === "hours" ? d.entry.hours : d.entry.count;
return colorScale(val);
}).on("mouseenter", function(event, d) {
const hours = d.entry ? d.entry.hours.toFixed(1) : "0.0";
const count = d.entry ? d.entry.count : 0;
const html = `<strong>${DISPLAY_FORMAT(d.date)}</strong><br>${hours}h (${count} entries)`;
const rect = event.target.getBoundingClientRect();
showTooltip(tooltip, html, rect, cellSize);
}).on("mouseleave", function() {
hideTooltip(tooltip);
}).on("click", function(_event, d) {
if (!ctx.onCellClick) return;
ctx.onCellClick(d.dateStr);
});
}
destroy() {
this.tooltip?.remove();
this.tooltip = null;
}
};
// assets/src/renderers/week.ts
var WEEKDAY_NAMES_MONDAY = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"];
var WEEKDAY_NAMES_SUNDAY = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
var WEEKDAY_SHORT_MONDAY = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
var WEEKDAY_SHORT_SUNDAY = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
function aggregateByWeekday(days, weekStart) {
const names = weekStart === "sunday" ? WEEKDAY_NAMES_SUNDAY : WEEKDAY_NAMES_MONDAY;
const shorts = weekStart === "sunday" ? WEEKDAY_SHORT_SUNDAY : WEEKDAY_SHORT_MONDAY;
const buckets = Array.from({ length: 7 }, (_, i) => ({
dayIndex: i,
label: names[i],
shortLabel: shorts[i],
totalHours: 0,
totalCount: 0,
dayCount: 0
}));
const seenDates = /* @__PURE__ */ new Map();
for (const d of days) {
const jsDay = (/* @__PURE__ */ new Date(d.date + "T00:00:00")).getDay();
const idx = weekStart === "sunday" ? jsDay : (jsDay + 6) % 7;
buckets[idx].totalHours += d.hours;
buckets[idx].totalCount += d.count;
if (!seenDates.has(idx)) seenDates.set(idx, /* @__PURE__ */ new Set());
seenDates.get(idx).add(d.date);
}
for (const [idx, dates] of seenDates) {
buckets[idx].dayCount = dates.size;
}
return buckets;
}
var WeekModeRenderer = class {
mode = "week";
tooltip = null;
render(ctx) {
ctx.container.innerHTML = "";
if (!ctx.data.days || ctx.data.days.length === 0) {
const msg = document.createElement("div");
msg.textContent = ctx.emptyMessage || "No tracking data available";
msg.style.padding = "1rem";
msg.style.color = "var(--tblr-secondary, #6c757d)";
ctx.container.appendChild(msg);
return;
}
this.destroy();
this.tooltip = createTooltip();
const aggregates = aggregateByWeekday(ctx.data.days, ctx.state.weekStart);
const syntheticDays = aggregates.filter((a) => a.dayCount > 0).map((a) => ({ date: "", hours: a.totalHours, count: a.totalCount }));
const colorScale = buildColorScale(syntheticDays, ctx.state.metric);
const cellWidth = 60;
const cellHeight = 40;
const cellGap = 4;
const labelWidth = 50;
const labelHeight = 16;
const totalWidth = labelWidth + 7 * (cellWidth + cellGap);
const totalHeight = labelHeight + cellHeight;
const wrapper = document.createElement("div");
wrapper.style.maxWidth = `${totalWidth}px`;
wrapper.style.margin = "0 auto";
ctx.container.appendChild(wrapper);
const svg = select_default2(wrapper).append("svg").attr("width", totalWidth).attr("height", totalHeight).attr("class", "heatmap-svg");
const tooltip = this.tooltip;
const metric = ctx.state.metric;
aggregates.forEach((agg, i) => {
svg.append("text").attr("class", "heatmap-label").attr("x", labelWidth + i * (cellWidth + cellGap) + cellWidth / 2).attr("y", labelHeight - 2).attr("text-anchor", "middle").text(agg.shortLabel);
});
aggregates.forEach((agg, i) => {
const hasData = agg.dayCount > 0;
const cls = "heatmap-week-cell" + (hasData ? "" : " heatmap-empty");
const fill = hasData ? colorScale(metric === "hours" ? agg.totalHours : agg.totalCount) : "";
svg.append("rect").attr("class", cls).attr("x", labelWidth + i * (cellWidth + cellGap)).attr("y", labelHeight).attr("width", cellWidth).attr("height", cellHeight).attr("fill", fill).attr("rx", 2).attr("ry", 2).on("mouseenter", function(event) {
let html;
if (hasData) {
if (metric === "hours") {
html = `<strong>${agg.label}</strong><br>${agg.totalHours.toFixed(1)}h (${agg.totalCount} entries)`;
} else {
html = `<strong>${agg.label}</strong><br>${agg.totalCount} entries (${agg.totalHours.toFixed(1)}h)`;
}
} else {
html = `<strong>${agg.label}</strong><br>No tracked time`;
}
const rect = event.target.getBoundingClientRect();
showTooltip(tooltip, html, rect, cellWidth);
}).on("mouseleave", function() {
hideTooltip(tooltip);
});
});
}
destroy() {
this.tooltip?.remove();
this.tooltip = null;
}
};
// assets/src/shared/stats.ts
var DATE_FORMAT2 = timeFormat("%Y-%m-%d");
var DISPLAY_FORMAT2 = timeFormat("%a, %b %-d, %Y");
function calculateStreak(days) {
if (days.length === 0) return 0;
const tracked = new Set(
days.filter((d) => d.hours > 0).map((d) => d.date)
);
if (tracked.size === 0) return 0;
const today = /* @__PURE__ */ new Date();
today.setHours(0, 0, 0, 0);
let current = new Date(today);
if (!tracked.has(DATE_FORMAT2(current))) {
current = timeDay.offset(current, -1);
}
let streak = 0;
while (tracked.has(DATE_FORMAT2(current))) {
streak++;
current = timeDay.offset(current, -1);
}
return streak;
}
function calculateStats(days) {
const withEntries = days.filter((d) => d.hours > 0);
if (withEntries.length === 0) {
return { totalHours: 0, avgHours: 0, busiestDay: null };
}
const totalHours = Math.round(withEntries.reduce((sum, d) => sum + d.hours, 0) * 10) / 10;
const avgHours = Math.round(totalHours / withEntries.length * 10) / 10;
const busiest = withEntries.reduce((best, d) => d.hours > best.hours ? d : best);
return {
totalHours,
avgHours,
busiestDay: { date: busiest.date, hours: busiest.hours }
};
}
function renderStats(container, days) {
const existing = container.querySelector(".heatmap-stats");
if (existing) existing.remove();
const streak = calculateStreak(days);
const stats = calculateStats(days);
const statsDiv = document.createElement("div");
statsDiv.className = "heatmap-stats";
const parts = [];
parts.push(`<span>\u{1F525} <span class="stat-value">${streak}</span> days</span>`);
parts.push(`<span>Total: <span class="stat-value">${stats.totalHours}h</span></span>`);
parts.push(`<span>Avg: <span class="stat-value">${stats.avgHours}h/day</span></span>`);
if (stats.busiestDay) {
const d = /* @__PURE__ */ new Date(stats.busiestDay.date + "T00:00:00");
const label = DISPLAY_FORMAT2(d);
parts.push(`<span>Busiest: <span class="stat-value">${label} \u2014 ${stats.busiestDay.hours.toFixed(1)}h</span></span>`);
}
statsDiv.innerHTML = parts.join("");
container.appendChild(statsDiv);
}
// assets/src/ui/controls.ts
function createModeControl(activeMode, modes, onChange) {
const nav = document.createElement("nav");
nav.className = "nav nav-segmented nav-sm";
nav.setAttribute("role", "tablist");
for (const m of modes) {
const btn = document.createElement("button");
btn.className = m.key === activeMode ? "nav-link active" : "nav-link";
btn.setAttribute("role", "tab");
btn.setAttribute("aria-selected", m.key === activeMode ? "true" : "false");
btn.textContent = m.label;
btn.addEventListener("click", () => {
nav.querySelectorAll("button").forEach((b) => {
b.classList.remove("active");
b.setAttribute("aria-selected", "false");
});
btn.classList.add("active");
btn.setAttribute("aria-selected", "true");
onChange(m.key);
});
nav.appendChild(btn);
}
return nav;
}
function createMetricControl(activeMetric, onChange) {
const nav = createModeControl(activeMetric, [
{ key: "hours", label: "Hours" },
{ key: "count", label: "Count" }
], onChange);
return nav;
}
// assets/src/heatmap.ts
registerRenderer(new YearModeRenderer());
registerRenderer(new WeekModeRenderer());
function init(container) {
const baseUrl = container.getAttribute("data-url");
if (!baseUrl) {
console.error("KimaiHeatmap: missing data-url attribute");
return;
}
const timesheetUrl = container.getAttribute("data-timesheet-url") || "/en/timesheet/";
const weekStart = container.getAttribute("data-week-start") || "monday";
const projectsJson = container.getAttribute("data-projects");
const projects = projectsJson ? JSON.parse(projectsJson) : [];
const state = createInitialState(weekStart);
const onCellClick = (dateStr) => {
const daterange = `${dateStr} - ${dateStr}`;
let url = `${timesheetUrl}?daterange=${encodeURIComponent(daterange)}`;
if (state.filters.projectId) {
url += `&projects[]=${state.filters.projectId}`;
}
window.location.href = url;
};
container.innerHTML = "";
const wrapper = document.createElement("div");
wrapper.className = "heatmap-wrapper";
const svgArea = document.createElement("div");
svgArea.className = "heatmap-svg-area";
wrapper.appendChild(svgArea);
const controlsContainer = document.getElementById("heatmap-controls");
if (controlsContainer) {
const modeControl = createModeControl(state.mode, [
{ key: "year", label: "Year" },
{ key: "week", label: "Week" }
], (mode) => {
state.mode = mode;
doRender();
});
const metricControl = createMetricControl(state.metric, (metric) => {
state.metric = metric;
doRender();
});
controlsContainer.appendChild(modeControl);
controlsContainer.appendChild(metricControl);
}
const doRender = () => {
if (!state.data) return;
const renderer = getRenderer(state.mode);
renderer.destroy?.();
renderer.render({
container: svgArea,
data: state.data,
state,
config: { cellSize: 13, cellGap: 2, marginTop: 20, marginLeft: 30, marginBottom: 4 },
onCellClick,
emptyMessage: state.filters.projectId ? "No tracking data for this project" : void 0
});
if (state.mode === "year") {
renderStats(container, state.data.days);
} else {
const existingStats = container.querySelector(".heatmap-stats");
if (existingStats) existingStats.remove();
}
if (state.mode === "year") {
svgArea.scrollLeft = svgArea.scrollWidth;
}
};
if (projects.length > 0) {
const filterDiv = document.createElement("div");
filterDiv.className = "heatmap-filter";
const selectEl = document.createElement("select");
selectEl.className = "form-select form-select-sm";
selectEl.setAttribute("aria-label", "Filter by project");
const defaultOpt = document.createElement("option");
defaultOpt.value = "";
defaultOpt.textContent = "All Projects";
selectEl.appendChild(defaultOpt);
for (const p of projects) {
const opt = document.createElement("option");
opt.value = String(p.id);
opt.textContent = p.name;
selectEl.appendChild(opt);
}
selectEl.addEventListener("change", () => {
const val = selectEl.value;
state.filters.projectId = val ? parseInt(val, 10) : null;
const fetchUrl = val ? `${baseUrl}?project=${val}` : baseUrl;
fetch(fetchUrl).then((res) => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}).then((data) => {
state.data = data;
doRender();
}).catch((err) => {
console.error("KimaiHeatmap: failed to load filtered data", err);
});
});
filterDiv.appendChild(selectEl);
wrapper.appendChild(filterDiv);
}
container.appendChild(wrapper);
let resizeTimer;
window.addEventListener("resize", () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
if (state.data) doRender();
}, 200);
});
fetch(baseUrl).then((res) => {
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}).then((data) => {
state.data = data;
doRender();
}).catch((err) => {
console.error("KimaiHeatmap: failed to load data", err);
svgArea.textContent = "Failed to load heatmap data";
});
}
return __toCommonJS(heatmap_exports);
})();
//# sourceMappingURL=heatmap.js.map