* Initial implementation of CollapsiblePanel

* Add margins to group items

* Update text object attributes panel

* Update textbox object attributes panel

* Update rect object attributes panel

* Update chart object attributes panel

* Update symbol object attributes panel

* Update axes and plot segments objects attributes panel

* Update legends objects attributes panel

* Update icon & guide coordiantor objects attributes panel

* Update image object attributes panel

* Update line object attributes panel

* Update curve plot segment object attributes panel

* Fix jitter layout icon size

* Add delimiter between groups

* Update object name header of attribute panel

* Add polar-grid icon for Fluent UI icons

* Fix data binding menu for "Group by..." button

* Change border color

* Change border for group header

* Fix inputNumber layout

* Revert "Update chart object attributes panel"

This reverts commit 9bdb9e3fcb.

* Configure Rotation input

Co-authored-by: Ilfat Galiev <v-igaliev@microsoft.com>
This commit is contained in:
Ilfat Galiev 2021-08-04 15:40:13 +03:00 коммит произвёл GitHub
Родитель 79abf0dfc9
Коммит 4b8c318c43
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
30 изменённых файлов: 1705 добавлений и 1145 удалений

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

@ -514,7 +514,7 @@
.editable-text-view {
$font-size: 14px;
$padding: 0;
$height: 24px;
$height: 32px;
display: flex;
flex-direction: row;
@ -540,7 +540,7 @@
transition: border-color $transition-default;
border-bottom: 2px solid transparent;
border-bottom: 2px solid $gray-210;
&:hover {
border-bottom: 2px solid $gray-210;

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

@ -18,12 +18,12 @@
font-size: 14px;
line-height: 24px;
padding-bottom: 4px;
margin-top: 1px;
margin-bottom: 0px;
border-bottom: 1px solid $gray-180;
border-bottom: 0px solid $gray-180;
color: $black;
.svg-image-icon {
padding: 2px;
width: 20px;
height: 20px;
vertical-align: top;
@ -1104,7 +1104,7 @@
padding-top: 4px;
background: lighten($color-active, 30%);
height: 26px;
&-attrubutes {
@extend .el-drag-over;
width: auto;

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

@ -7,7 +7,7 @@ $theme: "";
$theme-primary-background: $gray-100;
$theme-primary-foreground: "";
$theme-secondary-background: $gray-225;
$theme-secondary-background: $gray-230;
$theme-secondary-foreground: #333;
$theme-hover-background: $color-header-hover;

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

@ -1,8 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import * as React from "react";
import { ButtonFlat } from "./buttons";
import * as R from "../resources";
import {
FluentTextField,
labelRender,
} from "../views/panels/widgets/controls/fluentui_customized_components";
import { TextField } from "@fluentui/react";
export interface EditableTextViewProps {
text: string;
@ -57,32 +60,22 @@ export class EditableTextView extends React.Component<
});
}
public componentDidMount() {
if (this.props.autofocus) {
this.refs.input.select();
}
}
public componentDidUpdate(
prevProps: EditableTextViewProps,
prevState: EditableTextViewState
) {
if (prevState.editing == false && this.state.editing == true) {
this.refs.input.select();
}
}
public render() {
if (this.state.editing) {
return (
<div className="editable-text-view editable-text-view-editing">
<input
type="text"
ref="input"
return (
<div>
<FluentTextField>
<TextField
value={this.state.currentText}
onChange={() =>
this.setState({ currentText: this.refs.input.value })
}
onRenderLabel={labelRender}
type="text"
onChange={(event, newValue) => {
this.setState({ currentText: newValue });
}}
onBlur={() => {
if (this.state.currentText == this.props.text) {
this.cancelEdit();
}
}}
onKeyDown={(e) => {
if (e.key == "Enter") {
this.confirmEdit();
@ -91,26 +84,15 @@ export class EditableTextView extends React.Component<
this.cancelEdit();
}
}}
autoFocus={true}
onBlur={() => {
if (this.state.currentText == this.props.text) {
this.cancelEdit();
}
autoFocus={false}
styles={{
fieldGroup: {
border: !this.state.editing && "none",
},
}}
/>
<ButtonFlat
url={R.getSVGIcon("general/confirm")}
onClick={this.confirmEdit}
stopPropagation={true}
/>
</div>
);
} else {
return (
<div className="editable-text-view" onClick={this.startEdit}>
<span className="text">{this.props.text}</span>
</div>
);
}
</FluentTextField>
</div>
);
}
}

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

@ -174,7 +174,11 @@ export class AttributePanel extends React.Component<
<div className="attribute-editor charticulator__widget-container">
<section className="attribute-editor-element" key={object._id}>
<div className="header">
<SVGImageIcon url={getObjectIcon(object.classID)} />
<SVGImageIcon
url={getObjectIcon(object.classID)}
height={32}
width={32}
/>
<EditableTextView
text={object.properties.name}
onEdit={(newValue) => {

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

@ -0,0 +1,77 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import {
GroupedList,
GroupHeader,
IGroupHeaderProps,
SelectionMode,
} from "@fluentui/react";
import * as React from "react";
import {
FluentGroupedList,
groupHeaderStyles,
groupStyles,
} from "./fluentui_customized_components";
export const CollapsiblePanel: React.FunctionComponent<{
header: string;
widgets: JSX.Element[];
isCollapsed?: boolean;
}> = ({ header, widgets, isCollapsed }) => {
const [groupState, setIsCollapsed] = React.useState<boolean>(
isCollapsed === undefined ? true : isCollapsed
);
return (
<FluentGroupedList>
<GroupedList
groupProps={{
onRenderHeader: (props?: IGroupHeaderProps): JSX.Element => {
return (
<GroupHeader
onRenderGroupHeaderCheckbox={() => null}
{...props}
styles={groupHeaderStyles}
onToggleCollapse={(group) => {
setIsCollapsed(!group.isCollapsed);
}}
/>
);
},
}}
selectionMode={SelectionMode.none}
items={widgets
.filter((w) => w !== null)
.map((w, i) => ({
key: i,
item: w,
}))}
onRenderCell={(
nestingDepth?: number,
item?: {
item: JSX.Element;
key: number;
},
itemIndex?: number
) => {
return item && typeof itemIndex === "number" && itemIndex > -1 ? (
<div className="charticulator__widget-collapsible-panel-item">
{item.item}
</div>
) : null;
}}
groups={[
{
count: widgets.length,
key: "group",
level: 0,
name: header,
startIndex: 0,
isCollapsed: groupState,
},
]}
compact={true}
styles={groupStyles}
/>
</FluentGroupedList>
);
};

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

@ -4,8 +4,13 @@
import * as React from "react";
import {
IDropdownProps,
IGroupedListStyleProps,
IGroupedListStyles,
IGroupHeaderStyleProps,
IGroupHeaderStyles,
ILabelStyles,
IRenderFunction,
IStyleFunctionOrObject,
ITextFieldProps,
Label,
} from "@fluentui/react";
@ -68,12 +73,6 @@ export const FluentLayoutItem = styled.div<{ flex: number }>`
export const defaultFontWeight = 400;
export const FluentLabelFontWeight = styled.div`
label {
font-weight: ${defaultFontWeight};
}
`;
export const defaultLabelStyle: ILabelStyles = {
root: {
fontWeight: defaultFontWeight,
@ -88,6 +87,39 @@ export const NestedChartButtonsWrapper = styled.div`
margin-top: 5px;
`;
export const FluentGroupedList = styled.div`
.charticulator__widget-collapsible-panel-item {
margin-left: 15px;
margin-right: 15px;
min-width: 270px;
}
.ms-List-surface .ms-List-cell .ms-List-cell:last-child {
margin-bottom: 10px;
}
`;
export const groupHeaderStyles: IStyleFunctionOrObject<
IGroupHeaderStyleProps,
IGroupHeaderStyles
> = {
title: {
fontWeight: 600,
},
headerCount: {
display: "none",
},
};
export const groupStyles: IStyleFunctionOrObject<
IGroupedListStyleProps,
IGroupedListStyles
> = {
group: {
borderTop: "1px #C8C6C4 solid",
},
};
export const PlaceholderStyle = styled.div<{ color?: string }>`
input {
::-webkit-input-placeholder {

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

@ -11,8 +11,8 @@ import {
import * as React from "react";
import { prettyNumber } from "../../../../../core";
import {
defaultFontWeight,
defaultLabelStyle,
FluentLabelFontWeight,
FluentLayoutItem,
FluentRowLayout,
labelRender,
@ -126,38 +126,42 @@ export const FluentInputNumber: React.FC<InputNumberProps> = (props) => {
const tick = props.updownTick || 0.1;
return (
<>
<FluentLabelFontWeight>
<SpinButton
label={!props.showSlider ? props.label : null}
labelPosition={Position.top}
value={formatNumber(+value)}
iconProps={
props.updownStyle == "font"
? {
iconName: "Font",
}
: null
<SpinButton
label={!props.showSlider ? props.label : null}
labelPosition={Position.top}
value={formatNumber(+value)}
iconProps={
props.updownStyle == "font"
? {
iconName: "Font",
}
: null
}
step={tick}
onIncrement={(value) => {
if (reportValue(parseNumber(value) + tick)) {
setValue(parseNumber(value) + tick);
}
step={tick}
onIncrement={(value) => {
if (reportValue(parseNumber(value) + tick)) {
setValue(parseNumber(value) + tick);
}
}}
onDecrement={(value) => {
if (reportValue(parseNumber(value) - tick)) {
setValue(parseNumber(value) - tick);
}
}}
onValidate={(value) => {
const num = parseNumber(value);
if (reportValue(num)) {
setValue(num);
return formatNumber(parseNumber(value));
}
}}
/>
</FluentLabelFontWeight>
}}
onDecrement={(value) => {
if (reportValue(parseNumber(value) - tick)) {
setValue(parseNumber(value) - tick);
}
}}
onValidate={(value) => {
const num = parseNumber(value);
if (reportValue(num)) {
setValue(num);
return formatNumber(parseNumber(value));
}
}}
styles={{
label: {
fontWeight: defaultFontWeight,
height: 25,
},
}}
/>
</>
);
};

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

@ -100,6 +100,8 @@ import { InputImage, InputImageProperty } from "./controls/fluentui_image";
import { Director, IDefaultValue, MenuItemBuilder } from "../../dataset/data_field_binding_builder";
import { FluentInputFormat } from "./controls/fluentui_input_format";
import { CollapsiblePanel } from "./controls/collapsiblePanel";
export type OnEditMappingHandler = (
attribute: string,
mapping: Specification.Mapping
@ -264,7 +266,7 @@ export class FluentUIWidgetManager
} catch (ex) {
return {
pass: false,
error: "Invalid format",
error: strings.objects.invalidFormat,
};
}
}
@ -1205,62 +1207,72 @@ export class FluentUIWidgetManager
options: Prototypes.Controls.GroupByEditorOptions
): JSX.Element {
let button: HTMLElement;
let text = "Group by...";
switch (options.mode) {
case "button":
if (options.value) {
if (options.value.expression) {
text = "Group by " + options.value.expression;
let text = strings.objects.plotSegment.groupBy;
const getControl = () => {
switch (options.mode) {
case "button":
if (options.value) {
if (options.value.expression) {
text =
strings.objects.plotSegment.groupByCategory +
options.value.expression;
}
}
}
return (
<FluentButton
marginTop={"0px"}
key={
this.getKeyFromProperty(options.target?.property) +
options?.table +
options?.value
}
>
<DefaultButton
text={text}
elementRef={(e) => (button = e)}
iconProps={{
iconName: "RowsGroup",
}}
onClick={() => {
globals.popupController.popupAt(
(context) => {
return (
<PopupView context={context}>
<GroupByEditor
manager={this}
value={options.value}
options={options}
/>
</PopupView>
);
},
{ anchor: ReactDOM.findDOMNode(button) as Element }
);
}}
return (
<FluentButton
marginTop={"0px"}
key={
this.getKeyFromProperty(options.target?.property) +
options?.table +
options?.value
}
>
<DefaultButton
text={text}
elementRef={(e) => (button = e)}
iconProps={{
iconName: "RowsGroup",
}}
onClick={() => {
globals.popupController.popupAt(
(context) => {
return (
<PopupView context={context}>
<GroupByEditor
manager={this}
value={options.value}
options={options}
/>
</PopupView>
);
},
{ anchor: button as Element }
);
}}
/>
</FluentButton>
);
case "panel":
return (
<GroupByEditor
key={
this.getKeyFromProperty(options?.target?.property) +
options.table +
options?.value
}
manager={this}
value={options.value}
options={options}
/>
</FluentButton>
);
case "panel":
return (
<GroupByEditor
key={
this.getKeyFromProperty(options?.target?.property) +
options.table +
options?.value
}
manager={this}
value={options.value}
options={options}
/>
);
}
);
}
};
return (
<div style={{ display: "inline" }} ref={(e) => (button = e)}>
{getControl()}
</div>
);
}
public nestedChartEditor(
@ -1371,6 +1383,19 @@ export class FluentUIWidgetManager
);
}
public verticalGroup(
options: Prototypes.Controls.VerticalGroupOptions,
widgets: JSX.Element[]
) {
return (
<CollapsiblePanel
header={options.header}
widgets={widgets}
isCollapsed={options.isCollapsed}
/>
);
}
public table(
rows: JSX.Element[][],
// eslint-disable-next-line @typescript-eslint/no-unused-vars

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

@ -120,7 +120,9 @@ export class WidgetManager
) {}
public tooltip(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
widget: JSX.Element,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
tooltipContent: JSX.Element
): JSX.Element {
throw new Error("Method not implemented.");
@ -710,7 +712,7 @@ export class WidgetManager
const items = this.getPropertyValue(property) as string[];
return (
<PopupView context={context}>
<ReorderStringsValue
<ReorderStringsValue
items={items}
onConfirm={(items, customOrder) => {
this.emitSetProperty(property, items);
@ -1213,6 +1215,21 @@ export class WidgetManager
);
}
public verticalGroup(
options: Prototypes.Controls.VerticalGroupOptions,
widgets: JSX.Element[]
) {
return (
<div className="charticulator__widget-vertical">
{widgets.map((x, id) => (
<span className="el-layout-item" key={id}>
{x}
</span>
))}
</div>
);
}
public table(
rows: JSX.Element[][],
// eslint-disable-next-line

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

@ -132,6 +132,11 @@ export interface InputColorOptions {
// eslint-disable-next-line
export interface TableOptions {}
export interface VerticalGroupOptions {
isCollapsed?: boolean;
header: string;
}
export interface FilterEditorOptions {
table: string;
target: {
@ -184,6 +189,7 @@ export interface InputFormatOptions {
export interface InputFormatOptions {
blank?: string;
label?: string;
}
export interface InputFormatOptions {
@ -264,6 +270,7 @@ export interface WidgetManager {
// Basic layout elements
horizontal(cols: number[], ...widgets: Widget[]): Widget;
verticalGroup(options: VerticalGroupOptions, ...widgets: Widget[]): Widget;
vertical(...widgets: Widget[]): Widget;
table(rows: Widget[][], options?: TableOptions): Widget;
scrollList(widgets: Widget[], options?: ScrollListOptions): Widget;

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

@ -239,19 +239,16 @@ export class GuideCoordinatorClass extends ChartElementClass<
manager: Controls.WidgetManager
): Controls.Widget[] {
return [
manager.sectionHeader(strings.objects.guides.guideCoordinator),
manager.row(
strings.objects.guides.count,
manager.inputNumber(
{ property: "count" },
{
showUpdown: true,
updownTick: 1,
updownRange: [1, 100],
minimum: 1,
maximum: 100,
}
)
manager.inputNumber(
{ property: "count" },
{
showUpdown: true,
updownTick: 1,
updownRange: [1, 100],
minimum: 1,
maximum: 100,
label: strings.objects.guides.count,
}
),
];
}

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

@ -272,19 +272,26 @@ export class CategoricalLegendClass extends LegendClass {
return [
...widgets,
manager.inputSelect(
{ property: "orientation" },
manager.verticalGroup(
{
type: "radio",
showLabel: false,
icons: ["AlignHorizontalCenter", "AlignVerticalCenter"],
labels: [
strings.objects.legend.vertical,
strings.objects.legend.horizontal,
],
options: ["vertical", "horizontal"],
label: strings.objects.legend.orientation,
}
header: strings.objects.legend.categoricalLegend,
},
[
manager.inputSelect(
{ property: "orientation" },
{
type: "radio",
showLabel: false,
icons: ["AlignHorizontalCenter", "AlignVerticalCenter"],
labels: [
strings.objects.legend.vertical,
strings.objects.legend.horizontal,
],
options: ["vertical", "horizontal"],
label: strings.objects.legend.orientation,
}
),
]
),
];
}

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

@ -189,106 +189,118 @@ export abstract class LegendClass extends ChartElementClass {
manager: Prototypes.Controls.WidgetManager & CharticulatorPropertyAccessors
): Controls.Widget[] {
const widget = [
manager.sectionHeader(strings.objects.legend.labels),
manager.inputFontFamily(
{ property: "fontFamily" },
{ label: strings.objects.font }
),
manager.inputNumber(
{ property: "fontSize" },
manager.verticalGroup(
{
showUpdown: true,
updownStyle: "font",
updownTick: 2,
label: strings.objects.size,
}
),
manager.inputColor(
{ property: "textColor" },
{ label: strings.objects.color }
),
manager.inputSelect(
{ property: "markerShape" },
{
type: "dropdown",
showLabel: true,
icons: ["RectangleShape", "TriangleShape", "Ellipse"],
labels: [
strings.toolbar.rectangle,
strings.toolbar.triangle,
strings.toolbar.ellipse,
],
options: ["rectangle", "triangle", "circle"],
label: strings.objects.legend.markerShape,
}
),
manager.label("Ordering"),
manager.reorderWidget(
{
property: "order",
header: strings.objects.legend.labels,
},
{
items: this.getOrderingObjects(),
onConfirm: (items: string[]) => {
const scale = this.getScale()[0];
const newMap: { [name: string]: ValueType } = {};
items.forEach((item) => {
newMap[item] = (<Specification.AttributeMap>(
scale.properties.mapping
))[item];
});
Prototypes.setProperty(scale, "mapping", newMap);
manager.emitSetProperty(
{
property: "mapping",
field: null,
[
manager.inputFontFamily(
{ property: "fontFamily" },
{ label: strings.objects.font }
),
manager.inputNumber(
{ property: "fontSize" },
{
showUpdown: true,
updownStyle: "font",
updownTick: 2,
label: strings.objects.size,
}
),
manager.inputColor(
{ property: "textColor" },
{ label: strings.objects.color }
),
manager.inputSelect(
{ property: "markerShape" },
{
type: "dropdown",
showLabel: true,
icons: ["RectangleShape", "TriangleShape", "Ellipse"],
labels: [
strings.toolbar.rectangle,
strings.toolbar.triangle,
strings.toolbar.ellipse,
],
options: ["rectangle", "triangle", "circle"],
label: strings.objects.legend.markerShape,
}
),
manager.label("Ordering"),
manager.reorderWidget(
{
property: "order",
},
{
items: this.getOrderingObjects(),
onConfirm: (items: string[]) => {
const scale = this.getScale()[0];
const newMap: { [name: string]: ValueType } = {};
items.forEach((item) => {
newMap[item] = (<Specification.AttributeMap>(
scale.properties.mapping
))[item];
});
Prototypes.setProperty(scale, "mapping", newMap);
manager.emitSetProperty(
{
property: "mapping",
field: null,
},
<Specification.AttributeValue>newMap
);
},
<Specification.AttributeValue>newMap
);
},
}
}
),
]
),
manager.sectionHeader(strings.objects.legend.layout),
manager.vertical(
manager.label(strings.alignment.alignment),
manager.horizontal(
[0, 0],
manager.inputSelect(
{ property: "alignX" },
{
type: "radio",
icons: [
"AlignHorizontalLeft",
"AlignHorizontalCenter",
"AlignHorizontalRight",
],
labels: [
strings.alignment.left,
strings.alignment.middle,
strings.alignment.right,
],
options: ["start", "middle", "end"],
}
manager.verticalGroup(
{
header: strings.objects.legend.layout,
},
[
manager.vertical(
manager.label(strings.alignment.alignment),
manager.horizontal(
[0, 0],
manager.inputSelect(
{ property: "alignX" },
{
type: "radio",
icons: [
"AlignHorizontalLeft",
"AlignHorizontalCenter",
"AlignHorizontalRight",
],
labels: [
strings.alignment.left,
strings.alignment.middle,
strings.alignment.right,
],
options: ["start", "middle", "end"],
}
),
manager.inputSelect(
{ property: "alignY" },
{
type: "radio",
options: ["start", "middle", "end"],
icons: [
"AlignVerticalBottom",
"AlignVerticalCenter",
"AlignVerticalTop",
],
labels: [
strings.alignment.bottom,
strings.alignment.middle,
strings.alignment.top,
],
}
),
null
)
),
manager.inputSelect(
{ property: "alignY" },
{
type: "radio",
options: ["start", "middle", "end"],
icons: [
"AlignVerticalBottom",
"AlignVerticalCenter",
"AlignVerticalTop",
],
labels: [
strings.alignment.bottom,
strings.alignment.middle,
strings.alignment.top,
],
}
),
null
)
]
),
];

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

@ -334,49 +334,62 @@ export class DataAxisClass extends MarkClass<
manager,
strings.toolbar.dataAxis
);
const r = [...axisWidgets];
r.push(
manager.inputSelect(
{ property: "visibleOn" },
const r = [
manager.verticalGroup(
{
labels: [
strings.objects.visibleOn.all,
strings.objects.visibleOn.first,
strings.objects.visibleOn.last,
],
showLabel: true,
options: ["all", "first", "last"],
type: "dropdown",
label: strings.objects.visibleOn.label,
}
)
);
header: strings.objects.general,
},
[
manager.inputSelect(
{ property: "visibleOn" },
{
labels: [
strings.objects.visibleOn.all,
strings.objects.visibleOn.first,
strings.objects.visibleOn.last,
],
showLabel: true,
options: ["all", "first", "last"],
type: "dropdown",
label: strings.objects.visibleOn.label,
}
),
]
),
...axisWidgets,
];
if (props.dataExpressions.length > 0) {
r.push(manager.sectionHeader("Data Expressions"));
r.push(
manager.arrayWidget(
{ property: "dataExpressions" },
(item, index) => {
const expressionInput = manager.inputExpression(
{
property: "dataExpressions",
field:
item.field instanceof Array
? [...item.field, "expression"]
: [item.field, "expression"],
},
{ table: this.getGlyphClass().object.table }
);
return React.createElement(
"fragment",
{ key: index },
expressionInput
);
},
manager.verticalGroup(
{
allowDelete: true,
allowReorder: true,
}
header: strings.objects.axes.dataExpressions,
},
[
manager.arrayWidget(
{ property: "dataExpressions" },
(item, index) => {
const expressionInput = manager.inputExpression(
{
property: "dataExpressions",
field:
item.field instanceof Array
? [...item.field, "expression"]
: [item.field, "expression"],
},
{ table: this.getGlyphClass().object.table }
);
return React.createElement(
"fragment",
{ key: index },
expressionInput
);
},
{
allowDelete: true,
allowReorder: true,
}
),
]
)
);
}

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

@ -1,3 +1,4 @@
/* eslint-disable max-lines-per-function */
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
@ -285,92 +286,112 @@ export class IconElementClass extends EmphasizableMarkClass<
const parentWidgets = super.getAttributePanelWidgets(manager);
const props = this.object.properties;
let widgets = [
manager.sectionHeader(strings.toolbar.icon),
manager.mappingEditor(strings.objects.icon.image, "image", {}),
manager.mappingEditor(strings.objects.size, "size", {
acceptKinds: [Specification.DataKind.Numerical],
hints: { rangeNumber: [0, 100] },
defaultValue: 400,
numberOptions: {
showSlider: true,
minimum: 0,
sliderRange: [0, 3600],
sliderFunction: "sqrt",
manager.verticalGroup(
{
header: strings.toolbar.icon,
},
}),
[
manager.mappingEditor(strings.objects.icon.image, "image", {}),
manager.mappingEditor(strings.objects.size, "size", {
acceptKinds: [Specification.DataKind.Numerical],
hints: { rangeNumber: [0, 100] },
defaultValue: 400,
numberOptions: {
showSlider: true,
minimum: 0,
sliderRange: [0, 3600],
sliderFunction: "sqrt",
},
}),
manager.mappingEditor(
strings.objects.visibleOn.visibility,
"visible",
{
defaultValue: true,
}
),
]
),
];
widgets = widgets.concat([
manager.sectionHeader(strings.objects.icon.anchorAndRotation),
manager.row(
strings.objects.icon.anchorX,
manager.horizontal(
[0, 1],
manager.inputSelect(
{ property: "alignment", field: "x" },
{
type: "radio",
icons: [
"AlignHorizontalLeft",
"AlignHorizontalCenter",
"AlignHorizontalRight",
],
labels: [
strings.alignment.left,
strings.alignment.middle,
strings.alignment.right,
],
options: ["left", "middle", "right"],
}
manager.verticalGroup(
{
header: strings.objects.anchorAndRotation,
},
[
manager.horizontal(
[0, 1],
manager.inputSelect(
{ property: "alignment", field: "x" },
{
type: "radio",
icons: [
"AlignHorizontalLeft",
"AlignHorizontalCenter",
"AlignHorizontalRight",
],
labels: [
strings.alignment.left,
strings.alignment.middle,
strings.alignment.right,
],
options: ["left", "middle", "right"],
label: strings.objects.anchorX,
}
),
props.alignment.x != "middle"
? manager.inputNumber(
{ property: "alignment", field: "xMargin" },
{
label: strings.margins.margin,
}
)
: null
),
props.alignment.x != "middle"
? manager.horizontal(
[0, 1],
manager.label(strings.margins.margin),
manager.inputNumber({ property: "alignment", field: "xMargin" })
)
: null
)
),
manager.row(
strings.objects.icon.anchorY,
manager.horizontal(
[0, 1],
manager.inputSelect(
{ property: "alignment", field: "y" },
{
type: "radio",
icons: [
"AlignVerticalTop",
"AlignVerticalCenter",
"AlignVerticalBottom",
],
labels: [
strings.alignment.top,
strings.alignment.middle,
strings.alignment.bottom,
],
options: ["top", "middle", "bottom"],
}
manager.horizontal(
[0, 1],
manager.inputSelect(
{ property: "alignment", field: "y" },
{
type: "radio",
icons: [
"AlignVerticalTop",
"AlignVerticalCenter",
"AlignVerticalBottom",
],
labels: [
strings.alignment.top,
strings.alignment.middle,
strings.alignment.bottom,
],
options: ["top", "middle", "bottom"],
label: strings.objects.anchorY,
}
),
props.alignment.y != "middle"
? manager.inputNumber(
{ property: "alignment", field: "yMargin" },
{
label: strings.margins.margin,
}
)
: null
),
props.alignment.y != "middle"
? manager.horizontal(
[0, 1],
manager.label("Margin:"),
manager.inputNumber({ property: "alignment", field: "yMargin" })
)
: null
)
]
),
manager.verticalGroup(
{
header: strings.objects.style,
},
[
manager.mappingEditor(strings.objects.opacity, "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1 },
}),
]
),
manager.sectionHeader(strings.objects.style),
manager.mappingEditor(strings.objects.opacity, "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1, step: 0.1 },
}),
manager.mappingEditor(strings.objects.visibleOn.visibility, "visible", {
defaultValue: true,
}),
]);
return widgets.concat(parentWidgets);
}

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

@ -96,115 +96,148 @@ export class ImageElementClass extends EmphasizableMarkClass<
manager: Controls.WidgetManager
): Controls.Widget[] {
const parentWidgets = super.getAttributePanelWidgets(manager);
let widgets: Controls.Widget[] = [
manager.sectionHeader(strings.objects.size),
manager.mappingEditor(strings.objects.width, "width", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [Specification.DataKind.Numerical],
defaultAuto: true,
}),
manager.mappingEditor(strings.objects.height, "height", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [Specification.DataKind.Numerical],
defaultAuto: true,
}),
manager.sectionHeader(strings.toolbar.image),
manager.mappingEditor(strings.objects.icon.image, "image", {}),
manager.inputSelect(
{ property: "imageMode" },
const widgets: Controls.Widget[] = [
manager.verticalGroup(
{
type: "dropdown",
showLabel: true,
labels: [
strings.objects.image.letterbox,
strings.objects.image.stretch,
],
options: ["letterbox", "stretch"],
label: strings.objects.image.imageMode,
}
header: strings.objects.general,
},
[
manager.mappingEditor(strings.objects.width, "width", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [Specification.DataKind.Numerical],
defaultAuto: true,
}),
manager.mappingEditor(strings.objects.height, "height", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [Specification.DataKind.Numerical],
defaultAuto: true,
}),
manager.mappingEditor(
strings.objects.visibleOn.visibility,
"visible",
{
defaultValue: true,
}
),
]
),
...(this.object.properties.imageMode == "letterbox"
? [
manager.label(strings.alignment.align),
manager.horizontal(
[0, 1],
manager.inputSelect(
{ property: "alignX" },
// manager.sectionHeader(strings.objects.size),
manager.verticalGroup(
{
header: strings.toolbar.image,
},
[
manager.mappingEditor(strings.objects.icon.image, "image", {}),
manager.inputSelect(
{ property: "imageMode" },
{
type: "dropdown",
showLabel: true,
labels: [
strings.objects.image.letterbox,
strings.objects.image.stretch,
],
options: ["letterbox", "stretch"],
label: strings.objects.image.imageMode,
}
),
...(this.object.properties.imageMode == "letterbox"
? [
manager.label(strings.alignment.align),
manager.horizontal(
[0, 1],
manager.inputSelect(
{ property: "alignX" },
{
type: "radio",
options: ["start", "middle", "end"],
icons: [
"AlignHorizontalLeft",
"AlignHorizontalCenter",
"AlignHorizontalRight",
],
labels: [
strings.alignment.left,
strings.alignment.middle,
strings.alignment.right,
],
}
),
manager.inputSelect(
{ property: "alignY" },
{
type: "radio",
options: ["start", "middle", "end"],
icons: [
"AlignVerticalBottom",
"AlignVerticalCenter",
"AlignVerticalTop",
],
labels: [
strings.alignment.bottom,
strings.alignment.middle,
strings.alignment.top,
],
}
)
),
]
: []),
]
),
manager.verticalGroup(
{
header: strings.alignment.padding,
},
[
manager.label(strings.coordinateSystem.x),
manager.inputNumber(
{ property: "paddingX" },
{
updownTick: 1,
showUpdown: true,
}
),
manager.label(strings.coordinateSystem.y),
manager.inputNumber(
{ property: "paddingY" },
{
updownTick: 1,
showUpdown: true,
}
),
]
),
manager.verticalGroup(
{
header: strings.objects.style,
},
[
manager.mappingEditor(strings.objects.fill, "fill", {}),
manager.mappingEditor(strings.objects.stroke, "stroke", {}),
this.object.mappings.stroke != null
? manager.mappingEditor(
strings.objects.strokeWidth,
"strokeWidth",
{
type: "radio",
options: ["start", "middle", "end"],
icons: [
"AlignHorizontalLeft",
"AlignHorizontalCenter",
"AlignHorizontalRight",
],
labels: [
strings.alignment.left,
strings.alignment.middle,
strings.alignment.right,
],
}
),
manager.inputSelect(
{ property: "alignY" },
{
type: "radio",
options: ["start", "middle", "end"],
icons: [
"AlignVerticalBottom",
"AlignVerticalCenter",
"AlignVerticalTop",
],
labels: [
strings.alignment.bottom,
strings.alignment.middle,
strings.alignment.top,
],
hints: { rangeNumber: [0, 5] },
defaultValue: 1,
numberOptions: {
showSlider: true,
sliderRange: [0, 5],
minimum: 0,
},
}
)
),
]
: []),
manager.sectionHeader(strings.alignment.padding),
manager.label(strings.coordinateSystem.x),
manager.inputNumber(
{ property: "paddingX" },
{
updownTick: 1,
showUpdown: true,
}
: null,
manager.mappingEditor(strings.objects.opacity, "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1 },
}),
]
),
manager.label(strings.coordinateSystem.y),
manager.inputNumber(
{ property: "paddingY" },
{
updownTick: 1,
showUpdown: true,
}
),
manager.sectionHeader(strings.objects.style),
manager.mappingEditor(strings.objects.fill, "fill", {}),
manager.mappingEditor(strings.objects.stroke, "stroke", {}),
];
if (this.object.mappings.stroke != null) {
widgets.push(
manager.mappingEditor(strings.objects.strokeWidth, "strokeWidth", {
hints: { rangeNumber: [0, 5] },
defaultValue: 1,
numberOptions: { showSlider: true, sliderRange: [0, 5], minimum: 0 },
})
);
}
widgets = widgets.concat([
manager.mappingEditor(strings.objects.opacity, "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1, step: 0.1 },
}),
manager.mappingEditor(strings.objects.visibleOn.visibility, "visible", {
defaultValue: true,
}),
]);
return widgets.concat(parentWidgets);
}

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

@ -26,6 +26,7 @@ import * as Graphics from "../../graphics";
import { EmphasizableMarkClass } from "./emphasis";
import { ChartStateManager } from "../state";
import { MappingType } from "../../specification";
import { strings } from "../../../strings";
export { LineElementAttributes, LineElementProperties };
@ -305,45 +306,59 @@ export class LineElementClass extends EmphasizableMarkClass<
): Controls.Widget[] {
const parentWidgets = super.getAttributePanelWidgets(manager);
return [
manager.sectionHeader("Line"),
manager.mappingEditor("X Span", "dx", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [Specification.DataKind.Numerical],
defaultAuto: true,
}),
manager.mappingEditor("Y Span", "dy", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [Specification.DataKind.Numerical],
defaultAuto: true,
}),
manager.sectionHeader("Style"),
manager.mappingEditor("Stroke", "stroke", {}),
manager.mappingEditor("Line Width", "strokeWidth", {
hints: { rangeNumber: [0, 5] },
defaultValue: 1,
numberOptions: { showSlider: true, sliderRange: [0, 5], minimum: 0 },
}),
manager.row(
"Line Style",
manager.inputSelect(
{ property: "strokeStyle" },
{
type: "dropdown",
showLabel: true,
icons: ["stroke/solid", "stroke/dashed", "stroke/dotted"],
labels: ["Solid", "Dashed", "Dotted"],
options: ["solid", "dashed", "dotted"],
}
)
manager.verticalGroup(
{
header: strings.toolbar.line,
},
[
manager.mappingEditor("X Span", "dx", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [Specification.DataKind.Numerical],
defaultAuto: true,
}),
manager.mappingEditor("Y Span", "dy", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [Specification.DataKind.Numerical],
defaultAuto: true,
}),
manager.mappingEditor("Visibility", "visible", {
defaultValue: true,
}),
]
),
manager.verticalGroup(
{
header: strings.objects.style,
},
[
manager.mappingEditor(strings.objects.stroke, "stroke", {}),
manager.mappingEditor(strings.objects.strokeWidth, "strokeWidth", {
hints: { rangeNumber: [0, 5] },
defaultValue: 1,
numberOptions: {
showSlider: true,
sliderRange: [0, 5],
minimum: 0,
},
}),
manager.inputSelect(
{ property: "strokeStyle" },
{
type: "dropdown",
showLabel: true,
icons: ["stroke/solid", "stroke/dashed", "stroke/dotted"],
labels: ["Solid", "Dashed", "Dotted"],
options: ["solid", "dashed", "dotted"],
label: strings.objects.line.lineStyle,
}
),
manager.mappingEditor(strings.objects.opacity, "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1 },
}),
]
),
manager.mappingEditor("Opacity", "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1, step: 0.1 },
}),
manager.mappingEditor("Visibility", "visible", {
defaultValue: true,
}),
].concat(parentWidgets);
}

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

@ -1,3 +1,4 @@
/* eslint-disable max-lines-per-function */
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
@ -25,6 +26,7 @@ import {
RectElementAttributes,
RectElementProperties,
} from "./rect.attrs";
import { strings } from "../../../strings";
export { RectElementAttributes, RectElementProperties };
@ -172,70 +174,99 @@ export class RectElementClass extends EmphasizableMarkClass<
const parentWidgets = super.getAttributePanelWidgets(manager);
let widgets: Controls.Widget[] = [
manager.sectionHeader("Size & Shape"),
manager.mappingEditor("Width", "width", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [DataKind.Numerical],
defaultAuto: true,
}),
manager.mappingEditor("Height", "height", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [DataKind.Numerical],
defaultAuto: true,
}),
manager.inputSelect(
{ property: "shape" },
manager.verticalGroup(
{
type: "dropdown",
showLabel: true,
label: "Shape",
icons: ["RectangleShape", "TriangleShape", "Ellipse"],
labels: ["Rectangle", "Triangle", "Ellipse"],
options: ["rectangle", "triangle", "ellipse"],
}
header: strings.objects.general,
},
[
manager.mappingEditor(strings.objects.width, "width", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [DataKind.Numerical],
defaultAuto: true,
}),
manager.mappingEditor(strings.objects.height, "height", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [DataKind.Numerical],
defaultAuto: true,
}),
manager.inputSelect(
{ property: "shape" },
{
type: "dropdown",
showLabel: true,
label: strings.objects.rect.shape,
icons: ["RectangleShape", "TriangleShape", "Ellipse"],
labels: [
strings.objects.rect.shapes.rectangle,
strings.objects.rect.shapes.triangle,
strings.objects.rect.shapes.ellipse,
],
options: ["rectangle", "triangle", "ellipse"],
}
),
manager.inputBoolean(
{ property: "allowFlipping" },
{
type: "checkbox",
label: strings.objects.rect.flipping,
}
),
manager.mappingEditor(
strings.objects.visibleOn.visibility,
"visible",
{
defaultValue: true,
}
),
]
),
manager.inputBoolean(
{ property: "allowFlipping" },
manager.verticalGroup(
{
type: "checkbox",
label: "Flipping",
}
header: strings.objects.style,
},
[
manager.mappingEditor(strings.objects.fill, "fill", {}),
manager.mappingEditor(strings.objects.stroke, "stroke", {}),
this.object.mappings.stroke != null
? manager.mappingEditor(
strings.objects.strokeWidth,
"strokeWidth",
{
hints: { rangeNumber: [0, 5] },
defaultValue: 1,
numberOptions: {
showSlider: true,
sliderRange: [0, 5],
minimum: 0,
},
}
)
: null,
this.object.mappings.stroke != null
? manager.inputSelect(
{ property: "strokeStyle" },
{
type: "dropdown",
showLabel: true,
label: "Line Style",
icons: ["stroke/solid", "stroke/dashed", "stroke/dotted"],
labels: [
strings.objects.links.solid,
strings.objects.links.dashed,
strings.objects.links.dotted,
],
options: ["solid", "dashed", "dotted"],
}
)
: null,
manager.mappingEditor(strings.objects.opacity, "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1 },
}),
]
),
manager.sectionHeader("Style"),
manager.mappingEditor("Fill", "fill", {}),
manager.mappingEditor("Stroke", "stroke", {}),
];
if (this.object.mappings.stroke != null) {
widgets.push(
manager.mappingEditor("Line Width", "strokeWidth", {
hints: { rangeNumber: [0, 5] },
defaultValue: 1,
numberOptions: { showSlider: true, sliderRange: [0, 5], minimum: 0 },
})
);
manager.inputSelect(
{ property: "strokeStyle" },
{
type: "dropdown",
showLabel: true,
label: "Line Style",
icons: ["stroke/solid", "stroke/dashed", "stroke/dotted"],
labels: ["Solid", "Dashed", "Dotted"],
options: ["solid", "dashed", "dotted"],
}
);
}
widgets = widgets.concat([
manager.mappingEditor("Opacity", "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1, step: 0.1 },
}),
manager.mappingEditor("Visibility", "visible", {
defaultValue: true,
}),
]);
widgets = widgets.concat(parentWidgets);
return widgets;

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

@ -1,6 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { strings } from "../../../strings";
import { Point, Color, rgbToHex } from "../../common";
import * as Graphics from "../../graphics";
import * as Specification from "../../specification";
@ -297,46 +298,68 @@ export class SymbolElementClass extends EmphasizableMarkClass<
): Controls.Widget[] {
const parentWidgets = super.getAttributePanelWidgets(manager);
let widgets = [
manager.sectionHeader("Symbol"),
manager.mappingEditor("Shape", "symbol", {
acceptKinds: [Specification.DataKind.Categorical],
hints: { rangeEnum: symbolTypes },
defaultValue: "circle",
}),
manager.mappingEditor("Size", "size", {
acceptKinds: [Specification.DataKind.Numerical],
hints: { rangeNumber: [0, 200 * Math.PI] },
defaultValue: 60,
numberOptions: {
showSlider: true,
minimum: 0,
sliderRange: [0, 3600],
sliderFunction: "sqrt",
manager.verticalGroup(
{
header: strings.objects.general,
},
}),
manager.sectionHeader("Style"),
manager.mappingEditor("Fill", "fill", {}),
manager.mappingEditor("Stroke", "stroke", {}),
[
manager.mappingEditor(strings.objects.rect.shape, "symbol", {
acceptKinds: [Specification.DataKind.Categorical],
hints: { rangeEnum: symbolTypes },
defaultValue: "circle",
}),
manager.mappingEditor(strings.objects.size, "size", {
acceptKinds: [Specification.DataKind.Numerical],
hints: { rangeNumber: [0, 200 * Math.PI] },
defaultValue: 60,
numberOptions: {
showSlider: true,
minimum: 0,
sliderRange: [0, 3600],
sliderFunction: "sqrt",
},
}),
manager.mappingEditor(
strings.objects.visibleOn.visibility,
"visible",
{
defaultValue: true,
}
),
]
),
manager.verticalGroup(
{
header: strings.objects.style,
},
[
manager.mappingEditor(strings.objects.fill, "fill", {}),
manager.mappingEditor(strings.objects.stroke, "stroke", {}),
this.object.mappings.stroke != null
? manager.mappingEditor(
strings.objects.strokeWidth,
"strokeWidth",
{
hints: { rangeNumber: [0, 5] },
defaultValue: 1,
numberOptions: {
showSlider: true,
sliderRange: [0, 5],
minimum: 0,
},
}
)
: null,
manager.mappingEditor(strings.objects.opacity, "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1 },
}),
]
),
];
if (this.object.mappings.stroke != null) {
widgets.push(
manager.mappingEditor("Line Width", "strokeWidth", {
hints: { rangeNumber: [0, 5] },
defaultValue: 1,
numberOptions: { showSlider: true, sliderRange: [0, 5], minimum: 0 },
})
);
}
widgets = widgets.concat([
manager.mappingEditor("Opacity", "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1, step: 0.1 },
}),
manager.mappingEditor("Visibility", "visible", {
defaultValue: true,
}),
]);
widgets = widgets.concat([]);
return widgets.concat(parentWidgets);
}

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

@ -1,7 +1,9 @@
/* eslint-disable max-lines-per-function */
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
import { defaultFont, defaultFontSize } from "../../../app/stores/defaults";
import { strings } from "../../../strings";
import {
Point,
replaceNewLineBySymbol,
@ -291,80 +293,111 @@ export class TextElementClass extends EmphasizableMarkClass<
const parentWidgets = super.getAttributePanelWidgets(manager);
const props = this.object.properties;
return [
manager.mappingEditor("Text", "text", {}),
manager.mappingEditor("Font", "fontFamily", {
defaultValue: defaultFont,
}),
manager.mappingEditor("Size", "fontSize", {
hints: { rangeNumber: [0, 36] },
defaultValue: defaultFontSize,
numberOptions: {
showUpdown: true,
updownStyle: "font",
minimum: 0,
updownTick: 2,
manager.verticalGroup(
{
header: strings.objects.general,
},
}),
manager.sectionHeader("Anchor & Rotation"),
manager.inputSelect(
{ property: "alignment", field: "x" },
{
type: "radio",
icons: [
"AlignHorizontalLeft",
"AlignHorizontalCenter",
"AlignHorizontalRight",
],
labels: ["Left", "Middle", "Right"],
options: ["left", "middle", "right"],
label: "Anchor X",
}
),
props.alignment.x != "middle"
? manager.inputNumber(
{ property: "alignment", field: "xMargin" },
{
updownTick: 1,
[
manager.mappingEditor(strings.toolbar.text, "text", {}),
manager.mappingEditor(strings.objects.font, "fontFamily", {
defaultValue: defaultFont,
}),
manager.mappingEditor(strings.objects.size, "fontSize", {
hints: { rangeNumber: [0, 36] },
defaultValue: defaultFontSize,
numberOptions: {
showUpdown: true,
label: "Margin",
}
)
: null,
manager.inputSelect(
{ property: "alignment", field: "y" },
{
type: "radio",
icons: [
"AlignVerticalTop",
"AlignVerticalCenter",
"AlignVerticalBottom",
],
labels: ["Top", "Middle", "Bottom"],
options: ["top", "middle", "bottom"],
label: "Anchor Y",
}
),
props.alignment.y != "middle"
? manager.inputNumber(
{ property: "alignment", field: "yMargin" },
updownStyle: "font",
minimum: 0,
updownTick: 2,
},
}),
manager.mappingEditor(
strings.objects.visibleOn.visibility,
"visible",
{
updownTick: 1,
showUpdown: true,
label: "Margin",
defaultValue: true,
}
)
: null,
// manager.row("Rotation", manager.inputNumber({ property: "rotation" })),
manager.sectionHeader("Style"),
manager.mappingEditor("Color", "color", {}),
manager.mappingEditor("Outline", "outline", {}),
manager.mappingEditor("Opacity", "opacity", {
hints: { rangeNumber: [0, 1] },
numberOptions: { showSlider: true, minimum: 0, maximum: 1, step: 0.1 },
}),
manager.mappingEditor("Visibility", "visible", {
defaultValue: true,
}),
),
]
),
manager.verticalGroup(
{
header: strings.objects.anchorAndRotation,
},
[
manager.inputSelect(
{ property: "alignment", field: "x" },
{
type: "radio",
icons: [
"AlignHorizontalLeft",
"AlignHorizontalCenter",
"AlignHorizontalRight",
],
labels: ["Left", "Middle", "Right"],
options: ["left", "middle", "right"],
label: strings.objects.anchorX,
}
),
props.alignment.x != "middle"
? manager.inputNumber(
{ property: "alignment", field: "xMargin" },
{
updownTick: 1,
showUpdown: true,
label: "Margin",
}
)
: null,
manager.inputSelect(
{ property: "alignment", field: "y" },
{
type: "radio",
icons: [
"AlignVerticalTop",
"AlignVerticalCenter",
"AlignVerticalBottom",
],
labels: ["Top", "Middle", "Bottom"],
options: ["top", "middle", "bottom"],
label: strings.objects.anchorY,
}
),
props.alignment.y != "middle"
? manager.inputNumber(
{ property: "alignment", field: "yMargin" },
{
updownTick: 1,
showUpdown: true,
label: strings.objects.text.margin,
}
)
: null,
manager.inputNumber(
{ property: "rotation" },
{
label: strings.objects.rotation,
showUpdown: true,
updownTick: 1,
}
),
]
),
manager.verticalGroup(
{
header: "Style",
},
[
manager.mappingEditor(strings.objects.color, "color", {}),
manager.mappingEditor(strings.objects.outline, "outline", {}),
manager.mappingEditor(strings.objects.opacity, "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1 },
}),
]
),
].concat(parentWidgets);
}

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

@ -2,6 +2,7 @@
// Licensed under the MIT license.
import { defaultFont, defaultFontSize } from "../../../app/stores/defaults";
import { strings } from "../../../strings";
import {
Point,
replaceNewLineBySymbol,
@ -109,36 +110,52 @@ export class TextboxElementClass extends EmphasizableMarkClass<
const props = this.object.properties;
const parentWidgets = super.getAttributePanelWidgets(manager);
const widgets: Controls.Widget[] = [
manager.sectionHeader("Size"),
manager.mappingEditor("Width", "width", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [Specification.DataKind.Numerical],
defaultAuto: true,
}),
manager.mappingEditor("Height", "height", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [Specification.DataKind.Numerical],
defaultAuto: true,
}),
manager.sectionHeader("Text"),
manager.mappingEditor("Text", "text", {}),
manager.mappingEditor("Font", "fontFamily", {
defaultValue: defaultFont,
}),
manager.mappingEditor("Size", "fontSize", {
hints: { rangeNumber: [0, 36] },
defaultValue: defaultFontSize,
numberOptions: {
showUpdown: true,
updownStyle: "font",
minimum: 0,
updownTick: 2,
manager.verticalGroup(
{
header: strings.objects.general,
},
}),
manager.row(
"Align X",
manager.horizontal(
[0, 1],
[
manager.mappingEditor("Width", "width", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [Specification.DataKind.Numerical],
defaultAuto: true,
}),
manager.mappingEditor("Height", "height", {
hints: { autoRange: true, startWithZero: "always" },
acceptKinds: [Specification.DataKind.Numerical],
defaultAuto: true,
}),
manager.mappingEditor("Visibility", "visible", {
defaultValue: true,
}),
]
),
manager.verticalGroup(
{
header: strings.toolbar.text,
},
[
manager.mappingEditor("Text", "text", {}),
manager.mappingEditor("Font", "fontFamily", {
defaultValue: defaultFont,
}),
manager.mappingEditor("Size", "fontSize", {
hints: { rangeNumber: [0, 36] },
defaultValue: defaultFontSize,
numberOptions: {
showUpdown: true,
updownStyle: "font",
minimum: 0,
updownTick: 2,
},
}),
]
),
manager.verticalGroup(
{
header: strings.objects.layout,
},
[
manager.inputSelect(
{ property: "alignX" },
{
@ -150,6 +167,7 @@ export class TextboxElementClass extends EmphasizableMarkClass<
"AlignHorizontalRight",
],
labels: ["Left", "Middle", "Right"],
label: strings.objects.alignX,
}
),
props.alignX != "middle"
@ -161,16 +179,11 @@ export class TextboxElementClass extends EmphasizableMarkClass<
{
updownTick: 1,
showUpdown: true,
label: strings.objects.text.margin,
}
)
)
: null
)
),
manager.row(
"Align Y",
manager.horizontal(
[0, 1],
: null,
manager.inputSelect(
{ property: "alignY" },
{
@ -182,6 +195,7 @@ export class TextboxElementClass extends EmphasizableMarkClass<
"AlignVerticalTop",
],
labels: ["Bottom", "Middle", "Top"],
label: strings.objects.alignX,
}
),
props.alignY != "middle"
@ -193,65 +207,68 @@ export class TextboxElementClass extends EmphasizableMarkClass<
{
updownTick: 1,
showUpdown: true,
label: strings.objects.text.margin,
}
)
)
: null
)
),
manager.sectionHeader("Layout"),
manager.row(
"Wrap text",
manager.inputBoolean(
{ property: "wordWrap" },
{
type: "checkbox",
}
)
),
props.wordWrap
? manager.row(
"Alignment",
manager.horizontal(
[0, 1],
manager.inputSelect(
{ property: "alignText" },
{
type: "radio",
options: ["end", "middle", "start"],
icons: [
"AlignVerticalBottom",
"AlignVerticalCenter",
"AlignVerticalTop",
],
labels: ["Bottom", "Middle", "Top"],
}
)
)
)
: null,
props.wordWrap
? manager.row(
"Overflow",
: null,
manager.row(
"Wrap text",
manager.inputBoolean(
{ property: "overFlow" },
{ property: "wordWrap" },
{
type: "checkbox",
}
)
)
: null,
manager.sectionHeader("Style"),
manager.mappingEditor("Color", "color", {}),
manager.mappingEditor("Outline", "outline", {}),
manager.mappingEditor("Opacity", "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1, step: 0.1 },
}),
manager.mappingEditor("Visibility", "visible", {
defaultValue: true,
}),
),
props.wordWrap
? manager.row(
"Alignment",
manager.horizontal(
[0, 1],
manager.inputSelect(
{ property: "alignText" },
{
type: "radio",
options: ["end", "middle", "start"],
icons: [
"AlignVerticalBottom",
"AlignVerticalCenter",
"AlignVerticalTop",
],
labels: ["Bottom", "Middle", "Top"],
}
)
)
)
: null,
props.wordWrap
? manager.row(
"Overflow",
manager.inputBoolean(
{ property: "overFlow" },
{
type: "checkbox",
}
)
)
: null,
]
),
manager.verticalGroup(
{
header: strings.objects.style,
},
[
manager.mappingEditor("Color", "color", {}),
manager.mappingEditor("Outline", "outline", {}),
manager.mappingEditor("Opacity", "opacity", {
hints: { rangeNumber: [0, 1] },
defaultValue: 1,
numberOptions: { showSlider: true, minimum: 0, maximum: 1 },
}),
]
),
];
return widgets.concat(parentWidgets);
}

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

