Skip to main content

Metrics

This module adds metrics to the Qore.

Installation

To install this module

composer require qore/metrics
php artisan vendor:publish --tag=qore.metrics.config
php artisan vendor:publish --tag=qore.metrics.frontend

In the frontend directory of the Qore, install ApexCharts using yarn:

yarn add apexcharts
yarn add vue-apexcharts

Usage

To use this module

Implement the following class on the resource like the following:

class ExampleResource extends QoreResource implements MetricResource

Then add the following functions to your resource:

public function indexMetrics(): MetricCollection
{
return new MetricCollection(

);
}

public function detailMetrics(): MetricCollection
{
return new MetricCollection(

);
}

Add the metric wrapper component to the resource:
You can override the indexComponents and detailComponents function from the QoreResource class to add the metric wrapper component to the index and/or detail page.

    public function indexComponents(): array
{
return [
QoreVueComponent::make('resource-alerts'),
QoreVueComponent::make('metric-wrapper'),
QoreVueComponent::make('resource-index-table'),
];
}

public function detailComponents(): array
{
return [
QoreVueComponent::make('resource-alerts'),
QoreVueComponent::make('resource-block-buttons'),
QoreVueComponent::make('metric-wrapper'),
QoreVueComponent::make('resource-detail'),
];
}

Available Metrics

The following metrics are available:

  • LineMetric
  • AreaMetric
  • BarMetric
  • ColumnMetric
  • ValueMetric

Creating a metric

To create a metric, you can add it to the MetricCollection similar to creating Qore fields.

public function indexMetrics(): MetricCollection
{
return new MetricCollection(
LineMetric::make(__('Title'), 'line_metric')
);
}

The code shown above will show a empty line metric on the index page. Further in this documentation, we will show how to customize the metric.

info

Metrics that you want to show on the index page should be added to the indexMetrics function. Metrics that you want to show on the detail page should be added to the detailMetrics function.

Creating a series (Displaying data)

To display data in a metric you have to create a series. This can be done by adding the following code to your metric.

->series(function () {
return LineSeries::make(__('Data title'))
->countByMonth(Model::class)
})

Based on what metric you are using you can use the following series:

  • LineMetric: LineSeries
  • AreaMetric: AreaSeries
  • BarMetric: BarSeries
  • ColumnMetric: ColumnSeries
  • ValueMetric: ValueSeries

Default queries

To easily retrieve data to show in your metric there are several default queries that can be used on series.

LineSeries::make(__('Data title'))
->countByMonth(Model::class) // count the records by month

The code above will use the created_at column to count the records by month. If you want to use a custom column, for example 'date' you can use the following:

LineSeries::make(__('Data title'))
->dateColumn('date')
->countByMonth(Model::class)

The following default queries are available for axis metrics:

// By default count will use the 'id' column to count the records.
// This can be customized in the second parameter.
->countByYear(Model::class, 'custom_column')
->countByMonth(Model::class)
->countByWeek(Model::class)
->countByDay(Model::class)
->countByHour(Model::class)
->countByMinute(Model::class)

// Specify which column to sum in the second parameter.
->sumByYear(Model::class, 'column')
->sumByMonth(Model::class, 'column')
->sumByWeek(Model::class, 'column')
->sumByDay(Model::class, 'column')
->sumByHour(Model::class, 'column')
->sumByMinute(Model::class, 'column')

// Specify which column to calculate the avg from in the second parameter.
->avgByYear(Model::class, 'column')
->avgByMonth(Model::class, 'column')
->avgByWeek(Model::class, 'column')
->avgByDay(Model::class, 'column')
->avgByHour(Model::class, 'column')
->avgByMinute(Model::class, 'column')

// Specify which column to get the min from in the second parameter.
->minByYear(Model::class, 'column')
->minByMonth(Model::class, 'column')
->minByWeek(Model::class, 'column')
->minByDay(Model::class, 'column')
->minByHour(Model::class, 'column')
->minByMinute(Model::class, 'column')

