By using this site, you agree to the Privacy Policy and Terms of Use.
Accept
rocoderesrocoderes
  • Home
  • HTML & CSS
    • Login and Registration Form
    • Card Design
    • Loader
  • JavaScript
  • Python
  • Internet
  • Landing Pages
  • Tools
    • Google Drive Direct Download Link Generator
    • Word Count
  • Games
    • House Painter
Notification Show More
Latest News
How to set the dropdown value by clicking on a table row
Javascript – How to set the dropdown value by clicking on a table row
JavaScript
Attempting to increase the counter, when the object's tag exist
Javascript – Attempting to increase the counter, when the object’s tag exist
JavaScript
Cycle2 JS center active slide
Javascript – Cycle2 JS center active slide
JavaScript
Can import all THREE.js post processing modules as ES6 modules except OutputPass
Javascript – Can import all THREE.js post processing modules as ES6 modules except OutputPass
JavaScript
How to return closest match for an array in Google Sheets Appscript
Javascript – How to return closest match for an array in Google Sheets Appscript
JavaScript
Aa
Aa
rocoderesrocoderes
Search
  • Home
  • HTML & CSS
    • Login and Registration Form
    • Card Design
    • Loader
  • JavaScript
  • Python
  • Internet
  • Landing Pages
  • Tools
    • Google Drive Direct Download Link Generator
    • Word Count
  • Games
    • House Painter
Follow US
High Quality Design Resources for Free.
rocoderes > JavaScript > Javascript – Chart.Js. point style as a linear gradient
JavaScript

Javascript – Chart.Js. point style as a linear gradient

Admin
Last updated: 2024/01/07 at 7:12 AM
Admin
Share
11 Min Read
Chart.Js. point style as a linear gradient

Problem:

I am trying to make the points different colors: by default it should be background: linear-gradient(243.46deg, #FFC700 -1%, #F52525 131.66%);
If the next value is smaller than the previous, it should show be background: linear-gradient(55.98deg, #E83C3C 11.73%, #9D3C3C 72.51%);

Contents
Problem:Solution:

I’ve found some tutorials about linear-gradient on canvas but still all my points are black

var trendPriceArray = [
  0,
  109119,
  103610,
  112561,
  0,
  0,
  0,
  101852,
  0,
  99736,
  134382,
  110018
];

var trendPercentArray = [-5,
  8.6, -9.5, -2.1,
  34.7, -18.1
];

var monthLabels = [
  'January',
  'February',
  'March',
  'April',
  'May',
  'June',
  'July',
  'August',
  'September',
  'October',
  'November',
  'December'
];

// Filter out data points with trendPriceArray values of 0
var filteredData = [];
for (var i = 0; i < trendPriceArray.length; i++) {
  if (trendPriceArray[i] !== 0) {
    filteredData.push({
      x: monthLabels[i], // X coordinate as month label
      y: trendPriceArray[i], // Y coordinate
      label: trendPercentArray[i] + '%', // Display label above the point
    });
  }
}

// Initialize Chart.js
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
  type: 'line',
  data: {
    labels: monthLabels, // Use the month labels
    datasets: [{
      label: 'Price Trend',
      data: filteredData, // Use filtered data
      fill: false,
      borderColor: '#4e4e4e', // Set the line graph color to #4e4e4e
      backgroundColor: 'rgba(75, 192, 192, 0.2)',
      borderWidth: 1,
      pointBackgroundColor: [], // Empty array to be filled with point background colors
      pointRadius: 13, // Set the point radius to 13 pixels
      pointHoverRadius: 13, // Set the point hover radius to 13 pixels
    }]
  },
  options: {
    scales: {
      x: {
        type: 'category', // Use category scale with the month labels
        title: {
          display: true,
          text: 'Month',
          font: {
            family: 'Montserrat', // Set the font family to Montserrat
          },
          color: '#4e4e4e', // Set the axis label text color to #4e4e4e
        },
        ticks: {
          font: {
            family: 'Montserrat', // Set the font family to Montserrat
          },
          color: '#4e4e4e', // Set the tick text color to #4e4e4e
        },
      },
      y: {
        display: true,
        title: {
          display: true,
          text: 'Price',
          marginBottom: '10px',
          font: {
            family: 'Montserrat', // Set the font family to Montserrat
          },
          color: '#4e4e4e', // Set the axis label text color to #4e4e4e
        },
        ticks: {
          font: {
            family: 'Montserrat', // Set the font family to Montserrat
          },
          color: '#4e4e4e', // Set the tick text color to #4e4e4e
        },
      }
    },
    plugins: {
      tooltip: {
        enabled: true,
        mode: 'index',
        intersect: false,
      },
      legend: {
        labels: {
          font: {
            family: 'Montserrat', // Set the font family to Montserrat
          },
          color: '#4e4e4e', // Set the legend text color to #4e4e4e
        },
      },
    }
  }
});

