• Log inStart now

On August 31, 2024, we're EOLing developer.newrelic.com. All relevant content has been migrated to docs.newrelic.com.

Map page views by region in a custom app

30 min

New Relic has powerful and flexible tools for building custom apps and populating them with data. This guide shows you how to build a custom app and populate it with page view data using New Relic's Query Language (NRQL - pronounced 'nurkle'). Then you make your data interactive. And last, if you have a little more time and want to install a third-party React library, you can display the page view data you collect on a map of the world.

In this guide, you build an app to display page view data in two ways:

  • In a table
  • On a map

Please review the Before you begin section to make sure you have everything you need and don't get stuck halfway through.

map with pageviews

Before you begin

In order to get the most out of this guide, you must have:

  • A New Relic developer account, API key, and the command-line tool. If you don't have these yet, see the steps in Setting up your development environment
  • New Relic Browser page view data to populate the app. Without this data, you won't be able to complete this guide.

To add your data to a world map in the second half of the guide:

  • npm, which you'll use during this section of the guide to install Leaflet, a third-party JavaScript React library used to build interactive maps. If you're new to React and npm, you can go here to install Node.js and npm.

New Relic terminology

The following are some terms used in this guide:

  • New Relic application: The finished product where data is rendered in New Relic. This might look like a series of interactive charts or a map of the world.
  • Nerdpack: New Relic's standard collection of JavaScript, JSON, CSS, and other files that control the functionality and look of your application. For more information, see Nerdpack file structure.
  • Launcher: The button in New Relic that launches your application.
  • Nerdlets: New Relic React components used to build your application. The three default files are index.js, nr1.json, and styles.scss, but you can customize and add your own.

Build a custom app with a table chart

Step 1 of 8

Query your browser data

Use Query builder to write a NRQL query to see your page view data, as follows.

In New Relic, select Query your data (in the top right corner). That puts you in NRQL mode. You'll use NRQL to test your query before dropping the data into your table.

Copy and paste this query into a clear query field, and then select Run.

FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' FACET countryCode, regionCode SINCE 1 week ago LIMIT 1000

If you have PageView data, this query shows a week of average page views broken down by country and limited to a thousand items. The table will be full width and use the "chart" class defined in the CSS.

If you don't have any results at this point, ensure your query doesn't have any errors. If your query is correct, you might not have the Browser agent installed.

Step 2 of 8

Create and serve a new Nerdpack

To get started, create a new Nerdpack, and serve it up to New Relic from your local development environment:

  1. Update nr1 and create a new Nerdpack for this app:
bash
$
nr1 update
$
nr1 create --type nerdpack --name pageviews-app
Component created successfully!
nerdpack pageviews-app is available at "./pageviews-app"
  1. Serve the project up to New Relic:
bash
$
cd pageviews-app && nr1 nerdpack:serve
Found and loaded 2 nr1.json files on PageviewsApp (00e0f043-1fc3-42cd-a8ca-7eef5fc9cd45) Nerdpack.
Nerdpack:
✔ PageviewsApp (00e0f043-1fc3-42cd-a8ca-7eef5fc9cd45) nr1.json
Launchers:
pageviews-app-launcher launchers/pageviews-app-launcher/nr1.json
Nerdlets:
pageviews-app-nerdlet nerdlets/pageviews-app-nerdlet/nr1.json
🛠 Built artifact files for:
00e0f043-1fc3-42cd-a8ca-7eef5fc9cd45--pageviews-app-nerdlet built
Nerdpack built successfully!
Starting as orchestrator...
Server ready! Test it at: https://staging-one.newrelic.com/?nerdpacks=local
↩ Server will reload automatically if you modify any file!
🛠 Built artifact files for:
00e0f043-1fc3-42cd-a8ca-7eef5fc9cd45--pageviews-app-nerdlet built
Nerdpack built successfully!
Step 3 of 8

Review your app files and view your app locally

  1. Navigate to your pageviews-app to see how it's structured. It contains a launcher folder, where you can customize the description and icon that will be displayed on the app's launcher in New Relic. It also contains nerdlets, which each contain three default files: index.js, nr1.json, and styles.scss. You'll edit some of these files as part of this guide. For more information, see Nerdpack file structure.

  2. Now in your browser, open https://one.newrelic.com/?nerdpacks=local, and then click Apps to see the pageview-apps Nerdpack that you served up.

When you select the launcher, you see a Hello message.

Step 4 of 8

Hard code your account ID

For the purposes of this exercise and for your convenience, hard code your account ID. In the pageview-app-nerdlet directory, in the index.js file, add this code between the import and export lines. (Read about finding your account ID here).

1
import React from 'react';
2
3
const accountId = 0; // Replace with your account ID
4
5
export default class PageViewApp extends React.Component {
6
render() {
7
return <h1>Hello, pageview-app-nerdlet Nerdlet!</h1>;
8
}
9
}
pageview-app-nerdlet/index.js
1
pageview-app-nerdlet/styles.scss
1
.extended-webpackrc.js
Step 5 of 8