// Specify which column to get the max from in the second parameter.
->maxByYear(Model::class, 'column')
->maxByMonth(Model::class, 'column')
->maxByWeek(Model::class, 'column')
->maxByDay(Model::class, 'column')
->maxByHour(Model::class, 'column')
->maxByMinute(Model::class, 'column')

// To group results by a column instead of a date you can use the following:
->countByColumn(Model::class, 'group_by_column', 'count_column')
->sumByColumn(Model::class, 'group_by_column', 'sum_column')
->avgByColumn(Model::class, 'group_by_column', 'avg_column')
->minByColumn(Model::class, 'group_by_column', 'min_column')
->maxByColumn(Model::class, 'group_by_column', 'max_column')
warning

When using ....ByColumn queries, ranges cannot be used. Because you don't retrieve data based on a date but a different column.

Default queries for a value metric

The value metric also has some default queries. You can use the following:

->min(Model::class, 'column')
->max(Model::class, 'column')
->avg(Model::class, 'column')
->sum(Model::class, 'column')
->count(Model::class, 'column') // The column by default is 'id'

Using multiple series in one metric

It is possible to create multiple series of data. Note that this can only be done in line, area, bar and column metrics.

To do this, you can return a seriescollection instead of directly returning the series:

->series(function () {
return new SeriesCollection(
LineSeries::make(__('Series title'))
->countByMonth(Model::class),
LineSeries::make(__('Series title'))
->countByMonth(Model::class)
)
})
warning

When using multiple series in one metric make sure that the x-axis labels are the same. So you cannot use countByMonth for one series and countByWeek for another series on the same metric.

Custom x-axis label with default queries

When using the default queries that group by a date value, the x-axis label will be a date that is automatically formatted. This date format can be customized by adding the following to your series:

LineSeries::make(__('Series title'))
->countByMonth(Model::class)
->dateFormat('m-Y')
The default formats are:
'Y' // For years
'M' // For months
'W' // For weeks
'D' // For days
'The qore prefered time format' // For hours
'The qore prefered time format' // For minutes

Custom queries

Custom query

To create your own query while still using the functionality from the ranges and filters you can use the query() and mapUsing()

// Example when using an AreaMetric or any other metric where x and y values are needed.
AreaMetric::make('Festivals per maand', 'line_count_festivals')
->customRangeSelection()
->manualRefresh()
->series(function () {
return new SeriesCollection(
AreaSeries::make('Festivals')
->query(function (?QoreResource $resource, ?Model $model) {
return Festival::query();
})
->mapUsing(function (Collection $result) {
return $result->map(function (Festival $festival) {
return [
'x' => $festival->date->format('M'),
'y' => $festival->visitors,
];
})->toArray();
}));
}),

// Value metric to count the amount of festivals with a custom query.
ValueMetric::make('Aantal festivals', 'value_count_festivals')
->series(function () {
return ValueSeries::make('Festivals')
->rounded()
->query(function (?QoreResource $resource, ?Model $model) {
return Festival::query();
})
->mapUsing(function (Collection $result) {
return $result->count();
});
})

Custom calculation

If you require a more difficult query or a different way to get your data, you can use the calculateUsing function. In here you have to apply the ranges and filters yourself.

LineSeries::make(__('Series title'))
->calculateUsing(function (MetricRange $range, array $filters, ?QoreResource $resource, ?Model $model) {
// Your custom logic to retrieve data and apply ranges / filters.

// For example
return [
[
'x' => 'Jan',
'y' => 10
],
[
'x' => 'Feb',
'y' => 10
],
[
'x' => 'Mar',
'y' => 0
]
];

})

Metric ranges

To add a range selection to your metric you can add the following code to your metric.

->ranges([
MetricRange::today(),
MetricRange::yesterday()
])

Predefined ranges

For ease of use we have created a few predefined ranges that you can use.

