score:1
--- diclaimer: much of the code below is pasted from chart.js with very little changes. chart.js code is under mit license, please refer to that license if you plan to use it ---
found how to do it, although it's not probably the best and/or most reusable way.
for the legend, legend itself is a plugin in chart.js source code. for that reason, i simply overwritten the plugin logic as such:
const defaults = chart.defaults;
const element = chart.element;
const helpers = chart.helpers;
const layouts = chart.layouts;
const columnlegendplugin = {
id: 'column-legend',
beforeinit: function (chart) {
this.stash_draw = chart.legend.draw;
chart.legend.draw = function () {
const me = chart.legend;
const opts = me.options;
const labelopts = opts.labels;
const globaldefaults = defaults.global;
const defaultcolor = globaldefaults.defaultcolor;
const linedefault = globaldefaults.elements.line;
const legendheight = me.height;
const columnheights = me.columnheights;
const legendwidth = me.width;
const linewidths = me.linewidths;
if(opts.display) {
const ctx = me.ctx;
const fontcolor = helpers.valueordefault(labelopts.fontcolor, globaldefaults.defaultfontcolor);
const labelfont = helpers.options._parsefont(labelopts);
const fontsize = labelfont.size;
let cursor;
// canvas setup
ctx.textalign = 'left';
ctx.textbaseline = 'middle';
ctx.linewidth = 0.5;
ctx.strokestyle = fontcolor; // for strikethrough effect
ctx.fillstyle = fontcolor; // render in correct colour
ctx.font = labelfont.string;
const boxwidth = getboxwidth(labelopts, fontsize);
const hitboxes = me.legendhitboxes;
// current position
const drawlegendbox = function (x, y, legenditem) {
if(isnan(boxwidth) || boxwidth <= 0) {
return;
}
// set the ctx for the box
ctx.save();
const linewidth = helpers.valueordefault(legenditem.linewidth, linedefault.borderwidth);
ctx.fillstyle = helpers.valueordefault(legenditem.fillstyle, defaultcolor);
ctx.linecap = helpers.valueordefault(legenditem.linecap, linedefault.bordercapstyle);
ctx.linedashoffset = helpers.valueordefault(legenditem.linedashoffset, linedefault.borderdashoffset);
ctx.linejoin = helpers.valueordefault(legenditem.linejoin, linedefault.borderjoinstyle);
ctx.linewidth = linewidth;
ctx.strokestyle = helpers.valueordefault(legenditem.strokestyle, defaultcolor);
if(ctx.setlinedash) {
// ie 9 and 10 do not support line dash
ctx.setlinedash(helpers.valueordefault(legenditem.linedash, linedefault.borderdash));
}
if(labelopts && labelopts.usepointstyle) {
// recalculate x and y for drawpoint() because its expecting
// x and y to be center of figure (instead of top left)
const radius = boxwidth * math.sqrt2 / 2;
const centerx = x + boxwidth / 2;
const centery = y + fontsize / 2;
// draw pointstyle as legend symbol
helpers.canvas.drawpoint(ctx, legenditem.pointstyle, radius, centerx, centery, legenditem.rotation);
} else {
// draw box as legend symbol
ctx.fillrect(x, y, boxwidth, math.min(fontsize, labelopts.boxheight));
if(linewidth !== 0) {
ctx.strokerect(x, y, boxwidth, math.min(fontsize, labelopts.boxheight));
}
}
ctx.restore();
};
const filltext = function (x, y, legenditem, textwidth) {
const halffontsize = fontsize / 2;
const xleft = /* boxwidth + halffontsize + */ x;
//const ymiddle = y + halffontsize;
const ymiddle = y + labelopts.yshift;
if(legenditem.text && legenditem.text.length > labelopts.maxlabellength) {
legenditem.text = (legenditem.text as string).slice(0, labelopts.maxlabellength) + '.';
}
ctx.filltext(legenditem.text, xleft, ymiddle);
if(legenditem.hidden) {
// strikethrough the text if hidden
ctx.beginpath();
ctx.linewidth = 2;
ctx.moveto(xleft, ymiddle);
ctx.lineto(xleft + textwidth, ymiddle);
ctx.stroke();
}
};
const alignmentoffset = function (dimension, blocksize) {
switch(opts.align) {
case 'start':
return labelopts.padding;
case 'end':
return dimension - blocksize;
default: // center
return (dimension - blocksize + labelopts.padding) / 2;
}
};
// horizontal
const ishorizontal = me.ishorizontal();
if(ishorizontal) {
cursor = {
x: me.left + alignmentoffset(legendwidth, linewidths[0]),
y: me.top + labelopts.padding,
line: 0
};
} else {
cursor = {
x: me.left + labelopts.padding,
y: me.top + alignmentoffset(legendheight, columnheights[0]),
line: 0
};
}
const itemheight = fontsize + labelopts.padding;
helpers.each(me.legenditems, function (legenditem, i) {
const textwidth = math.min(ctx.measuretext(legenditem.text).width, 100);
const width = boxwidth + (fontsize / 2) + textwidth;
let x = cursor.x;
let y = cursor.y;
// use (me.left + me.minsize.width) and (me.top + me.minsize.height)
// instead of me.right and me.bottom because me.width and me.height
// may have been changed since me.minsize was calculated
if(ishorizontal) {
if(i > 0 && x + width + labelopts.padding > me.left + me.minsize.width) {
y = cursor.y += itemheight;
cursor.line++;
x = cursor.x = me.left + alignmentoffset(legendwidth, linewidths[cursor.line]);
}
} else if(i > 0 && y + itemheight > me.top + me.minsize.height) {
x = cursor.x = x + me.columnwidths[cursor.line] + labelopts.padding;
cursor.line++;
y = cursor.y = me.top + alignmentoffset(legendheight, columnheights[cursor.line]);
}
drawlegendbox(x, y, legenditem);
hitboxes[i].left = x;
hitboxes[i].top = y;
hitboxes[i].height = labelopts.yshift + labelopts.boxheight + labelopts.fontsize;
hitboxes[i].width = math.max(math.min(ctx.measuretext(legenditem.text).width, 100), boxwidth);
// fill the actual label
filltext(x, y, legenditem, textwidth);
if(ishorizontal) {
cursor.x += width + labelopts.padding;
} else {
cursor.y += itemheight;
}
});
}
};
}
};
this code works just fine, if you need to use the old legend simply implement a logic to reuse the stashed functions.
tooltips are quite harder to handle though, since they are a core functionality with little to no exported api. but you could overwrite the prototype, reusing the code from chart.js:
const defaults = chart.defaults;
const element = chart.element;
const helpers = chart.helpers;
const layouts = chart.layouts;
function getalignedx(vm, align) {
return align === 'center'
? vm.x + vm.width / 2
: align === 'right'
? vm.x + vm.width - vm.xpadding
: vm.x + vm.xpadding;
}
export const nicetooltipplugin = {
id: 'nice-tooltip-plugin',
beforeinit: function (chart) {
chart.tooltip.prototype.draw = function () {
const ctx = this._chart.ctx;
const vm = this._view;
if(vm.opacity === 0) {
return;
}
const tooltipsize = {
width: math.max(vm.width, ctx.measuretext(vm.body[0].lines[0].tooltiplabel).width + 50, ctx.measuretext(vm.body[0].lines[0].tooltipdata).width + 50),
height: 1.5 * vm.height
};
const pt = {
x: vm.x,
y: vm.y
};
const opacity = vm.opacity;
// truthy/falsey value for empty tooltip
const hastooltipcontent = vm.title.length || vm.beforebody.length || vm.body.length || vm.afterbody.length || vm.footer.length;
if(this._options.enabled && hastooltipcontent) {
ctx.save();
ctx.globalalpha = opacity;
// draw background
this.drawbackground(pt, vm, ctx, tooltipsize);
// draw title, body, and footer
pt.y += vm.ypadding;
// titles
this.drawtitle(pt, vm, ctx);
// body
this.drawbody(pt, vm, ctx);
// footer
this.drawfooter(pt, vm, ctx);
ctx.restore();
}
};
chart.tooltip.prototype.drawbody = function (pt, vm, ctx) {
const bodyfontsize = vm.bodyfontsize;
const bodyspacing = vm.bodyspacing;
const bodyalign = vm._bodyalign;
const body = vm.body;
const drawcolorboxes = vm.displaycolors;
const labelcolors = vm.labelcolors;
let xlinepadding = 0;
const colorx = drawcolorboxes ? getalignedx(vm, 'left') : 0;
let textcolor;
ctx.textalign = bodyalign;
ctx.textbaseline = 'top';
ctx.font = helpers.fontstring(bodyfontsize, vm._bodyfontstyle, vm._bodyfontfamily);
pt.x = getalignedx(vm, bodyalign);
// before body
const filllineoftext = function (line) {
ctx.filltext(line, pt.x + xlinepadding, pt.y);
pt.y += bodyfontsize + bodyspacing;
};
// before body lines
ctx.fillstyle = vm.bodyfontcolor;
helpers.each(vm.beforebody, filllineoftext);
xlinepadding = drawcolorboxes && bodyalign !== 'right'
? bodyalign === 'center' ? (bodyfontsize / 2 + 1) : (bodyfontsize + 2)
: 0;
// draw body lines now
helpers.each(body, function (bodyitem, i) {
textcolor = vm.labeltextcolors[i];
ctx.fillstyle = textcolor;
helpers.each(bodyitem.before, filllineoftext);
helpers.each(bodyitem.lines, function (line) {
// draw legend-like boxes if needed
if(drawcolorboxes) {
/* // fill a white rect so that colours merge nicely if the opacity is < 1
ctx.fillstyle = vm.legendcolorbackground;
ctx.fillrect(colorx, pt.y, bodyfontsize, bodyfontsize);
// border
ctx.linewidth = 1;
ctx.strokestyle = labelcolors[i].bordercolor;
ctx.strokerect(colorx, pt.y, bodyfontsize, bodyfontsize);
// inner square
ctx.fillstyle = labelcolors[i].backgroundcolor;
ctx.fillrect(colorx + 1, pt.y + 1, bodyfontsize - 2, bodyfontsize - 2);
ctx.fillstyle = textcolor; */
ctx.fillstyle = labelcolors[i].backgroundcolor;
helpers.canvas.drawpoint(ctx, undefined, 5, pt.x, pt.y + 12, 360);
ctx.fillstyle = textcolor;
}
ctx.font = helpers.fontstring(bodyfontsize, "bold", vm._bodyfontfamily);
filllineoftext(line.tooltiplabel);
ctx.font = helpers.fontstring(bodyfontsize, "normal", vm._bodyfontfamily);
ctx.fillstyle = "#b0b0b0";
filllineoftext(line.tooltipdata);
ctx.fillstyle = textcolor;
});
helpers.each(bodyitem.after, filllineoftext);
});
};
}
};
Source: stackoverflow.com
Related Query
- chart.js scatter chart - displaying label specific to point in tooltip
- show label in tooltip but not in x axis for chartjs line chart
- Chart.js bar chart : Grid color and hide label
- chart js - Apply different color for each x-axes label
- Chart.js line chart tooltip shows wrong label when line doesn't start at first label
- Chart.js Radar chart legend label font size doesn't work
- Change the background color of tooltip dynamically using chart color
- How can i give the full Legend a background color in chart js?
- Legend color not working with randomly generated background colors in chartjs pie chart
- angular-chart.js custom color based on chart label values
- Chartjs v3 tooltip label not showing tooltip label color on custom calbacks
- Chart js nested pie label colors in legend
- Chartjs: get the label title on the radar's chart tooltip
- Chart.js Label color positioning in tooltip/legend
- Chart JS tooltip label not showing correct value
- I am using chart js to draw a chart. I did everything right but i don't know why the x axis and y axis label is not comming in chart. code below
- Load Tooltip faster during onHover of Legend Doughnut chart
- How can i change the every legend label font color using chart.js version 2.8.0 (spacial line chart)?
- How get values on legend label withn Chart js on Angular
- How can I change the legend label without affecting my tooltip label?
- How to change label color of ng2 chart in angular
- Chart JS tooltip and label width is zeroed
- Tooltip backgroundColor depending on chart color ChartJS
- Change tooltip positioning in doughnut chart using Chart.js
- Chartjs pie chart tooltip mode label
- Chart.js label color
- Chart.js V2: Add prefix or suffix to tooltip label
- Chart Js Change Label orientation on x-Axis for Line Charts
- Chart area background color chartjs
- Chart.js - Increase spacing between legend and chart
More Query from same tag
- Chart Is Not Created
- Chart JS change pointBackgroundColor based on data value
- Remove white space in ChartJS when value is null
- Tooltip callbacks in line chart JS not working
- Problem for display a chart with Chart.js and Angular
- Chartjs 3.5.0 - Radar Chart - Converting the labels to images
- Chart js animating a line while changing x-axis labels
- I can't display the vue-chart.js on the page
- Change Legend Box Outline Chart.js 2
- Group bar chart in ReactChartJS2 click particular element
- Chart.js - line chart with two yAxis: "TypeError: yScale is undefined"
- How to create logarithmic scale in chart.js with normal numbers?
- Which type of chart is this in Chart.js?
- Setting width and height
- Property 'elements' does not exist on type 'typeof Chart'
- Error in implementing chart.js in AngularJS
- Chart.js on web-app
- chartJS - points overplotting, jittering, noise?
- ng2-charts and annotation plugin: annotations not visible after data update
- Chart.js - Plot line graph with X , Y coordinates and connected by line
- Transform JSON data for ChartJS
- Second dataset with single point makes y axis too big on Chart.js
- Why is my Line Chart not displaying (Chart.JS)?
- How to use two Y axes in Chart.js v2?
- Vuejs - Chartjs - turning a doughnut chart to a gauge - rotation
- How to create a charjs bar graph with many bars?
- How can i get my chartjs to show up graphically?
- Hide x-axis labels but show tooltips in chart.js
- Chart.js - Hide tooltip caret
- How to draw the circular progress bar in Chart.js Or any other JavaScript library in Angular 2