Import the TableChart component

To show your data in a table chart, import the TableChart component from New Relic. To do so, in index.js, add this code under import React.

1
import React from 'react';
2
import { TableChart } from 'nr1';
3
4
const accountId = 0; // Replace with your account ID
5
6
export default class PageViewApp extends React.Component {
7
render() {
8
return <h1>Hello, pageview-app-nerdlet Nerdlet!</h1>;
9
}
10
}
pageview-app-nerdlet/index.js
1
pageview-app-nerdlet/styles.scss
1
.extended-webpackrc.js
Step 6 of 8

Add a table with a single row

To add a table with a single row, in the index.js file, replace this line with this export code:

1
import React from 'react';
2
import { TableChart } from 'nr1';
3
4
const accountId = 0; // Replace with your account ID
5
6
export default class PageViewApp extends React.Component {
7
render() {
8
return (
9
<div className="container">
10
<div className="row"></div>
11
</div>
12
);
13
}
14
}
pageview-app-nerdlet/index.js
1
pageview-app-nerdlet/styles.scss
1
.extended-webpackrc.js
Step 7 of 8

Customize the look of your table (optional)

You can use standard CSS to customize the look of your components.

In the styles.scss file, add this CSS. Feel free to customize this CSS to your taste.

1
import React from 'react';
2
import { TableChart } from 'nr1';
3
4
const accountId = 0; // Replace with your account ID
5
6
export default class PageViewApp extends React.Component {
7
render() {
8
return (
9
<div className="container">
10
<div className="row"></div>
11
</div>
12
);
13
}
14
}
pageview-app-nerdlet/index.js
1
.container {
2
width: 100%;
3
height: 99vh;
4
display: flex;
5
flex-direction: column;
6
.row {
7
margin: 10px;
8
display: flex;
9
flex-direction: row;
10
}
11
.chart {
12
height: 250px;
13
}
14
}
pageview-app-nerdlet/styles.scss
1
.extended-webpackrc.js
Step 8 of 8

Get your data into that table

Now that you've got a table, you can drop a TableChart populated with data from the NRQL query you wrote at the very beginning of this guide.

Put this code into the row div.

1
import React from 'react';
2
import { TableChart } from 'nr1';
3
4
const accountId = 0; // Replace with your account ID
5
6
export default class PageViewApp extends React.Component {
7
render() {
8
return (
9
<div className="container">
10
<div className="row">
11
<TableChart
12
accountId={accountId}
13
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' SINCE 1 week ago LIMIT 1000`}
14
fullWidth
15
className="chart"
16
/>
17
</div>
18
</div>
19
);
20
}
21
}
pageview-app-nerdlet/index.js
1
.container {
2
width: 100%;
3
height: 99vh;
4
display: flex;
5
flex-direction: column;
6
.row {
7
margin: 10px;
8
display: flex;
9
flex-direction: row;
10
}
11
.chart {
12
height: 250px;
13
}
14
}
pageview-app-nerdlet/styles.scss
1
.extended-webpackrc.js

Go to New Relic and click your app to see your data in the table. (You might need to serve your app to New Relic again.)

Congratulations! You made your app! Continue on to make it interactive and show your data on a map.

Make your app interactive with a text field

Once you confirm that data is getting to New Relic from your app, you can start customizing it and making it interactive. To do this, you add a text field to filter your data. Later, you use a third-party library called Leaflet to show that data on a world map.

Step 1 of 3

Import the TextField component

Like you did with the TableChart component, you need to import a TextField component from New Relic.

1
import React from 'react';
2
import { TableChart, TextField } from 'nr1';
3
4
const accountId = 0; // Replace with your account ID
5
6
export default class PageViewApp extends React.Component {
7
render() {
8
return (
9
<div className="container">
10
<div className="row">
11
<TableChart
12
accountId={accountId}
13
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' SINCE 1 week ago LIMIT 1000`}
14
fullWidth
15
className="chart"
16
/>
17
</div>
18
</div>
19
);
20
}
21
}
pageview-app-nerdlet/index.js
1
.container {
2
width: 100%;
3
height: 99vh;
4
display: flex;
5
flex-direction: column;
6
.row {
7
margin: 10px;
8
display: flex;
9
flex-direction: row;
10
}
11
.chart {
12
height: 250px;
13
}
14
}
pageview-app-nerdlet/styles.scss
1
.extended-webpackrc.js
Step 2 of 3

Add a row for your text field

To add a text field filter above the table, put this code above the TableChart div. The text field will have a default value of "US".

