cycle.js + emotion + rxjs6でドラッグアンドドロップ(動作するものの欠陥あり)

f:id:tebaoKirito:20191009033813g:plain

アイソレート使うと2つドラックドロップできるよ

こういうのをドラッグするのをrxjsで書きたかった。

 

以下tsx
import { CycleDOMEvent, div, h1, hr, input, label, p, VNode } from "@cycle/dom";
import { css } from "emotion";
import * as Snabbdom from "snabbdom-pragma";
import { DOMSource, makeDOMDriver } from "@cycle/dom/lib/cjs/rxjs";
import { run } from "@cycle/rxjs-run";
import { Observable, timer, from } from "rxjs";
import "../stylus/style.styl";
import * as Rx from "rxjs";
import {
map,
startWith,
scan,
switchMap,
combineLatest,
takeUntil
} from "rxjs/operators";

type Sources = {
DOM: DOMSource;
};

type Sinks = {
DOM: Observable<VNode>;
};

/**
* アプリケーション
* @param sources
* @returns {{DOM: Observable<VNode>}}
**/

function cardMain(card: string) {
return function main(sources: Sources): Sinks {
// intent部分
const input$: Observable<Event> = sources.DOM.select("#" + card).events(
"mousedown"
);
const mouseMove$: Observable<Event> = sources.DOM.select("#" + card).events(
"mousemove"
);
const mouseUp$: Observable<Event> = sources.DOM.select("#" + card).events(
"mouseup"
);
const mouseLeave$: Observable<Event> = sources.DOM.select(
"#" + card
).events("mouseleave");
const mouseUpLeave$: Observable<Event> = Rx.merge(mouseUp$, mouseLeave$);
const inputGoniMousemomve$: Observable<Event> = input$
.pipe(switchMap( () => mouseMove$.pipe(takeUntil(mouseUpLeave$))))
;

// cssに入れる位置
const value$: Observable<[number, number]> = inputGoniMousemomve$.pipe(
map( (evt: MouseEvent) => {
return [evt.pageX - 30, evt.pageY - 30];
})
);

const state$ = value$.pipe(startWith([400, 400]));

const myStyle = css({
color: "hotpink",
fontSize: "3rem",
fontWeight: "bold"
});

// 現在の状態を画面に描画 ( View )
const vdom$: Observable<VNode> = state$.pipe(
map( (value) => {
console.log(card);
const styleOfCard = css({
top: value[1] + "px",
left: value[0] + "px",
position: "absolute"
});
return (
<div className={myStyle}>
<div id={card} className={styleOfCard}>
{card}
</div>
</div>
);
})
);

// 結果をドライバに出力する ( Sinks )
return {
DOM: vdom$
};
};
}
// // アプリケーションからの戻り値を受け取るドライバ群を定義
const drivers = {
DOM: makeDOMDriver("#app-container") // DOM をレンダリングするドライバ
};

// アプリケーションとドライバを結びつける
run(cardMain("裁きの龍"), drivers);
チュートリアルのコード(https://tech.recruit-mp.co.jp/front-end/post-11898/)をコピペしてそこを書き換えて作りました。

一応、ドラッグアンドドロップにはなる。しかしながら、マウスダウンストリームが生き残り続けて無限増殖するのがとても気持ち悪い。

更にいうと、cycle.jsはrxjs6をあまりサポートしてないみたいでdomdriver辺りを作ろうとするとどうもできないらしい。rxjs4はおそらく使えるとおもっていて、それを使うか素直にxstreamをつかうべきであるらしい。多分、こういうのを作りたいならdomdriver辺りを工夫するべきなんだろうな。

 

ちなみにバイト先のエンジニアの方はこのプログラムの致命的な欠陥を20秒ほどで見抜いていたのだった。