Published
Edited
Jul 6, 2022
Importers
28 stars
Insert cell
Insert cell
Insert cell
Insert cell
createEventList(document, {invalidation, onClick: e => mutable event = e})
Insert cell
Insert cell
Insert cell
Insert cell
{
const defaults = {
invalidation,
bubbling: includeBubbling,
useCapture: true,
duration: 5000,
};
const input = html`<input placeholder="Type something ...">`;
const label = html`<label>Label ${input}</label>`;
const filterMouse = n => n.match(/mouse|pointer|click|contextmenu|wheel/);
const filterKey = n => n.match(/^key/);

const mouseList = createEventList(label, { ...defaults, filter: filterMouse });
const keyList = createEventList(label, { ...defaults, filter: filterKey });
const otherList = createEventList(label, { ...defaults, filter: n => !filterMouse(n) && !filterKey(n) });

// Sets a custom animation timing function, ticking down every quarter second.
//for(let l of [mouseList, keyList, otherList]) l.style.setProperty('--bar-timing-func', `steps(12, start)`);
return html`<div class=ex>
${label}<br>
<dl>
<dt>Mouse events</dt><dd>${mouseList}</dd>
<dt>Key events</dt><dd>${keyList}</dd>
<dt>Other events</dt><dd>${otherList}</dd>
`;
}
Insert cell
Insert cell
function createEventList(target, options = {}) {
const {
invalidation: invalidated = invalidation,
// Capture bubbled events.
bubbling = true,
useCapture = false,
eventList = null,
onClick = logToConsole,
group = e => e.constructor.name,
filter = (type) => true,
hash = true,
sortRecent = false,
layout = 'row',
fontSize = '.7em',
duration = 4000,
className = `event-list-${Date.now().toString(36)}-${(Math.random()*1e10|0).toString(36)}`,
} = options;

const groups = new Map();
const events = eventList || getEventTypes(target, filter);
const hashKey = typeof hash === 'function' ? hash : e => e.constructor.name;
const types = new Map();
const handleClick = function() {
if(!this.lastEvent) return;
onClick.call(this, this.lastEvent, this.lastTimeStamp);
}

const list = html`<div ${{
class: className,
style: {
'--layout': layout,
'--font-size': fontSize,
'--bar-duration': `${duration / 1000}s`
},
}}>${getStyle(className)}`;
for(const type of events) {
target.addEventListener(type, handleEvent, useCapture || undefined);
invalidated.then(() => {
target.removeEventListener(type, handleEvent, useCapture || undefined);
});
}
return list;

function handleEvent(e) {
if(!bubbling && e?.target !== target) return;
const el = types.get(e.type) || addEvent(e, list);
if(hash) {
const key = hashKey(e);
if(el.hashKey !== key) {
el.hashKey = key;
el.style.setProperty('--bar-color', colorHash(key, 0, 360));
}
}
el.lastEvent = e;
el.lastTimeStamp = Date.now();
el.dataset.count++;
// Avoid reflow when using variable-width fonts.
el.style.setProperty('--digits', el.dataset.count.toString().length);
if(sortRecent) list.insertBefore(el, list.firstElementChild);
else list.insertBefore(el, el.nextElementSibling)
}
function addEvent(e, list) {
const type = e.type;
const element = html`<span>${type}`;
types.set(type, element);
element.dataset.type = type;
element.dataset.parentType = e.constructor.name;
element.dataset.count = 0;
element.onclick = handleClick;

return insertSorted(element, list, node => node.dataset.type > type);
}

function insertSorted(element, parent, findBefore) {
return parent.insertBefore(
element,
Array.prototype.find.call(parent.children, findBefore)
);
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more