1
import React from 'react';
2
import { TableChart, TextField } from 'nr1';
3
4
const accountId = 0; // Replace with your account ID
5
6
export default class PageViewApp extends React.Component {
7
render() {
8
return (
9
<div className="container">
10
<div className="row">
11
<div className="row">
12
<TextField
13
placeholder="US"
14
onChange={(event) => {
15
this.setState({ countryCode: event.target.value });
16
}}
17
/>
18
</div>
19
<TableChart
20
accountId={accountId}
21
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' SINCE 1 week ago LIMIT 1000`}
22
fullWidth
23
className="chart"
24
/>
25
</div>
26
</div>
27
);
28
}
29
}
pageview-app-nerdlet/index.js
1
.container {
2
width: 100%;
3
height: 99vh;
4
display: flex;
5
flex-direction: column;
6
.row {
7
margin: 10px;
8
display: flex;
9
flex-direction: row;
10
}
11
.chart {
12
height: 250px;
13
}
14
}
pageview-app-nerdlet/styles.scss
1
.extended-webpackrc.js
Step 3 of 3

Build the text field object

Above the render() function, add a constructor to build the text field object.

1
import React from 'react';
2
import { TableChart, TextField } from 'nr1';
3
4
const accountId = 0; // Replace with your account ID
5
6
export default class PageViewApp extends React.Component {
7
constructor(props) {
8
super(props);
9
this.state = {
10
countryCode: null,
11
};
12
}
13
14
render() {
15
return (
16
<div className="container">
17
<div className="row">
18
<div className="row">
19
<TextField
20
placeholder="US"
21
onChange={(event) => {
22
this.setState({ countryCode: event.target.value });
23
}}
24
/>
25
</div>
26
<TableChart
27
accountId={accountId}
28
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' SINCE 1 week ago LIMIT 1000`}
29
fullWidth
30
className="chart"
31
/>
32
</div>
33
</div>
34
);
35
}
36
}
pageview-app-nerdlet/index.js
1
.container {
2
width: 100%;
3
height: 99vh;
4
display: flex;
5
flex-direction: column;
6
.row {
7
margin: 10px;
8
display: flex;
9
flex-direction: row;
10
}
11
.chart {
12
height: 250px;
13
}
14
}
pageview-app-nerdlet/styles.scss
1
.extended-webpackrc.js

Above return, add:

1
import React from 'react';
2
import { TableChart, TextField } from 'nr1';
3
4
const accountId = 0; // Replace with your account ID
5
6
export default class PageViewApp extends React.Component {
7
constructor(props) {
8
super(props);
9
this.state = {
10
countryCode: null,
11
};
12
}
13
14
render() {
15
const { countryCode } = this.state;
16
17
return (
18
<div className="container">
19
<div className="row">
20
<div className="row">
21
<TextField
22
placeholder="US"
23
onChange={(event) => {
24
this.setState({ countryCode: event.target.value });
25
}}
26
/>
27
</div>
28
<TableChart
29
accountId={accountId}
30
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' SINCE 1 week ago LIMIT 1000`}
31
fullWidth
32
className="chart"
33
/>
34
</div>
35
</div>
36
);
37
}
38
}
pageview-app-nerdlet/index.js
1
.container {
2
width: 100%;
3
height: 99vh;
4
display: flex;
5
flex-direction: column;
6
.row {
7
margin: 10px;
8
display: flex;
9
flex-direction: row;
10
}
11
.chart {
12
height: 250px;
13
}
14
}
pageview-app-nerdlet/styles.scss
1
.extended-webpackrc.js

Now add countryCode to your table chart query.

1
import React from 'react';
2
import { TableChart, TextField } from 'nr1';
3
4
const accountId = 0; // Replace with your account ID
5
6
export default class PageViewApp extends React.Component {
7
constructor(props) {
8
super(props);
9
this.state = {
10
countryCode: null,
11
};
12
}
13
14
render() {
15
const { countryCode } = this.state;
16
17
return (
18
<div className="container">
19
<div className="row">
20
<div className="row">
21
<TextField
22
placeholder="US"
23
onChange={(event) => {
24
this.setState({ countryCode: event.target.value });
25
}}
26
/>
27
</div>
28
<TableChart
29
accountId={accountId}
30
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' ${
31
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
32
} FACET countryCode, regionCode SINCE 1 week ago LIMIT 1000`}
33
fullWidth
34
className="chart"
35
/>
36
</div>
37
</div>
38
);
39
}
40
}
pageview-app-nerdlet/index.js
1
.container {
2
width: 100%;
3
height: 99vh;
4
display: flex;
5
flex-direction: column;
6
.row {
7
margin: 10px;
8
display: flex;
9
flex-direction: row;
10
}
11
.chart {
12
height: 250px;
13
}
14
}
pageview-app-nerdlet/styles.scss
1
.extended-webpackrc.js

Reload your app to try out the text field.

Get your data on a map

To create the map, you use npm to install Leaflet.

Step 1 of 9

Install Leaflet

In your terminal, type:

bash
$
npm install --save leaflet react-leaflet

In your nerdlets styles.scss file, import the Leaflet CSS:

1
import React from 'react';
2
import { TableChart, TextField } from 'nr1';
3
4
const accountId = 0; // Replace with your account ID
5
6
export default class PageViewApp extends React.Component {
7
constructor(props) {
8
super(props);
9
this.state = {
10
countryCode: null,
11
};
12
}
13
14
render() {
15
const { countryCode } = this.state;
16
17
return (
18
<div className="container">
19
<div className="row">
20
<div className="row">
21
<TextField
22
placeholder="US"
23
onChange={(event) => {
24
this.setState({ countryCode: event.target.value });
25
}}
26
/>
27
</div>
28
<TableChart
29
accountId={accountId}
30
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' ${
31
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
32
} FACET countryCode, regionCode SINCE 1 week ago LIMIT 1000`}
33
fullWidth
34
className="chart"
35
/>
36
</div>
37
</div>
38
);
39
}
40
}
pageview-app-nerdlet/index.js
1
@import `~leaflet/dist/leaflet.css`;
2
3
.container {
4
width: 100%;
5
height: 99vh;
6
display: flex;
7
flex-direction: column;
8
.row {
9
margin: 10px;
10
display: flex;
11
flex-direction: row;
12
}
13
.chart {
14
height: 250px;
15
}
16
}
pageview-app-nerdlet/styles.scss
1
.extended-webpackrc.js

