I'm trying resource timeline custom view like below. The problem is last week of the year does not show and the last week of the previous year show up wrongly. Am i doing something wrong or this is a fullcalendar bug i don't know.
Sorry for my bad english. Any help would be greatly appriciated!
Thanks!
Here is my fullCalendar settings
{
initialDate: moment().startOf('year')._d,
customButtons: {
eventFilterButton: {
text: 'Filtrele',
click: function(e) {
setFilterPopupPosition({
top: e.clientY + window.scrollY,
left: e.clientX - 220,
});
setFilterPopupvisibility(true);
}
}
},
slotMinWidth: 40,
showNonCurrentDates: false,
fixedWeekCount: true,
slotLabelFormat: [
{ month: "long"}, // top level of text
{ week: "number" } // lower level of text
],
slotLabelContent: (arg) => {
if ( Number(arg.text) ) {
const result = getWeekOfMonth(arg.date);
return result;
}
},
height: window.innerHeight - 220,
eventMaxStack: 5,
scrollTimeReset: false,
stickyHeaderDates: true,
eventBackgroundColor: 'transparent',
eventBorderColor: 'transparent',
selectable: true,
initialView: 'resourceTimelineMonths',
locale: 'en',
weekends: true,
defaultView: 'resourceTimeline',
eventContent: renderEventContent,
views: {
resourceTimelineMonths: {
type: 'resourceTimeline',
duration: { months: 12 },
buttonText: 'Aylık Görünüm',
slotDuration: {
weeks: 1,
}
},
},
headerToolbar: {
right: 'today eventFilterButton' // prev,next
},
resourceLabelContent: function (renderInfo) {
return (<CalendarResourceItem resources={calendarResources.current} forceUpdateValue={forceUpdateValue} expanded={rersourceGroupExpandState.current[renderInfo.resource.id]} renderInfo={renderInfo} resourceMenuClickCallback={resourceMenuClickCallback} expandCallback={handleResourceExpand}/>)
},
resourceAreaWidth: '222px',
resourceAreaHeaderContent: yearPicker,
dayHeaderFormat: {
day: 'short',
weekday: 'short',
month: 'numeric',
week: 'numeric',
omitCommas: true,
},
allDayDefault: true,
droppable: true,
editable: true,
resourceGroupLabelContent: function (renderInfo) {
console.log('resourceGroupLabelContent', renderInfo)
return (
<div
className="schedule--resourceLabel"
onClick={() => handleResourceLAbelClick(renderInfo.groupValue)}
>
{renderInfo.groupValue}{' '}
{rersourceGroupExpandState.current[renderInfo.resource.id] ? (
<Icon rotate={180} component={IconChevronUp} />
) : (
<Icon component={IconChevronUp} />
)}
</div>
)
},
resourceLabelDidMount: (info) => {
setTimeout(() => {
// console.warn('************************ resourceGroupLabelDidMount --------------------------', info)
resourceExpanderElementList.push({
selector: info.resource.id,
el: info.el.querySelector('.fc-datagrid-expander'),
})
taskAssignmentStore.dispatch({
type: 'SET_RESOURCE_EXPAND_LABELS',
resourceLabels: resourceExpanderElementList,
})
rersourceGroupExpandState.current[info.resource.id] = false
});
},
}
Related
So I have react-datepicker to choose the dates of my data, the data that is returned looks like this:
{clicks: 6, date: "2022-05-15", link: "instagram"},
{clicks: 5, date: "2022-05-15", link: "google"}...
On load and every change in the datePicker, I have this function which sets the data variables, the date will be moment():
const onChangeClick = (dates: any) => {
const [start, end] = dates;
setStartDateClick(start);
setEndDateClick(end);
if (start & end) {
let dates = {
dateFrom: moment(start).format('YYYY-MM-DD'),
dateTo: moment(end).format("YYYY-MM-DD")
}
_statisticsService.getClickStats(dates).then((response: any) => {
response.data.map((e: any) => {
clicksData[e?.link].push(e)
})
setInstaDataClick(clicksData['instagram'].map((e: any) => {
return { clicks: e.clicks, date: moment(e.date) }
}))
setFacebookDataClick(clicksData['facebook'].map((e: any) => {
return { clicks: e.clicks, date: moment(e.date) }
}))
setGoogleDataClick(clicksData['google'].map((e: any) => {
return { clicks: e.clicks, date: moment(e.date) }
}))
setTripadvisorDataClick(clicksData['tripadvisor'].map((e: any) => {
return { clicks: e.clicks, date: moment(e.date) }
}))
setWebsiteDataClick(clicksData['website'].map((e: any) => {
return { clicks: e.clicks, date: moment(e.date) }
}))
})
setLabelsClick(getDaysArray(clicksData[0]?.date, clicksData[clicksData.length - 1].date))
}
};
And later I use this values in the datasets:
const data = {
labels: labelsClick,
datasets: [
{
label: 'Instagram',
data: instaDataClick,
borderColor: '#c32aa3',
backgroundColor: '#c32aa3',
},
{
label: 'Facebook',
data: facebookDataClick,
borderColor: '#1877f2',
backgroundColor: '#1877f2',
},
{
label: 'Google',
data: googleDataClick,
borderColor: '#ea4335',
backgroundColor: '#ea4335',
},
{
label: 'Tripadvisor',
data: tripadvisorDataClick,
borderColor: '#34e0a1',
backgroundColor: '#34e0a1',
},
{
label: 'Website',
data: websiteDataClick,
borderColor: '#010101',
backgroundColor: '#010101',
},
],
};
And at the end this is how I preview the Line chart
<div className='datepicker-container'>
<DatePicker
onChange={onChangeClick}
startDate={startDateClick}
endDate={endDateClick}
selectsRange
placeholderText='Select Date'
isClearable
/>
</div>
<div className='chart'>
<Line options={options} data={data} />
</div>
The options for this line look like this, x axis is the date and y is the clicks:
const options: ChartOptions<'line'> = {
responsive: true,
scales: {
y: {
title: {
display: true,
text: 'Date'
},
ticks: {
precision: 0,
}
},
x: {
type: 'time',
title: {
display: true,
text: "Date"
},
time: {
unit: 'day',
stepSize: 1,
displayFormats: {
day: "MMM DD"
}
}
},
},
parsing: {
xAxisKey: 'date',
yAxisKey: 'clicks',
},
plugins: {
legend: {
position: 'top',
},
title: {
display: true,
text: 'Click statistics',
},
},
};
And now THE PROBLEM:
On first load, the first line in the dataset, in this case Instagram, shows like this:
The instagram line has a different animation, what could be the problem?
[edit]: Changing the animation in options won't affect the instagram line, it will still come from the left, depending on the animation, it will come either slower or faster, but always from left.
For anyone who has the same issue in the future, here is the solution:
The problem with my code was that the first state of the instaDataClick variable was an empty array, it should have a date property, because the x axis is the date.
so the variable should look something like this:
const initialStartDate = new Date(moment().subtract(10, 'd').format('YYYY-MM-DD'))
const initialEndDate = new Date(moment().format('YYYY-MM-DD'))
const [instaDataClick, setInstaDataClick] = useState(
getDaysArray(initialStartDate.toString(), initialEndDate.toString()).map((e)=>{
return {clicks: null, date: e}
})
)
the function getDaysArray:
const getDaysArray = function (start: any, end: any) {
for (var arr = [], dt = new Date(start); dt <= new Date(end); dt.setDate(dt.getDate() + 1)) {
arr.push(new Date(dt).toString().substr(4, 6));
}
return arr;
};
And by doing this, we're setting the initial position of the line.
I'd like to be able to render a React Component inside of a HighCharts Graph. I'd like to render the component DatePicker inside my HighCharts Graph, rather than being above it like it currently is? I'm using the HighCharts Official React Wrapper, and this is what my code looks like:
function Graph(props) {
const [startDate, setStartDate] = useState(new Date('1969-11-19 PST'));
const [bx, setBx] = useState([]);
const [by, setBy] = useState([]);
const [bz, setBz] = useState([]);
async function getData(table, year, month, day) {
...
}
useEffect(() => {
...
}, [startDate])
var options = {
chart: {
events: {
load: function() {
this.showLoading();
setTimeout(this.hideLoading.bind(this), 2000);
}
}
},
lang: {
noData: "Awaiting for data"
},
rangeSelector: {
inputEnabled: false,
buttons: [
{
type: 'all',
text: '1d',
title: 'View 1 Day'
},
{
type: 'minute',
count: 10,
text: '10m',
title: 'View 10 minutes'
},
{
type: 'minute',
count: 1,
text: '1m',
title: 'View 1 minutes'
},
{
type: 'second',
count: 30,
text: '30s',
title: 'View 30 seconds'
},
]
},
chart: {
zoomType: 'x'
},
title: {
text: props.title
},
xAxis: {
type: 'datetime'
},
time: {
timezoneOffset: 8*60
},
series: [
{
marker: {
enabled: true,
radius: 2
},
color: 'red',
name: 'Bx',
pointStart: startDate.getTime(),
pointInterval: 1000,
data: bx // data has to be [x, y] pairs
},
{
marker: {
enabled: true,
radius: 2
},
color: 'blue',
name: 'By',
pointStart: startDate.getTime(),
pointInterval: 1000,
data: by
},
{
marker: {
enabled: true,
radius: 2
},
color: 'green',
name: 'Bz',
pointStart: startDate.getTime(),
pointInterval: 1000,
data: bz
}
]
}
const isValidDate = (date) => {
date.getTime();
const origDate = new Date('1969-11-19 PST');
const finalDate = new Date('1970-04-03 PST');
console.log("GET DATE", date.getTime()) // getting number day of month
const bool = origDate.getTime() <= date.getTime() && date.getTime() <= finalDate.getTime();
return bool;
}
return (
<React.Fragment>
<DatePicker
selected={startDate}
filterDate={isValidDate}
onChange={(date) => setStartDate(date)}
/>
<HighchartsReact
highcharts={Highcharts}
constructorType={'stockChart'}
options={options}
/>
</React.Fragment>
);
}
I see this example from the HighCharts React Official Wrapper Github, but I'm still a bit confused by it and am wondering if I could simply do the same thing with a functional component. https://codesandbox.io/s/1o5y7r31k3
I've made a codesandbox of my code here https://codesandbox.io/s/friendly-moon-y8guc
I'm using highcharts-react-official to render a HighchartsReact component. It shows up and works appropriately until I re-render the component. By changing the state at all, the chart will shrink vertically.
I've experimented with setting reflow in the chart options as well as toggling allowChartUpdate and immutable flags on the component itself to no avail.
const ChartView = props => {
const { data } = props;
if(data.highstockData && data.startDate && data.endDate) {
const min = parseInt(moment(data.startDate, 'x').startOf('day').format('x'));
const max = parseInt(moment(data.endDate, 'x').startOf('day').format('x'));
const chartOptions = getChartConfig(data.highstockData, min, max);
return (
<HighchartsReact
highcharts={Highcharts}
options={chartOptions}
/>
)
}
return null;
};
And the parent Component's render return:
return (
<div className="vertical-margin">
{isFetching && !data && <LoadingView/>}
{hasError && !data && <ErrorView/>}
{
data &&
<React.Fragment>
{buttonRow}
<ChartView
data={data}
/>
</React.Fragment>
}
</div>
)
As I said re-rendering for any reason causes the highchart to shrink in height with each re-render. For testing, I call this line:
this.setState({});
I could post the chart config if needed, but it's nothing too fancy.
I haven't been able to find anyone else having this issue and have been pulling my hair out searching for an answer.
It turned out to indeed be a highchart option I was passing into the component. Apparently it was because this option:
scrollbar: {
enabled: true
},
Was not nested under the xAxis section of the options as it should be. It still created a scrollbar correctly but caused this weird, shrinking issue on component render.
chart: {
marginRight: 75,
ignoreHiddenSeries: false,
panning: false,
spacingTop: 10,
height: `${Constants.HIGHCHART_TABLE_HEIGHT}px`,
},
time: {
useUTC: false
},
credits: {
enabled: false
},
exporting: {
enabled: false
},
legend: {
align: 'left',
enabled: true,
itemMarginTop: 5,
itemStyle: {
"color": "#333333",
"cursor": "pointer",
"fontSize": "12px",
"fontWeight": "normal",
"width": "240px"
},
layout: 'vertical',
verticalAlign: 'top',
y: 0
},
navigator: {
enabled: false,
xAxis: {
tickPixelInterval: 100
}
},
plotOptions: {
line: {
marker: {
enabled: true,
fillColor: "#ffffff",
lineColor: null,
lineWidth: 1
}
}
},
rangeSelector: {
enabled: false
},
tooltip: {
formatter: function () {
const sortedPoints = this.points.sort((a, b) => {
return a.point.legendOrder - b.point.legendOrder
});
return [
'<b>',
moment(this.x, 'x').format('MM/DD/YYYY HH:mm'),
'</b><br/>',
sortedPoints.map((item) => {
return [
'<br/><span style="color:'+ item.series.color +';">\u258c</span> ',
'<span>' + item.series.name + '</span>: <b>' + item.y + '</b>',
item.comments ? '<p>(' + item.comments + ')</p>' : ''
].join('');
}).join('')
].join('');
},
shared: true,
crosshairs: {
color: '#ddd',
dashStyle: 'solid'
},
},
xAxis: {
type: 'datetime',
labels:{
formatter: function() {
const parsed = moment(this.value, 'x');
return parsed.format('HH:mm') + '<br/>' + parsed.format('MM/DD');
}
},
min,
max,
reversed: true,
scrollbar: {
enabled: true
},
},
yAxis: [{
alignTicks: false,
max: 60,
min: 0,
opposite: false,
tickInterval: 5,
title: {
text: ''
}
}, {
alignTicks: false,
max: 300,
min: 0,
opposite: true,
tickInterval: 25,
title: {
text: ''
}
}],
//The below properties are watched separately for changes.
series: data,
title: {
text: ''
},
loading: false,
};
Also here's the full options file for reference. It wasn't just that scrollbar option causing it. It was a specific combination of options as I discovered by trying to re-create the problem with a new chart.
I would like to switch from React Highcharts to React Highstock because of the compare option I would like to use in Highstock. Here is my config:
var config = {
credits: {
enabled: false
},
title: {
text: '' // No Title
},
chart: {
height: 200,
type: 'line',
backgroundColor: 'rgba(155, 255, 255, 0.0)' // Always transparent Background
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2,
split: true
},
yAxis: {
labels: {
format: '$ {value}' // Always Money
},
title: {
text: '' // No Label
}
},
xAxis: {
type: 'datetime',
labels: {
format: '{value:%Y\'%b}'
},
tickInterval: getTickInterval(this.props.interval),
},
plotOptions: {
series: {
color: transformColor(this.props.color),
lineWidth: 1,
compare: 'percent',
showInNavigator: true
},
line: {
marker: {
enabled: false
}
}
},
legend: {
layout:'vertical',
align: getLegendPosition(this.props.legend).align,
verticalAlign: getLegendPosition(this.props.legend).verticalAlign,
x: getLegendPosition(this.props.legend).x,
y: getLegendPosition(this.props.legend).y,
floating: true,
itemStyle: {
font: 'sans-serif',
fontWeight: 'bold',
fontSize: '9px'
},
symbolHeight: 10,
symbolWidth: 10
},
series: this.props.series
};
return (
<div>
<ReactHighcharts config={config}/>
</div>
)
}
But when I switch to Highstock:
return (
<div>
<ReactHighstock config={config}/>
</div>
)
It gives me an error:
InvalidCharacterError: Failed to execute 'createElement' on 'Document': The tag name provided ('/static/media/Highstock.a88db6d5.jsx') is not a valid name.
Any ideas?
Nevermind, don't actually use the React-Highstock npm package. Just do this:
const ReactHighstock = require('react-highcharts/ReactHighstock');
I have recently implemented chart display using react-chartjs-2 (https://github.com/jerairrest/react-chartjs-2)
I want to enable zooming and panning feature so that it will be more user-friendly in touch based screens. To implement this features, I installed react-hammerjs and chartjs-plugin-zoom.
import {Chart, Line} from 'react-chartjs-2';
import Hammer from 'react-hammerjs';
import zoom from 'chartjs-plugin-zoom'
And I registered the plugin
componentWillMount(){
Chart.plugins.register(zoom)
}
And the render method goes as follows:
render(){
return <Line data={data} options={options} />
}
Pan and Zoom options:
pan:{
enabled=true,
mode:'x'
},
zoom:{
enabled:true,
drag:true,
mode:'xy'
}
I guess this is the correct method to implement. Unfortunately, the above implementation did not work. I will be really grateful if some of you guys already implemented Zooming and Panning using react-chartjs-2 plugin, please share if how you achieved these functionalities. Or you could point out the problem in my code above.
In order to add Zoom and Pan capabilities to your chart components based on react-chartjs-2, you can follow the steps as shown below:
Step 1: you need to install chartjs-plugin-zoom
$ npm install chartjs-plugin-zoom
Step 2: Import chartjs-plugin-zoom in your chart component
import 'chartjs-plugin-zoom';
Step 3: Enable zoom and pan in the ChartJS component options
zoom: {
enabled: true,
mode: 'x',
},
pan: {
enabled: true,
mode: 'x',
},
That's it. So now your chart component should look like this:
import React from 'react';
import { Line } from 'react-chartjs-2';
import 'chartjs-plugin-zoom';
export default function TimelineChart({ dailyDataSets }) {
const lineChart = dailyDataSets[0] ? (
<Line
data={{
labels: dailyDataSets.map(({ date }) => date),
datasets: [
{
data: dailyDataSets.map((data) => data.attr1),
label: 'First data set',
borderColor: 'red',
fill: true,
},
{
data: dailyDataSets.map((data) => data.attr2),
label: 'Second data set',
borderColor: 'green',
fill: true,
},
],
}}
options={{
title: { display: true, text: 'My Chart' },
zoom: {
enabled: true,
mode: 'x',
},
pan: {
enabled: true,
mode: 'x',
},
}}
/>
) : null;
return <div>{lineChart}</div>;
}
Notes:
You don't have to install hammerjs explicitly, as it will be automatically included by installing chartjs-plugin-zoom as its dependency, see below:
$ npm ls
...
├─┬ chartjs-plugin-zoom#0.7.7
│ └── hammerjs#2.0.8
...
One way to zoom as an example (at least for Mac), you can move your mouse pointer into the chart area, and then scroll your mouse down or up. Once zoomed in, you can keep your mouse clicked while dragging left or right.
There's a syntax error under pan object for enabled attribute.
You've mistakenly put = instead of :
Replace this:
pan:{
enabled=true,
...
},
With:
pan:{
enabled:true,
...
},
And also as #Jun Bin suggested:
Install hammerjs as:
npm install hammerjs --save
And in your component, import it as:
import Hammer from "hammerjs";
you imported the wrong hammer it should be from "hammerjs";
You need to add import 'chartjs-plugin-zoom'; and then add zoom options into options.plugins.zoom, like:
const options = {
plugins: {
zoom: {
pan: {
enabled: true,
mode: 'x',
},
zoom: {
enabled: true,
drag: true,
mode: 'xy'
}
}
}
};
I am trying to do this in a NextJS Project. But to no success so far.
I am using a timeseries plot with date-fns/locale for German and English and keep getting this error:
Cannot convert a Symbol value to a string
TypeError: Cannot convert a Symbol value to a string at TypedRegistry.register (webpack-internal:///./node_modules/chart.js/dist/chart.esm.js:4802:50) at Registry._exec (webpack-internal:///./node_modules/chart.js/dist/chart.esm.js:4927:21) at eval (webpack-internal:///./node_modules/chart.js/dist/chart.esm.js:4919:16) at each (webpack-internal:///./node_modules/chart.js/dist/chunks/helpers.segment.js:233:10) at eval (webpack-internal:///./node_modules/chart.js/dist/chart.esm.js:4917:70) at Array.forEach (<anonymous>) at Registry._each (webpack-internal:///./node_modules/chart.js/dist/chart.esm.js:4912:15) at Registry.add (webpack-internal:///./node_modules/chart.js/dist/chart.esm.js:4870:10) at Function.value [as register] (webpack-internal:///./node_modules/chart.js/dist/chart.esm.js:6192:16) at eval (webpack-internal:///./components/Charts/PortfolioPriceLineDual.jsx:39:45) at Module../components/Charts/PortfolioPriceLineDual.jsx (https://dev.domain.de/_next/static/chunks/components_Charts_PortfolioPriceLineDual_jsx.js:7758:1) at Module.options.factory (https://dev.domain.de/_next/static/chunks/webpack.js?ts=1653499440538:655:31) at __webpack_require__ (https://dev.domain.de/_next/static/chunks/webpack.js?ts=1653499440538:37:33) at Function.fn (https://dev.domain.de/_next/static/chunks/webpack.js?ts=1653499440538:310:21)
My Component:
import { Line } from 'react-chartjs-2'
import 'chartjs-adapter-date-fns'
import { de, enGB, ja } from 'date-fns/locale'
import dynamic from 'next/dynamic'
import 'chart.js/auto'
import { useRouter } from 'next/router'
import { Chart } from 'chart.js'
// import zoomPlugin from 'chartjs-plugin-zoom';
const zoomPlugin = dynamic(() => import('chartjs-plugin-zoom'), {
ssr: false,
})
Chart.register(zoomPlugin);
const PortfolioPriceLineDual = ({
title,
data,
unit,
axesOptions,
showLegend = true,
}) => {
const totalDuration = 5000
const delayBetweenPoints = totalDuration / data.datasets[0].data.length
// const animation =
const { locale } = useRouter()
let format
switch (locale) {
case 'de-DE':
format = de
break
case 'en-US':
format = enGB
break
case 'ja-JP':
format = ja
break
default:
break
}
return (
<Line
data={data}
options={{
responsive: true,
// maintainAspectRatio: true,
// aspectRatio: 16 / 9,
resizeDelay: 5,
animation: {
x: {
type: 'number',
easing: 'linear',
duration: delayBetweenPoints,
from: NaN, // the point is initially skipped
delay: (ctx) => {
if (ctx.type !== 'data' || ctx.xStarted) {
return 0
}
ctx.xStarted = true
return ctx.index * delayBetweenPoints
},
},
y: {
type: 'number',
easing: 'linear',
duration: delayBetweenPoints,
from: (ctx) => {
return ctx.index === 0
? ctx.chart.scales.y.getPixelForValue(100)
: ctx.chart
.getDatasetMeta(ctx.datasetIndex)
.data[ctx.index - 1].getProps(['y'], true).y
},
delay: (ctx) => {
if (ctx.type !== 'data' || ctx.yStarted) {
return 0
}
ctx.yStarted = true
return ctx.index * delayBetweenPoints
},
},
y1: {
type: 'number',
easing: 'linear',
duration: delayBetweenPoints,
from: (ctx) => {
return ctx.index === 0
? ctx.chart.scales.y.getPixelForValue(100)
: ctx.chart
.getDatasetMeta(ctx.datasetIndex)
.data[ctx.index - 1].getProps(['y'], true).y
},
delay: (ctx) => {
if (ctx.type !== 'data' || ctx.yStarted) {
return 0
}
ctx.yStarted = true
return ctx.index * delayBetweenPoints
},
},
},
interaction: {
mode: 'index',
intersect: false,
},
scales: {
x: {
type: 'time',
time: {
unit: 'year',
displayFormats: {
quarter: 'yyyy',
},
tooltipFormat: 'MMMM yyyy',
},
adapters: {
date: {
locale: format,
},
},
ticks: {
align: 'start',
color: '#122a42',
font: {
size: 14,
weight: 'bold',
},
},
grid: {
display: true,
drawBorder: false,
drawOnChartArea: true,
drawTicks: true,
},
},
y: {
type: 'logarithmic',
grid: {
display: true,
drawBorder: false,
drawOnChartArea: true,
drawTicks: true,
},
ticks: {
color: '#122a42',
align: 'end',
font: {
size: 10,
weight: 'normal',
},
// Include a dollar sign in the ticks
// stepSize: 1000,
callback: function (value) {
// callback: function (value, index, ticks) {
return `${new Intl.NumberFormat(locale, axesOptions).format(
value
)}`
},
},
},
y1: {
type: 'linear',
display: true,
position: 'right',
// grid line settings
grid: {
drawOnChartArea: false, // only want the grid lines for one axis to show up
},
ticks: {
color: '#122a42',
align: 'end',
font: {
size: 10,
weight: 'normal',
},
// Include a dollar sign in the ticks
// stepSize: 1000,
callback: function (value) {
// callback: function (value, index, ticks) {
return `${new Intl.NumberFormat(locale, axesOptions).format(
value
)}`
},
},
},
},
zoom: {
enabled: true,
mode: 'x',
},
pan: {
enabled: true,
mode: 'x',
},
plugins: {
zoom: {
enabled: true,
mode: 'x',
},
pan: {
enabled: true,
mode: 'x',
},
// zoom: {
// zoom: {
// wheel: {
// enabled: true,
// },
// pinch: {
// enabled: true,
// },
// mode: 'x',
// },
// },
title: {
display: true,
color: '#151C30',
font: {
size: 26,
weight: 'bold',
style: 'normal',
},
padding: {
bottom: 10,
},
text: `${title}`,
},
tooltip: {
enabled: true,
backgroundColor: '#122a42',
itemSort: function (a, b) {
return b.raw - a.raw
},
callbacks: {
label: function (context) {
let label = context.dataset.label || ''
if (label) {
label += ': '
}
if (context.parsed.y !== null) {
label += `${new Intl.NumberFormat(locale, axesOptions).format(
context.parsed.y
)} ${unit}`
}
return label
},
},
},
legend: {
position: 'bottom',
labels: {
// This more specific font property overrides the global property
color: '#151C30',
font: {
size: 12,
weight: 'light',
},
},
},
},
}}
/>
)
}
export default PortfolioPriceLineDual