Skip to content

Commit cee1dfd

Browse files
BennuFiredekelpaznielsdejong
authored
Gauge Chart (#223)
* added new gauge chart type (react-gauge-chart) * Gauge 0.1 * Added docs for Gauge chart * Gauge 0.4 * Added docs for gauge * Added value type handling for gauge * Gauge 0.6 * Added test for gauge chart * Gauge 0.9 Example and Margins * Removed reference to old record mapper Co-authored-by: Dekel Paz <[email protected]> Co-authored-by: Niels de Jong <[email protected]>
1 parent b870e6a commit cee1dfd

File tree

15 files changed

+455
-264
lines changed

15 files changed

+455
-264
lines changed

cypress/fixtures/cypher_queries.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cypress/integration/start_page.spec.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { tableCypherQuery, barChartCypherQuery, mapChartCypherQuery, sunburstChartCypherQuery, iFrameText, markdownText, loadDashboardURL, sankeyChartCypherQuery } from "../fixtures/cypher_queries"
1+
import { tableCypherQuery, barChartCypherQuery, mapChartCypherQuery, sunburstChartCypherQuery, iFrameText, markdownText, loadDashboardURL, sankeyChartCypherQuery, gaugeChartCypherQuery } from "../fixtures/cypher_queries"
22

33
// Ignore warnings that may appear when using the Cypress dev server
44
Cypress.on('uncaught:exception', (err, runnable) => {
@@ -105,6 +105,11 @@ describe('NeoDash E2E Tests', () => {
105105
cy.get('main .react-grid-item:eq(2) .MuiCardContent-root > div > div:nth-child(2) > span').contains('1,999')
106106
})
107107

108+
it('creates a gauge chart report', () => {
109+
createReportOfType('Gauge Chart', gaugeChartCypherQuery)
110+
cy.get('.text-group > text').contains('69')
111+
})
112+
108113
it('creates a sunburst chart report', () => {
109114
createReportOfType('Sunburst Chart', sunburstChartCypherQuery)
110115
cy.get('main .react-grid-item:eq(2) .MuiCardActions-root .MuiInputLabel-root').contains('Path').next()

docs/modules/ROOT/images/gauge.png

297 KB
Loading

docs/modules/ROOT/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*** xref:user-guide/reports/map.adoc[Map]
1818
*** xref:user-guide/reports/choropleth.adoc[Choropleth]
1919
*** xref:user-guide/reports/single-value.adoc[Single Value]
20+
*** xref:user-guide/reports/gauge-chart.adoc[Gauge Chart]
2021
*** xref:user-guide/reports/raw-json.adoc[Raw JSON]
2122
*** xref:user-guide/reports/parameter-select.adoc[Parameter Select]
2223
*** xref:user-guide/reports/iframe.adoc[iFrame]
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
= Gauge Chart
2+
3+
A gauge chart takes a single numeric value, and plots it on an animated gauge:
4+
5+
- The value returned should be in the range of 0 to 100.
6+
- The gauge chart can be customized with different colors and levels (arc segments).
7+
8+
== Examples
9+
10+
=== Basic Gauge Chart
11+
12+
[source,cypher]
13+
----
14+
MATCH (c:CPU)
15+
WHERE c.id = 1
16+
RETURN c.load_percentage * 100
17+
----
18+
19+
image::gauge.png[Gauge Chart]
20+
21+
== Advanced Settings
22+
23+
24+
[width="100%",cols="15%,2%,6%,77%",options="header",]
25+
|===
26+
|Name |Type |Default Value |Description
27+
|Number of levels | number | 3 | The number of distinct colored levels in the gauge.
28+
29+
| Comma-separated length of each arc | List | "0.15, 0.55, 0.3" | A comma-separated list of length for each of the colored arc segments on the gauge.
30+
31+
| Comma-separated arc colors | List | "#5BE12C, #F5CD19, #EA4228" | The HEX color values to assign to each arc.
32+
33+
| Color of the text | string | black | The color of the number on the gauge.
34+
35+
| Delay in ms before needle animation | number | 0 | Delay in milliseconds before starting the animation.
36+
37+
| Duration in ms for needle animation | number | 2000 | The duration of the moving needle animation when the chart renders.
38+
39+
|===
40+

docs/modules/ROOT/pages/user-guide/reports/index.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ pages:
117117
- link:choropleth[Choropleth Chart]
118118
- link:single-value[Single Value]
119119
- link:sankey[Sankey Chart]
120+
- link:gauge[Gauge Chart]
120121
- link:raw-json[Raw JSON]
121122
- link:parameter-select[Parameter Select]
122123
- link:iframe[iFrame]

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@
7272
"redux-thunk": "^2.4.1",
7373
"remark-gfm": "^3.0.1",
7474
"reselect": "^4.1.5",
75-
"use-neo4j": "^0.3.13"
75+
"use-neo4j": "^0.3.13",
76+
"react-gauge-chart": "^0.4.0"
7677
},
7778
"devDependencies": {
7879
"@babel/cli": "^7.16.8",

src/card/view/CardView.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ const NeoCardView = ({ title, database, query, globalParameters,
4949
showOptionalSelections={(settings["showOptionalSelections"])} >
5050
</NeoCardViewFooter> : <></>;
5151

52-
const withoutFooter = !REPORT_TYPES[type].selection || (settings && settings.hideSelections);
52+
const withoutFooter = REPORT_TYPES[type].withoutFooter ? REPORT_TYPES[type].withoutFooter : !REPORT_TYPES[type].selection || (settings && settings.hideSelections);
5353

5454
const getGlobalParameter = (key: string): any => {
5555
return globalParameters ? globalParameters[key] : undefined;

src/chart/SankeyChart.tsx

Lines changed: 0 additions & 18 deletions
This file was deleted.

src/chart/gauge/GaugeChart.tsx

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import React from 'react';
2+
import { ChartProps } from '../Chart';
3+
import GaugeChart from 'react-gauge-chart'
4+
import { createUUID } from '../../dashboard/DashboardThunks'
5+
import { NoDrawableDataErrorMessage } from "../../component/editor/CodeViewerComponent";
6+
7+
/**
8+
* Based on https://github.com/dekelpaz PR https://github.com/neo4j-labs/neodash/pull/191
9+
*/
10+
const NeoGaugeChart = (props: ChartProps) => {
11+
12+
const records = props.records;
13+
const selection = props.selection;
14+
const settings = props.settings;
15+
16+
17+
18+
if (!selection || props.records == null || props.records.length == 0 || props.records[0].keys == null) {
19+
return <NoDrawableDataErrorMessage />
20+
}
21+
/**
22+
* This visualization was extracted from https://github.com/Martin36/react-gauge-chart.
23+
*/
24+
25+
const nrOfLevels = settings.nrOfLevels ? props.settings.nrOfLevels : 3;
26+
const arcsLength = settings.arcsLength ? props.settings.arcsLength : "0.15, 0.55, 0.3";
27+
const arcPadding = props.settings.arcPadding ? props.settings.arcPadding : 0.02;
28+
const colors = props.settings.colors ? props.settings.colors : "#5BE12C, #F5CD19, #EA4228";
29+
const textColor = props.settings.textColor ? props.settings.textColor : "black";
30+
const animDelay = props.settings.animDelay ? props.settings.animDelay : 0;
31+
const animateDuration = props.settings.animateDuration ? props.settings.animateDuration : 2000;
32+
const marginRight = (settings["marginRight"]) ? settings["marginRight"] : 24;
33+
const marginLeft = (settings["marginLeft"]) ? settings["marginLeft"] : 24;
34+
const marginTop = (settings["marginTop"]) ? settings["marginTop"] : 40;
35+
const marginBottom = (settings["marginBottom"]) ? settings["marginBottom"] : 40;
36+
37+
let arcsLengthN = arcsLength.split(",").map(
38+
e => parseFloat(e.trim())
39+
);
40+
41+
if ((arcsLengthN.filter(e => isNaN(e)).length > 0) || (arcsLengthN.length != nrOfLevels))
42+
arcsLengthN = Array(nrOfLevels).fill(1);
43+
const sumArcs = arcsLengthN.reduce(
44+
(previousValue, currentValue) => previousValue + currentValue,
45+
0
46+
);
47+
arcsLengthN = arcsLengthN.map(e => e / sumArcs);
48+
49+
const chartId = createUUID();
50+
let score = (records && records[0] && records[0]["_fields"] && records[0]["_fields"][0]) ? records[0]["_fields"][0] : "";
51+
52+
if (isNaN(score)) return <NoDrawableDataErrorMessage />
53+
if (score.low != undefined) score = score.low;
54+
if (score >= 0) score = score / 100; // supporting older versions of Neo4j which don't support round to 2 decimal points
55+
56+
return <div style={{ position: "relative", top: "40%", transform: "translateY(-50%)" }}>
57+
{typeof (score) == "number" ?
58+
<GaugeChart
59+
id={chartId}
60+
nrOfLevels={nrOfLevels}
61+
percent={score}
62+
arcsLength={arcsLengthN}
63+
arcPadding={arcPadding}
64+
colors={colors.split(", ")}
65+
textColor={textColor}
66+
style={{ marginTop: marginTop, marginRight: marginRight, marginBottom: marginBottom, marginLeft : marginLeft }}
67+
animDelay={animDelay}
68+
animateDuration={animateDuration}
69+
/> : <></>}
70+
</div>
71+
72+
}
73+
74+
export default NeoGaugeChart;

0 commit comments

Comments
 (0)