Как программно вызвать события перетаскивания с d3. js? - PullRequest
2 голосов
/ 25 марта 2020

Я написал некоторый код, который использует событие перетаскивания для элементов SVG. Код работает нормально, и я хотел бы написать несколько тестов для него. Вместо ручного перемещения мыши вручную я хотел бы программно запускать события dragstart и drag с помощью selection.dispatch :

     svgSelection.dispatch('dragstart',{bubbles:true});
     svgSelection.dispatch('drag',{bubbles:true});

Однако эти события не кажутся быть уволеным. Может быть, я использую неправильные ключи событий или мне нужно включить какую-то дополнительную опцию?

Я также пытался использовать следующие варианты, которые не помогли:

svgElement.dispatchEvent(new Event('drag', {bubbles:true}));

svgSelection.dispatch('mousedown.drag',{bubbles:true});

Если я попытаюсь

svgElement.on('mousedown.drag')()

Я получаю сообщение об ошибке

Uncaught TypeError: Cannot read property 'ctrlKey' of null
    at defaultFilter (drag.js?009f:10)
    at mousedowned (drag.js?009f:51)

Как правильно запускать события 'start' и 'drag', используемые в следующем коде?

    let offset = [0,0];
    let drag = d3.drag()
        .on('start', () => this.__dragStarted(d3, svgSelection, offset))
        .on('drag', ()=> this.__dragged(d3, svgSelection, offset));
    svgSelection.call(drag);

Мой тестовый пример :

it('enableDragAndDrop', ()=>{
     let element = document.createElement('svg');
     let svgSelection = d3.select(element);

     spyOn(sut, '__dragStarted');
     spyOn(sut, '__dragged');

     sut.enableDragAndDrop(svgSelection);
     svgSelection.dispatch('dragstart',{bubbles:true});
     svgSelection.dispatch('drag',{bubbles:true});

     expect(sut.__dragStarted).toHaveBeenCalled();
     expect(sut.__dragged).toHaveBeenCalled();

});

Пример моего кода:

enableDragAndDrop(svgSelection){
    let offset = [0,0];
    let drag = d3.drag()
        .on('start', () => this.__dragStarted(d3, svgSelection, offset))
        .on('drag', ()=> this.__dragged(d3, svgSelection, offset));
    svgSelection.call(drag);
}

__dragStarted(d3, svgSelection, offset){
    if(!svgSelection.attr('transform')){
        svgSelection.attr('transform','translate(0,0)');
    }

    let transform = svgSelection.attr('transform');
    let translate = this.__extractTranslate(transform);
    offset[0] = translate[0] - d3.event.x;
    offset[1] = translate[1] - d3.event.y;
}

__dragged(d3, svgSelection, offset){

    let x = d3.event.x + offset[0];
    let y = d3.event.y + offset[1];
    svgSelection
        .attr('transform', 'translate(' + x + ', ' + y + ')');
}

__extractTranslate(transformString){
    let stripped = transformString;
    stripped = stripped.replace('translate(','');
    stripped = stripped.replace(')','');
    let numberStrings = stripped.split(',');
    return numberStrings.map(numberString=>parseFloat(numberString));
}

Связанные вопросы:

Как внешне запускать события d3

Как вызвать событие в JavaScript?

dataTransfer является нулевым при программном создании события перетаскивания

Ответы [ 2 ]

1 голос
/ 03 апреля 2020

Вот обходной путь, который частично дразнит d3 с шуткой:

import * as d3 from 'd3';

jest.mock('d3', ()=>{

    let wrappedD3 = jest.requireActual('d3');

    var d3Mock = {
        drag: undefined,
        event: wrappedD3.event,
        select: wrappedD3.select,
        __passedEventHandlers: []
    };

    d3Mock.drag = ()=>{
        let dragMock = {
            apply: ()=>{}
        };
        dragMock.on = (event, eventHandler)=>{
                d3Mock.__passedEventHandlers.push(eventHandler);
                return dragMock;
        }
        return dragMock;
    };

    return d3Mock;

});

Пример использования в тесте:

it('enableDragAndDrop', ()=>{
     let element = document.createElement('svg');
     document.body.appendChild(element);

     let svgSelection = d3.select(element);   

     sut.enableDragAndDrop(svgSelection);

     spyOn(sut, '__dragStarted');
     let dragStartedHandler = d3.__passedEventHandlers[0];
     dragStartedHandler();
     expect(sut.__dragStarted).toHaveBeenCalled();

     spyOn(sut, '__dragged');
     let draggedHandler = d3.__passedEventHandlers[1];
     draggedHandler();
     expect(sut.__dragged).toHaveBeenCalled();

});
0 голосов
/ 29 марта 2020

Я поделюсь примером перетаскивания круга на SVG, я надеюсь, что он работает для вас

svg.selectAll("circle")
            .data(yourdata)
            .enter()
            .append("circle")
            .attr("class", "nodes")
            .attr("cx", function(d) { return d.x; }) // your data have x and y position
            .attr("cy", function(d) { return d.y; })
            .attr("r", "5px")   
            .call(d3.drag().on("drag", dragged)) // you're calling drag function from here
            .attr("fill", "black");


function dragged(d) {
            d3.select(this)
                .attr("cx", d.x = d3.event.x)
                .attr("cy", d.y = d3.event.y)
}
...