While you're in styles.scss, fix the width and height of your map:

1
import React from 'react';
2
import { TableChart, TextField } from 'nr1';
3
4
const accountId = 0; // Replace with your account ID
5
6
export default class PageViewApp extends React.Component {
7
constructor(props) {
8
super(props);
9
this.state = {
10
countryCode: null,
11
};
12
}
13
14
render() {
15
const { countryCode } = this.state;
16
17
return (
18
<div className="container">
19
<div className="row">
20
<div className="row">
21
<TextField
22
placeholder="US"
23
onChange={(event) => {
24
this.setState({ countryCode: event.target.value });
25
}}
26
/>
27
</div>
28
<TableChart
29
accountId={accountId}
30
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' ${
31
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
32
} FACET countryCode, regionCode SINCE 1 week ago LIMIT 1000`}
33
fullWidth
34
className="chart"
35
/>
36
</div>
37
</div>
38
);
39
}
40
}
pageview-app-nerdlet/index.js
1
@import `~leaflet/dist/leaflet.css`;
2
3
.container {
4
width: 100%;
5
height: 99vh;
6
display: flex;
7
flex-direction: column;
8
.row {
9
margin: 10px;
10
display: flex;
11
flex-direction: row;
12
}
13
.chart {
14
height: 250px;
15
}
16
}
17
18
.containerMap {
19
width: 100%;
20
z-index: 0;
21
height: 70vh;
22
}
pageview-app-nerdlet/styles.scss
1
.extended-webpackrc.js
Step 2 of 9

Add a webpack config file for Leaflet

Add a webpack configuration file .extended-webpackrc.js to the top-level folder in your nerdpack. This supports your use of map tiling information data from Leaflet.

1
import React from 'react';
2
import { TableChart, TextField } from 'nr1';
3
4
const accountId = 0; // Replace with your account ID
5
6
export default class PageViewApp extends React.Component {
7
constructor(props) {
8
super(props);
9
this.state = {
10
countryCode: null,
11
};
12
}
13
14
render() {
15
const { countryCode } = this.state;
16
17
return (
18
<div className="container">
19
<div className="row">
20
<div className="row">
21
<TextField
22
placeholder="US"
23
onChange={(event) => {
24
this.setState({ countryCode: event.target.value });
25
}}
26
/>
27
</div>
28
<TableChart
29
accountId={accountId}
30
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' ${
31
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
32
} FACET countryCode, regionCode SINCE 1 week ago LIMIT 1000`}
33
fullWidth
34
className="chart"
35
/>
36
</div>
37
</div>
38
);
39
}
40
}
pageview-app-nerdlet/index.js
1
@import `~leaflet/dist/leaflet.css`;
2
3
.container {
4
width: 100%;
5
height: 99vh;
6
display: flex;
7
flex-direction: column;
8
.row {
9
margin: 10px;
10
display: flex;
11
flex-direction: row;
12
}
13
.chart {
14
height: 250px;
15
}
16
}
17
18
.containerMap {
19
width: 100%;
20
z-index: 0;
21
height: 70vh;
22
}
pageview-app-nerdlet/styles.scss
1
module.exports = {
2
module: {
3
rules: [
4
{
5
test: /\.(png|jpe?g|gif)$/,
6
use: [
7
{
8
loader: 'file-loader',
9
options: {},
10
},
11
{
12
loader: 'url-loader',
13
options: { limit: 25000 },
14
},
15
],
16
},
17
],
18
},
19
};
.extended-webpackrc.js
Step 3 of 9

Import modules from Leaflet

In index.js, import modules from Leaflet.

