TypeScript
by xylab
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"></script>
<div class="root">
<div class="header">
<h2 class="title">
Цены. Индекс потребительских цен на товары и услуги за последний месяц отчетного периода, в % к декабрю предыдущего года
</h2>
<div class="preview"></div>
</div>
<div class="actions">
<!--label id="form" for="show-voronoi">
Показать разбиение Вороного
<input type="checkbox" id="show-voronoi" disabled>
</label-->
<button class="reset-zoom-button">Сбросить зум</button>
</div>
<div class="chart"></div>
<div class="legend"></div>
<div class="extra-options-container"></div>
</div>
CSS
@font-face {
font-family: 'Montserrat';
font-style: normal;
font-weight: 500;
src: local('Montserrat Medium'), local('Montserrat-Medium'), url(https://fonts.gstatic.com/s/montserrat/v14/JTURjIg1_i6t8kCHKm45_ZpC3g3D_u50.woff2) format('woff2');
unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
body {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
font-family: Montserrat, sans-serif;
font-wight: 500;
font-size: 12px;
}
.root {
margin-left: 20px;
padding-bottom: 20px;
}
.header {
display: flex;
width: 910px;
padding-bottom: 10px;
margin-bottom: 10px;
border-bottom: 1px rgba(0,0,0,.1) solid;
}
.title {
padding-right: 40px;
margin: 0;
font-weight: 500;
font-size: 15px;
line-height: 25px;
margin-top: 3px;
width: 658px;
}
.preview {
position: relative;
}
.preview-rect {
position: absolute;
left: 0;
top: 0;
}
.actions {
display: flex;
margin-bottom: 10px;
width: 900px;
justify-content: space-between;
}
.axis path {
display: none;
}
.x-axis line {
stroke-opacity: 0.1;
}
.y-axis line {
stroke-opacity: 0.2;
}
.axis text {
font-weight: bold;
text-transform: uppercase;
font-size: 10px;
}
.y-axis line {
stroke-dasharray: 1, 2;
stroke-width: 1;
}
.y-axis .tick text {
text-anchor: end;
}
text, button {
font-family: Montserrat, sans-serif;
}
.preview-axis.x-axis .tick:nth-child(2) text {
text-anchor: start;
}
.preview-axis.x-axis .tick:nth-child(3) text {
text-anchor: end;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.region-hover {
stroke: #000;
stroke-width: 4px;
}
.voronoi path {
fill: none;
pointer-events: all;
}
.voronoi-show path {
stroke: red;
stroke-opacity: 0.2;
}
.dot {
stroke-width: 1px;
stroke: white;
}
.legend {
font-size: 0;
white-space: nowrap;
margin-left: 50px;
margin-top: 25px;
}
.legend-column {
position: relative;
width: 322px;
...
JavaScript
d3.timeFormatDefaultLocale({
'dateTime': '%A, %e %B %Y г. %X',
'date': '%d.%m.%Y',
'time': '%H:%M:%S',
'periods': ['AM', 'PM'],
'days': ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота'],
'shortDays': ['вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб'],
'months': ['январь', 'февраль', 'март', 'апрель', 'май', 'июнь', 'июль', 'август', 'сентябрь', 'октябрь', 'ноябрь', 'декабрь'],
'shortMonths': ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек']
});
const timeFormatter = d3.timeFormat('%d-%m-%Y');
function chunkHelper(data, numberOfChunks) { // eslint-disable-line
const result = [];
let remainingToDistribute = data.length;
while (result.length < numberOfChunks) {
const maxNumberOfElementsInChunk = Math.ceil(remainingToDistribute / (numberOfChunks - result.length));
const currentlyDistributed = data.length - remainingToDistribute;
const currentChunk = data.slice(currentlyDistributed, currentlyDistributed + maxNumberOfElementsInChunk);
result.push(currentChunk);
remainingToDistribute = remainingToDistribute - currentChunk.length;
}
return result;
}
d3.csv('https://raw.githubusercontent.com/moskau-git/vers/master/data.csv', draw);
function draw(data) {
const margin = { top: 0, right: 20, bottom: 50, left: 50 };
const previewMargin = { top: 10, right: 10, bottom: 15, left: 30 };
const width = 920 - margin.left - margin.right;
const height = 390 - margin.top - margin.bottom;
const ratio = 4;
const previewWidth = width / ratio;
const previewHeight = height / ratio;
const x = d3.scaleTime()
.range([0, width]);
const y = d3.scaleLinear()
.range([height, 0]);
let rescaledX = x;
let rescaledY = y;
const previewX = d3.scaleTime()
.range([0, previewWidth]);
const previewY = d3.scaleLinear()
.range([previewHeight, 0]);
const colorScale = d3.scaleOrdinal(d3.schemeCategory20);
const zoom = d3.zoom()
...