0

I'm trying to recreate RxMarbles for RxJS 5, but I'm having feedback problems when I change the collection's data (specifically the length of the data source).

I added console.logs for debugging

Note for those who are familiar with RxMarbles, I renamed "Diagram" to "Timeline".

import { svg } from '@cycle/dom';
import isolate from '@cycle/isolate';
import { Observable } from 'rxjs';
import { apply, flip, map, max, merge, path, prop, sortBy, zip } from 'ramda';

import { Collection } from '../collection';

import { Marble } from './marble';
import { EndMarker } from './end-marker';

function sortMarbleDoms$(marbles$) {
  const doms$ = Collection.pluck(marbles$, prop('DOM'));
  const dataList$ = Collection.pluck(marbles$, prop('data'));

  return Observable.combineLatest(doms$, dataList$, zip)
    .map(sortBy(path([1, 'time'])))
    .map(map(prop(0)));
}

function OriginalTimeline({ DOM, marbles: marblesState$, end: end$ }) {
  const marblesProps$ = end$.map(({ time }) => ({
    minTime: 0,
    maxTime: time,
  }));
  const endMarkerProps$ = marblesState$.map(marbles => ({
    minTime: marbles.map(prop('time')).reduce(max, 0),
    maxTime: 100,
  }));

  const marblesSources = { DOM, props: marblesProps$ };
  const endMarkerSources = {
    DOM,
    props: endMarkerProps$,
    time: end$.pluck('time'),
  };

  const marbles$ = Collection.gather(
    Marble, marblesSources, marblesState$
    .do(a=>console.log('marblesState', a)), '_itemId');
  const marbleDOMs$ = sortMarbleDoms$(marbles$);
  const endMarker = EndMarker(endMarkerSources);

  const vtree$ = Observable.combineLatest(marbleDOMs$, endMarker.DOM)
    .map(([marbleDOMs, endMarkerDOM]) =>
      svg({
        attrs: { viewBox: '0 0 100 10' },
        style: { width: 500, height: 50, overflow: 'visible' },
      }, [
        svg.line({
          attrs: { x1: 0, x2: 100, y1: 5, y2: 5 },
          style: { stroke: 'black', strokeWidth: 0.4 },
        }),
        endMarkerDOM,
        ...marbleDOMs,
      ])
    );

  const marbleData$ = Collection.pluck(marbles$, prop('data'))
    .withLatestFrom(marblesState$, zip)
    .map(map(apply(flip(merge))))

  const data$ = Observable.combineLatest(marbleData$, endMarker.time)
    .map(([marbles, endMarkerTime]) => ({
      marbles,
      end: { time: endMarkerTime },
    }))
    .debounceTime(1);

  return { DOM: vtree$, data: data$.do(a=>console.log('tdata', a)) };
}

export function Timeline(sources) {
  return isolate(OriginalTimeline)(sources);
}

The basic structure of the app is that all necessary data is fed into a global sink to a dummy driver that just takes the data and re-emits it as is (so in theory, all outputs should be new inputs).

Because of this, the problem might be in other parts of my code so I'm happy to post a codepen/plunkr of the code if it helps. This is indeed working sometimes, but not all the time.

Here's the console outputs (abridged)

store Object {route: "merge", inputs: undefined}

timeline.js:39 marblesState [Object, Object, Object, Object]
timeline.js:69 tdata Object {marbles: Array[3], end: Object}
sandbox.js:48 data [Object, Object]
app.js:26 store Object {route: "merge", inputs: Array[2]}

Notice the marblesState has 4 objects, but the tdata returns marbles with an array of 3 objects. For some reason, the Collection is only returning 3 items.

Any help is appreciated. Thanks!

Alan
  • 297
  • 3
  • 12

1 Answers1

0

I have no idea why this makes sense but moving up the debounceTime(1) made it work

const marbleData$ = Collection.pluck(marbles$, prop('data'))
  .debounceTime(1)
  .withLatestFrom(marblesState$, zip)
  .map(map(apply(flip(merge))))

const data$ = Observable.combineLatest(marbleData$, endMarker.time)
  .map(([marbles, endMarkerTime]) => ({
    marbles,
    end: { time: endMarkerTime },
  }));

The Collection.pluck was sending once for each piece of new and old data.

Alan
  • 297
  • 3
  • 12