Skip to content

Commit

Permalink
optimize characterset generation (microsoft#258)
Browse files Browse the repository at this point in the history
* optimize characterset generation
  • Loading branch information
danmarshall authored Jul 21, 2020
1 parent 12a6bbf commit 4cc744e
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 16 deletions.
68 changes: 68 additions & 0 deletions packages/sanddance/src/characterSet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { Insight } from '@msrvida/sanddance-specs';
import { types } from '@msrvida/vega-deck.gl';

export class CharacterSet {
public chars: string[];

public checkNeedsNewCharacterSet(forceNewCharacterSet: boolean, oldInsight: Insight, newInsight: Insight) {
if (forceNewCharacterSet || needsNewCharacterSet(oldInsight, newInsight)) {
this.chars = undefined;
}
}

public checkGenCharacterSet(stage: types.Stage) {
if (!this.chars) {
const map: { [char: string]: true } = {};
const addText = (text: string) => {
Array.from(text).forEach(char => { map[char] = true });
};
stage.textData.forEach(t => addText(t.text));
const { x, y } = stage.axes;
[x, y].forEach(axes => {
axes.forEach(axis => {
if (axis.tickText) axis.tickText.forEach(t => addText(t.text));
if (axis.title) addText(axis.title.text);
});
});
this.chars = Object.keys(map);
}
}
}

function needsNewCharacterSet(oldInsight: Insight, newInsight: Insight) {
if (!oldInsight) return true;
if (oldInsight.chart !== newInsight.chart) return true;
if (oldInsight.facetStyle !== newInsight.facetStyle) return true;
if (oldInsight.totalStyle !== newInsight.totalStyle) return true;
if (oldInsight.hideAxes !== newInsight.hideAxes) return true;
if (differentObjectValues(oldInsight.signalValues, newInsight.signalValues)) return true;
if (differentObjectValues(oldInsight.size, newInsight.size)) return true;
const oldColumns = oldInsight.columns;
const newColumns = newInsight.columns;
if (oldColumns.facet !== newColumns.facet) return true;
if (oldColumns.facetV !== newColumns.facetV) return true;
if (oldColumns.x !== newColumns.x) return true;
if (oldColumns.y !== newColumns.y) return true;
if (oldColumns.z !== newColumns.z) return true;
return false;
}

function differentObjectValues(a: { [key: string]: any }, b: { [key: string]: any }) {
if (!a && !b) return false;
if (!a || !b) return true;
const keys = Object.keys(b);
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
let ta = typeof a;
let tb = typeof b;
if (ta !== tb) return true;
if (ta === 'object') {
return differentObjectValues(a[key], b[key]);
} else {
if (a[key] !== b[key]) return true;
}
}
return false;
}
5 changes: 0 additions & 5 deletions packages/sanddance/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,6 @@ export interface ViewerOptions extends SpecViewOptions {
*/
language: Language;

/**
* Character set for text elements
*/

characterSet?: string[];
/**
* Tooltip options
*/
Expand Down
25 changes: 17 additions & 8 deletions packages/sanddance/src/viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { Spec, Transforms } from 'vega-typings';
import Search = searchExpression.Search;
import SearchExpression = searchExpression.SearchExpression;
import SearchExpressionGroup = searchExpression.SearchExpressionGroup;
import { CharacterSet } from './characterSet';

const { defaultView } = VegaDeckGl.defaults;

Expand Down Expand Up @@ -113,6 +114,7 @@ export class Viewer {
private _tooltip: Tooltip;
private _shouldSaveColorContext: () => boolean;
private _lastColorOptions: ColorSettings;
private _characterSet: CharacterSet;

/**
* Instantiate a new Viewer.
Expand All @@ -122,6 +124,7 @@ export class Viewer {
constructor(public element: HTMLElement, options?: Partial<ViewerOptions>) {
this.options = VegaDeckGl.util.deepMerge<ViewerOptions>(defaultViewerOptions, options as ViewerOptions);
this.presenter = new VegaDeckGl.Presenter(element, getPresenterStyle(this.options));
this._characterSet = new CharacterSet();
this._dataScope = new DataScope();
this._animator = new Animator(
this._dataScope,
Expand Down Expand Up @@ -408,20 +411,20 @@ export class Viewer {
const allowAsyncRenderTime = 100;
if (insight.filter) {
//refining
result = await this._render(insight, data, options);
result = await this._render(insight, data, options, true);
this.presenter.animationQueue(() => {
this.filter(insight.filter, options.rebaseFilter && options.rebaseFilter());
}, allowAsyncRenderTime, { waitingLabel: 'layout before refine', handlerLabel: 'refine after layout' });
} else {
//not refining
this._dataScope.setFilteredData(null);
result = await this._render(insight, data, options);
result = await this._render(insight, data, options, true);
this.presenter.animationQueue(() => {
this.reset();
}, allowAsyncRenderTime, { waitingLabel: 'layout before reset', handlerLabel: 'reset after layout' });
}
} else {
result = await this._render(insight, data, options);
result = await this._render(insight, data, options, false);
}
return result;
}
Expand Down Expand Up @@ -459,7 +462,7 @@ export class Viewer {
};
}

private async _render(insight: Insight, data: object[], options: RenderOptions) {
private async _render(insight: Insight, data: object[], options: RenderOptions, forceNewCharacterSet: boolean) {
if (this._tooltip) {
this._tooltip.finalize();
this._tooltip = null;
Expand All @@ -470,6 +473,9 @@ export class Viewer {
}
this._specColumns = getSpecColumns(insight, this._dataScope.getColumns(options.columnTypes));
const ordinalMap = assignOrdinals(this._specColumns, data, options.ordinalMap);

this._characterSet.checkNeedsNewCharacterSet(forceNewCharacterSet, this.insight, insight);

this.insight = VegaDeckGl.util.clone(insight);
this._lastColorOptions = VegaDeckGl.util.clone(this.options.colors);
this._shouldSaveColorContext = () => !options.initialColorContext;
Expand Down Expand Up @@ -607,6 +613,7 @@ export class Viewer {
private createConfig(c?: VegaDeckGl.types.PresenterConfig): VegaDeckGl.types.ViewGlConfig {
const { getTextColor, getTextHighlightColor, onTextClick } = this.options;
const defaultPresenterConfig: VegaDeckGl.types.PresenterConfig = {
getCharacterSet: () => this._characterSet.chars,
getTextColor,
getTextHighlightColor,
onTextClick: (e, t) => {
Expand Down Expand Up @@ -660,7 +667,12 @@ export class Viewer {
preserveDrawingBuffer: this.options.preserveDrawingBuffer
};
if (this.options.onBeforeCreateLayers) {
defaultPresenterConfig.preLayer = stage => this.options.onBeforeCreateLayers(stage, this.specCapabilities);
defaultPresenterConfig.preLayer = stage => {
this._characterSet.checkGenCharacterSet(stage);
this.options.onBeforeCreateLayers(stage, this.specCapabilities);
}
} else {
defaultPresenterConfig.preLayer = stage => this._characterSet.checkGenCharacterSet(stage);
}
const config: VegaDeckGl.types.ViewGlConfig = {
presenter: this.presenter,
Expand All @@ -669,9 +681,6 @@ export class Viewer {
if (this.options.transitionDurations) {
config.presenterConfig.transitionDurations = this.options.transitionDurations;
}
if (this.options.characterSet) {
config.presenterConfig.characterSet = this.options.characterSet;
}
return config;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/vega-deck.gl/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export interface TransitionDurations {
export interface PresenterConfig {
transitionDurations?: TransitionDurations;
preStage?: PreStage;
characterSet?: string[];
getCharacterSet?: () => string[];
redraw?: () => void;
onCubeHover?: (e: MouseEvent | PointerEvent | TouchEvent, cube: Cube) => void;
onCubeClick?: (e: MouseEvent | PointerEvent | TouchEvent, cube: Cube) => void;
Expand Down
4 changes: 2 additions & 2 deletions packages/vega-deck.gl/src/layers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,8 @@ function newTextLayer(presenter: Presenter, id: string, data: VegaTextLayerDatum
props.fontFamily = fontFamily;
}

if (config.characterSet) {
props.characterSet = config.characterSet;
if (config.getCharacterSet) {
props.characterSet = config.getCharacterSet();
}

return new base.layers.TextLayer(props);
Expand Down

0 comments on commit 4cc744e

Please sign in to comment.