@ -92,27 +92,33 @@ export abstract class ObjectClass<
manager: Controls.WidgetManager
): Controls.Widget[] {
return [
manager.sectionHeader("Interactivity"),
manager.inputBoolean(
{ property: "enableTooltips" },
manager.verticalGroup(
{
type: "checkbox",
label: "Tooltips",
}
),
manager.inputBoolean(
{ property: "enableContextMenu" },
{
type: "checkbox",
label: "Context menu",
}
),
manager.inputBoolean(
{ property: "enableSelection" },
{
type: "checkbox",
label: "Selection",
}
header: "Interactivity",
},
[
manager.inputBoolean(
{ property: "enableTooltips" },
{
type: "checkbox",
label: "Tooltips",
}
),
manager.inputBoolean(
{ property: "enableContextMenu" },
{
type: "checkbox",
label: "Context menu",
}
),
manager.inputBoolean(
{ property: "enableSelection" },
{
type: "checkbox",
label: "Selection",
}
),
]
),
];
}

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

@ -1,3 +1,4 @@
/* eslint-disable max-lines-per-function */
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
@ -960,85 +961,105 @@ export function getNumericalInterpolate(
export function buildAxisAppearanceWidgets(
isVisible: boolean,
axisProperty: string,
m: Controls.WidgetManager
manager: Controls.WidgetManager
) {
if (isVisible) {
return [
m.vertical(
m.inputBoolean(
{ property: axisProperty, field: "visible" },
{ type: "checkbox", label: "Visible", headerLabel: "Appearance" }
),
m.inputSelect(
{ property: axisProperty, field: "side" },
manager.vertical(
manager.verticalGroup(
{
type: "dropdown",
showLabel: true,
label: "Position:",
options: ["default", "opposite"],
labels: ["Default", "Opposite"],
}
),
m.sectionHeader("Axis Style"),
m.inputColor(
{
property: axisProperty,
field: ["style", "lineColor"],
header: strings.objects.appearance,
},
{
label: "Line Color",
}
[
manager.inputBoolean(
{ property: axisProperty, field: "visible" },
{ type: "checkbox", label: "Visible", headerLabel: "Appearance" }
),
manager.inputSelect(
{ property: axisProperty, field: "side" },
{
type: "dropdown",
showLabel: true,
label: "Position:",
options: ["default", "opposite"],
labels: ["Default", "Opposite"],
}
),
]
),
m.inputColor(
manager.verticalGroup(
{
property: axisProperty,
field: ["style", "tickColor"],
header: strings.objects.style,
},
{
label: "Tick Color",
}
),
m.inputNumber(
{
property: axisProperty,
field: ["style", "tickSize"],
},
{
label: "Tick Size",
}
),
m.inputFontFamily(
{
property: axisProperty,
field: ["style", "fontFamily"],
},
{
label: "Font Family",
}
),
m.inputNumber(
{ property: axisProperty, field: ["style", "fontSize"] },
{
showUpdown: true,
updownStyle: "font",
updownTick: 2,
label: "Font Size",
}
),
m.inputBoolean(
{ property: axisProperty, field: ["style", "wordWrap"] },
{
type: "checkbox",
headerLabel: "Text displaying",
label: "Wrap text",
}
[
manager.inputColor(
{
property: axisProperty,
field: ["style", "lineColor"],
},
{
label: "Line Color",
}
),
manager.inputColor(
{
property: axisProperty,
field: ["style", "tickColor"],
},
{
label: "Tick Color",
}
),
manager.inputNumber(
{
property: axisProperty,
field: ["style", "tickSize"],
},
{
label: "Tick Size",
}
),
manager.inputFontFamily(
{
property: axisProperty,
field: ["style", "fontFamily"],
},
{
label: "Font Family",
}
),
manager.inputNumber(
{ property: axisProperty, field: ["style", "fontSize"] },
{
showUpdown: true,
updownStyle: "font",
updownTick: 2,
label: "Font Size",
}
),
manager.inputBoolean(
{ property: axisProperty, field: ["style", "wordWrap"] },
{
type: "checkbox",
headerLabel: "Text displaying",
label: "Wrap text",
}
),
]
)
),
];
} else {
return m.inputBoolean(
{ property: axisProperty, field: "visible" },
{ type: "checkbox", label: "Visible", headerLabel: "Appearance" }
return manager.verticalGroup(
{
header: strings.objects.appearance,
},
[
manager.inputBoolean(
{ property: axisProperty, field: "visible" },
{ type: "checkbox", label: "Visible", headerLabel: "Appearance" }
),
]
);
}
}
@ -1047,7 +1068,7 @@ export function buildAxisAppearanceWidgets(
export function buildAxisWidgets(
data: Specification.Types.AxisDataBinding,
axisProperty: string,
m: Controls.WidgetManager,
manager: Controls.WidgetManager,
axisName: string
): Controls.Widget[] {
const widgets = [];
@ -1059,99 +1080,93 @@ export function buildAxisWidgets(
},
};
const makeAppearance = () => {
return buildAxisAppearanceWidgets(data.visible, axisProperty, m);
return buildAxisAppearanceWidgets(data.visible, axisProperty, manager);
};
if (data != null) {
switch (data.type) {
case "numerical":
{
widgets.push(
m.sectionHeader(
axisName + ": Numerical",
m.clearButton({ property: axisProperty }, null, true),
dropzoneOptions
)
);
if (axisName != "Data Axis") {
widgets.push(
m.inputExpression(
{
property: axisProperty,
field: "expression",
},
{
label: "Data",
}
)
);
}
if (data.valueType === "date") {
widgets.push(m.label("Range"));
widgets.push(
m.inputDate(
{ property: axisProperty, field: "domainMin" },
{ label: "Start" }
)
);
widgets.push(
m.inputDate(
{ property: axisProperty, field: "domainMax" },
{ label: "End" }
)
);
} else {
widgets.push(
m.vertical(
m.label("Range"),
m.horizontal(
[1, 0, 1],
m.inputNumber({ property: axisProperty, field: "domainMin" }),
m.label(" - ", {
addMargins: true,
}),
m.inputNumber({ property: axisProperty, field: "domainMax" })
)
)
);
}
if (data.numericalMode != "temporal") {
widgets.push(
m.inputSelect(
{ property: axisProperty, field: "numericalMode" },
{
options: ["linear", "logarithmic"],
labels: ["Linear", "Logarithmic"],
showLabel: true,
type: "dropdown",
label: "Mode",
}
)
);
}
widgets.push(
m.inputExpression(
manager.verticalGroup(
{
property: axisProperty,
field: "tickDataExpression",
header: axisName + strings.objects.axes.numericalSuffix,
},
{
label: "Tick Data",
}
)
);
widgets.push(
m.inputFormat(
{
property: axisProperty,
field: "tickFormat",
},
{
blank: strings.core.auto,
isDateField:
data.numericalMode === NumericalMode.Temporal ||
data.valueType === DataType.Date,
label: "Tick Format",
}
[
manager.sectionHeader(
axisName + strings.objects.axes.numericalSuffix,
manager.clearButton({ property: axisProperty }, null, true),
dropzoneOptions
),
manager.inputExpression(
{
property: axisProperty,
field: "expression",
},
{
label: "Data",
}
),
data.valueType === "date" ? manager.label("Range") : null,
data.valueType === "date"
? manager.inputDate(
{ property: axisProperty, field: "domainMin" },
{ label: "Start" }
)
: null,
data.valueType === "date"
? manager.inputDate(
{ property: axisProperty, field: "domainMax" },
{ label: "End" }
)
: null,
data.valueType !== "date" ? manager.label("Range") : null,
data.valueType !== "date"
? manager.inputNumber(
{ property: axisProperty, field: "domainMin" },
{ label: strings.objects.axes.from }
)
: null,
data.valueType !== "date"
? manager.inputNumber(
{ property: axisProperty, field: "domainMax" },
{ label: strings.objects.axes.to }
)
: null,
data.numericalMode != "temporal"
? manager.inputSelect(
{ property: axisProperty, field: "numericalMode" },
{
options: ["linear", "logarithmic"],
labels: ["Linear", "Logarithmic"],
showLabel: true,
type: "dropdown",
label: "Mode",
}
)
: null,
manager.inputExpression(
{
property: axisProperty,
field: "tickDataExpression",
},
{
label: "Tick Data",
}
),
manager.inputFormat(
{
property: axisProperty,
field: "tickFormat",
},
{
blank: strings.core.auto,
isDateField:
data.numericalMode === NumericalMode.Temporal ||
data.valueType === DataType.Date,
label: strings.objects.axes.tickFormat,
}
),
]
)
);
widgets.push(makeAppearance());
@ -1160,66 +1175,67 @@ export function buildAxisWidgets(
case "categorical":
{
widgets.push(
m.sectionHeader(
axisName + ": Categorical",
m.clearButton({ property: axisProperty }, null, true),
dropzoneOptions
)
);
widgets.push(
m.vertical(
m.label("Data"),
m.horizontal(
[1, 0],
m.inputExpression({
property: axisProperty,
field: "expression",
}),
m.reorderWidget(
{ property: axisProperty, field: "categories" },
{ allowReset: true }
)
)
)
);
if (data.valueType === "date") {
widgets.push(
m.inputExpression(
{
property: axisProperty,
field: "tickDataExpression",
},
{
label: "Tick Data",
}
)
);
widgets.push(
m.inputFormat(
{
property: axisProperty,
field: "tickFormat",
},
{
blank: strings.core.auto,
isDateField:
data.numericalMode === NumericalMode.Temporal ||
data.valueType === DataType.Date,
label: "Tick Format",
}
)
);
}
widgets.push(
m.inputNumber(
{ property: axisProperty, field: "gapRatio" },
manager.verticalGroup(
{
minimum: 0,
maximum: 1,
percentage: true,
showSlider: true,
label: "Gap",
}
header: axisName + ": Categorical",
},
[
manager.sectionHeader(
"Data",
manager.clearButton({ property: axisProperty }, null, true),
dropzoneOptions
),
manager.vertical(
manager.label("Data"),
manager.horizontal(
[1, 0],
manager.inputExpression({
property: axisProperty,
field: "expression",
}),
manager.reorderWidget(
{ property: axisProperty, field: "categories" },
{ allowReset: true }
)
),
manager.inputNumber(
{ property: axisProperty, field: "gapRatio" },
{
minimum: 0,
maximum: 1,
percentage: true,
showSlider: true,
label: "Gap",
}
),
data.valueType === "date"
? (manager.inputExpression(
{
property: axisProperty,
field: "tickDataExpression",
},
{
label: "Tick Data",
}
),
manager.row(
"Tick Format",
manager.inputFormat(
{
property: axisProperty,
field: "tickFormat",
},
{
blank: strings.core.auto,
isDateField:
data.numericalMode === NumericalMode.Temporal ||
data.valueType === DataType.Date,
}
)
))
: null
),
]
)
);
widgets.push(makeAppearance());
@ -1228,57 +1244,64 @@ export function buildAxisWidgets(
case "default":
{
widgets.push(
m.sectionHeader(
axisName + ": Stacking",
m.clearButton({ property: axisProperty }, null, true),
dropzoneOptions
)
);
widgets.push(
m.inputNumber(
{ property: axisProperty, field: "gapRatio" },
manager.verticalGroup(
{
minimum: 0,
maximum: 1,
percentage: true,
showSlider: true,
label: "Gap",
}
header: axisName + ": Stacking",
},
[
manager.sectionHeader(
axisName + ": Stacking",
manager.clearButton({ property: axisProperty }, null, true),
dropzoneOptions
),
manager.inputNumber(
{ property: axisProperty, field: "gapRatio" },
{
minimum: 0,
maximum: 1,
percentage: true,
showSlider: true,
label: "Gap",
}
),
]
)
);
}
break;
}
widgets.push(
m.sectionHeader(axisName + strings.objects.dataAxis.exportProperties)
);
widgets.push(
m.inputBoolean(
manager.verticalGroup(
{
property: axisProperty,
field: "autoDomainMin",
header: axisName + strings.objects.dataAxis.exportProperties,
},
{
type: "checkbox",
label: strings.objects.dataAxis.autoMin,
}
)
);
widgets.push(
m.inputBoolean(
{
property: axisProperty,
field: "autoDomainMax",
},
{
type: "checkbox",
label: strings.objects.dataAxis.autoMax,
}
[
manager.inputBoolean(
{
property: axisProperty,
field: "autoDomainMin",
},
{
type: "checkbox",
label: strings.objects.dataAxis.autoMin,
}
),
manager.inputBoolean(
{
property: axisProperty,
field: "autoDomainMax",
},
{
type: "checkbox",
label: strings.objects.dataAxis.autoMax,
}
),
]
)
);
} else {
widgets.push(
m.sectionHeader(
manager.sectionHeader(
axisName + ": " + strings.core.none,
null,
dropzoneOptions

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

@ -15,6 +15,7 @@ import {
import { AxisRenderer } from "./axis";
import { utcFormat } from "d3-time-format";
import { NumericalMode } from "../../specification/types";
import { strings } from "../../../strings";
export abstract class PlotSegmentClass<
PropertiesType extends Specification.AttributeMap = Specification.AttributeMap,
@ -98,49 +99,49 @@ export abstract class PlotSegmentClass<
return [];
}
return [
manager.sectionHeader("Gridline"),
manager.horizontal(
[1, 1],
manager.inputSelect(
{ property: axisProperty, field: ["style", "gridlineStyle"] },
{
type: "dropdown",
showLabel: true,
icons: [
"ChromeClose",
"stroke/solid",
"stroke/dashed",
"stroke/dotted",
],
options: ["none", "solid", "dashed", "dotted"],
labels: ["None", "Solid", "Dashed", "Dotted"],
label: "Style",
}
)
),
manager.horizontal(
[1, 1],
manager.inputColor(
{
property: axisProperty,
field: ["style", "gridlineColor"],
},
{
label: "Color",
}
)
),
manager.inputNumber(
manager.verticalGroup(
{
property: axisProperty,
field: ["style", "gridlineWidth"],
header: strings.objects.plotSegment.gridline,
},
{
minimum: 0,
maximum: 100,
showUpdown: true,
label: "Width",
}
[
manager.inputSelect(
{ property: axisProperty, field: ["style", "gridlineStyle"] },
{
type: "dropdown",
showLabel: true,
icons: [
"ChromeClose",
"stroke/solid",
"stroke/dashed",
"stroke/dotted",
],
options: ["none", "solid", "dashed", "dotted"],
labels: ["None", "Solid", "Dashed", "Dotted"],
label: strings.objects.style,
}
),
manager.inputColor(
{
property: axisProperty,
field: ["style", "gridlineColor"],
},
{
label: strings.objects.color,
}
),
manager.inputNumber(
{
property: axisProperty,
field: ["style", "gridlineWidth"],
},
{
minimum: 0,
maximum: 100,
showUpdown: true,
label: strings.objects.width,
}
),
]
),
];
}

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

@ -2605,18 +2605,24 @@ export class Region2DConstraintBuilder {
}
const options = this.applicableSublayoutOptions();
return [
m.sectionHeader("Sub-layout"),
m.inputSelect(
{ property: "sublayout", field: "type" },
m.verticalGroup(
{
type: "radio",
options: options.map((x) => x.value),
icons: options.map((x) => x.icon),
labels: options.map((x) => x.label),
label: "Type",
}
header: strings.objects.plotSegment.subLayout,
},
[
m.inputSelect(
{ property: "sublayout", field: "type" },
{
type: "radio",
options: options.map((x) => x.value),
icons: options.map((x) => x.icon),
labels: options.map((x) => x.label),
label: strings.objects.plotSegment.type,
}
),
...extra,
]
),
...extra,
];
}

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

@ -582,22 +582,22 @@ export class CurvePlotSegment extends PlotSegmentClass<
const builder = this.createBuilder();
return [
...super.getAttributePanelWidgets(manager),
manager.sectionHeader("Curve Coordinates"),
manager.vertical(
manager.label("Normal"),
manager.horizontal(
[1, 0, 1],
manager.inputNumber({ property: "normalStart" }),
manager.label("-"),
manager.inputNumber({ property: "normalEnd" })
)
manager.verticalGroup(
{
header: strings.objects.plotSegment.curveCoordinates,
},
[
manager.vertical(
manager.label(strings.objects.plotSegment.normal),
manager.horizontal(
[1, 0, 1],
manager.inputNumber({ property: "normalStart" }),
manager.label("-"),
manager.inputNumber({ property: "normalEnd" })
)
),
]
),
// manager.row("Radius", manager.horizontal([0, 1, 0, 1],
// manager.label("Inner:"),
// manager.inputNumber({ property: "innerRatio" }),
// manager.label("Outer:"),
// manager.inputNumber({ property: "outerRatio" })
// )),
...builder.buildPanelWidgets(manager),
];
}

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

@ -773,33 +773,39 @@ export class PolarPlotSegment extends PlotSegmentClass<
const builder = this.createBuilder();
return [
...super.getAttributePanelWidgets(manager),
manager.sectionHeader("Polar Coordinates"),
manager.vertical(
manager.label("Angle"),
manager.horizontal(
[1, 0, 1],
manager.inputNumber({ property: "startAngle" }),
manager.label("-"),
manager.inputNumber({ property: "endAngle" })
)
),
manager.vertical(
manager.label("Radius"),
manager.horizontal(
[0, 1, 0, 1],
manager.label("Inner:"),
manager.inputNumber({ property: "innerRatio" }),
manager.label("Outer:"),
manager.inputNumber({ property: "outerRatio" })
)
),
manager.inputBoolean(
{ property: "equalizeArea" },
manager.verticalGroup(
{
type: "checkbox",
label: "Height to Area",
headerLabel: "Equalize area",
}
header: strings.objects.plotSegment.polarCoordinates,
},
[
manager.vertical(
manager.label(strings.objects.plotSegment.angle),
manager.horizontal(
[1, 0, 1],
manager.inputNumber({ property: "startAngle" }),
manager.label("-"),
manager.inputNumber({ property: "endAngle" })
)
),
manager.vertical(
manager.label(strings.objects.plotSegment.radius),
manager.horizontal(
[0, 1, 0, 1],
manager.label(strings.objects.plotSegment.inner),
manager.inputNumber({ property: "innerRatio" }),
manager.label(strings.objects.plotSegment.outer),
manager.inputNumber({ property: "outerRatio" })
)
),
manager.inputBoolean(
{ property: "equalizeArea" },
{
type: "checkbox",
label: strings.objects.plotSegment.heightToArea,
headerLabel: strings.objects.plotSegment.equalizeArea,
}
),
]
),
...builder.buildPanelWidgets(manager),
];

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

@ -2462,7 +2462,7 @@ export function initializeIcons(
"sublayout/jitter": (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 32 32"
viewBox="0 0 16 16"
width="16"
height="16"
style={{
@ -2483,6 +2483,123 @@ export function initializeIcons(
/>
</svg>
),
"sublayout/polar-grid": (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
width="16"
height="16"
style={{
fill: "#0078d4",
strokeWidth: 0.1,
}}
>
<g>
<path
d="M10.766,1.558c0.242,0.038,0.483,0.082,0.723,0.13C11.249,1.64,11.008,1.596,10.766,1.558L10.766,1.558z M11.489,1.688
c0.317,0.064,0.632,0.137,0.945,0.218C12.121,1.825,11.806,1.752,11.489,1.688L11.489,1.688z"
/>
<path d="M14.353,2.521c0.524,0.202,1.042,0.422,1.548,0.676C15.395,2.943,14.877,2.722,14.353,2.521L14.353,2.521z" />
<path
d="M5.234,1.558C4.992,1.596,4.751,1.64,4.511,1.688C4.751,1.64,4.992,1.596,5.234,1.558L5.234,1.558z M4.511,1.688
C4.194,1.752,3.879,1.825,3.566,1.906C3.879,1.825,4.194,1.752,4.511,1.688L4.511,1.688z"
/>
<path d="M1.647,2.521C1.123,2.722,0.605,2.943,0.098,3.197C0.605,2.943,1.123,2.723,1.647,2.521L1.647,2.521z" />
<path
d="M3.398,1.95c-0.321,0.086-0.639,0.18-0.956,0.284C2.759,2.131,3.078,2.037,3.398,1.95L3.398,1.95z M2.443,2.235
C2.238,2.302,2.034,2.373,1.831,2.448C2.034,2.373,2.238,2.302,2.443,2.235L2.443,2.235z"
/>
<path
d="M12.602,1.95c0.321,0.086,0.639,0.181,0.956,0.284C13.241,2.131,12.922,2.036,12.602,1.95L12.602,1.95z M13.557,2.235
c0.205,0.067,0.409,0.138,0.611,0.214C13.966,2.373,13.762,2.302,13.557,2.235L13.557,2.235z"
/>
<path
d="M7.299,13.415c-0.04,0.005-0.08,0.011-0.12,0.017C7.218,13.425,7.259,13.42,7.299,13.415L7.299,13.415z M7.179,13.431
c-0.125,0.019-0.25,0.042-0.373,0.069C6.929,13.474,7.053,13.45,7.179,13.431L7.179,13.431z"
/>
<path d="M9.937,13.713c0.197,0.073,0.391,0.154,0.581,0.249C10.329,13.868,10.134,13.786,9.937,13.713L9.937,13.713z" />
<path d="M6.063,13.713c-0.197,0.072-0.391,0.154-0.581,0.249C5.672,13.868,5.866,13.786,6.063,13.713L6.063,13.713z" />
<path
d="M6.673,13.529c-0.079,0.019-0.158,0.041-0.236,0.064C6.516,13.57,6.594,13.548,6.673,13.529L6.673,13.529z M6.438,13.593
c-0.082,0.024-0.163,0.05-0.244,0.078C6.275,13.644,6.356,13.617,6.438,13.593L6.438,13.593z"
/>
<path
d="M9.327,13.529c0.079,0.019,0.158,0.041,0.236,0.064C9.484,13.57,9.406,13.548,9.327,13.529L9.327,13.529z M9.562,13.593
c0.082,0.024,0.163,0.051,0.244,0.078C9.725,13.643,9.644,13.617,9.562,13.593L9.562,13.593z"
/>
<path
d="M8.701,13.415c0.04,0.005,0.08,0.011,0.12,0.017C8.781,13.425,8.741,13.42,8.701,13.415L8.701,13.415z M8.821,13.431
c0.125,0.019,0.249,0.043,0.373,0.069C9.071,13.474,8.947,13.45,8.821,13.431L8.821,13.431z"
/>
<path d="M10.748,1.556c0.006,0.001,0.012,0.002,0.018,0.003C10.76,1.557,10.754,1.556,10.748,1.556L10.748,1.556z" />
<path
d="M9.806,13.671c0.023,0.008,0.047,0.015,0.07,0.022C9.853,13.686,9.83,13.679,9.806,13.671L9.806,13.671z M9.877,13.693
c0.02,0.006,0.041,0.013,0.061,0.02C9.917,13.706,9.897,13.7,9.877,13.693L9.877,13.693z"
/>
<path
d="M14.169,2.448c0.026,0.01,0.053,0.02,0.079,0.031C14.221,2.469,14.195,2.458,14.169,2.448L14.169,2.448z M14.248,2.479
c0.035,0.014,0.07,0.028,0.106,0.042C14.318,2.507,14.283,2.493,14.248,2.479L14.248,2.479z"
/>
<path d="M8.571,13.401c0.044,0.004,0.087,0.008,0.131,0.014C8.658,13.409,8.614,13.405,8.571,13.401L8.571,13.401z" />
<path
d="M9.195,13.501c0.023,0.005,0.046,0.01,0.069,0.014C9.241,13.51,9.218,13.506,9.195,13.501L9.195,13.501z M9.264,13.515
c0.021,0.004,0.042,0.009,0.063,0.014C9.306,13.524,9.285,13.519,9.264,13.515L9.264,13.515z"
/>
<path
d="M12.434,1.906c0.034,0.009,0.068,0.018,0.102,0.027C12.502,1.924,12.468,1.915,12.434,1.906L12.434,1.906z M12.536,1.933
c0.022,0.006,0.044,0.012,0.065,0.018C12.58,1.944,12.558,1.939,12.536,1.933L12.536,1.933z"
/>
<path
d="M9.921,2.453c0.229,0.026,0.459,0.057,0.69,0.093c0.504,0.079,1.033,0.189,1.572,0.328l0.159,0.042
c0.506,0.135,1.003,0.293,1.477,0.469l0.081,0.032l0.094,0.037c0.191,0.073,0.374,0.147,0.55,0.22l-1.319,2.639
c-1.099-0.449-2.26-0.751-3.469-0.901L9.921,2.453 M8.979,1.369L8.704,6.322c1.714,0.095,3.414,0.514,4.985,1.3l2.212-4.425
c-0.507-0.253-1.025-0.475-1.548-0.676c-0.062-0.024-0.123-0.05-0.185-0.073c-0.516-0.191-1.039-0.357-1.567-0.498
c-0.056-0.015-0.112-0.03-0.167-0.044c-0.551-0.142-1.108-0.26-1.668-0.348c-0.006-0.001-0.012-0.002-0.018-0.003
C10.162,1.464,9.571,1.402,8.979,1.369L8.979,1.369z"
/>
<path
d="M9.527,9.537c0.639,0.099,1.256,0.258,1.848,0.477l-1.34,2.679c-0.156-0.051-0.313-0.097-0.473-0.136l-0.153-0.033
c-0.016-0.003-0.032-0.007-0.047-0.01L9.527,9.537 M8.587,8.435l-0.274,4.938c0.087,0.005,0.172,0.019,0.258,0.028
c0.044,0.004,0.087,0.008,0.131,0.014c0.166,0.021,0.33,0.05,0.494,0.086c0.044,0.01,0.088,0.017,0.132,0.028
c0.162,0.04,0.321,0.088,0.48,0.142c0.044,0.015,0.088,0.026,0.131,0.042c0.197,0.073,0.391,0.154,0.581,0.249l2.222-4.445
C11.432,8.863,10.015,8.514,8.587,8.435L8.587,8.435z"
/>
<path
d="M6.805,13.501c-0.023,0.005-0.046,0.01-0.069,0.014C6.759,13.51,6.782,13.506,6.805,13.501L6.805,13.501z M6.736,13.515
c-0.021,0.004-0.042,0.009-0.063,0.014C6.694,13.524,6.715,13.519,6.736,13.515L6.736,13.515z"
/>
<path d="M7.429,13.401c-0.044,0.004-0.087,0.008-0.131,0.014C7.342,13.409,7.386,13.405,7.429,13.401L7.429,13.401z" />
<path
d="M6.194,13.671c-0.023,0.008-0.047,0.015-0.07,0.022C6.147,13.686,6.17,13.679,6.194,13.671L6.194,13.671z M6.123,13.693
c-0.02,0.006-0.041,0.013-0.061,0.02C6.083,13.706,6.103,13.7,6.123,13.693L6.123,13.693z"
/>
<path d="M5.252,1.556C5.246,1.556,5.24,1.557,5.234,1.558C5.24,1.557,5.246,1.556,5.252,1.556L5.252,1.556z" />
<path
d="M3.566,1.906C3.532,1.915,3.498,1.924,3.464,1.933C3.498,1.924,3.532,1.915,3.566,1.906L3.566,1.906z M3.464,1.933
C3.442,1.939,3.42,1.944,3.398,1.95C3.42,1.944,3.442,1.939,3.464,1.933L3.464,1.933z"
/>
<path
d="M1.831,2.448c-0.026,0.01-0.053,0.02-0.079,0.031C1.779,2.469,1.805,2.458,1.831,2.448L1.831,2.448z M1.752,2.479
c-0.035,0.014-0.07,0.028-0.106,0.042C1.682,2.507,1.717,2.493,1.752,2.479L1.752,2.479z"
/>
<path
d="M6.079,2.453l0.164,2.96c-1.209,0.151-2.37,0.452-3.469,0.901L1.456,3.675c0.176-0.074,0.359-0.147,0.55-0.221l0.093-0.037
l0.08-0.031c0.475-0.176,0.972-0.334,1.479-0.47l0.157-0.042c0.541-0.139,1.07-0.249,1.591-0.331
C5.629,2.509,5.854,2.478,6.079,2.453 M7.021,1.369C6.429,1.402,5.838,1.464,5.252,1.556C5.246,1.556,5.24,1.557,5.234,1.558
c-0.56,0.088-1.117,0.206-1.668,0.348C3.51,1.92,3.454,1.935,3.398,1.95C2.87,2.092,2.347,2.257,1.831,2.448
C1.769,2.471,1.708,2.497,1.647,2.521C1.123,2.722,0.605,2.943,0.098,3.197l2.212,4.425c1.571-0.786,3.271-1.205,4.985-1.3
L7.021,1.369L7.021,1.369z"
/>
<path
d="M6.473,9.537l0.165,2.977c-0.027,0.006-0.054,0.011-0.082,0.018l-0.12,0.026c-0.154,0.038-0.306,0.082-0.471,0.135
l-1.339-2.679C5.217,9.795,5.834,9.636,6.473,9.537 M7.413,8.435C5.985,8.514,4.568,8.863,3.259,9.518l2.222,4.445
c0.19-0.095,0.385-0.177,0.581-0.249c0.043-0.016,0.088-0.028,0.131-0.042c0.158-0.054,0.318-0.103,0.48-0.142
c0.044-0.011,0.088-0.018,0.132-0.028c0.163-0.036,0.328-0.065,0.494-0.086c0.044-0.005,0.087-0.01,0.131-0.014
c0.086-0.009,0.172-0.023,0.258-0.028L7.413,8.435L7.413,8.435z"
/>
</g>
</svg>
),
},
};

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

@ -328,10 +328,12 @@ export const strings = {
bottom: "Bottom",
},
objects: {
general: "General",
contextMenu: "Context menu",
interactivity: "Interactivity",
colors: "Colors",
color: "Color",
outline: "Outline",
dimensions: "Dimensions",
scale: "Scale",
width: "Width",
@ -342,9 +344,45 @@ export const strings = {
size: "Size",
axis: "Axis",
style: "Style",
rotation: "Rotation",
anchorAndRotation: "Anchor & Rotation",
fill: "Fill",
strokeWidth: "Line Width",
stroke: "Stroke",
anchorX: "Anchor X",
anchorY: "Anchor Y",
alignX: "Align X",
alignY: "Align Y",
layout: "Layout",
appearance: "Appearance",
invalidFormat: "Invalid format",
axes: {
numericalSuffix: ": Numerical",
categoricalSuffix: ": Categorical",
tickFormat: "Tick Format",
from: "from",
to: "to",
gap: "Gap",
direction: "Direction",
count: "Count",
dataExpressions: "Data Expressions",
},
plotSegment: {
subLayout: "Sub-layout",
type: "Type",
gridline: "Gridline",
polarCoordinates: "Polar Coordinates",
heightToArea: "Height to Area",
equalizeArea: "Equalize area",
inner: "Inner:",
outer: "Outer:",
radius: "Radius",
angle: "Angle",
curveCoordinates: "Curve Coordinates",
normal: "Normal",
groupBy: "Group by...",
groupByCategory: "Group by ",
},
visibleOn: {
visibility: "Visibility",
label: "Visible On",
@ -371,6 +409,7 @@ export const strings = {
markerShape: "Shape",
labels: "Labels",
layout: "Layout",
categoricalLegend: "Categorical legend",
},
links: {
lineType: "Line Type",
@ -384,6 +423,9 @@ export const strings = {
linkMarkType: "Line mark type",
curveness: "Curveness",
},
line: {
lineStyle: "Line Style",
},
anchor: {
label: "(drag the anchor in the glyph editor)",
},
@ -402,16 +444,13 @@ export const strings = {
icon: {
label: "Icon",
image: "Image",
anchorAndRotation: "Anchor & Rotation",
anchorX: "Anchor X",
anchorY: "Anchor Y",
},
image: {
imageMode: "Resize Mode",
letterbox: "Letterbox",
stretch: "Stretch",
dropImage: "Drop Image Here",
defaultPlaceholder: "Drop/Paste Image"
defaultPlaceholder: "Drop/Paste Image",
},
scales: {
mode: "Mode",
@ -420,5 +459,17 @@ export const strings = {
interval: "Interval",
inclusive: "Inclusive",
},
text: {
margin: "Margin",
},
rect: {
shape: "Shape",
flipping: "Flipping",
shapes: {
rectangle: "Rectangle",
triangle: "Triangle",
ellipse: "Ellipse",
},
},
},
};