function createDefaultGradient(ctx) {
  const gradient = ctx.createLinearGradient(0, 0, 0, 400);
  gradient.addColorStop(0, 'rgba(75, 192, 192, 0.2)');
  gradient.addColorStop(1, 'rgba(255, 255, 255, 0.2)');
  return gradient;
}

function createRedGradient(ctx) {
  const gradient = ctx.createLinearGradient(0, 0, 0, 400);
  gradient.addColorStop(0, 'rgba(255, 0, 0, 0.2)');
  gradient.addColorStop(1, 'rgba(255, 255, 255, 0.2)');
  return gradient;
}

function createGradientPointStyle(gradient) {
  return function(context) {
    const chart = context.chart;
    const {
      ctx,
      borderWidth
    } = chart;
    const {
      x,
      y
    } = context.p0;
    const pointRadius = 6; // You can adjust this value as needed

    ctx.save();
    ctx.beginPath();
    ctx.arc(x, y, pointRadius, 0, Math.PI * 2);
    ctx.fillStyle = gradient;
    ctx.closePath();
    ctx.fill();
    ctx.restore();
  };
}


// Initialize an empty pointStyle array
myChart.data.datasets[0].pointStyle = [];


for (var i = 0; i < filteredData.length; i++) {
  var gradient = createDefaultGradient(ctx); // Default gradient
  if (i < filteredData.length - 1 && filteredData[i + 1].y < filteredData[i].y) {
    gradient = createRedGradient(ctx); // Red gradient for smaller values
  }
  myChart.data.datasets[0].pointStyle.push(createGradientPointStyle(gradient));
}

myChart.update(); // Update the chart
<!DOCTYPE html>
<html>

<head>
  <!-- Include Chart.js library -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"></script>
  <!-- Include Montserrat font from Google Fonts -->
  <link href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap" rel="stylesheet">
</head>

<body>
  <!-- Create a container for the chart -->
  <div>
    <canvas id="myChart" width="400" height="200"></canvas>
  </div>
</body>

</html>

Solution:

There are theoretically two different avenues to
draw custom styled data points, and you combined them the wrong way:

  1. drawing yourself the point on the main canvas; this
    can only be done through a plugin, in its afterDraw function; otherwise, anything you draw is
    covered by the default drawing of the chart
  2. using pointStyle, to which you may assign
    a newly created (small) canvas or image on which you
    draw the (reusable) point symbol.

Since the second, standard method is good enough for
your requirements, we can forget about the first, which should only
be employed in exceptional cases, not covered by the other one.

Also, you should consider the moments/order
when each part of your code gets executed. In
particular, since you are using a
scriptable
pointStyle (i.e., a function that is called when the point style is needed and returns the canvas), you don’t need to set the pointStyle in a second stage, after the chart was first rendered,
and neither the chart.update call.

The very point of scriptable options is to enable you to use
just-computed dynamic values (like your filtered
y values) to avoid redrawing the whole chart.
The fact is that the point values are available before the points
are drawn, so through the arguments provided to the pointStyle
function you’ll find the required y values.

Here’s a corrected version of your code, with minimal change:

function createDefaultGradient(ctx, max) {
    const gradient = ctx.createLinearGradient(0, 0, 0, max);
    gradient.addColorStop(0, 'rgba(75, 192, 192, 0.2)');
    gradient.addColorStop(1, 'rgba(255, 255, 255, 0.2)');
    return gradient;
}

function createRedGradient(ctx, max) {
    const gradient = ctx.createLinearGradient(0, 0, 0, max);
    gradient.addColorStop(0, 'rgba(255, 0, 0, 0.2)');
    gradient.addColorStop(1, 'rgba(255, 255, 255, 0.2)');
    return gradient;
}

function createGradientPointStyle(gradientCreator, pointRadius) {
    const canvas = document.createElement('canvas');
    canvas.width = 2*pointRadius+2;
    canvas.height = 2*pointRadius+2;
    const ctx = canvas.getContext("2d");
    ctx.beginPath();
    ctx.arc(pointRadius+1, pointRadius+1, pointRadius, 0, Math.PI * 2);
    ctx.fillStyle = gradientCreator(ctx, 2*pointRadius+2);
    ctx.closePath();
    ctx.fill();
    return canvas;
}

