Published
Edited
Dec 21, 2020
1 fork
Insert cell
Insert cell
Insert cell
key = {
var yz = html`${alegreya()}
<div style="text-align:center"><span style="display: inline-block">${reference}</span></div>`
return yz
}

Insert cell
reference = table(ranges, {
paged: 4,
columns: {
ColourX: {
formatter(val, i) {
// A formatter that changes its behavior based on the row index,
// so we don’t repeat the $ for every row.
var x = html`<svg width="20" height="20" style="padding-top:.4em; padding-bottom:0em; padding-left:.2em; padding-right:.2em;">
<rect width="12.5" height="12.5" style="fill:${val};stroke-width:2;stroke:rgb(0,0,0)" />
</svg>`
return x
// return i === 0 ? d3.format('$.2f')(val) : d3.format('.2f')(val);
}
},
ColourY: {
formatter(val, i) {
// A formatter that changes its behavior based on the row index,
// so we don’t repeat the $ for every row.
var x = html`<svg width="20" height="20" style="padding-top:.4em; padding-bottom:0em; padding-left:.2em; padding-right:.2em;">
<rect width="12.5" height="12.5" style="fill:${val};stroke-width:2;stroke:rgb(0,0,0)" />
</svg>`
return x
// return i === 0 ? d3.format('$.2f')(val) : d3.format('.2f')(val);
}
},
Range: {
formatter(val) {
// Formatters can also return HTML values! Here’s
// one that highlights first names.
// let parts = val.match(/([^,]*)\,(.*)/);
var x = html`<div><text>${val}</text></div>`
return x
// return html`<strong>${parts[1]}</strong>, ${parts[2]}`;
}
}
}
})
Insert cell
ranges = d3.csv(
await FileAttachment("range.csv").url()
)
Insert cell
table = (data, options) => {
options = Object.assign({}, defaultOptions, options);
const { sortable, rank, paged } = options;
let sortKey = undefined;
let sortDirection = true;
let page = 0;
if (sortable && rank) {
throw new Error("A table can either be ranked or sortable, but not both");
}
let columns = Object.keys(data[0]).map(key => {
const opts = options.columns[key] || {};
return {
key: key,
type: opts.type || typeof data[0][key],
options: opts
};
});

function bake() {
if (sortKey) {
data = data.slice().sort((a, b) => {
let as = a[sortKey];
let bs = b[sortKey];
// make this sort stable
if (as == bs) return JSON.stringify(a).localeCompare(JSON.stringify(b));
let res = as > bs ? 1 : as < bs ? -1 : 0;
if (sortDirection) res = -res;
return res;
});
}
let rows = data.slice(page * paged, page * paged + paged);
let pages = Math.ceil(data.length / paged);
return html`<div><div>
<style>
.pretty-pager {
text-align: center;
}
.pretty-pager button {
padding-left: .5rem;
padding-right: .5rem;
cursor: pointer;
background: #efefef;
border: 2px solid #efefef;
font-family: Alegreya;
font-size: 12px;
font-weight: 400;
font-style: italic;

visibility:hidden;
}
.pretty-pager button:hover {
background: #ffffff;
border: 2px solid #efefef;
}
.pretty-table.normal {
font-family: Alegreya;
font-size: 13px;
text-align: center;
font-weight: 500;
font-style: italic;
}
.pretty-table.normal th,
.pretty-table.normal td {
padding: 2px 2px;
}
.pretty-table th,
.pretty-table td {
vertical-align: top;
font-family: Alegreya;
font-size: 13px;
text-align: center;
font-weight: 500;
font-style: italic;
}
.pretty-table thead th {
font-family: Alegreya;
font-size: 13px;
font-weight: 500;
font-style: normal;

visibility:hidden;
}
.pretty-table thead th.column-type-number string {
order: 1;
}
.pretty-table th.sortable {
cursor: pointer;
}
.pretty-table thead th.column-type-number,
.pretty-table tbody td.cell-type-number,
.pretty-table tbody td.cell-rank {
text-align:right;
}
.pretty-table tbody td.cell-type-number,
.pretty-table tbody td.cell-rank {
font-family: Alegreya;
font-size: 14px;
}
.pretty-table tbody td.cell-rank {
padding-right: 1em;
color: #666;
}

</style>
<table class='pretty-table ${options.style}'>
${
options.header === false
? ``
: html`<thead>
${rank ? html`<th></th>` : ""}
${columns.map(c => {
return th(c, sortKey, sortDirection, sortable);
})}
</thead>`
}
<tbody>
${rows.map(
(row, i) => html`<tr>
${rank ? html`<td class='cell-rank'>${i + 1}</td>` : ""}
${columns.map(c => {
let displayValue = (c.options.formatter || identity)(
row[c.key],
i,
row
);
if (
displayValue instanceof window.HTMLElement &&
displayValue.tagName == "TD"
) {
return displayValue;
}
return html`<td class='cell-type-${
c.type
}'>${displayValue}</td>`;
})}
</tr>`
)}
</tbody>
</table>
${
pages
? html`<div class='pretty-pager'>
${Array.from({ length: pages }).map(
(_, i) => html`<button data-page="${i}">${i+1}</button>`
)}
</div>`
: ""
}
</div></div>`;
}

let dom = bake();

function rerender() {
dom.firstChild.remove();
dom.appendChild(bake().firstChild);
}

// dom.addEventListener("click", e => {
// if (e.target.tagName === "TH" && sortable) {
// if (sortKey == e.target.dataset.key) {
// sortDirection = !sortDirection;
// }
// sortKey = e.target.dataset.key;
// rerender();
// }
// if (e.target.tagName === "BUTTON") {
// if (e.target.dataset.action) {
// switch (e.target.dataset.action) {
// case "next":
// page++, rerender();
// break;
// case "previous":
// page--, rerender();
// break;
// }
// } else if (e.target.dataset.page) {
// (page = parseInt(e.target.dataset.page)), rerender();
// }
// }
// });

return dom;
}
Insert cell
th = (c, sortKey, sortDirection, sortable) => {
let {
options: { title }
} = c;
let sortIndicator = sortKey && sortDirection ? "↑" : "↓";
let arrow = html`<span style='${
sortKey === c.key ? "" : "visibility:hidden"
}'>${sortIndicator}</span>`;
let displayedTitle = title !== undefined ? title : c.key;
return c.type === "number"
? html`<th style="
padding-bottom: .5em;"
data-key="${c.key}"
class='column-type-${c.type} ${sortable ? "sortable" : ""}'>
${arrow}${displayedTitle}
</th>`
: html`<th style="
padding-bottom: .5em;"
data-key="${c.key}"
class='column-type-${c.type} ${sortable ? "sortable" : ""}'>
${displayedTitle}${arrow}
</th>`;
}
Insert cell
defaultOptions = ({ columns: {}, style: 'normal', paged: 25 })
Insert cell
identity = i => i
Insert cell
import {legend} from "@d3/color-legend"
Insert cell
svg = FileAttachment("board-1.svg").text()
Insert cell
d3 = require("d3@5")
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