D3.js в компоненте vue - как привязать события мыши к элементам?

У меня есть рабочий код на простом javascript для интерактивной карты D3.js, и теперь я пытаюсь создать из него компонент vue.js. Я определил все функции как методы, и я не получаю никаких предупреждений или сообщений об ошибках, но ни одно из событий мыши не обрабатывается. Я пробовал оба, способ D3.js (.on ("click", this.clickBG)), так и vue (.attr ("v-on: click", "clickBG")) безуспешно.

    // vorlage: https://dev.to/ignoreintuition/binding-data-to-charts-using-vue-components-and-d3-4i27
    import * as d3 from 'd3';
    
    export default {
        props: ['data','vegbed'], 
        data: function () {
            return {
                gardenbox: {}
            }
        },
        computed: {
            displaywidth: function() { return 600; },
            displayheight: function() { return this.displaywidth*(this.vegbed.length/this.vegbed.width); },
            margin: function() { return {top: 0, right: 0, bottom: 0, left: 0}; }
        },
        methods: {
            initalizeChart: function () {
                this.drawGardenBox();
            },

            virtDia: function (realDia) {
                return (this.displaywidth/this.vegbed.width)*realDia;
            },
            
            clickPlant: function() {
                d3.selectAll(".selected").raise().classed("selected",false);
                d3.select(_this).selectAll(".plant").raise().classed("selected", true);
                d3.selectAll("#"+this.id).classed("selected", true);      
            },
            clickBG: function() {
                console.info("click");
                d3.selectAll(".selected").raise().classed("selected",false);
            },
            
            draggedPlant: function(d) {
                d3.select(this).attr("transform","translate("+(d.x = d3.event.x)+","+(d.y = d3.event.y)+")");
            },
            
            dragStartedPlant: function() {
                d3.selectAll(".selected").raise().classed("selected",false);
                d3.select(this).selectAll(".plant").raise().classed("selected", true);
                d3.selectAll("#"+this.id).classed("selected", true);

                //d3.event.sourceEvent.stopPropagation();
            },    
            dragEndedPlant: function(d) {
                
            },
            refreshBed: function () {
                let _this = this; // Workaround to call functions from inside callbacks
                var gplant = this.gardenbox.selectAll("g")
                    .data(this.data).enter().append("g")
                    .attr("id", function(d){ return d.id; })
                    .attr("transform", function(d){ return "translate("+d.x+","+d.y+")";  })
                    .on("click", this.clickPlant)
                    //.attr("v-on:click","this.clickPlant")
                    .call(d3.drag()
                    .on("start", this.draggedPlant)
                    .on("drag", this.dragStartedPlant)
                    .on("end", this.dragEndedPlant));

                gplant.append("circle") // max size
                    .attr('class', 'plant')
                    .attr("cx", function(d) { return d.x; })
                    .attr("cy", function(d) { return d.y; })
                    .attr("r", function(d) { return _this.virtDia(d.plant.adult_diameter); });

                gplant.append("circle") // min size
                    .attr('class', 'plant')
                    .attr("cx", function(d) { return d.x; })
                    .attr("cy", function(d) { return d.y; })
                    .attr("r", function(d) { return _this.virtDia(d.plant.exposure_diameter); });

                gplant.append("image")
                    .attr('class', 'plant')
                    .attr("xlink:href", function(d) { return d.picref; })
                    .attr("x", function(d) { return d.x-(d.picsize/2); })
                    .attr("y", function(d) { return d.y-(d.picsize/2); })
                    .attr("width", function(d) { return d.picsize; })
                    .attr("height", function(d) { return d.picsize; });
            },
            
            drawGardenBox: function () {
                this.gardenbox = d3.select('#vegbedcontainer').append('svg')
                        .attr("width", this.displaywidth + this.margin.left + this.margin.right)
                        .attr("height", this.displayheight + this.margin.top + this.margin.bottom)
                // hintergrund für deselect zeichen
                var bg = this.gardenbox.append("g")
                        //.attr("v-on:click","clickBG");
                        .on("click", this.clickBG); // unselect on background click

                bg.append("rect") 
                    .attr('class', 'bg')
                    .attr("x", this.margin.left)
                    .attr("y", this.margin.top)
                    .attr("width", this.displaywidth + this.margin.left + this.margin.right)
                    .attr("height", this.displayheight + this.margin.top + this.margin.bottom)
            }
        },


        // lifecycle events
        mounted: function () { // <-- lifecycle events
            console.info('VegBedEditor mounted.')
            this.initalizeChart();
            this.refreshBed();
        },
        // watch functions
        watch: { // <-- watch functions
            'data': {
                handler: function (val) {
                    this.refreshBed();
                },
                deep: true
            }
        },
        template: `<div id = "vegbedcontainer"><!-- SVG goes here --></div>`
    }

