diff --git a/src/data/nav.yml b/src/data/nav.yml
index 39ceb71ed..4b8e4eab1 100644
--- a/src/data/nav.yml
+++ b/src/data/nav.yml
@@ -66,12 +66,15 @@
url: '/build-apps/howto-use-nrone-table-components'
- title: Add, query, and mutate data using NerdStorage
url: '/build-apps/add-query-mutate-data-nerdstorage'
- - title: Custom visualizations and the New Relic One SDK
- url: '/build-apps/custom-visualizations-and-the-new-relic-one-sdk'
- - title: Customize visualizations with configuration
- url: '/build-apps/customize-visualizations-with-configuration'
- - title: Add custom visualizations to your dashboards
- url: '/build-apps/add-visualizations-to-dashboard'
+ - title: Display your data in different ways with a custom visualization
+ url: '/build-apps/custom-viz-alternate-charts'
+ pages:
+ - title: Custom visualizations and the New Relic One SDK
+ url: '/build-apps/custom-visualizations-and-the-new-relic-one-sdk'
+ - title: Customize visualizations with configuration
+ url: '/build-apps/customize-visualizations-with-configuration'
+ - title: Add custom visualizations to your dashboards
+ url: '/build-apps/add-visualizations-to-dashboard'
- title: Build an A/B test application
url: '/ab-test'
pages:
diff --git a/src/images/build-an-app/radar-chart-with-segmented-control.png b/src/images/build-an-app/radar-chart-with-segmented-control.png
deleted file mode 100644
index 25de75ac4..000000000
Binary files a/src/images/build-an-app/radar-chart-with-segmented-control.png and /dev/null differ
diff --git a/src/images/build-an-app/scrolled-custom-visualization-treemap-radar.png b/src/images/build-an-app/scrolled-custom-visualization-treemap-radar.png
deleted file mode 100644
index a1e447a5b..000000000
Binary files a/src/images/build-an-app/scrolled-custom-visualization-treemap-radar.png and /dev/null differ
diff --git a/src/images/custom-viz/nav-to-radar-or-treemap-viz.png b/src/images/custom-viz/nav-to-radar-or-treemap-viz.png
new file mode 100644
index 000000000..8d475154d
Binary files /dev/null and b/src/images/custom-viz/nav-to-radar-or-treemap-viz.png differ
diff --git a/src/images/custom-viz/radar-and-treemap.png b/src/images/custom-viz/radar-and-treemap.png
new file mode 100644
index 000000000..a4b0b08c8
Binary files /dev/null and b/src/images/custom-viz/radar-and-treemap.png differ
diff --git a/src/images/custom-viz/radar-chart-with-segmented-control.png b/src/images/custom-viz/radar-chart-with-segmented-control.png
new file mode 100644
index 000000000..1b16bd45f
Binary files /dev/null and b/src/images/custom-viz/radar-chart-with-segmented-control.png differ
diff --git a/src/images/custom-viz/radar-or-treemap-viz-logs.png b/src/images/custom-viz/radar-or-treemap-viz-logs.png
new file mode 100644
index 000000000..0c8fd8631
Binary files /dev/null and b/src/images/custom-viz/radar-or-treemap-viz-logs.png differ
diff --git a/src/images/custom-viz/radar-selected.png b/src/images/custom-viz/radar-selected.png
new file mode 100644
index 000000000..5aa21d7f8
Binary files /dev/null and b/src/images/custom-viz/radar-selected.png differ
diff --git a/src/images/custom-viz/treemap-selected.png b/src/images/custom-viz/treemap-selected.png
new file mode 100644
index 000000000..9f128a2bd
Binary files /dev/null and b/src/images/custom-viz/treemap-selected.png differ
diff --git a/src/markdown-pages/build-apps/customize-visualization-with-New-Relic-components.mdx b/src/markdown-pages/build-apps/customize-visualization-with-New-Relic-components.mdx
index afb79b7b8..c1ed65918 100644
--- a/src/markdown-pages/build-apps/customize-visualization-with-New-Relic-components.mdx
+++ b/src/markdown-pages/build-apps/customize-visualization-with-New-Relic-components.mdx
@@ -7,39 +7,95 @@ description: 'Customize your visualization'
resources:
- title: Build a custom visualization for dashboards
url: '/build-apps/build-visualization'
- - title: New Relic One VSCode extension
- url: https://marketplace.visualstudio.com/items?itemName=new-relic.nr1
- - title: 'Build on New Relic One'
- url: https://docs.newrelic.com/docs/new-relic-one/use-new-relic-one/build-new-relic-one/new-relic-one-build-your-own-custom-new-relic-one-application
- - title: New Relic VSCode extension pack
- url: https://marketplace.visualstudio.com/items?itemName=new-relic.new-relic-extension-pack
+ - title: Dashboards and Custom Visualizations
+ url: https://www.youtube.com/watch?v=_F61mxtKfGA
+ - title: 'Configuring custom visualizations for dashboards'
+ url: https://www.youtube.com/watch?v=sFpG_iG7Xa8
+ - title: Custom Data Visualizations on New Relic
+ url: https://www.youtube.com/watch?v=HuR0EdHGz24
tags:
- nr1 cli
- NR One Catalog
- Subscribe visualizations
---
+
+
+This lesson is part of a course that teaches you how to build a New Relic One custom visualization from the ground up. If you haven't already, check out the [course introduction](/build-apps/ab-test).
+
+Each lesson in the course builds upon the last, so make sure you've completed the last lesson, [_Present an end test confirmation modal_](../confirmation-modal), before starting this one.
+
+
+
-Now that you have a basic visualization, it's time to customize it! You can use all of the New Relic One SDK components in a Custom Visualization the same way you can use them in a Nerdlet. In this guide, you'll add a new chart type and a `SegmentedControl` component. You'll be able to dynamically swap between the Radar chart and the new chart right from the browser.
+Use New Relic One custom visualizations to display your data, whether it's from New Relic's database or an external source, in unique ways that are distinct from the charts offered by the New Relic platform.
-This guide builds off the Build a custom visualization for dashboards guide.
+In this lesson, you build a visualization that displays your data in one of two chart types: [`RadarChart`](https://recharts.org/en-US/api/RadarChart) or [`Treemap`](https://recharts.org/en-US/api/Treemap). You then implement a `SegmentedControl` component from the New Relic One SDK, which allows you to alternate between the two chart types. Ultimately, this gives you freedom to view your data in a dynamic way that isn't possible with New Relic's base offerings.
## Before you begin
-To get started, follow the Build a custom visualization for dashboards guide to get set up with your New Relic account, install the New Relic One CLI, and create your first visualization. You'll use the visualization you create in that guide as a starting point for this guide.
+Explore our [custom visualization](/explore-docs/custom-viz) guides and [build your first visualization](/explore-docs/custom-viz/build-visualization). After you're done, you'll have a better foundation for building more complex visualizations, such as the one you'll build in this course.
+
+Finally, if you haven't already:
+
+- Sign up for a [New Relic account](https://newrelic.com/signup?utm_source=developer-site)
+- Install [Node.js](https://nodejs.org/en/download/)
+- Complete the steps in the [`nr1` quick start](https://one.newrelic.com/launcher/developer-center.launcher?pane=eyJuZXJkbGV0SWQiOiJkZXZlbG9wZXItY2VudGVyLmRldmVsb3Blci1jZW50ZXIifQ==) to install and configure the CLI
+
+## Create your visualization
+
+
+
+
+
+Ensure you're working with the latest version of the New Relic One CLI:
+
+```bash
+nr1 update
+```
+
+
-## Set up the visualization component state
+
-In this first set of steps you'll add component state to your visualization template from the previous guide referenced above.
+Create a Nerdpack:
+
+```bash
+nr1 create --type nerdpack --name alternate-viz
+```
+
+If you receive a `RequestError` for a self-signed certificate when you run `nr1 create`, you may need to add a certificate to Node's certificate chain. Read more about this and other advanced configurations in [Enable advanced configurations for your Nerdpack](/build-apps/advanced-config).
+
+
+
+
+
+From the root of your Nerdpack, create a visualization:
+
+```bash
+cd alternate-viz
+nr1 create --type visualization --name radar-or-treemap
+```
+
+As a result, you have a new `visualizations/radar-or-treemap` directory:
+
+```bash
+ls visualizations/radar-or-treemap
+[output] index.js nr1.json styles.scss
+```
+
+
+
+
-```jsx fileName=visualizations/your-visualization/index.js
+```js fileName=visualizations/radar-or-treemap/index.js
import React from 'react';
import PropTypes from 'prop-types';
import {
@@ -49,16 +105,9 @@ import {
PolarAngleAxis,
PolarRadiusAxis,
} from 'recharts';
-import {
- Card,
- CardBody,
- HeadingText,
- NrqlQuery,
- Spinner,
- AutoSizer
-} from 'nr1';
+import {Card, CardBody, HeadingText, NrqlQuery, Spinner, AutoSizer} from 'nr1';
-export default class YourAwesomeVisualization extends React.Component {
+export default class RadarOrTreemapVisualization extends React.Component {
// Custom props you wish to be configurable in the UI must also be defined in
// the nr1.json file for the visualization. See docs for more details.
static propTypes = {
@@ -162,7 +211,6 @@ export default class YourAwesomeVisualization extends React.Component {
}
}
-
const EmptyState = () => (
@@ -182,6 +230,7 @@ const EmptyState = () => (
);
+
const ErrorState = () => (
@@ -199,16 +248,23 @@ const ErrorState = () => (
+## Set up your component state
+
+Add component state to the default visualization template that `nr1` created for you.
+
-
+
+
+Navigate to _alternate-viz/visualizations/radar-or-treemap/index.js_. You'll work in _index.js_ for the rest of this guide.
-From the root of the Nerdpack project you created in the previous guide, navigate to `/visualizations//index.js`. You'll continue to work in the `index.js` file for the rest of this guide.
+
-Add a chart types constant above the first line of the class and add the component state property with an initial state for `selectedChart`:
+
+Add a constant called `CHART_TYPES`:
-```jsx fileName=visualizations/your-visualization/index.js
+```js fileName=visualizations/radar-or-treemap/index.js
import React from 'react';
import PropTypes from 'prop-types';
import {
@@ -218,21 +274,178 @@ import {
PolarAngleAxis,
PolarRadiusAxis,
} from 'recharts';
+import {Card, CardBody, HeadingText, NrqlQuery, Spinner, AutoSizer} from 'nr1';
+
+const CHART_TYPES = {
+ 'Radar': 'radar',
+ 'Treemap': 'treemap'
+}
+
+export default class RadarOrTreemapVisualization extends React.Component {
+ // Custom props you wish to be configurable in the UI must also be defined in
+ // the nr1.json file for the visualization. See docs for more details.
+ static propTypes = {
+ /**
+ * A fill color to override the default fill color. This is an example of
+ * a custom chart configuration.
+ */
+ fill: PropTypes.string,
+
+ /**
+ * A stroke color to override the default stroke color. This is an example of
+ * a custom chart configuration.
+ */
+ stroke: PropTypes.string,
+ /**
+ * An array of objects consisting of a nrql `query` and `accountId`.
+ * This should be a standard prop for any NRQL based visualizations.
+ */
+ nrqlQueries: PropTypes.arrayOf(
+ PropTypes.shape({
+ accountId: PropTypes.number,
+ query: PropTypes.string,
+ })
+ ),
+ };
+
+ /**
+ * Restructure the data for a non-time-series, facet-based NRQL query into a
+ * form accepted by the Recharts library's RadarChart.
+ * (https://recharts.org/api/RadarChart).
+ */
+ transformData = (rawData) => {
+ return rawData.map((entry) => ({
+ name: entry.metadata.name,
+ // Only grabbing the first data value because this is not time-series data.
+ value: entry.data[0].y,
+ }));
+ };
+
+ /**
+ * Format the given axis tick's numeric value into a string for display.
+ */
+ formatTick = (value) => {
+ return value.toLocaleString();
+ };
+
+ render() {
+ const {nrqlQueries, stroke, fill} = this.props;
+
+ const nrqlQueryPropsAvailable =
+ nrqlQueries &&
+ nrqlQueries[0] &&
+ nrqlQueries[0].accountId &&
+ nrqlQueries[0].query;
+
+ if (!nrqlQueryPropsAvailable) {
+ return ;
+ }
+
+ return (
+
+ {({width, height}) => (
+
+ {({data, loading, error}) => {
+ if (loading) {
+ return ;
+ }
+
+ if (error) {
+ return ;
+ }
+
+ const transformedData = this.transformData(data);
+
+ return (
+
+
+
+
+
+
+ );
+ }}
+
+ )}
+
+ );
+ }
+}
+
+const EmptyState = () => (
+
+
+
+ Please provide at least one NRQL query & account ID pair
+
+
+ An example NRQL query you can try is:
+
+ FROM NrUsage SELECT sum(usage) FACET metric SINCE 1 week ago
+
+
+);
+
+const ErrorState = () => (
+
+
+
+ Oops! Something went wrong.
+
+
+
+);
+```
+
+`CHART_TYPES` enumerates the two chart types you'll be able to alternate between in your visualization.
+
+
+
+
+
+Initialize `selectedChart` in your component's `state`:
+
+```js fileName=visualizations/radar-or-treemap/index.js
+import React from 'react';
+import PropTypes from 'prop-types';
import {
- Card,
- CardBody,
- HeadingText,
- NrqlQuery,
- Spinner,
- AutoSizer
-} from 'nr1';
+ Radar,
+ RadarChart,
+ PolarGrid,
+ PolarAngleAxis,
+ PolarRadiusAxis,
+} from 'recharts';
+import {Card, CardBody, HeadingText, NrqlQuery, Spinner, AutoSizer} from 'nr1';
const CHART_TYPES = {
'Radar': 'radar',
'Treemap': 'treemap'
}
-export default class YourAwesomeVisualization extends React.Component {
+export default class RadarOrTreemapVisualization extends React.Component {
// Custom props you wish to be configurable in the UI must also be defined in
// the nr1.json file for the visualization. See docs for more details.
static propTypes = {
@@ -260,8 +473,8 @@ export default class YourAwesomeVisualization extends React.Component {
};
state = {
- selectedChart: CHART_TYPES.Radar
- }
+ selectedChart: CHART_TYPES.Radar,
+ };
/**
* Restructure the data for a non-time-series, facet-based NRQL query into a
@@ -340,7 +553,6 @@ export default class YourAwesomeVisualization extends React.Component {
}
}
-
const EmptyState = () => (
@@ -360,6 +572,7 @@ const EmptyState = () => (
);
+
const ErrorState = () => (
@@ -375,21 +588,31 @@ const ErrorState = () => (
);
```
-
+This `state` value stores the chart type in which you want to show your data.
+
+Now that you've created an object which enumerates the chart type options for your visualization, and you've initialized `state.selectedChart`, you're ready to implement a control UI for switching between the two chart types.
+
+
-## Add the `SegmentedControl` components
+## Add `SegmentedControl` components
+
+`state.selectedChart` isn't useful unless your visualization's users can actually select a chart type. Use [`SegmentedControl`](/components/segmented-control) and [`SegmentedControlItem`](/components/segmented-control-item) to switch between the two chart types.
+
+
-To let the consumers of your visualization decide what type of chart they want to display, you'll use `SegmentedControl` and `SegmentedControlItem`, which allow users to switch between a set of provided options. To learn more about the components available from New Relic, go to our Intro to New Relic One SDK.
+To learn more about the components available in the New Relic One SDK, go to our [Intro to New Relic One SDK](/explore-docs/intro-to-sdk).
+
+
-
+
-Add `SegmentedControl` and `SegmentedControlItem` to the import from `nr1`:
+Import `SegmentedControl` and `SegmentedControlItem` from `nr1`:
-```js fileName=visualizations/your-visualization/index.js
+```js fileName=visualizations/radar-or-treemap/index.js
import React from 'react';
import PropTypes from 'prop-types';
import {
@@ -400,14 +623,14 @@ import {
PolarRadiusAxis,
} from 'recharts';
import {
- Card,
- CardBody,
- HeadingText,
- NrqlQuery,
- SegmentedControl,
- SegmentedControlItem,
- Spinner,
- AutoSizer
+ AutoSizer,
+ Card,
+ CardBody,
+ HeadingText,
+ NrqlQuery,
+ SegmentedControl,
+ SegmentedControlItem,
+ Spinner,
} from 'nr1';
const CHART_TYPES = {
@@ -415,7 +638,7 @@ const CHART_TYPES = {
'Treemap': 'treemap'
}
-export default class YourAwesomeVisualization extends React.Component {
+export default class RadarOrTreemapVisualization extends React.Component {
// Custom props you wish to be configurable in the UI must also be defined in
// the nr1.json file for the visualization. See docs for more details.
static propTypes = {
@@ -443,8 +666,8 @@ export default class YourAwesomeVisualization extends React.Component {
};
state = {
- selectedChart: CHART_TYPES.Radar
- }
+ selectedChart: CHART_TYPES.Radar,
+ };
/**
* Restructure the data for a non-time-series, facet-based NRQL query into a
@@ -523,7 +746,6 @@ export default class YourAwesomeVisualization extends React.Component {
}
}
-
const EmptyState = () => (
@@ -543,6 +765,7 @@ const EmptyState = () => (
);
+
const ErrorState = () => (
@@ -558,13 +781,13 @@ const ErrorState = () => (
);
```
-
+
-
+
-In the `render` function, wrap `RadarChart` in ` ... `. Then add the `SegmentedControl` and `SegmentedControlItem` above the `RadarChart` and set the value and label:
+In `render()`, wrap `RadarChart` in a `React.Fragment`:
-```jsx fileName=visualizations/your-visualization/index.js
+```js fileName=visualizations/radar-or-treemap/index.js
import React from 'react';
import PropTypes from 'prop-types';
import {
@@ -575,20 +798,22 @@ import {
PolarRadiusAxis,
} from 'recharts';
import {
- Card,
- CardBody,
- HeadingText,
- NrqlQuery,
- SegmentedControl,
- SegmentedControlItem,
- Spinner,
- AutoSizer
+ AutoSizer,
+ Card,
+ CardBody,
+ HeadingText,
+ NrqlQuery,
+ SegmentedControl,
+ SegmentedControlItem,
+ Spinner,
} from 'nr1';
+
const CHART_TYPES = {
'Radar': 'radar',
'Treemap': 'treemap'
}
-export default class YourAwesomeVisualization extends React.Component {
+
+export default class RadarOrTreemapVisualization extends React.Component {
// Custom props you wish to be configurable in the UI must also be defined in
// the nr1.json file for the visualization. See docs for more details.
static propTypes = {
@@ -597,6 +822,7 @@ export default class YourAwesomeVisualization extends React.Component {
* a custom chart configuration.
*/
fill: PropTypes.string,
+
/**
* A stroke color to override the default stroke color. This is an example of
* a custom chart configuration.
@@ -613,9 +839,11 @@ export default class YourAwesomeVisualization extends React.Component {
})
),
};
+
state = {
- selectedChart: CHART_TYPES.Radar
- }
+ selectedChart: CHART_TYPES.Radar,
+ };
+
/**
* Restructure the data for a non-time-series, facet-based NRQL query into a
* form accepted by the Recharts library's RadarChart.
@@ -628,22 +856,27 @@ export default class YourAwesomeVisualization extends React.Component {
value: entry.data[0].y,
}));
};
+
/**
* Format the given axis tick's numeric value into a string for display.
*/
formatTick = (value) => {
return value.toLocaleString();
};
+
render() {
const {nrqlQueries, stroke, fill} = this.props;
+
const nrqlQueryPropsAvailable =
nrqlQueries &&
nrqlQueries[0] &&
nrqlQueries[0].accountId &&
nrqlQueries[0].query;
+
if (!nrqlQueryPropsAvailable) {
return ;
}
+
return (
{({width, height}) => (
@@ -656,24 +889,15 @@ export default class YourAwesomeVisualization extends React.Component {
if (loading) {
return ;
}
+
if (error) {
return ;
}
+
const transformedData = this.transformData(data);
+
return (
- console.log(value)}
- >
-
-
- (
@@ -719,6 +942,7 @@ const EmptyState = () => (
);
+
const ErrorState = () => (
@@ -734,28 +958,15 @@ const ErrorState = () => (
);
```
-
+This allows you to return multiple components from the same `render()`.
-If you run your visualization locally, your visualization should match the following image and changing the SegmentedControl should not have any effect on the visualization:
+
-
+
-
-
-## Connect component state with the new UI controls
-
-In the next steps, you're going to add a function to update state and connect that with the `SegmentedControl` component.
-
-
-
-
+Add a `SegmentedControl` and two `SegmentedControlItem` components, each with a `value` and a `label`:
-Add a component method that updates state to your visualization class:
-
-```js fileName=visualizations/your-visualization/index.js
+```js fileName=visualizations/radar-or-treemap/index.js
import React from 'react';
import PropTypes from 'prop-types';
import {
@@ -766,20 +977,22 @@ import {
PolarRadiusAxis,
} from 'recharts';
import {
- Card,
- CardBody,
- HeadingText,
- NrqlQuery,
- SegmentedControl,
- SegmentedControlItem,
- Spinner,
- AutoSizer
+ AutoSizer,
+ Card,
+ CardBody,
+ HeadingText,
+ NrqlQuery,
+ SegmentedControl,
+ SegmentedControlItem,
+ Spinner,
} from 'nr1';
+
const CHART_TYPES = {
'Radar': 'radar',
'Treemap': 'treemap'
}
-export default class YourAwesomeVisualization extends React.Component {
+
+export default class RadarOrTreemapVisualization extends React.Component {
// Custom props you wish to be configurable in the UI must also be defined in
// the nr1.json file for the visualization. See docs for more details.
static propTypes = {
@@ -788,6 +1001,7 @@ export default class YourAwesomeVisualization extends React.Component {
* a custom chart configuration.
*/
fill: PropTypes.string,
+
/**
* A stroke color to override the default stroke color. This is an example of
* a custom chart configuration.
@@ -804,9 +1018,11 @@ export default class YourAwesomeVisualization extends React.Component {
})
),
};
+
state = {
- selectedChart: CHART_TYPES.Radar
- }
+ selectedChart: CHART_TYPES.Radar,
+ };
+
/**
* Restructure the data for a non-time-series, facet-based NRQL query into a
* form accepted by the Recharts library's RadarChart.
@@ -819,6 +1035,7 @@ export default class YourAwesomeVisualization extends React.Component {
value: entry.data[0].y,
}));
};
+
/**
* Format the given axis tick's numeric value into a string for display.
*/
@@ -826,20 +1043,19 @@ export default class YourAwesomeVisualization extends React.Component {
return value.toLocaleString();
};
- updateSelectedChart = (evt, value) => {
- this.setState({ selectedChart: value })
- };
-
render() {
const {nrqlQueries, stroke, fill} = this.props;
+
const nrqlQueryPropsAvailable =
nrqlQueries &&
nrqlQueries[0] &&
nrqlQueries[0].accountId &&
nrqlQueries[0].query;
+
if (!nrqlQueryPropsAvailable) {
return ;
}
+
return (
{({width, height}) => (
@@ -852,24 +1068,27 @@ export default class YourAwesomeVisualization extends React.Component {
if (loading) {
return ;
}
+
if (error) {
return ;
}
+
const transformedData = this.transformData(data);
+
return (
console.log(value)}
- >
-
-
-
+ onChange={(event, value) => console.log(value)}
+ >
+
+
+
(
@@ -915,6 +1133,7 @@ const EmptyState = () => (
);
+
const ErrorState = () => (
@@ -930,13 +1149,83 @@ const ErrorState = () => (
);
```
-
+Here, your `SegmentedControl` logs the `SegmentedControlItem.value` to the console when you change your selection. The values you've defined for your `SegmentedControlItem` components correspond to the two `CHART_TYPES` you created in a previous step.
+
+
+
+
+
+Navigate to the root of your Nerdpack at _alternate-viz_.
+
+
+
+
+
+[Serve your Nerdpack locally](/build-apps/publish-deploy/serve/):
+
+```bash
+nr1 nerdpack:serve
+```
+
+
+
+
+
+Go to [https://one.newrelic.com/?nerdpacks=local](https://one.newrelic.com/?nerdpacks=local). The `nerdpacks=local` query string directs the UI to load your visualization from the local server.
+
+
+
+
+
+Open the **Apps** page:
+
+![Apps navigation is located in the New Relic One top navigation](../../images/build-an-app/nav-to-apps.png)
+
+
+
+
+
+Go to **Custom Visualizations**, which is favorited by default:
+
+![Navigate to Custom Visualizations](../../images/build-an-app/nav-to-custom-viz.png)
+
+
+
+
+
+In **Custom Visualizations**, find and click your visualization:
+
+![Navigate to your visualization](../../images/custom-viz/nav-to-radar-or-treemap-viz.png)
+
+
+
+
+
+Configure your visualization with an account ID and a query:
+
+![Visualization with SegmentedControl](../../images/custom-viz/radar-chart-with-segmented-control.png)
-
+With some required data for your chart to process, you now see a `RadarChart` with the `SegmentedControl` at the top of the view.
-Pass `updateSelectedChart` as the `SegmentedControl` component's onChange prop:
+Look at your browser's console to see your `SegmentedControl` logs:
-```jsx fileName=visualizations/your-visualization/index.js
+![SegmentedControl logs](../../images/custom-viz/radar-or-treemap-viz-logs.png)
+
+
+
+
+
+## Connect your component's `state` to the `SegmentedControl`
+
+Add a method to update `state` and connect that method with the `SegmentedControl` you added in the last section.
+
+
+
+
+
+Add a component method, called `updateSelectedChart()`:
+
+```js fileName=visualizations/radar-or-treemap/index.js
import React from 'react';
import PropTypes from 'prop-types';
import {
@@ -947,20 +1236,22 @@ import {
PolarRadiusAxis,
} from 'recharts';
import {
- Card,
- CardBody,
- HeadingText,
- NrqlQuery,
- SegmentedControl,
- SegmentedControlItem,
- Spinner,
- AutoSizer
+ AutoSizer,
+ Card,
+ CardBody,
+ HeadingText,
+ NrqlQuery,
+ SegmentedControl,
+ SegmentedControlItem,
+ Spinner,
} from 'nr1';
+
const CHART_TYPES = {
'Radar': 'radar',
'Treemap': 'treemap'
}
-export default class YourAwesomeVisualization extends React.Component {
+
+export default class RadarOrTreemapVisualization extends React.Component {
// Custom props you wish to be configurable in the UI must also be defined in
// the nr1.json file for the visualization. See docs for more details.
static propTypes = {
@@ -969,6 +1260,7 @@ export default class YourAwesomeVisualization extends React.Component {
* a custom chart configuration.
*/
fill: PropTypes.string,
+
/**
* A stroke color to override the default stroke color. This is an example of
* a custom chart configuration.
@@ -985,9 +1277,11 @@ export default class YourAwesomeVisualization extends React.Component {
})
),
};
+
state = {
- selectedChart: CHART_TYPES.Radar
- }
+ selectedChart: CHART_TYPES.Radar,
+ };
+
/**
* Restructure the data for a non-time-series, facet-based NRQL query into a
* form accepted by the Recharts library's RadarChart.
@@ -1000,6 +1294,7 @@ export default class YourAwesomeVisualization extends React.Component {
value: entry.data[0].y,
}));
};
+
/**
* Format the given axis tick's numeric value into a string for display.
*/
@@ -1013,14 +1308,17 @@ export default class YourAwesomeVisualization extends React.Component {
render() {
const {nrqlQueries, stroke, fill} = this.props;
+
const nrqlQueryPropsAvailable =
nrqlQueries &&
nrqlQueries[0] &&
nrqlQueries[0].accountId &&
nrqlQueries[0].query;
+
if (!nrqlQueryPropsAvailable) {
return ;
}
+
return (
{({width, height}) => (
@@ -1033,22 +1331,27 @@ export default class YourAwesomeVisualization extends React.Component {
if (loading) {
return ;
}
+
if (error) {
return ;
}
+
const transformedData = this.transformData(data);
+
return (
-
-
-
-
+ console.log(value)}
+ >
+
+
+ (
@@ -1094,6 +1396,7 @@ const EmptyState = () => (
);
+
const ErrorState = () => (
@@ -1109,26 +1412,15 @@ const ErrorState = () => (
);
```
-
-
-
-
-
-## Add your new chart option
-
-In the next couple of steps, you'll add the Treemap chart from Recharts and get the correct values passed into it.
+This new method takes a `value` argument and sets `state.selectedChart` to that value.
-
-This guide uses Recharts chart components but you can explore any other JavaScript charting libraries that are compatible with the current React version on the New Relic One Platform.
-
-
-
+
-
+
-Add `Treemap` to the import from recharts:
+Set `SegmentedControl.onChange` to `updateSelectedChart()`:
-```jsx fileName=visualizations/your-visualization/index.js
+```js fileName=visualizations/radar-or-treemap/index.js
import React from 'react';
import PropTypes from 'prop-types';
import {
@@ -1137,23 +1429,24 @@ import {
PolarGrid,
PolarAngleAxis,
PolarRadiusAxis,
- Treemap,
} from 'recharts';
import {
- Card,
- CardBody,
- HeadingText,
- NrqlQuery,
- SegmentedControl,
- SegmentedControlItem,
- Spinner,
- AutoSizer
+ AutoSizer,
+ Card,
+ CardBody,
+ HeadingText,
+ NrqlQuery,
+ SegmentedControl,
+ SegmentedControlItem,
+ Spinner,
} from 'nr1';
+
const CHART_TYPES = {
'Radar': 'radar',
'Treemap': 'treemap'
}
-export default class YourAwesomeVisualization extends React.Component {
+
+export default class RadarOrTreemapVisualization extends React.Component {
// Custom props you wish to be configurable in the UI must also be defined in
// the nr1.json file for the visualization. See docs for more details.
static propTypes = {
@@ -1162,6 +1455,7 @@ export default class YourAwesomeVisualization extends React.Component {
* a custom chart configuration.
*/
fill: PropTypes.string,
+
/**
* A stroke color to override the default stroke color. This is an example of
* a custom chart configuration.
@@ -1178,9 +1472,11 @@ export default class YourAwesomeVisualization extends React.Component {
})
),
};
+
state = {
- selectedChart: CHART_TYPES.Radar
- }
+ selectedChart: CHART_TYPES.Radar,
+ };
+
/**
* Restructure the data for a non-time-series, facet-based NRQL query into a
* form accepted by the Recharts library's RadarChart.
@@ -1193,6 +1489,7 @@ export default class YourAwesomeVisualization extends React.Component {
value: entry.data[0].y,
}));
};
+
/**
* Format the given axis tick's numeric value into a string for display.
*/
@@ -1206,14 +1503,17 @@ export default class YourAwesomeVisualization extends React.Component {
render() {
const {nrqlQueries, stroke, fill} = this.props;
+
const nrqlQueryPropsAvailable =
nrqlQueries &&
nrqlQueries[0] &&
nrqlQueries[0].accountId &&
nrqlQueries[0].query;
+
if (!nrqlQueryPropsAvailable) {
return ;
}
+
return (
{({width, height}) => (
@@ -1226,22 +1526,27 @@ export default class YourAwesomeVisualization extends React.Component {
if (loading) {
return ;
}
+
if (error) {
return ;
}
+
const transformedData = this.transformData(data);
+
return (
-
-
-
-
+
+
+
+ (
@@ -1287,6 +1591,7 @@ const EmptyState = () => (
);
+
const ErrorState = () => (
@@ -1302,18 +1607,29 @@ const ErrorState = () => (
);
```
-
-To learn more about the Treemap chart component, go to the Recharts Treemap example or the Recharts Treemap API docs.
-
+Now, when you change your selection in the `SegmentedControl`,
+
+
+
+
+
+## Implement a `Treemap` option
+
+Add a [`Treemap`](https://recharts.org/en-US/api/Treemap) to your visualization. This map will be an alternative to the existing `RadarChart`.
+
+
-
+This guide uses [Recharts](https://recharts.org) components for third-party charts, but you can use any other JavaScript charting libraries that are compatible with the current React version when you build New Relic One visualizations and apps.
+
+
+
-
+
-Under the `RadarChart` closing tag in render, add the `Treemap` component and the necessary props:
+Import `Treemap` from `recharts`:
-```jsx fileName=visualizations/your-visualization/index.js
+```js fileName=visualizations/radar-or-treemap/index.js
import React from 'react';
import PropTypes from 'prop-types';
import {
@@ -1322,22 +1638,25 @@ import {
PolarGrid,
PolarAngleAxis,
PolarRadiusAxis,
+ Treemap,
} from 'recharts';
import {
- Card,
- CardBody,
- HeadingText,
- NrqlQuery,
- SegmentedControl,
- SegmentedControlItem,
- Spinner,
- AutoSizer
+ AutoSizer,
+ Card,
+ CardBody,
+ HeadingText,
+ NrqlQuery,
+ SegmentedControl,
+ SegmentedControlItem,
+ Spinner,
} from 'nr1';
+
const CHART_TYPES = {
'Radar': 'radar',
'Treemap': 'treemap'
}
-export default class YourAwesomeVisualization extends React.Component {
+
+export default class RadarOrTreemapVisualization extends React.Component {
// Custom props you wish to be configurable in the UI must also be defined in
// the nr1.json file for the visualization. See docs for more details.
static propTypes = {
@@ -1346,6 +1665,7 @@ export default class YourAwesomeVisualization extends React.Component {
* a custom chart configuration.
*/
fill: PropTypes.string,
+
/**
* A stroke color to override the default stroke color. This is an example of
* a custom chart configuration.
@@ -1362,9 +1682,11 @@ export default class YourAwesomeVisualization extends React.Component {
})
),
};
+
state = {
- selectedChart: CHART_TYPES.Radar
- }
+ selectedChart: CHART_TYPES.Radar,
+ };
+
/**
* Restructure the data for a non-time-series, facet-based NRQL query into a
* form accepted by the Recharts library's RadarChart.
@@ -1377,6 +1699,7 @@ export default class YourAwesomeVisualization extends React.Component {
value: entry.data[0].y,
}));
};
+
/**
* Format the given axis tick's numeric value into a string for display.
*/
@@ -1390,14 +1713,17 @@ export default class YourAwesomeVisualization extends React.Component {
render() {
const {nrqlQueries, stroke, fill} = this.props;
+
const nrqlQueryPropsAvailable =
nrqlQueries &&
nrqlQueries[0] &&
nrqlQueries[0].accountId &&
nrqlQueries[0].query;
+
if (!nrqlQueryPropsAvailable) {
return ;
}
+
return (
{({width, height}) => (
@@ -1410,22 +1736,27 @@ export default class YourAwesomeVisualization extends React.Component {
if (loading) {
return ;
}
+
if (error) {
return ;
}
+
const transformedData = this.transformData(data);
+
return (
-
-
-
-
+
+
+
+
-
);
}}
@@ -1460,7 +1782,6 @@ export default class YourAwesomeVisualization extends React.Component {
}
}
-
const EmptyState = () => (
@@ -1480,6 +1801,7 @@ const EmptyState = () => (
);
+
const ErrorState = () => (
@@ -1495,29 +1817,15 @@ const ErrorState = () => (
);
```
-Now render the visualization in local development to see the new Treemap chart below your Radar chart. If you scroll down a bit in your visualization, it should look something like the following:
+Now, you can use `Treemap` in your visualization component.
-
+
-
+
-
-
-
-## Use component state to switch between charts
-
-In the final steps, you'll use the `selectedChart` state value to determine which chart to show, the Radar chart or the Treemap chart.
-
-
-
-
+In `render()`, add a `Treemap` component:
-Destructure `selectedChart` from state near the top of the `render()` function:
-
-```jsx fileName=visualizations/your-visualization/index.js
+```js fileName=visualizations/radar-or-treemap/index.js
import React from 'react';
import PropTypes from 'prop-types';
import {
@@ -1526,22 +1834,25 @@ import {
PolarGrid,
PolarAngleAxis,
PolarRadiusAxis,
+ Treemap,
} from 'recharts';
import {
- Card,
- CardBody,
- HeadingText,
- NrqlQuery,
- SegmentedControl,
- SegmentedControlItem,
- Spinner,
- AutoSizer
+ AutoSizer,
+ Card,
+ CardBody,
+ HeadingText,
+ NrqlQuery,
+ SegmentedControl,
+ SegmentedControlItem,
+ Spinner,
} from 'nr1';
+
const CHART_TYPES = {
'Radar': 'radar',
'Treemap': 'treemap'
}
-export default class YourAwesomeVisualization extends React.Component {
+
+export default class RadarOrTreemapVisualization extends React.Component {
// Custom props you wish to be configurable in the UI must also be defined in
// the nr1.json file for the visualization. See docs for more details.
static propTypes = {
@@ -1550,6 +1861,7 @@ export default class YourAwesomeVisualization extends React.Component {
* a custom chart configuration.
*/
fill: PropTypes.string,
+
/**
* A stroke color to override the default stroke color. This is an example of
* a custom chart configuration.
@@ -1566,9 +1878,11 @@ export default class YourAwesomeVisualization extends React.Component {
})
),
};
+
state = {
- selectedChart: CHART_TYPES.Radar
- }
+ selectedChart: CHART_TYPES.Radar,
+ };
+
/**
* Restructure the data for a non-time-series, facet-based NRQL query into a
* form accepted by the Recharts library's RadarChart.
@@ -1581,6 +1895,7 @@ export default class YourAwesomeVisualization extends React.Component {
value: entry.data[0].y,
}));
};
+
/**
* Format the given axis tick's numeric value into a string for display.
*/
@@ -1594,15 +1909,17 @@ export default class YourAwesomeVisualization extends React.Component {
render() {
const {nrqlQueries, stroke, fill} = this.props;
- const { selectedChart } = this.state;
+
const nrqlQueryPropsAvailable =
nrqlQueries &&
nrqlQueries[0] &&
nrqlQueries[0].accountId &&
nrqlQueries[0].query;
+
if (!nrqlQueryPropsAvailable) {
return ;
}
+
return (
{({width, height}) => (
@@ -1615,22 +1932,27 @@ export default class YourAwesomeVisualization extends React.Component {
if (loading) {
return ;
}
+
if (error) {
return ;
}
+
const transformedData = this.transformData(data);
+
return (
-
-
-
-
+
+
+
+
);
@@ -1665,7 +1987,6 @@ export default class YourAwesomeVisualization extends React.Component {
}
}
-
const EmptyState = () => (
@@ -1685,6 +2006,7 @@ const EmptyState = () => (
);
+
const ErrorState = () => (
@@ -1700,13 +2022,32 @@ const ErrorState = () => (
);
```
-
+Here, you've defined a new `Treemap` component with some props, including `height`, `width`, `fill`, and `stroke`.
+
+
+
+
+
+With your Nerdpack served locally, [view your visualization](https://one.newrelic.com?nerdpacks=local). The `SegmentedControl` and `RadarChart` are at the top of the view, but if you scroll down, you'll see your new `Treemap`:
+
+![Treemap and RadarChart together](../../images/custom-viz/radar-and-treemap.png)
+
+
+
+
+
-
+## Switch between charts with your component's `state`
-Here, you compare `selectedChart` to `CHART_TYPES.Radar`. If `selectedChart` is a Radar, you render a RadarChart. Otherwise, you render a Treemap. You can achieve this by wrapping the `RadarChart` and `Treemap` in a ternary using the `selectedChart` state:
+Use `state.selectedChart` to determine which chart to show: the `RadarChart` or the `Treemap`.
+
+
-```jsx fileName=visualizations/your-visualization/index.js
+
+
+Compare `state.selectedChart` to `CHART_TYPES.Radar`. If they are the same, render a `RadarChart`. Otherwise, render a `Treemap`:
+
+```js fileName=visualizations/radar-or-treemap/index.js
import React from 'react';
import PropTypes from 'prop-types';
import {
@@ -1715,22 +2056,25 @@ import {
PolarGrid,
PolarAngleAxis,
PolarRadiusAxis,
+ Treemap,
} from 'recharts';
import {
- Card,
- CardBody,
- HeadingText,
- NrqlQuery,
- SegmentedControl,
- SegmentedControlItem,
- Spinner,
- AutoSizer
+ AutoSizer,
+ Card,
+ CardBody,
+ HeadingText,
+ NrqlQuery,
+ SegmentedControl,
+ SegmentedControlItem,
+ Spinner,
} from 'nr1';
+
const CHART_TYPES = {
'Radar': 'radar',
'Treemap': 'treemap'
}
-export default class YourAwesomeVisualization extends React.Component {
+
+export default class RadarOrTreemapVisualization extends React.Component {
// Custom props you wish to be configurable in the UI must also be defined in
// the nr1.json file for the visualization. See docs for more details.
static propTypes = {
@@ -1739,6 +2083,7 @@ export default class YourAwesomeVisualization extends React.Component {
* a custom chart configuration.
*/
fill: PropTypes.string,
+
/**
* A stroke color to override the default stroke color. This is an example of
* a custom chart configuration.
@@ -1755,9 +2100,11 @@ export default class YourAwesomeVisualization extends React.Component {
})
),
};
+
state = {
- selectedChart: CHART_TYPES.Radar
- }
+ selectedChart: CHART_TYPES.Radar,
+ };
+
/**
* Restructure the data for a non-time-series, facet-based NRQL query into a
* form accepted by the Recharts library's RadarChart.
@@ -1770,6 +2117,7 @@ export default class YourAwesomeVisualization extends React.Component {
value: entry.data[0].y,
}));
};
+
/**
* Format the given axis tick's numeric value into a string for display.
*/
@@ -1783,15 +2131,17 @@ export default class YourAwesomeVisualization extends React.Component {
render() {
const {nrqlQueries, stroke, fill} = this.props;
- const { selectedChart } = this.state;
+
const nrqlQueryPropsAvailable =
nrqlQueries &&
nrqlQueries[0] &&
nrqlQueries[0].accountId &&
nrqlQueries[0].query;
+
if (!nrqlQueryPropsAvailable) {
return ;
}
+
return (
{({width, height}) => (
@@ -1804,25 +2154,29 @@ export default class YourAwesomeVisualization extends React.Component {
if (loading) {
return ;
}
+
if (error) {
return ;
}
+
const transformedData = this.transformData(data);
+
return (
-
-
-
-
- {
- selectedChart === CHART_TYPES.Radar ?
- (
+
+
+
+ {this.state.selectedChart === CHART_TYPES.Radar ? (
+
- )
- :
- (
+ ) : (
+ )}
+ stroke={stroke || '#000000'}
+ fill={fill || '#51C9B7'}
+ />
+ )}
);
}}
@@ -1857,7 +2212,6 @@ export default class YourAwesomeVisualization extends React.Component {
}
}
-
const EmptyState = () => (
@@ -1877,6 +2231,7 @@ const EmptyState = () => (
);
+
const ErrorState = () => (
@@ -1892,40 +2247,28 @@ const ErrorState = () => (
);
```
-
+Here, you used a ternary expression to render a `RadarChart` or a `Treemap`. The rendered chart is determined by the value of `selectedChart`.
+
+
-Go to the browser and try it out! Run your visualization locally and view it in the Custom Visualization app in New Relic. Click on "Treemap chart" in the SegmentedControl. You should see your Treemap chart render instead of the Radar chart:
+With your Nerdpack served locally, [view your visualization](https://one.newrelic.com?nerdpacks=local).
-
+Select **Radar chart** from the `SegmentedControl`:
-
Radar chart selected
+![RadarChart selected](../../images/custom-viz/radar-selected.png)
-
+Select **Treemap chart** from the `SegmentedControl`:
-
Treemap chart selected
+![Treemap selected](../../images/custom-viz/treemap-selected.png)
-
## Summary
-Congratulations on completing the steps in this example! You've learned how to:
+Congratulations! In this lesson, you learned how to:
- Customize your visualization using New Relic One SDK components
- Add a new chart type to your visualization
-- Create a user interaction in your visualization
-
-## Additional resources
-
-- New Relic Quick Tips video: [Dashboards and Custom Visualizations](https://www.youtube.com/watch?v=_F61mxtKfGA) (6 minutes)
-- New Relic NerdBytes video: [Configuring custom visualizations for dashboards](https://www.youtube.com/watch?v=sFpG_iG7Xa8) (7 minutes)
-- New Relic Nerdlog live stream: [Custom Data Visualizations on New Relic](https://www.youtube.com/watch?v=HuR0EdHGz24) (30 minutes)
-- New Relic One SDK components: Intro to New Relic One SDK Component library
+- Create a user interaction in your visualization
\ No newline at end of file