renderPaths({
    j,
    realIndex,
    pathFrom,
    pathTo,
    stroke,
    strokeWidth,
    strokeLinecap,
    fill,
    animationDelay,
    initialSpeed,
    dataChangeSpeed,
    className,
    chartType,
    shouldClipToGrid = true,
    bindEventsOnPaths = true,
    drawShadow = true,
  }) {
    let w = this.w
    const filters = new Filters(this.ctx)
    const anim = new Animations(this.ctx)

    let initialAnim = this.w.config.chart.animations.enabled
    let dynamicAnim =
      initialAnim && this.w.config.chart.animations.dynamicAnimation.enabled

    // Fix for paths starting with M 0 0
    if (pathFrom && pathFrom.startsWith('M 0 0') && pathTo) {
      const moveCommand = pathTo.match(/^M\s+[\d.-]+\s+[\d.-]+/)
      if (moveCommand) {
        pathFrom = pathFrom.replace(/^M\s+0\s+0/, moveCommand[0])
      }
    }

    let d
    let shouldAnimate = !!(
      (initialAnim && !w.globals.resized) ||
      (dynamicAnim && w.globals.dataChanged && w.globals.shouldAnimate)
    )

    if (shouldAnimate) {
      d = pathFrom
    } else {
      d = pathTo
      w.globals.animationEnded = true
    }

    let strokeDashArrayOpt = w.config.stroke.dashArray
    let strokeDashArray = 0
    if (Array.isArray(strokeDashArrayOpt)) {
      strokeDashArray = strokeDashArrayOpt[realIndex]
    } else {
      strokeDashArray = w.config.stroke.dashArray
    }

    let el = this.drawPath({
      d,
      stroke,
      strokeWidth,
      fill,
      fillOpacity: 1,
      classes: className,
      strokeLinecap,
      strokeDashArray,
    })

    el.attr('index', realIndex)

    if (shouldClipToGrid) {
      if (
        (chartType === 'bar' && !w.globals.isHorizontal) ||
        w.globals.comboCharts
      ) {
        el.attr({
          'clip-path': `url(#gridRectBarMask${w.globals.cuid})`,
        })
      } else {
        el.attr({
          'clip-path': `url(#gridRectMask${w.globals.cuid})`,
        })
      }
    }

    if (w.config.chart.dropShadow.enabled && drawShadow) {
      filters.dropShadow(el, w.config.chart.dropShadow, realIndex)
    }

    if (bindEventsOnPaths) {
      el.node.addEventListener('mouseenter', this.pathMouseEnter.bind(this, el))
      el.node.addEventListener('mouseleave', this.pathMouseLeave.bind(this, el))
      el.node.addEventListener('mousedown', this.pathMouseDown.bind(this, el))
    }

    el.attr({
      pathTo,
      pathFrom,
    })

    const defaultAnimateOpts = {
      el,
      j,
      realIndex,
      pathFrom,
      pathTo,
      fill,
      strokeWidth,
      delay: animationDelay,
    }

    if (initialAnim && !w.globals.resized && !w.globals.dataChanged) {
      anim.animatePathsGradually({
        ...defaultAnimateOpts,
        speed: initialSpeed,
      })
    } else {
      if (w.globals.resized || !w.globals.dataChanged) {
        anim.showDelayedElements()
      }
    }

    if (w.globals.dataChanged && dynamicAnim && shouldAnimate) {
      anim.animatePathsGradually({
        ...defaultAnimateOpts,
        speed: dataChangeSpeed,
      })
    }

    return el
  }
@memberof Graphics
@param {object}
 i = series's index
 realIndex = realIndex is series's actual index when it was drawn time. After several redraws, the iterating "i" may change in loops, but realIndex doesn't
 pathFrom = existing pathFrom to animateTo
 pathTo = new Path to which d attr will be animated from pathFrom to pathTo
 stroke = line Color
 strokeWidth = width of path Line
 fill = it can be gradient, single color, pattern or image
 animationDelay = how much to delay when starting animation (in milliseconds)
 dataChangeSpeed = for dynamic animations, when data changes
 className = class attribute to add
@return {object} svg.js path object