Philipp Erber
Philipp Erber

Reputation: 65

Style individual points from one dataset in Chart.js

I am trying to create a timeline using Chart.js. My Goal is to have a single row that shows various icons/events that happened in a game. By using a linechart and removing the lines, leaving only the points, you can place markers on the timeline.

You can display these points as custom images by assigning an image variable to the pointStyle attribute of the dataset.

With a single image this works perfectly fine, as you can see in the following snippet.

//Create the image    
const img = new Image(20,20); 
img.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Skull_Icon_%28Noun_Project%29.svg/1200px-Skull_Icon_%28Noun_Project%29.svg.png";

var ctx = document.getElementById('chart').getContext('2d');
var myChart = new Chart(ctx, {
    type: 'line',
    data: {
        datasets: [
            {
            label: "Deaths",
            data: [{x:"00:01:23", y: 0},{x:"00:03:41", y: 0},{x:"00:04:29", y: 0},{x:"00:05:35", y: 0},{x:"00:06:27", y: 0},{x:"00:07:07", y: 0},{x:"00:08:48", y: 0},{x:"00:09:31", y: 0}],
            //Assign the image in the point Style attribute
            pointStyle:img,
            showLine: false,
            fill: false,
            tooltip: "Player Died",
            borderColor: "#000000",
            backgroundColor: "#000000"
        },
                ]},
     //The Rest is just styling
    options: {
        interaction:{
            mode:'nearest'
        },
        tooltips:{
            custom: function(tooltip){
                if(!tooltip)return;
                tooltip.displayColors = false;
            },
            callbacks:{
                title: function(tooltipItem, data) {
                    return data.datasets[tooltipItem[0].datasetIndex]['tooltip'];
                },
                label: function(tooltipItem, data) {
                    return tooltipItem.xLabel;
                }
            }
        },
        legend: {
            display: true
        },
        scales: {
            xAxes: [{
                type: 'time',
                time: {
                    parser: 'hh:mm:ss',
                    tooltipFormat: 'HH:mm:ss',
                    displayFormats: {
                        second: "HH:mm:ss"
                    },
                unitStepSize: 30
                },
                ticks:{
                    fontColor: "white"
                }
            }],
            yAxes: [{
                ticks: {
                    display: false,
                },        
                gridLines: {
                    display: false
                }
            }]
        }
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.bundle.min.js"></script>
<canvas id="chart" height= "50px" style="background-color: rgb(200, 200, 200);"></canvas>

As you can see i am creating an Image(), pointing it to the source and assigning it as the pointStyle attribute of the dataset. But with this method i need to create a new Dataset whenever i want to display another image.

For my purpose i need to be able to dynamically assign different images for every point.

That is why i looked into scriptables in Chart.js. On the documentation it is stated that you can use custom functions to return an image/styling for pointStyles.

https://www.chartjs.org/docs/latest/general/options.html

In the following snippet you can see my current code. I moved the creation of the image to a custom function in the point Style attribute of the dataset. With this i will be able to select from more images later.

But for now i can not make it work with one image. So how can i make the function return an image, so that the styling works? With this i will later be able to select from multiple images. Or is there maybe another solution i did not come up with?

Thank you very much for your help.

var ctx = document.getElementById('chart').getContext('2d');
var myChart = new Chart(ctx, {
    type: 'line',
    data: {
        datasets: [
            {
            label: "Deaths",
            data: [{x:"00:01:23", y: 0},{x:"00:03:41", y: 0},{x:"00:04:29", y: 0},{x:"00:05:35", y: 0},{x:"00:06:27", y: 0},{x:"00:07:07", y: 0},{x:"00:08:48", y: 0},{x:"00:09:31", y: 0}],
            //Try to create the image in a custom function
            pointStyle: function(context){ 
                var img = new Image(20,20); 
                img.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Skull_Icon_%28Noun_Project%29.svg/1200px-Skull_Icon_%28Noun_Project%29.svg.png"; 
                return img; 
                },
            showLine: false,
            fill: false,
            tooltip: "Player Died",
            borderColor: "#000000",
            backgroundColor: "#000000"
        },
                ]},
    options: {
        interaction:{
            mode:'nearest'
        },
        tooltips:{
            custom: function(tooltip){
                if(!tooltip)return;
                tooltip.displayColors = false;
            },
            callbacks:{
                title: function(tooltipItem, data) {
                    return data.datasets[tooltipItem[0].datasetIndex]['tooltip'];
                },
                label: function(tooltipItem, data) {
                    return tooltipItem.xLabel;
                }
            }
        },
        legend: {
            display: true
        },
        scales: {
            xAxes: [{
                type: 'time',
                time: {
                    parser: 'hh:mm:ss',
                    tooltipFormat: 'HH:mm:ss',
                    displayFormats: {
                        second: "HH:mm:ss"
                    },
                unitStepSize: 30
                },
                ticks:{
                    fontColor: "white"
                }
            }],
            yAxes: [{
                ticks: {
                    display: false,
                },        
                gridLines: {
                    display: false
                }
            }]
        }
    }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.bundle.min.js"></script>
<canvas id="chart" height= "50px" style="background-color: rgb(200, 200, 200);"></canvas>

Upvotes: 2

Views: 2415

Answers (1)

Justin
Justin

Reputation: 2958

You can add different images via an array.

//Create the image    
const img = new Image(20, 20);
img.src = "https://upload.wikimedia.org/wikipedia/commons/thumb/1/1a/Skull_Icon_%28Noun_Project%29.svg/1200px-Skull_Icon_%28Noun_Project%29.svg.png";
const img2 = new Image(20, 20);
img2.src = "https://pngimg.com/uploads/pacman/pacman_PNG21.png";
const img3 = new Image(20, 20);
img3.src = "https://pngimg.com/uploads/pacman/pacman_PNG70.png"
var ctx = document.getElementById('chart').getContext('2d');


var myChart = new Chart(ctx, {
  type: 'line',
  data: {
    datasets: [{
      label: "Deaths",
      data: [{
        x: "00:01:23",
        y: 0
      }, {
        x: "00:03:41",
        y: 0
      }, {
        x: "00:04:29",
        y: 0
      }, {
        x: "00:05:35",
        y: 0
      }, {
        x: "00:06:27",
        y: 0
      }, {
        x: "00:07:07",
        y: 0
      }, {
        x: "00:08:48",
        y: 0
      }, {
        x: "00:09:31",
        y: 0
      }],
      //Assign the image in the point Style attribute
      pointStyle: [img2, img, img3],

      showLine: false,
      fill: false,
      tooltip: "Player Died",
      borderColor: "#000000",
      backgroundColor: "#000000"
    }, ]
  },
  //The Rest is just styling
  options: {
    interaction: {
      mode: 'nearest'
    },
    tooltips: {
      custom: function(tooltip) {
        if (!tooltip) return;
        tooltip.displayColors = false;
      },
      callbacks: {
        title: function(tooltipItem, data) {
          return data.datasets[tooltipItem[0].datasetIndex]['tooltip'];
        },
        label: function(tooltipItem, data) {
          return tooltipItem.xLabel;
        }
      }
    },
    legend: {
      display: true
    },
    scales: {
      xAxes: [{
        type: 'time',
        time: {
          parser: 'hh:mm:ss',
          tooltipFormat: 'HH:mm:ss',
          displayFormats: {
            second: "HH:mm:ss"
          },
          unitStepSize: 30
        },
        ticks: {
          fontColor: "white"
        }
      }],
      yAxes: [{
        ticks: {
          display: false,
        },
        gridLines: {
          display: false
        }
      }]
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.min.js"></script>
<canvas id="chart" height="50px" style="background-color: rgb(200, 200, 200);"></canvas>

How you get the images to the array is up to you.

You can update it with something like this

function addimage(img) {
  myChart.data.datasets[0].pointStyle.push(img);
  myChart.update();
};
addimage(img2)

Of course you will want to add your images in some other dynamic way I’m sure but this should help.

Upvotes: 4

Related Questions