@@ -14,7 +14,7 @@ | |||||
], | ], | ||||
"linebreak-style": [ | "linebreak-style": [ | ||||
"error", | "error", | ||||
"unix" | |||||
"windows" | |||||
], | ], | ||||
"semi": [ | "semi": [ | ||||
"error", | "error", | ||||
@@ -60,4 +60,8 @@ typings/ | |||||
# next.js build output | # next.js build output | ||||
.next | .next | ||||
.DS_Store | |||||
.DS_Store | |||||
package-lock.json | |||||
dist/ | |||||
docs/assets/js/ |
@@ -298,6 +298,7 @@ export default class AxisChart extends BaseChart { | |||||
svgDefs: this.svgDefs, | svgDefs: this.svgDefs, | ||||
heatline: this.lineOptions.heatline, | heatline: this.lineOptions.heatline, | ||||
regionFill: this.lineOptions.regionFill, | regionFill: this.lineOptions.regionFill, | ||||
spline: this.lineOptions.spline, | |||||
hideDots: this.lineOptions.hideDots, | hideDots: this.lineOptions.hideDots, | ||||
hideLine: this.lineOptions.hideLine, | hideLine: this.lineOptions.hideLine, | ||||
@@ -368,7 +368,8 @@ let componentConfigs = { | |||||
c.color, | c.color, | ||||
{ | { | ||||
heatline: c.heatline, | heatline: c.heatline, | ||||
regionFill: c.regionFill | |||||
regionFill: c.regionFill, | |||||
spline: c.spline | |||||
}, | }, | ||||
{ | { | ||||
svgDefs: c.svgDefs, | svgDefs: c.svgDefs, | ||||
@@ -419,7 +420,7 @@ let componentConfigs = { | |||||
if(Object.keys(this.paths).length) { | if(Object.keys(this.paths).length) { | ||||
animateElements = animateElements.concat(animatePath( | animateElements = animateElements.concat(animatePath( | ||||
this.paths, newXPos, newYPos, newData.zeroLine)); | |||||
this.paths, newXPos, newYPos, newData.zeroLine, this.constants.spline)); | |||||
} | } | ||||
if(this.units.length) { | if(this.units.length) { | ||||
@@ -1,4 +1,4 @@ | |||||
import { getBarHeightAndYAttr } from './draw-utils'; | |||||
import { getBarHeightAndYAttr, createSplineCurve } from './draw-utils'; | |||||
export const UNIT_ANIM_DUR = 350; | export const UNIT_ANIM_DUR = 350; | ||||
export const PATH_ANIM_DUR = 350; | export const PATH_ANIM_DUR = 350; | ||||
@@ -74,13 +74,14 @@ export function animateDot(dot, x, y) { | |||||
// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein); | // dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein); | ||||
} | } | ||||
export function animatePath(paths, newXList, newYList, zeroLine) { | |||||
export function animatePath(paths, newXList, newYList, zeroLine, spline) { | |||||
let pathComponents = []; | let pathComponents = []; | ||||
let pointsStr = newYList.map((y, i) => (newXList[i] + ',' + y)).join("L"); | |||||
if (spline) | |||||
pointsStr = createSplineCurve(newXList, newYList); | |||||
let pointsStr = newYList.map((y, i) => (newXList[i] + ',' + y)); | |||||
let pathStr = pointsStr.join("L"); | |||||
const animPath = [paths.path, {d:"M"+pathStr}, PATH_ANIM_DUR, STD_EASING]; | |||||
const animPath = [paths.path, {d:"M" + pointsStr}, PATH_ANIM_DUR, STD_EASING]; | |||||
pathComponents.push(animPath); | pathComponents.push(animPath); | ||||
if(paths.region) { | if(paths.region) { | ||||
@@ -89,7 +90,7 @@ export function animatePath(paths, newXList, newYList, zeroLine) { | |||||
const animRegion = [ | const animRegion = [ | ||||
paths.region, | paths.region, | ||||
{d:"M" + regStartPt + pathStr + regEndPt}, | |||||
{d:"M" + regStartPt + pointsStr + regEndPt}, | |||||
PATH_ANIM_DUR, | PATH_ANIM_DUR, | ||||
STD_EASING | STD_EASING | ||||
]; | ]; | ||||
@@ -101,4 +102,4 @@ export function animatePath(paths, newXList, newYList, zeroLine) { | |||||
export function animatePathStr(oldPath, pathStr) { | export function animatePathStr(oldPath, pathStr) { | ||||
return [oldPath, {d: pathStr}, UNIT_ANIM_DUR, STD_EASING]; | return [oldPath, {d: pathStr}, UNIT_ANIM_DUR, STD_EASING]; | ||||
} | |||||
} |
@@ -52,4 +52,48 @@ export function shortenLargeNumber(label) { | |||||
// Correct for floating point error upto 2 decimal places | // Correct for floating point error upto 2 decimal places | ||||
return Math.round(shortened*100)/100 + ' ' + ['', 'K', 'M', 'B', 'T'][l]; | return Math.round(shortened*100)/100 + ' ' + ['', 'K', 'M', 'B', 'T'][l]; | ||||
} | |||||
// cubic bezier curve calculation (from example by François Romain) | |||||
export function createSplineCurve(xList, yList) { | |||||
let points=[]; | |||||
for(let i=0;i<xList.length;i++){ | |||||
points.push([xList[i], yList[i]]); | |||||
} | |||||
let smoothing = 0.2; | |||||
let line = (pointA, pointB) => { | |||||
let lengthX = pointB[0] - pointA[0]; | |||||
let lengthY = pointB[1] - pointA[1]; | |||||
return { | |||||
length: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)), | |||||
angle: Math.atan2(lengthY, lengthX) | |||||
}; | |||||
}; | |||||
let controlPoint = (current, previous, next, reverse) => { | |||||
let p = previous || current; | |||||
let n = next || current; | |||||
let o = line(p, n); | |||||
let angle = o.angle + (reverse ? Math.PI : 0); | |||||
let length = o.length * smoothing; | |||||
let x = current[0] + Math.cos(angle) * length; | |||||
let y = current[1] + Math.sin(angle) * length; | |||||
return [x, y]; | |||||
}; | |||||
let bezierCommand = (point, i, a) => { | |||||
let cps = controlPoint(a[i - 1], a[i - 2], point); | |||||
let cpe = controlPoint(point, a[i - 1], a[i + 1], true); | |||||
return `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`; | |||||
}; | |||||
let pointStr = (points, command) => { | |||||
return points.reduce((acc, point, i, a) => i === 0 | |||||
? `${point[0]},${point[1]}` | |||||
: `${acc} ${command(point, i, a)}`, ''); | |||||
}; | |||||
return pointStr(points, bezierCommand); | |||||
} | } |
@@ -1,4 +1,4 @@ | |||||
import { getBarHeightAndYAttr, truncateString, shortenLargeNumber } from './draw-utils'; | |||||
import { getBarHeightAndYAttr, truncateString, shortenLargeNumber, createSplineCurve } from './draw-utils'; | |||||
import { getStringWidth } from './helpers'; | import { getStringWidth } from './helpers'; | ||||
import { DOT_OVERLAY_SIZE_INCR, PERCENTAGE_BAR_DEFAULT_DEPTH } from './constants'; | import { DOT_OVERLAY_SIZE_INCR, PERCENTAGE_BAR_DEFAULT_DEPTH } from './constants'; | ||||
import { lightenDarkenColor } from './colors'; | import { lightenDarkenColor } from './colors'; | ||||
@@ -577,6 +577,11 @@ export function datasetDot(x, y, radius, color, label='', index=0) { | |||||
export function getPaths(xList, yList, color, options={}, meta={}) { | export function getPaths(xList, yList, color, options={}, meta={}) { | ||||
let pointsList = yList.map((y, i) => (xList[i] + ',' + y)); | let pointsList = yList.map((y, i) => (xList[i] + ',' + y)); | ||||
let pointsStr = pointsList.join("L"); | let pointsStr = pointsList.join("L"); | ||||
// Spline | |||||
if (options.spline) | |||||
pointsStr = createSplineCurve(xList, yList); | |||||
let path = makePath("M"+pointsStr, 'line-graph-path', color); | let path = makePath("M"+pointsStr, 'line-graph-path', color); | ||||
// HeatLine | // HeatLine | ||||