Commit d5a8e248 authored by David Anderson's avatar David Anderson
Browse files

axis now draw backgrounds

parent 578181bd
import { AfterViewInit, Component, ElementRef, OnDestroy, ViewChild } from '@angular/core';
import {
CanvasStyle
, GetDataAtMouseEvent
, DataPoint
, BarChart
, ContinuousAxis
, CategoricalAxis
, ChartCanvas
BarChart,
CanvasStyle,
CategoricalAxis,
ChartCanvas,
ContinuousAxis,
DataPoint,
GetDataAtMouseEvent,
GistCanvas,
} from 'gist-charts';
import { Component, ViewChild, ElementRef, AfterViewInit, OnDestroy } from '@angular/core';
@Component( {
selector: 'app-barchart-demo',
templateUrl: './barchart-demo.component.html',
......@@ -32,6 +32,19 @@ export class BarChartDemoComponent implements AfterViewInit, OnDestroy {
};
const leftAxis: CategoricalAxis<string> = new CategoricalAxis<string>( 'left' );
const topAxis: ContinuousAxis = new ContinuousAxis( 'top' );
const leftImage = new GistCanvas();
const topImage = new GistCanvas();
leftImage.setSize( 40, 15 );
topImage.setSize( 20, 15 );
leftImage.clearCanvas( '#aaa' );
topImage.clearCanvas( '#ccc' );
leftAxis.getCategoryImageSource = function ( cat: string ) { return leftImage; };
topAxis.getCategoryImageSource = function ( cat: string ) { return topImage; };
barChart.getX2 = ( dp: DataPoint ) => dp.data.testScore + dp.data.hitCount;
me.chart = new ChartCanvas( me.drawspace.nativeElement );
......
import { drawSourceCanvas } from '../utility/drawSourceCanvas.method';
import { makeHiDPICanvas } from '../utility/makeHiDPICanvas.method';
export class GistCanvas {
/**
* The canvas element to be drawn to
......@@ -50,7 +51,7 @@ export class GistCanvas {
this.context.clearRect( margin, margin, width, height );
if ( background ) {
this.context.fillStyle = background;
this.context.fillRect( margin, margin, width - margin*2, height - margin* 2 );
this.context.fillRect( margin, margin, width - margin * 2, height - margin * 2 );
}
}
}
......@@ -86,4 +87,3 @@ export class GistCanvas {
}
}
}
import { uID } from '../../utility/uID.method';
import { makeList } from '../../utility/makeList.method';
import { DataPoint } from '../../classes/datapoint.class';
import { BaseChart } from '../charts/baseChart.class';
import { BaseAxisImplementation } from '../../implementations/axis/baseAxisImplementation.class';
import { DebugLogger } from '../../classes/debugLogger.class';
import { BaseAxisImplementation } from '../../implementations/axis/baseAxisImplementation.class';
import { makeList } from '../../utility/makeList.method';
import { uID } from '../../utility/uID.method';
import { BaseChart } from '../charts/baseChart.class';
import { GistCanvas } from './../../classes/gistCanvas.class';
/**
* The Base config object for axis in GistCharts.
* Define the axis with new ContinuousAxis( position: 'top' | 'left' | 'right' | 'bottom' );
......@@ -142,6 +144,13 @@ export abstract class BaseAxis<T = any> {
*/
public shouldRenderBorder: boolean = true;
/**
* Draw an image behind the text of this categories tick
*
* @memberof CategoricalAxis
*/
public getCategoryImageSource: ( ( cat: T ) => GistCanvas ) | undefined;
/**
* Registers given charts with this axis, and sets this x/y axis of the chart to this.
* Registered charts will have their data considered when determining what the domain of the axis will be.
......@@ -220,4 +229,4 @@ export abstract class BaseAxis<T = any> {
chart._implementation.isDirty = true;
} );
}
}
\ No newline at end of file
}
import { CategoricalAxisImplementation } from '../../implementations/axis/categoricalAxisImplementation.class';
import { Orientation } from '../../types/orientation.type';
import { BaseAxis } from './baseAxis.class';
import { Orientation } from "../../types/orientation.type";
export class CategoricalAxis<T extends string | number = string> extends BaseAxis {
/**
......@@ -33,13 +33,13 @@ export class CategoricalAxis<T extends string | number = string> extends BaseAxi
public getCategorySize: ( ( cat: T ) => number ) | undefined;
/**
* Determines the amount of pading between bands
* Will be treated as a number of pixels when set to 1 or higher
* Will be treated as a perctange when less than 1
*
* @type {number}
* @memberof CategoricalAxis
*/
* Determines the amount of pading between bands
* Will be treated as a number of pixels when set to 1 or higher
* Will be treated as a perctange when less than 1
*
* @type {number}
* @memberof CategoricalAxis
*/
public innerPadding: number = 0.1;
/**
* Determines the amount of pading before first category and after last
......
......@@ -109,8 +109,8 @@ export abstract class BaseAxisImplementation<T> {
public get drawScaleMinMax() {
const me = this;
let min = Math.min.apply( me, me.drawScale.range() );
let max = Math.max.apply( me, me.drawScale.range() );
let min = Math.min( ...me.drawScale.range() );
let max = Math.max( ...me.drawScale.range() );
let diff = max - min;
return {
min: min,
......@@ -259,6 +259,11 @@ export abstract class BaseAxisImplementation<T> {
glc.setSize( me.chartWidth, me.chartHeight );
}
function drawBackground( img: GistCanvas | undefined, x: number, y: number ) {
if ( img ) {
img.renderTo( me.canvas.canvasEle, x, y );
}
}
let mmd = me.drawScaleMinMax;
let tickList = me.getAxisLabels();
......@@ -268,25 +273,40 @@ export abstract class BaseAxisImplementation<T> {
return;
}
ctx.save();
let image: undefined | GistCanvas;
let imgageWidth = 0, imageHeight = 0;
if ( me.axis.getCategoryImageSource ) {
image = me.axis.getCategoryImageSource( tick );
imgageWidth = image ? image.canvasEle.width : 0;
imageHeight = image ? image.canvasEle.height : 0;
}
if ( me.position === 'top' ) {
drawBackground( image, tick.position - imgageWidth / 2, tickBorderOffset - tickHeight - imageHeight );
ctx.fillRect( tick.position, tickBorderOffset, tickWidth, tickHeight );
ctx.translate( tick.position, tickBorderOffset - tickHeight );
ctx.rotate( me.axis.tickAngle );
ctx.fillText( tick.stringValue, 0, 0 );
}
else if ( me.position === 'bottom' ) {
drawBackground( image, tick.position - imgageWidth / 2, brOffset + tickHeight + me.axis.tickLabelPad );
ctx.fillRect( tick.position, tickBorderOffset, tickWidth, tickHeight );
ctx.translate( tick.position, brOffset + tickHeight + me.axis.tickLabelPad );
ctx.rotate( me.axis.tickAngle );
ctx.fillText( tick.stringValue, 0, 0 );
}
else if ( me.position === 'left' ) {
drawBackground(
image,
tickBorderOffset - tickWidth - imgageWidth,
tick.position - imageHeight / 2
);
ctx.fillRect( tickBorderOffset, tick.position, tickWidth, tickHeight );
ctx.translate( tickBorderOffset - tickWidth, tick.position );
ctx.rotate( me.axis.tickAngle );
ctx.fillText( tick.stringValue, 0, 0 );
}
else if ( me.position === 'right' ) {
drawBackground( image, tickBorderOffset + tickWidth + me.axis.tickLabelPad, tick.position - imageHeight / 2 );
ctx.fillRect( tickBorderOffset, tick.position, tickWidth, tickHeight );
ctx.translate( tickBorderOffset + tickWidth + me.axis.tickLabelPad, tick.position );
ctx.rotate( me.axis.tickAngle );
......
import { BaseAxisImplementation } from '../../implementations/axis/baseAxisImplementation.class';
import { CategoricalAxis } from '../../configs/axis/categoricalAxis.class';
import { Orientation } from '../../types/orientation.type';
import { BaseAxisImplementation } from '../../implementations/axis/baseAxisImplementation.class';
import { AxisLabel } from '../../types/axisLabel.type';
import { Orientation } from '../../types/orientation.type';
import { GistCanvas } from './../../classes/gistCanvas.class';
export class CategoricalAxisImplementation<T extends number | string> extends BaseAxisImplementation<T> {
protected axis!: CategoricalAxis<T>;
......@@ -27,7 +28,7 @@ export class CategoricalAxisImplementation<T extends number | string> extends Ba
ctx.font = me.axis.font;
if ( me.axis.explicitCategories ) {
me.categoryList = me.axis.explicitCategories.slice(0);
me.categoryList = me.axis.explicitCategories.slice( 0 );
} else {
throw 'Gist Charts Error: Categorical Axis requires explicitCategories to be set';
}
......@@ -43,7 +44,7 @@ export class CategoricalAxisImplementation<T extends number | string> extends Ba
let getCategorySize = me.axis.getCategorySize;
if ( getCategorySize !== undefined ) {
me.categoryList.forEach(( cat ) => {
me.categoryList.forEach( ( cat ) => {
const catWidth = getCategorySize ? getCategorySize( cat ) : NaN;
if ( me.axis.minCategorySize !== undefined && catWidth < me.axis.minCategorySize ) {
me.axis.debugLogger._log( 'Gist Charts: CategoricalAxis: The calculated category size is less than the minimum category size' );
......@@ -54,7 +55,7 @@ export class CategoricalAxisImplementation<T extends number | string> extends Ba
me._categoryWidthMap[ cat.toString() ] = catWidth;
} );
} else if ( me.axis.minCategorySize !== undefined && me.axis.minCategorySize === me.axis.maxCategorySize ) {
me.categoryList.forEach(( cat ) => {
me.categoryList.forEach( ( cat ) => {
me._categoryWidthMap[ cat.toString() ] = me.axis.minCategorySize as number;
} );
} else {
......@@ -67,24 +68,24 @@ export class CategoricalAxisImplementation<T extends number | string> extends Ba
if ( me.axis.maxCategorySize !== undefined ) {
categorySize = Math.min( me.axis.maxCategorySize, categorySize );
}
me.categoryList.forEach(( cat ) => {
me.categoryList.forEach( ( cat ) => {
me._categoryWidthMap[ cat.toString() ] = categorySize;
} );
}
me.categoryList.forEach(( cat ) => {
me.categoryList.forEach( ( cat ) => {
totalCategorySize += me._categoryWidthMap[ cat.toString() ];
} );
me._actualInnerPading = Math.ceil( ( mmd.diff - totalCategorySize ) / me.categoryList.length );
let alteredDomain = Math.min( Math.abs( me.scale.range()[ 1 ] - me.scale.range()[ 0 ] ), );
let alteredDomain = Math.min( Math.abs( me.scale.range()[ 1 ] - me.scale.range()[ 0 ] ) );
me.scale.domain( [ 0, alteredDomain ] );
let pos = 0;
function getPad( x: number, w: number ): number {
return x >= 1 ? x : x * w;
}
me.categoryList.forEach(( cat, i ) => {
me.categoryList.forEach( ( cat, i ) => {
let width = me._categoryWidthMap[ cat.toString() ];
let prePad: number = 0;
let postPad: number = 0;
......@@ -101,7 +102,7 @@ export class CategoricalAxisImplementation<T extends number | string> extends Ba
me._categoryWidthMap[ cat.toString() ] = width - prePad - postPad;
if ( me.isVertical ) {
me.categoryDomainMap[ cat.toString() ] += width - prePad - postPad;
}
}
pos += width;
} );
......@@ -120,19 +121,23 @@ export class CategoricalAxisImplementation<T extends number | string> extends Ba
return scaled - me.getOffset();
}
public valueToImageCanvas( cat: T ): GistCanvas | undefined {
return undefined;
}
getAxisLabels(): Array<AxisLabel> {
const me = this;
let categories = me.axis.explicitCategories || me.getDefaultTicks();
let offset = me.getOffset();
return categories.map(( val, i ) => {
return categories.map( ( val, i ) => {
let tickStr = me.axis.valueToString( val, i, categories );
let band = me.valueToWidth( val );
let posOffset: number = offset;
if( me.axis.tickLabelPosition === 'stop' ){
if ( me.axis.tickLabelPosition === 'stop' ) {
posOffset += band;
}else if( me.axis.tickLabelPosition === 'start' ){
} else if ( me.axis.tickLabelPosition === 'start' ) {
posOffset += 0;
}else if( me.axis.tickLabelPosition === 'center' ){
} else if ( me.axis.tickLabelPosition === 'center' ) {
posOffset += band / 2;
}
return {
......
import { DataPoint } from '../../classes/datapoint.class';
import { BaseChart } from '../charts/baseChart.class';
import { BaseAxisImplementation } from '../../implementations/axis/baseAxisImplementation.class';
import { DebugLogger } from '../../classes/debugLogger.class';
import { BaseAxisImplementation } from '../../implementations/axis/baseAxisImplementation.class';
import { BaseChart } from '../charts/baseChart.class';
import { GistCanvas } from './../../classes/gistCanvas.class';
/**
* The Base config object for axis in GistCharts.
* Define the axis with new ContinuousAxis( position: 'top' | 'left' | 'right' | 'bottom' );
......@@ -120,6 +121,12 @@ export declare abstract class BaseAxis<T = any> {
* @memberof BaseAxis
*/
shouldRenderBorder: boolean;
/**
* Draw an image behind the text of this categories tick
*
* @memberof CategoricalAxis
*/
getCategoryImageSource: ((cat: T) => GistCanvas) | undefined;
/**
* Registers given charts with this axis, and sets this x/y axis of the chart to this.
* Registered charts will have their data considered when determining what the domain of the axis will be.
......
import { CategoricalAxisImplementation } from '../../implementations/axis/categoricalAxisImplementation.class';
import { Orientation } from '../../types/orientation.type';
import { BaseAxis } from './baseAxis.class';
import { Orientation } from "../../types/orientation.type";
export declare class CategoricalAxis<T extends string | number = string> extends BaseAxis {
/**
* The class object that implements this chart. This should never be touched outside of GistCharts
......@@ -25,13 +25,13 @@ export declare class CategoricalAxis<T extends string | number = string> extends
maxCategorySize: number | undefined;
getCategorySize: ((cat: T) => number) | undefined;
/**
* Determines the amount of pading between bands
* Will be treated as a number of pixels when set to 1 or higher
* Will be treated as a perctange when less than 1
*
* @type {number}
* @memberof CategoricalAxis
*/
* Determines the amount of pading between bands
* Will be treated as a number of pixels when set to 1 or higher
* Will be treated as a perctange when less than 1
*
* @type {number}
* @memberof CategoricalAxis
*/
innerPadding: number;
/**
* Determines the amount of pading before first category and after last
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
......@@ -77,8 +77,8 @@ export declare abstract class BaseAxisImplementation<T> {
*/
getScaledBandCenter(dp: DataPoint): number;
readonly drawScaleMinMax: {
min: any;
max: any;
min: number;
max: number;
diff: number;
};
readonly textAlign: string;
......
import { BaseAxisImplementation } from '../../implementations/axis/baseAxisImplementation.class';
import { CategoricalAxis } from '../../configs/axis/categoricalAxis.class';
import { Orientation } from '../../types/orientation.type';
import { BaseAxisImplementation } from '../../implementations/axis/baseAxisImplementation.class';
import { AxisLabel } from '../../types/axisLabel.type';
import { Orientation } from '../../types/orientation.type';
import { GistCanvas } from './../../classes/gistCanvas.class';
export declare class CategoricalAxisImplementation<T extends number | string> extends BaseAxisImplementation<T> {
protected axis: CategoricalAxis<T>;
private categoryList;
......@@ -16,6 +17,7 @@ export declare class CategoricalAxisImplementation<T extends number | string> ex
protected postFinalizeDataAndSize: () => void;
getDefaultTicks(): T[];
valueToPx(cat: T): number;
valueToImageCanvas(cat: T): GistCanvas | undefined;
getAxisLabels(): Array<AxisLabel>;
valueToWidth(cat: T): number;
}
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment