Skip to content

Commit

Permalink
Merge pull request #722 from react-component/draggable-track
Browse files Browse the repository at this point in the history
add dragableTrack
  • Loading branch information
jljsj33 authored Dec 15, 2020
2 parents 2c4437b + 6afc1d6 commit d4fc1ff
Show file tree
Hide file tree
Showing 8 changed files with 223 additions and 39 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ The following APIs are shared by Slider and Range.
| count | number | `1` | Determine how many ranges to render, and multiple handles will be rendered (number + 1). |
| allowCross | boolean | `true` | `allowCross` could be set as `true` to allow those handles to cross. |
| pushable | boolean or number | `false` | `pushable` could be set as `true` to allow pushing of surrounding handles when moving a handle. When set to a number, the number will be the minimum ensured distance between handles. Example: ![](http://i.giphy.com/l46Cs36c9HrHMExoc.gif) |
| draggableTrack | boolean | `false` | Open the track drag. open after click on the track will be invalid. |

### SliderTooltip

Expand Down
30 changes: 21 additions & 9 deletions docs/examples/range.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ class CustomizedRange extends React.Component {
};
}

onLowerBoundChange = e => {
onLowerBoundChange = (e) => {
this.setState({ lowerBound: +e.target.value });
};

onUpperBoundChange = e => {
onUpperBoundChange = (e) => {
this.setState({ upperBound: +e.target.value });
};

onSliderChange = value => {
onSliderChange = (value) => {
log(value);
this.setState({
value,
Expand Down Expand Up @@ -70,17 +70,17 @@ class DynamicBounds extends React.Component {
};
}

onSliderChange = value => {
onSliderChange = (value) => {
log(value);
};

onMinChange = e => {
onMinChange = (e) => {
this.setState({
min: +e.target.value || 0,
});
};

onMaxChange = e => {
onMaxChange = (e) => {
this.setState({
max: +e.target.value || 100,
});
Expand Down Expand Up @@ -115,7 +115,7 @@ class ControlledRange extends React.Component {
};
}

handleChange = value => {
handleChange = (value) => {
this.setState({
value,
});
Expand All @@ -134,7 +134,7 @@ class ControlledRangeDisableAcross extends React.Component {
};
}

handleChange = value => {
handleChange = (value) => {
this.setState({
value,
});
Expand All @@ -161,7 +161,7 @@ class PureRenderRange extends React.Component {
};
}

handleChange = value => {
handleChange = (value) => {
console.log(value);
this.setState(({ foo }) => ({ foo: !foo }));
};
Expand Down Expand Up @@ -234,5 +234,17 @@ export default () => (
<p>Range as child component</p>
<PureRenderRange />
</div>
<div style={style}>
<p>draggableTrack two points</p>
<Range allowCross={false} defaultValue={[0, 40]} draggableTrack onChange={log} />
</div>
<div style={style}>
<p>draggableTrack two points(reverse)</p>
<Range allowCross={false} reverse defaultValue={[0, 40]} draggableTrack onChange={log} />
</div>
<div style={style}>
<p>draggableTrack multiple points</p>
<Range allowCross={false} defaultValue={[0, 20, 30, 40, 50]} draggableTrack onChange={log} />
</div>
</div>
);
23 changes: 23 additions & 0 deletions docs/examples/vertical.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,28 @@ export default () => (
defaultValue={[20, 40]}
/>
</div>
<div style={style}>
<p>Range with marks and draggableTrack</p>
<Slider.Range
draggableTrack
vertical
min={-10}
marks={marks}
onChange={log}
defaultValue={[20, 40]}
/>
</div>
<div style={style}>
<p>Range with marks and draggableTrack(reverse)</p>
<Slider.Range
draggableTrack
vertical
reverse
min={-10}
marks={marks}
onChange={log}
defaultValue={[20, 40]}
/>
</div>
</div>
);
47 changes: 44 additions & 3 deletions src/Range.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export interface RangeProps extends GenericSliderProps {
ariaLabelledByGroupForHandles?: string | Array<string>;
ariaValueTextFormatterGroupForHandles?: string | Array<string>;
handle?: SliderProps['handle'];
draggableTrack?: boolean;
}

interface RangeState extends GenericSliderState {
Expand All @@ -76,6 +77,10 @@ class Range extends React.Component<RangeProps, RangeState> {
return 0;
}

getSliderLength() {
return 0;
}

calcOffset(value: number) {
return 0;
}
Expand All @@ -91,6 +96,7 @@ class Range extends React.Component<RangeProps, RangeState> {
count: 1,
allowCross: true,
pushable: false,
draggableTrack: false,
tabIndex: [],
ariaLabelGroupForHandles: [],
ariaLabelledByGroupForHandles: [],
Expand All @@ -107,6 +113,8 @@ class Range extends React.Component<RangeProps, RangeState> {

handlesRefs: Record<number, any>;

dragTrack: boolean;

constructor(props: RangeProps) {
super(props);

Expand Down Expand Up @@ -204,6 +212,19 @@ class Range extends React.Component<RangeProps, RangeState> {
props.onChange(changedValue);
}

positionGetValue = (position): number[] => {
const bounds = this.getValue();
const value = this.calcValueByPos(position);
const closestBound = this.getClosestBound(value);
const index = this.getBoundNeedMoving(value, closestBound);
const prevValue = bounds[index];
if (value === prevValue) return null;

const nextBounds = [...bounds];
nextBounds[index] = value;
return nextBounds;
};

onStart(position) {
const { props, state } = this;
const bounds = this.getValue();
Expand Down Expand Up @@ -233,6 +254,9 @@ class Range extends React.Component<RangeProps, RangeState> {
const { handle } = this.state;
this.removeDocumentEvents();

if (!handle) {
this.dragTrack = false;
}
if (handle !== null || force) {
this.props.onAfterChange(this.getValue());
}
Expand All @@ -242,10 +266,27 @@ class Range extends React.Component<RangeProps, RangeState> {
});
};

onMove(e, position) {
onMove(e, position, dragTrack, startBounds) {
utils.pauseEvent(e);
const { state } = this;

const { state, props } = this;
const maxValue = props.max || 100;
const minValue = props.min || 0;
if (dragTrack) {
let pos = props.vertical ? -position : position;
pos = props.reverse ? -pos : pos;
const max = maxValue - Math.max(...startBounds);
const min = minValue - Math.min(...startBounds);
const ratio = Math.min(Math.max(pos / (this.getSliderLength() / 100), min), max);
const nextBounds = startBounds.map(v =>
Math.floor(Math.max(Math.min(v + ratio, maxValue), minValue)),
);
if (state.bounds.map((c, i) => c === nextBounds[i]).some(c => !c)) {
this.onChange({
bounds: nextBounds,
});
}
return;
}
const value = this.calcValueByPos(position);
const oldValue = state.bounds[state.handle];
if (value === oldValue) return;
Expand Down
6 changes: 5 additions & 1 deletion src/Slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ class Slider extends React.Component<SliderProps, SliderState> {
return 0;
}

positionGetValue = (position): number[] => {
return [];
};

calcOffset(value: number) {
return 0;
}
Expand Down Expand Up @@ -246,7 +250,7 @@ class Slider extends React.Component<SliderProps, SliderState> {
ariaLabelledBy: ariaLabelledByForHandle,
ariaValueTextFormatter: ariaValueTextFormatterForHandle,
style: handleStyle[0] || handleStyle,
ref: h => this.saveHandle(0, h),
ref: (h) => this.saveHandle(0, h),
});

const trackOffset = startPoint !== undefined ? this.calcOffset(startPoint) : 0;
Expand Down
77 changes: 52 additions & 25 deletions src/common/createSlider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ export default function createSlider<

onMouseUpListener: any;

dragTrack: boolean;

startBounds: number[];

constructor(props: Props) {
super(props);

Expand Down Expand Up @@ -97,44 +101,64 @@ export default function createSlider<
this.removeDocumentEvents();
}

onDown = (e, position) => {
let p = position;
const { draggableTrack, vertical: isVertical } = this.props;
const { bounds } = this.state;

const value = draggableTrack && this.positionGetValue ? this.positionGetValue(p) || [] : [];

const inPoint = utils.isEventFromHandle(e, this.handlesRefs);
this.dragTrack =
draggableTrack &&
bounds.length >= 2 &&
!inPoint &&
!value
.map((n, i) => {
const v = !i ? n >= bounds[i] : true;
return i === value.length - 1 ? n <= bounds[i] : v;
})
.some((c) => !c);

if (this.dragTrack) {
this.dragOffset = p;
this.startBounds = [...bounds];
} else {
if (!inPoint) {
this.dragOffset = 0;
} else {
const handlePosition = utils.getHandleCenterPosition(isVertical, e.target);
this.dragOffset = p - handlePosition;
p = handlePosition;
}
this.onStart(p);
}
};

onMouseDown = (e: any) => {
if (e.button !== 0) {
return;
}
const isVertical = this.props.vertical;
let position = utils.getMousePosition(isVertical, e);
if (!utils.isEventFromHandle(e, this.handlesRefs)) {
this.dragOffset = 0;
} else {
const handlePosition = utils.getHandleCenterPosition(isVertical, e.target);
this.dragOffset = position - handlePosition;
position = handlePosition;
}

this.removeDocumentEvents();
this.onStart(position);
const isVertical = this.props.vertical;
const position = utils.getMousePosition(isVertical, e);
this.onDown(e, position);
this.addDocumentMouseEvents();
};

onTouchStart = (e: any) => {
if (utils.isNotTouchEvent(e)) return;

const isVertical = this.props.vertical;
let position = utils.getTouchPosition(isVertical, e);
if (!utils.isEventFromHandle(e, this.handlesRefs)) {
this.dragOffset = 0;
} else {
const handlePosition = utils.getHandleCenterPosition(isVertical, e.target);
this.dragOffset = position - handlePosition;
position = handlePosition;
}
this.onStart(position);
const position = utils.getTouchPosition(isVertical, e);
this.onDown(e, position);
this.addDocumentTouchEvents();
utils.pauseEvent(e);
};

onFocus = (e: React.FocusEvent<HTMLDivElement>) => {
const { onFocus, vertical } = this.props;
if (utils.isEventFromHandle(e, this.handlesRefs)) {
if (utils.isEventFromHandle(e, this.handlesRefs) && !this.dragTrack) {
const handlePosition = utils.getHandleCenterPosition(vertical, e.target);
this.dragOffset = 0;
this.onStart(handlePosition);
Expand All @@ -147,7 +171,10 @@ export default function createSlider<

onBlur = (e: React.FocusEvent<HTMLDivElement>) => {
const { onBlur } = this.props;
this.onEnd();
if (!this.dragTrack) {
this.onEnd();
}

if (onBlur) {
onBlur(e);
}
Expand All @@ -165,7 +192,7 @@ export default function createSlider<
return;
}
const position = utils.getMousePosition(this.props.vertical, e);
this.onMove(e, position - this.dragOffset);
this.onMove(e, position - this.dragOffset, this.dragTrack, this.startBounds);
};

onTouchMove = (e: React.TouchEvent<HTMLDivElement>) => {
Expand All @@ -175,7 +202,7 @@ export default function createSlider<
}

const position = utils.getTouchPosition(this.props.vertical, e);
this.onMove(e, position - this.dragOffset);
this.onMove(e, position - this.dragOffset, this.dragTrack, this.startBounds);
};

onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
Expand Down Expand Up @@ -243,7 +270,7 @@ export default function createSlider<
if (this.props.disabled) {
return;
}
Object.keys(this.handlesRefs).forEach(key => {
Object.keys(this.handlesRefs).forEach((key) => {
this.handlesRefs[key]?.blur?.();
});
}
Expand Down
Loading

1 comment on commit d4fc1ff

@vercel
Copy link

@vercel vercel bot commented on d4fc1ff Dec 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.