gist-charts
v1.1.1
Published
6harts written in canvas
Downloads
23
Keywords
Readme
Gist Charts
Overview
The Gist chart is a canvas charting library built around the idea that charts should be modular, fast, reusable, interactive, and defined by their data.
new ChartCanvas( htmlContainer to be filled with chart )
calling new ChartCanvas() defines a new chart container for you. The constructor takes an html element that will be filled with your chart. Your chart will be set to the same width and height of your provided element.
addChart( configs: BaseChartConfig | BaseChartConfig[] ): void
- Adds the given charts to this canvas. By Default, charts will be drawn in the order they are added. This can be changed by setting the zIndex value on charts though.
removeChart( configs: BaseChartConfig | BaseChartConfig[] ): void
- Removes one or many charts from this canvas.
addAxis( configs: BaseChartConfig | BaseChartConfig[] ): void
- Adds the given axis to this canvas. The axis itself will still need to register its charts, however this lets the axis know how much room it has when providing the range for the charts to draw with. By Default axis that are added will be drawn, but this can be prevented by setting the shouldRenderValues to false on the axis
removeAxis( configs: BaseChartConfig | BaseChartConfig[] ): void
- Removes the given axis from this chart. If the beginRender has been called on the chartcanvas, than it will need to be called again for this to have affect.
beginRender(): void
- All charts for this canvas will begin watching there datalist, and rendering all data given. Data can be added before or after beginRender as rendering is an asynchronous process. When all charts have drawn all of their given data, they will all be copied over to this canvas. Until then, they are each displayed over this canvas, so the user will be able to see their progress. All charts have a onRenderStateChange that can be overridden to know when they start or stop drawing.
stopRender(): void
- Tells all charts to stop watching there datalist.
addBehavior( behavior: GistBehavior | GistBehavior[] ): void
- Add the given behaviors to this canvas. By default, the canvas is a static element, but through behaviors you can allow the user to zoom, pan and drawn data interactivity with the user. See the section on behaviors for more data.
removeBehavior( behavior: GistBehavior | GistBehavior[] ): void
- Remove the given behaviors from this canvas. Behaviors that are removed, will no longer fire. They can always be restored by calling addBehavior again.
cancelBehaviorActivation(): void
- For performance reasons by default behaviors throttle or debounce their events. In the event that you wish to stop a delayed even from firing, you may call this method.
- Note: This is called whenever the user mouses away from this canvas.
zoom( zoomLevel: number ): void
- Set the given zoom level for this canvas. Values between 0 and 1 will zoom out. Values greater than 1 will zoom in.
pan( x: number, y: number ): void
- Pan the canvas by x,y pixels
getDataUrl( type?: string ): string
- Calls toDataUrl on this canvas displayed html canvas element.
- Note. If charts are currently rendering they may not be reflected by the return value of this. To ensure they are included, call this after renderstate change has been called.
getImageData(x: number?, y: number?, width: number?, height: number? ): ImageData
- Calls getImageData on the canvas's html canvas element's context. X, Y default to 0, and width and height default to the width and height of the canvas element.
- Note. If charts are currently rendering they may not be reflected by the return value of this. To ensure they are included, call this after renderstate change has been called.
background: string | undefined ( undefined by default )
- By default your canvas will be transparent, you can set a background color for the canvas by setting this.
- Note: This must be set before beginRender is called to have affect.
layout: GistChartLayout
- By default the chart canvas will take up the space in its parent element, then allocate space for the axis ( in the margins ), and leave the remaining space for the charts to be rendered in. This can be changed by editing these properties.
- minMargin: TBLR<number> The minimal amount of space supplied for the axis to draw, and for the chart to overflow ( used to allow charts to draw values on the edge and display the overflow )
- maxMargin: TBLR<number> The maximum amount of space supplied for the axis to draw, and for the chart to overflow ( used to allow charts to draw values on the edge and display the overflow )
- By default the chart canvas will take up the space in its parent element, then allocate space for the axis ( in the margins ), and leave the remaining space for the charts to be rendered in. This can be changed by editing these properties.
New DataPoint( data?: T)
All Charts contain a data list that is made up of data points.
- data: T | Undefined
- This is the data that is assoacited with this point. Anytime you need to do something with this specific point, store what you need here. This can be set either when the point as a contructor paramater or set directly later.
* getExtent( chart: BaseChart ): Extent
- Return the extent x and y bounds of the shape that the given chart drew for this point.
- Note: This will fail if the point is not drawn yet.
Base Chart
All charts will have the following properties unless otherwise specified
datalist( val?: Array | T ) {
- When given an array, This chart will wipe out drawn data it has already done, and then start watching the instance of the array given, and start drawing this array. That instance can have new points added, and this chart will draw them. However, points removed or changed after being drawn will not be detected.
getStyle( dp: DataPoint | undefined ): CanvasStyle
- This method should be overwritten. The method will take a DataPoint and return a style that determines how it will be drawn. See this method under each chart to see its defaults or any point of the canvas style that is ignored.
drawCountPerRender: number
- How many data points should be rendered per animation frame. Increasing this will cause the chart to draw faster, but may cause dips in browser performance.
margin: number ( 0 by default )
- The amount of space outside of the alloted chart that the chart can overflow onto. This is useful if you want a chart to draw on the explicit mins, or max and not be cut off.
background : string | undefined ( undefined by default )
- Charts are transparent by default ( easier to stack ) however, you can give a chart a background that will cover charts below this one.
alpha: number ( 1 by default )
- Decreasing the alpha will make this chart more transparent. Setting the value to 0 will make this chart completely invisible.
zIndex: number | undefined ( undefined by default )
- By defaults charts are drawn in the order they are given. The order can be changed by setting the zIndex.
isActive: boolean ( true by default )
- Active charts are drawn, inactive charts are not drawn.
shouldCenterBandX: boolean ( false by default )
- When this is set to true, if valueToWidth is overwritten, values will be offset by half of the returned value. This is useful if you want to align continuous axis and categorical axis. This is useful if you want to align a continuous axis with a categorical axis.
shouldCenterBandY: boolean ( false by default )
- When this is set to true, if valueToWidth is overwritten, values will be offset by half of the returned value. This is useful if you want to align continuous axis and categorical axis. This is useful if you want to align a continuous axis with a categorical axis.
LineChart extends BaseChart
Each LineChartData will be drawn as a single line on the chart. The entire line, will be treated as a single entity, meaning that it is styled the same throughout and supported mouse events will trigger if anywhere on the line is clicked. If you want to have separate styles through the lines, you will need to create multiple LineChartData objects. If you want to have events trigger on the vertices, you can pass the DataPoints of the LineChartData to a scatter chart.
class LineChartData<T = any> extends DataPoint<T> {
points: DataPoint<any>[] = [];
}
ScatterChart extends BaseChart
- getStyle( dp: DataPoint ): ScatterStyle
BarChart extends BaseChart
- getX2: undefined | ( ( dp: DataPoint ) => any );
- Bars are anchored by the corner defined by the axis getValues. The second x coordinate is defined by getX2 if it is defined, if not, it is defined by valueToWidth.
- getY2: undefined | ( ( dp: DataPoint ) => any );
- Bars are anchored by the corner defined by the axis getValues. The second y coordinate is defined by getY2 if it is defined, if not, it is defined by valueToWidth.
AreaChart extends BaseChart
- fillAxis: BaseAxis ( the charts x axis by default )
- When shouldFillToOrigin is true ( it is by default ), this axis will be used to fill the area with.
- shouldFillToOrigin : boolean ( true by default )
- If true, the data lines will connect the areas bounding line to the origin and then fill it.
- If false, the end of the lines will be connected and filled.
- axisOrigin: any ( should be the same type used for values of the fill axis )
- This is the value that areas will be filled to.
BoxPlot extends BaseChart
- primaryAxis: BaseAxis ( has to be set or will not drawn )
- The whiskers of the boxplot will stretch out from the core box along this axis.
- secondaryAxis: BaseAxis ( has to be set or will not drawn )
- The box plot items will use this axis to determine the width of each item drawn.
- getBandThickness: ( datapoint?: BoxPlotData ) => number
- How wide should the box plots be drawn? by default this is determined by the axis. Categorical axis will give the width of the corresponding category. While continuous axis will return the size of the stroke. You can overwrite this behavior by redefining this function.
RadialChart extends BaseChart
Note: radial chart close enough property only works on the inner and outer radius. It will not consider the point if is not between the start and stop angles.
- isClockwise: boolean = false;
- By default unit circles are not clockwise. flip this to true if you want them
- labelPixelOffset: number = 15;
- set the number of pixels to offset labels by
- centerXValue: number = 0;
- This is the value that will be given to the axis to determine the center of the chart
- centerYValue: number = 0;
- This is the value that will be given to the axis to determine the center of the chart
- radialAxis: BaseAxis | undefined;
- Axis to use when scaling the radius. By default will be the x axis
- getStartAngle: ( dp: DataPoint )=>number = shouldImplement.bind( this, 'getStartAngle') as any;
- How to extract the start angle from the data point
- getStopAngle: ( dp: DataPoint )=>number = shouldImplement.bind( this, 'getStopAngle') as any;
- How to extract the end angle from the data point
- getInnerRadius: ( dp: DataPoint )=>number = shouldImplement.bind( this, 'getInnerRadius') as any;
- Given the data point get what you need to give to the axis getValue( x: any )=> number method
- getOuterRadius: ( dp: DataPoint )=>number = shouldImplement.bind( this, 'getOuterRadius') as any;
- Given the data point get what you need to give to the axis getValue( x:any )=> number method
- getLabel:( dp: DataPoint )=>string|undefined = shouldImplement.bind(this, 'getLabel') as any;
- Given the data point get the label for that curve
Base Axis<T>
All Axis will have these properties and configs unless otherwise specified.
getValue( dp: DataPoint ): T
- This method must be provided by the coder. It converts a datapoint to the value that this axis is built off of.
valueToString( value: T, tickIndex?: number, tickArray?: T[] ): string This method determines how axis values are displayed on the tick marks. By default, what ever the value, is will just have toString() called on it. However if you are using something like a date, or floating numbers, you will want to overwrite this method to provide your own formatting. The value is the current value getting formatted. The tick index is the index of the tick mark in its array. tickArray, is an array of all the tick values that will be displayed.
valueToImage( value:T )=> GistCanvas | undefined
- Set this method to draw the given GistCanvas behind or in place of any text given by valueToString.
- We use GistCanvas because it automatically applies the pixel ratio logic to prevent blurs.
label: string | undefined;
The string that displayed on the side of this axis.
lineHeight: number = 20;
- How tall the canvas should consider the text to be to ensure that it has enough room to display
font: string = 'bold 14px Roboto,"Helvetica Neue",sans-serif';
- What font the canvas should use to draw with this axis
tickAngle: number = 0 ( radians );
- By default, tick labels will be drawn horizontally, You can give an an angle in radians to rotate the text. Note, this will throw off the alignment for the labels, so we advise setting that.
tickTextAlign: undefined | 'center' | 'right' | 'left' = undefined;
- How the tick labels should be aligned with respect to their ticks. When undefined, Top and bottom axis will center their text, and the left and right text will align the text to line up against the tick mark.
axisLineThickness: number = 1;
- How thick are the tick marks/ axis border
color: string = '#000';
- The color that will be used to draw the axis border, ticks, tick labels and axis label.
tickLength: number = 5;
- How long in pixels to make the tick marks
tickLabelPad: number = 3;
- How much space around between tick marks and tick labels, and the tick labels and axis label.
shouldRenderTicks: boolean = true;
- Set this to false to not draw tick marks or their labels
shouldRenderBorder: boolean = true;
- Set this to false to not draw the border against the edge of the chart
shouldExtendTicksAcrossChart: boolean = false;
- Set this to true to extend tick makes across the chart. These will be drawn behind each chart.
registerChart( charts: BaseChart | BaseChart[] ): BaseAxis
- Tells each provided chart to use this axis as its x or y axis ( determined by this axis orientation )
resetZoom(): void
- Reset the zoom level to 1.
zoom( zoom: number = 1.14, offset: number = 0 ): void
- Set the zoom level for this axis. Values between 0 and 1, zoom out from the default view. Values greater than 1 zoom in.
CategoricalAxis<T> extends BaseAxis
CategoricalAxis are axis non continuous domains. They require explicitCategories to be set. And any value datapoint that cannot find a cateogry will throw an error, so they should be filtered out before given to a list. By default, the size of each category will be the same such that when combined, they will fill the chart.
explicitCategories( value: T ):
- An array of the categories that make up this axis domain. In order for changes in this to be detected, chartCanvas.beginRender() must be called.
getCategorySize( value: T ): number
- If you want a category to be a certain size, you can set this method. It will overwrite minCategorySize and maxCategorySize.
minCategorySize: number | undefined = undefined * Ensure that categories will be no smaller than this. If there is not enough room on the axis, points will be drawn off canvas and not be seen.
- Note: this will be overwritten by getCategorySize
maxCategorySize: number | undefined = undefined
- Ensure that categories will be no larger than this. This may cause the chart to not fill the given canvas.
- Note: this will be overwritten by getCategorySize
innerPadding: number = 0.1
- Once the width for the category is determined,what percentage of that belongs to the space between categories. This value only determines the space in between categories. To set the space between the first and last category and the edge of the chart, set outerPadding
outerPadding: number = 0.1
- Once the width for the category is determined,what percentage of that belongs to the space between the first and last category and the edge of the chart canvas. To set the space between the categories, set innerPadding
tickLabelPosition: 'center' | 'stop' | 'start' = 'center'
- Tells the axis where to draw its label for the category.
- 'center' ( default ) is in the middle of the category.
- 'start' will draw it where the band begins.
- 'stop' will draw it where the band ends.
- Tells the axis where to draw its label for the category.
ContinuousAxis<T> extends BaseAxis
Continuous axis. Where the value to pixel is determined using a linear scale mapped from the chart extents to the explicit bounds.
explicitBounds: T[]
- Explicit min and max values for this axis. Order does not matter, the chart will flow with the first value being on the left, to second value being on the right.
explicitTickValues: T[] | undefined
valueToWidth( value: T )
- This method will determine how wide a category on the axis will be given. By default, a ContinuousAxis will give all values the value of Axis.axisLineThickness.
LogAxis extends ContinuousAxis
Log axis is an extension of the continuous scale. Instead of a linear scale, a log scale will be used.
- base: number = 10
- The base for this logarithmic to use.
TemporalAxis extends ContinuousAxis
TemporalAxis is an extension of the continuous axis. The value of the dates are used to generate ticks. Using a temporal axis instead of a continuous axis will result in much better tick marks.
Behaviors
ChartCanvas will not be interactive by default. You can change this by calling addBehavior, and then passing in a new behavior object.
let getData = new GetDataAtMouseEvent(
'click',
{
chart: charts,
onEvent: ( reports ) => {
let pointsAtEvent: DataPoint[] = [];
reports.forEach( r => pointsAtEvent.push( ...r.dpl ) );
if ( !pointsAtEvent.length ) {
selectedData = [];
}
selectedData.push( ...pointsAtEvent );
selectionUpdate();
}
},
3
);
let zoom = new ZoomBehavior();
zoom.limitZoom( axis, 0.5, 1.5 );
let pan = new PanBehavior('wheel'); // use wheel because we want to click on the data
pan.limitPan( bottomAxis, pointCount * -0.25, pointCount * 1.25 );
me.chart.addBehavior( [ getData, zoom, pan ] );
PanBehavior
PanBehavior will allow the user to pan the various charts by the x and y axis. By default, it works by holding the mouse button down on the chart, dragging to pan, and then releasing to stop. Be warned that this does trigger redraws on every chart and this can be costly in performance.
- new PanBehavior(eventNames: 'mousedrag' | 'wheel', throttleTime: number )
- eventNames: 'wheel' allows the user to pan by scrolling the mouse. 'mousedrag' works by clicking down and dragging.
- throttleTime: How often in milliseconds this event can fire. defaults to 15
- limitPan( axis: BaseAxis, minValue: T, maxValue: T ) where T is the type that the axis uses for values
- The given axis will not allow the min or max value to be moved out of the chart view.
- Beta feature. It is known that this can lock up sometimes, especially when used with ZoomBehavior.limitZoom
ZoomBehavior
ZoomBehavior allow the user to zoom in on the data while not changing the size of the chart element and still keep the same resolution.
new ZoomBehavior(zoomConstant: number ,zoomMethod: 'multiplication' | 'addition' , throttleTime: number )
- zoomConstant: controls how strong the zoom step is. Defaults to 1.15
- zoomMethod: multiplication zoom steps are based on the current zoom level resulting in a smoother movement. addition will jump by steps. defaults to 'multiplication'
- throttleTime: how long in milliseconds to throttle the event. defaults to 50.
limitZoom( targets: BaseAxis | Array, minZoomLevel: number, maxZoomLevel: number )
- The given axis will not be able to zoom past the minZoomLevel and maxZoomLevel
- Beta feature. It is known that this can lock up sometimes, especially when used with PanBehavior.limitPan
GetDataAtEvent
This behavior will get all drawn data points at the given event, and make a callback with each of the given charts, and the data at that point for the chart. Note, only points that are drawn will be returned.
- new GetDataAtMouseEvent ( eventNames: supportedEventType | supportedEventType[], eventHandlers: EventHandler | EventHandler[], closeEnough: number = 0 throttleTime: number = 250, limiter: LimiterType = 'throttle' )
- supportedEventType: 'dblclick' | 'click' | 'mousedown' | 'mousemove' | 'mouseout' | 'mouseover' | 'mouseup'
- EventHandler is an interface object you need to pass to tell what charts to listen for this event on, and how to handle the event. When the onEvent method you pass is called, it will be called with a list of reports EventReports. Each report has a chart, and the list of drawn datapoints at this event.
- closeEnough: number( 0 by default ) The number of pixels that a mouse can be away from a drawn value and still register as being over it.
interface EventHandler {
chart: BaseChart | Array<BaseChart> | undefined;
onEvent: (
reportList: Array<EventReport>,
mouseEvent: MouseEvent | undefined
) => void;
}
interface EventReport {
dpl: DataPoint[],
chart: BaseChart
}
Debugging ( debugLogger.enabled=true )
ChartCanvas, Charts, and Axis objects all have an object property called debugLogger. If you set its enabled flag, to true, it will print out various debug information.This is very very verbose. To help with the amount of information, You can set the logPrefix to prefix each message an object prints with the prefix. By default, it will use window.console.error to log debug information, bt you can overwrite its log method to anything youd like. The object is defined as.
class DebugLogger{
logPrefix: string = '' // string to prefix any message from this logger.
logMethod: = console.error // method to be called when debug information is provided.
isEnabled: boolean = false // whether or not to provide debug information.
}
Helper Functions
makeHiDPICanvas( width: number, height: number, canvas?: HTMLCanvasElement )
Will scale a canvas to device resolution. See https://www.html5rocks.com/en/tutorials/canvas/hidpi/ for an explanation for why this is needed.
drawSourceCanvas( source: HTMLCanvasElement, destination: HTMLCanvasElement, left: number, top: number )
Will draw the source canvas onto the destination canvas. This is essentially context.drawImage, except that this will do the HiDPI scaling for you.
Utility Classes / Interfaces
class TBLR<T>{
public top:T
public bottom:T
public left:T
public right:T
constructor ( defaultValue: T | TBLR<T> )
isEqual( tblr: TBLR<T> // returns true if all values of both instances are the same
setValue( value: T ) // Returns true if top, bottom left and right all equal value.
setValue( TBLR<T> ) // Returns if top, bottom, left, and right all equal their corresponding values
}
class DebugLogger{
logPrefix: string = ''
logMethod: = console.error
isEnabled: boolean = false
}
Change Log
- 1.1.0:
- Feature: ValueToImage on axis
- Bug Fix: OnRenderStateChange will trigger when rendering begins and finishes on the same cycle
- 1.1.001
- Bug Fix: Chart margins will now be cleared