Public
Edited
Jan 10, 2024
Importers
1 star
Insert cell
Insert cell
Insert cell
generateCheckboxOptionsWithBold = (
showMacroAssets = false,
showCMIAssets = false,
checkboxOptions,
boldOptionsStringArray = CMI_ASSETS_SYMBOLS,
showSymbolInParentheses = true
) => {
const checkboxOptionsArray = checkboxOptions
? checkboxOptions
: getCheckboxOptions(showMacroAssets, showCMIAssets);

const checkIfBoldTextOption = (value, label) => {
if (boldOptionsStringArray.includes(value)) {
return `<b>${label}</b>`;
}

if (DACS_SECTORS.map((ds) => ds.value).includes(value)) {
return `<i>${label}</i>`;
}

return label;
};

return checkboxOptionsArray
.map(({ label, value }) => {
const optionLabel = `${label} ${
showSymbolInParentheses ? `(${value})` : ""
}`;
return {
value,
label: checkIfBoldTextOption(value, optionLabel)
};
})
.sort((a, b) => (a.label > b.label ? 1 : -1));
}
Insert cell
Insert cell
getCheckboxOptions = (showMacroAssets, showCMIAssets) => {
const macroAssets = showMacroAssets ? MACRO_OPTIONS : [];
const cmiAssets = showCMIAssets ? CMI_ASSETS : [];
const allOptions = [
...CRYPTO_OPTIONS,
...DIGITAL_ASSETS_OPTIONS,
...macroAssets,
...cmiAssets
];
const uniqueArray = filterRepeatedOptionsByProp(allOptions, "value");

return uniqueArray;
}
Insert cell
CHECKBOX_OPTIONS = {
const allOptions = [
...CRYPTO_OPTIONS,
...MACRO_OPTIONS,
...DIGITAL_ASSETS_OPTIONS,
...CMI_ASSETS,
...DACS_SECTORS
].sort((a, b) => (a.label > b.label ? 1 : -1));

const uniqueArray = filterRepeatedOptionsByProp(allOptions, "value");

return uniqueArray;
}
Insert cell
JSON.stringify(CHECKBOX_OPTIONS, null, 2)
Insert cell
CRYPTO_OPTIONS = [
{ value: "ADA", label: "Cardano" }, //
{ value: "ATOM", label: "Cosmos" },
{ value: "AVAX", label: "Avalanche" }, //
{ value: "BTC", label: "Bitcoin" }, //
{ value: "DOGE", label: "Dogecoin" }, //
{ value: "ETH", label: "Ethereum" }, //
{ value: "GALA", label: "Gala" }, // add this
{ value: "ICP", label: "Internet Computer" }, //
{ value: "LINK", label: "Chainlink" }, //
{ value: "LRC", label: "Loopring" }, // add this
// { value: "LUNA", label: "Terra 2" }, //
// { value: "LUNC", label: "Terra Classic" }, //
{ value: "MANA", label: "Decentraland" }, //
{ value: "MATIC", label: "Polygon" }, //
{ value: "DOT", label: "Polkadot" }, //
{ value: "SHIB", label: "Shiba InU" }, //
{ value: "SOL", label: "Solana" }, //
{ value: "USDC", label: "USD Coin" }, //
{ value: "USDT", label: "Thether" }, //
{ value: "XLM", label: "Stellar" }, //
{ value: "XRP", label: "XRP" }, //
{ value: "LTC", label: "Litecoin" },
{ value: "ALGO", label: "Algorand" },
{ value: "BCH", label: "Bitcoin Cash" },
{ value: "XTZ", label: "Tezos" },
{ value: "EOS", label: "EOS" },
{ value: "BSV", label: "Bitcoin SV" },
{ value: "ETC", label: "Ethereum Classic" },
{ value: "ZRX", label: "Token 0x" },
{ value: "XMR", label: "Monero" },
{ value: "ZEC", label: "Zcash" },
{ value: "DASH", label: "Dash" },
{ value: "BAT", label: "Basic Attention Token" },
{ value: "TRX", label: "Tron" },
{ value: "OXT", label: "Orchid" },
{ value: "OMG", label: "OMG Network" },
{ value: "KNC", label: "Kyber Network" },
{ value: "AAVE", label: "Aave" },
{ value: "FIL", label: "Filecoin" },
{ value: "GRT", label: "The Graph" },
{ value: "NU", label: "NuCypher" },
{ value: "UNI", label: "Uniswap" },
{ value: "YFI", label: "Yearn Finance" },
{ value: "REP", label: "Augar" },
{ value: "CHZ", label: "Chiliz" },
{ value: "DCR", label: "Decred" }
]
Insert cell
MACRO_OPTIONS = [
{
value: "SP500",
label: "S&P 500",
data: "sp500Data",
returns: "sp500Returns"
},
{ value: "GOLD", label: "Gold", data: "goldData", returns: "goldReturns" },
{
value: "NASDAQ",
label: "Nasdaq",
data: "nasdaqData",
returns: "nasdaqReturns"
},
{
value: "NASDAQ100",
label: "Nasdaq100",
data: "nasdaq100Data",
returns: "nasdaq100Returns"
},
{
value: "TLT",
label: "Bonds (iShares 20+ Year Treasury Bond (TLT) ETF)",
data: "tltData",
returns: "tltReturns"
},
// {
// value: "NIKKEI",
// label: "Nikkei 225",
// data: "nikkeiData",
// returns: "nikkeiReturns"
// },
{
value: "FTSE",
label: "FTSE 100",
data: "ftseData",
returns: "ftseReturns"
}
]
Insert cell
DIGITAL_ASSETS_OPTIONS = [
{
value: "CD20",
label: "CoinDesk 20 Index",
data: "cmiData",
returns: "cmiReturns"
}
]
Insert cell
MACRO_PARSER = {
const mp = {};
[...MACRO_OPTIONS, ...DIGITAL_ASSETS_OPTIONS].forEach(
({ label, data, returns }) => (mp[label] = { data, returns })
);
return mp;
}
Insert cell
DACS_SECTORS = [
{ value: "CCY", label: "CoinDesk Currency Index" },
{ value: "SMT", label: "CoinDesk Smart Contract Platform Index" },
{ value: "DCF", label: "CoinDesk DeFi Index" },
{ value: "CNE", label: "CoinDesk Culture & Entertainment Index" },
{ value: "CPU", label: "CoinDesk Computing Index" },
{ value: "DTZ", label: "CoinDesk Digitization Index" },
{
value: "CD20",
label: "CoinDesk 20 Index",
data: "cmixData",
returns: "cmixReturns"
},
{
value: "CSC",
label: "CoinDesk Stablecoin Index",
data: "ccxData",
returns: "ccxReturns"
}
]
Insert cell
import { latestCMIAssetsFull, assetsBySector } from "@coindesk-research/cmi-asset-provider-monthly-updated-list"
Insert cell
CMI_ASSETS = latestCMIAssetsFull
Insert cell
CMIAssetValuesBySector = {
const returns = {};
Object.keys(assetsBySector).map((a) => {
returns[a] = assetsBySector[a].map((abs) => abs.value);
});

return returns;
}
Insert cell
CMI_ASSETS_SYMBOLS = CMI_ASSETS.map((a) => a.value)
Insert cell
/**
* UPDATE THIS ACCORDING TO DATA ON
* https://www.coindesk.com/coindesk20/
* Last updated: July, 2022
*/
COINDESK_20 = [
"ADA",
"ATOM",
"AVAX",
"BTC",
"DOGE",
"ETH",
"GALA",
"LINK",
"LRC",
"LUNA",
"MANA",
"MATIC",
"DOT",
"SHIB",
"SOL",
"XLM",
"XRP"
]
Insert cell
filterRepeatedOptionsByProp = (optionArray, prop = "label") => {
return optionArray.filter((value, index) => {
const _value = JSON.stringify(value[prop]);
return (
index ===
optionArray.findIndex((obj) => {
return JSON.stringify(obj[prop]) === _value;
})
);
});
}
Insert cell
Insert cell
selectedEndDateMinusAYear = (date) => {
const oneYearFromNow = new Date(date);
oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() - 1);
return oneYearFromNow.toISOString().slice(0, -8);
}
Insert cell
getDaysBetweenDates = (startDate, endDate) => {
const date1 = new Date(startDate);
const date2 = new Date(endDate);
const diffTime = Math.abs(date2 - date1);
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
return diffDays;
}
Insert cell
dateToTime = (date) => new Date(date).getTime()
Insert cell
formatDateForChart = (date) => new Date(date).toISOString().split("T")[0]
Insert cell
formatDateToInputFormat = (date) => date.toISOString().slice(0, 10)
Insert cell
removeNumberOfDaysFromCurrentDate = (numberOfDays = 30) =>
formatDateToInputFormat(
new Date(new Date().setDate(new Date().getDate() - numberOfDays))
)
Insert cell
removeNumberOfDaysFromDate = (date, numberOfDays = 30) =>
formatDateToInputFormat(
new Date(new Date().setDate(new Date(date).getDate() - numberOfDays))
)
Insert cell
removeNumberOfDaysFromDateNoFormat = (date, numberOfDays) =>
new Date(new Date().setDate(new Date(date).getDate() - numberOfDays))
Insert cell
removeNumberOfDaysFromDateToTime = (date, numberOfDays = 30) =>
new Date(
new Date().setDate(new Date(date).getDate() - numberOfDays)
).getTime()
Insert cell
removeNumberOfDaysFromDateToUnix = (date, numberOfDays) =>
Math.floor(
new Date(
new Date().setDate(new Date(date).getDate() - (numberOfDays - 1))
).getTime() / 1000
)
Insert cell
unixTimestampToDateObj = (unix) => new Date(unix * 1000)
Insert cell
unixTimestampToDateObj(removeNumberOfDaysFromDateToUnix("2022-09-28", 1))
Insert cell
momentDateInputFormat = (d) => d.format("YYYY-MM-DD")
Insert cell
momentTimeInputFormat = (d) => d.format("HH:mm:ss")
Insert cell
now = moment()
Insert cell
Insert cell
assetReturnCalculator = (startValue, endValue) =>
(endValue - startValue) / startValue
Insert cell
Insert cell
formatPercentageVanilla = (number) =>
Number(number).toLocaleString("en-US", {
maximumFractionDigits: 2,
minimumFractionDigits: 1
})
Insert cell
formatPercentageD3 = d3.format(".1%")
Insert cell
createNewDateObject = date => {
return new Date(date);
}
Insert cell
locale = d3.formatLocale({
decimal: ".",
thousands: ",",
grouping: [3],
currency: ["$", ""],
dateTime: "%a %b %e %X %Y",
date: "%m/%d/%Y",
time: "%H:%M:%S",
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"
]
})
Insert cell
currencyFormat = locale.format("$,.2f")
Insert cell
nodeToString = (node) => {
var tmpNode = document.createElement("div");
tmpNode.appendChild(node.cloneNode(true));
var str = tmpNode.innerHTML;
tmpNode = node = null; // prevent memory leaks in IE
return str;
}
Insert cell
Insert cell
mutable apiLoadingState = false
Insert cell
assetFunctionGenerator = async (assetArray, apiStringGenerator, options) => {
mutable apiLoadingState = true;
const apiAssets = assetArray.map(async (asset) => {
const newMap = new Map();
const assetResult = await d3.json(apiStringGenerator(asset));
const assetData = assetResult[0];
if (options && options.calculatePercentage) {
const { o, c } = assetData;
const percentage = ((c - o) / c) * 100;
return newMap.set(asset.toUpperCase(), { percentage });
}
return newMap.set(asset.toUpperCase(), assetData);
});
const returns = await Promise.all(apiAssets);

if (options && options.callback) {
return options.callback(returns);
}
mutable apiLoadingState = false;
return returns;
}
Insert cell
CDTickerAPI = async (assetString) => {
return (
await d3.json(
replaceCharsForNoCorsServer(
`https://production.api.coindesk.com/v2/tb/price/ticker?assets=${assetString}`
)
)
)["data"];
}
Insert cell
CORS_HEAD = "https://proxy.mangaraiku.eu.org/" //"https://observable-cors.glitch.me/"
Insert cell
CORS_HEAD_TEMP = "https://proxy.mangaraiku.eu.org/?url="
Insert cell
replaceCharsForNoCorsServer = (
url,
replaceAnd = true,
replaceQuestion = true
) => {
let returnUrl = url;

if (replaceAnd) {
returnUrl = returnUrl.replaceAll("&", "%26");
}

if (replaceQuestion) {
returnUrl = returnUrl.replaceAll("?", "%3F");
}

// if (replaceQuestion) {
returnUrl = returnUrl.replaceAll("^", "%5E");
// }

return `${CORS_HEAD_TEMP}${returnUrl}`;
}
Insert cell
Insert cell
SP500API = async () => {
return (
await d3.csv(
replaceCharsForNoCorsServer(
`https://query1.finance.yahoo.com/v7/finance/download/^GSPC?period1=1627987200&period2=${new Date().getTime()}&interval=1d&events=history`
)
)
).map(({ Date, Close }) => ({
date: createNewDateObject(Date),
price: parseFloat(Close)
}));
}
Insert cell
GOLDAPI = async () => {
return (
await d3.csv(
replaceCharsForNoCorsServer(
`https://query1.finance.yahoo.com/v7/finance/download/GC=F?period1=1627987200&period2=${new Date().getTime()}&interval=1d&events=history`
)
)
).map(({ Date, Close }) => ({
date: createNewDateObject(Date),
price: parseFloat(Close)
}));
}
Insert cell
TREASURYAPI = async () => {
return (
await d3.csv(
replaceCharsForNoCorsServer(
`https://query1.finance.yahoo.com/v7/finance/download/^TNX?period1=1627987200&period2=${new Date().getTime()}&interval=1d&events=history`
)
)
)
.map(({ Date, Close }) => ({
date: createNewDateObject(Date),
price: parseFloat(Close)
}))
.filter((p) => isNaN(p.price) === false);
}
Insert cell
FTSEAPI = async () =>
(
await d3.csv(
replaceCharsForNoCorsServer(
`https://query1.finance.yahoo.com/v7/finance/download/^FTSE?period1=1230768000&period2=${new Date().getTime()}&interval=1d&events=history`
)
)
).map(({ Date, Close }) => ({
date: createNewDateObject(Date),
price: Close
}))
Insert cell
NASDAQAPI = async () =>
(
await d3.csv(
replaceCharsForNoCorsServer(
"https://fred.stlouisfed.org/graph/fredgraph.csv?id=NASDAQCOM"
)
)
).map(({ DATE, NASDAQ100 }) => ({
date: createNewDateObject(DATE),
price: NASDAQ100
}))
Insert cell
NASDAQ100API = async () =>
(
await d3.csv(
replaceCharsForNoCorsServer(
"https://fred.stlouisfed.org/graph/fredgraph.csv?id=NASDAQ100"
)
)
).map(({ DATE, NASDAQ100 }) => ({
date: createNewDateObject(DATE),
price: NASDAQ100
}))
Insert cell
NIKKEIAPI = async () =>
(
await d3.csv(
replaceCharsForNoCorsServer(
"https://fred.stlouisfed.org/graph/fredgraph.csv?id=NIKKEI225"
)
)
).map(({ DATE, NIKKEI225 }) => ({
date: createNewDateObject(DATE),
price: NIKKEI225
}))
Insert cell
getYahooFinanceAPIRequest = async (ticker, apiVersion = 7) => {
const apiConfig7 = {
d3Func: d3.csv,
url: replaceCharsForNoCorsServer(
`https://query1.finance.yahoo.com/v7/finance/download/${ticker}?period1=1127987200&period2=${new Date().getTime()}&interval=1d&events=history`
),
mapper: (data) => {
return {
date: createNewDateObject(data.Date),
price: data.Close
};
}
};

const encodedTicker = encodeURI(ticker);

const url = `https://query1.finance.yahoo.com/v8/finance/chart/${decodeURI(
ticker
)}?symbol=${encodedTicker}&period1=1127987200&period2=${new Date().getTime()}&useYfid=true&interval=1d&includePrePost=true&format=true`;
const apiConfig8 = {
d3Func: d3.json,
url: replaceCharsForNoCorsServer(url),
mapper: (data) => {
return data;
}
};

const apiConfig = apiVersion === 7 ? apiConfig7 : apiConfig8;

if (apiVersion === 7) {
return (await apiConfig.d3Func(apiConfig.url)).map(apiConfig.mapper);
}

const tickerData = (await apiConfig.d3Func(apiConfig.url))?.chart?.result[0];

const { timestamp, indicators } = tickerData;
const { quote } = indicators;
const { volume, open, close, low, high } = quote[0];

const parsedData = timestamp.map((value, index) => {
return {
date: new Date(value * 1000),
price: close[index],
volume: volume[index],
open: open[index],
close: close[index],
low: low[index],
high: high[index]
};
});

return { tickerData, parsedData };
}
Insert cell
Insert cell
logger = (
isDebugging,
logParams,
override = false,
loggerTextPrepend = "DEGUB LOGGER"
) => {
if (isDebugging === true) {
console.log(`🐞 [${loggerTextPrepend}]`, logParams);
}

if (override === true) {
console.info(`🐞 [${loggerTextPrepend}]`, logParams);
}
}
Insert cell
Insert cell
Insert cell
async function toDataURL(url) {
return new Promise(async (resolve, reject) => {
const res = await fetch(url);
if (!res.ok) return reject(`Error: ${res.status} ${res.statusText}`);
const blob = await res.blob();
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = () => resolve(reader.result);
});
}
Insert cell
loadingStateFunction = (whatToShowWhenFinished = md`----`, spinnerHelperText) =>
apiLoadingState ? html`${spinnerDIV()}` : whatToShowWhenFinished
Insert cell
spinnerDIV = (
loadingText = "Loading assets"
) => html`<div class="loading-spinner">
<div class="spinner-text">${loadingText}</div>
<div class="spinner"></div>
</div>`
Insert cell
pageCSS = html`<style>
@font-face {
font-family: "Roslindale Display Bold";
src: url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/roslindale/display-bold.woff2?d=197"
)}) format("woff2"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/roslindale/display-bold.woff?d=197"
)}) format("woff"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/roslindale/display-bold.ttf?d=197"
)}) format("truetype");
font-style: normal;
font-display: swap;
}

@font-face {
font-family: "Display Narrow Bold Roslindale";
src: url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/roslindale/display-narrow-bold.woff2?d=197"
)}) format("woff2"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/roslindale/display-narrow-bold.woff?d=197"
)}) format("woff"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/roslindale/display-narrow-bold.ttf?d=197"
)}) format("truetype");
font-style: normal;
font-display: swap;
}

@font-face {
font-family: "Neue Haas Grotesk Text Pro";
src: url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-55-rg.woff2?d=197"
)}) format("woff2"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-55-rg.woff?d=197"
)}) format("woff"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-55-rg.ttf?d=197"
)}) format("truetype");
font-style: normal;
font-display: swap;
}

@font-face {
font-family: "Neue Haas Grotesk Text Pro";
src: url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-56-it.woff2?d=197"
)}) format("woff2"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-56-it.woff?d=197"
)}) format("woff"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-56-it.ttf?d=197"
)}) format("truetype");
font-style: italic;
font-display: swap;
}

@font-face {
font-family: "Neue Haas Grotesk Display Pro";
src: url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-65-md.woff2?d=197"
)}) format("woff2"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-65-md.ttf?d=197"
)}) format("truetype");
font-style: normal;
font-display: swap;
}

@font-face {
font-family: "Neue Haas Grotesk Display Pro";
src: url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-66-mdit.woff2?d=197"
)}) format("woff2"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-66-mdit.woff?d=197"
)}) format("woff"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-66-mdit.ttf?d=197"
)}) format("truetype");
font-style: italic;
font-display: swap;
}

@font-face {
font-family: "Neue Haas Grotesk Text Pro";
src: url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-75-bd.woff2?d=197"
)}) format("woff2"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-75-bd.woff?d=197"
)}) format("woff"),
url(${await toDataURL(
"https://www.coindesk.com/pf/resources/fonts/neue-haas/grotesk-text-pro-75-bd.ttf?d=197"
)}) format("truetype");
font-style: normal;
font-weight: 700;
font-display: swap;
}


body {
font-family: "Neue Haas Grotesk Text Pro", sans-serif;
}
h1, h2, h3, h4, h5, h6 {
font-family: "Display Narrow Bold Roslindale", serif;
font-weight: 700;
letter-spacing: 0.03em;
color: rgb(38, 38, 38);
}

h3 {
font-size: 36px;
}
</style>`
Insert cell
formElementsCSS = html`<style>
button {
border: 1px solid lightgray;
border-radius: 3px;
margin: 0 10px;
width: 200px !important;
background-color: #fff;
padding: 10px;
color: #333 !important;
min-width: 200px !important;
background-color: #fff;
padding: 10px;
color: #333 !important;
max-width: 100% !important;
font-weight: 700 !important;
font-size: 14px !important;
}

button:hover {
border: 1px solid black;
cursor: pointer;
background-color: #262626;
color: #f5bf1e !important;
}

form.oi-ec050e>label {
width: 250px !important;
}

.oi-ec050e-input {
width: 150px;
}

.oi-ec050e button {
font-weight: 600;
color: #333;
}


/* CUSTOM INPUT ELEMENTS */
.cd-checkbox-form-wrapper {
display: grid;
grid-template-columns: repeat(4, 1fr);
}

#cd-input-title {
grid-column: span 4;
}

#cd-input-description {
grid-column: span 4;
}
</style>`
Insert cell
spinnerSTYLE = html`<style>
.loading-spinner {
display:flex;
}

.spinner-text {
flex: 1;
text-align: right;
padding-top: 17px;
padding-right: 50px;
font-size: 20px
}
@keyframes spinner {
to {transform: rotate(360deg);}
}
.spinner {
flex: 1;
}
.spinner:before {
content: '';
box-sizing: border-box;
position: absolute;
top: 50%;
left: 50%;
width: 40px;
height: 40px;
margin-top: -10px;
margin-left: -10px;
border-radius: 50%;
border: 2px solid #ccc;
border-top-color: #000;
animation: spinner .6s linear infinite;
}
</style>`
Insert cell
/* GET TABLE STYLING FROM https://observablehq.com/@coindesk-research/cd-cmi-market-wrap-first-movers AND MAKE GENERIC */
Insert cell
Insert cell
importjs = function (src, targetvar) {
/*if (!$("head").find(`script[src="${src}"]`)) {
$("head").append(`<script src="${src}"></script>`);
}*/
return new Promise(function (resolve, reject) {
function waitForFoo() {
if (typeof targetvar == "undefined") resolve();
if (eval(targetvar)) resolve(eval(targetvar));
setTimeout(waitForFoo, 30);
}

require(src)
.then(function () {
waitForFoo();
})
.catch(function () {
waitForFoo();
});
});
}
Insert cell
importcss = function (src) {
$("head").append(`<link rel="stylesheet" href="${src}">`);
}
Insert cell
$ = require("https://code.jquery.com/jquery-3.3.1.js")
// $ = require( 'jquery' );
Insert cell
// Copies a string to the users clipboard
import { Copier, pbcopy } from "@mbostock/copier"
Insert cell
d3format = require("d3-format@1")
Insert cell
// checks if anything is empty or nil
isEmptyOrNil = R.anyPass([R.isNil, R.isEmpty])
Insert cell
R = require("ramda")
Insert cell
Insert cell
function cdCheckbox(config = {}) {
let {
value: formValue,
title,
description,
submit,
disabled,
options,
formId = "cd-checkbox-form",
labelCSSClass = "cd-label-for-checkbox",
wrapperCSSClass = "cd-checkbox-form-wrapper"
} = Array.isArray(config) ? { options: config } : config;
options = options.map((o) =>
typeof o === "string" ? { value: o, label: o } : o
);
const form = input({
type: "checkbox",
title,
description,
submit,
getValue: (input) => {
if (input.length)
return Array.prototype.filter
.call(input, (i) => i.checked)
.map((i) => i.value);
return input.checked ? input.value : false;
},
wrapperCSSClass,
form: html`
<form id="${formId}">
${options.map(({ value, label }, i) => {
const input = html`<input type=checkbox name=input ${
(formValue || []).indexOf(value) > -1 ? "checked" : ""
} style="vertical-align: top; ${
i === 0 ? `margin-left: 1px;` : ``
}" />`;
input.setAttribute("value", value);
if (disabled) input.setAttribute("disabled", disabled);
const tag = html`<label style="display: inline-block; margin: 5px 10px 3px 0; font-size: 0.85em;" class="${labelCSSClass}">
${input}
${label}
</label>`;
return tag;
})}
</form>
`
});
form.output.remove();
return form;
}
Insert cell
function input(config) {
let {
form,
type = "text",
attributes = {},
action,
getValue,
title,
description,
format,
display,
submit,
options,
wrapperCSSClass
} = config;
const wrapper = html`<div class="${wrapperCSSClass}"></div>`;
if (!form)
form = html`<form>
<input name=input type=${type} />
</form>`;
Object.keys(attributes).forEach((key) => {
const val = attributes[key];
if (val != null) form.input.setAttribute(key, val);
});
if (submit)
form.append(
html`<input name=submit type=submit style="margin: 0 0.75em" value="${
typeof submit == "string" ? submit : "Submit"
}" />`
);
form.append(
html`<output name=output style="font: 14px Menlo, Consolas, monospace; margin-left: 0.5em;"></output>`
);
if (title)
form.prepend(
html`<div id="cd-input-title" style="font: 700 0.9rem sans-serif; margin-bottom: 3px;">${title}</div>`
);
if (description)
form.append(
html`<div id="cd-input-description" style="font-size: 0.85rem; font-style: italic; margin-top: 3px;">${description}</div>`
);
if (format)
format = typeof format === "function" ? format : d3format.format(format);
if (action) {
action(form);
} else {
const verb = submit
? "onsubmit"
: type == "button"
? "onclick"
: type == "checkbox" || type == "radio"
? "onchange"
: "oninput";
form[verb] = (e) => {
e && e.preventDefault();
const value = getValue ? getValue(form.input) : form.input.value;
if (form.output) {
const out = display ? display(value) : format ? format(value) : value;
if (out instanceof window.Element) {
while (form.output.hasChildNodes()) {
form.output.removeChild(form.output.lastChild);
}
form.output.append(out);
} else {
form.output.value = out;
}
}
form.value = value;
if (verb !== "oninput")
form.dispatchEvent(new CustomEvent("input", { bubbles: true }));
};
if (verb !== "oninput")
wrapper.oninput = (e) => e && e.stopPropagation() && e.preventDefault();
if (verb !== "onsubmit") form.onsubmit = (e) => e && e.preventDefault();
form[verb]();
}
while (form.childNodes.length) {
wrapper.appendChild(form.childNodes[0]);
}
form.append(wrapper);
return form;
}
Insert cell
import { checkbox, time } from "@jashkenas/inputs"
Insert cell
moment = require("moment")
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