Merge branch 'master' into feature/categorical-gridlines
This commit is contained in:
Коммит
ade06dd85b
|
@ -27,6 +27,7 @@ import { DataAxisExpression } from "../core/prototypes/marks/data_axis.attrs";
|
|||
import { MappingType, ScaleMapping, ValueMapping } from "../core/specification";
|
||||
import { Region2DSublayoutOptions } from "../core/prototypes/plot_segments/region_2d/base";
|
||||
import { GuideAttributeNames } from "../core/prototypes/guides";
|
||||
import { scaleLinear } from "d3-scale";
|
||||
|
||||
export interface TemplateInstance {
|
||||
chart: Specification.Chart;
|
||||
|
@ -477,13 +478,25 @@ export class ChartTemplate {
|
|||
const scale = new Scale.LinearScale();
|
||||
scale.inferParameters(vector);
|
||||
if (inference.autoDomainMin) {
|
||||
axisDataBinding.domainMin = scale.domainMin;
|
||||
axisDataBinding.dataDomainMin = scale.domainMin;
|
||||
}
|
||||
if (inference.autoDomainMax) {
|
||||
axisDataBinding.domainMax = scale.domainMax;
|
||||
axisDataBinding.dataDomainMax = scale.domainMax;
|
||||
}
|
||||
if (axisDataBinding.allowScrolling) {
|
||||
const scrollScale = scaleLinear()
|
||||
.domain([0, 100])
|
||||
.range([
|
||||
axisDataBinding.dataDomainMin,
|
||||
axisDataBinding.dataDomainMax,
|
||||
]);
|
||||
const start = scrollScale(axisDataBinding.scrollPosition);
|
||||
axisDataBinding.domainMin = start;
|
||||
axisDataBinding.domainMax = start + axisDataBinding.windowSize;
|
||||
} else {
|
||||
axisDataBinding.domainMin = scale.domainMin;
|
||||
axisDataBinding.domainMax = scale.domainMax;
|
||||
}
|
||||
if (axis.defineCategories) {
|
||||
axisDataBinding.categories = defineCategories(vector);
|
||||
}
|
||||
|
|
|
@ -117,7 +117,10 @@ export class AxisRenderer {
|
|||
this.setStyle(data.style);
|
||||
this.oppositeSide = data.side == "opposite";
|
||||
this.scrollRequired = data.allowScrolling;
|
||||
this.shiftAxis = data.barOffset == null || data.barOffset === 0;
|
||||
this.shiftAxis =
|
||||
(data.barOffset == null || data.barOffset === 0) &&
|
||||
((data.allCategories && data.windowSize < data.allCategories.length) ||
|
||||
Math.abs(data.dataDomainMax - data.dataDomainMin) > data.windowSize);
|
||||
switch (data.type) {
|
||||
case "numerical":
|
||||
{
|
||||
|
@ -1462,57 +1465,6 @@ export function buildAxisWidgets(
|
|||
]
|
||||
)
|
||||
);
|
||||
widgets.push(
|
||||
manager.sectionHeader(strings.objects.dataAxis.scrolling)
|
||||
);
|
||||
widgets.push(
|
||||
manager.inputBoolean(
|
||||
{
|
||||
property: axisProperty,
|
||||
field: "allowScrolling",
|
||||
},
|
||||
{
|
||||
type: "checkbox",
|
||||
label: strings.objects.dataAxis.allowScrolling,
|
||||
observerConfig: {
|
||||
isObserver: true,
|
||||
properties: {
|
||||
property: axisProperty,
|
||||
field: "windowSize",
|
||||
},
|
||||
value: 10,
|
||||
},
|
||||
}
|
||||
)
|
||||
);
|
||||
if (data.allowScrolling) {
|
||||
widgets.push(
|
||||
manager.inputNumber(
|
||||
{
|
||||
property: axisProperty,
|
||||
field: "windowSize",
|
||||
},
|
||||
{
|
||||
maximum: 1000,
|
||||
minimum: 1,
|
||||
label: strings.objects.dataAxis.windowSize,
|
||||
}
|
||||
)
|
||||
);
|
||||
widgets.push(
|
||||
manager.inputNumber(
|
||||
{
|
||||
property: axisProperty,
|
||||
field: "barOffset",
|
||||
},
|
||||
{
|
||||
maximum: 1000,
|
||||
minimum: -1000000,
|
||||
label: strings.objects.dataAxis.barOffset,
|
||||
}
|
||||
)
|
||||
);
|
||||
}
|
||||
widgets.push(makeAppearance());
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -416,8 +416,16 @@ export class CartesianPlotSegment extends PlotSegmentClass<
|
|||
const attrs = this.state.attributes;
|
||||
const props = this.object.properties;
|
||||
const g = [];
|
||||
// TODO optimize axis render;
|
||||
if (props.xData && props.xData.visible && props.xData.allowScrolling) {
|
||||
|
||||
if (
|
||||
props.xData &&
|
||||
props.xData.visible &&
|
||||
props.xData.allowScrolling &&
|
||||
((props.xData.allCategories &&
|
||||
props.xData.allCategories.length > props.xData.windowSize) ||
|
||||
Math.abs(props.xData.dataDomainMax - props.xData.dataDomainMin) >
|
||||
props.xData.windowSize)
|
||||
) {
|
||||
const axisRenderer = new AxisRenderer().setAxisDataBinding(
|
||||
props.xData,
|
||||
0,
|
||||
|
@ -441,12 +449,12 @@ export class CartesianPlotSegment extends PlotSegmentClass<
|
|||
if (!props.xData.allCategories) {
|
||||
return;
|
||||
}
|
||||
props.xData.scrollPosition = position;
|
||||
props.xData.scrollPosition = 100 - position;
|
||||
|
||||
const start = Math.floor(
|
||||
((props.xData.allCategories.length - props.xData.windowSize) /
|
||||
100) *
|
||||
position
|
||||
props.xData.scrollPosition
|
||||
);
|
||||
props.xData.categories = props.xData.allCategories.slice(
|
||||
start,
|
||||
|
@ -454,13 +462,14 @@ export class CartesianPlotSegment extends PlotSegmentClass<
|
|||
);
|
||||
|
||||
if (props.xData.categories.length === 0) {
|
||||
props.xData.allCategories
|
||||
.reverse()
|
||||
.slice(start - 1, start + props.xData.windowSize);
|
||||
props.xData.allCategories.slice(
|
||||
start - 1,
|
||||
start + props.xData.windowSize
|
||||
);
|
||||
}
|
||||
} else if (props.xData.type === AxisDataBindingType.Numerical) {
|
||||
const scale = scaleLinear()
|
||||
.domain([0, 100])
|
||||
.domain([100, 0])
|
||||
.range([props.xData.dataDomainMin, props.xData.dataDomainMax]);
|
||||
props.xData.scrollPosition = position;
|
||||
const start = scale(position);
|
||||
|
@ -478,8 +487,10 @@ export class CartesianPlotSegment extends PlotSegmentClass<
|
|||
props.yData &&
|
||||
props.yData.visible &&
|
||||
props.yData.allowScrolling &&
|
||||
props.yData.allCategories &&
|
||||
props.yData.allCategories.length > props.yData.windowSize
|
||||
((props.yData.allCategories &&
|
||||
props.yData.allCategories.length > props.yData.windowSize) ||
|
||||
Math.abs(props.yData.dataDomainMax - props.yData.dataDomainMin) >
|
||||
props.yData.windowSize)
|
||||
) {
|
||||
const axisRenderer = new AxisRenderer().setAxisDataBinding(
|
||||
props.yData,
|
||||
|
@ -510,19 +521,20 @@ export class CartesianPlotSegment extends PlotSegmentClass<
|
|||
100) *
|
||||
position
|
||||
);
|
||||
props.yData.categories = props.yData.allCategories
|
||||
.reverse()
|
||||
.slice(start, start + props.yData.windowSize)
|
||||
.reverse();
|
||||
props.yData.categories = props.yData.allCategories.slice(
|
||||
start,
|
||||
start + props.yData.windowSize
|
||||
);
|
||||
|
||||
if (props.yData.categories.length === 0) {
|
||||
props.yData.allCategories
|
||||
.reverse()
|
||||
.slice(start - 1, start + props.yData.windowSize);
|
||||
props.yData.allCategories.slice(
|
||||
start - 1,
|
||||
start + props.yData.windowSize
|
||||
);
|
||||
}
|
||||
} else if (props.yData.type === AxisDataBindingType.Numerical) {
|
||||
const scale = scaleLinear()
|
||||
.domain([0, 100])
|
||||
.domain([100, 0])
|
||||
.range([props.yData.dataDomainMin, props.yData.dataDomainMax]);
|
||||
props.yData.scrollPosition = position;
|
||||
const start = scale(position);
|
||||
|
|
|
@ -48,7 +48,8 @@ export const VirtualScrollBar: React.FC<VirtualScrollBarPropertes> = ({
|
|||
handlePosition = 0;
|
||||
}
|
||||
|
||||
handlePosition = ((trackSize - handleSize) / 100) * handlePosition; // map % to axis position
|
||||
handlePosition =
|
||||
((trackSize - handleSize) / 100) * (100 - handlePosition); // map % to axis position
|
||||
|
||||
if (vertical) {
|
||||
handlePositionY = handlePosition;
|
||||
|
@ -113,10 +114,10 @@ export const VirtualScrollBar: React.FC<VirtualScrollBarPropertes> = ({
|
|||
let newPosition = position;
|
||||
if (vertical) {
|
||||
const trackSize = Math.abs(trackElement.bottom - trackElement.top);
|
||||
newPosition = 100 - (deltaY / trackSize) * 100;
|
||||
newPosition = (deltaY / trackSize) * 100;
|
||||
} else {
|
||||
const trackSize = Math.abs(trackElement.right - trackElement.left);
|
||||
newPosition = (deltaX / trackSize) * 100;
|
||||
newPosition = 100 - (deltaX / trackSize) * 100;
|
||||
}
|
||||
|
||||
if (newPosition > 100) {
|
||||
|
@ -134,7 +135,14 @@ export const VirtualScrollBar: React.FC<VirtualScrollBarPropertes> = ({
|
|||
|
||||
const onClick = React.useCallback(
|
||||
(sign: number) => {
|
||||
const newPosition = position + sign * 5;
|
||||
let newPosition = position + sign * 5;
|
||||
|
||||
if (newPosition > 100) {
|
||||
newPosition = 100;
|
||||
}
|
||||
if (newPosition < 0) {
|
||||
newPosition = 0;
|
||||
}
|
||||
setPosition(newPosition);
|
||||
onScroll(newPosition);
|
||||
},
|
||||
|
@ -195,7 +203,7 @@ export const VirtualScrollBar: React.FC<VirtualScrollBarPropertes> = ({
|
|||
fill: "#b3b0ad",
|
||||
}}
|
||||
onClick={() => {
|
||||
onClick(-1);
|
||||
onClick(1);
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
|
@ -219,7 +227,7 @@ export const VirtualScrollBar: React.FC<VirtualScrollBarPropertes> = ({
|
|||
fill: "#b3b0ad",
|
||||
}}
|
||||
onClick={() => {
|
||||
onClick(1);
|
||||
onClick(-1);
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
|
@ -256,7 +264,7 @@ export const VirtualScrollBar: React.FC<VirtualScrollBarPropertes> = ({
|
|||
fill: "#b3b0ad",
|
||||
}}
|
||||
onClick={() => {
|
||||
onClick(-1);
|
||||
onClick(1);
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
|
@ -278,7 +286,7 @@ export const VirtualScrollBar: React.FC<VirtualScrollBarPropertes> = ({
|
|||
fill: "#b3b0ad",
|
||||
}}
|
||||
onClick={() => {
|
||||
onClick(1);
|
||||
onClick(-1);
|
||||
}}
|
||||
/>
|
||||
<path
|
||||
|
|
Загрузка…
Ссылка в новой задаче