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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more