MetricRange::all() // No range just retrieve all data.
MetricRange::today()
MetricRange::yesterday() 
MetricRange::ytd() // The start of the current year until today.
MetricRange::qtd() // The start of the current quarter until today.
MetricRange::mtd() // The start of the current month until today.
MetricRange::wtd() // The start of the current week until today.
MetricRange::year() // Start/end of the current year
MetricRange::quarter() // Start/end of the current quarter
MetricRange::month() // Start/end of the current month
MetricRange::week() // Start/end of the current week
info

If you want to use a custom label for a predefined range you can set this as parameter of the range:

MetricRange::today(__('Custom label'))

Creating a custom range

To create a custom range you can use the "make" function:

MetricRange::make(__('Past 30 days'), [
now()->subDays(30),
now()
])

Custom range selection

If you want the user to select their own range with a date picker you can use the customRangeSelection function.

This function has two optional parameters: min_date and max_date. To set the min and max date a user can pick as a range.

->customRangeSelection(now(), now()->addYears(1))

Hide range

If you want to hide the range menu. You can use the following code on your metric:

->hideRange()

Disable range

If you want to disable the range menu and make it only for showing purposes. You can use the following code on your metric:

->disableRange();

Metric filters

To add a filters to your metric you can add the following code to your series:

info

Filters has to be applied to Series and not directly to the metric. This is because the filters can be different for each series.

Toggle filter

The code shown below will add a toggleable filter to your metric that the user can enable/disable.

->filters([
MetricFilter::make(__('In Groningen'), 'Only show locations in Groningen')
->query(function (Builder $query) {
return $query->where('location', 'Groningen');
}),
])

As seen in the code below you can also supply a hint for the filter, as second parameter to the make() function.

Select filter

If you want a select filter you can add options to your filter as followed:

->filters([
MetricFilter::make(__('Location'))
->query(function (Builder $query, mixed $value) {
// The $value parameter is the selected value defined in the options. In this case 'Groningen' or 'Amsterdam'.
return $query->where('location', $value);
})
->options([
[
'label' => 'Groningen',
'value' => 'Groningen'
],
[
'label' => 'Amsterdam',
'value' => 'Amsterdam'
]
])

// You can also set your options with a callback function.
->options(function () {
return Locations::all()->map(function ($location) {
return [
'label' => $location->name,
'value' => $location->id,
];
});
})
])

Multi select filter

To enable multiselect simply add multiselect() to your filter as followed:

MetricFilter::make(__('Location'))
->query(function (Builder $query, mixed $value) {
// The $value parameter is an array of the selected values defined in the options.
return $query->whereIn('location', $value);
})
->options([
[
'label' => 'Groningen',
'value' => 'Groningen'
],
[
'label' => 'Amsterdam',
'value' => 'Amsterdam'
]
])
->multiselect()

Default filter

You can also set a default filter that will always be applied. This can be done by adding the following code to your series:
This closure needs to return the builder.

->defaultFilter(fn (Builder $query) => $query->where('location', 'Groningen'))

Axis metric options

The following customization options are available for every axis metric. (Line, Area, Bar, Column)

Toolbar

To show the metric toolbar you can add the following code to your metric.

->showToolbar()

Legend

info

The legend is by default only visible when using more than one series of data.

Hiding the legend:

->hideLegend()

Change the legends position

You can choose from: TOP, RIGHT, BOTTOM, LEFT

->legendPosition(LegendPosition::TOP)

Change the legends horizontal alignment

You can choose from: LEFT, CENTER, RIGHT

->legendHorizontalAlign(LegendAlign::LEFT)

X-Axis

Set a title:

The following code will set the title of the x-axis.

->xAxisTitle('Your title')

Y-Axis

Set a title:

The following code will set the title of the y-axis.

->yAxisTitle('Your title')

Datalabels

Enable datalabels

The enable datalabels you can add the following code to your metric.

->enableDataLabels()

Stroke

Change stroke curve (Line and Area metric)

By default the curve of the line and area metric is 'smooth' you can change this to 'straight', 'stepline' or 'monotoneCubic'.