function pointStyle(context, opt){
    var i = context.dataIndex,
        data = context.dataset.data;
    var gradientCreator = createDefaultGradient;
    if (i < data.length - 1 && data[i + 1].y < data[i].y) {
        gradientCreator = createRedGradient; // Red gradient for smaller values
    }
    var radius = context.active ? opt.hoverRadius : opt.radius;
    return createGradientPointStyle(gradientCreator, radius)
}

var trendPriceArray = [
    0,
    109119,
    103610,
    112561,
    0,
    0,
    0,
    101852,
    0,
    99736,
    134382,
    110018
];

var trendPercentArray = [-5,
    8.6, -9.5, -2.1,
    34.7, -18.1
];

var monthLabels = [
    'January',
    'February',
    'March',
    'April',
    'May',
    'June',
    'July',
    'August',
    'September',
    'October',
    'November',
    'December'
];

// Filter out data points with trendPriceArray values of 0
var filteredData = [];
for (var i = 0; i < trendPriceArray.length; i++) {
    if (trendPriceArray[i] !== 0) {
        filteredData.push({
            x: monthLabels[i], // X coordinate as month label
            y: trendPriceArray[i], // Y coordinate
            label: trendPercentArray[i] + '%', // Display label above the point
        });
    }
}

// Initialize Chart.js
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: monthLabels, // Use the month labels
        datasets: [{
            label: 'Price Trend',
            data: filteredData, // Use filtered data
            // fill: false,
            borderColor: '#4e4e4e', // Set the line graph color to #4e4e4e
            //backgroundColor: 'rgba(75, 192, 192, 0.2)',
            borderWidth: 1,
            // pointBackgroundColor: [], // Empty array to be filled with point background colors
            pointRadius: 13, // Set the point radius to 13 pixels
            pointHoverRadius: 23, // Set the point hover radius to 13 pixels
            pointStyle
        }]
    },
    options: {
        scales: {
            x: {
                type: 'category', // Use category scale with the month labels
                title: {
                    display: true,
                    text: 'Month',
                    font: {
                        family: 'Montserrat', // Set the font family to Montserrat
                    },
                    color: '#4e4e4e', // Set the axis label text color to #4e4e4e
                },
                ticks: {
                    font: {
                        family: 'Montserrat', // Set the font family to Montserrat
                    },
                    color: '#4e4e4e', // Set the tick text color to #4e4e4e
                },
            },
            y: {
                display: true,
                title: {
                    display: true,
                    text: 'Price',
                    marginBottom: '10px',
                    font: {
                        family: 'Montserrat', // Set the font family to Montserrat
                    },
                    color: '#4e4e4e', // Set the axis label text color to #4e4e4e
                },
                ticks: {
                    font: {
                        family: 'Montserrat', // Set the font family to Montserrat
                    },
                    color: '#4e4e4e', // Set the tick text color to #4e4e4e
                },
            }
        },
        plugins: {
            tooltip: {
                enabled: true,
                mode: 'index',
                intersect: false,
            },
            legend: {
                labels: {
                    font: {
                        family: 'Montserrat', // Set the font family to Montserrat
                    },
                    color: '#4e4e4e', // Set the legend text color to #4e4e4e
                },
            },
        }
    }
});
<div style="min-height: 60vh">
    <canvas id="myChart"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"></script>

Expand snippet

Related

Subscribe to Our Newsletter

Subscribe to our newsletter to get our newest articles instantly!

Share this Article
Facebook Twitter Email Print
What do you think?
Love0
Sad0
Happy0
Sleepy0
Angry0
Dead0
Wink0
Previous Article How can I overwrite a JS function added to core.action_registry in Odoo 15? Javascript – How can I overwrite a JS function added to core.action_registry in Odoo 15?
Next Article Need help optimizing a loop of merging objects and arrays Javascript – Need help optimizing a loop of merging objects and arrays
Leave a comment Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

- Advertisement -

You Might Also Like

How to set the dropdown value by clicking on a table row

Javascript – How to set the dropdown value by clicking on a table row

February 11, 2024
Attempting to increase the counter, when the object's tag exist

Javascript – Attempting to increase the counter, when the object’s tag exist

February 11, 2024
Cycle2 JS center active slide

Javascript – Cycle2 JS center active slide

February 10, 2024
Can import all THREE.js post processing modules as ES6 modules except OutputPass

Javascript – Can import all THREE.js post processing modules as ES6 modules except OutputPass

February 10, 2024
rocoderesrocoderes
Follow US

Copyright © 2022 All Right Reserved By Rocoderes

  • Home
  • About us
  • Contact us
  • Disclaimer
Join Us!

Subscribe to our newsletter and never miss our latest news, podcasts etc.

Zero spam, Unsubscribe at any time.
Welcome Back!

Sign in to your account

Lost your password?