From 9bb3c9c2abec6271939d834952ed97fefe94d384 Mon Sep 17 00:00:00 2001 From: Franc Camps-Febrer Date: Thu, 3 Jan 2019 17:24:35 +0100 Subject: [PATCH] Comment and clean late timeline js --- src/components/Timeline.jsx | 59 +++++++++---- src/components/TimelineCategories.jsx | 49 ----------- src/components/TimelineEvents.jsx | 2 +- src/components/TimelineMarkers.jsx | 2 +- src/js/timeline/timeline.js | 118 ++++++++++++-------------- src/scss/timeline.scss | 1 - 6 files changed, 100 insertions(+), 131 deletions(-) delete mode 100644 src/components/TimelineCategories.jsx diff --git a/src/components/Timeline.jsx b/src/components/Timeline.jsx index b7d802c..0c54cd1 100644 --- a/src/components/Timeline.jsx +++ b/src/components/Timeline.jsx @@ -12,7 +12,6 @@ import TimelineLogic from '../js/timeline/timeline.js'; import TimelineLabels from './TimelineLabels.jsx'; import TimelineMarkers from './TimelineMarkers.jsx' import TimelineEvents from './TimelineEvents.jsx'; -import TimelineCategories from './TimelineCategories.jsx'; class Timeline extends React.Component { constructor(props) { @@ -26,20 +25,22 @@ class Timeline extends React.Component { width_controls: 100, height_controls: 115, margin_left: 120 - } + }, + softTimeUpdate: 0 }; } componentDidMount() { - this.timeline = new TimelineLogic(this.svgRef.current, this.props.app, this.props.ui, this.props.methods); - this.timeline.update(this.props.domain, this.props.app); + this.methods = Object.assign({}, this.props.methods, { onSoftUpdate: (toggle) => { this.setState({ softTimeUpdate: toggle }) }}); + this.timeline = new TimelineLogic(this.svgRef.current, this.props.ui, this.methods); + this.timeline.update(this.props.domain.categories, this.props.app.timerange); this.computeDims(); window.addEventListener('resize', () => { this.computeDims(); }); } componentWillReceiveProps(nextProps) { if (hash(nextProps) !== hash(this.props)) { - this.timeline.update(nextProps.domain, nextProps.app); + this.timeline.update(nextProps.domain.categories, nextProps.app.timerange); } } @@ -69,7 +70,23 @@ class Timeline extends React.Component { return this.timeline.applyZoom(zoom); } return null; - } + } + + renderTimelineClip() { + const dims = this.state.dims; + + return ( + + + + + ); + } renderSVG() { const dims = this.state.dims; @@ -80,17 +97,25 @@ class Timeline extends React.Component { width={dims.width} height={dims.height} > - - - - { this.onMoveTime(dir) }} /> - { this.onApplyZoom(zoom); }} /> - - {/* { this.timeline.onDragStart(ev) }} - onDrag={(ev) => { this.timeline.onDrag(ev); }} - />*/} - this.timeline.getEventX(e)} getEventY={(e) => this.timeline.getEventY(e)} /> + {this.renderTimelineClip()} + { this.onMoveTime(dir) }} + /> + { this.onApplyZoom(zoom); }} + /> + + this.timeline.getEventX(e)} + getEventY={(e) => this.timeline.getEventY(e)} + /> this.timeline.getEventX(e)} diff --git a/src/components/TimelineCategories.jsx b/src/components/TimelineCategories.jsx deleted file mode 100644 index 07a3da3..0000000 --- a/src/components/TimelineCategories.jsx +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; - -class TimelineCategories extends React.Component { - - constructor() { - super(); - - this.state = { - isDragging: false, - dragPos0: 0, - scaleXDomain - } - } - - getY(idx) { - const h = 76; - console.log((idx + 1) * h / this.props.categories.length) - return (idx + 1) * h / this.props.categories.length; - } - - renderCategory(cat, idx) { - return ( - - { this.props.onDragStart(ev) }} - onDrag={(ev) => { this.props.onDrag(ev) }} - onMouseDown={this.setState({ isDragging: true })} - onMouseUp={this.setState({ isDragging: false })} - stroke="red" x2="-720"> - {cat.category} - - ); - } - - render () { - return ( - - - {this.props.categories.map((cat, idx) => { return this.renderCategory(cat, idx); })} - - ); - } -} - -export default TimelineCategories; \ No newline at end of file diff --git a/src/components/TimelineEvents.jsx b/src/components/TimelineEvents.jsx index 9b8462e..60c676e 100644 --- a/src/components/TimelineEvents.jsx +++ b/src/components/TimelineEvents.jsx @@ -17,7 +17,7 @@ class TimelineEvents extends React.Component { cy={0} style={{ 'transform': `translate(${this.props.getEventX(event)}px, ${this.props.getEventY(event)}px)`, - 'transition': 'transform 0.5s ease' + 'transition': 'transform 0.3s ease' }} r={5} fill={this.props.getCategoryColor(event.category)} diff --git a/src/components/TimelineMarkers.jsx b/src/components/TimelineMarkers.jsx index 893caea..a97b3cf 100644 --- a/src/components/TimelineMarkers.jsx +++ b/src/components/TimelineMarkers.jsx @@ -10,7 +10,7 @@ class TimelineMarkers extends React.Component { cy={0} style={{ 'transform': `translate(${this.props.getEventX(event)}px, ${this.props.getEventY(event)}px)`, - 'transition': 'transform 0.5s ease', + 'transition': 'transform 0.3s ease', 'opacity': 0.9 }} r="10" diff --git a/src/js/timeline/timeline.js b/src/js/timeline/timeline.js index 23bd0b8..4c41b51 100644 --- a/src/js/timeline/timeline.js +++ b/src/js/timeline/timeline.js @@ -8,34 +8,31 @@ import { parseDate } from '../utilities'; import hash from 'object-hash'; import esLocale from '../data/es-MX.json'; -export default function(svg, newApp, ui, methods) { +export default function(svg, ui, methods) { d3.timeFormatDefaultLocale(esLocale); - const domain = { - categories: [] - } - const app = { - timerange: newApp.timerange, - } + let categories = []; + let timerange = [null, null]; // Dimension of the client const WIDTH_CONTROLS = 100; let WIDTH = getCurrentWidth() - WIDTH_CONTROLS; + const HEIGHT = 80; // NB: is it possible to do this with SCSS? // A: Maybe, although we are using it programmatically here for now - const margin = { left: 120 }; + const margin = { left: 120, top: 20 }; // Drag behavior let dragPos0; - let transitionDuration = 500; + let transitionDuration = 300; /** * Create scales */ const scale = {}; scale.x = d3.scaleTime() - .domain(app.timerange) + .domain(timerange) .range([margin.left, WIDTH]); scale.y = d3.scaleOrdinal() @@ -72,13 +69,13 @@ export default function(svg, newApp, ui, methods) { d3.axisBottom(scale.x) .ticks(10) .tickPadding(5) - .tickSize(80) + .tickSize(HEIGHT) .tickFormat(d3.timeFormat('%d %b')); axis.x1 = d3.axisBottom(scale.x) .ticks(10) - .tickPadding(20) + .tickPadding(margin.top) .tickSize(0) .tickFormat(d3.timeFormat('%H:%M')); @@ -114,7 +111,7 @@ export default function(svg, newApp, ui, methods) { } addResizeListener(); - /* + /** * Get y height of eventPoint, considering the ordinal Y scale * @param {object} eventPoint: regular eventPoint data */ @@ -123,7 +120,7 @@ export default function(svg, newApp, ui, methods) { return scale.y(yGroup); } - /* + /** * Get x position of eventPoint, considering the time scale * @param {object} eventPoint: regular eventPoint data */ @@ -131,14 +128,13 @@ export default function(svg, newApp, ui, methods) { return scale.x(parseDate(eventPoint.timestamp)); } + /** + * Returns the time scale (x) extent in minutes + */ function getTimeScaleExtent() { return (scale.x.domain()[1].getTime() - scale.x.domain()[0].getTime()) / 60000; } - function getScaleX() { - return scale.x; - } - /** * Apply zoom level to timeline * @param {object} zoom: zoom level from zoomLevels @@ -147,10 +143,11 @@ export default function(svg, newApp, ui, methods) { const extent = getTimeScaleExtent(); const newCentralTime = d3.timeMinute.offset(scale.x.domain()[0], extent / 2); - const domain0 = d3.timeMinute.offset(newCentralTime, -zoom.duration / 2); - const domainF = d3.timeMinute.offset(newCentralTime, zoom.duration / 2); + scale.x.domain([ + d3.timeMinute.offset(newCentralTime, -zoom.duration / 2), + d3.timeMinute.offset(newCentralTime, zoom.duration / 2) + ]); - scale.x.domain([domain0, domainF]); methods.onUpdateTimerange(scale.x.domain()); } @@ -192,23 +189,27 @@ export default function(svg, newApp, ui, methods) { toggleTransition(false); } + /* + * Drag and update + */ function onDrag() { const drag0 = scale.x.invert(dragPos0).getTime(); const dragNow = scale.x.invert(d3.event.x).getTime(); const timeShift = (drag0 - dragNow) / 1000; - const newDomain0 = d3.timeSecond.offset(app.timerange[0], timeShift); - const newDomainF = d3.timeSecond.offset(app.timerange[1], timeShift); + const newDomain0 = d3.timeSecond.offset(timerange[0], timeShift); + const newDomainF = d3.timeSecond.offset(timerange[1], timeShift); scale.x.domain([newDomain0, newDomainF]); render(); - //app.timerange = scale.x.domain(); - //methods.onUpdateTimerange(scale.x.domain()); + // Updates components without updating timerange + methods.onSoftUpdate(1); } function onDragEnd() { toggleTransition(true); - app.timerange = scale.x.domain(); + timerange = scale.x.domain(); + methods.onSoftUpdate(0); methods.onUpdateTimerange(scale.x.domain()); } @@ -217,6 +218,26 @@ export default function(svg, newApp, ui, methods) { .on('drag', onDrag) .on('end', onDragEnd); + /** + * Updates data displayed by this timeline, but only render if necessary + * @param {Object} domain: Redux state domain subtree + * @param {Object} app: Redux state app subtree + */ + function updateAxis() { + let groupYs = Array.apply(null, Array(categories.length)); + groupYs = groupYs.map((g, i) => { + return (i + 1) * HEIGHT / groupYs.length; + }); + scale.y = d3.scaleOrdinal() + .domain(categories) + .range(groupYs); + + axis.y = + d3.axisLeft(scale.y) + .tickValues(categories.map(c => c.category)); + } + + /** * Render axis on timeline and viewbox boundaries */ @@ -237,9 +258,9 @@ export default function(svg, newApp, ui, methods) { dom.axis.dragGrabber = dom.svg.insert('rect', ':first-child') .attr('class', 'drag-grabber') .attr('x', margin.left) - .attr('y', 20) + .attr('y', margin.top) .attr('width', WIDTH - margin.left) - .attr('height', 80) + .attr('height', HEIGHT) .call(drag); } @@ -253,41 +274,18 @@ export default function(svg, newApp, ui, methods) { .call(axis.y); } - /** - * Updates data displayed by this timeline, but only render if necessary - * @param {Object} domain: Redux state domain subtree - * @param {Object} app: Redux state app subtree - */ - function updateAxis() { - let groupYs = Array.apply(null, Array(domain.categories.length)); - groupYs = groupYs.map((g, i) => { - const h = 76; - return (i + 1) * h / groupYs.length; - }); - scale.y = d3.scaleOrdinal() - .domain(domain.categories) - .range(groupYs); - - axis.y = - d3.axisLeft(scale.y) - .tickValues(domain.categories.map(c => c.category)); - } - /** * Updates displayable data on the timeline: events, selected and * potentially adjusts time range - * @param {Object} newDomain: object of arrays of events and categories - * @param {Object} newApp: object of time range and selected events + * @param {Object} newCategories: object of arrays of categories + * @param {Object} newTimerange: object of time range */ - function update(newDomain, newApp) { - const isNewDomain = (hash(domain) !== hash(newDomain)); - const isNewAppProps = (hash(app) !== hash(newApp)); + function update(newCategories, newTimerange) { + if (hash(categories) !== hash(newCategories)) categories = newCategories; + if (hash(timerange) !== hash(newTimerange)) timerange = newTimerange; - if (isNewDomain) domain.categories = newDomain.categories; - if (isNewAppProps) app.timerange = newApp.timerange; - - if (isNewDomain || isNewAppProps) render(); + render(); } function render() { @@ -296,14 +294,10 @@ export default function(svg, newApp, ui, methods) { } return { - getScaleX, getEventX, getEventY, applyZoom, moveTime, - update, - onDragStart, - onDrag, - onDragEnd + update }; } diff --git a/src/scss/timeline.scss b/src/scss/timeline.scss index c7b1802..54d63a3 100644 --- a/src/scss/timeline.scss +++ b/src/scss/timeline.scss @@ -192,7 +192,6 @@ } .event { - fill: $event_default; cursor: pointer; opacity: .7;