Skip to content

Commit

Permalink
feat(wordcloud): accept custom canvas (#6354)
Browse files Browse the repository at this point in the history
* feat(wordcloud): accept custom canvas

* docs: update wordcloud docs

* feat(data-transform): pass createCanvas

* refactor(runtime): simplfy library param
  • Loading branch information
pearmini authored Jul 11, 2024
1 parent 1aae3a5 commit 759ee3f
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 78 deletions.
28 changes: 28 additions & 0 deletions __tests__/integration/api-chart-word-cloud-canvas.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { chartWordCloudCanvas as render } from '../plots/api/chart-word-cloud-canvas';
import './utils/useSnapshotMatchers';
import { createNodeGCanvas } from './utils/createNodeGCanvas';
import './utils/useCustomFetch';

describe('word cloud canvas', () => {
const canvas = createNodeGCanvas(640, 480);

it('word cloud should use custom canvas.', async () => {
// This no canvas in JSDOM environment, so it will throw error.
// But it's ok, we just need to test if the ref is called.
let ref;
try {
const rendered = render({
canvas,
container: document.createElement('div'),
});
ref = rendered.ref;
await rendered.finished;
} catch (e) {
expect(ref.called).toBe(true);
}
});

afterAll(() => {
canvas?.destroy();
});
});
28 changes: 28 additions & 0 deletions __tests__/plots/api/chart-word-cloud-canvas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { Chart } from '../../../src';

export function chartWordCloudCanvas(context) {
const { container, canvas } = context;

const ref = { called: false };

const chart = new Chart({
container,
canvas,
createCanvas: () => {
ref.called = true;
return document.createElement('canvas');
},
});

chart.options({
type: 'wordCloud',
data: {
type: 'fetch',
value: 'data/philosophyWord.json',
},
});

const finished = chart.render();

return { chart, ref, finished };
}
1 change: 1 addition & 0 deletions __tests__/plots/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,4 @@ export { chartAutoFitHeight } from './chart-auto-fit-height';
export { chartAutoFitWidth } from './chart-auto-fit-width';
export { chartOnLabelClick } from './chart-on-label-click';
export { chartChangeSizeLabelRotate } from './chart-change-size-label-rotate';
export { chartWordCloudCanvas } from './chart-word-cloud-canvas';
5 changes: 4 additions & 1 deletion src/api/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export type RuntimeOptions = ViewComposition & {
plugins?: RendererPlugin[];
theme?: string;
lib?: G2Library;
createCanvas?: () => HTMLCanvasElement;
};

export class Runtime<Spec extends G2Spec = G2Spec> extends CompositionNode {
Expand All @@ -53,7 +54,8 @@ export class Runtime<Spec extends G2Spec = G2Spec> extends CompositionNode {
private _compositions: Record<string, new () => Node>;

constructor(options: RuntimeOptions) {
const { container, canvas, renderer, plugins, lib, ...rest } = options;
const { container, canvas, renderer, plugins, lib, createCanvas, ...rest } =
options;
super(rest, 'view');
this._renderer = renderer || new CanvasRenderer();
this._plugins = plugins || [];
Expand All @@ -63,6 +65,7 @@ export class Runtime<Spec extends G2Spec = G2Spec> extends CompositionNode {
library: { ...lib, ...library },
emitter: this._emitter,
canvas,
createCanvas,
};
this._create();
}
Expand Down
8 changes: 6 additions & 2 deletions src/data/utils/d3-cloud/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,10 +256,10 @@ export function tagCloud() {
event = cloudDispatch,
words = [],
timer = null,
timeInterval = Infinity;
timeInterval = Infinity,
canvas = cloudCanvas;

const fontStyle = cloudFontNormal;
const canvas = cloudCanvas;
const cloud: any = {};

cloud.start = function () {
Expand Down Expand Up @@ -476,6 +476,10 @@ export function tagCloud() {
rotate = functor(_);
};

cloud.canvas = function (_) {
canvas = functor(_);
};

cloud.spiral = function (_) {
spiral = spirals[_] || _;
};
Expand Down
16 changes: 14 additions & 2 deletions src/data/wordCloud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,16 @@ export type WordCloudOptions = {
* If not specified, returns the current random number generator, which defaults to Math.random.
*/
random: () => number;

/**
* If specified, sets the spiral used for positioning words.
*/
spiral: any;

/**
* If specified, sets the image mask used for positioning words.
*/
canvas: HTMLCanvasElement;
};

const DEFAULT_OPTIONS = {
Expand Down Expand Up @@ -151,9 +160,11 @@ export function normalizeFontSize(fontSize: any, range?: [number, number]) {
return () => fontSize;
}

export const WordCloud: DC<Partial<WordCloudOptions>> = (options) => {
export const WordCloud: DC<Partial<WordCloudOptions>> = (options, context) => {
return async (data) => {
const cloudOptions = Object.assign({}, DEFAULT_OPTIONS, options);
const cloudOptions = Object.assign({}, DEFAULT_OPTIONS, options, {
canvas: context.createCanvas,
});
const layout = tagCloud();

await flow(layout, cloudOptions)
Expand All @@ -172,6 +183,7 @@ export const WordCloud: DC<Partial<WordCloudOptions>> = (options) => {
.set('random')
.set('text')
.set('on')
.set('canvas')
.setAsync('imageMask', processImageMask, layout.createMask);

layout.words([...data]);
Expand Down
13 changes: 4 additions & 9 deletions src/runtime/mark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,11 @@ import {
G2Mark,
G2TransformOptions,
G2EncodeOptions,
G2Context,
} from './types/options';
import { MarkProps } from './types/mark';
import { NormalizedEncodeSpec, EncodeComponent, Encode } from './types/encode';
import {
ColumnOf,
TransformContext,
Transform,
TransformComponent,
} from './types/transform';
import { ColumnOf, Transform, TransformComponent } from './types/transform';
import {
applyDefaults,
applyDataTransform,
Expand All @@ -33,10 +29,9 @@ import {
export async function initializeMark(
partialMark: G2Mark,
partialProps: MarkProps,
library: G2Library,
context: G2Library,
): Promise<[G2Mark, G2MarkState]> {
// Apply transform to mark to derive indices, data, encode, etc,.
const context = { library };
const [I, transformedMark] = await applyMarkTransform(
partialMark,
partialProps,
Expand Down Expand Up @@ -143,7 +138,7 @@ export function createColumnOf(library: G2Library): ColumnOf {
async function applyMarkTransform(
mark: G2Mark,
props: MarkProps,
context: TransformContext,
context: G2Context,
): Promise<[number[], G2Mark]> {
const { library } = context;
const [useTransform] = useLibrary<
Expand Down
Loading

0 comments on commit 759ee3f

Please sign in to comment.