├── deploy.sh ├── .gitignore ├── src ├── index.ts ├── Telemap │ ├── StackedPercentTelemap.ts │ ├── LineTelemap.ts │ ├── StackedTelemap.ts │ ├── TwoAxisTelemap.ts │ └── AbstractTelemap.ts ├── Display │ ├── LineTeledisplay.ts │ ├── TwoAxisTeledisplay.ts │ ├── StackedPercentTeledisplay.ts │ ├── StackedTeledisplay.ts │ └── AbstractTeledisplay.ts ├── Telemation.ts ├── Drawer │ ├── LineChartDrawer.ts │ ├── StackedPercentChartDrawer.ts │ ├── StackedChartDrawer.ts │ └── AbstractChartDrawer.ts ├── Teletip.ts ├── Telegend.ts ├── Telecolumn.ts ├── Telecanvas.ts └── Telechart.ts ├── webpack.prod.js ├── webpack.dev.js ├── make-sources-tar.sh ├── README.md ├── tslint.json ├── webpack.common.js ├── package.json ├── dist ├── telechart.css ├── index.html └── data │ ├── 1 │ └── overview.json │ ├── 2 │ └── overview.json │ ├── 3 │ └── overview.json │ ├── 4 │ └── overview.json │ └── 5 │ └── overview.json └── tsconfig.json /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git pull origin master 4 | npm run build 5 | ./make-sources-tar.sh -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .code 3 | dist/* 4 | !dist/index.html 5 | !dist/data 6 | !dist/telechart.css 7 | node_modules 8 | package-lock.json 9 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Telechart } from './Telechart' 2 | 3 | export { Telechart } 4 | export default Telechart 5 | ; (window as any).Telechart = Telechart 6 | -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | const extend = require('webpack-merge') 2 | 3 | module.exports = extend(require('./webpack.common'), { 4 | mode: 'production', 5 | devtool: false, 6 | }) -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | const extend = require('webpack-merge') 2 | 3 | module.exports = extend(require('./webpack.common'), { 4 | mode: 'development', 5 | devtool: 'inline-source-map', 6 | }) -------------------------------------------------------------------------------- /make-sources-tar.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | tar -czf dist/sources.tar.gz --exclude="node_modules" --exclude="package-lock.json" --exclude="dist/telechart.min.js" --exclude="dist/sources.tar.gz" * .gitignore 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 5 charts for Telegram April 2019 Coding Contest 2 | 3 | To see how it looks just do this: 4 | 5 | ```bash 6 | git clone https://github.com/native-elements/telechart && cd telechart 7 | npm install 8 | npm run demo 9 | ``` 10 | 11 | After that new browser tab shall open. 12 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "defaultSeverity": "error", 3 | "extends": [ 4 | "tslint:recommended" 5 | ], 6 | "jsRules": {}, 7 | "rules": { 8 | "semicolon": false, 9 | "arrow-parens": false, 10 | "quotemark": { 11 | "options": "single" 12 | }, 13 | "align": false, 14 | "ordered-imports": false, 15 | "no-console": false, 16 | "object-literal-sort-keys": false, 17 | "max-line-length": false 18 | }, 19 | "rulesDirectory": [] 20 | } -------------------------------------------------------------------------------- /webpack.common.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: ['./src/index.ts'], 5 | module: { 6 | rules: [ 7 | { 8 | test: /\.tsx?$/, 9 | use: 'ts-loader', 10 | exclude: /node_modules/ 11 | } 12 | ] 13 | }, 14 | resolve: { 15 | extensions: [ '.tsx', '.ts', '.js' ] 16 | }, 17 | output: { 18 | filename: 'telechart.min.js', 19 | path: path.resolve(__dirname, 'dist') 20 | } 21 | } -------------------------------------------------------------------------------- /src/Telemap/StackedPercentTelemap.ts: -------------------------------------------------------------------------------- 1 | import { StackedTelemap } from './StackedTelemap' 2 | import Telechart from '../index'; 3 | import { StackedPercentChartDrawer } from '../Drawer/StackedPercentChartDrawer' 4 | 5 | export class StackedPercentTelemap extends StackedTelemap { 6 | 7 | constructor(telechart: Telechart) { 8 | super(telechart) 9 | this.drawers.push(new StackedPercentChartDrawer(telechart, { noGuides: true, noMilestones: true, topPadding: this.topPadding, bottomPadding: this.bottomPadding })) 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "telechart", 3 | "version": "0.0.1", 4 | "description": "", 5 | "scripts": { 6 | "build": "webpack --config webpack.prod.js", 7 | "watch": "webpack -w --config webpack.dev.js", 8 | "demo": "npm run build && http-server ./dist -o -p 9876", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "author": "Valery Shibanov", 12 | "license": "MIT", 13 | "dependencies": { 14 | "http-server": "^0.12.3" 15 | }, 16 | "devDependencies": { 17 | "css-loader": "^2.1.1", 18 | "mini-css-extract-plugin": "^0.5.0", 19 | "ts-loader": "^5.3.3", 20 | "typescript": "^3.3.3333", 21 | "webpack": "^4.29.6", 22 | "webpack-cli": "^3.2.3", 23 | "webpack-merge": "^4.2.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Telemap/LineTelemap.ts: -------------------------------------------------------------------------------- 1 | import { AbstractTelemap } from './AbstractTelemap' 2 | import { Telecolumn } from '../Telecolumn' 3 | import { Telechart } from '../Telechart' 4 | import { LineChartDrawer } from '../Drawer/LineChartDrawer' 5 | 6 | export class LineTelemap extends AbstractTelemap { 7 | 8 | constructor(telechart: Telechart) { 9 | super(telechart) 10 | this.drawers.push(new LineChartDrawer(telechart, { noGuides: true, noMilestones: true, topPadding: this.topPadding, bottomPadding: this.bottomPadding })) 11 | } 12 | 13 | public addColumn(column: Telecolumn) { 14 | this.drawers.forEach(d => d.addColumn(column)) 15 | super.addColumn(column) 16 | } 17 | 18 | protected drawColumns() { 19 | for (const drawer of this.drawers) { 20 | drawer.drawColumns() 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/Telemap/StackedTelemap.ts: -------------------------------------------------------------------------------- 1 | import { AbstractTelemap } from './AbstractTelemap' 2 | import { Telecolumn } from '../Telecolumn' 3 | import { Telechart } from '../Telechart' 4 | import { StackedChartDrawer } from '../Drawer/StackedChartDrawer' 5 | 6 | export class StackedTelemap extends AbstractTelemap { 7 | 8 | constructor(telechart: Telechart) { 9 | super(telechart) 10 | this.drawers.push(new StackedChartDrawer(telechart, { noGuides: true, noMilestones: true, topPadding: this.topPadding, bottomPadding: this.bottomPadding })) 11 | } 12 | 13 | public addColumn(column: Telecolumn) { 14 | this.drawers.forEach(d => d.addColumn(column)) 15 | super.addColumn(column) 16 | } 17 | 18 | protected drawColumns() { 19 | for (const drawer of this.drawers) { 20 | drawer.drawColumns() 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/Telemap/TwoAxisTelemap.ts: -------------------------------------------------------------------------------- 1 | import { AbstractTelemap } from './AbstractTelemap' 2 | import { Telechart } from '../Telechart' 3 | import { LineChartDrawer } from '../Drawer/LineChartDrawer' 4 | import { Telecolumn } from '../Telecolumn' 5 | 6 | export class TwoAxisTelemap extends AbstractTelemap { 7 | 8 | constructor(telechart: Telechart) { 9 | super(telechart) 10 | this.drawers.push(new LineChartDrawer(telechart, { topPadding: this.topPadding, bottomPadding: this.bottomPadding })) 11 | this.drawers.push(new LineChartDrawer(telechart, { noGuides: true, noMilestones: true, topPadding: this.topPadding, bottomPadding: this.bottomPadding })) 12 | } 13 | 14 | public addColumn(column: Telecolumn) { 15 | if (this.columns.length === 0) { 16 | this.drawers[0].addColumn(column) 17 | } else if (this.columns.length === 1) { 18 | this.drawers[1].addColumn(column) 19 | } 20 | super.addColumn(column) 21 | } 22 | 23 | protected drawColumns() { 24 | if (!this.firstDrawer) { 25 | return 26 | } 27 | for (const drawer of this.drawers as LineChartDrawer[]) { 28 | drawer.drawColumns() 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/Display/LineTeledisplay.ts: -------------------------------------------------------------------------------- 1 | import { AbstractTeledisplay } from './AbstractTeledisplay' 2 | import { LineChartDrawer } from '../Drawer/LineChartDrawer' 3 | import { Telechart } from '../Telechart' 4 | import { Telecolumn } from '../Telecolumn' 5 | 6 | export class LineTeledisplay extends AbstractTeledisplay { 7 | 8 | constructor(telechart: Telechart) { 9 | super(telechart) 10 | this.drawers.push(new LineChartDrawer(telechart, { isRangeDisplay: true, lineWidth: 2, topPadding: 15, bottomPadding: 40 + this.telechart.telemap.height })) 11 | } 12 | 13 | public addColumn(column: Telecolumn) { 14 | super.addColumn(column) 15 | this.drawers.forEach(d => d.addColumn(column)) 16 | } 17 | 18 | public draw() { 19 | if (!this.firstDrawer) { 20 | return 21 | } 22 | this.firstDrawer.drawGuides(this.axisColor) 23 | for (const drawer of this.drawers as LineChartDrawer[]) { 24 | drawer.drawMilestones(this.axisTextColor) 25 | drawer.drawCurrentLine(this.lineColor) 26 | drawer.drawColumns() 27 | drawer.drawGuides(undefined, this.axisTextColor) 28 | drawer.drawCurrentPoints() 29 | } 30 | this.updateTeletip() 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/Telemation.ts: -------------------------------------------------------------------------------- 1 | export class Telemation { 2 | 3 | public static create(to: number): Telemation 4 | public static create(from: number, to: number, duration: number): Telemation 5 | 6 | public static create(a: number, b?: number, c?: number) { 7 | if (arguments.length === 1) { 8 | return new Telemation(0, a, 0) 9 | } 10 | return new Telemation(a, b!, c!) 11 | } 12 | 13 | public finished: boolean 14 | protected start: number 15 | 16 | constructor(public from: number, public to: number, protected duration: number) { 17 | this.start = Date.now() 18 | this.finished = !duration 19 | } 20 | 21 | public update(to: number): Telemation 22 | public update(from: number, to: number, duration: number): Telemation 23 | 24 | public update(a: number, b?: number, c?: number): Telemation { 25 | if (arguments.length === 1) { 26 | this.from = 0 27 | this.to = a 28 | this.duration = 0 29 | } else { 30 | this.from = a 31 | this.to = b! 32 | this.duration = c! 33 | } 34 | this.finished = !this.duration 35 | 36 | return this 37 | } 38 | 39 | get value() { 40 | if (this.finished) { 41 | return this.to 42 | } 43 | const p = Math.min(1, Math.max(0, ((Date.now() - this.start)) / this.duration)) 44 | if (p === 1) { 45 | this.finished = true 46 | return this.to 47 | } else if (p === 0) { 48 | return this.from 49 | } 50 | return (this.from + (this.to - this.from) * (p * (2 - p))) 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/Drawer/LineChartDrawer.ts: -------------------------------------------------------------------------------- 1 | import { AbstractChartDrawer, IAbstractChartDrawerOptions } from './AbstractChartDrawer' 2 | import { Telecolumn } from '../Telecolumn' 3 | import { Telechart} from '../Telechart' 4 | 5 | export interface ILineChartDrawerOptions extends IAbstractChartDrawerOptions { 6 | lineWidth?: number 7 | } 8 | 9 | export class LineChartDrawer extends AbstractChartDrawer { 10 | public lineWidth: number 11 | 12 | constructor(telechart: Telechart, options?: ILineChartDrawerOptions) { 13 | super(telechart, options) 14 | this.lineWidth = options && options.lineWidth ? options.lineWidth : 1 15 | } 16 | 17 | public drawColumns() { 18 | const c = this.telecanvas 19 | c.save() 20 | c.setClippingRect(0, 0, c.width, c.height - this.bottomPadding + 30) 21 | this.columns.forEach(col => this.drawColumn(col)) 22 | c.restore() 23 | if (!this.borders.maxX.finished || !this.borders.maxY.finished || (!this.isZeroStart && !this.borders.minY.finished)) { 24 | this.telechart.redraw() 25 | } 26 | } 27 | 28 | public drawColumn(column: Telecolumn) { 29 | if (!column.opacity.value) { 30 | return 31 | } 32 | const c = this.telecanvas 33 | const allVals = this.getInDisplayColumnValues(column) 34 | if (allVals.length) { 35 | let opacity = Math.round(column.opacity.value * 255).toString(16) 36 | if (opacity.length === 1) { 37 | opacity = '0' + opacity 38 | } 39 | c.path(allVals.map(i => [this.getCanvasX(i.x), this.getCanvasY(i.y)] as [number, number]), column.color + opacity, this.lineWidth) 40 | if (!column.opacity.finished) { 41 | this.telechart.redraw() 42 | } 43 | } 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/Display/TwoAxisTeledisplay.ts: -------------------------------------------------------------------------------- 1 | import { AbstractTeledisplay } from './AbstractTeledisplay' 2 | import { LineChartDrawer } from '../Drawer/LineChartDrawer' 3 | import { Telecolumn } from '../Telecolumn' 4 | import { Telechart } from '../Telechart' 5 | 6 | export class TwoAxisTeledisplay extends AbstractTeledisplay { 7 | 8 | constructor(telechart: Telechart) { 9 | super(telechart) 10 | this.drawers.push(new LineChartDrawer(telechart, { isRangeDisplay: true, lineWidth: 2, topPadding: 15, bottomPadding: 40 + this.telechart.telemap.height })) 11 | this.drawers.push(new LineChartDrawer(telechart, { isRangeDisplay: true, noMilestones: true, lineWidth: 2, topPadding: 15, bottomPadding: 40 + this.telechart.telemap.height })) 12 | } 13 | 14 | public addColumn(column: Telecolumn) { 15 | super.addColumn(column) 16 | if (this.columns.length === 1) { 17 | this.drawers[0].addColumn(column) 18 | } else if (this.columns.length === 2) { 19 | this.drawers[1].addColumn(column) 20 | } 21 | } 22 | 23 | public draw() { 24 | if (!this.firstDrawer) { 25 | return 26 | } 27 | for (let n = 0; n < this.drawers.length; n++) { 28 | const drawer = this.drawers[n] as LineChartDrawer 29 | if (n === 0) { 30 | drawer.drawMilestones(this.axisTextColor) 31 | drawer.drawCurrentLine(this.lineColor) 32 | } 33 | drawer.drawGuides(this.theme === 'dark' ? '#3b4453' : '#eaebed') 34 | } 35 | for (const drawer of this.drawers) { 36 | drawer.drawColumns() 37 | } 38 | for (let n = 0; n < this.drawers.length; n++) { 39 | const drawer = this.drawers[n] as LineChartDrawer 40 | drawer.drawGuides(undefined, this.columns[n].color, n === 0 ? 'left' : 'right') 41 | drawer.drawCurrentPoints() 42 | } 43 | this.updateTeletip() 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/Display/StackedPercentTeledisplay.ts: -------------------------------------------------------------------------------- 1 | import { AbstractTeledisplay } from './AbstractTeledisplay' 2 | import { Telechart } from '../Telechart' 3 | import { Telecolumn } from '../Telecolumn' 4 | import { StackedChartDrawer } from '../Drawer/StackedChartDrawer' 5 | import { StackedPercentChartDrawer } from '../Drawer/StackedPercentChartDrawer' 6 | import { ITeletipContent } from '../Teletip' 7 | 8 | export class StackedPercentTeledisplay extends AbstractTeledisplay { 9 | protected drawers: StackedChartDrawer[] = [] 10 | 11 | constructor(telechart: Telechart) { 12 | super(telechart) 13 | this.drawers.push(new StackedPercentChartDrawer(telechart, { isRangeDisplay: true, topPadding: 15, bottomPadding: 40 + this.telechart.telemap.height })) 14 | } 15 | 16 | public addColumn(column: Telecolumn) { 17 | super.addColumn(column) 18 | this.drawers.forEach(d => d.addColumn(column)) 19 | } 20 | 21 | public draw() { 22 | if (!this.firstDrawer) { 23 | return 24 | } 25 | const textColor = this.theme === 'dark' ? '#ECF2F87F' : '#2525297F' 26 | const c = this.telecanvas 27 | c.text('100%', [0, this.firstDrawer.topPadding - 6], textColor, undefined, 11) 28 | for (const drawer of this.drawers as StackedPercentChartDrawer[]) { 29 | drawer.drawMilestones(this.axisTextColor) 30 | drawer.drawColumns() 31 | drawer.drawGuides(this.axisColor, textColor, undefined, (label) => label + '%') 32 | drawer.drawCurrentLine(this.theme === 'dark' ? '#dfe6eb7F' : '#3b4a5a7F') 33 | } 34 | this.updateTeletip() 35 | } 36 | 37 | protected getTeletipContent(currentColumns: Telecolumn[]): ITeletipContent { 38 | const sum = currentColumns.reduce((r, v) => r + v.currentPoint!.y, 0) 39 | const values = currentColumns.map(col => { 40 | return { 41 | name: col.name, 42 | color: col.color, 43 | value: this.telechart.formatNumber(col.currentPoint!.y), 44 | percentage: Math.round(col.currentPoint!.y / sum * 100), 45 | } 46 | }) 47 | return { title: this.telechart.getDateString(currentColumns[0]!.currentPoint!.x, 'D, j M Y'), values } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/Display/StackedTeledisplay.ts: -------------------------------------------------------------------------------- 1 | import { AbstractTeledisplay } from './AbstractTeledisplay' 2 | import { Telechart } from '../Telechart' 3 | import { Telecolumn } from '../Telecolumn' 4 | import { StackedChartDrawer } from '../Drawer/StackedChartDrawer' 5 | 6 | interface IStackedTeledisplayOptions { 7 | rectangle?: boolean 8 | } 9 | 10 | export class StackedTeledisplay extends AbstractTeledisplay { 11 | protected drawers: StackedChartDrawer[] = [] 12 | protected rectangle: boolean 13 | 14 | constructor(telechart: Telechart, options?: IStackedTeledisplayOptions) { 15 | super(telechart) 16 | this.rectangle = options && options.rectangle ? true : false 17 | this.drawers.push(new StackedChartDrawer(telechart, { 18 | isRangeDisplay: true, 19 | topPadding: 15, 20 | bottomPadding: 40 + this.telechart.telemap.height, 21 | rectangle: this.rectangle, 22 | })) 23 | } 24 | 25 | public addColumn(column: Telecolumn) { 26 | super.addColumn(column) 27 | this.drawers.forEach(d => d.addColumn(column)) 28 | } 29 | 30 | public draw() { 31 | if (!this.firstDrawer) { 32 | return 33 | } 34 | for (const drawer of this.drawers as StackedChartDrawer[]) { 35 | drawer.drawMilestones(this.axisTextColor) 36 | drawer.drawColumns() 37 | drawer.drawGuides(this.axisColor, this.theme === 'dark' ? '#ECF2F87F' : '#2525297F') 38 | if (!this.rectangle) { 39 | drawer.drawCurrentLine(this.theme === 'dark' ? '#dfe6eb7F' : '#3b4a5a7F') 40 | } 41 | } 42 | this.updateTeletip() 43 | } 44 | 45 | protected onMouseMove(x: number, y: number) { 46 | if (!this.rectangle) { 47 | super.onMouseMove(x, y) 48 | return 49 | } 50 | if (!this.drawers.length || !this.firstDrawer || !this.firstDrawer.bordersAnimationFinished) { 51 | return 52 | } 53 | if (x >= 0 && y >= 0 && x < this.telecanvas.width && y < this.height) { 54 | const val = this.firstDrawer.getXValue(x - this.telecanvas.width / this.drawers[0].valuesLength / 2) 55 | if (this.columns.reduce((r, c) => c.setCurrentX(val) || r, false)) { 56 | this.telechart.redraw() 57 | } 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/Drawer/StackedPercentChartDrawer.ts: -------------------------------------------------------------------------------- 1 | import { Telecolumn } from '../Telecolumn' 2 | import { StackedChartDrawer } from './StackedChartDrawer' 3 | import { Telemation } from '../Telemation' 4 | 5 | export class StackedPercentChartDrawer extends StackedChartDrawer { 6 | protected guidesCount = 4 7 | 8 | public drawColumns() { 9 | let prev: number[]|undefined 10 | const borders = { minX: this.borders.minX.value, maxX: this.borders.maxX.value, minY: 0, maxY: this.borders.maxY.value } 11 | const colsValues: Array<{ col: Telecolumn, values: Array<{ x: number, y: number }> }> = [] 12 | for (const col of this.columns) { 13 | if (!col.opacity.value) { 14 | continue 15 | } 16 | colsValues.push({ col, values: this.getInDisplayColumnValues(col, [borders.minX, borders.maxX]) }) 17 | } 18 | if (!colsValues.length) { 19 | return 20 | } 21 | for (let n = colsValues[0].values.length - 1; n >= 0; n--) { 22 | const sum = colsValues.reduce((r, v) => r + v.values[n].y * v.col.opacity.value, 0) 23 | for (const colVals of colsValues) { 24 | colVals.values[n] = { x: colVals.values[n].x, y: colVals.values[n].y / sum * 100 } 25 | } 26 | } 27 | for (const colVals of colsValues) { 28 | const result = this.drawValues(colVals.col, colVals.values, [borders.minX, borders.maxX], prev) 29 | if (result && !prev) { 30 | prev = result 31 | } else if (result) { 32 | for (let n = result.length - 1; n >= 0; n--) { 33 | prev![n] = prev![n] + result[n] 34 | } 35 | } 36 | } 37 | if (!this.borders.maxX.finished || !this.borders.maxY.finished) { 38 | this.telechart.redraw() 39 | } 40 | } 41 | 42 | protected getNewBorders(duration?: number) { 43 | const result = { 44 | minX: Math.min(...this.columns.filter(c => c.visible).map(c => c.getMinX(this.isRangeDisplay))), 45 | maxX: Math.max(...this.columns.filter(c => c.visible).map(c => c.getMaxX(this.isRangeDisplay))), 46 | minY: 0, 47 | maxY: 100, 48 | } 49 | return { 50 | minX: duration && this.borders ? Telemation.create(this.borders.minX.value, result.minX, 100) : Telemation.create(result.minX), 51 | maxX: duration && this.borders ? Telemation.create(this.borders.maxX.value, result.maxX, 100) : Telemation.create(result.maxX), 52 | minY: duration && this.borders ? Telemation.create(this.borders.minY.value, result.minY, duration) : Telemation.create(result.minY), 53 | maxY: duration && this.borders ? Telemation.create(this.borders.maxY.value, result.maxY, duration) : Telemation.create(result.maxY), 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /dist/telechart.css: -------------------------------------------------------------------------------- 1 | .telechart { 2 | position: relative; 3 | font-family: sans-serif; 4 | user-select: none; 5 | -webkit-tap-highlight-color: transparent; 6 | } 7 | .telechart-heading { 8 | margin-bottom: 10px; 9 | display: flex; 10 | position: relative 11 | } 12 | .telechart-heading-title { 13 | font-size: 20px; 14 | font-weight: bold; 15 | } 16 | .telechart-heading-range { 17 | font-size: 14px; 18 | font-weight: bold; 19 | position: absolute; 20 | right: 0; 21 | top: 4px; 22 | opacity: 1; 23 | transition: opacity .1s; 24 | } 25 | .telechart-heading-range.blink { 26 | opacity: .5; 27 | } 28 | .telechart-tip { 29 | background: #fff; 30 | position: absolute; 31 | border: #e3e3e3 1px solid; 32 | box-shadow: 1px 1px 4px rgba(0, 0, 0, .1); 33 | border-radius: 10px; 34 | transition: .1s; 35 | padding: 7px 9px; 36 | white-space: nowrap; 37 | font-size: 13px; 38 | color: #222; 39 | min-width: 130px; 40 | } 41 | .telechart-tip.dark { 42 | background: #222836; 43 | border-color: #202a37; 44 | color: #fff; 45 | } 46 | .telechart-tip table { 47 | width: 100%; 48 | } 49 | .telechart-tip table td { 50 | padding: 0 3px; 51 | } 52 | .telechart-tip table tr:first-child td { 53 | column-span: 2; 54 | font-weight: bold; 55 | } 56 | .telegend { 57 | padding-top: 16px; 58 | } 59 | .telegend-telement { 60 | display: inline-block; 61 | font-size: 15px; 62 | border-radius: 100px; 63 | padding: 8px 18px 10px; 64 | cursor: pointer; 65 | margin: 6px 6px 0 0; 66 | box-sizing: border-box; 67 | position: relative; 68 | font-weight: bold; 69 | border: 2px solid; 70 | line-height: 15px; 71 | } 72 | .telegend-telement.visible { 73 | color: #fff !important; 74 | } 75 | .telegend-telement > * { 76 | position: relative 77 | } 78 | .telegend-element-back { 79 | position: absolute; 80 | left: -2px; 81 | top: -2px; 82 | right: -2px; 83 | bottom: -2px; 84 | box-sizing: border-box; 85 | box-shadow: none; 86 | border-radius: 100px; 87 | transition: box-shadow .5s; 88 | } 89 | .telegend-telement.visible .telegend-element-back { 90 | box-shadow: inset 0 0 20px 20px; 91 | } 92 | .telegend-element-checkbox { 93 | display: inline-block; 94 | margin-left: -6px; 95 | margin-right: -9px; 96 | position: relative; 97 | width: 12px; 98 | height: 5px; 99 | top: -3px; 100 | opacity: 0; 101 | border-bottom: 2.5px solid #fff; 102 | border-left: 2.5px solid #fff; 103 | transform: rotate(0deg); 104 | transition: transform .6s, width .3s, margin .3s, opacity .3s; 105 | } 106 | .telegend-telement.visible .telegend-element-checkbox { 107 | opacity: 1; 108 | width: 12px; 109 | height: 5px; 110 | transform: rotate(-45deg); 111 | margin-right: 6px; 112 | } 113 | .telegend-element-label { 114 | display: inline-block; 115 | vertical-align: top; 116 | } -------------------------------------------------------------------------------- /src/Teletip.ts: -------------------------------------------------------------------------------- 1 | import { Telechart } from './Telechart' 2 | 3 | export interface ITeletipContent { 4 | title: string, 5 | values: Array<{ name: string, color: string, value: number|string, percentage?: number|string }>, 6 | } 7 | 8 | export class Teletip { 9 | protected readonly element: HTMLDivElement 10 | private themeProperty: 'light'|'dark' = 'light' 11 | 12 | constructor(protected readonly telechart: Telechart, protected parentElement: HTMLElement) { 13 | this.element = parentElement.appendChild(document.createElement('div')) 14 | this.element.classList.add('telechart-tip') 15 | this.theme = telechart.theme 16 | this.hide() 17 | } 18 | 19 | get theme() { 20 | return this.themeProperty 21 | } 22 | 23 | set theme(value) { 24 | this.themeProperty = value 25 | if (value === 'dark') { 26 | this.element.classList.add('dark') 27 | } else { 28 | this.element.classList.remove('dark') 29 | } 30 | } 31 | 32 | public show() { 33 | this.element.style.display = 'block' 34 | } 35 | 36 | public hide() { 37 | this.element.style.display = 'none' 38 | } 39 | 40 | public setCoordinates(value: [number, number]) { 41 | this.element.style.display = 'block' 42 | const width = this.element.offsetWidth 43 | const height = this.element.offsetHeight 44 | const parentWidth = this.parentElement.clientWidth 45 | let top = value[1] - height + 33 /*header height*/ - 15 46 | let left = value[0] - width - 15 47 | if (top < 33) { 48 | top = 33 49 | } 50 | if (left < 0) { 51 | left = value[0] + 15 52 | } 53 | if (left + width > parentWidth) { 54 | left = value[0] - width - 15 55 | } 56 | this.element.style.left = `${left}px` 57 | this.element.style.top = `${top}px` 58 | } 59 | 60 | public setContent(content: ITeletipContent) { 61 | while (this.element.firstChild) { 62 | this.element.removeChild(this.element.firstChild); 63 | } 64 | const table = this.element.appendChild(document.createElement('table')) 65 | const titleRow = table.insertRow() 66 | const titleCell = titleRow.insertCell() 67 | titleCell.innerText = content.title 68 | titleCell.colSpan = content.values[0].percentage ? 3 : 2 69 | 70 | content.values.forEach(val => { 71 | const row = table.insertRow() 72 | if (val.percentage) { 73 | const perc = row.insertCell() 74 | perc.style.textAlign = 'right' 75 | perc.innerHTML = '' + val.percentage + '%' 76 | } 77 | const name = row.insertCell() 78 | const value = row.insertCell() 79 | name.innerText = val.name 80 | value.innerText = String(val.value) 81 | value.style.color = val.color 82 | value.style.fontWeight = 'bold' 83 | value.style.textAlign = 'right' 84 | }) 85 | } 86 | 87 | public draw() {/* */} 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/Display/AbstractTeledisplay.ts: -------------------------------------------------------------------------------- 1 | import { Telecolumn } from '../Telecolumn' 2 | import { Telechart } from '../Telechart' 3 | import { AbstractChartDrawer } from '../Drawer/AbstractChartDrawer' 4 | import { ITeletipContent } from '../Teletip' 5 | 6 | export abstract class AbstractTeledisplay { 7 | public theme: 'light'|'dark' = 'light' 8 | protected columns: Telecolumn[] = [] 9 | protected drawers: AbstractChartDrawer[] = [] 10 | 11 | constructor(protected readonly telechart: Telechart) { 12 | this.telechart.telecanvas.addMouseMoveListener(this.onMouseMove.bind(this)) 13 | this.theme = telechart.theme 14 | } 15 | 16 | public abstract draw(): void 17 | 18 | get axisColor() { 19 | return this.theme === 'dark' ? '#FFFFFF19' : '#182D3B19' 20 | } 21 | 22 | get axisTextColor() { 23 | return this.theme === 'dark' ? '#A3B1C2' : '#8E8E93' 24 | } 25 | 26 | get lineColor() { 27 | return this.theme === 'dark' ? '#3b4a5a' : '#dfe6eb' 28 | } 29 | 30 | get firstDrawer() { 31 | return this.drawers.length ? this.drawers[0] : undefined 32 | } 33 | 34 | get telecanvas() { 35 | return this.telechart.telecanvas 36 | } 37 | 38 | get height() { 39 | return this.telecanvas.height - this.telechart.telemap.height 40 | } 41 | 42 | public addColumn(column: Telecolumn) { 43 | this.columns.push(column) 44 | } 45 | 46 | public removeColumn(column: Telecolumn) { 47 | this.columns.splice(this.columns.indexOf(column), 1) 48 | this.drawers.forEach(d => d.removeColumn(column)) 49 | } 50 | 51 | public recalcBorders(duration: number = 0) { 52 | this.drawers.forEach(d => d.recalcBorders(duration)) 53 | this.telechart.redraw() 54 | } 55 | 56 | protected getTeletipContent(currentColumns: Telecolumn[]): ITeletipContent { 57 | const values = currentColumns.map(col => { 58 | return { name: col.name, color: col.color, value: this.telechart.formatNumber(col.currentPoint!.y) } 59 | }) 60 | 61 | return { title: this.telechart.getDateString(currentColumns[0]!.currentPoint!.x, 'D, j M Y'), values } 62 | } 63 | 64 | protected updateTeletip() { 65 | const curColumns = this.columns.filter(col => col.currentPoint) 66 | if (curColumns.length) { 67 | const pos = this.firstDrawer!.getCanvasX(curColumns[0]!.currentPoint!.x) 68 | if (pos < 0 || pos > this.telecanvas.width) { 69 | this.telechart.teletip.hide() 70 | } else { 71 | this.telechart.teletip.setContent(this.getTeletipContent(curColumns)) 72 | this.telechart.teletip.setCoordinates([ 73 | this.firstDrawer!.getCanvasX(curColumns[0]!.currentPoint!.x), 74 | this.firstDrawer!.getCanvasY(Math.max(...curColumns.map(c => c.currentPoint!.y))), 75 | ]) 76 | this.telechart.teletip.show() 77 | } 78 | } else { 79 | this.telechart.teletip.hide() 80 | } 81 | } 82 | 83 | protected onMouseMove(x: number, y: number) { 84 | if (!this.drawers.length || !this.firstDrawer || !this.firstDrawer.bordersAnimationFinished) { 85 | return 86 | } 87 | if (x >= 0 && y >= 0 && x < this.telecanvas.width && y < this.height) { 88 | const val = this.firstDrawer.getXValue(x) 89 | if (this.columns.reduce((r, c) => c.setCurrentX(val) || r, false)) { 90 | this.telechart.redraw() 91 | } 92 | } 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/Telegend.ts: -------------------------------------------------------------------------------- 1 | import { Telechart } from './Telechart' 2 | import { Telecolumn } from './Telecolumn' 3 | 4 | export class Telegend { 5 | protected columns: Array<{ telecolumn: Telecolumn, element: HTMLElement, onClick: () => void }> = [] 6 | protected element: HTMLElement 7 | private themeProperty: 'light'|'dark' = 'light' 8 | 9 | constructor(protected telechart: Telechart, parentElement: HTMLElement) { 10 | this.element = document.createElement('div') 11 | this.element.classList.add('telegend') 12 | parentElement.appendChild(this.element) 13 | } 14 | 15 | get theme() { 16 | return this.themeProperty 17 | } 18 | 19 | set theme(value) { 20 | this.themeProperty = value 21 | this.element.classList.toggle('dark', value === 'dark') 22 | } 23 | 24 | public addColumn(telecolumn: Telecolumn) { 25 | const element = document.createElement('div') 26 | element.classList.add('telegend-telement') 27 | if (telecolumn.visible) { 28 | element.classList.add('visible') 29 | } 30 | element.style.borderColor = telecolumn.color 31 | element.style.color = telecolumn.color 32 | this.element.appendChild(element) 33 | 34 | const back = document.createElement('div') 35 | back.style.color = telecolumn.color 36 | back.classList.add('telegend-element-back') 37 | 38 | const checkbox = document.createElement('div') 39 | checkbox.classList.add('telegend-element-checkbox') 40 | 41 | const label = document.createElement('div') 42 | label.classList.add('telegend-element-label') 43 | label.innerText = telecolumn.name 44 | 45 | element.appendChild(back) 46 | element.appendChild(checkbox) 47 | element.appendChild(label) 48 | let timeout: number|undefined 49 | const onClick = () => { 50 | this.columns.forEach(c => c.telecolumn.setCurrentX(null)) 51 | telecolumn.visible = !telecolumn.visible 52 | element.classList.toggle('visible', telecolumn.visible) 53 | this.telechart.teledisplay.recalcBorders(200) 54 | this.telechart.telemap.recalcBorders(200) 55 | this.telechart.redraw() 56 | } 57 | const onDown = () => { 58 | if (timeout) { 59 | return 60 | } 61 | timeout = setTimeout(() => { 62 | timeout = undefined 63 | this.columns.forEach(c => c.telecolumn.visible = true) 64 | telecolumn.visible = false 65 | this.columns.forEach(c => c.onClick()) 66 | }, 500) 67 | } 68 | const onUp = () => { 69 | if (timeout) { 70 | clearTimeout(timeout) 71 | timeout = undefined 72 | onClick() 73 | } 74 | } 75 | const onMove = () => { 76 | if (timeout) { 77 | clearTimeout(timeout) 78 | timeout = undefined 79 | } 80 | } 81 | element.addEventListener('touchstart', onDown) 82 | element.addEventListener('mousedown', onDown) 83 | element.addEventListener('mouseup', onUp) 84 | element.addEventListener('touchmove', onMove) 85 | element.addEventListener('mousemove', onMove) 86 | this.columns.push({ telecolumn, element, onClick }) 87 | } 88 | 89 | public removeColumn(column: Telecolumn) { 90 | this.columns.forEach((c, i) => { 91 | if (c.telecolumn === column) { 92 | this.element.removeChild(c.element) 93 | this.columns.splice(i, 1) 94 | } 95 | }) 96 | } 97 | 98 | public draw() {/**/} 99 | 100 | } 101 | -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Telechart Example 7 | 8 | 70 | 71 | 72 |
73 | 74 |
75 |
76 | 77 | Download sources 78 |
Switch to Night Mode
79 | 80 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /src/Telecolumn.ts: -------------------------------------------------------------------------------- 1 | import { Telechart } from './Telechart' 2 | import { Telemation } from './Telemation' 3 | 4 | export interface ITelechartColumnData { 5 | id: string 6 | name: string 7 | values: Array<{ x: number, y: number}> 8 | color: string 9 | } 10 | 11 | export class Telecolumn { 12 | public readonly id: string|number 13 | public readonly name: string 14 | public readonly color: string 15 | public readonly values: Array<{ x: number, y: number}> 16 | public opacity: Telemation 17 | public current: { x: number, y: number }|null = null 18 | public config!: { background: string } 19 | private visibleProperty = true 20 | private readonly telechart: Telechart 21 | private currentRange: { from: number, to: number }|null = null 22 | private themeProperty: 'light'|'dark' = 'light' 23 | 24 | constructor(telechart: Telechart, data: ITelechartColumnData) { 25 | this.telechart = telechart 26 | this.id = data.id 27 | this.name = data.name 28 | this.values = data.values 29 | this.color = data.color 30 | this.theme = telechart.theme 31 | this.opacity = this.visible ? Telemation.create(1) : Telemation.create(0) 32 | } 33 | 34 | get theme() { 35 | return this.themeProperty 36 | } 37 | 38 | set theme(value) { 39 | this.themeProperty = value 40 | if (value === 'dark') { 41 | this.config = { 42 | ...this.config, 43 | background: '#242f3e', 44 | } 45 | } else { 46 | this.config = { 47 | ...this.config, 48 | background: '#fff', 49 | } 50 | } 51 | } 52 | 53 | get visible() { 54 | return this.visibleProperty 55 | } 56 | 57 | set visible(value: boolean) { 58 | if (value !== this.visibleProperty) { 59 | this.visibleProperty = value 60 | this.opacity = value ? Telemation.create(0, 1, 200) : Telemation.create(1, 0, 200) 61 | } 62 | } 63 | 64 | get currentValues() { 65 | return this.currentRange ? this.values.filter(v => v.x >= this.currentRange!.from && v.x <= this.currentRange!.to) : [] 66 | } 67 | 68 | public getMinX(inCurrentRange = false): number { 69 | if (inCurrentRange && this.currentRange) { 70 | return this.currentRange.from 71 | } 72 | const result = this.values.reduce((res: number|null, val) => { 73 | return res === null ? val.x : Math.min(res, val.x) 74 | }, null) 75 | return result ? result : 0 76 | } 77 | 78 | public getMaxX(inCurrentRange = false): number { 79 | if (inCurrentRange && this.currentRange) { 80 | return this.currentRange.to 81 | } 82 | const result = this.values.reduce((res: number|null, val) => { 83 | return res === null ? val.x : Math.max(res, val.x) 84 | }, null) 85 | return result ? result : 0 86 | } 87 | 88 | public getMinY(inCurrentRange = false): number { 89 | const values = inCurrentRange && this.currentRange ? this.currentValues : this.values 90 | const result = values.reduce((res: number|null, val) => { 91 | return res === null ? val.y : Math.min(res, val.y) 92 | }, null) 93 | return result ? result : 0 94 | } 95 | 96 | public getMaxY(inCurrentRange = false): number { 97 | const values = inCurrentRange && this.currentRange ? this.currentValues : this.values 98 | const result = values.reduce((res: number|null, val) => { 99 | return res === null ? val.y : Math.max(res, val.y) 100 | }, null) 101 | return result ? result : 0 102 | } 103 | 104 | public setCurrentX(value: number|null) { 105 | const oldValue = this.current 106 | if (value === null) { 107 | this.current = null 108 | } else { 109 | const currentValues = this.currentValues 110 | if (!currentValues) { 111 | return 112 | } 113 | let min: { val: number, index: number }|null = null 114 | for (let n = 0, length = currentValues.length; n < length; n++) { 115 | const v = currentValues[n] 116 | if (!min) { 117 | min = { val: v.x, index: n } 118 | } 119 | if (Math.abs(v.x - value) < min.val) { 120 | min = { val: Math.abs(v.x - value), index: n } 121 | } 122 | } 123 | if (min!) { 124 | this.current = currentValues[min!.index] 125 | } 126 | } 127 | if (this.current !== oldValue) { 128 | return true 129 | } 130 | } 131 | 132 | get currentPoint(): { x: number, y: number }|null { 133 | return this.current 134 | } 135 | 136 | public setCurrentRange(from: number, to: number) { 137 | this.currentRange = { from, to } 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */ 5 | "module": "es6", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ 6 | // "lib": [], /* Specify library files to be included in the compilation. */ 7 | "allowJs": false, /* Allow javascript files to be compiled. */ 8 | // "checkJs": true, /* Report errors in .js files. */ 9 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 10 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 11 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 12 | "sourceMap": true, /* Generates corresponding '.map' file. */ 13 | // "outFile": "./dist/telechart.js", /* Concatenate and emit output to single file. */ 14 | "outDir": "./dist", /* Redirect output structure to the directory. */ 15 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 16 | // "composite": true, /* Enable project compilation */ 17 | // "removeComments": true, /* Do not emit comments to output. */ 18 | // "noEmit": true, /* Do not emit outputs. */ 19 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 20 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 21 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 22 | 23 | /* Strict Type-Checking Options */ 24 | "strict": true, /* Enable all strict type-checking options. */ 25 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 26 | // "strictNullChecks": true, /* Enable strict null checks. */ 27 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 28 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 29 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 30 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 31 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 32 | 33 | /* Additional Checks */ 34 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 35 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 36 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 37 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 38 | 39 | /* Module Resolution Options */ 40 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 41 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 42 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 43 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 44 | // "typeRoots": [], /* List of folders to include type definitions from. */ 45 | // "types": [], /* Type declaration files to be included in compilation. */ 46 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 47 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 48 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 49 | 50 | /* Source Map Options */ 51 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 52 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 53 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 54 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 55 | 56 | /* Experimental Options */ 57 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 58 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 59 | } 60 | } -------------------------------------------------------------------------------- /src/Drawer/StackedChartDrawer.ts: -------------------------------------------------------------------------------- 1 | import { Telecolumn } from '../Telecolumn' 2 | import { Telemation } from '../Telemation' 3 | import { Telechart } from '../Telechart' 4 | import { AbstractChartDrawer, IAbstractChartDrawerOptions } from './AbstractChartDrawer' 5 | 6 | interface IStackedChartDrawerOptions extends IAbstractChartDrawerOptions { 7 | noCurrent?: boolean 8 | rectangle?: boolean 9 | } 10 | 11 | export class StackedChartDrawer extends AbstractChartDrawer { 12 | public valuesLength = 0 13 | public noCurrent: boolean 14 | public rectangle: boolean 15 | 16 | constructor(telechart: Telechart, options?: IStackedChartDrawerOptions) { 17 | super(telechart, options) 18 | this.noCurrent = options && options.noCurrent ? true : false 19 | this.rectangle = options && options.rectangle ? true : false 20 | } 21 | 22 | get currentPoint() { 23 | if (!this.noCurrent && this.columns.length && this.columns[0].currentPoint) { 24 | return this.columns[0].currentPoint.x 25 | } 26 | } 27 | 28 | public drawColumns() { 29 | let prev: number[]|undefined 30 | const borders = { minX: this.borders.minX.value, maxX: this.borders.maxX.value, minY: 0, maxY: this.borders.maxY.value } 31 | for (const col of this.columns) { 32 | let result 33 | if (this.rectangle) { 34 | result = this.drawColumn(col, prev, borders) 35 | } else { 36 | result = this.drawValues(col, this.getInDisplayColumnValues(col, [borders.minX, borders.maxX]), 37 | [borders.minX, borders.maxX], prev, 38 | ) 39 | } 40 | if (result && !prev) { 41 | prev = result 42 | } else if (result) { 43 | for (let n = result.length - 1; n >= 0; n--) { 44 | prev![n] = prev![n] + result[n] 45 | } 46 | } 47 | } 48 | if (!this.borders.maxX.finished || !this.borders.maxY.finished) { 49 | this.telechart.redraw() 50 | } 51 | } 52 | 53 | public drawColumn(column: Telecolumn, prev?: number[], borders?: { minX: number, maxX: number, minY: number, maxY: number }): number[]|undefined { 54 | if (!column.opacity.value) { 55 | return 56 | } 57 | const c = this.telecanvas 58 | const horBorders = borders ? [borders.minX, borders.maxX] as [number, number] : undefined 59 | const verBorders = borders ? [borders.minY, borders.maxY] as [number, number] : undefined 60 | const allVals = this.getInDisplayColumnValues(column, horBorders) 61 | if (allVals.length) { 62 | const currentPoint = this.currentPoint 63 | const colOpacityVal = column.opacity.value 64 | let opacity = Math.round((currentPoint ? .5 : 1) * 255).toString(16) 65 | if (opacity.length === 1) { 66 | opacity = '0' + opacity 67 | } 68 | const result: number[] = [] 69 | const path: Array<[number, number]> = [] 70 | const valsPrep: Array<{ x: number, y: number, height: number }> = [] 71 | let current: Array<[number, number]>|undefined 72 | this.valuesLength = allVals.length 73 | for (let n = 0; n < allVals.length; n++) { 74 | const x = this.getCanvasX(allVals[n].x, horBorders) 75 | const ySt = this.getCanvasY(0) 76 | let height = ySt - this.getCanvasY(allVals[n].y, verBorders) 77 | if (colOpacityVal < 1) { 78 | height *= colOpacityVal 79 | } 80 | const y = ySt - height - (prev ? prev[n] : 0) 81 | if (colOpacityVal === 1 && height < 2) { 82 | height = 2 83 | } 84 | if (n) { 85 | path[path.length - 1][0] = x 86 | } 87 | path.push([x, y]) 88 | path.push([x, y]) 89 | valsPrep.push({ x, y, height }) 90 | result.push(height) 91 | if (allVals[n].x === currentPoint) { 92 | current = [[x, y], [n + 1 < allVals.length ? this.getCanvasX(allVals[n + 1].x, horBorders) : x + 30, y]] 93 | current.push([current[current.length - 1][0], y + height]) 94 | current.push([x, y + height]) 95 | } 96 | } 97 | for (let n = valsPrep.length - 1; n >= 0; n--) { 98 | path.push([path[n * 2 + 1][0], valsPrep[n].y + valsPrep[n].height]) 99 | path.push([path[n * 2][0], valsPrep[n].y + valsPrep[n].height]) 100 | } 101 | c.shape(path, column.color + opacity) 102 | if (current) { 103 | c.shape(current, column.color) 104 | } 105 | if (!column.opacity.finished) { 106 | this.telechart.redraw() 107 | } 108 | return result 109 | } 110 | } 111 | 112 | public drawValues(column: Telecolumn, values: Array<{ x: number, y: number }>, borders: [number, number], prev?: number[]) { 113 | const c = this.telecanvas 114 | if (values.length) { 115 | const colOpacityVal = column.opacity.value 116 | const result: number[] = [] 117 | const path: Array<[number, number]> = [] 118 | const valsPrep: Array<{ x: number, y: number, height: number }> = [] 119 | this.valuesLength = values.length 120 | for (let n = 0; n < values.length; n++) { 121 | const x = this.getCanvasX(values[n].x, borders) 122 | const ySt = this.getCanvasY(0) 123 | let height = ySt - this.getCanvasY(values[n].y) 124 | if (colOpacityVal < 1) { 125 | height *= colOpacityVal 126 | } 127 | const y = ySt - height - (prev ? prev[n] : 0) 128 | if (colOpacityVal === 1 && height < 2) { 129 | height = 2 130 | } 131 | path.push([x, y]) 132 | valsPrep.push({ x, y, height }) 133 | result.push(height) 134 | } 135 | for (let n = valsPrep.length - 1; n >= 0; n--) { 136 | path.push([path[n][0], valsPrep[n].y + valsPrep[n].height]) 137 | } 138 | c.shape(path, column.color) 139 | if (!column.opacity.finished) { 140 | this.telechart.redraw() 141 | } 142 | return result 143 | } 144 | } 145 | 146 | protected getNewBorders(duration?: number) { 147 | const result = { 148 | minX: Math.min(...this.columns.filter(c => c.visible).map(c => c.getMinX(this.isRangeDisplay))), 149 | maxX: Math.max(...this.columns.filter(c => c.visible).map(c => c.getMaxX(this.isRangeDisplay))), 150 | minY: 0, 151 | maxY: this.columns.filter(c => c.visible).map(c => c.getMaxY(this.isRangeDisplay)).reduce((r, v) => r + v, 0), 152 | } 153 | return { 154 | minX: duration && this.borders ? Telemation.create(this.borders.minX.value, result.minX, 100) : Telemation.create(result.minX), 155 | maxX: duration && this.borders ? Telemation.create(this.borders.maxX.value, result.maxX, 100) : Telemation.create(result.maxX), 156 | minY: Telemation.create(result.minY), 157 | maxY: duration && this.borders ? Telemation.create(this.borders.maxY.value, result.maxY, duration) : Telemation.create(result.maxY), 158 | } 159 | } 160 | 161 | } 162 | -------------------------------------------------------------------------------- /dist/data/4/overview.json: -------------------------------------------------------------------------------- 1 | {"columns":[["x",1523059200000,1523145600000,1523232000000,1523318400000,1523404800000,1523491200000,1523577600000,1523664000000,1523750400000,1523836800000,1523923200000,1524009600000,1524096000000,1524182400000,1524268800000,1524355200000,1524441600000,1524528000000,1524614400000,1524700800000,1524787200000,1524873600000,1524960000000,1525046400000,1525132800000,1525219200000,1525305600000,1525392000000,1525478400000,1525564800000,1525651200000,1525737600000,1525824000000,1525910400000,1525996800000,1526083200000,1526169600000,1526256000000,1526342400000,1526428800000,1526515200000,1526601600000,1526688000000,1526774400000,1526860800000,1526947200000,1527033600000,1527120000000,1527206400000,1527292800000,1527379200000,1527465600000,1527552000000,1527638400000,1527724800000,1527811200000,1527897600000,1527984000000,1528070400000,1528156800000,1528243200000,1528329600000,1528416000000,1528502400000,1528588800000,1528675200000,1528761600000,1528848000000,1528934400000,1529020800000,1529107200000,1529193600000,1529280000000,1529366400000,1529452800000,1529539200000,1529625600000,1529712000000,1529798400000,1529884800000,1529971200000,1530057600000,1530144000000,1530230400000,1530316800000,1530403200000,1530489600000,1530576000000,1530662400000,1530748800000,1530835200000,1530921600000,1531008000000,1531094400000,1531180800000,1531267200000,1531353600000,1531440000000,1531526400000,1531612800000,1531699200000,1531785600000,1531872000000,1531958400000,1532044800000,1532131200000,1532217600000,1532304000000,1532390400000,1532476800000,1532563200000,1532649600000,1532736000000,1532822400000,1532908800000,1532995200000,1533081600000,1533168000000,1533254400000,1533340800000,1533427200000,1533513600000,1533600000000,1533686400000,1533772800000,1533859200000,1533945600000,1534032000000,1534118400000,1534204800000,1534291200000,1534377600000,1534464000000,1534550400000,1534636800000,1534723200000,1534809600000,1534896000000,1534982400000,1535068800000,1535155200000,1535241600000,1535328000000,1535414400000,1535500800000,1535587200000,1535673600000,1535760000000,1535846400000,1535932800000,1536019200000,1536105600000,1536192000000,1536278400000,1536364800000,1536451200000,1536537600000,1536624000000,1536710400000,1536796800000,1536883200000,1536969600000,1537056000000,1537142400000,1537228800000,1537315200000,1537401600000,1537488000000,1537574400000,1537660800000,1537747200000,1537833600000,1537920000000,1538006400000,1538092800000,1538179200000,1538265600000,1538352000000,1538438400000,1538524800000,1538611200000,1538697600000,1538784000000,1538870400000,1538956800000,1539043200000,1539129600000,1539216000000,1539302400000,1539388800000,1539475200000,1539561600000,1539648000000,1539734400000,1539820800000,1539907200000,1539993600000,1540080000000,1540166400000,1540252800000,1540339200000,1540425600000,1540512000000,1540598400000,1540684800000,1540771200000,1540857600000,1540944000000,1541030400000,1541116800000,1541203200000,1541289600000,1541376000000,1541462400000,1541548800000,1541635200000,1541721600000,1541808000000,1541894400000,1541980800000,1542067200000,1542153600000,1542240000000,1542326400000,1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000,1552089600000,1552176000000,1552262400000,1552348800000,1552435200000,1552521600000,1552608000000,1552694400000,1552780800000,1552867200000,1552953600000,1553040000000,1553126400000,1553212800000,1553299200000,1553385600000,1553472000000,1553558400000,1553644800000,1553731200000,1553817600000,1553904000000,1553990400000,1554076800000,1554163200000,1554249600000,1554336000000,1554422400000,1554508800000],["y0",30600800,31327000,35296200,36671400,38742200,39538200,40365200,42177400,41253800,42994000,41398800,42850400,43624400,44164400,43575200,42069200,42733200,40369800,40467800,43160200,47773400,46834200,43145800,64329200,38156800,36229800,34755800,36527000,33582800,31686200,32552000,30499600,29413400,30605200,29920600,27942600,26974600,24874400,24546600,24789000,25654200,26277000,24491600,24444600,24416600,24593400,25214400,24817200,25938600,25223200,23816000,23189200,22654200,22579000,22185600,23108800,22146600,19930200,22292000,19980600,21812600,19632600,21635800,20944800,20299200,20543000,20725800,20119400,20247600,17315200,19133200,19691000,20111200,19735400,17922600,18467200,19467400,18115600,19175200,17285400,18604800,18150200,18689400,19497800,19688800,20074200,19243000,20180600,19962400,19130800,19464800,20429200,20254600,21029800,20104400,19559400,18572400,19560800,20320200,20534000,20865800,20705000,20326600,19589400,20039800,20672000,20448600,20431400,20203000,19807800,19114600,19737000,20446400,19984200,19013000,21106600,18543800,16215800,16996600,16285200,16812800,18398000,17487600,19092400,18394000,18933000,19541600,19880800,20069600,19929800,18914400,18397600,18944200,20357400,19935200,19857200,19392000,18742600,18331000,18930400,19992400,19907600,20189800,19738000,18392200,17742200,18294600,19626800,19650000,20076800,20142200,19624800,18711200,19298400,20398200,20290600,20346200,21254200,20288000,19139800,19492200,19611800,19389000,18652400,17296600,16267200,17129200,21290200,19845000,19130600,19087400,18704600,19270000,19601800,20168800,18454200,18388800,18521200,18595400,18921800,18961600,20607400,18806000,18761800,18780400,19312600,19751200,20555800,21416400,11018800,19735000,19565600,19622600,20178400,20873400,21822600,20152400,20210000,20094000,19408600,20045200,21272800,22675200,20556600,20628800,20193800,23418000,21550800,22184600,23645000,21168000,21156400,20624600,20763600,22816400,22499400,22984000,19503000,19126800,18676000,18452400,18917800,19860600,21129200,18835600,18816400,18739400,19215600,18999000,19278200,21011000,20021200,21848400,19470600,18784200,18774400,19653200,21242600,18834800,18868800,18462200,18098000,18211600,19367800,20742800,18762000,18738000,18249600,18001600,18234400,19228200,20551600,19084200,19204600,19331800,19235600,18789800,19783000,20253000,20858800,20679600,20483200,20695800,20676000,21407600,23004600,22544800,22397600,22540600,22594800,22962600,23580800,23441600,23028200,23179200,23496800,22729200,23086200,22961000,23396400,22557200,22907400,23239000,22632800,22261200,23621600,24424200,23286600,22865400,22802600,22799400,22745400,22599800,24371000,23400200,24004200,24141000,23751000,22954000,22941400,23675000,23115600,23478800,22618800,22171600,21867600,22016200,22925600,24285600,23554800,25214800,22918800,22629200,23121600,24037200,22052600,21490000,20981000,21275000,21153200,21562000,22737000,20606400,20894400,20349200,20001800,20993600,21822600,23157400,20812400,20631600,20920000,20787600,20625600,21468200,23499200,21612800,21550000,21703600,21410600,22272400,22455600,23961000,22611600,23301400,22674600,21071000,24589200,23748400,22198400,21311200,22167400,23862400,23883200,22336800,21860800,21619000,21934000,23330600,23336400,19579600,22230200,22727600,22706600,21370000]],"types":{"y0":"bar","x":"x"},"names":{"y0":"Views"},"colors":{"y0":"#64ADED"}} -------------------------------------------------------------------------------- /dist/data/1/overview.json: -------------------------------------------------------------------------------- 1 | {"columns":[["x",1523059200000,1523145600000,1523232000000,1523318400000,1523404800000,1523491200000,1523577600000,1523664000000,1523750400000,1523836800000,1523923200000,1524009600000,1524096000000,1524182400000,1524268800000,1524355200000,1524441600000,1524528000000,1524614400000,1524700800000,1524787200000,1524873600000,1524960000000,1525046400000,1525132800000,1525219200000,1525305600000,1525392000000,1525478400000,1525564800000,1525651200000,1525737600000,1525824000000,1525910400000,1525996800000,1526083200000,1526169600000,1526256000000,1526342400000,1526428800000,1526515200000,1526601600000,1526688000000,1526774400000,1526860800000,1526947200000,1527033600000,1527120000000,1527206400000,1527292800000,1527379200000,1527465600000,1527552000000,1527638400000,1527724800000,1527811200000,1527897600000,1527984000000,1528070400000,1528156800000,1528243200000,1528329600000,1528416000000,1528502400000,1528588800000,1528675200000,1528761600000,1528848000000,1528934400000,1529020800000,1529107200000,1529193600000,1529280000000,1529366400000,1529452800000,1529539200000,1529625600000,1529712000000,1529798400000,1529884800000,1529971200000,1530057600000,1530144000000,1530230400000,1530316800000,1530403200000,1530489600000,1530576000000,1530662400000,1530748800000,1530835200000,1530921600000,1531008000000,1531094400000,1531180800000,1531267200000,1531353600000,1531440000000,1531526400000,1531612800000,1531699200000,1531785600000,1531872000000,1531958400000,1532044800000,1532131200000,1532217600000,1532304000000,1532390400000,1532476800000,1532563200000,1532649600000,1532736000000,1532822400000,1532908800000,1532995200000,1533081600000,1533168000000,1533254400000,1533340800000,1533427200000,1533513600000,1533600000000,1533686400000,1533772800000,1533859200000,1533945600000,1534032000000,1534118400000,1534204800000,1534291200000,1534377600000,1534464000000,1534550400000,1534636800000,1534723200000,1534809600000,1534896000000,1534982400000,1535068800000,1535155200000,1535241600000,1535328000000,1535414400000,1535500800000,1535587200000,1535673600000,1535760000000,1535846400000,1535932800000,1536019200000,1536105600000,1536192000000,1536278400000,1536364800000,1536451200000,1536537600000,1536624000000,1536710400000,1536796800000,1536883200000,1536969600000,1537056000000,1537142400000,1537228800000,1537315200000,1537401600000,1537488000000,1537574400000,1537660800000,1537747200000,1537833600000,1537920000000,1538006400000,1538092800000,1538179200000,1538265600000,1538352000000,1538438400000,1538524800000,1538611200000,1538697600000,1538784000000,1538870400000,1538956800000,1539043200000,1539129600000,1539216000000,1539302400000,1539388800000,1539475200000,1539561600000,1539648000000,1539734400000,1539820800000,1539907200000,1539993600000,1540080000000,1540166400000,1540252800000,1540339200000,1540425600000,1540512000000,1540598400000,1540684800000,1540771200000,1540857600000,1540944000000,1541030400000,1541116800000,1541203200000,1541289600000,1541376000000,1541462400000,1541548800000,1541635200000,1541721600000,1541808000000,1541894400000,1541980800000,1542067200000,1542153600000,1542240000000,1542326400000,1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000,1552089600000,1552176000000,1552262400000,1552348800000,1552435200000,1552521600000,1552608000000,1552694400000,1552780800000,1552867200000,1552953600000,1553040000000,1553126400000,1553212800000,1553299200000,1553385600000,1553472000000,1553558400000,1553644800000,1553731200000,1553817600000,1553904000000,1553990400000,1554076800000,1554163200000,1554249600000,1554336000000,1554422400000,1554508800000],["y0",930,890,900,980,1120,1250,1220,1030,960,1390,1300,1200,1030,880,1820,1680,1190,1320,1790,1610,1210,1170,1300,1080,1320,1200,970,760,1230,1250,1040,1020,1300,1290,970,900,1050,1040,980,1070,1410,1080,1000,1100,1070,1010,940,1160,1110,990,1070,830,940,1070,1160,1040,1020,1120,1210,3030,2530,1660,1170,1240,1180,1000,1170,720,1010,1300,1020,1180,1080,960,1050,880,950,970,1360,1020,1280,1140,1150,1100,1100,1260,1280,1540,1360,1250,1060,1330,930,1060,940,1190,1320,1180,1050,1210,1370,1330,950,1270,1130,1300,1170,1530,1110,1380,1240,1390,1150,1230,1340,1160,1140,1380,1690,1460,1240,1610,1320,1360,1320,1460,1450,1330,1080,1720,1600,1250,1570,1530,1610,1860,1450,1560,1690,1560,1730,1600,2170,1540,1940,1430,1410,1840,1790,1850,1620,1520,2190,1870,1550,2080,1560,1720,2040,1810,1890,2000,1900,2270,2060,1890,1930,1590,2030,1890,1810,1620,1690,1310,1700,1530,1970,2080,1620,1510,1990,1720,1750,1870,1740,1620,1840,1980,1910,1790,2080,1820,1530,2140,2440,2130,2430,2180,2080,2190,2090,1910,2440,1940,2680,3310,2510,2200,3020,2550,2450,2800,2450,2780,3020,2680,2210,2550,3160,2870,2690,3140,2820,2850,2160,2540,3050,2720,2540,3000,2630,2660,2780,2350,2510,2980,2650,2770,2220,3000,2950,2450,2610,2270,2200,2200,2920,2600,2470,2180,2480,2400,2450,2970,2830,2740,2680,2750,2200,2720,2270,3100,3510,3400,2920,2240,2330,2660,3400,3240,2940,3300,3760,3270,3460,3340,2820,2300,2830,2690,2760,2570,2420,2730,2480,3000,3260,2920,2750,2660,3130,3480,2530,3140,2200,2970,2900,2510,2500,2660,2970,2810,3200,2640,2790,3360,2690,2750,2810,3090,3080,2490,2810,2570,2630,2370,3320,2610,2300,2670,2470,2680,3270,3580,3000,2670,2540,2740,2940,2800,3590,3000,3130,3030,2460,2400,2610,3240,4010,2880,2930,2890,3240,2600,3530,2850,3580,3480,3210,3150,2730,3240,2720,3210,3090,3310,2670,2750,2540,2600,2930,3400,3050,3480,2930],["y1",1060,990,1140,1090,1210,1160,1450,970,1400,1140,1230,1440,1660,1130,1390,1410,1110,1060,1100,1340,1140,1340,980,1390,1190,1350,1390,1230,1280,1250,1360,1470,1540,1170,1500,1330,1330,1190,1280,1370,1460,1160,1490,1300,1240,1370,1330,1360,1780,1470,1300,1390,1420,1450,1520,1270,1180,1270,1440,1470,1500,1440,1710,1460,1390,1510,1510,1730,1630,1440,1690,1480,1340,1550,1410,1470,1380,1550,1280,1550,1500,1350,1280,1270,1430,1330,1190,1380,1790,1610,1240,1520,1120,1250,1040,1370,1140,1650,1840,1320,1860,1490,1680,1920,1190,1410,1180,1510,1490,1950,1700,1060,1630,1410,1230,1340,1640,1620,1610,1780,1320,1430,1510,1410,1660,1610,1320,1420,1360,1330,1300,1370,1590,1380,1580,1250,1460,1740,2250,1820,1670,1590,1710,1630,1770,1410,2100,1640,1670,1560,1820,1580,1560,1680,1520,1660,1570,1790,1560,1850,1670,2050,1660,1690,2110,1900,2280,1680,1770,2250,1910,2190,2070,2160,1810,1890,2130,2470,2150,2320,2420,2510,2390,2340,2260,2250,2250,2560,2090,1620,2340,2410,2270,2470,2360,2520,2380,2690,2590,2600,3010,2970,2480,2680,2910,2960,3150,3290,2380,2860,3130,2680,2980,3030,2900,3570,3340,2970,2910,3130,3180,3370,3590,3380,3720,3670,3480,3470,3770,3400,3060,3080,3090,3380,3040,3080,3410,3620,3320,2890,3570,3260,3100,3450,3490,3070,2640,3360,3260,3030,3250,3690,2950,2910,3540,3140,3090,3350,2960,2930,2940,3280,3080,2750,3370,3740,2550,2340,3290,2800,2910,3160,3200,3640,2910,2930,2830,3230,3190,2930,3090,2530,2760,2990,2700,3130,3140,3020,2790,2820,3400,3360,3100,3470,2560,3030,3340,3240,3540,3310,3300,3040,2870,2960,3140,2960,3130,2910,3140,2380,3080,3100,2910,2700,3020,2590,2790,2880,3390,3190,3130,3320,2480,2850,3070,3030,2750,3190,3130,2960,3060,2810,2810,2980,3130,3150,2990,2310,2690,3070,3670,3530,2890,2510,2890,3090,2930,2850,3260,3720,2460,2610,3280,2860,3240,3420,2920,2280,2840,3030,3370,2650,3200,3190,2590]],"types":{"y0":"line","y1":"line","x":"x"},"names":{"y0":"Joined","y1":"Left"},"colors":{"y0":"#4BD964","y1":"#FE3C30"}} -------------------------------------------------------------------------------- /dist/data/2/overview.json: -------------------------------------------------------------------------------- 1 | {"columns":[["x",1523059200000,1523145600000,1523232000000,1523318400000,1523404800000,1523491200000,1523577600000,1523664000000,1523750400000,1523836800000,1523923200000,1524009600000,1524096000000,1524182400000,1524268800000,1524355200000,1524441600000,1524528000000,1524614400000,1524700800000,1524787200000,1524873600000,1524960000000,1525046400000,1525132800000,1525219200000,1525305600000,1525392000000,1525478400000,1525564800000,1525651200000,1525737600000,1525824000000,1525910400000,1525996800000,1526083200000,1526169600000,1526256000000,1526342400000,1526428800000,1526515200000,1526601600000,1526688000000,1526774400000,1526860800000,1526947200000,1527033600000,1527120000000,1527206400000,1527292800000,1527379200000,1527465600000,1527552000000,1527638400000,1527724800000,1527811200000,1527897600000,1527984000000,1528070400000,1528156800000,1528243200000,1528329600000,1528416000000,1528502400000,1528588800000,1528675200000,1528761600000,1528848000000,1528934400000,1529020800000,1529107200000,1529193600000,1529280000000,1529366400000,1529452800000,1529539200000,1529625600000,1529712000000,1529798400000,1529884800000,1529971200000,1530057600000,1530144000000,1530230400000,1530316800000,1530403200000,1530489600000,1530576000000,1530662400000,1530748800000,1530835200000,1530921600000,1531008000000,1531094400000,1531180800000,1531267200000,1531353600000,1531440000000,1531526400000,1531612800000,1531699200000,1531785600000,1531872000000,1531958400000,1532044800000,1532131200000,1532217600000,1532304000000,1532390400000,1532476800000,1532563200000,1532649600000,1532736000000,1532822400000,1532908800000,1532995200000,1533081600000,1533168000000,1533254400000,1533340800000,1533427200000,1533513600000,1533600000000,1533686400000,1533772800000,1533859200000,1533945600000,1534032000000,1534118400000,1534204800000,1534291200000,1534377600000,1534464000000,1534550400000,1534636800000,1534723200000,1534809600000,1534896000000,1534982400000,1535068800000,1535155200000,1535241600000,1535328000000,1535414400000,1535500800000,1535587200000,1535673600000,1535760000000,1535846400000,1535932800000,1536019200000,1536105600000,1536192000000,1536278400000,1536364800000,1536451200000,1536537600000,1536624000000,1536710400000,1536796800000,1536883200000,1536969600000,1537056000000,1537142400000,1537228800000,1537315200000,1537401600000,1537488000000,1537574400000,1537660800000,1537747200000,1537833600000,1537920000000,1538006400000,1538092800000,1538179200000,1538265600000,1538352000000,1538438400000,1538524800000,1538611200000,1538697600000,1538784000000,1538870400000,1538956800000,1539043200000,1539129600000,1539216000000,1539302400000,1539388800000,1539475200000,1539561600000,1539648000000,1539734400000,1539820800000,1539907200000,1539993600000,1540080000000,1540166400000,1540252800000,1540339200000,1540425600000,1540512000000,1540598400000,1540684800000,1540771200000,1540857600000,1540944000000,1541030400000,1541116800000,1541203200000,1541289600000,1541376000000,1541462400000,1541548800000,1541635200000,1541721600000,1541808000000,1541894400000,1541980800000,1542067200000,1542153600000,1542240000000,1542326400000,1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000,1552089600000,1552176000000,1552262400000,1552348800000,1552435200000,1552521600000,1552608000000,1552694400000,1552780800000,1552867200000,1552953600000,1553040000000,1553126400000,1553212800000,1553299200000,1553385600000,1553472000000,1553558400000,1553644800000,1553731200000,1553817600000,1553904000000,1553990400000,1554076800000,1554163200000,1554249600000,1554336000000,1554422400000,1554508800000],["y0",272400,311800,339600,335800,335800,328800,317600,299600,337200,366400,350200,349800,354400,348400,324200,329000,356200,356200,329000,352400,343800,308400,261400,364400,333600,380000,353600,345400,320200,355000,354400,365000,349200,353000,339200,320200,335800,381400,357000,355200,354800,332800,320600,329400,365800,363400,365000,361600,345200,300800,344200,370800,360200,362600,349400,357800,294800,349000,372200,368200,365600,365600,357000,320200,329800,383600,383600,382200,363000,361200,329200,351000,381400,364200,394600,372200,363000,335400,361800,379600,389000,382000,389000,370400,326000,363200,406400,392200,368400,398200,367200,326200,335600,386800,386000,378600,378800,387400,341600,349000,404600,379800,388600,393600,385200,345400,371600,419600,399800,422000,410800,410200,381200,380400,442600,457800,453000,459200,457200,411000,428600,465800,451000,459800,484600,461200,427000,421800,481800,466600,402400,477800,466600,467200,457200,517000,493000,482600,504400,505600,478800,491400,518800,520800,508800,522800,531400,492400,508400,557800,564200,528000,555200,537600,480400,520600,551000,566000,531000,531200,519400,499000,495000,553800,578000,553200,554800,532400,501800,540600,567600,567600,563000,542400,566600,486800,538400,621200,580800,574200,597200,584000,522200,589600,622800,623800,627800,595200,576000,366000,592200,655600,660000,640000,639600,638400,590800,675600,746600,708400,710400,722400,708600,632200,764400,840200,810200,667000,766800,766000,740400,850800,858400,857400,851800,851800,821000,757600,851400,883000,883600,879800,852800,804800,730600,805800,864000,844800,834800,838800,809200,722800,843800,894000,820400,819000,810000,793400,737600,818000,866800,830600,845000,819200,760000,728400,793200,830000,837600,811400,823400,752800,696400,770600,844800,823000,793400,812000,769400,723200,755600,764600,811200,826200,866800,833000,755000,770600,649800,740400,836800,833600,859000,796000,834800,858400,809000,853000,801400,763600,713600,799200,819200,818000,781800,809200,736600,689800,802400,828600,794200,813000,788400,755200,689200,777800,811200,766000,809400,776800,759000,684800,807400,830800,802800,786000,751800,745000,666400,773200,795200,743600,739200,714000,727600,654000,717000,751600,739600,757600,730600,705200,674400,730800,767000,751600,776600,712000,688000,637800,686000,748600,750200,765400,742400,701000,636800,720400,779000,765200,851200,793000,731400,651200,734800,825400,790800,763400,724200,723600,625800,714600,803600,742600,738000,745800,706600,613600,712000,767400,750800,821200,813400,757800,683800],["y1",12360,16240,14210,14040,15190,13570,14020,15600,16080,15800,16740,15680,16790,15520,17410,17660,17000,15080,17190,17020,16620,15200,13210,16970,16030,16090,16800,15280,15450,15990,17130,14970,16020,15780,15770,15720,16210,15820,16080,14860,14210,14980,16200,15430,15510,16750,16460,15130,15120,15580,18040,16380,15940,16590,15950,15480,14940,16520,16570,15910,15950,16280,17120,15720,16600,17580,16260,17270,15660,16500,16410,17140,16240,17330,16320,17490,17220,17030,19130,17440,17350,17010,19050,16150,16350,18280,17670,19690,17470,16320,16180,16290,15440,16600,17430,17800,18110,16870,17200,16700,18010,18110,17850,17600,17870,18100,17300,19960,18340,19650,19710,21300,18930,20090,20240,21150,21020,21940,22350,22160,20800,22390,21450,22970,20690,23410,21490,21690,20650,22440,21630,23420,22860,23490,24460,23610,23810,22840,23540,24800,23460,24140,25050,23910,23790,23190,23390,23160,23830,23680,25940,23420,23330,23630,23400,26230,22690,24700,22010,23050,22460,24620,24960,26180,24540,24240,24690,24140,25140,29410,25900,25880,24600,25380,25090,24930,28930,26570,25270,26560,25520,27150,25130,25600,28580,25800,25500,27870,26320,18930,30390,27640,27790,28380,29230,28160,28490,31290,31710,32150,29840,29860,30240,30750,33300,34750,33250,31920,36940,36930,33360,38500,33700,34630,36580,36130,34960,35210,37600,37100,34640,36840,36150,33850,32800,35440,37510,36770,35560,35460,36650,35370,36990,39810,39340,36350,35350,33160,34440,36720,35200,37240,36030,36330,34940,34840,39350,37370,34040,33510,35270,32940,33310,34730,35760,37300,35190,33420,32550,33450,34360,41660,42960,38970,37080,37150,36460,41330,34220,34980,34840,39150,38110,35380,38760,36080,33790,36150,35960,32570,33180,36000,36390,33950,35390,36680,36540,31270,34720,35030,37090,38120,32870,34800,35000,34370,35070,35430,36830,37380,35390,33170,37300,34710,36450,37500,37820,31590,34370,37430,36650,35300,35520,35830,35650,32070,38700,34460,34450,32720,34900,35680,33340,37500,35730,35270,37150,35010,35260,33690,40330,36410,35540,35600,35480,37740,35600,44060,34610,37160,37880,36800,37940,35140,36900,40490,37740,36330,37730,35330,35800,39580,37590,35770,36430,36720,36860,33580,36830,35830,36600,37840,39450,35390,35310]],"types":{"y0":"line","y1":"line","x":"x"},"names":{"y0":"Views","y1":"Shares"},"colors":{"y0":"#108BE3","y1":"#E8AF14"},"y_scaled":true} -------------------------------------------------------------------------------- /src/Telecanvas.ts: -------------------------------------------------------------------------------- 1 | type Coordinate = [number, number] 2 | type MouseMoveListener = (x: number, y: number) => void 3 | 4 | export class Telecanvas { 5 | private widthProperty!: number 6 | private mouseMoveListeners: MouseMoveListener[] = [] 7 | private mouseDownListeners: Array<(x: number, y: number) => void> = [] 8 | private mouseUpListeners: Array<() => void> = [] 9 | private resizeListeners: Array<() => void> = [] 10 | private canvas: HTMLCanvasElement 11 | private context: CanvasRenderingContext2D 12 | private cachedDpr?: number 13 | 14 | constructor(parentElement: HTMLElement|null, public height: number, width?: number) { 15 | this.canvas = document.createElement('canvas') 16 | if (parentElement) { 17 | parentElement.appendChild(this.canvas) 18 | this.canvas.style.display = 'block' 19 | } else { 20 | document.body.appendChild(this.canvas) 21 | this.canvas.style.display = 'none' 22 | } 23 | this.context = this.canvas.getContext('2d')! 24 | if (!width) { 25 | window.addEventListener('resize', () => { 26 | if (this.width !== (width ? width : parentElement!.clientWidth)) { 27 | this.canvas.height = height * this.dpr 28 | this.canvas.style.height = `${height}px` 29 | this.width = width ? width : parentElement!.clientWidth 30 | this.resizeListeners.forEach(l => l()) 31 | } 32 | }) 33 | window.dispatchEvent(new Event('resize')) 34 | } else { 35 | this.width = width 36 | } 37 | 38 | const mousemove = (x: number, y: number) => { 39 | const rect = this.canvas.getBoundingClientRect() 40 | this.mouseMoveListeners.forEach(callback => callback(x - rect.left, y - rect.top)) 41 | } 42 | const mousedown = (x: number, y: number) => { 43 | const rect = this.canvas.getBoundingClientRect() 44 | this.mouseDownListeners.forEach(callback => callback(x - rect.left, y - rect.top)) 45 | } 46 | window.addEventListener('mousemove', (e) => mousemove(e.clientX, e.clientY)) 47 | window.addEventListener('touchmove', (e) => mousemove(e.touches[0].clientX, e.touches[0].clientY)) 48 | this.canvas.addEventListener('mousedown', (e) => mousedown(e.clientX, e.clientY)) 49 | this.canvas.addEventListener('touchstart', (e) => mousedown(e.touches[0].clientX, e.touches[0].clientY)) 50 | window.addEventListener('mouseup', () => this.mouseUpListeners.forEach(callback => callback())) 51 | window.addEventListener('touchend', () => this.mouseUpListeners.forEach(callback => callback())) 52 | } 53 | 54 | get width() { 55 | return this.widthProperty 56 | } 57 | 58 | set width(value: number) { 59 | this.cachedDpr = undefined 60 | this.widthProperty = value 61 | this.canvas.width = value * this.dpr 62 | this.canvas.style.width = `100%` 63 | this.context.scale(this.dpr, this.dpr) 64 | } 65 | 66 | get dpr() { 67 | return this.cachedDpr ? this.cachedDpr : window.devicePixelRatio || 1 68 | } 69 | 70 | set cursor(value: string) { 71 | this.canvas.style.cursor = value 72 | } 73 | 74 | public save() { 75 | this.context.save() 76 | } 77 | 78 | public setRoundedClippingRect(left: number, top: number, width: number, height: number, radius: number) { 79 | const c = this.context 80 | c.beginPath() 81 | c.moveTo(left + radius, top) 82 | c.lineTo(left + width - radius, top) 83 | c.quadraticCurveTo(left + width, top, left + width, top + radius) 84 | c.lineTo(left + width, top + height - radius) 85 | c.quadraticCurveTo(left + width, top + height, left + width - radius, top + height) 86 | c.lineTo(left + radius, top + height) 87 | c.quadraticCurveTo(left, top + height, left, top + height - radius) 88 | c.lineTo(left, top + radius) 89 | c.quadraticCurveTo(left, top, left + radius, top) 90 | c.closePath() 91 | c.clip() 92 | } 93 | 94 | public setClippingRect(left: number, top: number, width: number, height: number) { 95 | const c = this.context 96 | c.beginPath() 97 | c.rect(left, top, width, height) 98 | c.closePath() 99 | c.clip() 100 | } 101 | 102 | public restore() { 103 | this.context.restore() 104 | } 105 | 106 | public line(from: Coordinate, to: Coordinate, color: string, width = 1) { 107 | const c = this.context 108 | c.lineCap = 'butt' 109 | c.strokeStyle = color 110 | c.lineWidth = width 111 | c.beginPath() 112 | c.moveTo(from[0] + .5, from[1] + .5) 113 | c.lineTo(to[0] + .5, to[1] + .5) 114 | c.stroke() 115 | } 116 | 117 | public path(path: Array<[number, number]>, color: string, width = 1) { 118 | const c = this.context 119 | c.lineJoin = 'miter' 120 | c.miterLimit = 2 121 | c.strokeStyle = color 122 | c.lineWidth = width 123 | c.beginPath() 124 | c.moveTo(path[0][0], path[0][1]) 125 | for (let n = 1; n < path.length; n++) { 126 | c.lineTo(path[n][0], path[n][1]) 127 | } 128 | c.stroke() 129 | } 130 | 131 | public circle(point: [number, number], radius: number, stroke: string|null, fill: string|null, borderWidth: number = 1) { 132 | const c = this.context 133 | c.beginPath() 134 | c.arc(point[0], point[1], radius, 0, 2 * Math.PI) 135 | if (fill) { 136 | c.fillStyle = fill 137 | c.fill() 138 | } 139 | if (stroke) { 140 | c.strokeStyle = stroke 141 | c.lineWidth = borderWidth 142 | c.stroke() 143 | } 144 | } 145 | 146 | public text(text: string, to: Coordinate, color: string, fontFamily = 'sans-serif', size = 14, align: 'left'|'right'|'center'|'start'|'end' = 'left') { 147 | const c = this.context 148 | c.fillStyle = color 149 | c.font = `${size}px "${fontFamily}"` 150 | c.textAlign = align 151 | c.fillText(text, to[0], to[1]) 152 | } 153 | 154 | public shape(path: Array<[number, number]>, color: string) { 155 | const c = this.context 156 | c.fillStyle = color 157 | c.beginPath() 158 | c.moveTo(path[0][0], path[0][1]) 159 | for (let n = 1; n < path.length; n++) { 160 | c.lineTo(path[n][0], path[n][1]) 161 | } 162 | c.closePath() 163 | c.fill() 164 | } 165 | 166 | public rect(left: number, top: number, width: number, height: number, fill?: string, stroke?: string, borderWidth?: number) { 167 | const c = this.context 168 | c.beginPath() 169 | if (fill) { 170 | c.fillStyle = fill 171 | c.fillRect(left, top, width, height) 172 | } 173 | if (stroke) { 174 | c.strokeStyle = stroke 175 | c.lineWidth = borderWidth! 176 | c.strokeRect(left, top, width, height) 177 | } 178 | } 179 | 180 | public roundedRect(left: number, top: number, width: number, height: number, radius: number, fill?: string, stroke?: string, borderWidth?: number) { 181 | const c = this.context 182 | c.beginPath() 183 | c.moveTo(left + radius, top) 184 | c.lineTo(left + width - radius, top) 185 | c.quadraticCurveTo(left + width, top, left + width, top + radius) 186 | c.lineTo(left + width, top + height - radius) 187 | c.quadraticCurveTo(left + width, top + height, left + width - radius, top + height) 188 | c.lineTo(left + radius, top + height) 189 | c.quadraticCurveTo(left, top + height, left, top + height - radius) 190 | c.lineTo(left, top + radius) 191 | c.quadraticCurveTo(left, top, left + radius, top) 192 | c.closePath() 193 | if (fill) { 194 | c.fillStyle = fill 195 | c.fill() 196 | } 197 | if (stroke) { 198 | c.strokeStyle = stroke 199 | c.lineWidth = borderWidth! 200 | c.stroke() 201 | } 202 | } 203 | 204 | public drawTelecanvas(telecanvas: Telecanvas, destX: number, destY: number) { 205 | this.context.resetTransform() 206 | this.context.drawImage(telecanvas.canvas, destX * this.dpr, destY * this.dpr) 207 | if (this.dpr > 1) { 208 | this.context.scale(this.dpr, this.dpr) 209 | } 210 | } 211 | 212 | public getOpacityValue(color: string) { 213 | return color.length === 9 ? parseInt(color.substr(7, 2), 16) / 255 : 1 214 | } 215 | 216 | public getColorString(baseColor: string, opacity: number) { 217 | const opacityPart = Math.round(this.getOpacityValue(baseColor) * opacity * 255).toString(16) 218 | return baseColor.substr(0, 7) + (opacityPart.length === 1 ? '0' + opacityPart : opacityPart) 219 | } 220 | 221 | public clear() { 222 | this.context.clearRect(0, 0, this.width, this.height) 223 | } 224 | 225 | public addMouseMoveListener(callback: (x: number, y: number) => void) { 226 | this.mouseMoveListeners.push(callback) 227 | } 228 | 229 | public addMouseDownListener(callback: (x: number, y: number) => void) { 230 | this.mouseDownListeners.push(callback) 231 | } 232 | 233 | public addMouseUpListener(callback: () => void) { 234 | this.mouseUpListeners.push(callback) 235 | } 236 | 237 | public addResizeListener(callback: () => void) { 238 | this.resizeListeners.push(callback) 239 | } 240 | 241 | } 242 | -------------------------------------------------------------------------------- /src/Telemap/AbstractTelemap.ts: -------------------------------------------------------------------------------- 1 | import { Telechart } from '../Telechart' 2 | import { AbstractChartDrawer } from '../Drawer/AbstractChartDrawer' 3 | import { Telecolumn } from '../Telecolumn' 4 | import { Telecanvas } from '../Telecanvas' 5 | import { Telemation } from '../Telemation' 6 | 7 | export abstract class AbstractTelemap { 8 | protected config!: { rangeBackground: string, rangeFill: string, shadow: string } 9 | protected rangeProperty: { from: Telemation, to: Telemation }|null = null 10 | protected topPadding = 0 11 | protected bottomPadding = 0 12 | protected cacheTeelcanvas: Telecanvas 13 | protected telecanvasCached = false 14 | protected columns: Telecolumn[] = [] 15 | protected drawers: AbstractChartDrawer[] = [] 16 | private themeProperty: 'light'|'dark' = 'light' 17 | 18 | constructor(protected readonly telechart: Telechart, public height = 44) { 19 | this.theme = telechart.theme 20 | this.topPadding = this.telecanvas.height - height 21 | this.initHTML() 22 | this.cacheTeelcanvas = new Telecanvas(null, this.height - 2, this.telecanvas.width) 23 | this.telecanvas.addResizeListener(() => { 24 | this.cacheTeelcanvas.width = this.telecanvas.width 25 | this.telecanvasCached = false 26 | }) 27 | } 28 | 29 | get telecanvas() { 30 | return this.telechart.telecanvas 31 | } 32 | 33 | get firstDrawer() { 34 | return this.drawers.length ? this.drawers[0] : undefined 35 | } 36 | 37 | public addColumn(column: Telecolumn) { 38 | this.columns.push(column) 39 | } 40 | 41 | public removeColumn(column: Telecolumn) { 42 | this.columns.splice(this.columns.indexOf(column), 1) 43 | this.drawers.forEach(d => d.removeColumn(column)) 44 | } 45 | 46 | get theme() { 47 | return this.themeProperty 48 | } 49 | 50 | set theme(value) { 51 | this.themeProperty = value 52 | if (value === 'dark') { 53 | this.config = { 54 | ...this.config, 55 | rangeBackground: '#56626D', 56 | rangeFill: '#242f3e', 57 | shadow: '#30425999', 58 | } 59 | } else { 60 | this.config = { 61 | ...this.config, 62 | rangeBackground: '#C0D1E1', 63 | rangeFill: '#fff', 64 | shadow: '#E2EEF999', 65 | } 66 | } 67 | } 68 | 69 | set range(value: { from: number, to: number }|null) { 70 | const current = this.range 71 | this.rangeProperty = { 72 | from: Telemation.create(current ? current.from : 0, value!.from, current ? 50 : 0), 73 | to: Telemation.create(current ? current.to : 0, value!.to, current ? 50 : 0), 74 | } 75 | if (!this.firstDrawer) { 76 | return 77 | } 78 | this.columns.forEach((c, index) => { 79 | const from = this.firstDrawer!.borders.minX.to + (this.firstDrawer!.borders.maxX.to - this.firstDrawer!.borders.minX.to) * value!.from 80 | const to = this.firstDrawer!.borders.minX.to + (this.firstDrawer!.borders.maxX.to - this.firstDrawer!.borders.minX.to) * value!.to 81 | if (!index) { 82 | this.telechart.setRangeText(this.telechart.getDateString(from) + ' - ' + this.telechart.getDateString(to)) 83 | } 84 | c.setCurrentRange(from, to) 85 | }) 86 | this.telechart.teledisplay.recalcBorders(current ? 200 : 0) 87 | } 88 | 89 | get range(): { from: number, to: number }|null { 90 | return this.rangeProperty ? { from: this.rangeProperty!.from.value, to: this.rangeProperty!.to.value } : null 91 | } 92 | 93 | public draw() { 94 | const c = this.telecanvas 95 | const left = this.range!.from * this.telecanvas.width 96 | const width = (this.range!.to - this.range!.from) * this.telecanvas.width 97 | 98 | if (this.columns.reduce((r, col) => !col.opacity.finished || r, false) || !this.firstDrawer!.borders.maxY.finished) { 99 | this.telecanvasCached = false 100 | } 101 | if (!this.telecanvasCached) { 102 | this.cacheTeelcanvas.clear() 103 | this.drawColumns() 104 | this.cacheTeelcanvas.drawTelecanvas(this.telecanvas, 0, -this.topPadding - 1) 105 | this.telecanvasCached = true 106 | c.clear() 107 | } 108 | c.save() 109 | c.setRoundedClippingRect(0, this.topPadding + 1, c.width, this.height - 2, 6) 110 | c.drawTelecanvas(this.cacheTeelcanvas, 0, this.topPadding + 1) 111 | 112 | c.rect(0, this.topPadding + 1, left + 6, this.height - 2, this.config.shadow) // Shadow to left 113 | c.rect(left + width - 6, this.topPadding + 1, this.telecanvas.width - left - width + 6, this.height - 2, this.config.shadow) // Shadow to right 114 | 115 | c.restore() 116 | 117 | c.roundedRect(left, this.topPadding, 10, this.height, 6, this.config.rangeBackground) // Left gripper corners 118 | c.rect(left + 5, this.topPadding, 5, this.height, this.config.rangeBackground) // Left gripper rect 119 | c.roundedRect(left + 4, this.topPadding + 15, 2, 12, 2, this.config.rangeFill) // Left gripper strip 120 | 121 | c.roundedRect(left + width - 10, this.topPadding, 10, this.height, 6, this.config.rangeBackground) // Right gripper corners 122 | c.rect(left + width - 10, this.topPadding, 5, this.height, this.config.rangeBackground) // Right gripper rect 123 | c.roundedRect(left + width - 6, this.topPadding + 15, 2, 12, 2, this.config.rangeFill) // Right gripper strip 124 | 125 | c.line([left + 10 - 1, this.topPadding], [left + width - 10 + 1, this.topPadding], this.config.rangeBackground) 126 | c.line([left + 10 - 1, this.topPadding + this.height - 1], [left + width - 10 + 1, this.topPadding + this.height - 1], this.config.rangeBackground) 127 | 128 | if (!this.rangeProperty!.to.finished) { 129 | this.telechart.redraw() 130 | } 131 | } 132 | 133 | public recalcBorders(duration: number = 0) { 134 | this.drawers.forEach(d => d.recalcBorders(duration)) 135 | this.telechart.redraw() 136 | } 137 | 138 | protected abstract drawColumns(): void 139 | 140 | protected initHTML() { 141 | let currentPos = { left: 0, top: 0 } 142 | let startRange: { from: number, to: number }|null = null 143 | let startPos: { left: number, top: number }|null = null 144 | let moveType: 'all'|'from'|'to'|null = null 145 | let yInArea = false 146 | const mousemove = (x: number, y: number) => { 147 | currentPos = { left: x, top: y } 148 | yInArea = y >= this.topPadding && y < this.topPadding + this.height 149 | 150 | if (!startPos || !startRange) { 151 | if (yInArea) { 152 | const left = this.range!.from * this.telecanvas.width 153 | const width = (this.range!.to - this.range!.from) * this.telecanvas.width 154 | if (x >= left - 5 && x <= left + 20) { 155 | moveType = 'from' 156 | this.telecanvas.cursor = 'ew-resize' 157 | } else if (x >= left + width - 15 && x < left + width + 5) { 158 | moveType = 'to' 159 | this.telecanvas.cursor = 'ew-resize' 160 | } else if (x >= left && x < left + width) { 161 | moveType = 'all' 162 | this.telecanvas.cursor = 'move' 163 | } else { 164 | moveType = null 165 | this.telecanvas.cursor = 'default' 166 | } 167 | } else { 168 | this.telecanvas.cursor = 'default' 169 | } 170 | return 171 | } 172 | this.columns.forEach(c => c.setCurrentX(null)) 173 | const diff = (currentPos.left - startPos!.left) / this.telecanvas.width 174 | let newRangeFrom = startRange!.from 175 | let newRangeTo = startRange!.to 176 | if (moveType === 'all' || moveType === 'from') { 177 | newRangeFrom += diff 178 | } 179 | if (moveType === 'all' || moveType === 'to') { 180 | newRangeTo += diff 181 | } 182 | if (newRangeFrom < 0) { 183 | if (moveType === 'all' || moveType === 'to') { 184 | newRangeTo = newRangeTo - newRangeFrom 185 | } 186 | newRangeFrom = 0 187 | } 188 | if (newRangeTo > 1) { 189 | if (moveType === 'all' || moveType === 'from') { 190 | newRangeFrom = newRangeFrom - (newRangeTo - 1) 191 | } 192 | newRangeTo = 1 193 | } 194 | if (newRangeTo - newRangeFrom < 0.1) { 195 | if (moveType === 'to') { 196 | newRangeTo = newRangeFrom + 0.1 197 | } else { 198 | newRangeFrom = newRangeTo - 0.1 199 | } 200 | } 201 | this.range = { from: newRangeFrom, to: newRangeTo } 202 | } 203 | const mousedown = (x: number, y: number) => { 204 | if (moveType) { 205 | startPos = { ...currentPos } 206 | startRange = { ...this.range! } 207 | } 208 | } 209 | const mouseup = () => { 210 | moveType = null 211 | startPos = null 212 | startRange = null 213 | } 214 | this.telecanvas.addMouseMoveListener(mousemove) 215 | this.telecanvas.addMouseDownListener((x, y) => { 216 | mousemove(x, y) 217 | mousedown(x, y) 218 | }) 219 | this.telecanvas.addMouseUpListener(mouseup) 220 | } 221 | 222 | } 223 | -------------------------------------------------------------------------------- /src/Telechart.ts: -------------------------------------------------------------------------------- 1 | import { Telecolumn, ITelechartColumnData } from './Telecolumn' 2 | import { Telecanvas } from './Telecanvas' 3 | import { AbstractTeledisplay } from './Display/AbstractTeledisplay' 4 | import { Teletip } from './Teletip' 5 | import { AbstractTelemap } from './Telemap/AbstractTelemap' 6 | import { Telegend } from './Telegend' 7 | import { LineTeledisplay } from './Display/LineTeledisplay' 8 | import { TwoAxisTeledisplay } from './Display/TwoAxisTeledisplay' 9 | import { LineTelemap } from './Telemap/LineTelemap' 10 | import { TwoAxisTelemap } from './Telemap/TwoAxisTelemap' 11 | import { StackedTeledisplay } from './Display/StackedTeledisplay' 12 | import { StackedTelemap } from './Telemap/StackedTelemap' 13 | import { StackedPercentTeledisplay } from './Display/StackedPercentTeledisplay' 14 | import { StackedPercentTelemap } from './Telemap/StackedPercentTelemap' 15 | 16 | interface ITelechartData { 17 | columns: Array> 18 | types: { [key: string]: 'line'|'bar'|'x' } 19 | names: { [key: string]: string } 20 | colors: { [key: string]: string } 21 | y_scaled?: boolean 22 | stacked?: boolean 23 | percentage?: boolean 24 | } 25 | interface ITelechartOptions { 26 | data: ITelechartData 27 | height?: number 28 | title?: string 29 | showFps?: boolean 30 | allRange?: boolean 31 | } 32 | 33 | export class Telechart { 34 | public static init(el: HTMLElement|string, options: ITelechartOptions) { 35 | let element: HTMLElement|null 36 | if (typeof el === 'string' || el instanceof String) { 37 | element = document.getElementById(el as string) 38 | if (!element) { 39 | throw new Error(`Element #${el} not found`) 40 | } 41 | } else if (el instanceof HTMLElement) { 42 | element = el 43 | } 44 | 45 | return new Telechart(element!, options) 46 | } 47 | 48 | public telecanvas!: Telecanvas 49 | public teledisplay!: AbstractTeledisplay 50 | public teletip!: Teletip 51 | public telemap!: AbstractTelemap 52 | public telegend!: Telegend 53 | protected config!: { 54 | data: ITelechartData, 55 | height: number, 56 | title: string, 57 | showFps: boolean, 58 | allRange: boolean, 59 | } 60 | protected loaded = false 61 | protected columns: Telecolumn[] = [] 62 | protected canvas!: HTMLCanvasElement 63 | protected needRedraw = false 64 | protected headingElement!: HTMLDivElement 65 | protected rangeElement?: HTMLDivElement 66 | private themeProperty: 'light'|'dark' = 'light' 67 | 68 | constructor(protected readonly element: HTMLElement, options: ITelechartOptions) { 69 | if (!element) { 70 | throw new Error('HTML element for Telechart is not found') 71 | } 72 | if (!(element instanceof HTMLElement)) { 73 | throw new Error('First argument of Telechart constructor must be an HTMLElement') 74 | } 75 | this.config = { 76 | data: options.data, 77 | height: options.height ? options.height : 360, 78 | title: options.title ? options.title : 'Untitled chart', 79 | showFps: options.showFps ? true : false, 80 | allRange: options.allRange ? true : false, 81 | } 82 | this.initHTML() 83 | this.updateData(options.data ? options.data : { columns: [], types: {}, names: {}, colors: {}, y_scaled: false }) 84 | this.redraw() 85 | } 86 | 87 | get data() { 88 | return this.config.data 89 | } 90 | 91 | set data(value) { 92 | this.config.data = value 93 | this.updateData(value) 94 | } 95 | 96 | get theme() { 97 | return this.themeProperty 98 | } 99 | 100 | set theme(value) { 101 | this.themeProperty = value 102 | this.teletip.theme = value 103 | this.teledisplay.theme = value 104 | this.telemap.theme = value 105 | this.telegend.theme = value 106 | this.columns.forEach(c => c.theme = value) 107 | this.redraw() 108 | } 109 | 110 | public setRangeText(value: string) { 111 | if (!this.rangeElement) { 112 | this.rangeElement = this.headingElement.appendChild(document.createElement('div')) 113 | this.rangeElement.classList.add('telechart-heading-range') 114 | } 115 | this.rangeElement.innerText = value 116 | } 117 | 118 | public addColumn(data: ITelechartColumnData) { 119 | const column = new Telecolumn(this, data) 120 | this.columns.push(column) 121 | this.teledisplay.addColumn(column) 122 | this.telemap.addColumn(column) 123 | this.telegend.addColumn(column) 124 | } 125 | 126 | public removeColumn(id: string|number) { 127 | for (let n = this.columns.length - 1; n >= 0; n--) { 128 | const c = this.columns[n] 129 | if (c.id === id) { 130 | this.removeTelecolumn(c) 131 | return 132 | } 133 | } 134 | } 135 | 136 | public removeTelecolumn(column: Telecolumn) { 137 | if (this.teledisplay) { 138 | this.teledisplay.removeColumn(column) 139 | } 140 | if (this.telemap) { 141 | this.telemap.removeColumn(column) 142 | } 143 | this.telegend.removeColumn(column) 144 | this.columns.splice(this.columns.indexOf(column), 1) 145 | this.redraw() 146 | } 147 | 148 | public removeColumns() { 149 | for (let n = this.columns.length - 1; n >= 0; n--) { 150 | this.removeTelecolumn(this.columns[n]) 151 | } 152 | } 153 | 154 | public redraw() { 155 | this.needRedraw = true 156 | } 157 | 158 | public updateData(data: ITelechartData) { 159 | let x: number[] 160 | let hasBar = false 161 | this.removeColumns() 162 | 163 | for (const key in data.types) { 164 | if (data.types[key] === 'bar') { 165 | hasBar = true 166 | break 167 | } 168 | } 169 | 170 | if (data.stacked || hasBar) { 171 | if (data.percentage) { 172 | this.telemap = new StackedPercentTelemap(this) 173 | this.teledisplay = new StackedPercentTeledisplay(this) 174 | } else { 175 | this.telemap = new StackedTelemap(this) 176 | this.teledisplay = new StackedTeledisplay(this) 177 | } 178 | } else if (data.y_scaled) { 179 | this.telemap = new TwoAxisTelemap(this) 180 | this.teledisplay = new TwoAxisTeledisplay(this) 181 | } else { 182 | this.telemap = new LineTelemap(this) 183 | this.teledisplay = new LineTeledisplay(this) 184 | } 185 | for (const col of data.columns) { 186 | const id = col[0] as string 187 | const row: number[] = [] 188 | for (let n = 1; n < col.length; n++) { 189 | row.push(col[n] as number) 190 | } 191 | if (data.types[id] === 'x') { 192 | x = row 193 | continue 194 | } 195 | const values = row.reduce((result, val, i) => { 196 | if (x[i] === undefined) { 197 | throw new Error('Incorrect input data') 198 | } 199 | result.push({ x: x[i], y: val }) 200 | 201 | return result 202 | }, [] as Array<{ x: number, y: number}>) 203 | this.addColumn({ id, name: data.names[id], color: data.colors[id], values }) 204 | } 205 | this.telemap.range = this.config.allRange ? { from: 0, to: 1 } : { from: .8, to: 1 } 206 | this.loaded = true 207 | window.dispatchEvent(new Event('resize')) 208 | } 209 | 210 | public getDateString(timestamp: number, format: string = 'j F Y') { 211 | const date = new Date(timestamp) 212 | let result = '' 213 | for (const c of format.split('')) { 214 | let a = c 215 | if (c === 'j') { 216 | a = date.getDate().toString() 217 | } else if (c === 'F') { 218 | a = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][date.getMonth()] 219 | } else if (c === 'Y') { 220 | a = date.getFullYear().toString() 221 | } else if (c === 'M') { 222 | a = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][date.getMonth()] 223 | } else if (c === 'D') { 224 | a = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getDay()] 225 | } 226 | result += a 227 | } 228 | return result 229 | } 230 | 231 | public formatNumber(value: number): string { 232 | let result = '' 233 | value.toString(10).split('').reverse().forEach((n, i) => { 234 | if (i % 3 === 0) { 235 | result = ' ' + result 236 | } 237 | result = n + result 238 | }) 239 | return result 240 | } 241 | 242 | protected initHTML() { 243 | this.element.classList.add('telechart') 244 | const heading = this.headingElement = this.element.appendChild(document.createElement('div')) 245 | heading.classList.add('telechart-heading') 246 | const title = heading.appendChild(document.createElement('div')) 247 | title.classList.add('telechart-heading-title') 248 | title.innerText = this.config.title 249 | 250 | this.telecanvas = new Telecanvas(this.element, this.config.height!) 251 | this.teletip = new Teletip(this, this.element) 252 | this.telegend = new Telegend(this, this.element) 253 | 254 | this.telecanvas.addResizeListener(() => this.redraw()) 255 | 256 | let frames = 0 257 | let start = Date.now() 258 | let fps = 60 259 | const draw = () => { 260 | const needRedraw = this.needRedraw 261 | if (this.needRedraw) { 262 | this.draw() 263 | } 264 | frames++ 265 | if (frames % 30 === 0) { 266 | fps = 1 / ((Date.now() - start) / 1000 / 30) 267 | start = Date.now() 268 | } 269 | if (this.config.showFps && (needRedraw || frames % 10 === 0)) { 270 | this.telecanvas.rect(2, 2, 30, 10, '#fff') 271 | this.telecanvas.text('fps ' + fps.toFixed(0), [3, 10], '#000', 'sans', 9) 272 | } 273 | window.requestAnimationFrame(draw) 274 | } 275 | window.requestAnimationFrame(draw) 276 | } 277 | 278 | protected draw() { 279 | if (!this.loaded) { 280 | return 281 | } 282 | this.needRedraw = false 283 | this.telecanvas.clear() 284 | this.telemap.draw() 285 | this.teledisplay.draw() 286 | this.teletip.draw() 287 | this.telegend.draw() 288 | } 289 | 290 | } 291 | -------------------------------------------------------------------------------- /src/Drawer/AbstractChartDrawer.ts: -------------------------------------------------------------------------------- 1 | import { Telechart } from '../Telechart' 2 | import { Telecolumn } from '../Telecolumn' 3 | import { Telemation } from '../Telemation' 4 | 5 | export interface IBorders { 6 | maxX: Telemation, 7 | maxY: Telemation, 8 | minX: Telemation, 9 | minY: Telemation, 10 | } 11 | 12 | export interface IAbstractChartDrawerOptions { 13 | isRangeDisplay?: boolean 14 | isZeroStart?: boolean 15 | noGuides?: boolean 16 | noMilestones?: boolean 17 | topPadding?: number 18 | bottomPadding?: number 19 | } 20 | 21 | export abstract class AbstractChartDrawer { 22 | public isRangeDisplay = false 23 | public isZeroStart = false 24 | public topPadding: number = 0 25 | public bottomPadding: number = 0 26 | public borders!: IBorders 27 | public noGuides: boolean 28 | public noMilestones: boolean 29 | protected guidesCount = 6 30 | protected milestones: Array<{ x: number, title: string|null }> = [] 31 | protected guides: Array<{ y: number, title: string, opacity: Telemation }> = [] 32 | protected columns: Telecolumn[] = [] 33 | 34 | constructor(protected readonly telechart: Telechart, options?: IAbstractChartDrawerOptions) { 35 | this.isRangeDisplay = options && options.isRangeDisplay ? true : false 36 | this.isZeroStart = options && options.isZeroStart ? true : false 37 | this.noGuides = options && options.noGuides ? true : false 38 | this.noMilestones = options && options.noMilestones ? true : false 39 | this.topPadding = options && options.topPadding ? options.topPadding : 0 40 | this.bottomPadding = options && options.bottomPadding ? options.bottomPadding : 0 41 | } 42 | 43 | public abstract drawColumns(): void 44 | 45 | public abstract drawColumn(column: Telecolumn): void 46 | 47 | public get telecanvas() { 48 | return this.telechart.telecanvas 49 | } 50 | 51 | public get bordersAnimationFinished() { 52 | return this.borders.maxX.finished && this.borders.maxY.finished 53 | } 54 | 55 | public getXValue(canvasX: number) { 56 | return Math.round((this.borders.maxX.value - this.borders.minX.value) * canvasX / this.telecanvas.width + this.borders.minX.value) 57 | } 58 | 59 | public getYValue(canvasY: number) { 60 | const tHeight = this.telecanvas.height - (this.bottomPadding + this.topPadding) 61 | return Math.round((this.topPadding - canvasY) * (this.borders.maxY.to - this.borders.minY.to) / tHeight + this.borders.maxY.to) 62 | } 63 | 64 | public getCanvasX(value: number, borders?: [number, number]) { 65 | const min = borders ? borders[0] : this.borders.minX.value 66 | const max = borders ? borders[1] : this.borders.maxX.value 67 | return (value - min) / (max - min) * this.telecanvas.width 68 | } 69 | 70 | public getCanvasY(value: number, borders?: [number, number]) { 71 | const min = borders ? borders[0] : this.borders.minY.value 72 | const max = borders ? borders[1] : this.borders.maxY.value 73 | const tHeight = this.telecanvas.height - (this.bottomPadding + this.topPadding) 74 | return tHeight - (value - min) / (max - min) * tHeight + this.topPadding 75 | } 76 | 77 | public addColumn(column: Telecolumn) { 78 | this.columns.push(column) 79 | this.recalcBorders(0) 80 | if (!this.noMilestones) { 81 | this.recalcMilestones() 82 | } 83 | } 84 | 85 | public removeColumn(column: Telecolumn) { 86 | this.columns.splice(this.columns.indexOf(column), 1) 87 | this.recalcBorders(0) 88 | if (!this.noMilestones) { 89 | this.recalcMilestones() 90 | } 91 | } 92 | 93 | public drawCurrentPoints() { 94 | this.columns.forEach(col => { 95 | if (col.current) { 96 | this.telecanvas.circle([this.getCanvasX(col.current.x), this.getCanvasY(col.current.y)], 4.5, col.color, col.config.background, 2) 97 | } 98 | }) 99 | } 100 | 101 | public drawCurrentLine(color: string) { 102 | const c = this.telecanvas 103 | if (this.columns.length && this.columns[0].currentPoint) { 104 | c.line( 105 | [this.getCanvasX(this.columns[0].currentPoint.x), 0], 106 | [this.getCanvasX(this.columns[0].currentPoint.x), c.height - this.bottomPadding], 107 | color, 1, 108 | ) 109 | } 110 | } 111 | 112 | public drawMilestones(textColor: string) { 113 | const c = this.telecanvas 114 | const dateWidth = 75 115 | const milestones = this.milestones.filter(m => { 116 | const x = this.getCanvasX(m.x) 117 | return x > -50 && x < c.width + 50 118 | }) 119 | milestones.forEach(m => { 120 | const index = this.milestones.indexOf(m) 121 | const x = this.getCanvasX(m.x) 122 | if (!m.title) { 123 | m.title = this.telechart.getDateString(m.x, 'M j') 124 | } 125 | const roundToPowerOfTwo = (num: number) => { 126 | return Math.pow(2, Math.round(Math.log(num) / Math.log(2))) 127 | } 128 | const odd = roundToPowerOfTwo(Math.ceil(milestones.length / (c.width / dateWidth))) 129 | let opacity = 0 130 | if (index % odd === 0) { 131 | opacity = 1 132 | } else if (index % (odd / 2) === 0) { 133 | opacity = Math.min(1, c.width / (milestones.length / odd + milestones.length / odd / 2) / dateWidth) 134 | opacity = opacity * opacity * opacity * opacity 135 | } 136 | if (opacity < .15) { 137 | return 138 | } 139 | c.text(m.title!, [x, c.height - this.bottomPadding + 18], c.getColorString(textColor, opacity), undefined, 11, 'center') 140 | }) 141 | } 142 | 143 | public drawGuides(lineColor: string|undefined, textColor?: string, textAlign: 'left'|'right' = 'left', labelFormatter?: (label: string) => string) { 144 | if (!lineColor && !textColor) { 145 | return 146 | } 147 | const c = this.telecanvas 148 | c.save() 149 | c.setClippingRect(0, 0, c.width, c.height - this.bottomPadding + 30) 150 | for (let n = this.guides.length - 1; n >= 0; n--) { 151 | const g = this.guides[n] 152 | const y = this.getCanvasY(g.y) 153 | if (g.opacity.finished && g.opacity.value === 0) { 154 | this.guides.splice(n, 1) 155 | } 156 | if (lineColor) { 157 | c.line([0, y], [c.width, y], c.getColorString(lineColor, g.opacity.value), 1) 158 | } 159 | if (textColor) { 160 | if (textAlign === 'left') { 161 | c.text(labelFormatter ? labelFormatter(g.title) : g.title, [0, y - 6], c.getColorString(textColor, g.opacity.value), undefined, 11) 162 | } else { 163 | c.text(labelFormatter ? labelFormatter(g.title) : g.title, [c.width, y - 6], c.getColorString(textColor, g.opacity.value), undefined, 11, 'right') 164 | } 165 | } 166 | } 167 | c.restore() 168 | } 169 | 170 | public recalcBorders(duration = 100) { 171 | if (!this.columns.filter(c => c.visible).length) { 172 | return 173 | } 174 | const oldMax = this.borders ? this.borders.maxY.to : 0 175 | const oldMin = this.borders ? this.borders.minY.to : 0 176 | this.borders = this.getNewBorders(duration) 177 | if (!this.noGuides && (oldMax !== this.borders.maxY.to || oldMin !== this.borders.minY.to)) { 178 | this.recalcGuides(duration) 179 | } 180 | } 181 | 182 | protected getNewBorders(duration?: number) { 183 | const result = { 184 | minX: Math.min(...this.columns.filter(c => c.visible).map(c => c.getMinX(this.isRangeDisplay))), 185 | maxX: Math.max(...this.columns.filter(c => c.visible).map(c => c.getMaxX(this.isRangeDisplay))), 186 | minY: this.isZeroStart ? 0 : Math.min(...this.columns.filter(c => c.visible).map(c => c.getMinY(this.isRangeDisplay))), 187 | maxY: Math.max(...this.columns.filter(c => c.visible).map(c => c.getMaxY(this.isRangeDisplay))), 188 | } 189 | return { 190 | minX: duration && this.borders ? Telemation.create(this.borders.minX.value, result.minX, 100) : Telemation.create(result.minX), 191 | maxX: duration && this.borders ? Telemation.create(this.borders.maxX.value, result.maxX, 100) : Telemation.create(result.maxX), 192 | minY: duration && this.borders ? Telemation.create(this.borders.minY.value, result.minY, duration) : Telemation.create(result.minY), 193 | maxY: duration && this.borders ? Telemation.create(this.borders.maxY.value, result.maxY, duration) : Telemation.create(result.maxY), 194 | } 195 | } 196 | 197 | protected getInDisplayColumnValues(column: Telecolumn, borders?: [number, number]) { 198 | const allVals = column.currentValues 199 | while (this.getCanvasX(allVals[0].x, borders) > 0) { 200 | const prevIndex = column.values.indexOf(allVals[0]) - 1 201 | if (prevIndex < 0) { 202 | break 203 | } 204 | allVals.unshift(column.values[prevIndex]) 205 | } 206 | while (this.getCanvasX(allVals[allVals.length - 1].x, borders) < this.telecanvas.width) { 207 | const nextIndex = column.values.indexOf(allVals[allVals.length - 1]) + 1 208 | if (nextIndex >= column.values.length) { 209 | break 210 | } 211 | allVals.push(column.values[nextIndex]) 212 | } 213 | return allVals 214 | } 215 | 216 | protected recalcGuides(duration: number = 0) { 217 | const c = this.telecanvas 218 | if (!duration) { 219 | this.guides = [] 220 | } else { 221 | for (const g of this.guides) { 222 | g.opacity = Telemation.create(g.opacity.value, 0, duration) 223 | } 224 | } 225 | for (let n = 0; n < this.guidesCount; n++) { 226 | const y = this.getYValue(c.height - this.bottomPadding - (c.height - this.bottomPadding - this.topPadding) / this.guidesCount * n) 227 | let value = Math.round(y - y % Math.pow(10, y.toString().length - 2)) 228 | let modifier = '' 229 | const diff = this.borders.maxY.to - this.borders.minY.to 230 | if (diff > 5000000) { 231 | value = Math.round(value / 1000000) 232 | modifier = 'M' 233 | } else if (diff > 5000) { 234 | value = Math.round(value / 1000) 235 | modifier = 'K' 236 | } 237 | this.guides.push({ y, title: `${value}${modifier}`, opacity: duration ? Telemation.create(0, 1, duration) : Telemation.create(1) }) 238 | } 239 | while (this.guides.length > this.guidesCount * 3) { 240 | this.guides.shift() 241 | } 242 | } 243 | 244 | protected recalcMilestones() { 245 | this.milestones = [] 246 | for (let x = this.borders.minX.to; x < this.borders.maxX.to; x += 60 * 60 * 24 * 1000) { 247 | const value = { x, title: null } 248 | this.milestones.push(value) 249 | } 250 | } 251 | 252 | } 253 | -------------------------------------------------------------------------------- /dist/data/5/overview.json: -------------------------------------------------------------------------------- 1 | {"columns":[["x",1523059200000,1523145600000,1523232000000,1523318400000,1523404800000,1523491200000,1523577600000,1523664000000,1523750400000,1523836800000,1523923200000,1524009600000,1524096000000,1524182400000,1524268800000,1524355200000,1524441600000,1524528000000,1524614400000,1524700800000,1524787200000,1524873600000,1524960000000,1525046400000,1525132800000,1525219200000,1525305600000,1525392000000,1525478400000,1525564800000,1525651200000,1525737600000,1525824000000,1525910400000,1525996800000,1526083200000,1526169600000,1526256000000,1526342400000,1526428800000,1526515200000,1526601600000,1526688000000,1526774400000,1526860800000,1526947200000,1527033600000,1527120000000,1527206400000,1527292800000,1527379200000,1527465600000,1527552000000,1527638400000,1527724800000,1527811200000,1527897600000,1527984000000,1528070400000,1528156800000,1528243200000,1528329600000,1528416000000,1528502400000,1528588800000,1528675200000,1528761600000,1528848000000,1528934400000,1529020800000,1529107200000,1529193600000,1529280000000,1529366400000,1529452800000,1529539200000,1529625600000,1529712000000,1529798400000,1529884800000,1529971200000,1530057600000,1530144000000,1530230400000,1530316800000,1530403200000,1530489600000,1530576000000,1530662400000,1530748800000,1530835200000,1530921600000,1531008000000,1531094400000,1531180800000,1531267200000,1531353600000,1531440000000,1531526400000,1531612800000,1531699200000,1531785600000,1531872000000,1531958400000,1532044800000,1532131200000,1532217600000,1532304000000,1532390400000,1532476800000,1532563200000,1532649600000,1532736000000,1532822400000,1532908800000,1532995200000,1533081600000,1533168000000,1533254400000,1533340800000,1533427200000,1533513600000,1533600000000,1533686400000,1533772800000,1533859200000,1533945600000,1534032000000,1534118400000,1534204800000,1534291200000,1534377600000,1534464000000,1534550400000,1534636800000,1534723200000,1534809600000,1534896000000,1534982400000,1535068800000,1535155200000,1535241600000,1535328000000,1535414400000,1535500800000,1535587200000,1535673600000,1535760000000,1535846400000,1535932800000,1536019200000,1536105600000,1536192000000,1536278400000,1536364800000,1536451200000,1536537600000,1536624000000,1536710400000,1536796800000,1536883200000,1536969600000,1537056000000,1537142400000,1537228800000,1537315200000,1537401600000,1537488000000,1537574400000,1537660800000,1537747200000,1537833600000,1537920000000,1538006400000,1538092800000,1538179200000,1538265600000,1538352000000,1538438400000,1538524800000,1538611200000,1538697600000,1538784000000,1538870400000,1538956800000,1539043200000,1539129600000,1539216000000,1539302400000,1539388800000,1539475200000,1539561600000,1539648000000,1539734400000,1539820800000,1539907200000,1539993600000,1540080000000,1540166400000,1540252800000,1540339200000,1540425600000,1540512000000,1540598400000,1540684800000,1540771200000,1540857600000,1540944000000,1541030400000,1541116800000,1541203200000,1541289600000,1541376000000,1541462400000,1541548800000,1541635200000,1541721600000,1541808000000,1541894400000,1541980800000,1542067200000,1542153600000,1542240000000,1542326400000,1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000,1552089600000,1552176000000,1552262400000,1552348800000,1552435200000,1552521600000,1552608000000,1552694400000,1552780800000,1552867200000,1552953600000,1553040000000,1553126400000,1553212800000,1553299200000,1553385600000,1553472000000,1553558400000,1553644800000,1553731200000,1553817600000,1553904000000,1553990400000,1554076800000,1554163200000,1554249600000,1554336000000,1554422400000,1554508800000],["y0",34310,38260,47440,42460,43740,43770,41720,35440,39770,42420,45930,42840,42080,41300,33430,34690,44450,41780,33570,40180,38560,33220,27930,44050,35100,47290,46580,43240,34810,39960,45820,43680,44660,46050,43560,32970,42450,47550,50150,45430,44740,41950,30010,38770,45030,50130,42960,43090,39330,35630,41110,46810,48720,49340,45190,38450,31440,37730,42390,48980,49870,43060,44800,32470,38350,46770,49570,49110,50510,43630,37390,42040,49600,49120,44440,48430,47780,39650,37610,47430,49810,47090,47960,42390,31880,38090,43410,47620,48660,49410,48980,33870,39340,52190,48170,48830,49110,44620,29840,34750,52870,44890,48690,50820,41630,32840,33220,45130,48770,40130,42330,39850,30770,30490,42370,44410,42050,45240,37590,28220,28460,43830,35120,37970,38080,33960,31170,33140,35170,31390,23890,35030,29560,27300,29170,41540,38970,40210,40290,42360,33160,37040,45390,43470,45240,48290,45280,39430,37240,46040,53750,52340,56740,48730,32760,35940,57580,48800,44720,47330,40000,37190,44400,53920,48080,42060,45650,41430,34950,35300,50860,44030,46780,43890,38240,29930,36670,43530,46970,47220,45550,38840,34260,39740,41650,45770,47930,44510,42120,20810,35470,41790,45670,44380,42660,40320,32480,40190,47830,47030,47340,42530,42240,37300,38980,49190,45440,37440,34270,46220,33960,44960,45250,43860,44340,44010,41790,34410,43200,46130,48550,43810,45360,50150,35320,39170,48970,48150,47340,48960,39830,32340,37610,49160,45110,41230,44360,44180,33100,37630,47340,46860,47800,43470,39480,36760,38750,46680,42040,41890,43630,39920,30640,37680,42650,42410,39520,38680,33620,26190,31120,31710,24600,29640,35580,33250,29090,31260,20900,25900,39520,38410,38970,37370,32060,41190,42710,42410,44490,42680,33690,38400,42230,44920,41980,42120,40250,35550,37400,48750,44870,45750,44020,41510,30420,37770,48420,42870,47080,47870,41520,33120,39320,52990,44150,49360,42200,42290,29470,41270,47010,42710,44330,39960,40600,30710,33290,44720,43690,42740,40440,40440,32720,37030,42310,42630,38830,39250,36590,26960,29320,41210,40850,40130,40860,38760,29040,33270,44720,44170,43990,42110,40370,30110,30340,46630,42680,41700,41820,43800,31090,33950,46700,43480,44790,41260,40460,28270,32880,42010,43890,45990,42250,39450,28870],["y1",13730,13690,15220,13820,13080,13870,13300,11290,14240,15260,15150,14600,13690,14460,12750,13510,15220,15070,12730,15170,14140,12650,11480,13980,14500,15550,15590,15470,14040,14770,16590,14470,14840,14910,14490,13380,14410,14170,14800,15700,15180,14010,13020,14750,14950,14350,14710,15120,14070,12520,14680,15510,14200,15610,15180,14540,11940,15190,16180,15670,13830,14800,14560,12850,13800,14890,16190,15610,15230,14770,13940,15450,15530,16340,16000,16880,15530,13800,14410,15520,16630,14890,14660,15540,14100,15960,15950,16010,16150,15500,13800,14030,14520,16270,16110,15870,15270,15810,13670,15600,16290,15610,16060,16400,16340,13810,14920,16820,16950,17530,17490,17050,14650,15670,19000,18680,18240,18210,17680,16420,16190,16760,16580,18300,20560,18760,16440,17800,18270,21800,16760,18260,18150,18100,18210,20350,20730,22270,21910,19380,17800,20190,19540,19730,19530,19810,21450,17920,19850,21320,22400,22700,22810,20180,19140,21540,21730,21580,22800,23640,19150,22070,22740,20730,23820,21880,22700,22450,21120,21180,24150,20920,23890,21320,22110,20860,21190,22710,22170,23680,23590,23760,23170,22360,24520,23830,24690,26700,22220,14530,22920,26310,24840,24910,27490,24910,23330,28350,29540,29300,28910,30530,27710,26870,31170,34050,32040,28070,31970,32860,30500,35250,34900,35680,34820,36470,36600,31880,37310,38540,37510,36470,37070,33790,32550,34480,35660,34840,35070,34430,33800,29450,32910,37250,34730,33970,33660,32470,29670,32120,35610,33620,35090,32780,30180,26990,32680,35540,33250,33070,31350,31500,29800,29620,32630,32060,31030,31850,31040,29000,31410,30880,34180,31390,31410,33940,30190,29970,27620,28530,31660,35190,34050,33360,33250,32930,33570,32310,31930,32520,31000,34450,35120,33320,32760,32310,32110,30030,32290,32180,34510,34630,33840,32850,29680,32390,35360,32350,33910,32170,31140,25910,31100,33070,31630,32140,32980,31910,26510,28700,32450,30350,30620,28170,27090,24020,26210,30630,30010,29060,28280,27480,25640,27380,31170,30140,29880,27080,27190,26540,26100,28950,28390,29580,28430,27180,26900,27890,30370,29010,37710,31070,28200,24050,29250,30280,30940,30400,29590,27840,25070,28680,30740,28600,30670,30550,28430,26900,27170,29890,30590,33270,31990,30770,27010],["y2",10200,11610,11210,11800,11010,10980,12360,9040,11290,10530,10530,9160,8920,10140,8700,8320,9860,9330,7450,9840,8710,6850,6500,8840,7640,8690,7730,7990,8020,7160,9640,7810,9740,8010,10200,7060,6570,8240,8260,8390,9060,7860,8050,6180,8160,8020,9000,8300,7980,6450,6700,7870,7820,7330,8520,8010,6940,7800,8480,8430,7360,7010,7310,6680,5940,7100,6890,8810,6600,7580,5680,6710,8530,9210,6170,6940,7760,6120,5890,9590,6340,6450,8990,7720,7650,6330,8120,7200,7620,8010,5930,8830,7360,8020,6730,7360,7870,8170,6520,6500,6820,9860,7160,7960,7270,6420,5610,7340,7070,6480,7090,6960,6440,5830,7230,8080,6980,7660,9220,5980,4930,6880,6920,6910,7140,6030,5800,7240,8090,5640,5530,6520,6230,6210,6200,8850,8430,9310,8930,8140,7330,7770,7820,7380,8020,7310,6790,6980,6910,8800,7250,9200,8440,8230,6710,7710,8430,7780,7290,9210,8000,8170,7140,8060,7360,6840,7850,6650,6150,7120,8510,9020,9750,9200,9320,7500,6820,8560,9350,9020,8150,8610,6740,8500,8330,7170,8790,7090,6870,4910,7700,8490,9190,10100,7720,7850,8530,7970,9480,8170,9900,9190,8690,10060,10280,10930,9470,9840,11210,11240,7870,10100,11280,10970,11100,10590,10920,8850,9130,11280,10410,10530,10560,10150,11230,8580,9660,10010,10990,10560,7710,7710,9290,10680,9030,8690,9440,8860,7170,9130,10090,9080,9240,9090,8760,8070,8520,9110,9240,9110,9500,9080,7810,9090,10110,9700,10770,9580,8390,8100,7840,9530,9590,8820,9140,9580,9610,8950,7980,8180,9920,9730,9940,8990,9600,9830,9680,9840,8840,9030,9090,10470,9820,10730,9900,10470,11100,7790,10320,10060,11450,10110,10020,10170,10540,11910,11290,11040,9940,10240,9850,9610,9920,10440,10880,10290,9930,10560,10560,9590,11160,10660,10540,9800,9490,9350,9440,10260,11180,9980,9590,9240,8560,9170,9290,9370,9420,10210,9640,8780,11220,10440,9800,10500,10420,9840,8990,9410,10860,10710,13840,13700,10680,8830,11480,12140,11130,13350,11750,9780,9150,9820,11100,10890,11930,10630,10490,8880,11000,11480,12160,10660,11210,10410,9850],["y3",2000,2540,3540,3380,3190,3530,3190,2160,2520,3770,3360,3300,3130,2810,1710,2210,3490,3370,2270,3070,2870,1750,1430,2340,2210,3470,3380,3470,2150,2210,3540,3450,3280,3360,2890,2130,2250,3940,3480,3380,3470,2920,1920,1950,3600,3440,3450,3540,2940,2070,2050,3430,3610,3290,3320,2770,1880,2280,3690,3360,3490,3060,3120,2080,2220,3390,3290,3580,3330,3160,2160,2140,3290,3010,3540,3280,3060,2350,2490,3260,3430,3160,3860,2730,1890,2300,3050,2940,3150,3380,2840,1870,1940,3020,3050,3310,2960,2760,1730,2330,3610,3390,2790,2930,2840,1750,1910,2990,3190,2620,2940,2190,1580,1490,2430,2490,2350,2270,2030,1240,1510,2550,2100,1900,2290,1770,1450,1560,1790,1670,1110,2060,1530,1600,1620,2470,2760,2390,2260,2200,1690,1590,2630,2580,2500,2780,2280,1810,1970,2880,2970,2830,3030,2910,2150,2150,3090,2950,2850,3120,2540,1830,2290,3110,3210,2950,2670,2940,1800,1820,3130,3180,3690,3030,2940,1780,2080,3120,3470,3220,3240,3140,2080,2510,3300,3260,3390,3490,2970,1780,2260,3610,3280,3540,3620,3020,2110,2360,3120,3420,3440,3430,3050,2630,2670,4080,3320,2980,2400,2920,2240,2010,3290,3880,3480,3180,3750,2200,3050,3160,3590,2890,3580,3510,1790,2610,3930,3540,3660,3280,2900,2100,2580,3660,4100,3340,3590,3050,2390,2360,3880,3870,3910,3230,2690,1990,2280,3710,3540,3350,3150,2870,2290,2280,3230,3520,2990,2590,2390,1890,2170,1950,1360,2060,2650,2430,1920,1820,1400,1540,2900,3080,3560,2360,2710,3960,3900,3660,4000,3550,2930,3770,4240,4490,4760,4160,3410,2350,3210,3420,3980,4010,4000,4150,2390,3060,3830,4060,3700,3510,3530,2380,2430,3640,4550,3700,3310,3870,2130,2480,3650,3820,4180,3500,3380,1970,2640,3970,3800,3830,3400,3110,1820,2370,3860,3650,3650,3620,3270,2100,2440,3520,3290,3470,3210,3210,2020,2360,3910,3700,3650,3200,3250,2220,2420,4010,3870,3620,3620,3010,2410,2530,3820,3630,3870,3510,3190,1880,2460,3500,3750,3880,4140,3320,2260],["y4",5480,5930,10490,9460,11790,9530,9690,5500,5810,8090,9510,8830,8350,8490,5130,5550,9110,9850,5800,8930,8280,4540,4350,6630,4490,9810,9130,8680,5040,5120,9100,9520,8670,10550,8860,5140,5050,9510,10390,10290,10130,9700,4150,5270,9790,9670,9120,10030,9790,5250,5530,9280,9610,9870,9580,9410,4700,6340,10490,10390,10850,9680,8600,4920,5050,10960,10680,10500,10070,8270,5410,5730,10780,10250,10470,9690,9640,5080,5630,10050,11060,8290,9540,8070,5380,5310,9710,9750,10760,9870,9080,5030,6720,9830,10500,9190,9550,9580,6040,6360,10720,9090,10170,9570,9750,4810,5280,9420,9310,8830,9050,8400,4480,3990,7880,8890,8320,8770,7420,5210,3960,7940,7750,8310,8070,6670,4590,4500,6150,5190,3850,5940,6310,4300,4370,9240,7760,7810,7700,7790,4380,4990,8640,9060,8870,9760,8780,6250,6250,10460,10520,10970,10430,9440,5390,5270,10630,10740,10160,10030,9180,4620,5290,9080,11090,9930,10520,9910,5120,5360,9810,9170,9120,10310,8460,4200,4390,9770,9800,10000,9530,9130,4830,4820,9390,8900,8820,9390,8480,3240,4990,9510,9060,8840,9480,8970,4800,5620,9750,10350,9890,9510,9170,5790,6960,10760,9780,8790,6010,8560,5550,5710,9910,9130,9630,10250,9720,4930,6080,9760,10140,8950,10930,9040,5390,6260,9570,10320,9450,10200,8570,5630,5230,10030,10220,9690,10240,9500,5680,5970,9350,9710,9090,9760,8630,4730,5930,9900,10220,9480,8960,7940,5080,4910,9060,8490,10270,9200,7350,4800,5420,4580,3820,4200,6850,7120,5040,4870,4070,3590,7720,7710,7330,5230,5980,8450,10610,9030,9480,8870,5010,5210,10050,9270,9770,9290,9480,5280,4770,9320,10050,9310,9650,8280,4880,5350,10050,9730,9880,10130,9120,5140,5840,9820,9870,9770,8920,9010,4810,5480,10440,9540,9450,9540,9390,5380,5460,10590,9370,10240,9790,9370,5140,5630,9530,9240,9440,9760,8500,4900,4850,9890,8650,9450,9820,8880,5050,5000,9100,9690,9630,9870,8570,4840,5130,9910,9760,9930,10210,9010,4990,5580,10040,10630,10260,10610,8240,5080,4530,10140,9920,9670,10590,10600,4970],["y5",4770,4760,4910,5490,5560,5270,4900,4520,5420,5750,5640,5290,5090,5670,4290,4160,4990,5170,4380,5370,5840,4710,3600,4560,4640,5000,4660,4800,3900,6400,4150,5100,5190,5950,4670,3940,4070,4490,4750,4760,4910,4730,3780,3760,4860,4730,4960,4330,5320,4700,4390,5570,5470,4330,4250,4070,3500,3790,5020,4630,5070,3930,4360,3470,3730,4130,4910,4670,4100,4240,3660,3360,4430,4090,3860,4180,4420,3540,4120,4180,4330,4000,4450,3460,3090,3600,3720,4190,3890,3900,4340,3150,3210,3940,4150,4310,4300,3600,3380,2970,3320,3520,3570,4010,3400,3210,3130,3670,3740,3790,2910,3230,2280,3030,2770,3310,3640,3050,3090,2810,2880,3470,3120,3270,3140,2460,2950,2690,3000,2950,2430,3210,3500,2230,2620,3030,3010,3150,3110,3170,3680,3020,3380,2600,3180,3240,3690,3150,3200,2860,3320,3290,3200,3240,2760,3100,3660,3180,4120,3110,4100,2950,2360,3590,3320,3410,3220,3200,2510,2800,3490,3050,2830,3100,3000,3030,2800,3670,2890,3320,2640,2660,2410,2720,3370,3230,3070,2920,3010,2240,2510,2970,2750,2560,2700,2630,2660,2700,2890,3030,2430,3300,3700,2830,3010,2990,2850,2850,3290,2400,2890,3000,2640,2900,2970,2980,2430,2450,2960,2990,2940,2950,2900,2670,2300,2610,2670,2760,2440,2960,2740,2290,2820,2330,2690,2420,2780,2110,2180,2040,2740,2960,3230,2880,2680,2180,2380,2560,2890,2540,2660,2450,2440,2450,2590,2930,2960,3030,2380,2220,2390,2520,2650,2490,2590,2450,2200,2340,2150,2520,2140,2100,2240,2150,2770,2740,2240,2080,2480,2090,2230,2180,2390,2390,2670,2920,1960,1910,2420,2180,2860,2800,2460,2700,2360,2320,2750,2520,2690,2580,2270,2370,2190,2440,2120,2360,2110,2170,2200,2370,2110,2280,2410,2640,2240,2380,2090,2620,2570,2510,2320,2390,1970,2190,2340,2340,2310,2290,2450,1960,2140,1930,2400,1980,2290,2160,1840,1700,2110,2540,2390,2150,1800,1990,2130,2040,1910,1740,2290,2030,1820,2090,2200,2340,2010,2200,2030,2340,1630,2010,1910,1980,1970,1640,1660]],"types":{"y0":"area","y1":"area","y2":"area","y3":"area","y4":"area","y5":"area","x":"x"},"names":{"y0":"Apples","y1":"Oranges","y2":"Lemons","y3":"Apricots","y4":"Kiwi","y5":"Mango"},"colors":{"y0":"#3497ED","y1":"#2373DB","y2":"#9ED448","y3":"#5FB641","y4":"#F5BD25","y5":"#F79E39"},"percentage":true,"stacked":true} -------------------------------------------------------------------------------- /dist/data/3/overview.json: -------------------------------------------------------------------------------- 1 | {"columns":[["x",1523059200000,1523145600000,1523232000000,1523318400000,1523404800000,1523491200000,1523577600000,1523664000000,1523750400000,1523836800000,1523923200000,1524009600000,1524096000000,1524182400000,1524268800000,1524355200000,1524441600000,1524528000000,1524614400000,1524700800000,1524787200000,1524873600000,1524960000000,1525046400000,1525132800000,1525219200000,1525305600000,1525392000000,1525478400000,1525564800000,1525651200000,1525737600000,1525824000000,1525910400000,1525996800000,1526083200000,1526169600000,1526256000000,1526342400000,1526428800000,1526515200000,1526601600000,1526688000000,1526774400000,1526860800000,1526947200000,1527033600000,1527120000000,1527206400000,1527292800000,1527379200000,1527465600000,1527552000000,1527638400000,1527724800000,1527811200000,1527897600000,1527984000000,1528070400000,1528156800000,1528243200000,1528329600000,1528416000000,1528502400000,1528588800000,1528675200000,1528761600000,1528848000000,1528934400000,1529020800000,1529107200000,1529193600000,1529280000000,1529366400000,1529452800000,1529539200000,1529625600000,1529712000000,1529798400000,1529884800000,1529971200000,1530057600000,1530144000000,1530230400000,1530316800000,1530403200000,1530489600000,1530576000000,1530662400000,1530748800000,1530835200000,1530921600000,1531008000000,1531094400000,1531180800000,1531267200000,1531353600000,1531440000000,1531526400000,1531612800000,1531699200000,1531785600000,1531872000000,1531958400000,1532044800000,1532131200000,1532217600000,1532304000000,1532390400000,1532476800000,1532563200000,1532649600000,1532736000000,1532822400000,1532908800000,1532995200000,1533081600000,1533168000000,1533254400000,1533340800000,1533427200000,1533513600000,1533600000000,1533686400000,1533772800000,1533859200000,1533945600000,1534032000000,1534118400000,1534204800000,1534291200000,1534377600000,1534464000000,1534550400000,1534636800000,1534723200000,1534809600000,1534896000000,1534982400000,1535068800000,1535155200000,1535241600000,1535328000000,1535414400000,1535500800000,1535587200000,1535673600000,1535760000000,1535846400000,1535932800000,1536019200000,1536105600000,1536192000000,1536278400000,1536364800000,1536451200000,1536537600000,1536624000000,1536710400000,1536796800000,1536883200000,1536969600000,1537056000000,1537142400000,1537228800000,1537315200000,1537401600000,1537488000000,1537574400000,1537660800000,1537747200000,1537833600000,1537920000000,1538006400000,1538092800000,1538179200000,1538265600000,1538352000000,1538438400000,1538524800000,1538611200000,1538697600000,1538784000000,1538870400000,1538956800000,1539043200000,1539129600000,1539216000000,1539302400000,1539388800000,1539475200000,1539561600000,1539648000000,1539734400000,1539820800000,1539907200000,1539993600000,1540080000000,1540166400000,1540252800000,1540339200000,1540425600000,1540512000000,1540598400000,1540684800000,1540771200000,1540857600000,1540944000000,1541030400000,1541116800000,1541203200000,1541289600000,1541376000000,1541462400000,1541548800000,1541635200000,1541721600000,1541808000000,1541894400000,1541980800000,1542067200000,1542153600000,1542240000000,1542326400000,1542412800000,1542499200000,1542585600000,1542672000000,1542758400000,1542844800000,1542931200000,1543017600000,1543104000000,1543190400000,1543276800000,1543363200000,1543449600000,1543536000000,1543622400000,1543708800000,1543795200000,1543881600000,1543968000000,1544054400000,1544140800000,1544227200000,1544313600000,1544400000000,1544486400000,1544572800000,1544659200000,1544745600000,1544832000000,1544918400000,1545004800000,1545091200000,1545177600000,1545264000000,1545350400000,1545436800000,1545523200000,1545609600000,1545696000000,1545782400000,1545868800000,1545955200000,1546041600000,1546128000000,1546214400000,1546300800000,1546387200000,1546473600000,1546560000000,1546646400000,1546732800000,1546819200000,1546905600000,1546992000000,1547078400000,1547164800000,1547251200000,1547337600000,1547424000000,1547510400000,1547596800000,1547683200000,1547769600000,1547856000000,1547942400000,1548028800000,1548115200000,1548201600000,1548288000000,1548374400000,1548460800000,1548547200000,1548633600000,1548720000000,1548806400000,1548892800000,1548979200000,1549065600000,1549152000000,1549238400000,1549324800000,1549411200000,1549497600000,1549584000000,1549670400000,1549756800000,1549843200000,1549929600000,1550016000000,1550102400000,1550188800000,1550275200000,1550361600000,1550448000000,1550534400000,1550620800000,1550707200000,1550793600000,1550880000000,1550966400000,1551052800000,1551139200000,1551225600000,1551312000000,1551398400000,1551484800000,1551571200000,1551657600000,1551744000000,1551830400000,1551916800000,1552003200000,1552089600000,1552176000000,1552262400000,1552348800000,1552435200000,1552521600000,1552608000000,1552694400000,1552780800000,1552867200000,1552953600000,1553040000000,1553126400000,1553212800000,1553299200000,1553385600000,1553472000000,1553558400000,1553644800000,1553731200000,1553817600000,1553904000000,1553990400000,1554076800000,1554163200000,1554249600000,1554336000000,1554422400000,1554508800000],["y0",12360,16240,14210,14040,15190,13570,14020,15600,16080,15800,16740,15680,16790,15520,17410,17660,17000,15080,17190,17020,16620,15200,13210,16970,16030,16090,16800,15280,15450,15990,17130,14970,16020,15780,15770,15720,16210,15820,16080,14860,14210,14980,16200,15430,15510,16750,16460,15130,15120,15580,18040,16380,15940,16590,15950,15480,14940,16520,16570,15910,15950,16280,17120,15720,16600,17580,16260,17270,15660,16500,16410,17140,16240,17330,16320,17490,17220,17030,19130,17440,17350,17010,19050,16150,16350,18280,17670,19690,17470,16320,16180,16290,15440,16600,17430,17800,18110,16870,17200,16700,18010,18110,17850,17600,17870,18100,17300,19960,18340,19650,19710,21300,18930,20090,20240,21150,21020,21940,22350,22160,20800,22390,21450,22970,20690,23410,21490,21690,20650,22440,21630,23420,22860,23490,24460,23610,23810,22840,23540,24800,23460,24140,25050,23910,23790,23190,23390,23160,23830,23680,25940,23420,23330,23630,23400,26230,22690,24700,22010,23050,22460,24620,24960,26180,24540,24240,24690,24140,25140,29410,25900,25880,24600,25380,25090,24930,28930,26570,25270,26560,25520,27150,25130,25600,28580,25800,25500,27870,26320,18930,30390,27640,27790,28380,29230,28160,28490,31290,31710,32150,29840,29860,30240,30750,33300,34750,33250,31920,36940,36930,33360,38500,33700,34630,36580,36130,34960,35210,37600,37100,34640,36840,36150,33850,32800,35440,37510,36770,35560,35460,36650,35370,36990,39810,39340,36350,35350,33160,34440,36720,35200,37240,36030,36330,34940,34840,39350,37370,34040,33510,35270,32940,33310,34730,35760,37300,35190,33420,32550,33450,34360,41660,42960,38970,37080,37150,36460,41330,34220,34980,34840,39150,38110,35380,38760,36080,33790,36150,35960,32570,33180,36000,36390,33950,35390,36680,36540,31270,34720,35030,37090,38120,32870,34800,35000,34370,35070,35430,36830,37380,35390,33170,37300,34710,36450,37500,37820,31590,34370,37430,36650,35300,35520,35830,35650,32070,38700,34460,34450,32720,34900,35680,33340,37500,35730,35270,37150,35010,35260,33690,40330,36410,35540,35600,35480,37740,35600,44060,34610,37160,37880,36800,37940,35140,36900,40490,37740,36330,37730,35330,35800,39580,37590,35770,36430,36720,36860,33580,36830,35830,36600,37840,39450,35390,35310],["y1",9850,8210,10800,10490,11600,11160,11920,10210,8010,12010,12270,11720,12790,12330,10970,10150,11180,12150,9320,11460,12290,10400,7790,12150,8920,11330,11450,11550,10900,9800,11770,12130,11070,11850,11670,11260,10110,10790,10940,11200,12710,11660,9980,9120,11410,12830,11380,13290,12080,11020,9770,11700,11980,13020,12200,12320,9780,10660,10900,11940,12490,11300,12220,10410,10270,12310,12580,12170,12590,13110,10510,8960,12310,13270,13860,13460,12980,10030,10480,11550,12540,11630,13280,12670,9230,9510,11770,12160,12510,12130,12220,9630,8880,11210,10570,11600,12920,11260,11260,9570,11440,11850,12090,12640,12330,12180,9550,12990,12830,13600,14390,13380,11200,9350,13120,14140,15400,14090,14010,12900,10810,13690,13380,13910,13970,14260,12480,11110,12830,12910,8660,11560,13010,11910,11520,13260,15130,13850,14270,13940,13170,12080,15420,15530,16720,16800,16950,15980,13840,16930,17870,17780,17860,18180,16790,13320,18470,19150,18290,20630,19410,16410,15320,18460,18970,18930,20580,20850,17600,17750,22190,19970,21820,22900,21350,17600,16250,21290,20670,21300,22480,21530,17690,18860,21140,21100,22620,21730,21500,14230,17470,22730,22990,22790,23880,23070,21310,20790,23750,26840,25400,27300,25810,23570,21880,27560,29980,29890,22490,27400,25220,23230,28400,29720,31360,29380,31590,27210,23950,28940,29740,32280,32270,32520,27280,22010,30900,31550,32050,31800,32050,28210,23880,31450,29530,30470,32430,31660,27030,24270,31230,31630,31470,33030,32890,23600,24670,30340,31460,31610,31910,30550,26730,25180,29610,32710,33670,35040,35140,27820,23700,24670,16390,18390,29090,28130,25560,23590,21840,16420,24260,27670,29570,25730,22280,29060,29430,28930,29790,31130,25750,22390,29480,31690,30350,31150,31420,26440,22340,28380,29510,31160,30110,31910,25370,23090,30500,30550,29850,29560,30570,24870,23180,28910,29270,29670,31770,30990,26920,24520,30170,30620,30320,28920,30310,25300,22950,28800,30250,31800,30740,31250,27140,24710,30040,30210,32370,30260,31210,25190,24120,29280,30080,31050,31120,29810,25580,22500,28520,30260,35910,31510,31150,25450,23190,29760,31150,30540,30290,31860,26750,25020,30190,30700,30360,31060,30420,27340,22040,29990,30980,32710,32880,33190,30180],["y2",13730,13690,15220,13820,13080,13870,13300,11290,14240,15260,15150,14600,13690,14460,12750,13510,15220,15070,12730,15170,14140,12650,11480,13980,14500,15550,15590,15470,14040,14770,16590,14470,14840,14910,14490,13380,14410,14170,14800,15700,15180,14010,13020,14750,14950,14350,14710,15120,14070,12520,14680,15510,14200,15610,15180,14540,11940,15190,16180,15670,13830,14800,14560,12850,13800,14890,16190,15610,15230,14770,13940,15450,15530,16340,16000,16880,15530,13800,14410,15520,16630,14890,14660,15540,14100,15960,15950,16010,16150,15500,13800,14030,14520,16270,16110,15870,15270,15810,13670,15600,16290,15610,16060,16400,16340,13810,14920,16820,16950,17530,17490,17050,14650,15670,19000,18680,18240,18210,17680,16420,16190,16760,16580,18300,20560,18760,16440,17800,18270,21800,16760,18260,18150,18100,18210,20350,20730,22270,21910,19380,17800,20190,19540,19730,19530,19810,21450,17920,19850,21320,22400,22700,22810,20180,19140,21540,21730,21580,22800,23640,19150,22070,22740,20730,23820,21880,22700,22450,21120,21180,24150,20920,23890,21320,22110,20860,21190,22710,22170,23680,23590,23760,23170,22360,24520,23830,24690,26700,22220,14530,22920,26310,24840,24910,27490,24910,23330,28350,29540,29300,28910,30530,27710,26870,31170,34050,32040,28070,31970,32860,30500,35250,34900,35680,34820,36470,36600,31880,37310,38540,37510,36470,37070,33790,32550,34480,35660,34840,35070,34430,33800,29450,32910,37250,34730,33970,33660,32470,29670,32120,35610,33620,35090,32780,30180,26990,32680,35540,33250,33070,31350,31500,29800,29620,32630,32060,31030,31850,31040,29000,31410,30880,34180,31390,31410,33940,30190,29970,27620,28530,31660,35190,34050,33360,33250,32930,33570,32310,31930,32520,31000,34450,35120,33320,32760,32310,32110,30030,32290,32180,34510,34630,33840,32850,29680,32390,35360,32350,33910,32170,31140,25910,31100,33070,31630,32140,32980,31910,26510,28700,32450,30350,30620,28170,27090,24020,26210,30630,30010,29060,28280,27480,25640,27380,31170,30140,29880,27080,27190,26540,26100,28950,28390,29580,28430,27180,26900,27890,30370,29010,37710,31070,28200,24050,29250,30280,30940,30400,29590,27840,25070,28680,30740,28600,30670,30550,28430,26900,27170,29890,30590,33270,31990,30770,27010],["y3",930,890,900,980,1120,1250,1220,1030,960,1390,1300,1200,1030,880,1820,1680,1190,1320,1790,1610,1210,1170,1300,1080,1320,1200,970,760,1230,1250,1040,1020,1300,1290,970,900,1050,1040,980,1070,1410,1080,1000,1100,1070,1010,940,1160,1110,990,1070,830,940,1070,1160,1040,1020,1120,1210,3030,2530,1660,1170,1240,1180,1000,1170,720,1010,1300,1020,1180,1080,960,1050,880,950,970,1360,1020,1280,1140,1150,1100,1100,1260,1280,1540,1360,1250,1060,1330,930,1060,940,1190,1320,1180,1050,1210,1370,1330,950,1270,1130,1300,1170,1530,1110,1380,1240,1390,1150,1230,1340,1160,1140,1380,1690,1460,1240,1610,1320,1360,1320,1460,1450,1330,1080,1720,1600,1250,1570,1530,1610,1860,1450,1560,1690,1560,1730,1600,2170,1540,1940,1430,1410,1840,1790,1850,1620,1520,2190,1870,1550,2080,1560,1720,2040,1810,1890,2000,1900,2270,2060,1890,1930,1590,2030,1890,1810,1620,1690,1310,1700,1530,1970,2080,1620,1510,1990,1720,1750,1870,1740,1620,1840,1980,1910,1790,2080,1820,1530,2140,2440,2130,2430,2180,2080,2190,2090,1910,2440,1940,2680,3310,2510,2200,3020,2550,2450,2800,2450,2780,3020,2680,2210,2550,3160,2870,2690,3140,2820,2850,2160,2540,3050,2720,2540,3000,2630,2660,2780,2350,2510,2980,2650,2770,2220,3000,2950,2450,2610,2270,2200,2200,2920,2600,2470,2180,2480,2400,2450,2970,2830,2740,2680,2750,2200,2720,2270,3100,3510,3400,2920,2240,2330,2660,3400,3240,2940,3300,3760,3270,3460,3340,2820,2300,2830,2690,2760,2570,2420,2730,2480,3000,3260,2920,2750,2660,3130,3480,2530,3140,2200,2970,2900,2510,2500,2660,2970,2810,3200,2640,2790,3360,2690,2750,2810,3090,3080,2490,2810,2570,2630,2370,3320,2610,2300,2670,2470,2680,3270,3580,3000,2670,2540,2740,2940,2800,3590,3000,3130,3030,2460,2400,2610,3240,4010,2880,2930,2890,3240,2600,3530,2850,3580,3480,3210,3150,2730,3240,2720,3210,3090,3310,2670,2750,2540,2600,2930,3400,3050,3480,2930],["y4",2090,2070,2080,2490,2580,2210,2670,2940,2280,2520,2840,2480,3150,2590,2630,2490,3220,2390,2430,2490,2490,1520,1680,2680,2240,2630,2440,2340,2430,2710,2670,2420,2210,2750,3630,2450,2650,2330,2120,2310,2280,2500,2310,2410,2210,2210,2550,2690,2190,2030,1940,1790,3250,3370,2580,2330,2190,2270,2460,2310,2030,3070,2440,1820,2260,1580,2070,2230,2890,2430,1540,2450,2590,2200,2470,2790,2430,1960,2370,2470,2880,2960,2140,2420,1570,2530,2430,2850,2290,2380,2450,3150,3240,2100,2210,2580,2780,2880,2220,2290,2560,2550,3230,3760,4940,2460,2890,3120,3950,3170,2850,3480,2160,2770,3070,4080,2860,2950,2550,3890,3760,5150,7520,5950,4400,3150,2820,3390,3740,3140,3480,2480,2980,4740,3230,3370,3970,3730,3910,3890,2250,3340,5110,4360,3940,3030,3130,3470,3470,4230,3190,2950,5310,4600,3540,3170,3780,3210,4020,5060,4180,3710,4540,4070,3530,4100,3950,3810,4960,4750,4030,3760,4790,6930,5160,4060,4490,4500,4410,4950,4850,4380,4500,3270,3620,4910,4160,4520,5990,3080,5560,4510,4190,4390,4380,4260,4240,4260,4650,4630,3880,5130,4430,5030,5610,4420,4200,4300,5710,6660,4860,5620,4330,4120,10220,12330,7070,6430,6420,5510,4970,5390,5910,5440,4760,6080,4730,6690,6130,6050,4920,5310,5860,6880,6510,4860,6470,4960,4820,6520,5230,4350,5110,6100,4660,5110,4780,3790,5480,3560,4670,4530,5010,4590,4350,5670,3950,5150,4430,3630,4390,4090,3730,3380,6720,7270,5950,5350,4280,4400,6240,6950,5740,4400,5100,5880,4670,4710,6370,5630,4960,5780,6110,6070,5160,5280,4890,4560,5700,5030,4770,5370,6800,7150,3830,12010,4190,4320,4520,5850,5830,5670,4670,4980,4330,5050,5820,4610,5920,5160,4690,3980,4380,4450,3670,3440,4870,4330,4510,3880,4830,4850,4290,4400,5830,3760,4940,4670,5020,3920,4480,5410,5410,3750,5490,4150,3990,3910,4460,4240,3770,5000,4520,5000,4070,5080,4710,4440,5540,5280,5960,5260,4480,5540,6320,6150,5610,4900,4300,5010,5440,4450,5570,5840,4530],["y5",2520,2490,3090,2800,2820,3140,2780,2780,2770,2770,2960,2660,3010,2590,2670,2800,2630,2860,2590,2930,3020,2520,1990,2740,2540,2950,2920,3190,2610,2710,2900,3340,3240,2920,2870,2610,2600,2660,3110,3080,3260,2790,3140,2510,2940,2700,2780,3010,3010,2440,2750,3250,3500,3190,3150,2720,2550,2580,3060,2820,2640,2980,2720,2440,2270,3010,3150,3160,2830,2710,2420,2870,3130,2860,2840,2940,2780,2630,2770,2690,3100,3050,3020,2830,2270,2630,2550,3260,3120,2500,2720,2360,2170,3180,3410,2830,3250,2890,2680,2500,3730,3290,2790,2660,3160,2780,2490,3480,2990,2980,3110,3550,2900,2560,2920,3210,3410,3340,3190,3370,3430,3370,3380,3570,3360,3280,2920,3100,3250,3620,2640,2920,3370,2890,3210,3700,3880,3340,3630,3810,3960,4240,3680,3690,3540,3900,4130,3230,3430,4060,4240,3920,3950,4300,3340,3290,3670,3410,3640,4180,3560,3160,3060,3920,3980,4390,3810,3960,3590,4130,4310,3970,3870,4080,4170,3850,3750,3930,3880,3770,3970,3810,3910,3960,4180,4420,4390,4460,4420,2620,4500,4300,4470,4590,4580,4470,4120,4610,4730,5040,4970,5170,4990,4210,4870,5340,5170,4530,5560,5230,4300,5140,5630,5780,5400,5200,5310,5130,5480,5260,5780,5750,5350,5460,4670,4900,6280,6380,6580,6710,7110,5210,5230,5790,5720,5340,5510,5090,4550,5150,5370,5460,5550,5600,5510,5140,4960,5160,5180,5260,5340,5030,4750,5150,5030,5220,4620,5250,5000,4650,4080,4320,4360,4160,5420,5690,4580,4600,3750,4000,4990,5070,5510,5480,5260,5840,5330,5930,5640,5150,5560,4640,6140,5560,5880,6310,5370,5160,4920,5550,5730,5410,5180,5820,4790,5990,4960,5490,5540,5500,5140,5000,4960,5650,5440,5360,5790,5360,4690,5370,5490,5280,5510,5840,5720,4590,4760,5380,5220,5310,5300,5400,4540,4900,5140,5360,5540,5310,5480,4690,4800,5320,5900,5450,5250,4900,4410,4760,5150,5110,5890,5900,5460,4770,5100,5700,5560,5510,5700,5080,4880,4950,5880,5840,5470,5450,5320,4490,4090,5870,5420,6160,6240,5640,4530],["y6",120,60,90,70,50,60,110,150,100,60,70,50,60,80,130,80,90,130,170,80,160,100,90,100,90,40,90,100,80,100,110,100,80,120,180,160,110,50,60,50,20,110,130,120,50,40,110,110,70,140,150,70,50,110,30,70,130,110,140,60,60,80,170,110,140,60,40,140,60,160,150,90,70,150,130,100,80,110,100,30,80,80,130,130,150,130,160,70,70,70,80,200,80,80,80,50,70,80,70,90,50,70,120,140,110,170,180,90,70,80,100,150,220,170,90,120,140,90,190,190,100,110,80,180,150,140,150,220,170,120,160,130,170,150,190,200,120,100,130,210,190,100,100,180,130,80,90,230,130,100,120,120,110,100,140,140,50,100,100,100,150,140,110,120,80,100,70,150,120,100,100,100,130,110,110,190,170,210,100,90,130,210,180,90,160,90,70,120,190,140,100,100,100,160,160,200,190,190,100,90,140,180,120,170,130,60,50,160,130,170,280,160,130,140,170,110,240,220,150,110,150,80,180,150,70,190,80,150,220,210,160,170,90,120,50,180,180,130,220,100,150,200,110,280,180,150,190,140,60,120,100,110,180,100,140,120,200,180,220,170,160,70,140,150,210,120,200,80,330,90,100,140,60,100,160,50,80,120,80,120,170,80,80,110,80,70,210,140,190,60,100,120,60,170,240,200,70,80,80,120,160,90,120,100,130,180,110,130,240,130,90,80,150,150,240,250,140,80,130,170,120,120,170,110,80,170,150,130,190,210,180,120,50,100,180,210,170,150,120,110,170,160,220,140,150,160,130,120,60,230,170,270,120,160,200,160,150,180,210,200,150,110,120,160,210]],"types":{"y0":"bar","y1":"bar","y2":"bar","y3":"bar","y4":"bar","y5":"bar","y6":"bar","x":"x"},"names":{"y0":"Apples","y1":"Oranges","y2":"Lemons","y3":"Apricots","y4":"Kiwi","y5":"Mango","y6":"Pears"},"colors":{"y0":"#3497ED","y1":"#2373DB","y2":"#9ED448","y3":"#5FB641","y4":"#F5BD25","y5":"#F79E39","y6":"#E65850"},"stacked":true} --------------------------------------------------------------------------------