1
import React from 'react';
2
import { TableChart, TextField } from 'nr1';
3
import { Map, CircleMarker, TileLayer } from 'react-leaflet';
4
5
const accountId = 0; // Replace with your account ID
6
7
export default class PageViewApp extends React.Component {
8
constructor(props) {
9
super(props);
10
this.state = {
11
countryCode: null,
12
};
13
}
14
15
render() {
16
const { countryCode } = this.state;
17
18
return (
19
<div className="container">
20
<div className="row">
21
<div className="row">
22
<TextField
23
placeholder="US"
24
onChange={(event) => {
25
this.setState({ countryCode: event.target.value });
26
}}
27
/>
28
</div>
29
<TableChart
30
accountId={accountId}
31
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' ${
32
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
33
} FACET countryCode, regionCode SINCE 1 week ago LIMIT 1000`}
34
fullWidth
35
className="chart"
36
/>
37
</div>
38
</div>
39
);
40
}
41
}
pageview-app-nerdlet/index.js
1
@import `~leaflet/dist/leaflet.css`;
2
3
.container {
4
width: 100%;
5
height: 99vh;
6
display: flex;
7
flex-direction: column;
8
.row {
9
margin: 10px;
10
display: flex;
11
flex-direction: row;
12
}
13
.chart {
14
height: 250px;
15
}
16
}
17
18
.containerMap {
19
width: 100%;
20
z-index: 0;
21
height: 70vh;
22
}
pageview-app-nerdlet/styles.scss
1
module.exports = {
2
module: {
3
rules: [
4
{
5
test: /\.(png|jpe?g|gif)$/,
6
use: [
7
{
8
loader: 'file-loader',
9
options: {},
10
},
11
{
12
loader: 'url-loader',
13
options: { limit: 25000 },
14
},
15
],
16
},
17
],
18
},
19
};
.extended-webpackrc.js
Step 4 of 9

Import additional modules from New Relic

You need several more modules from New Relic to make the Leaflet map work well. Import them with this code:

1
import React from 'react';
2
import {
3
TableChart,
4
TextField,
5
NerdGraphQuery,
6
Spinner,
7
Button,
8
BlockText,
9
} from 'nr1';
10
import { Map, CircleMarker, TileLayer } from 'react-leaflet';
11
12
const accountId = 0; // Replace with your account ID
13
14
export default class PageViewApp extends React.Component {
15
constructor(props) {
16
super(props);
17
this.state = {
18
countryCode: null,
19
};
20
}
21
22
render() {
23
const { countryCode } = this.state;
24
25
return (
26
<div className="container">
27
<div className="row">
28
<div className="row">
29
<TextField
30
placeholder="US"
31
onChange={(event) => {
32
this.setState({ countryCode: event.target.value });
33
}}
34
/>
35
</div>
36
<TableChart
37
accountId={accountId}
38
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' ${
39
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
40
} FACET countryCode, regionCode SINCE 1 week ago LIMIT 1000`}
41
fullWidth
42
className="chart"
43
/>
44
</div>
45
</div>
46
);
47
}
48
}
pageview-app-nerdlet/index.js
1
@import `~leaflet/dist/leaflet.css`;
2
3
.container {
4
width: 100%;
5
height: 99vh;
6
display: flex;
7
flex-direction: column;
8
.row {
9
margin: 10px;
10
display: flex;
11
flex-direction: row;
12
}
13
.chart {
14
height: 250px;
15
}
16
}
17
18
.containerMap {
19
width: 100%;
20
z-index: 0;
21
height: 70vh;
22
}
pageview-app-nerdlet/styles.scss
1
module.exports = {
2
module: {
3
rules: [
4
{
5
test: /\.(png|jpe?g|gif)$/,
6
use: [
7
{
8
loader: 'file-loader',
9
options: {},
10
},
11
{
12
loader: 'url-loader',
13
options: { limit: 25000 },
14
},
15
],
16
},
17
],
18
},
19
};
.extended-webpackrc.js

NerdGraphQuery lets you make multiple NRQL queries at once and is what will populate the map with data. Spinner adds a loading spinner. Button gives you button components. BlockText give you block text components.

Step 5 of 9

Get data for the map

Using latitude and longitude with country codes, you can put New Relic data on a map.