->curve('straight')

Color palette

Qore Metrics uses the same color palettes as ApexCharts. These are defined on the ApexCharts website You can use the following code to set the color palette. (By default palette1 is used.)

->palette2() // 2, 3 ... 10 are available

Custom color palette

If you want to use a custom color palette you can use the following code:

->palette(['#123456', '#123456', '#123456'])

You can use as many colors as you want.

Sparkline

Sparkline is a setting to disable the toolbar, legend and axis labels and show a minimalistic version of the metric. You can enable it by adding the following code to your metric.

->sparkline() 

Common metric options

The following options are available for all metrics.

Refreshing

Manual refreshing of metric data

This will show a refresh button on the metric.

->manualRefresh()

Automatically refreshing of metric data

info

The minimum and default of the refresh interval is 1 minute.

->refreshInterval(2) // Refresh every 2 minutes

Caching

Enable caching the metrics result

To enable caching you can add the following code to your metric, with as parameter the ttl (time to live) in seconds.

->cache(60)

Width

To set the width of the metric you can use the following:

->setWidth('col-4')

//This is the default width
'col-12 col-md-6 col-lg-3'

Styling

To set additional styling you can use the following:

->setStyling('your custom styling')

Classes

To set additional classes you can use the following:

->setStyling('your custom classes')

Table Metric

The table metric uses the Qore Table class to show a table, and can be used as followed:

TableMetric::make('Tabel widget', 'table_widget')
->manualRefresh()
->refreshInterval(1)
->setWidth('col-4')
->table(CustomQoreTable::class)
->perPage(3),

How to create the CustomQoreTable class is explained in the Qore Table documentation. You only need to do the back-end part. The front-end is handled by the metrics module.

By default the history of the table is disabled to prevent conflicts in the url. But you can enable this by using:

->enableHistory()
info

The table metric only supports refreshing. filters and ranges are not supported.

Config

In the metrics config metrics.php all the default settings for apexcharts are set. You can change them here for all metrics or change the settings per metric.

Using metrics in a dashboard

When using a metric in a dashboard the implementation is slightly different then in the resources. To access the metrics they need a seperate class and be globally registered.

Creating a metric class

To create a new metric class you can use the following command:

php artisan make:metric ExampleMetric --type=line

This will create a new metric class in de App\Metrics folder. The type parameter can be one of the following: line, area, bar, column, value.

Registering a metric class

To register your metric class you can add the following to the register function in your AppServiceProvider.php

metrics()->register(new ExampleMetric());

The metric class

In the metric class you have to set the name, title, series and the ranges. This is the same as explained before in the resource metrics. But then in a class.

<?php

namespace App\Metrics;

use Qore\Metrics\Metrics\Line\LineMetric;
use Qore\Metrics\Metrics\MetricRange;
use Qore\Metrics\Collection\SeriesCollection;

class ExampleMetric extends LineMetric
{
public function name(): string
{
return 'ExampleMetric';
}

public function title(): string
{
// TODO: Implement title() method.
}

public function getSeries(): SeriesCollection
{
return new SeriesCollection(
// TODO: Add series here
);
}

public function getRanges(): array
{
return [
MetricRange::all()
];
}
}

If you want to add more customization options, for example caching you can enable this in the constructor of the metric class:

public function __construct()
{
$this->cache();
}

If you prefer to set these options in the dashboard class you can also do this:

(new ExampleMetric())
->xAxisTitel('Your title')
->cache()

Using the metric in a dashboard class

To use the metric in a dashboard you can add it to your dashboard just like you would add any other widget in a dashboard.

info

For more information about creating dashboards and adding widgets to your dashboard see the dashboard documentation.

Using a metric as a loose component

You can also use a metric in a custom place in your application.

info

Make sure to register your metric class the same way as you would do in a dashboard.

Use the Metric component in your vue component to show the metric.

<Metric metric-name="the_registered_name_of_your_metric" />