Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set up highchart #3506

Draft
wants to merge 10 commits into
base: main
Choose a base branch
from
Draft
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,5 +132,8 @@
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"highcharts": "^12.1.2"
}
}
7 changes: 7 additions & 0 deletions src/components/chart/_chart.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.ons-chart {
margin: 0;
&__download-title {
@extend .ons-u-pt-l;
@extend .ons-u-fs-r--b;
}
}
117 changes: 117 additions & 0 deletions src/components/chart/_macro-options.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
| Name | Type | Required | Description |
| ----------- | ------ | -------- | ------------------------------------------------------------------------------------------ |
| chartType | string | true | The type of chart to render (e.g., 'line', 'bar', etc.). |
| theme | string | true | The theme to apply to the chart. Either `primary` or `alternate`. |
| title | string | true | The main title of the chart. |
| subtitle | string | true | A subtitle that appears under the main title. |
| uuid | string | true | A unique identifier for the chart instance. |
| caption | string | false | A caption providing additional context for the chart. |
| description | string | false | A textual description of the chart for screen readers. |
| download | object | false | Object for (download)[#download] options. |
| config | object | true | The full [configuration](#config) object passed to Highcharts, defining axes, series, etc. |

### Download

| Property | Type | Required | Description |
| --------- | ------ | -------- | -------------------------------------------------------------------------------------------- |
| title | string | false | The title displayed above the download options. |
| itemsList | array | false | An array of items available for download, each described by a (DownloadItem)[#DownloadItem]. |

### DownloadItem

| Property | Type | Required | Description |
| -------- | ------ | -------- | -------------------------------------------------- |
| `text` | string | true | The label or description of the downloadable item. |
| `url` | string | true | The URL to the downloadable resource. |

### Config

| Name | Type | Required | Description |
| ------ | ------ | -------- | ----------------------------------------------------------------------------------------- |
| chart | object | true | Defines the [chart's](#chart) overall behavior and appearance. |
| legend | object | false | Controls the appearance and behavior of the [legend](#legend). |
| yAxis | object | true | Defines the vertical axis [y-axis](#y_axis) properties, including labels and title. |
| xAxis | object | true | Defines the horizontal axis [x-axis](#x_axis) properties, including categories and title. |
| series | array | true | The data [series](#series) to be plotted, including labels and values. |

### Chart

| Name | Type | Required | Description |
| ---- | ------ | -------- | -------------------------------------------------------- |
| type | string | true | The type of chart (e.g., `'line'`, `'bar'`, `'column'`). |

### Legend

| Name | Type | Required | Description |
| ------------- | ------- | -------- | --------------------------------------------------------------- |
| enabled | boolean | false | Whether the legend is displayed. Defaults to `true`. |
| align | string | false | Horizontal alignment of the legend (`left`, `center`, `right`). |
| verticalAlign | string | false | Vertical alignment of the legend (`top`, `middle`, `bottom`). |
| layout | string | false | Legend layout (`horizontal` or `vertical`). |

### Y_Axis

| Name | Type | Required | Description |
| -------- | ------- | -------- | --------------------------------------------------------------------- |
| title | object | true | Defines the [title](#title) of the y-axis. |
| reversed | boolean | false | Sets the axis so that the highest number is closest to the origin. |
| labels | object | false | The axis [labels](#labels) show the number or category for each tick. |

### X_Axis

| Name | Type | Required | Description |
| ------------ | ------- | -------- | ---------------------------------------------------------------------------------- |
| title | object | true | Defines the [title](#title) of the x-axis. |
| categories | array | false | Labels for each tick mark along the x-axis. |
| reversed | boolean | false | Sets the axis so that the highest number is closest to the origin. |
| type | string | false | The type of axis. Can be one of `linear`, `logarithmic`, `datetime` or `category`. |
| labels | object | false | The axis [labels](#labels) show the number or category for each tick. |
| tickInterval | number | false | The interval of the tick marks in axis units |

### Title

| Name | Type | Required | Description |
| ---- | ------ | -------- | ------------------------------------------------- |
| text | string | true | The title text displayed on the y-axis or x-axis. |

### Labels

| Name | Type | Required | Description |
| ------ | ------ | -------- | ----------------------------------- |
| format | string | false | A format string for the axis label. |

### Series

| Name | Type | Required | Description |
| ---------- | ------ | -------- | ------------------------------------------------------------------------------------------- |
| name | string | true | The name of the series. |
| data | array | true | The data values for the series. Each value corresponds to a category on the x-axis. |
| dataLabels | object | false | Configuration options for displaying labels on the data points. |
| marker | object | false | Configuration options for the series (markers)[#markers]. |
| tooltip | object | false | Customization options for the (tooltip)[#tooltip] displayed when hovering over data points. |
| animation | object | false | Defines (animation)[#animation] options for rendering the series. Defaults to false. |

### DataLabel

| Name | Type | Required | Description |
| ------- | ------- | -------- | -------------------------------------------------------- |
| enabled | boolean | false | Whether the DataLabel is displayed. Defaults to `false`. |

### Marker

| Name | Type | Required | Description |
| ------- | ------- | -------- | ----------------------------------------------------------------- |
| enabled | boolean | false | Whether markers are displayed for the series. Defaults to `true`. |
| symbol | string | false | The shape of the marker (`circle`, `square`, `diamond`, etc.). |

### Tooltip

| Name | Type | Required | Description |
| ----------- | ------ | -------- | ------------------------------------------------------------ |
| valueSuffix | string | false | A string to append to each tooltip value (e.g., '°C', 'kg'). |

#### Animation

| Name | Type | Required | Description |
| -------- | ------ | -------- | ------------------------------------------------------------- |
| duration | number | false | Duration of the animation in milliseconds. Default is `1000`. |
36 changes: 36 additions & 0 deletions src/components/chart/_macro.njk
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{% from "components/list/_macro.njk" import onsList %}

{% macro onsChart(params) %}
<div
data-highcharts-base-chart
data-highcharts-type="{{ params.chartType }}"
data-highcharts-theme="{{ params.theme }}"
data-highcharts-title="{{ params.title }}"
data-highcharts-uuid="{{ params.uuid }}"
>
<figure class="ons-chart">
<h3>{{ params.title }}</h3>
<h4>{{ params.subtitle }}</h4>
<h5 class="ons-u-vh">{{ params.description }}</h5>
<div data-highcharts-chart></div>
{% if params.caption %}
<figcaption>{{ params.caption }}</figcaption>
{% endif %}
</figure>

{% if params.download.title and params.download.itemsList | length > 0 %}
<h6 class="ons-chart__download-title">{{ params.download.title }}</h6>
{{
onsList({
"element": "ol",
"itemsList": params.download.itemsList
})
}}
{% endif %}

<!-- Set scripts to pass the config values as json to the javascript -->
{# <script type="application/json" data-highcharts-config--{{ params.uuid }}>
{{ params.config | dump | safe }}
</script> #}
</div>
{% endmacro %}
8 changes: 8 additions & 0 deletions src/components/chart/chart.dom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import HighchartsBaseChart from './chart';
import domready from '../../js/domready';

domready(async () => {
[HighchartsBaseChart].forEach((Component) => {
document.querySelectorAll(Component.selector()).forEach((el) => new Component(el));
});
});
55 changes: 55 additions & 0 deletions src/components/chart/chart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import CommonChartOptions from './common-chart-options';
import SpecificChartOptions from './specific-chart-options';
import LineChartPlotOptions from './line-chart';
import Highcharts from 'highcharts';

class HighchartsBaseChart {
static selector() {
return '[data-highcharts-base-chart]';
}

constructor(node) {
this.node = node;
this.chartType = this.node.dataset.highchartsType;
this.theme = this.node.dataset.highchartsTheme;
this.title = this.node.dataset.highchartsTitle;
const chartNode = this.node.querySelector('[data-highcharts-chart]');

this.uuid = this.node.dataset.highchartsUuid;

this.config = JSON.parse(this.node.querySelector(`[data-highcharts-config--${this.uuid}]`).textContent);

this.commonChartOptions = new CommonChartOptions();
this.specificChartOptions = new SpecificChartOptions(this.theme, this.chartType);

if (window.isCommonChartOptionsDefined === undefined) {
this.setCommonChartOptions();
window.isCommonChartOptionsDefined = true;
}

this.setSpecificChartOptions();

Highcharts.chart(chartNode, this.config);
}

// Set up the global Highcharts options
setCommonChartOptions = () => {
const chartOptions = this.commonChartOptions.getOptions();
Highcharts.setOptions(chartOptions);
};

setSpecificChartOptions = () => {
const specificChartOptions = this.specificChartOptions.getOptions();
for (const option in specificChartOptions) {
this.config[option] = specificChartOptions[option];
}
// Add the line chart plotOptions to the config - merge with
// any existing plotOptions
this.config.plotOptions = {
...(Highcharts.getOptions()?.plotOptions || {}),
line: new LineChartPlotOptions().plotOptions.line,
};
};
}

export default HighchartsBaseChart;
118 changes: 118 additions & 0 deletions src/components/chart/common-chart-options.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
class CommonChartOptions {
constructor() {
this.constants = {
axisLabelColor: '#707071',
gridLineColor: '#d9d9d9',
zeroLineColor: '#b3b3b3',
// Responsive font sizes
mobileFontSize: '0.875rem',
desktopFontSize: '1rem',
};

this.options = {
chart: {
backgroundColor: 'transparent',
style: {
fontFamily: '"OpenSans", "Helvetica Neue", arial, sans-serif',
color: '#222222',
},
},
// Remove the chart title as rendered by Highcharts, as this is rendered in the surrounding component
title: {
text: '',
},
credits: {
// Remove Highcharts watermark
enabled: false,
},
accessibility: {
enabled: true,
},
yAxis: {
labels: {
style: {
color: this.constants.axisLabelColor,
fontSize: this.constants.desktopFontSize,
},
},
title: {
align: 'high',
offset: 0,
rotation: 0,
y: -25,
},
lineColor: this.constants.gridLineColor,
gridLineColor: this.constants.gridLineColor,
zeroLineColor: this.constants.zeroLineColor,
},
xAxis: {
labels: {
rotation: 0,
style: {
color: this.constants.axisLabelColor,
fontSize: this.constants.desktopFontSize,
},
},
title: {
align: 'high',
},
lineColor: this.constants.gridLineColor,
gridLineColor: this.constants.gridLineColor,
zeroLineColor: this.constants.zeroLineColor,
// Add tick marks
tickWidth: 1,
tickLength: 6,
tickColor: this.constants.gridLineColor,
},
plotOptions: {
series: {
// disabes the tooltip on hover
enableMouseTracking: false,

// disables the legend item hover
states: {
inactive: {
enabled: false,
},
},
},
},
// Adjust font size for smaller width of chart
// Note this is not the same as the viewport width
responsive: {
rules: [
{
condition: {
maxWidth: 400,
},
chartOptions: {
legend: {
itemStyle: {
fontSize: this.constants.mobileFontSize,
},
},
xAxis: {
labels: {
style: {
fontSize: this.constants.mobileFontSize,
},
},
},
yAxis: {
labels: {
style: {
fontSize: this.constants.mobileFontSize,
},
},
},
},
},
],
},
};
}

getOptions = () => this.options;
}

export default CommonChartOptions;
Loading
Loading