Last active
January 25, 2022 12:11
-
-
Save nexpr/bf735bde467427b9c80210ed6b83e667 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8" /> | |
<style> | |
body { | |
margin: 0; | |
} | |
.control { | |
display: inline-block; | |
padding: 10px; | |
position: sticky; | |
top: 0; | |
background: white; | |
border-bottom: 1px solid #aaa; | |
} | |
.result { | |
margin: 0 10px; | |
} | |
.date-range { | |
display: flex; | |
align-items: center; | |
gap: 10px; | |
} | |
.flex-center { | |
display: flex; | |
justify-content: center; | |
margin: 5px; | |
gap: 10px; | |
} | |
</style> | |
<script type="module"> | |
import { html, render } from "https://unpkg.com/lit-html@2.1.1/lit-html.js" | |
const formatDate = date => date.toLocaleString("ja-JP", { year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit" }) | |
const addDate = (base, diff) => new Date(base.getFullYear() + (diff.year || 0), base.getMonth() + (diff.month || 0), base.getDate() + (diff.date || 0), base.getHours() + (diff.hour || 0), base.getMinutes() + (diff.minute || 0), base.getSeconds() + (diff.second || 0)) | |
const values = { | |
data: [], | |
rows: [], | |
from: new Date("2022-01-01 00:00:00"), | |
to: new Date("2022-02-01 00:00:00"), | |
} | |
values.data = Array.from(Array(1000), (x, i) => { | |
const from = +new Date("2021-01-01 00:00:00") | |
const to = +new Date("2023-01-01 00:00:00") | |
const offset = ~~(Math.random() * (to - from) / 1000) * 1000 | |
return new Date(from + offset) | |
}) | |
.sort((a, b) => a - b) | |
.map((date, i) => ({ date, text: String(i).padStart(4, "0") })) | |
const updateFilter = () => { | |
const from = values.from ? +values.from : 0 | |
const to = values.to ? values.to : Infinity | |
values.rows = values.data.filter(row => from <= row.date && row.date < to) | |
update() | |
} | |
const changeRange = (type, move) => () => { | |
if (move) { | |
switch (type) { | |
case "day": | |
if (values.from) { | |
values.from = addDate(values.from, { date: move }) | |
} | |
if (values.to) { | |
values.to = addDate(values.to, { date: move }) | |
} | |
break | |
case "week": | |
if (values.from) { | |
values.from = addDate(values.from, { date: move * 7 }) | |
} | |
if (values.to) { | |
values.to = addDate(values.to, { date: move * 7 }) | |
} | |
break | |
case "month": | |
if (values.from) { | |
values.from = addDate(values.from, { month: move }) | |
} | |
if (values.to) { | |
values.to = addDate(values.to, { month: move }) | |
} | |
break | |
case "year": | |
if (values.from) { | |
values.from = addDate(values.from, { year: move }) | |
} | |
if (values.to) { | |
values.to = addDate(values.to, { year: move }) | |
} | |
break | |
} | |
} else { | |
switch (type) { | |
case "day": | |
if (values.from) { | |
values.to = addDate(values.from, { date: 1 }) | |
} else if (values.to) { | |
values.from = addDate(values.to, { date: -1 }) | |
} | |
break | |
case "week": | |
if (values.from) { | |
values.to = addDate(values.from, { date: 7 }) | |
} else if (values.to) { | |
values.from = addDate(values.to, { date: -7 }) | |
} | |
break | |
case "month": | |
if (values.from) { | |
values.to = addDate(values.from, { month: 1 }) | |
} else if (values.to) { | |
values.from = addDate(values.to, { month: -1 }) | |
} | |
break | |
case "year": | |
if (values.from) { | |
values.to = addDate(values.from, { year: 1 }) | |
} else if (values.to) { | |
values.from = addDate(values.to, { year: -1 }) | |
} | |
break | |
} | |
} | |
updateFilter() | |
} | |
const inputTemplate = (date, onchange) => { | |
const date_utc = date ? addDate(date, { minute: -date.getTimezoneOffset() }) : null | |
const handler = (eve) => { | |
const date_utc = eve.target.valueAsDate | |
onchange(date_utc ? addDate(date_utc, { minute: date_utc.getTimezoneOffset() }) : null) | |
} | |
return html`<input type="date" .valueAsDate=${date_utc} @change=${handler}>` | |
} | |
const rangeTemplate = (label, onclick) => html` | |
<div class="flex-center"> | |
<button @click=${onclick(-1)}>◀</button> | |
<button @click=${onclick()}>${label}</button> | |
<button @click=${onclick(1)}>▶</button> | |
</div> | |
` | |
const template = () => html` | |
<div class="container flex-row"> | |
<div class="control"> | |
<div class="date-range"> | |
${inputTemplate(values.from, date => { values.from = date; updateFilter() })} | |
~ | |
${inputTemplate(values.to, date => { values.to = date; updateFilter() })} | |
</div> | |
${rangeTemplate("日", x => changeRange("day", x))} | |
${rangeTemplate("週", x => changeRange("week", x))} | |
${rangeTemplate("月", x => changeRange("month", x))} | |
${rangeTemplate("年", x => changeRange("year", x))} | |
</div> | |
<div class="result"> | |
${values.rows.map(row => html`<div>${formatDate(row.date)} | ${row.text}</div>`)} | |
</div> | |
</div> | |
` | |
const root_element = document.getElementById("root") | |
const update = () => render(template(), root_element) | |
updateFilter() | |
</script> | |
<div id="root"></div> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment