Created
December 23, 2019 17:32
-
-
Save iliakan/064ef83dcedbc97cb4b203a8b23f7d53 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> | |
<body> | |
<link rel="stylesheet" href="../../styles/common.css"> | |
<link rel="stylesheet" href="style.css"> | |
<script type="module"> | |
import salesData from './salesData.js'; | |
import ColumnChart from './index.js'; | |
let chart = new ColumnChart({ | |
url: '/api/dashboard/orders', | |
height: 200, | |
range: { | |
from: new Date(Date.now() - 60*86400e3), | |
to: new Date() | |
}, | |
name: 'orders', | |
title: "Orders", | |
link: '/orders', | |
formatHeading: data => Object.values(data).reduce((a, b) => a + b, 0), | |
formatTooltip: (date, value) => `${date}: ${value}` | |
}); | |
document.body.appendChild(chart.elem); | |
</script> | |
</body> |
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
import fetchJson from "../../lib/fetchJson.js"; | |
import createElement from "../../lib/createElement.js"; | |
export default class ColumnChart { | |
/** | |
* @param data object {key: value} | |
* @param height fixed height of the widget | |
* @param name unique name, appended to the class | |
* @param title | |
* @param link | |
* @param formatHeading function to format the header | |
* @param formatTooltip function to format the tooltip | |
*/ | |
constructor({ url, range, height, name, title, link, formatHeading, formatTooltip }) { | |
this.url = new URL(url, location.href); | |
this.range = range; | |
this.height = height; | |
this.name = name; | |
this.title = title; | |
this.link = link; | |
this.formatHeading = formatHeading; | |
this.formatTooltip = formatTooltip; | |
this.render(); | |
} | |
async render() { | |
this.elem = createElement(`<div class="column-chart dashboard__chart_${this.name}"> | |
<div class="column-chart__title"> | |
${this.title} | |
${ | |
this.link ? `<a href="${this.link}" class="column-chart__link">View all</a>` : `` | |
} | |
</div> | |
<div class="column-chart__container"> | |
<div class="column-chart__header"></div> | |
<div class="column-chart__chart"></div> | |
</div> | |
</div>`); | |
this.chartContainer = this.elem.querySelector('.column-chart__container'); | |
this.chartElem = this.elem.querySelector('.column-chart__chart'); | |
this.chartElem.addEventListener('mouseover', e => this.onChartMouseOver(e)); | |
this.chartElem.addEventListener('mouseout', e => this.onChartMouseOut(e)); | |
await this.update(); | |
} | |
onChartMouseOver(event) { | |
if (event.target.parentNode !== this.chartElem) { | |
return; // click not on a column | |
} | |
let column = event.target; | |
// not using :hover, as it's not supported on mobiles | |
this.chartElem.classList.add('has-hovered'); | |
column.classList.add('is-hovered'); | |
} | |
onChartMouseOut(event) { | |
if (this.chartElem.classList.contains('has-hovered')) { | |
this.chartElem.classList.remove('has-hovered'); | |
this.chartElem.querySelector('.is-hovered').classList.remove('is-hovered'); | |
} | |
} | |
setRange(range) { | |
this.range = range; | |
this.update(); | |
} | |
async update() { | |
// clear previous data if any | |
this.chartElem.innerHTML = ""; | |
this.elem.classList.add(`column-chart_loading`); | |
this.url.searchParams.set('from', this.range.from.toISOString()); | |
this.url.searchParams.set('to', this.range.to.toISOString()); | |
let chartData = await fetchJson(this.url); | |
this.elem.classList.remove(`column-chart_loading`); | |
let maxValue = Math.max(...Object.values(chartData)); | |
let scale = getComputedStyle(this.chartElem).getPropertyValue('--chart-height') / maxValue; | |
let chartColumnsHtml = ``; | |
for(let [date, value] of Object.entries(chartData)) { | |
// console.log(this.height, Math.floor(value*scale)); | |
chartColumnsHtml += `<div style="--value:${Math.floor(value*scale)}" data-tooltip="${this.formatTooltip(new Date(date), value)}"></div>` | |
} | |
this.elem.querySelector('.column-chart__header').innerHTML = this.formatHeading(chartData); | |
this.chartElem.innerHTML = chartColumnsHtml; | |
} | |
}; |
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
export default { | |
"2019-08-20": 163062, | |
"2019-08-21": 61193, | |
"2019-08-22": 79611, | |
"2019-08-23": 61484, | |
"2019-08-24": 36438, | |
"2019-08-25": 108245, | |
"2019-08-26": 172881, | |
"2019-08-27": 183783, | |
"2019-08-28": 243141, | |
"2019-08-29": 213068, | |
"2019-08-30": 213854, | |
"2019-08-31": 207498, | |
"2019-09-01": 151681, | |
"2019-09-02": 90608, | |
"2019-09-03": 195460, | |
"2019-09-04": 282072, | |
"2019-09-05": 251894, | |
"2019-09-06": 132690, | |
"2019-09-07": 158875, | |
"2019-09-08": 193952, | |
"2019-09-09": 187590, | |
"2019-09-10": 126407, | |
"2019-09-11": 189518, | |
"2019-09-12": 145015, | |
"2019-09-13": 259758, | |
"2019-09-14": 184997, | |
"2019-09-15": 103850, | |
"2019-09-16": 180280, | |
"2019-09-17": 218248, | |
"2019-09-18": 206180, | |
"2019-09-19": 170767, | |
"2019-09-20": 252596, | |
} |
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> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<style rel="stylesheet"> | |
body { | |
background: var(--light-blue); padding: 100px; | |
} | |
</style> | |
<link rel="stylesheet" href="../../styles/common.css"> | |
<link href="style.css"> | |
</head> | |
<body> | |
</body> | |
</html> |
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
.column-chart__chart { | |
display: grid; | |
grid-column-gap: 1px; | |
grid-auto-columns: 1fr; | |
grid-template-rows: repeat(50, minmax(0, 1fr)); | |
width: 100%; | |
height: calc(var(--chart-height) * 1px); | |
} | |
.column-chart__chart div { | |
--start: calc(var(--chart-height) + 1 - var(--value)); | |
grid-row: var(--start) / -1; | |
background-color: var(--chart-column-color); | |
min-width: 1px; | |
cursor: pointer; | |
} | |
.column-chart__chart div.is-hovered { | |
opacity: 1; | |
} | |
.column-chart__chart.has-hovered div:not(.is-hovered) { | |
opacity: 0.5; | |
} | |
.column-chart__container { | |
max-width: 100%; | |
position: relative; | |
} | |
.column-chart { | |
padding: 16px 26px 24px; | |
background: var(--white); | |
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.06); | |
border-radius: 4px; | |
border-left: 2px solid var(--chart-column-color); | |
position: relative; | |
} | |
.column-chart__title { | |
font-size: 16px; | |
line-height: 20px; | |
color: var(--grey); | |
display: flex; | |
flex-direction: row; | |
justify-content: space-between; | |
margin-bottom: 8px; | |
} | |
.column-chart__link { | |
color: var(--blue); | |
text-decoration: none; | |
} | |
.column-chart__header { | |
font-weight: 600; | |
font-size: 28px; | |
line-height: 35px; | |
color: var(--dark-blue); | |
margin-bottom: 28px; | |
position: relative; | |
} | |
.column-chart_loading .column-chart__header, | |
.column-chart_loading .column-chart__chart { | |
display: none; | |
} | |
.column-chart_loading .column-chart__container:before { | |
content: ""; | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
height: 113px; | |
background: url("/assets/images/charts-skeleton.svg") center no-repeat; | |
background-size: cover; | |
display: block; | |
} | |
.column-chart_loading .loading-line { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 100%; | |
z-index: 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment