* 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:
Dan Marshall 2019-05-01 16:03:35 -07:00 коммит произвёл GitHub
Родитель a94e769afb
Коммит 6e903d9887
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
29 изменённых файлов: 422 добавлений и 351 удалений

Просмотреть файл

@ -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)
);