This repository has been archived by the owner on Jul 31, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Loading status checks…
FLOW-958 : @ollion/flow-dashboard (#205)
* FLOW-958 flow-dashboard package added * FLOW-958 f-dashboard story added * FLOW-958 gridstack added * FLOW-958 worker added * FLOW-958 worker added * FLOW-958 rebased * FLOW-958 worker updated * FLOW-958 timeseries chart added * FLOW-958 tooltip possitioning logic updated * FLOW-958 tooltip css updated * FLOW-958 x and y lines feature added * FLOW-958 multiline chart * FLOW-958 code segregation * FLOW-958 area chart added * FLOW-958 bar area line chart series added * FLOW-958 colors updated * FLOW-958 colors updated * FLOW-958 namespace updated from cldcvr to ollion * FLOW-958 tooltip is now configurable * FLOW-958 responsive behavior added for chart * FLOW-958 tick config added for xAxis * FLOW-958 yaxis tick config added * FLOW-958 interval type ticks fixed * FLOW-958 x-axis tick removal logic updated for small widths or when ticks are overlapping * FLOW-958 legends added * FLOW-958 Legend interaction updated * FLOW-958 tested legend overflow with 50 series * FLOW-958 legends directions added * FLOW-958 legends template added * FLOW-958 all options story added * FLOW-958 sample tests added to pass lint checks * FLOW-958 integration with f-dashboard * FLOW-958 number widget dimentions updated * FLOW-958 mock data utils updated * FLOW-958 mock data util updated * FLOW-958 realtime data story updated * FLOW-958 widget header option added * FLOW-958 footer option added for widget * FLOW-958 tooltip sync feature * FLOW-958 story updated to generate randon data * FLOW-958 changelog updated * FLOW-958 code duplication reduced
- @ollion/flow-text-editor@0.0.1
- @ollion/flow-table@2.4.8
- @ollion/flow-table@2.4.7
- @ollion/flow-table@2.4.6
- @ollion/flow-table@2.4.5
- @ollion/flow-table@2.4.4
- @ollion/flow-table@2.4.3
- @ollion/flow-table@2.4.2
- @ollion/flow-table@2.4.1
- @ollion/flow-table@2.4.0
- @ollion/flow-table@2.3.0
- @ollion/flow-table@2.2.5
- @ollion/flow-md-editor@2.1.2
- @ollion/flow-md-editor@2.1.1
- @ollion/flow-log@2.1.1
- @ollion/flow-log@2.1.0
- @ollion/flow-log@2.0.6
- @ollion/flow-log@2.0.5
- @ollion/flow-log@2.0.4
- @ollion/flow-log@2.0.3
- @ollion/flow-log@2.0.2
- @ollion/flow-lineage@3.2.2
- @ollion/flow-lineage@3.2.1
- @ollion/flow-lineage@3.2.0
- @ollion/flow-form-builder@2.4.4
- @ollion/flow-form-builder@2.4.3
- @ollion/flow-form-builder@2.4.2
- @ollion/flow-form-builder@2.4.1
- @ollion/flow-form-builder@2.4.0
- @ollion/flow-form-builder@2.3.1
- @ollion/flow-form-builder@2.3.0
- @ollion/flow-form-builder@2.2.5
- @ollion/flow-form-builder@2.2.4
- @ollion/flow-form-builder@2.2.3
- @ollion/flow-form-builder@2.2.2
- @ollion/flow-dashboard@0.0.1
- @ollion/flow-core@2.10.0
- @ollion/flow-core@2.9.15
- @ollion/flow-core@2.9.14
- @ollion/flow-core@2.9.13
- @ollion/flow-core@2.9.12
- @ollion/flow-core@2.9.11
- @ollion/flow-core@2.9.10
- @ollion/flow-core@2.9.9
- @ollion/flow-core@2.9.8
- @ollion/flow-core@2.9.7
- @ollion/flow-core@2.9.6
- @ollion/flow-core@2.9.5
- @ollion/flow-core@2.9.4
- @ollion/flow-core@2.9.3
- @ollion/flow-core@2.9.2
- @ollion/flow-core@2.9.1
- @ollion/flow-core@2.9.0
- @ollion/flow-core@2.8.7
- @ollion/flow-core@2.8.6
- @ollion/flow-core@2.8.5
- @ollion/flow-core@2.8.4
- @ollion/flow-core@2.8.3
- @ollion/flow-core@2.8.2
- @ollion/flow-core@2.8.1
- @ollion/flow-core@2.8.0
- @ollion/flow-code-editor@1.1.1
- @ollion/custom-elements-manifest-to-types@2.0.5
1 parent
8a613f4
commit 2a75c8b
Showing
31 changed files
with
4,400 additions
and
2,470 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
* | ||
!dist/**/*.* | ||
!shims.d.ts | ||
!custom-elements.json | ||
!html.html-data.json | ||
!src/**/*.* | ||
!README.md | ||
!umd/**/*.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<h4 className="margin-btm-8">Release Notes</h4> | ||
|
||
# Change Log | ||
|
||
## [0.0.1] - 2023-11-03 | ||
|
||
### First Release | ||
|
||
- `@ollion/flow-dashboard` released. | ||
|
||
### Note | ||
|
||
- Since this is the first release, we are testing it with various frameworks (thus, it is not production-ready) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
|
||
Copyright (c) 2022 CloudCover Consultancy Pvt Ltd | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining | ||
a copy of this software and associated documentation files (the | ||
"Software"), to deal in the Software without restriction, including | ||
without limitation the rights to use, copy, modify, merge, publish, | ||
distribute, sublicense, and/or sell copies of the Software, and to | ||
permit persons to whom the Software is furnished to do so, subject to | ||
the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be | ||
included in all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# Flow Dashboard | ||
|
||
The Flow dashboard is built on the Flow design framework ([website](https://flow.ollion.com/) / [github](https://github.com/ollionorg/flow-core)) | ||
|
||
# Installation | ||
|
||
### 1️⃣ Install flow dashboard dependency | ||
|
||
``` | ||
npm i --save @ollion/flow-dashboard | ||
``` | ||
|
||
**Note:** after installation, re-start your application. | ||
|
||
<br> | ||
|
||
### 2️⃣ Import flow-dashboard into your project | ||
|
||
Paste the below snippet in your project and add your application startup/runtime code to it. | ||
|
||
```javascript | ||
import "@ollion/flow-core"; | ||
import "@ollion/flow-dashboard"; | ||
``` | ||
|
||
<br> | ||
|
||
### 3️⃣ For a typescript enabled project (optional) | ||
|
||
**Note:** After adding, re-start your application. Make sure you are using version >4.5 | ||
|
||
**For Vue 3:** | ||
Copy paste below import types in your `main.ts` file. | ||
|
||
```Javascript | ||
import "@ollion/flow-dashboard/dist/types/vue3"; | ||
``` | ||
|
||
<details> | ||
<summary>For Vue 2</summary> | ||
|
||
Copy paste below import types in your `main.ts` file. | ||
|
||
```Javascript | ||
import "@ollion/flow-dashboard/dist/types/vue2"; | ||
``` | ||
|
||
</details> | ||
|
||
<details> | ||
<summary>For React</summary> | ||
|
||
**React**: Include react type in `tsconfig.json` file like below. | ||
|
||
```json | ||
"include": ["src", "./node_modules/@ollion/flow-dashboard/dist/types/react.ts"] | ||
``` | ||
|
||
</details> | ||
<br> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
|
||
#!/bin/bash | ||
|
||
HERE=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) | ||
|
||
cd "$HERE" | ||
|
||
pnpm run analyze | ||
|
||
echo "building library..." | ||
pnpm vite build --emptyOutDir | ||
pnpm vite build --emptyOutDir --config vite.umd.config.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
{ | ||
"name": "@ollion/flow-dashboard", | ||
"version": "0.0.1", | ||
"description": "Dashboard as code", | ||
"module": "dist/flow-dashboard.es.js", | ||
"main": "dist/flow-dashboard.cjs.js", | ||
"types": "dist/src/index.d.ts", | ||
"scripts": { | ||
"build": "bash ./compile.sh", | ||
"build:watch": "concurrently --kill-others \"vite build --emptyOutDir --watch\" \"tsc --watch\"", | ||
"analyze": "cem analyze --litelement --globs \"src/**/*.ts\" && wca analyze src --format vscode --outFile html.html-data.json", | ||
"analyze:watch": "cem analyze --litelement --globs \"src/**/*.ts\" --watch", | ||
"test": "web-test-runner ./src/**/*.test.ts --node-resolve --port 8095", | ||
"test:file": "pnpm run build && web-test-runner --node-resolve --port 8095", | ||
"test:watch": "pnpm run build && web-test-runner ./src/**/*.test.ts --node-resolve --watch --port 8095" | ||
}, | ||
"keywords": [ | ||
"web-components", | ||
"lit-element", | ||
"typescript", | ||
"lit" | ||
], | ||
"dependencies": { | ||
"@ollion/flow-core": "workspace:*", | ||
"@ollion/flow-core-config": "workspace:*", | ||
"axios": "^0.27.2", | ||
"d3": "^7.6.1", | ||
"gridstack": "^9.5.0", | ||
"lit": "^3.1.0", | ||
"rxjs": "^7.8.1" | ||
}, | ||
"peerDependencies": { | ||
"@ollion/flow-core": "^*", | ||
"@ollion/flow-core-config": "^*" | ||
}, | ||
"devDependencies": { | ||
"@custom-elements-manifest/analyzer": "^0.5.7", | ||
"@open-wc/testing": "^3.1.5", | ||
"@types/d3": "7.4.3", | ||
"@types/jest": "29.5.5", | ||
"@web/dev-server-esbuild": "^0.4.1", | ||
"@web/test-runner": "^0.17.1", | ||
"concurrently": "^8.2.1", | ||
"esbuild-sass-plugin": "2.2.6", | ||
"lit-html": "^3.1.0", | ||
"sass": "^1.52.3", | ||
"typescript": "^5.2.2", | ||
"vite": "^4.4.11", | ||
"web-component-analyzer": "^2.0.0-next.4" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/ollionorg/flow-core.git", | ||
"directory": "packages/flow-dashboard" | ||
}, | ||
"publishConfig": { | ||
"access": "public", | ||
"registry": "https://registry.npmjs.org" | ||
}, | ||
"customElements": "custom-elements.json", | ||
"bugs": { | ||
"url": "https://github.com/ollionorg/flow-core/issues" | ||
}, | ||
"homepage": "https://github.com/ollionorg/flow-core/packages/flow-dashboard#readme", | ||
"author": "@ollion", | ||
"license": "MIT" | ||
} |
46 changes: 46 additions & 0 deletions
46
packages/flow-dashboard/src/components/f-dashboard/f-dashboard-global.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
@import "../../../../flow-core/src/mixins/scss/mixins"; | ||
|
||
@import "gridstack/dist/gridstack.min.css"; | ||
|
||
f-dashboard { | ||
@include base(); | ||
height: 100%; | ||
width: 100%; | ||
|
||
display: flex; | ||
overflow: auto; | ||
.grid-stack { | ||
width: 100%; | ||
.grid-stack-item { | ||
.grid-stack-item-content { | ||
background: var(--color-surface-secondary); | ||
display: flex; | ||
flex-direction: column; | ||
f-timeseries-chart { | ||
flex: 1 0 100%; | ||
} | ||
> f-div[height="fill-container"] { | ||
flex: 1 1; | ||
max-height: 100%; | ||
} | ||
> f-div[width="fill-container"] { | ||
width: 100%; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
f-div[direction="column"] { | ||
> f-dashboard { | ||
flex: 1 1; | ||
max-height: 100%; | ||
} | ||
} | ||
|
||
f-div[direction="row"] { | ||
> f-dashboard { | ||
flex: 1 1; | ||
max-width: 100%; | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
packages/flow-dashboard/src/components/f-dashboard/f-dashboard-utils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { html, nothing } from "lit"; | ||
import { FDashboardWidget } from "../../types"; | ||
|
||
export function getWidgetHeader(widget: FDashboardWidget) { | ||
if (widget.header) { | ||
if (typeof widget.header === "object") { | ||
return html`<f-div | ||
align="middle-left" | ||
height="hug-content" | ||
padding="medium" | ||
direction="column" | ||
border="small solid subtle bottom" | ||
> | ||
<f-text ellipsis .tooltip=${widget.header.title} variant="heading" weight="medium" | ||
>${widget.header.title}</f-text | ||
> | ||
<f-text ellipsis state="secondary" .tooltip=${widget.header.description} size="small" | ||
>${widget.header.description}</f-text | ||
> | ||
</f-div>`; | ||
} else if (typeof widget.header === "function") { | ||
return widget.header(); | ||
} | ||
} | ||
|
||
return nothing; | ||
} | ||
|
||
export function getWidgetFooter(widget: FDashboardWidget) { | ||
if (widget.footer) { | ||
if (typeof widget.footer === "string") { | ||
return html`<f-div | ||
align="middle-left" | ||
height="hug-content" | ||
padding="medium" | ||
direction="column" | ||
border="small solid subtle top" | ||
> | ||
<f-text state="subtle" size="small">${widget.footer}</f-text> | ||
</f-div>`; | ||
} else if (typeof widget.footer === "function") { | ||
return widget.footer(); | ||
} | ||
} | ||
|
||
return nothing; | ||
} | ||
|
||
export function renderWidget(widget: FDashboardWidget) { | ||
switch (widget.type) { | ||
case "big-number": | ||
return html`<f-div padding="medium" class="big-number">${widget.data.toFixed(2)}</f-div>`; | ||
|
||
case "timeseries": | ||
return html`<f-div padding="medium" | ||
><f-timeseries-chart .config=${widget.data}></f-timeseries-chart | ||
></f-div>`; | ||
|
||
default: | ||
return nothing; | ||
} | ||
} |
108 changes: 108 additions & 0 deletions
108
packages/flow-dashboard/src/components/f-dashboard/f-dashboard.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import { CSSResult, html, PropertyValueMap, unsafeCSS } from "lit"; | ||
import { property } from "lit/decorators.js"; | ||
import { FRoot, flowElement } from "@ollion/flow-core"; | ||
import globalStyle from "./f-dashboard-global.scss?inline"; | ||
import { injectCss } from "@ollion/flow-core-config"; | ||
import { GridStack } from "gridstack"; | ||
import { FDashboardConfig } from "../../types"; | ||
import { getWidgetHeader, renderWidget, getWidgetFooter } from "./f-dashboard-utils"; | ||
import { createRef, Ref, ref } from "lit/directives/ref.js"; | ||
|
||
import { keyed } from "lit/directives/keyed.js"; | ||
|
||
injectCss("f-dashboard", globalStyle); | ||
|
||
// const pollingWorker = new Worker(new URL("./polling-worker.ts", import.meta.url)); | ||
@flowElement("f-dashboard") | ||
export class FDashboard extends FRoot { | ||
/** | ||
* css loaded from scss file | ||
*/ | ||
static styles: CSSResult[] = [unsafeCSS(globalStyle)]; | ||
|
||
/** | ||
* @attribute comments baout title | ||
*/ | ||
@property({ type: Object }) | ||
config!: FDashboardConfig; | ||
|
||
/** | ||
* mention required fields here for generating vue types | ||
*/ | ||
readonly required = ["config"]; | ||
|
||
gridStack?: GridStack; | ||
|
||
gridStackElement: Ref<HTMLDivElement> = createRef<HTMLDivElement>(); | ||
|
||
createRenderRoot() { | ||
return this; | ||
} | ||
protected willUpdate( | ||
_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown> | ||
): void { | ||
if (this.gridStack) { | ||
// destroy existing grid | ||
this.gridStack.destroy(false); | ||
} | ||
} | ||
|
||
render() { | ||
return html` | ||
<div class="grid-stack" ${ref(this.gridStackElement)}> | ||
${this.config.widgets.map(wgt => { | ||
return keyed( | ||
wgt.id, | ||
html`<div | ||
id="${wgt.id}" | ||
class="grid-stack-item" | ||
gs-w="${wgt.placement.w}" | ||
gs-h="${wgt.placement.h}" | ||
> | ||
<div class="grid-stack-item-content"> | ||
${getWidgetHeader(wgt)}${renderWidget(wgt)}${getWidgetFooter(wgt)} | ||
</div> | ||
</div>` | ||
); | ||
})} | ||
</div> | ||
`; | ||
} | ||
|
||
protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void { | ||
super.updated(changedProperties); | ||
try { | ||
this.gridStack = GridStack.init({ margin: "4px" }); | ||
|
||
this.updateWidgetFontSize(); | ||
this.gridStack.on("resizecontent", () => { | ||
this.updateWidgetFontSize(); | ||
}); | ||
} catch (er) { | ||
//ignore girdstack error for now | ||
} | ||
} | ||
|
||
updateWidgetFontSize() { | ||
this.querySelectorAll<HTMLDivElement>(".grid-stack-item-content > .big-number").forEach( | ||
widgetContainer => { | ||
const wHeight = widgetContainer.offsetHeight; | ||
const wWidth = widgetContainer.offsetWidth; | ||
const fontSize = Math.min(wHeight, wWidth) * 0.3 + "px"; | ||
widgetContainer.style.fontSize = fontSize; | ||
widgetContainer.style.display = "flex"; | ||
widgetContainer.style.alignItems = "center"; | ||
widgetContainer.style.justifyContent = "center"; | ||
} | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* Required for typescript | ||
*/ | ||
declare global { | ||
export interface HTMLElementTagNameMap { | ||
"f-dashboard": FDashboard; | ||
} | ||
} |
110 changes: 110 additions & 0 deletions
110
packages/flow-dashboard/src/components/f-timeseries-chart/f-timeseries-chart-global.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
@import "../../../../flow-core/src/mixins/scss/mixins"; | ||
f-timeseries-chart { | ||
@include base(); | ||
display: flex; | ||
flex-direction: column; | ||
min-height: 100px; | ||
|
||
svg { | ||
.domain { | ||
stroke: var(--color-border-secondary); | ||
} | ||
.tick { | ||
line { | ||
stroke: var(--color-border-secondary); | ||
&.grid-line { | ||
stroke: var(--color-border-subtle); | ||
} | ||
} | ||
text { | ||
stroke: var(--color-text-secondary); | ||
} | ||
} | ||
.tooltip-line { | ||
stroke: var(--color-border-default); | ||
stroke-dasharray: 6; | ||
} | ||
.tooltip-point { | ||
fill: var(--color-primary-default); | ||
} | ||
.area-path, | ||
.bars { | ||
fill-opacity: 0.5; | ||
} | ||
} | ||
.f-chart-tooltip { | ||
position: fixed; | ||
pointer-events: none; | ||
z-index: 1; | ||
&.hide { | ||
display: none; | ||
} | ||
&.show { | ||
display: flex; | ||
} | ||
transition: | ||
left 0.2s linear, | ||
top 0.2s linear, | ||
bottom 0.2s linear, | ||
right 0.2s linear; | ||
} | ||
|
||
.disable-legend { | ||
opacity: 0.4; | ||
} | ||
|
||
.series-path, | ||
.custom-lines { | ||
transition: | ||
opacity 0.3s linear, | ||
stroke-width 0.3s linear; | ||
} | ||
.series-path.disable, | ||
.custom-lines.disable { | ||
opacity: 0.5; | ||
fill-opacity: 0.5; | ||
.bars { | ||
fill-opacity: 0.3; | ||
} | ||
} | ||
.series-path.active, | ||
.custom-lines.active { | ||
opacity: 1; | ||
fill-opacity: 1 !important; | ||
stroke-opacity: 1; | ||
.bars { | ||
fill-opacity: 1; | ||
} | ||
&.line-path { | ||
stroke-width: 2pt !important; | ||
} | ||
} | ||
|
||
.f-timeseries-wrapper { | ||
&[data-legends-position="top"] { | ||
flex-direction: column-reverse; | ||
} | ||
&[data-legends-position="left"] { | ||
flex-direction: row-reverse; | ||
} | ||
&[data-legends-position="right"] { | ||
flex-direction: row; | ||
} | ||
} | ||
} | ||
|
||
f-div[direction="column"] { | ||
> f-timeseries-chart { | ||
flex: 1 1; | ||
max-height: 100%; | ||
width: 100%; | ||
} | ||
} | ||
|
||
f-div[direction="row"] { | ||
> f-timeseries-chart { | ||
flex: 1 1; | ||
max-width: 100%; | ||
height: 100%; | ||
} | ||
} |
99 changes: 99 additions & 0 deletions
99
packages/flow-dashboard/src/components/f-timeseries-chart/f-timeseries-chart-types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import { HTMLTemplateResult } from "lit"; | ||
|
||
export type AxisLine = { | ||
value: number; | ||
color: string; | ||
}; | ||
|
||
export type YAxisLine = AxisLine; | ||
export type XAxisLine = AxisLine; | ||
export type TimeseriesPoint = { | ||
date: number; | ||
value: number; | ||
}; | ||
|
||
export type SeriesType = "line" | "bar" | "area"; | ||
export type TimeseriesData = { | ||
seriesName: string; | ||
points: TimeseriesPoint[]; | ||
color: string; | ||
type: SeriesType; | ||
disable?: boolean; | ||
}; | ||
|
||
export type FTimeseriesTickAuto = { | ||
type: "auto"; | ||
}; | ||
|
||
export type TickInterval = { | ||
type: "milliseconds" | "seconds" | "minutes" | "hours" | "days" | "months" | "years"; | ||
every: number; | ||
}; | ||
|
||
export type FTimeseriesXTickInterval = { | ||
type: "interval"; | ||
interval: TickInterval; | ||
}; | ||
|
||
export type FTimeseriesXTickValues = { | ||
type: "values"; | ||
values: Date[]; | ||
}; | ||
|
||
export type FTimeseriesYTickValues = { | ||
type: "values"; | ||
values: number[]; | ||
}; | ||
|
||
export type FTimeseriesXTickConfig = { | ||
format?: (tickDate: Date) => string; | ||
} & (FTimeseriesTickAuto | FTimeseriesXTickInterval | FTimeseriesXTickValues); | ||
|
||
export type FTimeseriesYTickConfig = { | ||
format?: (value: number) => string; | ||
} & (FTimeseriesTickAuto | FTimeseriesYTickValues); | ||
|
||
export type FTimeseriesLegendTemplate = ( | ||
interactions: FTimeseriesLegendInteraction | ||
) => HTMLTemplateResult; | ||
export type FTimeseriesLegendInteraction = { | ||
click: (seriesName: string) => void; | ||
mouseLeave: () => void; | ||
mouseEnter: (seriesName: string) => void; | ||
}; | ||
|
||
export type FTimeseriesChartConfig = { | ||
data: TimeseriesData[]; | ||
size?: { | ||
width?: number; | ||
height?: number; | ||
margin?: { | ||
top?: number; | ||
right?: number; | ||
left?: number; | ||
bottom?: number; | ||
}; | ||
}; | ||
xAxis?: { | ||
lines?: XAxisLine[]; | ||
tickConfig?: FTimeseriesXTickConfig; | ||
}; | ||
yAxis?: { | ||
lines?: YAxisLine[]; | ||
tickConfig?: FTimeseriesYTickConfig; | ||
}; | ||
legends?: { | ||
disabled?: boolean; | ||
position?: "bottom" | "left" | "right" | "top"; | ||
template?: FTimeseriesLegendTemplate; | ||
}; | ||
tooltipTemplate?: (tooltipDate: Date, tooltipPoints: TooltipPoints) => HTMLTemplateResult; | ||
}; | ||
|
||
export type TooltipPoints = { | ||
seriesName: string; | ||
value: number; | ||
color: string; | ||
type: SeriesType; | ||
date: number; | ||
}[]; |
54 changes: 54 additions & 0 deletions
54
packages/flow-dashboard/src/components/f-timeseries-chart/f-timeseries-chart-utils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { TickInterval, TooltipPoints } from "./f-timeseries-chart-types"; | ||
import * as d3 from "d3"; | ||
import { html } from "lit"; | ||
import { Subject } from "rxjs"; | ||
|
||
export const TOOLTIP_SYNC = new Subject<number>(); | ||
|
||
export function getTickInterval({ type, every }: TickInterval) { | ||
return d3.timeInterval( | ||
(_date: Date) => {}, | ||
(date: Date, _step: number) => { | ||
switch (type) { | ||
case "milliseconds": | ||
date.setMilliseconds(date.getMilliseconds() + every); | ||
break; | ||
case "seconds": | ||
date.setSeconds(date.getSeconds() + every); | ||
break; | ||
case "minutes": | ||
date.setMinutes(date.getMinutes() + every); | ||
break; | ||
case "hours": | ||
date.setHours(date.getHours() + every); | ||
break; | ||
case "days": | ||
date.setDate(date.getDate() + every); | ||
break; | ||
case "months": | ||
date.setMonth(date.getMonth() + every); | ||
break; | ||
case "years": | ||
date.setFullYear(date.getFullYear() + every); | ||
} | ||
} | ||
); | ||
} | ||
|
||
export function defaultTooltipTemplate(tooltipDate: Date, tooltipPoints: TooltipPoints) { | ||
return html`<f-div width="100%" direction="column" gap="small"> | ||
<f-text>Date : ${tooltipDate.toLocaleDateString()} ${tooltipDate.toLocaleTimeString()}</f-text> | ||
${tooltipPoints.map(point => { | ||
return html`<f-text | ||
>${point.seriesName} : | ||
<f-text inline weight="bold" .state=${"custom," + point.color} | ||
>${point?.value}</f-text | ||
></f-text | ||
>`; | ||
})} | ||
</f-div>`; | ||
} | ||
|
||
export function escapeSeriesName(name: string) { | ||
return name.replace(/[^a-zA-Z0-9]/g, "_"); | ||
} |
18 changes: 18 additions & 0 deletions
18
packages/flow-dashboard/src/components/f-timeseries-chart/f-timeseries-chart.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { expect } from "@open-wc/testing"; | ||
|
||
// IconPack to test | ||
import IconPack from "@ollion/flow-system-icon/dist/types/icon-pack"; | ||
// import flow-core elements | ||
import "@ollion/flow-core"; | ||
import "@ollion/flow-dashboard"; | ||
import { ConfigUtil } from "@ollion/flow-core"; | ||
import { FTimeseriesChart } from "@ollion/flow-dashboard"; | ||
|
||
ConfigUtil.setConfig({ iconPack: IconPack }); | ||
|
||
describe("f-timeseries-chart", () => { | ||
it("is defined", () => { | ||
const el = document.createElement("f-timeseries-chart"); | ||
expect(el).instanceOf(FTimeseriesChart); | ||
}); | ||
}); |
713 changes: 713 additions & 0 deletions
713
packages/flow-dashboard/src/components/f-timeseries-chart/f-timeseries-chart.ts
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export * from "./components/f-dashboard/f-dashboard"; | ||
export * from "./components/f-timeseries-chart/f-timeseries-chart"; | ||
export * from "./types"; | ||
export * from "./components/f-timeseries-chart/f-timeseries-chart-types"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { HTMLTemplateResult } from "lit"; | ||
import { FTimeseriesChartConfig } from "./components/f-timeseries-chart/f-timeseries-chart-types"; | ||
|
||
export type FDashboardConfig = { | ||
widgets: FDashboardWidget[]; | ||
}; | ||
|
||
export type FDashboardWidgetGridPlacement = { | ||
h: number; | ||
w: number; | ||
x?: number; | ||
y?: number; | ||
}; | ||
|
||
export type FDashboardWidgetCore<T> = { | ||
id: string; | ||
placement: FDashboardWidgetGridPlacement; | ||
data: T; | ||
header?: | ||
| { | ||
title: string; | ||
description?: string; | ||
} | ||
| (() => HTMLTemplateResult); | ||
footer?: string | (() => HTMLTemplateResult); | ||
}; | ||
|
||
export type FDashboardBigNumberWidget = FDashboardWidgetCore<number> & { | ||
type: "big-number"; | ||
dataType?: "storage" | "time" | "count" | "currency" | "percentage"; | ||
}; | ||
export type FDashboardWidget = FDashboardBigNumberWidget | FDashboardTimeseriesWidget; | ||
|
||
export type FDashboardTimeseriesWidget = FDashboardWidgetCore<FTimeseriesChartConfig> & { | ||
type: "timeseries"; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"extends": "../../tsconfig.json", | ||
"compilerOptions": { | ||
"outDir": "./dist" | ||
}, | ||
"include": ["src/**/*"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { defineConfig } from "vite"; | ||
|
||
export default defineConfig({ | ||
build: { | ||
// Disabling minification makes it easy to debug during development | ||
// And all modern bundlers will consume the library and minify it anyway | ||
minify: false, | ||
sourcemap: true, | ||
lib: { | ||
entry: "src/index.ts", | ||
name: "flow-dashboard", | ||
fileName: format => `flow-dashboard.${format}.js`, | ||
formats: ["es", "cjs"] | ||
}, | ||
rollupOptions: { | ||
// If we want to publish standalone components we don't externalize lit, | ||
// if you are going to use lit in your own project, you can make it a dep instead. | ||
// external: /^lit/, <-- comment this line | ||
external: ["@ollion/flow-core-config", "@ollion/flow-core", /^lit/], | ||
output: { | ||
globals: { | ||
"@ollion/flow-core": "@ollion/flow-core" | ||
} | ||
} | ||
} | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { defineConfig } from "vite"; | ||
|
||
/** | ||
* UMD build with no externals , to consume through CDN in static html files. | ||
*/ | ||
export default defineConfig({ | ||
build: { | ||
sourcemap: true, | ||
lib: { | ||
entry: "src/index.ts", | ||
name: "flowDashboard", | ||
fileName: format => `flow-dashboard.${format}.js`, | ||
formats: ["umd"] | ||
}, | ||
outDir: "umd" | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { esbuildPlugin } from "@web/dev-server-esbuild"; | ||
|
||
export default { | ||
plugins: [esbuildPlugin({ ts: true })] | ||
}; |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import { Meta } from "@storybook/web-components"; | ||
import { html } from "lit-html"; | ||
import { | ||
FDashboard, | ||
FDashboardConfig, | ||
FDashboardWidget, | ||
FTimeseriesChartConfig | ||
} from "@ollion/flow-dashboard"; | ||
import { generateTimeseriesChartData } from "./mock-data-utils"; | ||
import { faker } from "@faker-js/faker"; | ||
import { createRef, ref } from "lit/directives/ref.js"; | ||
|
||
export default { | ||
title: "@ollion/flow-dashboard/f-dashboard", | ||
argTypes: { | ||
field: { | ||
control: false | ||
} | ||
} | ||
} as Meta<any>; | ||
|
||
const getWidgets = () => { | ||
const iconsNames = [ | ||
"p-azure", | ||
"p-google", | ||
"p-aws", | ||
"p-hadoop", | ||
"p-sonarcloud", | ||
"p-snowflake", | ||
"p-terraform", | ||
"p-discord" | ||
]; | ||
const widgets: FDashboardWidget[] = []; | ||
const startFrom = new Date(); | ||
for (let index = 0; index < 10; index++) { | ||
if (index % 2 === 0) { | ||
widgets.push({ | ||
type: "timeseries", | ||
data: { | ||
data: generateTimeseriesChartData(startFrom) | ||
}, | ||
id: faker.string.alpha(10), | ||
header() { | ||
const name = faker.company.name(); | ||
const description = faker.lorem.sentences(3); | ||
return html`<f-div | ||
align="middle-left" | ||
height="hug-content" | ||
padding="medium" | ||
gap="medium" | ||
border="small solid subtle bottom" | ||
> | ||
<f-icon .source=${faker.helpers.arrayElement(iconsNames)} size="large"></f-icon> | ||
<f-div direction="column" align="middle-left"> | ||
<f-text ellipsis .tooltip=${name} variant="heading" weight="medium">${name}</f-text> | ||
<f-text ellipsis .tooltip=${description} size="small">${description}</f-text> | ||
</f-div> | ||
</f-div>`; | ||
}, | ||
footer: () => { | ||
const date = faker.date.recent({ refDate: new Date() }); | ||
const state = faker.helpers.arrayElement(["danger", "success", "warning"]); | ||
return html`<f-div | ||
padding="medium" | ||
gap="auto" | ||
border="small solid subtle top" | ||
height="hug-content" | ||
> | ||
<f-div gap="small" align="middle-left"> | ||
<f-icon source="i-clock-outline" size="small" .state=${state}></f-icon> | ||
<f-text .state=${state} size="small" | ||
>Last updated on ${date.toLocaleDateString()} ${date.toLocaleTimeString()}</f-text | ||
> | ||
</f-div> | ||
<f-button label="view details" size="x-small" icon-right="i-new-tab"></f-button> | ||
</f-div>`; | ||
}, | ||
placement: { | ||
w: faker.number.int({ min: 4, max: 8 }), | ||
h: faker.number.int({ min: 3, max: 4 }) | ||
} | ||
}); | ||
} else { | ||
widgets.push({ | ||
type: "big-number", | ||
data: faker.number.int({ min: 11, max: 999 }), | ||
dataType: "count", | ||
id: faker.string.alpha(10), | ||
header: { | ||
title: faker.company.name(), | ||
description: faker.lorem.sentences(3) | ||
}, | ||
footer: `Powered by Flow`, | ||
placement: { | ||
w: faker.number.int({ min: 1.5, max: 3 }), | ||
h: faker.number.int({ min: 1.5, max: 2 }) | ||
} | ||
}); | ||
} | ||
} | ||
|
||
return widgets; | ||
}; | ||
const Template = () => { | ||
const dashboardRef = createRef<FDashboard>(); | ||
const dashboardConfig: FDashboardConfig = { | ||
widgets: getWidgets() | ||
}; | ||
const randomize = () => { | ||
if (dashboardRef.value) { | ||
dashboardRef.value.config = { | ||
widgets: getWidgets() | ||
}; | ||
} | ||
}; | ||
|
||
return html`<f-div height="100%" width="100%" gap="small" direction="column"> | ||
<f-div | ||
variant="curved" | ||
state="primary" | ||
height="hug-content" | ||
padding="medium" | ||
gap="auto" | ||
align="middle-left" | ||
> | ||
<f-text state="inherit">Click on randomize button to generate new data</f-text> | ||
<f-button @click=${randomize} label="randomize"></f-button> | ||
</f-div> | ||
<f-dashboard ${ref(dashboardRef)} .config=${dashboardConfig}> </f-dashboard> | ||
</f-div>`; | ||
}; | ||
|
||
export const basic = Template.bind({}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,395 @@ | ||
import { faker } from "@faker-js/faker"; | ||
import { | ||
FTimeseriesChartConfig, | ||
FTimeseriesChart, | ||
YAxisLine, | ||
XAxisLine, | ||
TooltipPoints, | ||
TimeseriesData | ||
} from "@ollion/flow-dashboard"; | ||
import { html } from "lit-html"; | ||
import { createRef, ref } from "lit/directives/ref.js"; | ||
import { generateTimeseriesChartData } from "./mock-data-utils"; | ||
|
||
export default { | ||
title: "@ollion/flow-dashboard/f-timeseries-chart", | ||
|
||
parameters: { | ||
controls: { | ||
hideNoControlsWarning: true | ||
} | ||
} | ||
}; | ||
|
||
function getXYLines(chartData: TimeseriesData[]) { | ||
const yLines: YAxisLine[] = [ | ||
{ | ||
value: faker.number.int({ min: 150, max: 200 }), | ||
color: "var(--color-danger-default)" | ||
}, | ||
{ | ||
value: faker.number.int({ min: 50, max: 100 }), | ||
color: "var(--color-warning-default)" | ||
} | ||
]; | ||
|
||
const xLines: XAxisLine[] = [ | ||
{ | ||
value: chartData[0].points[+(chartData[0].points.length / 3).toFixed(0)].date, | ||
color: "yellow" | ||
}, | ||
{ | ||
value: chartData[0].points[+(chartData[0].points.length / 2).toFixed(0)].date, | ||
color: "yellow" | ||
} | ||
]; | ||
|
||
return { | ||
xLines, | ||
yLines | ||
}; | ||
} | ||
|
||
export const AllOptions = { | ||
render: () => { | ||
const chartData = generateTimeseriesChartData(new Date()); | ||
const { xLines, yLines } = getXYLines(chartData); | ||
|
||
const chartRef = createRef<FTimeseriesChart>(); | ||
|
||
const customTickValues = []; | ||
for (let d = 0; d < 10; d++) { | ||
const date = new Date(); | ||
date.setMinutes(date.getMinutes() + 15 * (d + 1)); | ||
customTickValues.push(date); | ||
} | ||
const chartConfig: FTimeseriesChartConfig = { | ||
data: chartData, | ||
xAxis: { | ||
lines: xLines, | ||
tickConfig: { | ||
format: (d: Date) => { | ||
return `${d.getHours()}h${d.getMinutes()}m`; | ||
}, | ||
// type: "auto" | ||
type: "interval", | ||
interval: { | ||
type: "minutes", | ||
every: 5 | ||
} | ||
// type: "values", | ||
// values: customTickValues | ||
} | ||
}, | ||
yAxis: { | ||
lines: yLines, | ||
tickConfig: { | ||
format: (value: number) => { | ||
return `#${value}`; | ||
}, | ||
type: "auto" | ||
// type: "values", | ||
// values: [50, 100] | ||
} | ||
}, | ||
legends: { | ||
disabled: false, | ||
position: "bottom", | ||
template: ({ click, mouseEnter, mouseLeave }) => { | ||
const icons = ["i-area", "i-bar", "i-line"]; | ||
return html`<f-div height="hug-content" gap="medium" align="middle-center"> | ||
${chartData.map((series, idx) => { | ||
return html`<f-div | ||
.id=${"legend-" + series.seriesName} | ||
class="timeseries-legend" | ||
width="hug-content" | ||
height="hug-content" | ||
@click=${() => click(series.seriesName)} | ||
@mouseenter=${() => mouseEnter(series.seriesName)} | ||
@mouseleave=${() => mouseLeave()} | ||
clickable | ||
align="middle-left" | ||
gap="small" | ||
> | ||
<f-icon-button | ||
.state=${"custom," + series.color} | ||
category="packed" | ||
size="medium" | ||
.icon=${icons[idx]} | ||
></f-icon-button> | ||
<f-text>${series.seriesName}</f-text></f-div | ||
>`; | ||
})} | ||
</f-div>`; | ||
} | ||
}, | ||
tooltipTemplate: (tooltipDate: Date, tooltipPoints: TooltipPoints) => { | ||
return html`<f-div | ||
width="280px" | ||
max-height="500px" | ||
overflow="scroll" | ||
direction="column" | ||
gap="small" | ||
> | ||
${tooltipPoints.map(point => { | ||
return html`<f-text weight="medium" .state=${"custom," + point.color} | ||
>${point.seriesName} : ${point?.value}</f-text | ||
>`; | ||
})} | ||
<f-divider state="subtle"></f-divider> | ||
<f-div align="middle-right" gap="x-small"> | ||
<f-text inline variant="code" size="small"> | ||
${tooltipDate.toLocaleDateString()} | ${tooltipDate.toLocaleTimeString()}</f-text | ||
> | ||
</f-div> | ||
</f-div>`; | ||
} | ||
}; | ||
|
||
const interval = setInterval(() => { | ||
const chartDataFlat = chartData.map(series => series.points).flat(); | ||
const newPoints = generateTimeseriesChartData( | ||
new Date(chartDataFlat[chartDataFlat.length - 1].date + 60 * 1000), | ||
chartData.length, | ||
1 | ||
); | ||
newPoints.forEach((element, idx) => { | ||
const series = chartData[idx]; | ||
series?.points.shift(); | ||
series?.points.push(...element.points); | ||
}); | ||
if (chartRef.value) { | ||
chartRef.value.config = { ...chartConfig }; | ||
} | ||
}, 1000); | ||
|
||
setTimeout(() => { | ||
clearInterval(interval); | ||
}, 3000); | ||
return html`<f-div height="500px"> | ||
<f-timeseries-chart ${ref(chartRef)} .config=${chartConfig}></f-timeseries-chart> | ||
</f-div>`; | ||
}, | ||
|
||
name: "all-options" | ||
}; | ||
|
||
export const CustomLegendTemplate = { | ||
render: () => { | ||
const chartData = generateTimeseriesChartData(new Date()); | ||
|
||
const chartRef = createRef<FTimeseriesChart>(); | ||
|
||
const chartConfig: FTimeseriesChartConfig = { | ||
data: chartData, | ||
xAxis: { | ||
tickConfig: { | ||
format: (d: Date) => { | ||
return `${d.getHours()}h${d.getMinutes()}m`; | ||
}, | ||
// type: "auto" | ||
type: "interval", | ||
interval: { | ||
type: "minutes", | ||
every: 5 | ||
} | ||
// type: "values", | ||
// values: customTickValues | ||
} | ||
}, | ||
yAxis: { | ||
tickConfig: { | ||
format: (value: number) => { | ||
return `#${value}`; | ||
}, | ||
type: "auto" | ||
// type: "values", | ||
// values: [50, 100] | ||
} | ||
}, | ||
legends: { | ||
disabled: false, | ||
position: "bottom", | ||
template: ({ click, mouseEnter, mouseLeave }) => { | ||
const icons = ["i-user", "i-home", "i-computer"]; | ||
return html`<f-div height="hug-content" align="middle-center"> | ||
${chartData.map((series, idx) => { | ||
return html`<f-div | ||
.id=${"legend-" + series.seriesName} | ||
class="timeseries-legend" | ||
width="hug-content" | ||
height="hug-content" | ||
padding="small medium" | ||
@click=${() => click(series.seriesName)} | ||
@mouseenter=${() => mouseEnter(series.seriesName)} | ||
@mouseleave=${() => mouseLeave()} | ||
clickable | ||
align="middle-left" | ||
gap="small" | ||
> | ||
<f-icon-button | ||
.state=${"custom," + series.color} | ||
category="packed" | ||
size="small" | ||
.icon=${icons[idx]} | ||
></f-icon-button> | ||
<f-text .state=${"custom," + series.color}>${series.seriesName}</f-text></f-div | ||
>`; | ||
})} | ||
</f-div>`; | ||
} | ||
} | ||
}; | ||
return html`<f-div height="500px"> | ||
<f-timeseries-chart ${ref(chartRef)} .config=${chartConfig}></f-timeseries-chart> | ||
</f-div>`; | ||
}, | ||
|
||
name: "legends-template" | ||
}; | ||
|
||
export const Lines = { | ||
render: () => { | ||
const chartData = generateTimeseriesChartData(new Date()); | ||
|
||
const { xLines, yLines } = getXYLines(chartData); | ||
|
||
const chartRef = createRef<FTimeseriesChart>(); | ||
|
||
const chartConfig: FTimeseriesChartConfig = { | ||
data: chartData, | ||
xAxis: { | ||
lines: xLines | ||
}, | ||
yAxis: { | ||
lines: yLines | ||
} | ||
}; | ||
|
||
return html`<f-div height="500px"> | ||
<f-timeseries-chart ${ref(chartRef)} .config=${chartConfig}></f-timeseries-chart> | ||
</f-div>`; | ||
}, | ||
|
||
name: "x-&-y-lines" | ||
}; | ||
|
||
export const CustomTooltip = { | ||
render: () => { | ||
const chartData = generateTimeseriesChartData(new Date()); | ||
|
||
const chartRef = createRef<FTimeseriesChart>(); | ||
|
||
const chartConfig: FTimeseriesChartConfig = { | ||
data: chartData, | ||
|
||
tooltipTemplate: (tooltipDate: Date, tooltipPoints: TooltipPoints) => { | ||
return html`<f-div | ||
width="280px" | ||
max-height="500px" | ||
overflow="scroll" | ||
direction="column" | ||
gap="small" | ||
> | ||
${tooltipPoints.map(point => { | ||
return html`<f-text weight="medium" .state=${"custom," + point.color} | ||
>${point.seriesName} : ${point?.value}</f-text | ||
>`; | ||
})} | ||
<f-divider state="subtle"></f-divider> | ||
<f-div align="middle-right" gap="x-small"> | ||
<f-text inline variant="code" size="small"> | ||
${tooltipDate.toLocaleDateString()} | ${tooltipDate.toLocaleTimeString()}</f-text | ||
> | ||
</f-div> | ||
</f-div>`; | ||
} | ||
}; | ||
|
||
return html`<f-div height="500px"> | ||
<f-timeseries-chart ${ref(chartRef)} .config=${chartConfig}></f-timeseries-chart> | ||
</f-div>`; | ||
}, | ||
|
||
name: "tooltip-template" | ||
}; | ||
|
||
export const TickFormat = { | ||
render: () => { | ||
const chartData = generateTimeseriesChartData(new Date()); | ||
|
||
const chartRef = createRef<FTimeseriesChart>(); | ||
|
||
const chartConfig: FTimeseriesChartConfig = { | ||
data: chartData, | ||
xAxis: { | ||
tickConfig: { | ||
format: (d: Date) => { | ||
return `${d.getHours()}h${d.getMinutes()}m`; | ||
}, | ||
type: "auto" | ||
} | ||
}, | ||
yAxis: { | ||
tickConfig: { | ||
format: (value: number) => { | ||
return `#${value}`; | ||
}, | ||
type: "auto" | ||
} | ||
} | ||
}; | ||
|
||
return html`<f-div height="500px"> | ||
<f-timeseries-chart ${ref(chartRef)} .config=${chartConfig}></f-timeseries-chart> | ||
</f-div>`; | ||
}, | ||
|
||
name: "tick-format" | ||
}; | ||
|
||
export const Realtime = { | ||
render: () => { | ||
const chartData = generateTimeseriesChartData(new Date()); | ||
|
||
const { xLines, yLines } = getXYLines(chartData); | ||
|
||
const chartRef = createRef<FTimeseriesChart>(); | ||
|
||
const chartConfig: FTimeseriesChartConfig = { | ||
data: chartData, | ||
xAxis: { | ||
lines: xLines | ||
}, | ||
yAxis: { | ||
lines: yLines | ||
} | ||
}; | ||
|
||
const interval = setInterval(() => { | ||
const chartDataFlat = chartData.map(series => series.points).flat(); | ||
const newPoints = generateTimeseriesChartData( | ||
new Date(chartDataFlat[chartDataFlat.length - 1].date + 60 * 1000), | ||
chartData.length, | ||
1 | ||
); | ||
newPoints.forEach((element, idx) => { | ||
const series = chartData[idx]; | ||
series?.points.shift(); | ||
series?.points.push(...element.points); | ||
}); | ||
if (chartRef.value) { | ||
chartRef.value.config = { ...chartConfig }; | ||
} | ||
}, 1000); | ||
|
||
setTimeout(() => { | ||
clearInterval(interval); | ||
}, 60000 * 60); | ||
return html`<f-div height="500px"> | ||
<f-timeseries-chart ${ref(chartRef)} .config=${chartConfig}></f-timeseries-chart> | ||
</f-div>`; | ||
}, | ||
|
||
name: "realtime-data" | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { TimeseriesData, TimeseriesPoint } from "@ollion/flow-dashboard"; | ||
import { faker } from "@faker-js/faker"; | ||
|
||
export function getColor() { | ||
return "#" + Math.floor(faker.number.float({ min: 0, max: 1 }) * 16777215).toString(16); | ||
} | ||
|
||
export function generateTimeseriesChartData( | ||
from?: Date, | ||
seriesCount?: number, | ||
pointsCount?: number | ||
): TimeseriesData[] { | ||
const startFrom = new Date().getTime(); | ||
const masterData: TimeseriesData[] = []; | ||
|
||
const numberOfPoints = pointsCount ?? 150; //faker.number.int({ min: 50, max: 150 }); | ||
const numberOfSeries = seriesCount ?? faker.number.int({ min: 1, max: 3 }); | ||
const colors = [ | ||
"#66c2ff", | ||
"#ff6666", | ||
"#99ff99", | ||
"#ffb366", | ||
"#cc99ff", | ||
"#99ccff", | ||
"#ffcc99", | ||
"#66ff99", | ||
"#ff99cc", | ||
"#ccccff" | ||
]; | ||
const seriesColors = faker.helpers.arrayElements(colors, numberOfSeries); | ||
for (let j = 0; j < numberOfSeries; j++) { | ||
const startDate = from ? from.getTime() : startFrom; | ||
const points: TimeseriesPoint[] = []; | ||
for (let i = 0; i < numberOfPoints; i++) { | ||
const currentDate = startDate + i * 60 * 1000; | ||
let fluctuatingValue = Math.floor(faker.number.float({ min: 0, max: 1 }) * 10) + 50 * (j + 1); //faker.number.float({ min: 0, max: 1 }) * (yOffSet ?? 100) + Math.sin(i / 8) * 50; // Adding a sine wave for fluctuation | ||
if (fluctuatingValue < 0) { | ||
fluctuatingValue *= -1; | ||
} | ||
if (fluctuatingValue % 9 === 0) { | ||
fluctuatingValue = 50 * (j + 1) * getRndInteger(1, 2); | ||
} | ||
const dataPoint: TimeseriesPoint = { | ||
date: currentDate, | ||
value: +fluctuatingValue.toFixed(0) | ||
}; | ||
|
||
points.push(dataPoint); | ||
} | ||
masterData.push({ | ||
seriesName: faker.location.country(), | ||
points, | ||
color: seriesColors[j], | ||
type: faker.helpers.arrayElement(["line", "bar", "area"]) | ||
}); | ||
} | ||
|
||
return masterData; | ||
} | ||
|
||
export function getRndInteger(min: number, max: number) { | ||
return faker.number.int({ min, max }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters