* Fixed minor axis scrolling issues

* Removed log

* Added unique key for identical data

* Fixed scrolling windowSize issue

* Fixed save order in axis

* Fixed data inputExpression

* Fixed date column

* Fixed issue with numeric axis (Initial scroll position)

* Fixed issue with scroll bar

* Removed log

* Remove unused code

* Remove unused code

* Remove commented code

* Updated version

Co-authored-by: Ramil Minyukov (Akvelon INC) <v-rminyukov@microsoft.com>
This commit is contained in:
Ramil Minyukov 2021-12-07 17:41:39 +03:00 коммит произвёл GitHub
Родитель ccb2154620
Коммит 51f4f55dad
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 161 добавлений и 111 удалений

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

@ -1,6 +1,6 @@
{
"name": "charticulator",
"version": "2.1.2",
"version": "2.1.3",
"private": true,
"author": {
"name": "Donghao Ren",

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

@ -437,7 +437,7 @@
&.is-top {
top: -1px;
bottom: none;
bottom: unset;
}
}
}
@ -763,6 +763,14 @@
flex: 1 1;
}
&-no-height {
height: unset;
line-height: unset;
display: flex;
flex-direction: row;
margin: 2px 0;
}
&-dropzone {
transition: background $transition-default;
@ -1145,51 +1153,6 @@
// border: 1px solid $gray-200;
}
&-updown-button {
display: inline-block;
vertical-align: top;
width: calc($line-height / 2 + 4px);
height: $line-height;
display: flex;
flex-direction: column;
.el-part {
display: block;
width: math.div($line-height, 2);
height: math.div($line-height, 2);
padding: 0 2px;
.el-svg-icon {
width: math.div($line-height, 2);
height: math.div($line-height, 2);
filter: invert(40%);
}
&:first-child {
.el-svg-icon {
margin-top: 2px;
}
}
&:last-child {
.el-svg-icon {
margin-top: -2px;
}
}
cursor: pointer;
border-radius: 2px;
&:hover {
background: $color-primary;
.el-svg-icon {
filter: invert(100%);
}
}
}
}
&-button {
display: inline-block;
vertical-align: top;

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

@ -1938,8 +1938,13 @@ export class AppStore extends BaseStore {
dataBinding.order = order != undefined ? order : null;
dataBinding.allCategories = deepClone(categories);
if (dataBinding.windowSize == null) {
dataBinding.windowSize = Math.ceil(categories.length / 10);
if (
dataBinding.windowSize == null ||
dataBinding.windowSize > dataBinding.allCategories.length
) {
dataBinding.windowSize =
dataBinding.allCategories?.length ??
Math.ceil(categories.length / 10);
}
dataBinding.categories = categories;
if (dataBinding.allowScrolling) {

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

@ -687,6 +687,7 @@ export class Migrator {
element.properties.xData.style.showBaseline = true;
}
element.properties.xData.offset = 0;
element.properties.xData.barOffset = 0;
if (element.properties.xData.orderByCategories == undefined) {
element.properties.xData.orderByCategories =
element.properties.xData.categories;
@ -711,6 +712,7 @@ export class Migrator {
element.properties.yData.style.showBaseline = true;
}
element.properties.yData.offset = 0;
element.properties.yData.barOffset = 0;
if (element.properties.yData.orderByCategories == undefined) {
element.properties.yData.orderByCategories =
element.properties.yData.categories;
@ -739,6 +741,7 @@ export class Migrator {
element.properties.xData.style.showBaseline = true;
}
element.properties.xData.offset = 0;
element.properties.xData.barOffset = 0;
if (element.properties.xData.orderByCategories == undefined) {
element.properties.xData.orderByCategories =
element.properties.xData.categories;
@ -771,6 +774,7 @@ export class Migrator {
);
}
element.properties.yData.offset = 0;
element.properties.yData.barOffset = 0;
element.properties.yData.enableSelection = true;
}
if (element.properties.yData === undefined) {
@ -795,6 +799,7 @@ export class Migrator {
);
}
element.properties.axis.enableSelection = true;
element.properties.axis.barOffset = 0;
}
}
if (
@ -810,6 +815,7 @@ export class Migrator {
element.properties.xData.style.showBaseline = true;
}
element.properties.xData.offset = 0;
element.properties.xData.barOffset = 0;
if (element.properties.xData.orderByCategories == undefined) {
element.properties.xData.orderByCategories =
element.properties.xData.categories;
@ -842,6 +848,7 @@ export class Migrator {
);
}
element.properties.yData.offset = 0;
element.properties.yData.barOffset = 0;
element.properties.yData.enableSelection = true;
}
if (element.properties.yData === undefined) {
@ -865,6 +872,7 @@ export class Migrator {
);
}
element.properties.axis.enableSelection = true;
element.properties.axis.barOffset = 0;
if (element.properties.axis?.style) {
element.properties.axis.style.showBaseline = true;

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

@ -7,6 +7,7 @@ import { ButtonRaised } from "../../../../components";
import { strings } from "../../../../../strings";
import { DefaultButton } from "@fluentui/react";
import { defultComponentsHeight } from "./fluentui_customized_components";
import { getRandomNumber } from "../../../../../core";
interface ReorderStringsValueProps {
items: string[];
@ -49,7 +50,7 @@ export class FluentUIReorderStringsValue extends React.Component<
}}
>
{items.map((x) => (
<div key={x} className="el-item">
<div key={x + getRandomNumber()} className="el-item">
{x}
</div>
))}

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

@ -675,6 +675,9 @@ export class FluentUIWidgetManager
this.emitSetProperty(property, v);
}
this.defaultNotification(options.observerConfig);
if (options.onChange && !v) {
options.onChange(v);
}
}}
/>
</FluentCheckbox>
@ -882,12 +885,14 @@ export class FluentUIWidgetManager
public clearButton(
property: Prototypes.Controls.Property,
icon?: string,
isHeader?: boolean
isHeader?: boolean,
styles?: CSSProperties
) {
return (
<FluentButton
key={this.getKeyFromProperty(property)}
marginTop={isHeader ? "0px" : null}
style={styles}
>
<DefaultButton
styles={{
@ -1039,7 +1044,7 @@ export class FluentUIWidgetManager
<FluentButton
ref={(e) => (container = e)}
key={this.getKeyFromProperty(property)}
marginTop={"0px"}
marginTop={"1px"}
paddingRight={"0px"}
>
<DefaultButton
@ -1336,6 +1341,9 @@ export class FluentUIWidgetManager
);
const menuRender = this.director.getMenuRender();
const className = options.noLineHeight
? "charticulator__widget-section-header-no-height charticulator__widget-section-header-dropzone"
: "charticulator__widget-section-header charticulator__widget-section-header-dropzone";
return (
<DropZoneView
key={title}
@ -1349,7 +1357,7 @@ export class FluentUIWidgetManager
true
).dispatch(this.store.dispatcher);
}}
className="charticulator__widget-section-header charticulator__widget-section-header-dropzone"
className={className}
draggingHint={() => (
<span className="el-dropzone-hint">{options.dropzone.prompt}</span>
)}
@ -1410,6 +1418,25 @@ export class FluentUIWidgetManager
);
}
public styledHorizontal(
styles: CSSProperties,
cols: number[],
...widgets: JSX.Element[]
) {
return (
<div className="charticulator__widget-horizontal" style={styles}>
{widgets.map((x, id) => (
<span
className={`el-layout-item el-layout-item-col-${cols[id]}`}
key={id}
>
{x}
</span>
))}
</div>
);
}
public filterEditor(
options: Prototypes.Controls.FilterEditorOptions
): JSX.Element {
@ -1695,52 +1722,18 @@ export class FluentUIWidgetManager
<PopupView context={context}>
<FluentUIReorderStringsValue
items={items}
onConfirm={(items, customOrder, sortOrder) => {
onConfirm={(items) => {
this.emitSetProperty(property, items);
if (options.onConfirmClick) {
options.onConfirmClick(items);
}
if (customOrder) {
this.emitSetProperty(
{
property: property.property,
field: "orderMode",
},
OrderMode.order
);
this.emitSetProperty(
{
property: property.property,
field: "order",
},
items
);
} else {
if (sortOrder) {
this.emitSetProperty(
{
property: property.property,
field: "orderMode",
},
OrderMode.alphabetically
);
} else {
this.emitSetProperty(
{
property: property.property,
field: "orderMode",
},
OrderMode.order
);
this.emitSetProperty(
{
property: property.property,
field: "order",
},
items
);
}
}
this.emitSetProperty(
{
property: property.property,
field: "orderMode",
},
OrderMode.order
);
context.close();
}}
onReset={() => {

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

@ -1233,6 +1233,10 @@ export class WidgetManager
reorderByAnotherColumnWidget(): JSX.Element {
throw new Error("Method not implemented.");
}
styledHorizontal(): JSX.Element {
throw new Error("Method not implemented.");
}
}
export interface DropZoneViewProps {

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

@ -69,6 +69,7 @@ export interface InputBooleanOptions {
label?: string;
observerConfig?: ObserverConfig;
checkBoxStyles?: ICheckboxStyles;
onChange?: (value: boolean) => void;
}
export interface RowOptions {
@ -78,6 +79,7 @@ export interface RowOptions {
property?: string;
defineCategories?: boolean;
};
noLineHeight?: boolean;
}
export interface DropTargetOptions {
@ -307,7 +309,12 @@ export interface WidgetManager {
inputColorGradient(property: Property, inline?: boolean): Widget;
// A button, once clicked, set the property to null.
clearButton(property: Property, icon?: string, isHeader?: boolean): Widget;
clearButton(
property: Property,
icon?: string,
isHeader?: boolean,
styles?: CSSProperties
): Widget;
setButton(
property: Property,
value: Specification.AttributeValue,
@ -354,6 +361,12 @@ export interface WidgetManager {
// Basic layout elements
horizontal(cols: number[], ...widgets: Widget[]): Widget;
styledHorizontal(
styles: CSSProperties,
cols: number[],
...widgets: Widget[]
): Widget;
verticalGroup(options: VerticalGroupOptions, ...widgets: Widget[]): Widget;
vertical(...widgets: Widget[]): Widget;
table(rows: Widget[][], options?: TableOptions): Widget;

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

@ -9,8 +9,8 @@ import {
fillDefaults,
Geometry,
getFormat,
makeRange,
getRandomNumber,
makeRange,
replaceSymbolByNewLine,
replaceSymbolByTab,
rgbToHex,
@ -146,15 +146,29 @@ export class AxisRenderer {
this.oppositeSide = data.side == "opposite";
this.scrollRequired = data.allowScrolling;
this.shiftAxis =
data.allowScrolling &&
(data.barOffset == null || data.barOffset === 0) &&
((data.allCategories && data.windowSize < data.allCategories?.length) ||
Math.abs(data.dataDomainMax - data.dataDomainMin) > data.windowSize);
this.dataType = data.type;
if (data.allCategories && data.windowSize < data.allCategories?.length) {
this.hiddenCategoriesRatio = data.windowSize / data.allCategories.length;
if (this.shiftAxis) {
this.hiddenCategoriesRatio =
data.windowSize /
(data.allCategories
? data.allCategories.length
: Math.abs(data.dataDomainMax - data.dataDomainMin));
this.handlerSize = rangeMax / this.hiddenCategoriesRatio;
this.windowSize = data.windowSize;
if (
data.windowSize > data.allCategories?.length ||
data.windowSize > Math.abs(data.dataDomainMax - data.dataDomainMin)
) {
this.windowSize = data.allCategories
? data.allCategories.length
: Math.abs(data.dataDomainMax - data.dataDomainMin);
} else {
this.windowSize = data.windowSize;
}
}
switch (data.type) {
@ -499,6 +513,7 @@ export class AxisRenderer {
if (this.oppositeSide) {
side = -side;
}
//shift axis for scrollbar space
if (this.scrollRequired && this.shiftAxis) {
if (angle === 90) {
@ -1444,6 +1459,7 @@ export function buildAxisAppearanceWidgets(
{
label: strings.objects.axes.tickTextBackgroudColor,
labelKey: strings.objects.axes.tickTextBackgroudColor,
allowNull: true,
}
),
manager.inputFormat(
@ -1542,7 +1558,8 @@ export function buildAxisWidgets(
axisProperty: string,
manager: Controls.WidgetManager,
axisName: string,
showOffset: boolean = true
showOffset: boolean = true,
onChange?: () => void
): Controls.Widget[] {
const widgets = [];
const dropzoneOptions: Controls.RowOptions = {
@ -1551,6 +1568,7 @@ export function buildAxisWidgets(
property: axisProperty,
prompt: axisName + ": " + strings.objects.dropData,
},
noLineHeight: true,
};
const makeAppearance = () => {
return buildAxisAppearanceWidgets(axisProperty, manager, {
@ -1560,6 +1578,7 @@ export function buildAxisWidgets(
});
};
if (data != null) {
const isDateExpression = data.expression.includes("date.");
switch (data.type) {
case "numerical":
{
@ -1575,7 +1594,10 @@ export function buildAxisWidgets(
// dropzoneOptions
// ),
manager.label(strings.objects.axes.data),
manager.horizontal(
manager.styledHorizontal(
{
alignItems: "start",
},
[1, 0],
manager.sectionHeader(
null,
@ -1588,7 +1610,9 @@ export function buildAxisWidgets(
),
dropzoneOptions
),
manager.clearButton({ property: axisProperty }, null, true)
manager.clearButton({ property: axisProperty }, null, true, {
marginTop: "1px",
})
),
data.valueType === "date"
? manager.label(strings.objects.dataAxis.range)
@ -1715,6 +1739,7 @@ export function buildAxisWidgets(
},
value: 10,
},
onChange: onChange,
}
),
data.allowScrolling
@ -1764,7 +1789,10 @@ export function buildAxisWidgets(
// ),
// manager.vertical(
manager.label(strings.objects.axes.data),
manager.horizontal(
manager.styledHorizontal(
{
alignItems: "start",
},
[1, 0],
manager.sectionHeader(
null,
@ -1777,10 +1805,20 @@ export function buildAxisWidgets(
),
dropzoneOptions
),
manager.clearButton({ property: axisProperty }, null, true)
isDateExpression
? manager.reorderWidget(
{ property: axisProperty, field: "categories" },
{ allowReset: true }
)
: null,
manager.clearButton({ property: axisProperty }, null, true, {
marginTop: "1px",
})
),
...getOrderByAnotherColumnWidgets(data, axisProperty, manager),
!isDateExpression
? getOrderByAnotherColumnWidgets(data, axisProperty, manager)
: null,
manager.inputNumber(
{ property: axisProperty, field: "gapRatio" },
@ -1835,6 +1873,7 @@ export function buildAxisWidgets(
},
value: 10,
},
onChange: onChange,
}
),
data.allowScrolling

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

@ -22,6 +22,7 @@ import {
import { PlotSegmentClass } from "../plot_segment";
import { strings } from "./../../../../strings";
import { ChartStateManager } from "../../state";
export enum Region2DSublayoutType {
Overlap = "overlap",
@ -273,7 +274,8 @@ export class Region2DConstraintBuilder {
public y1Name: string,
public y2Name: string,
public solver?: ConstraintSolver,
public solverContext?: BuildConstraintsContext
public solverContext?: BuildConstraintsContext,
public chartStateManager?: ChartStateManager
) {}
public static defaultJitterPackingRadius = 5;
@ -2753,7 +2755,14 @@ export class Region2DConstraintBuilder {
return [
manager.customCollapsiblePanel(
[
...buildAxisWidgets(data, axisProperty, manager, axisName),
...buildAxisWidgets(
data,
axisProperty,
manager,
axisName,
false,
this.updatePlotSegment.bind(this)
),
...this.plotSegment.buildGridLineWidgets(data, manager, axisProperty),
],
{
@ -2766,6 +2775,12 @@ export class Region2DConstraintBuilder {
];
}
public updatePlotSegment() {
if (this.chartStateManager && this.plotSegment) {
this.chartStateManager.remapPlotSegmentGlyphs(this.plotSegment.object);
}
}
public buildPanelWidgets(m: Controls.WidgetManager): Controls.Widget[] {
const { terminology } = this.config;
if (this.isSublayoutApplicable()) {

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

@ -140,6 +140,8 @@ export class CartesianPlotSegment extends PlotSegmentClass<
public readonly state: CartesianState;
public chartManager: ChartStateManager;
public attributeNames: string[] = [
"x1",
"x2",
@ -211,7 +213,8 @@ export class CartesianPlotSegment extends PlotSegmentClass<
"y1",
"y2",
solver,
context
context,
this.chartManager
);
return builder;
}
@ -309,6 +312,7 @@ export class CartesianPlotSegment extends PlotSegmentClass<
}
public getGraphics(manager: ChartStateManager): Graphics.Group {
this.chartManager = manager;
const g = Graphics.makeGroup([]);
const props = this.object.properties;
if (props.xData && props.xData.visible) {
@ -328,6 +332,7 @@ export class CartesianPlotSegment extends PlotSegmentClass<
axis: Specification.Types.AxisDataBinding,
manager: ChartStateManager
) => {
this.chartManager = manager;
const table = manager.getTable(this.object.table);
const axisExpression = manager.dataflow.cache.parse(axis.expression);
const tickDataExpression = manager.dataflow.cache.parse(
@ -346,6 +351,7 @@ export class CartesianPlotSegment extends PlotSegmentClass<
private getPlotSegmentAxisXDataGraphics(
manager: ChartStateManager
): Graphics.Group {
this.chartManager = manager;
const g = Graphics.makeGroup([]);
const attrs = this.state.attributes;
const props = this.object.properties;
@ -383,6 +389,7 @@ export class CartesianPlotSegment extends PlotSegmentClass<
private getPlotSegmentAxisYDataGraphics(
manager: ChartStateManager
): Graphics.Group {
this.chartManager = manager;
const g = Graphics.makeGroup([]);
const attrs = this.state.attributes;
const props = this.object.properties;
@ -422,6 +429,7 @@ export class CartesianPlotSegment extends PlotSegmentClass<
public getPlotSegmentBackgroundGraphics(
manager: ChartStateManager
): Graphics.Group {
this.chartManager = manager;
const g = Graphics.makeGroup([]);
const attrs = this.state.attributes;
const props = this.object.properties;
@ -481,6 +489,7 @@ export class CartesianPlotSegment extends PlotSegmentClass<
manager: ChartStateManager,
zoom: ZoomInfo
): React.ReactElement<any>[] {
this.chartManager = manager;
const attrs = this.state.attributes;
const props = this.object.properties;
const g = [];
@ -541,8 +550,8 @@ export class CartesianPlotSegment extends PlotSegmentClass<
.range([props.xData.dataDomainMin, props.xData.dataDomainMax]);
props.xData.scrollPosition = position;
const start = scale(position);
props.xData.domainMin = start;
props.xData.domainMax = start + props.xData.windowSize;
props.xData.domainMin = start - props.xData.windowSize;
props.xData.domainMax = start;
}
manager.remapPlotSegmentGlyphs(this.object);
manager.solveConstraints();