У меня есть рабочий код на простом 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>`
}Спасибо за эту информацию. Но все же остается вопрос, почему способ D3.js не работает. например var gplant = this.gardenbox.selectAll ("g") [...]. on ("click", this.clickPlant) Есть идеи по этому поводу?
.on("click", ...) у меня работает, но я использую встроенную функцию, а не метод Vue. Это работает? .on("click", () => d3.selectAll(".selected").raise().classed("selected",false))Я не знаю, сможете ли вы собрать фрагмент кода или скрипку, демонстрирующую проблему. У меня недостаточно четкого представления о том, что вы пытаетесь сделать и где.
В общем, я добавляю какую-то группу svg (gplant), и они должны быть перетаскиваемыми. Я постараюсь сделать отрывок позже в этот же день.
@Hiram Я только что попробовал, но встроенная функция не работает. Вроде как просто не зацепило.
Это может быть что-то в настройке. Можете ли вы опубликовать свое полное репо на Github для сравнения?
Я только что перешел на использование метода Vue, и он мне тоже подходит.
Проверяя ваши настройки bg, я могу получить щелчок, работающий с var bg = d3.select('svg').on("click", this.clickBG). Однако щелчки не на пузыре bg до этого обработчика и d3.event имеет значение null, поэтому d3.event.stopPropagation() завершается ошибкой.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вот результат некоторых экспериментов, которые работают в моем приложении 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
}
Чтобы сделать это способом Vue, вам нужно, чтобы
v-on:clickбыл частью шаблона, а не частью DOM. Куда вы пытаетесь привязать события щелчка?