зеркало из https://github.com/microsoft/SandDance.git
Stacks view (#28)
* remove comment * try/catch around signal getter * expose default viewer options * clone default viewer options, merge every update * correct shouldViewstateTransition * extend specLanguage * add grid signal names * use new signalname * nullref check * add name for catch-all * get key or catch-all * added stacks view * use common axes code * prefer 3d for stacks, 2d for treemap * transitions durations text * use legend data for quantitative color * remove opacity * show bin signals * add trailing slashes * prevent x-overlap * remove sequ * clamp signal range * use tick value for selection, format number * use defaultPresenterConfig * enable 2D/3D in transition editor * fix boundary check for resize
This commit is contained in:
Родитель
a94e769afb
Коммит
6e903d9887
|
@ -28,10 +28,10 @@
|
|||
<a href="{{ site.baseurl }}/" class="c-site-nav__item">
|
||||
Home
|
||||
</a>
|
||||
<a href="{{ site.baseurl }}/app" class="c-site-nav__item">
|
||||
<a href="{{ site.baseurl }}/app/" class="c-site-nav__item">
|
||||
Try Online
|
||||
</a>
|
||||
<a href="{{ site.baseurl }}/examples" class="c-site-nav__item">
|
||||
<a href="{{ site.baseurl }}/examples/" class="c-site-nav__item">
|
||||
Examples
|
||||
</a>
|
||||
<a href="{{ site.baseurl }}/docs/" class="c-site-nav__item">
|
||||
|
|
|
@ -59,6 +59,20 @@
|
|||
};
|
||||
var prefs = {
|
||||
"*": {
|
||||
"stacks": {
|
||||
"*": {
|
||||
"*": {
|
||||
"view": "3d"
|
||||
}
|
||||
}
|
||||
},
|
||||
"treemap": {
|
||||
"*": {
|
||||
"*": {
|
||||
"view": "2d"
|
||||
}
|
||||
}
|
||||
},
|
||||
"*": {
|
||||
"*": {
|
||||
"*": {
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
<header>
|
||||
<h1>vega-deck.gl transition editor</h1>
|
||||
<button id="view-type-button" onclick="view.view=~~!view.view">2D / 3D</button>
|
||||
<button id="view-type-button" onclick="transition.toggleView()">2D / 3D</button>
|
||||
</header>
|
||||
<div id="split-left" class="double">
|
||||
<div class="textform">
|
||||
|
|
|
@ -84,6 +84,20 @@
|
|||
};
|
||||
var prefs = {
|
||||
"*": {
|
||||
"stacks": {
|
||||
"*": {
|
||||
"*": {
|
||||
"view": "3d"
|
||||
}
|
||||
}
|
||||
},
|
||||
"treemap": {
|
||||
"*": {
|
||||
"*": {
|
||||
"view": "2d"
|
||||
}
|
||||
}
|
||||
},
|
||||
"*": {
|
||||
"*": {
|
||||
"*": {
|
||||
|
|
|
@ -48,14 +48,13 @@ export function Chart(props: Props) {
|
|||
text: strings.chartTypeTreeMap,
|
||||
checked: props.chart === 'treemap',
|
||||
disabled: props.disabled
|
||||
},
|
||||
{
|
||||
key: 'stacks',
|
||||
text: strings.chartTypeStacks,
|
||||
checked: props.chart === 'stacks',
|
||||
disabled: props.disabled
|
||||
}
|
||||
//,
|
||||
// {
|
||||
// key: 'stacks',
|
||||
// text: strings.chartTypeStacks,
|
||||
// checked: props.chart === 'stacks',
|
||||
// disabled: props.disabled
|
||||
// }
|
||||
]}
|
||||
onChange={(e, o) => props.onChangeChartType(o.key as SandDance.types.Chart)}
|
||||
/>
|
||||
|
|
|
@ -107,11 +107,20 @@ function initState(props: Props): State {
|
|||
};
|
||||
}
|
||||
|
||||
function signalGroupKey(key: string) {
|
||||
for (let i = 0; i < strings.signalGroups.length; i++) {
|
||||
if (strings.signalGroups[i].prefix === key) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
return '*';
|
||||
}
|
||||
|
||||
function vegaSignalGroups(vegaSignals: VegaSignal[]) {
|
||||
const signalGroupMap: { [key: string]: VegaSignal[] } = {};
|
||||
vegaSignals.forEach(vs => {
|
||||
const split = vs.name.split('_');
|
||||
const key = split[0];
|
||||
const key = signalGroupKey(split[0]);
|
||||
signalGroupMap[key] = signalGroupMap[key] || [];
|
||||
signalGroupMap[key].push(vs);
|
||||
});
|
||||
|
@ -183,6 +192,46 @@ export class Settings extends React.Component<Props, State> {
|
|||
})}
|
||||
/>
|
||||
</Group>
|
||||
<Group
|
||||
label={strings.labelTransitionDurations}
|
||||
>
|
||||
<base.fabric.Slider
|
||||
label={strings.labelTransitionColor}
|
||||
onChange={value => {
|
||||
this.props.explorer.viewerOptions.transitionDurations.color = value;
|
||||
}}
|
||||
min={0}
|
||||
max={10000}
|
||||
defaultValue={this.props.explorer.viewerOptions.transitionDurations.color}
|
||||
/>
|
||||
<base.fabric.Slider
|
||||
label={strings.labelTransitionPosition}
|
||||
onChange={value => {
|
||||
this.props.explorer.viewerOptions.transitionDurations.position = value;
|
||||
}}
|
||||
min={0}
|
||||
max={10000}
|
||||
defaultValue={this.props.explorer.viewerOptions.transitionDurations.position}
|
||||
/>
|
||||
<base.fabric.Slider
|
||||
label={strings.labelTransitionSize}
|
||||
onChange={value => {
|
||||
this.props.explorer.viewerOptions.transitionDurations.size = value;
|
||||
}}
|
||||
min={0}
|
||||
max={10000}
|
||||
defaultValue={this.props.explorer.viewerOptions.transitionDurations.size}
|
||||
/>
|
||||
<base.fabric.Slider
|
||||
label={strings.labelTransitionCamera}
|
||||
onChange={value => {
|
||||
this.props.explorer.viewerOptions.transitionDurations.view = value;
|
||||
}}
|
||||
min={0}
|
||||
max={10000}
|
||||
defaultValue={this.props.explorer.viewerOptions.transitionDurations.view}
|
||||
/>
|
||||
</Group>
|
||||
<Dialog
|
||||
hidden={!state.showVegaDialog}
|
||||
onDismiss={() => this.setState(initState(this.props))}
|
||||
|
|
|
@ -138,7 +138,7 @@ export class Explorer extends React.Component<Props, State> {
|
|||
this.state.selectedItemIndex[DataScopeId.SelectedData] = 0;
|
||||
|
||||
this.discardColorContextUpdates = true;
|
||||
this.updateViewerOptions(props.viewerOptions);
|
||||
this.updateViewerOptions({ ...SandDance.VegaDeckGl.util.clone(SandDance.Viewer.defaultViewerOptions), ...props.viewerOptions });
|
||||
}
|
||||
|
||||
public updateViewerOptions(viewerOptions: Partial<SandDance.types.ViewerOptions>) {
|
||||
|
@ -185,7 +185,6 @@ export class Explorer extends React.Component<Props, State> {
|
|||
const newPresenterStyle = SandDance.util.getPresenterStyle(this.viewerOptions as SandDance.types.ViewerOptions);
|
||||
const mergePrenterStyle = { ...this.viewer.presenter.style, ...newPresenterStyle };
|
||||
this.viewer.presenter.style = mergePrenterStyle;
|
||||
this.viewer.options = SandDance.VegaDeckGl.util.deepMerge(this.viewer.options, this.viewerOptions) as SandDance.types.ViewerOptions;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,7 +283,8 @@ export class Explorer extends React.Component<Props, State> {
|
|||
}
|
||||
|
||||
changeChartType(chart: SandDance.types.Chart) {
|
||||
const newState: Partial<State> = { chart };
|
||||
const partialInsight = copyPrefToNewState(this.prefs, chart, '*', '*');
|
||||
const newState: Partial<State> = { chart, ...partialInsight };
|
||||
|
||||
//special case mappings when switching chart type
|
||||
if (this.state.chart === 'scatterplot' && chart === 'barchart') {
|
||||
|
@ -835,7 +835,7 @@ export class Explorer extends React.Component<Props, State> {
|
|||
if (oldInsight.columns.color !== newInsight.columns.color) {
|
||||
return null;
|
||||
}
|
||||
return this.viewer.colorContexts[this.viewer.currentColorContext];
|
||||
return this.viewer.colorContexts && this.viewer.colorContexts[this.viewer.currentColorContext];
|
||||
};
|
||||
//don't allow tabbing to the canvas
|
||||
this.viewer.presenter.getElement(SandDance.VegaDeckGl.PresenterElement.gl).getElementsByTagName('canvas')[0].tabIndex = -1;
|
||||
|
|
|
@ -80,6 +80,11 @@ export const strings = {
|
|||
labelSearchOperator: "Operator",
|
||||
labelSearchValue: "Value",
|
||||
labelSnapshotDescription: "Description",
|
||||
labelTransitionDurations: "Transition durations",
|
||||
labelTransitionCamera: "2D / 3D view",
|
||||
labelTransitionColor: "Color",
|
||||
labelTransitionPosition: "Position",
|
||||
labelTransitionSize: "Size",
|
||||
labelVegaSpecData: "Data reference",
|
||||
labelVegaSpecNotes: "Note: You may need to change the color scheme to make this visible in Vega.",
|
||||
loading: "Loading...",
|
||||
|
@ -133,5 +138,6 @@ export const strings = {
|
|||
{ prefix: "RoleY", label: "Y axis options" },
|
||||
{ prefix: "RoleZ", label: "Z axis options" },
|
||||
{ prefix: "Text", label: "Text options" },
|
||||
{ prefix: "*", label: "Options" }
|
||||
]
|
||||
};
|
||||
|
|
|
@ -75,6 +75,7 @@ export class SandDanceReact extends Component<Props, State> {
|
|||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
this.viewer.options = VegaDeckGl.util.deepMerge(this.viewer.options, this.props.viewerOptions) as types.ViewerOptions;
|
||||
this.view();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,35 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
///<reference path='../node_modules/@msrvida/sanddance/dist/umd/sanddance.d.ts' />
|
||||
///<reference path='vega.d.ts' />
|
||||
|
||||
namespace transition {
|
||||
declare var deck: SandDance.VegaDeckGl.types.DeckBase & SandDance.VegaDeckGl.types.DeckLayerBase;
|
||||
declare var luma: SandDance.VegaDeckGl.types.LumaBase;
|
||||
declare var vega: SandDance.VegaDeckGl.types.VegaBase;
|
||||
|
||||
var view: SandDance.ViewGl_Class;
|
||||
let lastText;
|
||||
let view: SandDance.ViewGl_Class;
|
||||
let lastSpec: Vega.Spec;
|
||||
let viewType: SandDance.VegaDeckGl.types.View = "3d";
|
||||
|
||||
SandDance.use(vega, deck, deck, luma);
|
||||
|
||||
export function update(spec) {
|
||||
view = new SandDance.VegaDeckGl.ViewGl(vega.parse(spec), { presenter: view && view.presenter, getView: ()=> "3d" })
|
||||
export function toggleView() {
|
||||
if (viewType === '3d') {
|
||||
viewType = '2d';
|
||||
} else {
|
||||
viewType = '3d';
|
||||
}
|
||||
update(lastSpec);
|
||||
}
|
||||
|
||||
export function update(spec: Vega.Spec) {
|
||||
view = new SandDance.VegaDeckGl.ViewGl(vega.parse(spec), { presenter: view && view.presenter, getView: () => viewType })
|
||||
.renderer('deck.gl')
|
||||
.initialize(document.querySelector('#split-right'))
|
||||
.run();
|
||||
|
||||
lastText = JSON.stringify(spec);
|
||||
lastSpec = spec;
|
||||
}
|
||||
|
||||
export function getText(textId) {
|
||||
|
@ -31,8 +42,6 @@ namespace transition {
|
|||
try {
|
||||
var spec = JSON.parse(text);
|
||||
|
||||
if (JSON.stringify(spec) === lastText) return;
|
||||
|
||||
splitRight.style.opacity = '1';
|
||||
errorDiv.style.display = 'none';
|
||||
update(spec);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
import * as VegaDeckGl from './vega-deck.gl';
|
||||
import { defaultPresenterStyle } from './vega-deck.gl/defaults';
|
||||
import { defaultPresenterConfig, defaultPresenterStyle } from './vega-deck.gl/defaults';
|
||||
import { desaturate } from './vega-deck.gl/color';
|
||||
import { ViewerOptions } from './types';
|
||||
|
||||
|
@ -19,7 +19,7 @@ export const defaultViewerOptions: ViewerOptions = {
|
|||
const c = desaturate(color, 0.05);
|
||||
c[3] = 171;
|
||||
return c;
|
||||
} //[128, 128, 128, 128]
|
||||
}
|
||||
},
|
||||
language: {
|
||||
headers: {
|
||||
|
@ -40,8 +40,14 @@ export const defaultViewerOptions: ViewerOptions = {
|
|||
reset: 'reset',
|
||||
colorBinCount: 'Color bin count',
|
||||
colorReverse: 'Color reverse',
|
||||
count: 'Count',
|
||||
scatterPointSize: 'Point size',
|
||||
barChartBinSize: 'X Axis Bin size',
|
||||
XBinSize: 'X axis bin size',
|
||||
YBinSize: 'Y axis bin size',
|
||||
XGridSize: 'X grid size',
|
||||
YGridSize: 'Y grid size',
|
||||
InnerPaddingSize: 'Inner padding size',
|
||||
OuterPaddingSize: 'Outer padding size',
|
||||
treeMapMethod: 'Method',
|
||||
facetColumns: 'Facet columns',
|
||||
facetRows: 'Facet rows',
|
||||
|
@ -56,10 +62,8 @@ export const defaultViewerOptions: ViewerOptions = {
|
|||
//console.log(`UnitVisViewer errors: ${errors.join('\n')}`);
|
||||
},
|
||||
transitionDurations: {
|
||||
color: 100,
|
||||
position: 600,
|
||||
scope: 800,
|
||||
size: 600
|
||||
...defaultPresenterConfig.transitionDurations,
|
||||
scope: 600
|
||||
},
|
||||
selectionPolygonZ: -1,
|
||||
tickSize: 10,
|
||||
|
|
|
@ -10,23 +10,11 @@ export function notNice(niceValue: string) {
|
|||
return niceValue.replace(/,/g, '');
|
||||
}
|
||||
|
||||
function columnTypeValue(column: Column, value: string) {
|
||||
switch (column.type) {
|
||||
case 'integer':
|
||||
//BUG? axis of integers may contain floats
|
||||
//return parseInt(notNice(value));
|
||||
case 'number':
|
||||
return parseFloat(notNice(value));
|
||||
case 'string':
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
function tickValue(axis: VegaDeckGl.types.Axis, column: Column, i: number) {
|
||||
function tickValue(axis: VegaDeckGl.types.Axis, i: number) {
|
||||
const tick = axis.tickText[i];
|
||||
let value: any;
|
||||
if (tick) {
|
||||
value = columnTypeValue(column, axis.tickText[i].text);
|
||||
value = axis.tickText[i].value;
|
||||
}
|
||||
return { tick, value };
|
||||
}
|
||||
|
@ -67,7 +55,7 @@ export function selectNone(column: Column, values: string[]) {
|
|||
}
|
||||
|
||||
export function selectExactAxis(axis: VegaDeckGl.types.Axis, column: Column, i: number) {
|
||||
const result = tickValue(axis, column, i);
|
||||
const result = tickValue(axis, i);
|
||||
if (result.tick) {
|
||||
return selectExact(column, result.value);
|
||||
}
|
||||
|
@ -99,8 +87,8 @@ export function selectBetween(column: Column, lowValue: string, highValue: strin
|
|||
}
|
||||
|
||||
export function selectBetweenAxis(axis: VegaDeckGl.types.Axis, column: Column, i: number) {
|
||||
const low = tickValue(axis, column, i);
|
||||
const high = tickValue(axis, column, i + 1);
|
||||
const low = tickValue(axis, i);
|
||||
const high = tickValue(axis, i + 1);
|
||||
return selectBetween(column, low.value, high.value);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,10 @@ export function extractSignalValuesFromView(view: View, spec: Spec) {
|
|||
spec.signals.forEach((signalA: NewSignal) => {
|
||||
//bound to a UI control
|
||||
if (signalA.bind) {
|
||||
result[signalA.name] = view.signal(signalA.name);
|
||||
try {
|
||||
result[signalA.name] = view.signal(signalA.name);
|
||||
}
|
||||
catch (e) { }
|
||||
}
|
||||
});
|
||||
return result;
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
import { Axis } from 'vega-typings';
|
||||
import { Column, SpecViewOptions } from './types';
|
||||
import { SignalNames } from './constants';
|
||||
import { util } from '../vega-deck.gl';
|
||||
|
||||
export function partialAxes(specViewOptions: SpecViewOptions, xColumn: Column, yColumn: Column) {
|
||||
const lineColor = util.colorToString(specViewOptions.colors.axisLine);
|
||||
const axisColor = {
|
||||
"domainColor": lineColor,
|
||||
"tickColor": lineColor,
|
||||
"labelColor": util.colorToString(specViewOptions.colors.axisText)
|
||||
};
|
||||
const bottom: Partial<Axis> = {
|
||||
"orient": "bottom",
|
||||
"labelAlign": "left",
|
||||
"labelAngle": {
|
||||
"signal": SignalNames.TextAngleX
|
||||
},
|
||||
"labelFontSize": {
|
||||
"signal": SignalNames.TextSize
|
||||
},
|
||||
"titleAngle": {
|
||||
"signal": SignalNames.TextAngleX
|
||||
},
|
||||
"titleAlign": "left",
|
||||
"titleFontSize": {
|
||||
"signal": SignalNames.TextTitleSize
|
||||
},
|
||||
"titleColor": util.colorToString(specViewOptions.colors.axisText),
|
||||
"tickSize": specViewOptions.tickSize,
|
||||
...axisColor
|
||||
};
|
||||
if (xColumn.quantitative) {
|
||||
bottom.format = "~r";
|
||||
}
|
||||
const left: Partial<Axis> =
|
||||
{
|
||||
"orient": "left",
|
||||
"labelAlign": "right",
|
||||
"labelAngle": {
|
||||
"signal": SignalNames.TextAngleY
|
||||
},
|
||||
"labelFontSize": {
|
||||
"signal": SignalNames.TextSize
|
||||
},
|
||||
"titleAngle": {
|
||||
"signal": SignalNames.TextAngleY
|
||||
},
|
||||
"titleAlign": "right",
|
||||
"titleFontSize": {
|
||||
"signal": SignalNames.TextTitleSize
|
||||
},
|
||||
"titleColor": util.colorToString(specViewOptions.colors.axisText),
|
||||
"tickSize": specViewOptions.tickSize,
|
||||
...axisColor
|
||||
};
|
||||
if (yColumn.quantitative) {
|
||||
left.format = "~r";
|
||||
}
|
||||
return { left, bottom };
|
||||
}
|
|
@ -28,6 +28,10 @@ export const ScaleNames = {
|
|||
//Signal names
|
||||
export const SignalNames = {
|
||||
PointSize: "Chart_PointSizeSignal",
|
||||
XGridSize: "Chart_XGridSize",
|
||||
YGridSize: "Chart_YGridSize",
|
||||
InnerPadding: "Chart_InnerPadding",
|
||||
OuterPadding: "Chart_OuterPadding",
|
||||
TreeMapMethod: "Chart_TreeMapMethodSignal",
|
||||
ColorBinCount: "RoleColor_BinCountSignal",
|
||||
ColorReverse: "RoleColor_ReverseSignal",
|
||||
|
|
|
@ -1,64 +1,22 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
import { Axis } from 'vega-typings';
|
||||
import {
|
||||
ScaleNames,
|
||||
SignalNames
|
||||
} from '../constants';
|
||||
import { partialAxes } from '../axes';
|
||||
import { ScaleNames } from '../constants';
|
||||
import { SpecColumns, SpecViewOptions } from '../types';
|
||||
import { util } from '../../vega-deck.gl';
|
||||
|
||||
export default function (specViewOptions: SpecViewOptions, columns: SpecColumns) {
|
||||
const lineColor = util.colorToString(specViewOptions.colors.axisLine);
|
||||
const axisColor = {
|
||||
"domainColor": lineColor,
|
||||
"tickColor": lineColor,
|
||||
"labelColor": util.colorToString(specViewOptions.colors.axisText)
|
||||
};
|
||||
const pa = partialAxes(specViewOptions, columns.x, columns.y);
|
||||
const axes: Axis[] = [
|
||||
{
|
||||
"orient": "bottom",
|
||||
"labelAngle": {
|
||||
"signal": SignalNames.TextAngleX
|
||||
},
|
||||
"labelAlign": "left",
|
||||
"labelFontSize": {
|
||||
"signal": SignalNames.TextSize
|
||||
},
|
||||
"scale": ScaleNames.X,
|
||||
"title": columns.x.name,
|
||||
"titleAngle": {
|
||||
"signal": SignalNames.TextAngleX
|
||||
},
|
||||
"titleAlign": "left",
|
||||
"titleFontSize": {
|
||||
"signal": SignalNames.TextTitleSize
|
||||
},
|
||||
"titleColor": util.colorToString(specViewOptions.colors.axisText),
|
||||
"tickSize": specViewOptions.tickSize,
|
||||
...axisColor
|
||||
...pa.bottom as Axis
|
||||
},
|
||||
{
|
||||
"orient": "left",
|
||||
"labelAlign": "right",
|
||||
"labelAngle": {
|
||||
"signal": SignalNames.TextAngleY
|
||||
},
|
||||
"labelFontSize": {
|
||||
"signal": SignalNames.TextSize
|
||||
},
|
||||
"scale": ScaleNames.Y,
|
||||
"title": columns.y.name,
|
||||
"titleAngle": {
|
||||
"signal": SignalNames.TextAngleY
|
||||
},
|
||||
"titleAlign": "right",
|
||||
"titleFontSize": {
|
||||
"signal": SignalNames.TextTitleSize
|
||||
},
|
||||
"titleColor": util.colorToString(specViewOptions.colors.axisText),
|
||||
"tickSize": specViewOptions.tickSize,
|
||||
...axisColor
|
||||
...pa.left as Axis
|
||||
}
|
||||
];
|
||||
return axes;
|
||||
|
|
|
@ -1,53 +1,21 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
import { Axis } from 'vega-typings';
|
||||
import {
|
||||
ScaleNames,
|
||||
SignalNames
|
||||
} from '../constants';
|
||||
import { partialAxes } from '../axes';
|
||||
import { ScaleNames } from '../constants';
|
||||
import { SpecColumns, SpecViewOptions } from '../types';
|
||||
import { util } from '../../vega-deck.gl';
|
||||
|
||||
export default function (specViewOptions: SpecViewOptions, columns: SpecColumns) {
|
||||
const lineColor = util.colorToString(specViewOptions.colors.axisLine);
|
||||
const axisColor = {
|
||||
"domainColor": lineColor,
|
||||
"tickColor": lineColor,
|
||||
"labelColor": util.colorToString(specViewOptions.colors.axisText)
|
||||
};
|
||||
const pa = partialAxes(specViewOptions, columns.x, columns.y);
|
||||
const axes: Axis[] = [
|
||||
{
|
||||
"orient": "bottom",
|
||||
"labelAngle": {
|
||||
"signal": SignalNames.TextAngleX
|
||||
},
|
||||
"labelAlign": "left",
|
||||
"labelFontSize": {
|
||||
"signal": SignalNames.TextSize
|
||||
},
|
||||
"scale": ScaleNames.X,
|
||||
"title": columns.x.name,
|
||||
"titleAngle": {
|
||||
"signal": SignalNames.TextAngleX
|
||||
},
|
||||
"titleAlign": "left",
|
||||
"titleFontSize": {
|
||||
"signal": SignalNames.TextTitleSize
|
||||
},
|
||||
"titleColor": util.colorToString(specViewOptions.colors.axisText),
|
||||
"tickSize": specViewOptions.tickSize,
|
||||
...axisColor
|
||||
...pa.bottom as Axis
|
||||
},
|
||||
{
|
||||
"orient": "left",
|
||||
"labelAlign": "right",
|
||||
"labelAngle": {
|
||||
"signal": SignalNames.TextAngleY
|
||||
},
|
||||
"labelFontSize": {
|
||||
"signal": SignalNames.TextSize
|
||||
},
|
||||
"scale": "yscalelabel",
|
||||
"title": specViewOptions.language.count,
|
||||
"encode": {
|
||||
"labels": {
|
||||
"update": {
|
||||
|
@ -57,17 +25,7 @@ export default function (specViewOptions: SpecViewOptions, columns: SpecColumns)
|
|||
}
|
||||
}
|
||||
},
|
||||
"title": "Count",
|
||||
"titleAngle": {
|
||||
"signal": SignalNames.TextAngleY
|
||||
},
|
||||
"titleAlign": "right",
|
||||
"titleFontSize": {
|
||||
"signal": SignalNames.TextTitleSize
|
||||
},
|
||||
"titleColor": util.colorToString(specViewOptions.colors.axisText),
|
||||
"tickSize": specViewOptions.tickSize,
|
||||
...axisColor
|
||||
...pa.left as Axis
|
||||
}
|
||||
];
|
||||
return axes;
|
||||
|
|
|
@ -19,7 +19,7 @@ export default function (insight: Insight, columns: SpecColumns, specViewOptions
|
|||
"name": SignalNames.XBins,
|
||||
"value": 7,
|
||||
"bind": {
|
||||
"name": specViewOptions.language.barChartBinSize,
|
||||
"name": specViewOptions.language.XBinSize,
|
||||
"input": "range",
|
||||
"min": 1,
|
||||
"max": 20,
|
||||
|
|
|
@ -1,25 +1,27 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
import { Axis } from 'vega-typings';
|
||||
import { partialAxes } from '../axes';
|
||||
import { SpecColumns, SpecViewOptions } from '../types';
|
||||
|
||||
export default function (specViewOptions: SpecViewOptions, columns: SpecColumns) {
|
||||
const pa = partialAxes(specViewOptions, columns.x, columns.y);
|
||||
const axes: Axis[] = [
|
||||
{
|
||||
"scale": "xband",
|
||||
"title": columns.x.name,
|
||||
"bandPosition": 0.5,
|
||||
"grid": true,
|
||||
"domain": false,
|
||||
"orient": "bottom",
|
||||
"tickCount": 5,
|
||||
"title": columns.x.name
|
||||
"labelFlush": true,
|
||||
...pa.bottom as Axis
|
||||
},
|
||||
{
|
||||
"scale": "yband",
|
||||
"title": columns.y.name,
|
||||
"bandPosition": columns.y.quantitative ? 0 : 0.5,
|
||||
"grid": true,
|
||||
"domain": false,
|
||||
"orient": "left",
|
||||
"titlePadding": 5,
|
||||
"title": columns.y.name
|
||||
"labelFlush": true,
|
||||
...pa.left as Axis
|
||||
}
|
||||
];
|
||||
return axes;
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
import { allTruthy } from '../../array';
|
||||
import { Data } from 'vega-typings';
|
||||
import {
|
||||
Column,
|
||||
Insight,
|
||||
SpecColumns,
|
||||
SpecViewOptions
|
||||
} from '../types';
|
||||
import { Data, StackTransform, Transforms } from 'vega-typings';
|
||||
import { DataNames, SignalNames } from '../constants';
|
||||
import { Insight, SpecColumns, SpecViewOptions } from '../types';
|
||||
import { topLookup } from '../top';
|
||||
|
||||
export default function (insight: Insight, columns: SpecColumns, specViewOptions: SpecViewOptions) {
|
||||
|
@ -12,7 +17,7 @@ export default function (insight: Insight, columns: SpecColumns, specViewOptions
|
|||
[
|
||||
{
|
||||
"name": DataNames.Main,
|
||||
"transform": [
|
||||
"transform": allTruthy<Transforms>([
|
||||
{
|
||||
"type": "extent",
|
||||
"field": columns.x.name,
|
||||
|
@ -23,7 +28,7 @@ export default function (insight: Insight, columns: SpecColumns, specViewOptions
|
|||
"field": columns.y.name,
|
||||
"signal": "lat_extent"
|
||||
},
|
||||
{
|
||||
columns.x.quantitative && {
|
||||
"type": "bin",
|
||||
"field": columns.x.name,
|
||||
"extent": {
|
||||
|
@ -32,17 +37,19 @@ export default function (insight: Insight, columns: SpecColumns, specViewOptions
|
|||
"maxbins": {
|
||||
"signal": SignalNames.XBins
|
||||
},
|
||||
"nice": false,
|
||||
"as": [
|
||||
"long0",
|
||||
"long1"
|
||||
]
|
||||
},
|
||||
{
|
||||
columns.y.quantitative && {
|
||||
"type": "bin",
|
||||
"field": columns.y.name,
|
||||
"extent": {
|
||||
"signal": "lat_extent"
|
||||
},
|
||||
"nice": false,
|
||||
"maxbins": {
|
||||
"signal": SignalNames.YBins
|
||||
},
|
||||
|
@ -51,54 +58,16 @@ export default function (insight: Insight, columns: SpecColumns, specViewOptions
|
|||
"lat1"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "summary",
|
||||
"source": DataNames.Main,
|
||||
"transform": [
|
||||
{
|
||||
"type": "nest",
|
||||
"keys": [
|
||||
"lat0",
|
||||
"long0"
|
||||
]
|
||||
}]
|
||||
},
|
||||
{
|
||||
"name": "aggregated",
|
||||
"source": DataNames.Main,
|
||||
"transform": [
|
||||
{
|
||||
"type": "aggregate",
|
||||
"groupby": [
|
||||
"lat0",
|
||||
"long0"
|
||||
],
|
||||
|
||||
"ops": [
|
||||
"count"
|
||||
]
|
||||
}]
|
||||
},
|
||||
])
|
||||
}
|
||||
],
|
||||
categoricalColor && topLookup(columns.color, specViewOptions.maxLegends),
|
||||
[
|
||||
{
|
||||
"name": "stackedgroup",
|
||||
"source": "summary",
|
||||
"source": categoricalColor ? DataNames.Legend : DataNames.Main,
|
||||
"transform": [
|
||||
{
|
||||
"type": "stack",
|
||||
"groupby": [
|
||||
"lat0",
|
||||
"long0"
|
||||
],
|
||||
"sort": {
|
||||
"field": columns.sort.name
|
||||
},
|
||||
"as": [
|
||||
"s1",
|
||||
"s2"
|
||||
]
|
||||
},
|
||||
stackTransform(columns.sort, columns.x, columns.y),
|
||||
{
|
||||
"type": "extent",
|
||||
"signal": "xtent",
|
||||
|
@ -116,12 +85,12 @@ export default function (insight: Insight, columns: SpecColumns, specViewOptions
|
|||
},
|
||||
{
|
||||
"type": "formula",
|
||||
"expr": "datum.s1 % mywidth",
|
||||
"expr": `datum.s1 % ${SignalNames.XGridSize}`,
|
||||
"as": "column"
|
||||
},
|
||||
{
|
||||
"type": "formula",
|
||||
"expr": "floor((datum.s1 % columns)/ mywidth)",
|
||||
"expr": `floor((datum.s1 % columns)/ ${SignalNames.XGridSize})`,
|
||||
"as": "depth"
|
||||
},
|
||||
{
|
||||
|
@ -131,8 +100,27 @@ export default function (insight: Insight, columns: SpecColumns, specViewOptions
|
|||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
categoricalColor && topLookup(columns.color, specViewOptions.maxLegends),
|
||||
]
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
function stackTransform(sortColumn: Column, xColumn: Column, yColumn: Column) {
|
||||
const st: StackTransform = {
|
||||
"type": "stack",
|
||||
"groupby": [
|
||||
yColumn.quantitative ? "lat0" : yColumn.name,
|
||||
xColumn.quantitative ? "long0" : xColumn.name
|
||||
],
|
||||
"as": [
|
||||
"s1",
|
||||
"s2"
|
||||
]
|
||||
};
|
||||
if (sortColumn) {
|
||||
st.sort = {
|
||||
"field": sortColumn.name
|
||||
};
|
||||
}
|
||||
return st;
|
||||
}
|
|
@ -5,13 +5,7 @@ import getData from './data';
|
|||
import getMarks from './marks';
|
||||
import getScales from './scales';
|
||||
import getSignals from './signals';
|
||||
import { DataNames, SignalNames } from '../constants';
|
||||
import {
|
||||
checkForFacetErrors,
|
||||
facetMarks,
|
||||
facetSize,
|
||||
layout
|
||||
} from '../facet';
|
||||
import { checkForFacetErrors, facetSize, layout } from '../facet';
|
||||
import {
|
||||
Insight,
|
||||
SpecCapabilities,
|
||||
|
@ -19,7 +13,8 @@ import {
|
|||
SpecViewOptions
|
||||
} from '../types';
|
||||
import { legend } from '../legends';
|
||||
import { Mark, Spec } from 'vega-typings';
|
||||
import { SignalNames } from '../constants';
|
||||
import { Spec } from 'vega-typings';
|
||||
import { SpecCreator, SpecResult } from '../interfaces';
|
||||
|
||||
export const stacks: SpecCreator = (insight: Insight, columns: SpecColumns, specViewOptions: SpecViewOptions): SpecResult => {
|
||||
|
@ -27,6 +22,7 @@ export const stacks: SpecCreator = (insight: Insight, columns: SpecColumns, spec
|
|||
|
||||
if (!columns.uid) errors.push(`Must set a field for id`);
|
||||
if (!columns.x) errors.push(`Must set a field for x axis`);
|
||||
if (!columns.y) errors.push(`Must set a field for y axis`);
|
||||
checkForFacetErrors(insight.facets, errors);
|
||||
|
||||
const specCapabilities: SpecCapabilities = {
|
||||
|
@ -54,13 +50,8 @@ export const stacks: SpecCreator = (insight: Insight, columns: SpecColumns, spec
|
|||
{
|
||||
role: 'sort',
|
||||
allowNone: true
|
||||
},
|
||||
{
|
||||
role: 'facet',
|
||||
allowNone: true
|
||||
}
|
||||
],
|
||||
signals: ['mywidth', 'mydepth']
|
||||
]
|
||||
};
|
||||
|
||||
if (errors.length) {
|
||||
|
@ -90,7 +81,6 @@ export const stacks: SpecCreator = (insight: Insight, columns: SpecColumns, spec
|
|||
"$schema": "https://vega.github.io/schema/vega/v3.json",
|
||||
"height": size.height,
|
||||
"width": size.width,
|
||||
"padding": 5,
|
||||
signals: getSignals(insight, columns, specViewOptions),
|
||||
data: getData(insight, columns, specViewOptions),
|
||||
scales: getScales(columns, insight),
|
||||
|
|
|
@ -16,7 +16,7 @@ export default function (columns: SpecColumns, specViewOptions: SpecViewOptions)
|
|||
"update": {
|
||||
"x": {
|
||||
"scale": "xband",
|
||||
"field": "long0",
|
||||
"field": columns.x.quantitative ? "long0" : columns.x.name,
|
||||
"offset": {
|
||||
"scale": "xinternalscale",
|
||||
"field": "column"
|
||||
|
@ -24,7 +24,7 @@ export default function (columns: SpecColumns, specViewOptions: SpecViewOptions)
|
|||
},
|
||||
"y": {
|
||||
"scale": "yband",
|
||||
"field": "lat0",
|
||||
"field": columns.y.quantitative ? "lat0" : columns.y.name,
|
||||
"offset": {
|
||||
"scale": "yinternalscale",
|
||||
"field": "depth"
|
||||
|
@ -41,9 +41,6 @@ export default function (columns: SpecColumns, specViewOptions: SpecViewOptions)
|
|||
"width": {
|
||||
"signal": "actsize"
|
||||
},
|
||||
"opacity": {
|
||||
"value": 0.1
|
||||
},
|
||||
"height": {
|
||||
"signal": "actsize"
|
||||
},
|
||||
|
|
|
@ -18,7 +18,7 @@ export default function (columns: SpecColumns, insight: Insight) {
|
|||
"type": "band",
|
||||
"domain": {
|
||||
"data": DataNames.Main,
|
||||
"field": "long0",
|
||||
"field": columns.x.quantitative ? "long0" : columns.x.name,
|
||||
"sort": true
|
||||
},
|
||||
"range": [
|
||||
|
@ -27,7 +27,7 @@ export default function (columns: SpecColumns, insight: Insight) {
|
|||
"signal": "width"
|
||||
}
|
||||
],
|
||||
"padding": 0.05,
|
||||
"padding": { "signal": SignalNames.OuterPadding },
|
||||
"round": true
|
||||
},
|
||||
{
|
||||
|
@ -36,11 +36,11 @@ export default function (columns: SpecColumns, insight: Insight) {
|
|||
"reverse": true,
|
||||
"domain": {
|
||||
"data": DataNames.Main,
|
||||
"field": "lat0",
|
||||
"field": columns.y.quantitative ? "lat0" : columns.y.name,
|
||||
"sort": true
|
||||
},
|
||||
"range": "height",
|
||||
"padding": 0.05,
|
||||
"padding": { "signal": SignalNames.OuterPadding },
|
||||
"round": true
|
||||
},
|
||||
{
|
||||
|
@ -56,11 +56,11 @@ export default function (columns: SpecColumns, insight: Insight) {
|
|||
"range": [
|
||||
0,
|
||||
{
|
||||
"signal": "height"
|
||||
"signal": "countheight"
|
||||
}
|
||||
],
|
||||
"padding": 0.1,
|
||||
"round": true
|
||||
"padding": { "signal": SignalNames.InnerPadding },
|
||||
"round": false
|
||||
},
|
||||
{
|
||||
"name": "xinternalscale",
|
||||
|
@ -68,11 +68,11 @@ export default function (columns: SpecColumns, insight: Insight) {
|
|||
"range": [
|
||||
0,
|
||||
{
|
||||
"signal": "xbandw"
|
||||
"signal": "xbandsignal"
|
||||
}
|
||||
],
|
||||
"padding": {
|
||||
"signal": "x_padding"
|
||||
"signal": SignalNames.InnerPadding
|
||||
},
|
||||
"domain": {
|
||||
"data": "stackedgroup",
|
||||
|
@ -90,52 +90,13 @@ export default function (columns: SpecColumns, insight: Insight) {
|
|||
}
|
||||
],
|
||||
"padding": {
|
||||
"signal": "x_padding"
|
||||
"signal": SignalNames.InnerPadding
|
||||
},
|
||||
"domain": {
|
||||
"data": "stackedgroup",
|
||||
"field": "depth",
|
||||
"sort": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x",
|
||||
"type": "linear",
|
||||
"round": true,
|
||||
"nice": true,
|
||||
"zero": false,
|
||||
"domain": {
|
||||
"data": DataNames.Main,
|
||||
"field": columns.x.name
|
||||
},
|
||||
"range": "width"
|
||||
},
|
||||
{
|
||||
"name": "y",
|
||||
"type": "linear",
|
||||
"round": true,
|
||||
"nice": true,
|
||||
"zero": false,
|
||||
"domain": {
|
||||
"data": DataNames.Main,
|
||||
"field": columns.y.name
|
||||
},
|
||||
"range": "height"
|
||||
},
|
||||
{
|
||||
"name": "z",
|
||||
"type": "linear",
|
||||
"round": true,
|
||||
"nice": true,
|
||||
"zero": false,
|
||||
"domain": {
|
||||
"data": "stackedgroup",
|
||||
"field": "s1"
|
||||
},
|
||||
"range": [
|
||||
0,
|
||||
"height"
|
||||
]
|
||||
}
|
||||
];
|
||||
if (columns.color) {
|
||||
|
|
|
@ -1,111 +1,119 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT license.
|
||||
import { allTruthy } from '../../array';
|
||||
import { colorBinCountSignal, textSignals } from '../signals';
|
||||
import { colorBinCountSignal, colorReverseSignal, textSignals } from '../signals';
|
||||
import { facetSignals } from '../facet';
|
||||
import { Insight, SpecViewOptions, SpecColumns } from '../types';
|
||||
import { ScaleNames, SignalNames } from '../constants';
|
||||
import { Insight, SpecColumns, SpecViewOptions } from '../types';
|
||||
import { Signal } from 'vega-typings';
|
||||
import { SignalNames } from '../constants';
|
||||
|
||||
export default function (insight: Insight, columns: SpecColumns, specViewOptions: SpecViewOptions) {
|
||||
const signals = allTruthy<Signal>(
|
||||
textSignals(specViewOptions),
|
||||
[
|
||||
columns.x.quantitative && {
|
||||
"name": SignalNames.XBins,
|
||||
"value": 20,
|
||||
colorBinCountSignal(specViewOptions),
|
||||
colorReverseSignal(specViewOptions),
|
||||
{
|
||||
"name": SignalNames.XGridSize,
|
||||
"value": 3,
|
||||
"bind": {
|
||||
"name": specViewOptions.language.barChartBinSize,
|
||||
"name": specViewOptions.language.XGridSize,
|
||||
"input": "range",
|
||||
"min": 1,
|
||||
"max": 50,
|
||||
"max": 20,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": SignalNames.YGridSize,
|
||||
"value": 3,
|
||||
"bind": {
|
||||
"name": specViewOptions.language.YGridSize,
|
||||
"input": "range",
|
||||
"min": 1,
|
||||
"max": 20,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
columns.x.quantitative && {
|
||||
"name": SignalNames.XBins,
|
||||
"value": 30,
|
||||
"bind": {
|
||||
"name": specViewOptions.language.XBinSize,
|
||||
"input": "range",
|
||||
"min": 1,
|
||||
"max": 60,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
columns.y.quantitative && {
|
||||
"name": SignalNames.YBins,
|
||||
"value": 20,
|
||||
"value": 30,
|
||||
"bind": {
|
||||
"name": specViewOptions.language.barChartBinSize,
|
||||
"name": specViewOptions.language.YBinSize,
|
||||
"input": "range",
|
||||
"min": 1,
|
||||
"max": 50,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
colorBinCountSignal(specViewOptions),
|
||||
{
|
||||
"name": "mywidth",
|
||||
"value": 3,
|
||||
"bind": {
|
||||
"name": "TODO width",
|
||||
"input": "range",
|
||||
"min": 1,
|
||||
"max": 20,
|
||||
"max": 60,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mydepth",
|
||||
"value": 3,
|
||||
"bind": {
|
||||
"name": "TODO depth",
|
||||
"input": "range",
|
||||
"min": 1,
|
||||
"max": 20,
|
||||
"step": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x_padding",
|
||||
"name": SignalNames.InnerPadding,
|
||||
"value": 0.1,
|
||||
"bind": {
|
||||
"name": "TODO x padding",
|
||||
"name": specViewOptions.language.InnerPaddingSize,
|
||||
"input": "range",
|
||||
"min": 0.1,
|
||||
"max": 1,
|
||||
"max": 0.6,
|
||||
"step": 0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x_out_padding",
|
||||
"value": 0.1,
|
||||
"name": SignalNames.OuterPadding,
|
||||
"value": 0.2,
|
||||
"bind": {
|
||||
"name": "TODO x out padding",
|
||||
"name": specViewOptions.language.OuterPaddingSize,
|
||||
"input": "range",
|
||||
"min": 0.1,
|
||||
"max": 1,
|
||||
"max": 0.6,
|
||||
"step": 0.1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "actheight",
|
||||
"update": "actsize*rowxtent[1] * (1+ x_padding)"
|
||||
},
|
||||
|
||||
{
|
||||
"name": "columns",
|
||||
"update": "mywidth*mydepth"
|
||||
"update": `${SignalNames.XGridSize}*${SignalNames.YGridSize}`
|
||||
},
|
||||
{
|
||||
"name": "xbandw",
|
||||
"update": `width/(${SignalNames.XBins}+x_out_padding)`
|
||||
"name": "xbandw2",
|
||||
"update": "bandwidth('xband')"
|
||||
},
|
||||
{
|
||||
"name": "xbandsize",
|
||||
"update": "(xbandw / (mywidth + x_padding))*(1-x_padding)"
|
||||
"update": `(xbandw2 / (${SignalNames.XGridSize} + ${SignalNames.InnerPadding}))*(1-${SignalNames.InnerPadding})`
|
||||
},
|
||||
{
|
||||
"name": "ybandw",
|
||||
"update": `height/(${SignalNames.YBins}+x_out_padding)`
|
||||
"update": `height/((${columns.y.quantitative ? SignalNames.YBins : columns.y.stats.distinctValueCount}) * (1 + ${SignalNames.OuterPadding}))`
|
||||
},
|
||||
{
|
||||
"name": "ybandsize",
|
||||
"update": "(ybandw / (mydepth + x_padding))*(1-x_padding)"
|
||||
"update": `(ybandw / (${SignalNames.YGridSize} + ${SignalNames.InnerPadding}))*(1-${SignalNames.InnerPadding})`
|
||||
},
|
||||
{
|
||||
"name": "actsize",
|
||||
"update": "min(xbandsize,ybandsize)"
|
||||
},
|
||||
{
|
||||
"name": "xbandsignal",
|
||||
"update": "bandwidth('xband')"
|
||||
},
|
||||
{
|
||||
"name": "ybandsignal",
|
||||
"update": "bandwidth('yband')"
|
||||
},
|
||||
{
|
||||
"name": "countheight",
|
||||
"update": "rowxtent[1]*actsize"
|
||||
}
|
||||
],
|
||||
insight.columns.facet && facetSignals(insight.facets, specViewOptions)
|
||||
|
|
|
@ -191,6 +191,11 @@ export interface SpecColorSettings {
|
|||
*/
|
||||
export interface SpecLanguage {
|
||||
|
||||
/**
|
||||
* Label for a count axis.
|
||||
*/
|
||||
count: string;
|
||||
|
||||
/**
|
||||
* Label for treemap method dropdown.
|
||||
*/
|
||||
|
@ -202,9 +207,34 @@ export interface SpecLanguage {
|
|||
scatterPointSize: string;
|
||||
|
||||
/**
|
||||
* Label for bar chart bin size slider.
|
||||
* Label for bar x axis bin size slider.
|
||||
*/
|
||||
barChartBinSize: string;
|
||||
XBinSize: string;
|
||||
|
||||
/**
|
||||
* Label for bar y axis bin size slider.
|
||||
*/
|
||||
YBinSize: string;
|
||||
|
||||
/**
|
||||
* Label for bar x grid size slider.
|
||||
*/
|
||||
XGridSize: string;
|
||||
|
||||
/**
|
||||
* Label for bar y grid size slider.
|
||||
*/
|
||||
YGridSize: string;
|
||||
|
||||
/**
|
||||
* Label for bar inner padding size slider.
|
||||
*/
|
||||
InnerPaddingSize: string;
|
||||
|
||||
/**
|
||||
* Label for bar outer padding size slider.
|
||||
*/
|
||||
OuterPaddingSize: string;
|
||||
|
||||
/**
|
||||
* Label for the color bin count slider.
|
||||
|
@ -245,11 +275,6 @@ export interface SpecLanguage {
|
|||
* Label for z scale proportion slider.
|
||||
*/
|
||||
zScaleProportion: string;
|
||||
|
||||
// errorRequiredX: string;
|
||||
// errorRequiredY: string;
|
||||
// errorRequiredSize: string;
|
||||
|
||||
}
|
||||
|
||||
export interface SignalValues {
|
||||
|
|
|
@ -11,10 +11,14 @@ export interface StyledLine extends LineLayerDatum {
|
|||
strokeWidth?: number;
|
||||
}
|
||||
|
||||
export interface TickText extends TextLayerDatum {
|
||||
value: number | string;
|
||||
}
|
||||
|
||||
export interface Axis {
|
||||
domain: StyledLine;
|
||||
ticks: StyledLine[];
|
||||
tickText: TextLayerDatum[];
|
||||
tickText: TickText[];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
SceneTextAlign,
|
||||
SceneTextBaseline
|
||||
} from 'vega-typings';
|
||||
import { Stage } from '../interfaces';
|
||||
import { Stage, TickText } from '../interfaces';
|
||||
|
||||
const markStager: MarkStager = (options: MarkStagerOptions, stage: Stage, scene: Scene, x: number, y: number, groupType: GroupType) => {
|
||||
|
||||
|
@ -37,7 +37,9 @@ const markStager: MarkStager = (options: MarkStagerOptions, stage: Stage, scene:
|
|||
};
|
||||
|
||||
if (item.mark.role === "axis-label") {
|
||||
options.currAxis.tickText.push(textItem);
|
||||
const tickText = textItem as TickText;
|
||||
tickText.value = item.datum['value'];
|
||||
options.currAxis.tickText.push(tickText);
|
||||
} else if (options.currFacetRect && !options.currFacetRect.facetTitle) {
|
||||
options.currFacetRect.facetTitle = textItem;
|
||||
} else {
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
Scene3d,
|
||||
Stage,
|
||||
View
|
||||
} from './interfaces';
|
||||
} from './interfaces';
|
||||
import { CubeLayer_Class, CubeLayerInterpolatedProps } from './cube-layer/cube-layer';
|
||||
import { DeckProps } from '@deck.gl/core/lib/deck';
|
||||
import { easeExpInOut } from 'd3-ease';
|
||||
|
@ -30,6 +30,13 @@ import { PresenterElement } from './enums';
|
|||
import { sceneToStage } from './stagers';
|
||||
import { targetViewState, viewStateProps } from './viewState';
|
||||
|
||||
interface IBounds {
|
||||
view: View;
|
||||
height: number;
|
||||
width: number;
|
||||
cubeCount: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class which presents a Stage of chart data using Deck.gl to render.
|
||||
*/
|
||||
|
@ -71,7 +78,7 @@ export class Presenter {
|
|||
}
|
||||
|
||||
private queuedAnimationOptions: QueuedAnimationOptions;
|
||||
private _last: { view: View, height: number, width: number, cubeCount: number, stage: Stage, homeViewState: any };
|
||||
private _last: IBounds & { stage: Stage };
|
||||
private _showGuides: boolean;
|
||||
|
||||
/**
|
||||
|
@ -82,7 +89,7 @@ export class Presenter {
|
|||
constructor(public el: HTMLElement, style?: PresenterStyle) {
|
||||
this.style = deepMerge<PresenterStyle>(defaultPresenterStyle, style);
|
||||
initializePanel(this);
|
||||
this._last = { view: null, height: null, width: null, cubeCount: null, stage: null, homeViewState: null };
|
||||
this._last = { view: null, height: null, width: null, cubeCount: null, stage: null };
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -212,21 +219,35 @@ export class Presenter {
|
|||
this.setDeckProps(newStage, this._last.height, this._last.width, this._last.cubeCount, modifyConfig);
|
||||
}
|
||||
|
||||
private isNewBounds(view: View, height: number, width: number, cubeCount: number) {
|
||||
const lastBounds: IBounds = this.lastBounds();
|
||||
for (let prop in lastBounds) {
|
||||
if (lastBounds[prop] === null) return true;
|
||||
}
|
||||
const newBounds: IBounds = { cubeCount, height, view, width };
|
||||
for (let prop in lastBounds) {
|
||||
if (lastBounds[prop] !== newBounds[prop]) return true;
|
||||
}
|
||||
}
|
||||
|
||||
private lastBounds(): IBounds {
|
||||
const { cubeCount, height, view, width } = this._last;
|
||||
return { cubeCount, height, view, width };
|
||||
}
|
||||
|
||||
private setDeckProps(stage: Stage, height: number, width: number, cubeCount: number, modifyConfig: PresenterConfig) {
|
||||
const config = deepMerge<PresenterConfig>(defaultPresenterConfig, modifyConfig);
|
||||
const switchView = this._last.view && this._last.view !== stage.view;
|
||||
const newBounds = this.isNewBounds(stage.view, height, width, cubeCount);
|
||||
let lightSettings = this.style.lightSettings[stage.view];
|
||||
let lightingMix = stage.view === '3d' ? 1.0 : 0.0;
|
||||
let linearInterpolator: LinearInterpolator_Class<CubeLayerInterpolatedProps>;
|
||||
//choose the current OrbitView viewstate if possible
|
||||
let homeViewState = this._last.homeViewState;
|
||||
let viewState = (this.deckgl.viewState && Object.keys(this.deckgl.viewState).length && this.deckgl.viewState.OrbitView)
|
||||
//otherwise use the initial viewstate if any
|
||||
|| this.deckgl.props.viewState;
|
||||
|
||||
if (!viewState || switchView || config.shouldViewstateTransition && config.shouldViewstateTransition()) {
|
||||
if (!viewState || newBounds || config.shouldViewstateTransition && config.shouldViewstateTransition()) {
|
||||
viewState = targetViewState(height, width, stage.view);
|
||||
homeViewState = clone(viewState);
|
||||
const oldCubeLayer = getCubeLayer(this.deckgl.props) as CubeLayer_Class;
|
||||
if (oldCubeLayer) {
|
||||
linearInterpolator = new LinearInterpolator(viewStateProps);
|
||||
|
@ -257,8 +278,7 @@ export class Presenter {
|
|||
height,
|
||||
width,
|
||||
stage: stage,
|
||||
view: stage.view,
|
||||
homeViewState
|
||||
view: stage.view
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -266,7 +286,7 @@ export class Presenter {
|
|||
* Home the camera to the last initial position.
|
||||
*/
|
||||
homeCamera() {
|
||||
const viewState = clone(this._last.homeViewState);
|
||||
const viewState = targetViewState(this._last.height, this._last.width, this._last.view) as any;
|
||||
viewState.transitionDuration = defaultPresenterConfig.transitionDurations.view;
|
||||
viewState.transitionEasing = easeExpInOut;
|
||||
viewState.transitionInterpolator = new LinearInterpolator(viewStateProps);
|
||||
|
|
|
@ -50,6 +50,11 @@ let didRegisterColorSchemes = false;
|
|||
*/
|
||||
export class Viewer {
|
||||
|
||||
/**
|
||||
* Default Viewer options.
|
||||
*/
|
||||
static defaultViewerOptions = defaultViewerOptions;
|
||||
|
||||
/**
|
||||
* Behavior specified by the visualization type.
|
||||
*/
|
||||
|
@ -121,7 +126,7 @@ export class Viewer {
|
|||
this.currentColorContext = ~~remap;
|
||||
this.renderSameLayout();
|
||||
},
|
||||
() => this.insight && !!this.insight.columns.color && this.colorContexts.length > 1
|
||||
() => this.insight && !!this.insight.columns.color && this.colorContexts && this.colorContexts.length > 1
|
||||
);
|
||||
this.insight = {} as Insight;
|
||||
this._signalValues = {};
|
||||
|
@ -400,7 +405,6 @@ export class Viewer {
|
|||
}
|
||||
this._specColumns = getSpecColumns(insight, this._dataScope.getColumns(options.columnTypes));
|
||||
const map = assignOrdinals(this._specColumns, data, options.ordinalMap);
|
||||
const shouldViewstateTransition = this.shouldViewstateTransition(insight, this.insight);
|
||||
this.insight = VegaDeckGl.util.clone(insight);
|
||||
this._shouldSaveColorContext = () => !options.initialColorContext;
|
||||
const colorContext = options.initialColorContext || {
|
||||
|
@ -436,7 +440,7 @@ export class Viewer {
|
|||
this.applyLegendColorContext(colorContext);
|
||||
}
|
||||
},
|
||||
shouldViewstateTransition: () => shouldViewstateTransition
|
||||
shouldViewstateTransition: () => this.shouldViewstateTransition(insight, this.insight)
|
||||
},
|
||||
this.getView(insight.view)
|
||||
);
|
||||
|
|
Загрузка…
Ссылка в новой задаче