Browse Source

optimized Slider control

David Sehnal 5 years ago
parent
commit
0171b785af
1 changed files with 24 additions and 157 deletions
  1. 24 157
      src/mol-plugin-ui/controls/slider.tsx

+ 24 - 157
src/mol-plugin-ui/controls/slider.tsx

@@ -213,7 +213,7 @@ function getHandleCenterPosition(vertical: boolean, handle: HTMLElement) {
         coords.left + (coords.width * 0.5);
 }
 
-function pauseEvent(e: Event) {
+function pauseEvent(e: MouseEvent | TouchEvent) {
     e.stopPropagation();
     e.preventDefault();
 }
@@ -244,17 +244,14 @@ export interface SliderBaseProps {
     defaultValue?: number | number[],
     value?: number | number[],
     marks?: any,
-    included?: boolean,
     className?: string,
     prefixCls?: string,
     disabled?: boolean,
-    children?: any,
     onBeforeChange?: (value: number | number[]) => void,
     onChange?: (value: number | number[]) => void,
     onAfterChange?: (value: number | number[]) => void,
     handle?: JSX.Element,
     tipFormatter?: (value: number, index: number) => any,
-    dots?: boolean,
     range?: boolean | number,
     vertical?: boolean,
     allowCross?: boolean,
@@ -268,8 +265,8 @@ export interface SliderBaseState {
 }
 
 export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState> {
-    private sliderElement: HTMLElement | undefined = void 0;
-    private handleElements: (HTMLElement | undefined)[] = [];
+    private sliderElement = React.createRef<HTMLDivElement>();
+    private handleElements: React.Ref<HTMLDivElement>[] = [];
 
     constructor(props: SliderBaseProps) {
         super(props);
@@ -307,9 +304,7 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
         onChange: noop,
         onAfterChange: noop,
         tipFormatter: (value, index) => value,
-        included: true,
         disabled: false,
-        dots: false,
         range: false,
         vertical: false,
         allowCross: true,
@@ -360,7 +355,7 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
         props.onChange!(changedValue);
     }
 
-    onMouseDown(e: MouseEvent) {
+    onMouseDown = (e: MouseEvent) => {
         if (e.button !== 0) { return; }
 
         let position = getMousePosition(this.props.vertical!, e);
@@ -455,7 +450,7 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
         this.onChange({ bounds: nextBounds } as SliderBaseState);
     }
 
-    onTouchMove(e: TouchEvent) {
+    onTouchMove = (e: TouchEvent) => {
         if (isNotTouchEvent(e)) {
             this.end('touch');
             return;
@@ -465,7 +460,7 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
         this.onMove(e, position - this.dragOffset);
     }
 
-    onTouchStart(e: TouchEvent) {
+    onTouchStart = (e: TouchEvent) => {
         if (isNotTouchEvent(e)) return;
 
         let position = getTouchPosition(this.props.vertical!, e);
@@ -512,7 +507,7 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
     }
 
     getSliderLength() {
-        const slider = this.sliderElement;
+        const slider = this.sliderElement.current;
         if (!slider) {
             return 0;
         }
@@ -521,7 +516,7 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
     }
 
     getSliderStart() {
-        const slider = this.sliderElement as HTMLElement;
+        const slider = this.sliderElement.current as HTMLElement;
         const rect = slider.getBoundingClientRect();
 
         return this.props.vertical ? rect.top : rect.left;
@@ -549,7 +544,7 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
         }
     }
 
-    calcOffset(value: number) {
+    calcOffset = (value: number) => {
         const { min, max } = this.props;
         const ratio = (value - min) / (max - min);
         return ratio * 100;
@@ -574,17 +569,11 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
         this.setState({ handle: null } as SliderBaseState);
     }
 
-    isEventFromHandle(e: Event) {
-        for (const h of this.handleElements) {
-            if (h === e.target) return true;
+    isEventFromHandle(e: MouseEvent | TouchEvent) {
+        for (const h of this.handleElements as any) {
+            if (h.current === e.target) return true;
         }
         return false;
-
-        // return this.state.bounds.some((x, i) => e.target
-
-        // (
-        //     //this.handleElements[i] && e.target === ReactDOM.findDOMNode(this.handleElements[i])
-        // ));
     }
 
     isValueOutOfBounds(value: number, props: SliderBaseProps) {
@@ -701,19 +690,15 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
             prefixCls,
             disabled,
             vertical,
-            dots,
-            included,
             range,
             step,
             marks,
-            max, min,
-            tipFormatter,
-            children,
+            tipFormatter
         } = this.props;
 
         const customHandle = this.props.handle;
 
-        const offsets = bounds.map(v => this.calcOffset(v));
+        const offsets = bounds.map(this.calcOffset);
 
         const handleClassName = `${prefixCls}-handle`;
 
@@ -733,7 +718,10 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
             vertical,
         };
 
-        this.handleElements = [];
+        if (this.handleElements.length !== bounds.length) {
+            this.handleElements = []; // = [];
+            for (let i = 0; i < bounds.length; i++) this.handleElements.push(React.createRef());
+        }
         const handles = bounds.map((v, i) => React.cloneElement(customHandle!, {
             ...commonHandleProps,
             className: handlesClassNames[i],
@@ -742,25 +730,10 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
             dragging: handle === i,
             index: i,
             key: i,
-            ref: (h: any) => this.handleElements.push(h)  // `handle-${i}`,
+            ref: this.handleElements[i]
         }));
         if (!range) { handles.shift(); }
-
-        const isIncluded = included || range;
-
-        const tracks: JSX.Element[] = [];
-        // for (let i = 1; i < bounds.length; ++i) {
-        //     const trackClassName = classNames({
-        //         [`${prefixCls}-track`]: true,
-        //         [`${prefixCls}-track-${i}`]: true,
-        //     });
-        //     tracks.push(
-        //         <Track className={trackClassName} vertical={vertical} included={isIncluded}
-        //             offset={offsets[i - 1]} length={offsets[i] - offsets[i - 1]} key={i}
-        //             />
-        //     );
-        // }
-
+ 
         const sliderClassName = classNames({
             [prefixCls!]: true,
             [`${prefixCls}-with-marks`]: Object.keys(marks).length,
@@ -770,22 +743,12 @@ export class SliderBase extends React.Component<SliderBaseProps, SliderBaseState
         });
 
         return (
-            <div ref={e => this.sliderElement = e!} className={sliderClassName}
-                onTouchStart={disabled ? noop : this.onTouchStart.bind(this)}
-                onMouseDown={disabled ? noop : this.onMouseDown.bind(this)}
+            <div ref={this.sliderElement} className={sliderClassName} 
+                onTouchStart={disabled ? noop : this.onTouchStart as any} 
+                onMouseDown={disabled ? noop : this.onMouseDown as any}
             >
                 <div className={`${prefixCls}-rail`} />
-                {tracks}
-                <Steps prefixCls={prefixCls} vertical={vertical} marks={marks} dots={dots} step={step}
-                    included={isIncluded} lowerBound={bounds[0]}
-                    upperBound={bounds[bounds.length - 1]} max={max} min={min}
-                />
                 {handles}
-                <Marks className={`${prefixCls}-mark`} vertical={vertical!} marks={marks}
-                    included={isIncluded!} lowerBound={bounds[0]}
-                    upperBound={bounds[bounds.length - 1]} max={max} min={min}
-                />
-                {children}
             </div>
         );
     }
@@ -798,100 +761,4 @@ export interface HandleProps {
     tipFormatter: (v: number, index: number) => any,
     value: number,
     index: number,
-}
-
-interface MarksProps {
-    className: string,
-    vertical: boolean,
-    marks: any,
-    included: boolean | number,
-    upperBound: number,
-    lowerBound: number,
-    max: number,
-    min: number
-}
-const Marks = ({ className, vertical, marks, included, upperBound, lowerBound, max, min }: MarksProps) => {
-    const marksKeys = Object.keys(marks);
-    const marksCount = marksKeys.length;
-    const unit = 100 / (marksCount - 1);
-    const markWidth = unit * 0.9;
-
-    const range = max - min;
-    const elements = marksKeys.map(parseFloat).sort((a, b) => a - b).map((point) => {
-        const isActived = (!included && point === upperBound) ||
-            (included && point <= upperBound && point >= lowerBound);
-        const markClassName = classNames({
-            [`${className}-text`]: true,
-            [`${className}-text-active`]: isActived,
-        });
-
-        const bottomStyle = {
-            // height: markWidth + '%',
-            marginBottom: '-50%',
-            bottom: `${(point - min) / range * 100}%`,
-        };
-
-        const leftStyle = {
-            width: `${markWidth}%`,
-            marginLeft: `${-markWidth / 2}%`,
-            left: `${(point - min) / range * 100}%`,
-        };
-
-        const style = vertical ? bottomStyle : leftStyle;
-
-        const markPoint = marks[point];
-        const markPointIsObject = typeof markPoint === 'object' && !React.isValidElement(markPoint);
-        const markLabel = markPointIsObject ? markPoint.label : markPoint;
-        const markStyle = markPointIsObject ? { ...style, ...markPoint.style } : style;
-        return (<span className={markClassName} style={markStyle} key={point}>
-            {markLabel}
-        </span>);
-    });
-
-    return <div className={className}>{elements}</div>;
-};
-
-function calcPoints(vertical: boolean, marks: any, dots: boolean, step: number, min: number, max: number) {
-    const points = Object.keys(marks).map(parseFloat);
-    if (dots) {
-        for (let i = min; i <= max; i = i + step) {
-            if (points.indexOf(i) >= 0) continue;
-            points.push(i);
-        }
-    }
-    return points;
-}
-
-const Steps = ({ prefixCls, vertical, marks, dots, step, included,
-    lowerBound, upperBound, max, min }: any) => {
-    const range = max - min;
-    const elements = calcPoints(vertical, marks, dots, step, min, max).map((point) => {
-        const offset = `${Math.abs(point - min) / range * 100}%`;
-        const style = vertical ? { bottom: offset } : { left: offset };
-
-        const isActived = (!included && point === upperBound) ||
-            (included && point <= upperBound && point >= lowerBound);
-        const pointClassName = classNames({
-            [`${prefixCls}-dot`]: true,
-            [`${prefixCls}-dot-active`]: isActived,
-        });
-
-        return <span className={pointClassName} style={style} key={point} />;
-    });
-
-    return <div className={`${prefixCls}-step`}>{elements}</div>;
-};
-
-    // const Track = ({ className, included, vertical, offset, length }: any) => {
-    //     const style: any = {
-    //         visibility: included ? 'visible' : 'hidden'
-    //     };
-    //     if (vertical) {
-    //         style.bottom = `${offset}%`;
-    //         style.height = `${length}%`;
-    //     } else {
-    //         style.left = `${offset}%`;
-    //         style.width = `${length}%`;
-    //     }
-    //     return <div className={className} style={style} />;
-    // };
+}