mfrachet
mfrachet

Reputation: 8922

Cyclejs and moving an element by x and y

I m studying cyclejs and having some trouble dealing with how to make a div movabble.

To start, I have isolated 3 events that I have to compute

The aim is to produce the move when map is down AND mousemove, and stop when I mouseup

Here's what I've got :

import {div} from '@cycle/dom'
import xs from 'xstream'

const getStyle = left => top => {
    return ({
        style: {
            position: 'absolute',
            left: left + 'px',
            top: top + 'px',
            backgroundColor: '#FF0000',
            cursor: 'pointer'
        }
    })
}

function intent(DOMSources) {
    const marble$ = DOMSources.select('.marble')
    const marbleDown$ = marble$.events('mousedown')
    const marbleMove$ = marble$.events('mousemove')
    const marbleUp$ = marble$.events('mouseup')
    return {marbleDown$, marbleUp$, marbleMove$}
}

function model({marbleDown$, marbleUp$, marbleMove$}) {
    return xs.combine(marbleDown$, marbleMove$)
        .map(([marbleDown, marbleMove]) => marbleMove)
        .map(ev => ({x: ev.pageX, y: ev.pageY}))
        .endWhen(marbleUp$)
}

function view(state$) {
    return state$
        .startWith({x: 0, y: 0})
        .map(value => div('.marble', getStyle(value.x)(value.y), 'Move me ! ' + value.x + ' - ' + value.y))
}


export function Marble(sources) {
    const changes$ = intent(sources.DOM)
    const state$ = model(changes$)
    const vTree$ = view(state$)
    return {DOM: vTree$}
}

My problem seems to appear on the model part. When I enter the the div and mousedown and it, and moving the element, I m only able to move the element to down and right, not to top and left.

My second problem is that when I leave the bouton with my mouse, it continues to move when I refocus on it.

It seems that I m missing something in a bad way.

A gif is better that a thousand words :

enter image description here

Upvotes: 2

Views: 90

Answers (1)

Nurlan Mirzayev
Nurlan Mirzayev

Reputation: 1370

Your problem is, your mouse is outside of div when you move mouse to left. You can solve this problem as this:

function between(first, second) {
    return (source) => first.mapTo(source.endWhen(second)).flatten()
}

function model({marbleDown$, marbleUp$, marbleMove$}) {
   return xs.combine(marbleDown$, marbleMove$)
      .map(([marbleDown, marbleMove]) => ({x: marbleMove.pageX - marbleDown.layerX, y: marbleMove.pageY - marbleDown.layerY}))
      .compose(between(marbleDown$, marbleUp$))
}

But you will have problem with mouseUp event. Because you left your div mouseUp event wait listener on your div element, so you need put your div on container. And take mouseUp listener to this container element. For example container can be body element.

const marbleUp$ = DOMSources.select('body').events('mouseup')

I recommend to you css style for marble div 'user-selection': 'none'. This will deactive selection mode when you click on marble.

Upvotes: 1

Related Questions