UNPKG

labo-components

Version:
179 lines (161 loc) 6.62 kB
import React from "react"; import PropTypes from "prop-types"; import classNames from "classnames"; const LAYER_HEADER_WIDTH = 210; import IDUtil from "../../../../util/IDUtil"; import Section from "./Section"; // Render the given layers with a slight delay, so the UI has time to process the mouse interaction class Layer extends React.Component { constructor(props) { super(props); this.doubleClickTime = this.props.doubleClickTime ? this.props.doubleClickTime : 200; this.doubleClickOffset = this.props.doubleClickOffset ? this.props.doubleClickOffset : 5; } onMouseDown = (e) => { const leftMouseButton = e.button === 0; const time = new Date().getTime(); const clickPosition = this.props.start + (e.pageX - LAYER_HEADER_WIDTH) / this.props.pixelsPerSecond; // check for double click and if available call layer.onDoubleClick if ( leftMouseButton && this.interactionVars && this.props.layer.onDoubleClick && time - this.interactionVars.lastDown < this.doubleClickTime && e.pageX - this.interactionVars.downX < this.doubleClickOffset ) { this.interactionVars = null; e.stopPropagation(); // pass to onDoubleClick e.persist(); this.props.layer.onDoubleClick(clickPosition, e); } else { // set interaction variables this.interactionVars = { downX: e.pageX, lastDown: leftMouseButton ? time : 0, }; // make layer active this.props.onSectionClick(this.props.layer.id, ""); // optional onMouseDown callback this.props.layer.onClick && this.props.layer.onClick(clickPosition, e.originalEvent); } }; onSectionClick = (layerId, sectionId) => { this.props.onSectionClick(layerId, sectionId); }; render() { const { layer, start, end, pixelsPerSecond, activeLayerId, activeSectionId, } = this.props; // Get layers with sections in view const durationPadding = (end - start) * 0.03; return ( <div className={classNames( IDUtil.cssClassName("tl-layer"), layer.className )} style={{ height: layer.height, }} onMouseDown={this.onMouseDown} layer={layer.id} > {layer.sections .filter( (section) => section.start > start - (section.end - section.start) - durationPadding && section.end < end + (section.end - section.start) + durationPadding ) .map((section) => ( <Section key={section.id} sectionId={section.id} layerId={layer.id} start={section.start} active={ layer.id === activeLayerId && section.id === activeSectionId } cropped={section.start < start} highlight={section.highlight} match={section.match} left={Math.round( section.start >= start ? section.start * pixelsPerSecond : start * pixelsPerSecond )} width={ Math.round( section.start >= start ? Math.max( 0.25, // always keep a minimum duration in view so the section could still be edited section.end - section.start ) * pixelsPerSecond : (Math.max( 0.25, // always keep a minimum duration in view so the section could still be edited section.end - section.start ) + Math.min( 0, section.start - start )) * pixelsPerSecond ) + 1 // +1 for filling gaps } onClick={this.onSectionClick} > {section.data} </Section> ))} </div> ); } } export const LayerPropTypes = PropTypes.shape({ id: PropTypes.number.isRequired, title: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired, description: PropTypes.string, sections: PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.string.isRequired, start: PropTypes.number.isRequired, end: PropTypes.number.isRequired, rawData: PropTypes.string, data: PropTypes.object.isRequired, }).isRequired ).isRequired, onClick: PropTypes.func, // on layer click onDoubleClick: PropTypes.func, // on layer double click headerChildren: PropTypes.object, // additional children to render in layer header }).isRequired; Layer.propTypes = { start: PropTypes.number.isRequired, end: PropTypes.number.isRequired, pixelsPerSecond: PropTypes.number.isRequired, layer: LayerPropTypes, activeLayerId: PropTypes.number, activeSectionId: PropTypes.string, onSectionClick: PropTypes.func, doubleClickTime: PropTypes.number, doubleClickOffset: PropTypes.number, }; export default Layer;