Skip to content

Instantly share code, notes, and snippets.

@nwkm
Created June 28, 2019 09:48
Show Gist options
  • Select an option

  • Save nwkm/ed32a34ea66d156b3af9dbaa92070a53 to your computer and use it in GitHub Desktop.

Select an option

Save nwkm/ed32a34ea66d156b3af9dbaa92070a53 to your computer and use it in GitHub Desktop.

Revisions

  1. nwkm created this gist Jun 28, 2019.
    137 changes: 137 additions & 0 deletions chart.helpers.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,137 @@
    //draws a rectangle with a rounded top

    Chart.helpers.drawRoundedTopRectangle = function(
    ctx: any,
    x: number,
    y: number,
    width: number,
    height: number,
    radius: number,
    ) {
    ctx.beginPath();
    ctx.moveTo(x + radius, y);
    // top right corner
    ctx.lineTo(x + width - radius, y);
    ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
    // bottom right corner
    ctx.lineTo(x + width, y + height);
    // bottom left corner
    ctx.lineTo(x, y + height);
    // top left
    ctx.lineTo(x, y + radius);
    ctx.quadraticCurveTo(x, y, x + radius, y);
    ctx.closePath();
    };

    (Chart as any).elements.RoundedTopRectangle = (Chart as any).elements.Rectangle.extend(
    {
    draw() {
    const ctx = this._chart.ctx;
    const vm = this._view;
    let left;
    let right;
    let top;
    let bottom;
    let signX;
    let signY;
    let borderSkipped;
    let borderWidth = vm.borderWidth;

    if (!vm.horizontal) {
    // bar
    left = vm.x - vm.width / 2;
    right = vm.x + vm.width / 2;
    top = vm.y;
    // If the y-axis stack is true, we should increase bottom value by xxx
    // vm.base + xxx ===> Help to lower the stacked bar to make they look nice
    bottom = vm.base;
    signX = 1;
    signY = bottom > top ? 1 : -1;
    borderSkipped = vm.borderSkipped || 'bottom';
    } else {
    // horizontal bar
    left = vm.base;
    right = vm.x;
    top = vm.y - vm.height / 2;
    bottom = vm.y + vm.height / 2;
    signX = right > left ? 1 : -1;
    signY = 1;
    borderSkipped = vm.borderSkipped || 'left';
    }

    // Canvas doesn't allow us to stroke inside the width so we can
    // adjust the sizes to fit if we're setting a stroke on the line
    if (borderWidth) {
    // borderWidth shold be less than bar width and bar height.
    const barSize = Math.min(
    Math.abs(left - right),
    Math.abs(top - bottom),
    );
    borderWidth = borderWidth > barSize ? barSize : borderWidth;
    const halfStroke = borderWidth / 2;
    // Adjust borderWidth when bar top position is near vm.base(zero).
    const borderLeft =
    left + (borderSkipped !== 'left' ? halfStroke * signX : 0);
    const borderRight =
    right +
    (borderSkipped !== 'right' ? -halfStroke * signX : 0);
    const borderTop =
    top + (borderSkipped !== 'top' ? halfStroke * signY : 0);
    const borderBottom =
    bottom +
    (borderSkipped !== 'bottom' ? -halfStroke * signY : 0);
    // not become a vertical line?
    if (borderLeft !== borderRight) {
    top = borderTop;
    bottom = borderBottom;
    }
    // not become a horizontal line?
    if (borderTop !== borderBottom) {
    left = borderLeft;
    right = borderRight;
    }
    }

    // calculate the bar width and roundess
    const barWidth = Math.abs(left - right);
    const roundness = this._chart.config.options.barRoundness || 0.5;
    const radius = barWidth * roundness * 0.5;

    // keep track of the original top of the bar
    const prevTop = top;

    // move the top down so there is room to draw the rounded top
    top = prevTop + radius;
    const barRadius = top - prevTop;

    ctx.beginPath();
    ctx.fillStyle = vm.backgroundColor;
    ctx.strokeStyle = vm.borderColor;
    ctx.lineWidth = borderWidth;

    // draw the rounded top rectangle
    Chart.helpers.drawRoundedTopRectangle(
    ctx,
    left,
    top - barRadius + 1,
    barWidth,
    bottom - prevTop,
    barRadius,
    );

    ctx.fill();
    if (borderWidth) {
    ctx.stroke();
    }

    // restore the original top value so tooltips and scales still work
    top = prevTop;
    },
    },
    );

    Chart.defaults.roundedBar = Chart.helpers.clone(Chart.defaults.bar);

    Chart.controllers.roundedBar = Chart.controllers.bar.extend({
    dataElementType: (Chart as any).elements.RoundedTopRectangle,
    });