d3 svg zoom не работает, когда существует соседний элемент - PullRequest
1 голос
/ 01 июля 2019

Я использую div, содержащий другие div, в качестве наложения поверх (или под) svg.Это позволит мне поставить богатые функции на основе HTML поверх SVG, такие как таблицы прокрутки, мало чем отличающиеся от наложений Google Maps.Я просто заставляю концепцию работать в данный момент, и основная трудность состоит в том, чтобы заставить div оставаться с точками SVG, к которым они привязаны.

Код масштабирования в приведенном ниже примере не работает, если я не удаляюили скрыть оверлейный div.

Я пробовал: - перемещать div из "outerdiv" - не работает, потому что div не получает данных (кажется, что функция ввода перестает работать) - установка z index наsvg и div оверлея - перемещение SVG до или после оверлея div

Что бы я ни делал, событие масштабирования не срабатывает, но если вы скрываете div с display:none или visibility:hidden в CSS,работает отлично

var
  outerwidth = 1000,
  outerheight = 500,
  width = outerwidth,
  height = outerheight,
  rectwidth = 200,
  rectheight = 50;
var div = d3.select(".outerdiv");
var overlay = div.select(".overlay");
var svg = div.select("svg")
  .attr("preserveAspectRatio", "xMidYMid")
  .attr("class", "svgnetwork");

var g = svg.append("g");

overlay.style("width", outerwidth + "px").style("height", outerheight + "px");

var data = [
  ["Test1", 15],
  ["Test2", 25],
  ["Test3", 10],
  ["Test4", 20]
];

var nodes = overlay.selectAll("div").data(data).enter().append("div").attr("class", "node")
  .style("top", function(d, i) {
    return i * 100 + "px";
  })
  .style("left", function(d, i) {
    return 0 + "px";
  })
  .style("width", rectwidth + "px")
  .style("height", rectheight + "px")

// inner text content of node
nodes
  .append("div").text(function(d, i) {
    return "Content : " + d[0] + " " + d[1];
  });

// rects which should appear in the same places as divs
g.selectAll("rect").data(data).enter().append("rect")
  .attr("class", "noderect")
  .attr("width", rectwidth)
  .attr("height", rectheight)
  .attr("y", function(d, i) {
    return i * 100;
  })
  .attr("x", 0);

// set svg viewbox
svg.attr("viewBox", "0 0 " + width + " " + height);

// uncomment the next line and zoom on svg works
// overlay.node().style.display = "none";
svg.call(d3.zoom()
  .scaleExtent([1 / 2, 2])
  .on("zoom", function() { // zoom fires on pan and zoom
    svg.attr("transform", d3.event.transform);
    return false;
  })
);
svg {
  background-color: #ffffee;
  z-index: 2;
}

.outerdiv {
  border: 1px solid black;
  margin: 5px;
  height: 500px;
  width: 1000px;
  position: relative;
  background-color: transparent;
}

.overlay {
  border: 1px solid blue;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
}

.node {
  box-sizing: border-box;
  border: 1px solid green;
  height: 25px;
  width: 150px;
  position: absolute;
}

.noderect {
  fill: none;
  stroke: red;
  stroke-width: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.7/d3.min.js"></script>
<div class="outerdiv">
  <div class="overlay"></div>
  <svg></svg>
</div>

Конечная цель - получить элементы div в оверлее для перемещения с содержимым SVG при масштабировании и панорамировании, но, очевидно, первым шагом являетсячтобы получить масштабирование вообще.

спасибо

РЕДАКТИРОВАТЬ: ЗАКЛЮЧИТЕЛЬНОЕ РЕШЕНИЕ, ВКЛЮЧАЯ МАСШТАБИРОВАНИЕ И ПЛАНИРОВАНИЕ OVERLAY

https://jsfiddle.net/paull3876/z6ef2uwg/

Подумал, что это может быть довольно распространенным требованием и, следовательно, кому-то полезно :)

1 Ответ

2 голосов
/ 01 июля 2019

вы можете добавить pointer-events:none; к оверлею div

.overlay {
  pointer-events:none;
}

, тогда базовый svg получит события мыши

var
  outerwidth = 1000,
  outerheight = 500,
  width = outerwidth,
  height = outerheight,
  rectwidth = 200,
  rectheight = 50;
var div = d3.select(".outerdiv");
var overlay = div.select(".overlay");
var svg = div.select("svg")
  .attr("preserveAspectRatio", "xMidYMid")
  .attr("class", "svgnetwork");

var g = svg.append("g");

overlay.style("width", outerwidth + "px").style("height", outerheight + "px");

var data = [
  ["Test1", 15],
  ["Test2", 25],
  ["Test3", 10],
  ["Test4", 20]
];

var nodes = overlay.selectAll("div").data(data).enter().append("div").attr("class", "node")
  .style("top", function(d, i) {
    return i * 100 + "px";
  })
  .style("left", function(d, i) {
    return 0 + "px";
  })
  .style("width", rectwidth + "px")
  .style("height", rectheight + "px")

// inner text content of node
nodes
  .append("div").text(function(d, i) {
    return "Content : " + d[0] + " " + d[1];
  });

// rects which should appear in the same places as divs
g.selectAll("rect").data(data).enter().append("rect")
  .attr("class", "noderect")
  .attr("width", rectwidth)
  .attr("height", rectheight)
  .attr("y", function(d, i) {
    return i * 100;
  })
  .attr("x", 0);

// set svg viewbox
svg.attr("viewBox", "0 0 " + width + " " + height);

// uncomment the next line and zoom on svg works
// overlay.node().style.display = "none";
svg.call(d3.zoom()
  .scaleExtent([1 / 2, 2])
  .on("zoom", function() { // zoom fires on pan and zoom
    svg.attr("transform", d3.event.transform);
    overlay.raise()
    return false;
  })
);
svg {
  background-color: #ffffee;
  z-index: 2;
}

.outerdiv {
  border: 1px solid black;
  margin: 5px;
  height: 500px;
  width: 1000px;
  position: relative;
  background-color: transparent;
}

.overlay {
  border: 1px solid blue;
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  pointer-events:none;
}

.node {
  box-sizing: border-box;
  border: 1px solid green;
  height: 25px;
  width: 150px;
  position: absolute;
}

.noderect {
  fill: none;
  stroke: red;
  stroke-width: 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.9.7/d3.min.js"></script>
<div class="outerdiv">
  <div class="overlay"></div>
  <svg></svg>
</div>

, но вам также необходимо применить преобразования к оверлею

...