function categoryOrderInput(domain, options = {}) {
let {
sampleWidth = 30,
sampleHeight = 18,
width = 220,
font = "9pt sans-serif",
lineHeight = 20,
checkboxes = true,
selectedDomain = domain,
colorScale
} = options;
if (!colorScale) colorScale = Plot.scale({ color: { domain } });
const div = htl.html`<div class="categoryInput">`;
let selected = null;
function dragOver(e) {
if (e.preventDefault) {
e.preventDefault();
}
if (e.target == selected) return;
if (isBefore(selected, e.target)) {
e.target.parentNode.insertBefore(selected, e.target);
} else {
e.target.parentNode.insertBefore(selected, e.target.nextSibling);
}
e.dataTransfer.dropEffect = "move";
}
function onchanged() {
div.value = div.getValue();
div.dispatchEvent(new CustomEvent("input"));
}
function dragEnd(e) {
if (e.preventDefault) {
e.preventDefault();
}
onchanged();
selected = null;
}
function dragStart(e) {
if (selected) return;
e.dataTransfer.dropEffect = "move";
e.dataTransfer.effectAllowed = "move";
e.dataTransfer.setData("text/plain", null);
selected = e.target;
}
function isBefore(el1, el2) {
let cur;
if (el2.parentNode === el1.parentNode) {
for (cur = el1.previousSibling; cur; cur = cur.previousSibling) {
if (cur === el2) return true;
}
}
return false;
}
Object.assign(div.style, {
lineHeight: `${lineHeight}px`,
width: `${width}px`
});
for (let cat of [...domain].reverse()) {
const row = htl.html`<div class="category" draggable="true">`;
const sample = htl.html`<div>`;
Object.assign(sample.style, {
background: colorScale.apply(cat),
height: `${sampleHeight}px`,
width: `${sampleWidth}px`,
minWidth: `${sampleWidth}px`,
verticalAlign: "middle",
display: "inline-block"
});
row.append(sample);
const checkbox = htl.html`<input type="checkbox">`;
checkbox.checked = selectedDomain.indexOf(cat) >= 0;
checkbox.onchange = onchanged;
row.append(checkbox);
const text = htl.html`<span>${cat}`;
Object.assign(text.style, {
font,
paddingLeft: "3px",
verticalAlign: "middle"
});
row.append(text);
row.value = cat;
div.append(row);
row.ondragend = dragEnd;
row.ondragstart = dragStart;
row.ondragover = dragOver;
}
div.getValue = () => {
const value = [];
for (let el of div.children) {
if (el.querySelector("input").checked) value.push(el.value);
}
return value.reverse();
};
div.value = div.getValue();
return div;
}