# renderer/canvas/stroker/QuadraticCanvasStroker.js

    import * as StrokeComponent from '../../../model/StrokeComponent'
    import { computeLinksPoints, computeMiddlePoint, computeAxeAngle } from '../../QuadraticUtils'

    /**
     * Stroker info
     * @typedef {Object} StrokerInfo
     * @property {String} type Renderer type.
     * @property {String} name Stroker name.
     * @property {String} apiVersion Supported api version.
     */

    /**
     * Define how a stroke should be drawn
     * @typedef {Object} Stroker
     * @property {function} getInfo Get some information about this stroker
     * @property {function} drawStroke Render a stroke on the current context.
     */

    /**
     * Get info
     * @return {StrokerInfo} Information about this stroker
     */
    export function getInfo () {
      return {
        type: 'canvas',
        name: 'quadratic'
      }
    }

    function renderArc (context, center, radius) {
      context.arc(center.x, center.y, radius, 0, Math.PI * 2, true)
    }

    function renderLine (context, begin, end, width) {
      const linkPoints1 = computeLinksPoints(begin, computeAxeAngle(begin, end), width)
      const linkPoints2 = computeLinksPoints(end, computeAxeAngle(begin, end), width)

      context.moveTo(linkPoints1[0].x, linkPoints1[0].y)
      context.lineTo(linkPoints2[0].x, linkPoints2[0].y)
      context.lineTo(linkPoints2[1].x, linkPoints2[1].y)
      context.lineTo(linkPoints1[1].x, linkPoints1[1].y)
    }

    function renderFinal (context, begin, end, width) {
      const ARCSPLIT = 6
      const angle = computeAxeAngle(begin, end)
      const linkPoints = computeLinksPoints(end, angle, width)
      context.moveTo(linkPoints[0].x, linkPoints[0].y)
      for (let i = 1; i <= ARCSPLIT; i++) {
        const newAngle = angle - ((i * Math.PI) / ARCSPLIT)
        context.lineTo(end.x - ((end.p * width) * Math.sin(newAngle)), end.y + (end.p * width * Math.cos(newAngle)))
      }
    }

    function renderQuadratic (context, begin, end, ctrl, width) {
      const linkPoints1 = computeLinksPoints(begin, computeAxeAngle(begin, ctrl), width)
      const linkPoints2 = computeLinksPoints(end, computeAxeAngle(ctrl, end), width)
      const linkPoints3 = computeLinksPoints(ctrl, computeAxeAngle(begin, end), width)

      context.moveTo(linkPoints1[0].x, linkPoints1[0].y)
      context.quadraticCurveTo(linkPoints3[0].x, linkPoints3[0].y, linkPoints2[0].x, linkPoints2[0].y)
      context.lineTo(linkPoints2[1].x, linkPoints2[1].y)
      context.quadraticCurveTo(linkPoints3[1].x, linkPoints3[1].y, linkPoints1[1].x, linkPoints1[1].y)
    }

    /**
     * Draw a stroke on a canvas, using quadratics
     * @param {Object} context Current rendering context
     * @param {Stroke} stroke Current stroke to be drawn
     */
    export function drawStroke (context, stroke) {
      const contextReference = context
      const length = stroke.x.length
      const width = stroke.width > 0 ? stroke.width : contextReference.lineWidth
      const color = stroke.color ? stroke.color : contextReference.strokeStyle
      const firstPoint = StrokeComponent.getPointByIndex(stroke, 0)
      const nbquadratics = length - 2

      contextReference.save()
      try {
        contextReference.beginPath()
        if (length < 3) {
          renderArc(contextReference, firstPoint, width * 0.6)
        } else {
          renderArc(contextReference, firstPoint, width * firstPoint.p)
          renderLine(contextReference, firstPoint, computeMiddlePoint(firstPoint, StrokeComponent.getPointByIndex(stroke, 1)), width)

          // Possibility to try this (the start looks better when the ink is large)
          // var first = computeMiddlePoint(stroke[0], stroke[1]);
          // contextReference.arc(first.x, first.y, width * first.p, 0, Math.PI * 2, true);

          for (let i = 0; i < nbquadratics; i++) {
            renderQuadratic(contextReference, computeMiddlePoint(StrokeComponent.getPointByIndex(stroke, i), StrokeComponent.getPointByIndex(stroke, i + 1)), computeMiddlePoint(StrokeComponent.getPointByIndex(stroke, i + 1), StrokeComponent.getPointByIndex(stroke, i + 2)), StrokeComponent.getPointByIndex(stroke, i + 1), width)
          }
          renderLine(contextReference, computeMiddlePoint(StrokeComponent.getPointByIndex(stroke, length - 2), StrokeComponent.getPointByIndex(stroke, length - 1)), StrokeComponent.getPointByIndex(stroke, length - 1), width)
          renderFinal(contextReference, StrokeComponent.getPointByIndex(stroke, length - 2), StrokeComponent.getPointByIndex(stroke, length - 1), width)
        }
        contextReference.closePath()
        if (color !== undefined) {
          contextReference.fillStyle = color
          contextReference.fill()
        }
      } finally {
        contextReference.restore()
      }
    }