Compare commits

..
12 Commits
Author SHA1 Message Date
Benjy Cui ee0dd09a4f fix: support decimal step 2015-11-23 16:00:21 +08:00
Benjy Cui a5de9b0dbc Merge pull request #48 from react-component/improve-performance
refactor: improve performance
2015-11-23 15:37:13 +08:00
Benjy Cui 37d32ae71c Merge pull request #49 from just-boris/master
style: reduce gaps between marks
2015-11-23 09:57:24 +08:00
just-boris f339db494b reduce gaps between marks 2015-11-23 00:17:29 +03:00
Benjy Cui c097b8f761 bump 3.1.1 2015-11-22 10:31:08 +08:00
Benjy Cui 10244cf01b refactor: improve the performance of Slider 2015-11-22 10:29:41 +08:00
Benjy Cui e8a86b91e2 Merge pull request #45 from react-component/feat-mark-as-step
Feat mark as step
2015-11-19 11:55:10 +08:00
Benjy Cui 05dafc0f10 bump 3.1.0 2015-11-19 11:43:25 +08:00
Benjy Cui 5dbde43da8 docs: update README.md 2015-11-19 11:43:07 +08:00
Benjy Cui 0a23a67f31 feat: allow user set step to null to make marks as steps 2015-11-19 11:42:04 +08:00
Benjy Cui 6f39212df5 Merge pull request #43 from react-component/fix-marks
fix: the key of marks could be negative
2015-11-18 18:37:46 +08:00
Benjy Cui a7c2319949 fix: the key of marks could be negative 2015-11-18 18:27:37 +08:00
8 changed files with 103 additions and 114 deletions
+11 -23
View File
@@ -88,11 +88,17 @@ ReactDOM.render(<Rcslider />, container);
<td>100</td>
<td>The maximum value of the slider</td>
</tr>
<tr>
<td>marks</td>
<td>object {number: string}</td>
<td>{}</td>
<td>Mark on the slider. The key determines the position, and the value determines what will show.</td>
</tr>
<tr>
<td>step</td>
<td>number</td>
<td>number or `null`</td>
<td>1</td>
<td>Value to be added or subtracted on each step the slider makes. Must be greater than zero. max - min should be evenly divisible by the step value.</td>
<td>Value to be added or subtracted on each step the slider makes. Must be greater than zero. max - min should be evenly divisible by the step value. When `marks` is not an empty object, `step` can be set to `null`, to make marks as steps.</td>
</tr>
<tr>
<td>range</td>
@@ -112,35 +118,17 @@ ReactDOM.render(<Rcslider />, container);
<td></td>
<td>Set current positions of handles. If range is `false`, the type of `defaultValue` should be `number`. Otherwise, `[number, number]`</td>
</tr>
<tr>
<td>marks</td>
<td>array</td>
<td>[]</td>
<td>Mark every step for the slider, it will ignore the `step` parameter if it has been defined. Does not work with `range`</td>
</tr>
<tr>
<td>included</td>
<td>boolean</td>
<td>true</td>
<td>If the value is `true`, it means a continuous value interval, otherwise, it is a independent value.</td>
</tr>
<tr>
<td>defaultIndex</td>
<td>number</td>
<td>0</td>
<td>For step or marks slider, determines the initial position of the handle. Does not work with `range`</td>
</tr>
<tr>
<td>index</td>
<td>number</td>
<td></td>
<td>For step or marks slider, determines current position of the handle. Does not work with `range`</td>
</tr>
<tr>
<td>disabled</td>
<td>boolean</td>
<td>false</td>
<td>If true the handles can't be moved.</td>
<td>If `true`, handles can't be moved.</td>
</tr>
<tr>
<td>tipTransitionName</td>
@@ -150,7 +138,7 @@ ReactDOM.render(<Rcslider />, container);
</tr>
<tr>
<td>tipFormatter</td>
<td>func</td>
<td>function</td>
<td></td>
<td>Format the value of the tooltip if it shows.</td>
</tr>
@@ -158,7 +146,7 @@ ReactDOM.render(<Rcslider />, container);
<td>dots</td>
<td>bool</td>
<td>false</td>
<td>For linear slider, when the `step` value is greater than 1, you can set the `dots` to `true` if you want to render the slider bar with dots.</td>
<td>When the `step` value is greater than 1, you can set the `dots` to `true` if you want to render the slider with dots.</td>
</tr>
</tbody>
</table>
+9 -8
View File
@@ -8,6 +8,7 @@ var Slider = require('rc-slider');
var style = {width: 400, margin: 50};
var marks = {
'-10': '-10°C',
0: '0°C',
26: '26°C',
37: '37°C',
@@ -21,30 +22,30 @@ var log = function(value) {
ReactDOM.render(
<div>
<div style={style}>
<p>Slider with marks, `included=true`</p>
<Slider marks={marks} onChange={log} defaultValue={20} />
<p>Slider with marks, `step=null`</p>
<Slider min={-10} marks={marks} step={null} onChange={log} defaultValue={20} />
</div>
<div style={style}>
<p>Slider with marks and steps, `included=true`</p>
<Slider marks={marks} step={10} onChange={log} defaultValue={20} />
<p>Slider with marks and steps</p>
<Slider min={-10} marks={marks} step={10} onChange={log} defaultValue={20} />
</div>
<div style={style}>
<p>Slider with marks, `included=false`</p>
<Slider marks={marks} included={false} defaultValue={20} />
<Slider min={-10} marks={marks} included={false} defaultValue={20} />
</div>
<div style={style}>
<p>Slider with marks and steps, `included=false`</p>
<Slider marks={marks} step={10} included={false} defaultValue={20} />
<Slider min={-10} marks={marks} step={10} included={false} defaultValue={20} />
</div>
<div style={style}>
<p>Range with marks</p>
<Slider range marks={marks} onChange={log} defaultValue={[20, 40]} />
<Slider min={-10} range marks={marks} onChange={log} defaultValue={[20, 40]} />
</div>
<div style={style}>
<p>Range with marks and steps</p>
<Slider range marks={marks} step={10} onChange={log} defaultValue={[20, 40]} />
<Slider min={-10} range marks={marks} step={10} onChange={log} defaultValue={[20, 40]} />
</div>
</div>
, document.getElementById('__react-content'));
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "rc-slider",
"version": "3.0.0",
"version": "3.1.2",
"description": "slider ui component for react",
"keywords": [
"react",
+33
View File
@@ -0,0 +1,33 @@
import React from 'react';
import { classSet } from 'rc-util';
function calcPoints(marks, dots, step, min, max) {
const points = Object.keys(marks).map(parseFloat);
if (dots) {
for (let i = min; i <= max; i = i + step) {
points.push(i);
}
}
return points;
}
const Dots = ({prefixCls, marks, dots, step, included, lowerBound, upperBound, max, min}) => {
const range = max - min;
const elements = calcPoints(marks, dots, step, min, max).map((point) => {
const offset = (point - min) / range * 100 + '%';
const style = { left: offset };
const isActived = (!included && point === upperBound) ||
(included && point <= upperBound && point >= lowerBound);
const pointClassName = classSet({
[prefixCls + '-dot']: true,
[prefixCls + '-dot-active']: isActived,
});
return <span className={pointClassName} style={style} key={point} />;
});
return <div className={prefixCls + '-step'}>{elements}</div>;
};
export default Dots;
+3 -9
View File
@@ -5,7 +5,7 @@ const Marks = ({className, marks, included, upperBound, lowerBound, max, min}) =
const marksKeys = Object.keys(marks);
const marksCount = marksKeys.length;
const unit = 100 / (marksCount - 1);
const markWidth = unit / 2 + '%';
const markWidth = unit * 0.9;
const range = max - min;
const elements = marksKeys.map(parseFloat).map((point) => {
@@ -16,14 +16,8 @@ const Marks = ({className, marks, included, upperBound, lowerBound, max, min}) =
[className + '-text-active']: isActived,
});
const style = { width: markWidth };
if (point === marksCount - 1) {
style.right = -unit / 4 + '%';
} else if (point === 0) {
style.left = -unit / 4 + '%';
} else {
style.left = (point - min) / range * 100 - unit / 4 + '%';
}
const style = { width: markWidth + '%' };
style.left = (point - min) / range * 100 - markWidth / 2 + '%';
return (<span className={markClassName} style={style} key={point}>
{marks[point]}
+44 -48
View File
@@ -2,7 +2,7 @@ import React from 'react';
import {Dom as DomUtils, classSet} from 'rc-util';
import Track from './Track';
import Handle from './Handle';
import Steps from './Steps';
import Dots from './Dots';
import Marks from './Marks';
function noop() {
@@ -25,10 +25,6 @@ function pauseEvent(e) {
e.preventDefault();
}
function isEmpty(collection) {
return Object.keys(collection).length === 0;
}
class Slider extends React.Component {
constructor(props) {
super(props);
@@ -191,17 +187,6 @@ class Slider extends React.Component {
return this.props.range ? [lowerBound, upperBound] : upperBound;
}
getPoints() {
const {marks, step, min, max} = this.props;
const points = Object.keys(marks);
if (isEmpty(marks) || step > 1) {
for (let i = min; i <= max; i = i + step) {
points.push(i);
}
}
return points;
}
getSliderLength() {
const slider = this.refs.slider;
if (!slider) {
@@ -218,10 +203,20 @@ class Slider extends React.Component {
return rect.left;
}
getPrecision() {
const props = this.props;
const stepString = props.step.toString();
let precision = 0;
if (stepString.indexOf('.') >= 0) {
precision = stepString.length - stepString.indexOf('.') - 1;
}
return precision;
}
trimAlignValue(v) {
const state = this.state || {};
const {handle, lowerBound, upperBound} = state;
const {min, max} = this.props;
const {marks, step, min, max} = this.props;
let val = v;
if (val <= min) {
@@ -237,11 +232,16 @@ class Slider extends React.Component {
val = upperBound;
}
const points = this.getPoints().map(parseFloat);
const points = Object.keys(marks).map(parseFloat);
if (step !== null) {
const closestStep = Math.round(val / step) * step;
points.push(closestStep);
}
const diffs = points.map((point) => Math.abs(val - point));
const closestPoint = points[diffs.indexOf(Math.min.apply(Math, diffs))];
return closestPoint;
return step !== null ? parseFloat(closestPoint.toFixed(this.getPrecision())) : closestPoint;
}
calcOffset(value) {
@@ -273,7 +273,7 @@ class Slider extends React.Component {
}
}
removeEventons(type) {
removeEvents(type) {
if (type === 'touch') {
this.onTouchMoveListener.remove();
this.onTouchUpListener.remove();
@@ -284,54 +284,50 @@ class Slider extends React.Component {
}
end(type) {
this.removeEventons(type);
this.removeEvents(type);
this.props.onAfterChange(this.getValue());
this.setState({handle: null});
}
render() {
const {handle, upperBound, lowerBound} = this.state;
const {className, prefixCls, disabled, dots, included, range,
const {className, prefixCls, disabled, dots, included, range, step,
marks, max, min, tipTransitionName, tipFormatter, children} = this.props;
const marksCount = Object.keys(marks).length;
const upperOffset = this.calcOffset(upperBound);
const lowerOffset = this.calcOffset(lowerBound);
const handleClassName = prefixCls + '-handle';
const isNoTip = (step === null) && !tipFormatter;
const upper = (<Handle className={handleClassName}
noTip={isNoTip} tipTransitionName={tipTransitionName} tipFormatter={tipFormatter}
offset={upperOffset} value={upperBound} dragging={handle === 'upperBound'} />);
let lower = null;
if (range) {
lower = (<Handle className={handleClassName}
noTip={isNoTip} tipTransitionName={tipTransitionName} tipFormatter={tipFormatter}
offset={lowerOffset} value={lowerBound} dragging={handle === 'lowerBound'} />);
}
const sliderClassName = classSet({
[prefixCls]: true,
[prefixCls + '-disabled']: disabled,
[className]: !!className,
});
const upperOffset = this.calcOffset(upperBound);
const lowerOffset = this.calcOffset(lowerBound);
let track = null;
if (included || range) {
const trackClassName = prefixCls + '-track';
track = <Track className={trackClassName} offset={lowerOffset} length={upperOffset - lowerOffset}/>;
}
const handleClassName = prefixCls + '-handle';
const isNoTip = (marksCount > 0) && !tipFormatter;
const upper = (<Handle className={handleClassName} tipTransitionName={tipTransitionName} noTip={isNoTip} tipFormatter={tipFormatter}
offset={upperOffset} value={upperBound} dragging={handle === 'upperBound'} />);
let lower = null;
if (range) {
lower = (<Handle className={handleClassName} tipTransitionName={tipTransitionName} noTip={isNoTip} tipFormatter={tipFormatter}
offset={lowerOffset} value={lowerBound} dragging={handle === 'lowerBound'} />);
}
const isIncluded = included || range;
return (
<div ref="slider" className={sliderClassName}
onTouchStart={disabled ? noop : this.onTouchStart.bind(this)}
onMouseDown={disabled ? noop : this.onMouseDown.bind(this)}>
{track}
{upper}
{lower}
<Steps prefixCls={prefixCls} points={this.getPoints()} dots={dots}
included={isIncluded} lowerBound={lowerBound}
upperBound={upperBound} max={max} min={min} />
<Track className={prefixCls + '-track'} included={isIncluded}
offset={lowerOffset} length={upperOffset - lowerOffset}/>
<Dots prefixCls={prefixCls} marks={marks} dots={dots} step={step}
included={isIncluded} lowerBound={lowerBound}
upperBound={upperBound} max={max} min={min} />
<Marks className={prefixCls + '-mark'} marks={marks}
included={isIncluded} lowerBound={lowerBound}
upperBound={upperBound} max={max} min={min} />
-24
View File
@@ -1,24 +0,0 @@
import React from 'react';
import { classSet } from 'rc-util';
const Steps = ({prefixCls, points, dots, included, lowerBound, upperBound, max, min}) => {
const range = max - min;
const elements = points.filter((point) => typeof point === 'string' || dots).map(parseFloat)
.map((point) => {
const offset = (point - min) / range * 100 + '%';
const style = { left: offset };
const isActived = (!included && point === upperBound) ||
(included && point <= upperBound && point >= lowerBound);
const pointClassName = classSet({
[prefixCls + '-dot']: true,
[prefixCls + '-dot-active']: isActived,
});
return <span className={pointClassName} style={style} key={point} />;
});
return <div className={prefixCls + '-step'}>{elements}</div>;
};
export default Steps;
+2 -1
View File
@@ -1,9 +1,10 @@
import React from 'react';
const Track = ({className, offset, length}) => {
const Track = ({className, included, offset, length}) => {
const style = {
left: offset + '%',
width: length + '%',
visibility: included ? 'visible' : 'hidden',
};
return <div className={className} style={style} />;
};