1
import React from 'react';
2
import {
3
TableChart,
4
TextField,
5
NerdGraphQuery,
6
Spinner,
7
Button,
8
BlockText,
9
} from 'nr1';
10
import { Map, CircleMarker, TileLayer } from 'react-leaflet';
11
12
const accountId = 0; // Replace with your account ID
13
14
export default class PageViewApp extends React.Component {
15
constructor(props) {
16
super(props);
17
this.state = {
18
countryCode: null,
19
};
20
}
21
22
mapData() {
23
const { countryCode } = this.state;
24
const query = `{
25
actor {
26
account(id: 1606862) {
27
mapData: nrql(query: "SELECT count(*) as x, average(duration) as y, sum(asnLatitude)/count(*) as lat, sum(asnLongitude)/count(*) as lng FROM PageView FACET regionCode, countryCode WHERE appName = 'WebPortal' ${
28
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
29
} LIMIT 1000 ") {
30
results
31
nrql
32
}
33
}
34
}
35
}`;
36
37
return query;
38
}
39
40
render() {
41
const { countryCode } = this.state;
42
43
return (
44
<div className="container">
45
<div className="row">
46
<div className="row">
47
<TextField
48
placeholder="US"
49
onChange={(event) => {
50
this.setState({ countryCode: event.target.value });
51
}}
52
/>
53
</div>
54
<TableChart
55
accountId={accountId}
56
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' ${
57
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
58
} FACET countryCode, regionCode SINCE 1 week ago LIMIT 1000`}
59
fullWidth
60
className="chart"
61
/>
62
</div>
63
</div>
64
);
65
}
66
}
pageview-app-nerdlet/index.js
1
@import `~leaflet/dist/leaflet.css`;
2
3
.container {
4
width: 100%;
5
height: 99vh;
6
display: flex;
7
flex-direction: column;
8
.row {
9
margin: 10px;
10
display: flex;
11
flex-direction: row;
12
}
13
.chart {
14
height: 250px;
15
}
16
}
17
18
.containerMap {
19
width: 100%;
20
z-index: 0;
21
height: 70vh;
22
}
pageview-app-nerdlet/styles.scss
1
module.exports = {
2
module: {
3
rules: [
4
{
5
test: /\.(png|jpe?g|gif)$/,
6
use: [
7
{
8
loader: 'file-loader',
9
options: {},
10
},
11
{
12
loader: 'url-loader',
13
options: { limit: 25000 },
14
},
15
],
16
},
17
],
18
},
19
};
.extended-webpackrc.js
Step 6 of 9

Customize the map marker colors

Above the mapData function, add this code to customize the map marker colors.

1
import React from 'react';
2
import {
3
TableChart,
4
TextField,
5
NerdGraphQuery,
6
Spinner,
7
Button,
8
BlockText,
9
} from 'nr1';
10
import { Map, CircleMarker, TileLayer } from 'react-leaflet';
11
12
const accountId = 0; // Replace with your account ID
13
14
export default class PageViewApp extends React.Component {
15
constructor(props) {
16
super(props);
17
this.state = {
18
countryCode: null,
19
};
20
}
21
22
getMarkerColor(measure, apdexTarget = 1.7) {
23
if (measure <= apdexTarget) {
24
return '#11A600';
25
} else if (measure >= apdexTarget && measure <= apdexTarget * 4) {
26
return '#FFD966';
27
} else {
28
return '#BF0016';
29
}
30
}
31
32
mapData() {
33
const { countryCode } = this.state;
34
const query = `{
35
actor {
36
account(id: 1606862) {
37
mapData: nrql(query: "SELECT count(*) as x, average(duration) as y, sum(asnLatitude)/count(*) as lat, sum(asnLongitude)/count(*) as lng FROM PageView FACET regionCode, countryCode WHERE appName = 'WebPortal' ${
38
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
39
} LIMIT 1000 ") {
40
results
41
nrql
42
}
43
}
44
}
45
}`;
46
47
return query;
48
}
49
50
render() {
51
const { countryCode } = this.state;
52
53
return (
54
<div className="container">
55
<div className="row">
56
<div className="row">
57
<TextField
58
placeholder="US"
59
onChange={(event) => {
60
this.setState({ countryCode: event.target.value });
61
}}
62
/>
63
</div>
64
<TableChart
65
accountId={accountId}
66
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' ${
67
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
68
} FACET countryCode, regionCode SINCE 1 week ago LIMIT 1000`}
69
fullWidth
70
className="chart"
71
/>
72
</div>
73
</div>
74
);
75
}
76
}
pageview-app-nerdlet/index.js
1
@import `~leaflet/dist/leaflet.css`;
2
3
.container {
4
width: 100%;
5
height: 99vh;
6
display: flex;
7
flex-direction: column;
8
.row {
9
margin: 10px;
10
display: flex;
11
flex-direction: row;
12
}
13
.chart {
14
height: 250px;
15
}
16
}
17
18
.containerMap {
19
width: 100%;
20
z-index: 0;
21
height: 70vh;
22
}
pageview-app-nerdlet/styles.scss
1
module.exports = {
2
module: {
3
rules: [
4
{
5
test: /\.(png|jpe?g|gif)$/,
6
use: [
7
{
8
loader: 'file-loader',
9
options: {},
10
},
11
{
12
loader: 'url-loader',
13
options: { limit: 25000 },
14
},
15
],
16
},
17
],
18
},
19
};
.extended-webpackrc.js

Feel free to change the HTML color code values to your taste. In this example, #11A600 is green, #FFD966 is sort of yellow, and #BF0016 is red.

Step 7 of 9

Set your map's default center point

Set a default center point for your map using latitude and longitude.

