d3. js - разрешить чистку и масштабирование на одном графике - PullRequest
1 голос
/ 15 января 2020

ОБНОВЛЕНИЕ

Мне наконец-то удалось найти рабочее решение этой проблемы. Zoom включает в себя event.stopPropagation (). Это означает, что любые события в элементах, содержащихся в родительском элементе, не будут «пузыриться» по отношению к родительскому элементу в соответствии с:

https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events#Event_bubbling_and_capture

Вот как Я понимаю, что это работает, и что я рационализировал, чтобы сделать свое решение функциональным: для чистки событие будет распространяться до элементов-предков. В моем случае я добавил элемент 'rect' в svg, как показано в примерах, и добавил поведение zoom к прямоугольнику. Поэтому элемент с действием масштабирования не является родителем элемента с действием bru sh.

Я изменил код, вместо этого прикрепив поведение масштабирования к svg (а не к прямоугольнику), чтобы это предок группового элемента с действием bru sh, это позволит действию на элемент g всплыть до svg. Теперь зум также может сработать, так как событие всплывет из элемента g.

Затем я поставил галочку, чтобы проверить, был ли нажат элемент управления, и в зависимости от результата я запустил соответствующий зум или bru * 1045. * функция. Я предполагаю, что другой метод может заключаться в том, чтобы проверить исходное событие, запущенное, и затем запускать только в том случае, если это событие было тем, которое мы хотим активировать, или масштабирование, или действие bru sh.


Добрый день,

У меня возникла проблема, когда действие масштабирования потребляет события на линейном графике. Я видел несколько примеров использования контекста и фокуса, а также масштабирования и перетаскивания с дискретными элементами, но ни одного с разрешением масштабирования и чистки на одной и той же линии / диаграмме области.

Цель: Для разрешить пользователю либо удерживать клавиши ctrlKey или shiftKey, чтобы включить панорамирование, и без удержания клавиши нажатой диаграмма будет панорамировать (используя d3-zoom).

Проблема: Масштабирование потребляет события согласно документации d3. js. Это предотвращает запуск чистки. Это означает, что даже если я использую фильтр и разрешу использовать ctrlKey, а затем использую блок if, чтобы определить, была ли нажата ctrlKey или нет, событие все равно никогда не будет передано обработчику масштабирования в bru sh .

Я заметил, что в ранних версиях d3 (кажется, до v4) это сосуществование событий не было проблемой для моего варианта использования, но, похоже, вызывало проблемы с одновременным срабатыванием нескольких событий для другого использования. - случаи, которые вызывали проблемы. Похоже, что для разрешения проблем в поведении d3-zoom были реализованы предотвращение дефолта и остановка пропуска. Это предотвращает распространение события на обработчик bru sh и последующее использование настраиваемой логики c для масштабирования (в моем случае просто панорамирования) или bru sh.

Вопрос: Кто-нибудь знает какие-либо средства, позволяющие распространяться событиям без изменения самого кода d3. js? Мне бы очень хотелось иметь возможность панорамирования или масштабирования в зависимости от того, нажата ли клавиша ctrlKey, без использования переключателя для отключения событий указателя.

Код:

const MARGIN = { TOP: 10, BOTTOM: 80, LEFT: 120, RIGHT: 10 }
const WIDTH = 1000 - MARGIN.LEFT - MARGIN.RIGHT;
const HEIGHT = 500 - MARGIN.TOP - MARGIN.BOTTOM;

svg = d3.select(element.current)
        .append("svg")
            .attr("width", WIDTH + MARGIN.LEFT + MARGIN.RIGHT)
            .attr("height", HEIGHT + MARGIN.TOP + MARGIN.BOTTOM);

graph = svg.append("g")
            .attr("transform", `translate(${MARGIN.LEFT-50}, ${MARGIN.TOP})`)
            .attr("class", "graph")

svg.append("defs")
        .append("svg:clipPath")
            .attr("id", "clip")
        .append("svg:rect")
            .attr("width", WIDTH )
            .attr("height", HEIGHT );

x = d3.scaleTime()
        .range([0, WIDTH]);

y = d3.scaleLinear()
        .range([HEIGHT , 0]);

panBehaviour = d3.zoom()
            .extent([[0, 0], [WIDTH, HEIGHT]])
            .translateExtent([[0, 0], [WIDTH, HEIGHT]])
            .scaleExtent([1, 1])
            .filter( ()=>!d3.event.button) 
            .on('zoom', panPlot)

pan  = svg.append('rect')
            .attr('class', 'pan')
            .attr("transform", `translate(${MARGIN.LEFT-50}, ${MARGIN.TOP})`)
            .attr("width", WIDTH )
            .attr("height", HEIGHT )
                .call(panBehaviour);

brush = d3.brushX()
            .extent([ [0, 0], [WIDTH, HEIGHT] ])
            .on("end", zoom) 

graph.append('g') 
        .attr('class', 'brush')
        .call(brush)

path = graph.append('path');
path.attr("clip-path", "url(#clip)"); 

// The panning function replaced with a log statement
panPlot() {
    if (d3.event.sourceEvent.ctrlKey){
        console.log("PANNING");
    }
};

// The zoom function replaced with a log statement
zoom(){ 
    if (!d3.event.sourceEvent.ctrlKey){ 
    console.log("ZOOMING");
    }
};



Здесь был задан очень похожий вопрос, но без решения. D3 v4 Bru sh и Zoom на одном и том же элементе (без конфликта событий мыши)

1 Ответ

0 голосов
/ 15 января 2020

Вы можете отключить / включить режимы панорамирования и bru sh при каждом нажатии / отпускании клавиши ctrl. Эти два поведения не могут сосуществовать, поэтому вы должны отключить одно. Ответ основан на d3 v5.

const noZoom = d3.zoom();

const doc = d3.select(document);
doc.on('keydown', () => {
    if (d3.event.key === "Control") {
        pan.call(noZoom);
    }
})

doc.on('keyup', () => {
    if (d3.event.key === "Control") {
        pan.call(panBehaviour);
    }
})

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...