Чтобы сделать это способом Vue, вам нужно, чтобы v-on:click был частью шаблона, а не частью DOM. Куда вы пытаетесь привязать события щелчка?

Roy J 11.12.2018 00:21

Спасибо за эту информацию. Но все же остается вопрос, почему способ D3.js не работает. например var gplant = this.gardenbox.selectAll ("g") [...]. on ("click", this.clickPlant) Есть идеи по этому поводу?

Christian 11.12.2018 00:23
.on("click", ...) у меня работает, но я использую встроенную функцию, а не метод Vue. Это работает? .on("click", () => d3.selectAll(".selected").raise().classed("selected",false))
user9161752 11.12.2018 02:01

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

Roy J 11.12.2018 02:38

В общем, я добавляю какую-то группу svg (gplant), и они должны быть перетаскиваемыми. Я постараюсь сделать отрывок позже в этот же день.

Christian 11.12.2018 07:53

@Hiram Я только что попробовал, но встроенная функция не работает. Вроде как просто не зацепило.

Christian 11.12.2018 22:55

Это может быть что-то в настройке. Можете ли вы опубликовать свое полное репо на Github для сравнения?

user9161752 11.12.2018 23:04

Я только что перешел на использование метода Vue, и он мне тоже подходит.

user9161752 11.12.2018 23:25

Проверяя ваши настройки bg, я могу получить щелчок, работающий с var bg = d3.select('svg').on("click", this.clickBG). Однако щелчки не на пузыре bg до этого обработчика и d3.event имеет значение null, поэтому d3.event.stopPropagation() завершается ошибкой.

user9161752 12.12.2018 00:48
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
9
2 155
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вот результат некоторых экспериментов, которые работают в моем приложении Vue.

Настройка обработчика кликов на фоне svg

drawGardenBox: function () {
  this.gardenbox = d3.select('#vegbedcontainer').append('svg')
    .attr("width", this.displaywidth + this.margin.left + this.margin.right)
    .attr("height", this.displayheight + this.margin.top + this.margin.bottom)

  var bg = d3.select('svg')
    .on("click", this.clickBG); // unselect on background click

Остановка распространения кликов от другого обработчика

clickPlant: function() {
  d3.selectAll(".selected").raise().classed("selected",false);
  d3.select(_this).selectAll(".plant").raise().classed("selected", true);
  d3.selectAll("#"+this.id).classed("selected", true); 
  d3.event.stopPropagation(); 
},

Настройка d3.event

Я импортирую только выбранные части библиотеки d3, включая event, но изначально d3.event.stopPropagation() не работал, потому что d3.event был нулевым.

Благодаря этому вопросу импорт d3.event в пользовательскую сборку с помощью накопительного пакета, я изменил импорт event, и теперь он работает

import { select, selectAll, event, customEvent } from 'd3-selection'
import { zoom } from 'd3-zoom'
import { tree, hierarchy } from 'd3-hierarchy'

export const d3 = {
  select,
  selectAll,
  tree,
  hierarchy,
  zoom,
  // event,
  get event() { return event; },
  customEvent
}

Другие вопросы по теме