1
import React from 'react';
2
import {
3
TableChart,
4
TextField,
5
NerdGraphQuery,
6
Spinner,
7
Button,
8
BlockText,
9
} from 'nr1';
10
import { Map, CircleMarker, TileLayer } from 'react-leaflet';
11
12
const accountId = 0; // Replace with your account ID
13
14
export default class PageViewApp extends React.Component {
15
constructor(props) {
16
super(props);
17
this.state = {
18
countryCode: null,
19
};
20
}
21
22
getMarkerColor(measure, apdexTarget = 1.7) {
23
if (measure <= apdexTarget) {
24
return '#11A600';
25
} else if (measure >= apdexTarget && measure <= apdexTarget * 4) {
26
return '#FFD966';
27
} else {
28
return '#BF0016';
29
}
30
}
31
32
mapData() {
33
const { countryCode } = this.state;
34
const query = `{
35
actor {
36
account(id: 1606862) {
37
mapData: nrql(query: "SELECT count(*) as x, average(duration) as y, sum(asnLatitude)/count(*) as lat, sum(asnLongitude)/count(*) as lng FROM PageView FACET regionCode, countryCode WHERE appName = 'WebPortal' ${
38
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
39
} LIMIT 1000 ") {
40
results
41
nrql
42
}
43
}
44
}
45
}`;
46
47
return query;
48
}
49
50
render() {
51
const { countryCode } = this.state;
52
const defaultMapCenter = [10.5731, -7.5898];
53
54
return (
55
<div className="container">
56
<div className="row">
57
<div className="row">
58
<TextField
59
placeholder="US"
60
onChange={(event) => {
61
this.setState({ countryCode: event.target.value });
62
}}
63
/>
64
</div>
65
<TableChart
66
accountId={accountId}
67
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' ${
68
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
69
} FACET countryCode, regionCode SINCE 1 week ago LIMIT 1000`}
70
fullWidth
71
className="chart"
72
/>
73
</div>
74
</div>
75
);
76
}
77
}
pageview-app-nerdlet/index.js
1
@import `~leaflet/dist/leaflet.css`;
2
3
.container {
4
width: 100%;
5
height: 99vh;
6
display: flex;
7
flex-direction: column;
8
.row {
9
margin: 10px;
10
display: flex;
11
flex-direction: row;
12
}
13
.chart {
14
height: 250px;
15
}
16
}
17
18
.containerMap {
19
width: 100%;
20
z-index: 0;
21
height: 70vh;
22
}
pageview-app-nerdlet/styles.scss
1
module.exports = {
2
module: {
3
rules: [
4
{
5
test: /\.(png|jpe?g|gif)$/,
6
use: [
7
{
8
loader: 'file-loader',
9
options: {},
10
},
11
{
12
loader: 'url-loader',
13
options: { limit: 25000 },
14
},
15
],
16
},
17
],
18
},
19
};
.extended-webpackrc.js
Step 8 of 9

Add a row for your map

Between the text field row and the table chart row, insert a new row for the map content using NerdGraphQuery.

1
import React from 'react';
2
import {
3
TableChart,
4
TextField,
5
NerdGraphQuery,
6
Spinner,
7
Button,
8
BlockText,
9
} from 'nr1';
10
import { Map, CircleMarker, TileLayer } from 'react-leaflet';
11
12
const accountId = 0; // Replace with your account ID
13
14
export default class PageViewApp extends React.Component {
15
constructor(props) {
16
super(props);
17
this.state = {
18
countryCode: null,
19
};
20
}
21
22
getMarkerColor(measure, apdexTarget = 1.7) {
23
if (measure <= apdexTarget) {
24
return '#11A600';
25
} else if (measure >= apdexTarget && measure <= apdexTarget * 4) {
26
return '#FFD966';
27
} else {
28
return '#BF0016';
29
}
30
}
31
32
mapData() {
33
const { countryCode } = this.state;
34
const query = `{
35
actor {
36
account(id: 1606862) {
37
mapData: nrql(query: "SELECT count(*) as x, average(duration) as y, sum(asnLatitude)/count(*) as lat, sum(asnLongitude)/count(*) as lng FROM PageView FACET regionCode, countryCode WHERE appName = 'WebPortal' ${
38
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
39
} LIMIT 1000 ") {
40
results
41
nrql
42
}
43
}
44
}
45
}`;
46
47
return query;
48
}
49
50
render() {
51
const { countryCode } = this.state;
52
const defaultMapCenter = [10.5731, -7.5898];
53
54
return (
55
<div className="container">
56
<div className="row">
57
<div className="row">
58
<TextField
59
placeholder="US"
60
onChange={(event) => {
61
this.setState({ countryCode: event.target.value });
62
}}
63
/>
64
</div>
65
<div className="row">
66
<NerdGraphQuery query={this.mapData()}>
67
{({ loading, error, data }) => {
68
if (loading) {
69
return <Spinner fillContainer />;
70
}
71
if (error) {
72
return 'Error';
73
}
74
const { results } = data.actor.account.mapData;
75
console.debug(results);
76
return 'Hello';
77
}}
78
</NerdGraphQuery>
79
</div>
80
<TableChart
81
accountId={accountId}
82
query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' ${
83
countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
84
} FACET countryCode, regionCode SINCE 1 week ago LIMIT 1000`}
85
fullWidth
86
className="chart"
87
/>
88
</div>
89
</div>
90
);
91
}
92
}
pageview-app-nerdlet/index.js
1
@import `~leaflet/dist/leaflet.css`;
2
3
.container {
4
width: 100%;
5
height: 99vh;
6
display: flex;
7
flex-direction: column;
8
.row {
9
margin: 10px;
10
display: flex;
11
flex-direction: row;
12
}
13
.chart {
14
height: 250px;
15
}
16
}
17
18
.containerMap {
19
width: 100%;
20
z-index: 0;
21
height: 70vh;
22
}
pageview-app-nerdlet/styles.scss
1
module.exports = {
2
module: {
3
rules: [
4
{
5
test: /\.(png|jpe?g|gif)$/,
6
use: [
7
{
8
loader: 'file-loader',
9
options: {},
10
},
11
{
12
loader: 'url-loader',
13
options: { limit: 25000 },
14
},
15
],
16
},
17
],
18
},
19
};
.extended-webpackrc.js

Reload your application in New Relic to test that it works.

Step 9 of 9

Replace "Hello" with the Leaflet code

Replace return "Hello"; with:

import React from 'react';
import {
  TableChart,
  TextField,
  NerdGraphQuery,
  Spinner,
  Button,
  BlockText,
} from 'nr1';
import { Map, CircleMarker, TileLayer } from 'react-leaflet';

const accountId = 0; // Replace with your account ID

export default class PageViewApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      countryCode: null,
    };
  }

  getMarkerColor(measure, apdexTarget = 1.7) {
    if (measure <= apdexTarget) {
      return '#11A600';
    } else if (measure >= apdexTarget && measure <= apdexTarget * 4) {
      return '#FFD966';
    } else {
      return '#BF0016';
    }
  }

  mapData() {
    const { countryCode } = this.state;
    const query = `{
      actor {
        account(id: 1606862) {
          mapData: nrql(query: "SELECT count(*) as x, average(duration) as y, sum(asnLatitude)/count(*) as lat, sum(asnLongitude)/count(*) as lng FROM PageView FACET regionCode, countryCode WHERE appName = 'WebPortal' ${
            countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
          } LIMIT 1000 ") {
            results
            nrql
          }
        }
      }
    }`;

    return query;
  }

  render() {
    const { countryCode } = this.state;
    const defaultMapCenter = [10.5731, -7.5898];

    return (
      <div className="container">
        <div className="row">
          <div className="row">
            <TextField
              placeholder="US"
              onChange={(event) => {
                this.setState({ countryCode: event.target.value });
              }}
            />
          </div>
          <div className="row">
            <NerdGraphQuery query={this.mapData()}>
              {({ loading, error, data }) => {
                if (loading) {
                  return <Spinner fillContainer />;
                }
                if (error) {
                  return 'Error';
                }
                const { results } = data.actor.account.mapData;
                console.debug(results);

                return (
                  <Map
                    className="containerMap"
                    center={defaultMapCenter}
                    zoom={2}
                    zoomControl
                  >
                    <TileLayer
                      attribution='&copy OpenStreetMap contributors'
                      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                    />
                    {results.map((pt, i) => {
                      const center = [pt.lat, pt.lng];
                      return (
                        <CircleMarker
                          key={`circle-${i}`}
                          center={center}
                          color={this.getMarkerColor(pt.y)}
                          radius={Math.log(pt.x) * 3}
                          onClick={() => {
                            alert(JSON.stringify(pt));
                          }}
                        />
                      );
                    })}
                  </Map>
                );
              }}
            </NerdGraphQuery>
          </div>
          <TableChart
            accountId={accountId}
            query={`FROM PageView SELECT count(*), average(duration) WHERE appName = 'WebPortal' ${
              countryCode ? ` WHERE countryCode like '%${countryCode}%' ` : ''
            } FACET countryCode, regionCode SINCE 1 week ago LIMIT 1000`}
            fullWidth
            className="chart"
          />
        </div>
      </div>
    );
  }
}
pageview-app-nerdlet/index.js
1
@import `~leaflet/dist/leaflet.css`;
2
3
.container {
4
width: 100%;
5
height: 99vh;
6
display: flex;
7
flex-direction: column;
8
.row {
9
margin: 10px;
10
display: flex;
11
flex-direction: row;
12
}
13
.chart {
14
height: 250px;
15
}
16
}
17
18
.containerMap {
19
width: 100%;
20
z-index: 0;
21
height: 70vh;
22
}
pageview-app-nerdlet/styles.scss
1
module.exports = {
2
module: {
3
rules: [
4
{
5
test: /\.(png|jpe?g|gif)$/,
6
use: [
7
{
8
loader: 'file-loader',
9
options: {},
10
},
11
{
12
loader: 'url-loader',
13
options: { limit: 25000 },
14
},
15
],
16
},
17
],
18
},
19
};
.extended-webpackrc.js

This code creates a world map centered on the latitude and longitude you chose using OpenStreetMap data and your marker colors.

Reload your app to see the pageview data on the map!

Copyright © 2024 New Relic Inc.

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.