Как работает координата "d3.translateExtent"? - PullRequest
0 голосов
/ 14 декабря 2018

jsfiddle DEMO

Я пытаюсь добавить перетаскивание в круг и пытаюсь применить translateExtent.Так как же ограничить границу перетаскивания прямоугольником?Как рассчитывается граница по координатам.

1 Ответ

0 голосов
/ 14 декабря 2018

Здесь есть несколько соображений, и, учитывая то, что они, конечно, были спокоены ими в прошлом, я надеюсь, что смогу объяснить их здесь ясно.

Экстент масштабирования

Давайте рассмотрим экстент масштабирования (zoom.extent) - не переводить экстент.Экстентом по умолчанию является «[[0, 0], [width, height]], где width - это ширина клиента элемента, а height - его высота клиента» ( d3-zoom docs ).Поскольку вы вызываете масштабирование на svg, экстент по умолчанию должен быть [0,0],[width,height], где ширина и высота в вашем случае равны 500.

Ваш экстент перевода, [100,100],[400,400] меньше чем ваш масштаб, это не сработает, от Майка Бостока (Mike Bostock) по аналогичной проблеме: «Проблема в том, что указанный вами translateExtent меньше, чем экстент масштабирования. Поэтому нет способа удовлетворить запрошенное ограничение."( средство отслеживания проблем d3-zoom ).

TranslateExtent

Проблема заключается в том, что вы используете неверный перевод экстента.Указанный вами экстент перевода - это границы, которые вы хотите ограничить кругом.Но это не равно экстенту перевода, который представляет собой границы координатного пространства, которое вы хотите показать (границы мира, в котором находится круг) при заданном экстенте масштабирования.

Давайте рассмотрим круг в [100,100], он центрирован там с трансфокацией с помощью translate(0,0): он находится в начальной позиции.Это помечает верхнюю левую позицию для ограничительной рамки, в которой вы надеетесь ограничить окружность. Верхняя левая координата увеличения в этой точке равна [0,0].В правом нижнем углу экстента масштабирования или области просмотра находится [500,500].

Если окружность находится в [400,400], в правом нижнем углу ее предполагаемого движения она имеет преобразование translate(300,300), так как оно равно 300пиксели вправо и 300 пикселей вниз от того места, где это началось (изначально с помощью cx / cy).Учитывая, что все смещено на 300 пикселей вниз и вправо, верхний левый угол области просмотра или масштабирования теперь равен [-300,-300] (круг с cx, cy из -300 будет иметь центр в верхнем левом углу SVG, учитывая преобразование масштабирования).И в правом нижнем углу - [200,200].

. Для начала, когда круг не может двигаться дальше вверх или влево, у нас есть показанный экстент [0,0],[500,500], а когда круг находится в правом нижнем углу, когдакруг не может двигаться дальше вниз или вправо, у нас есть показанный экстент [-300,-300],[200,200].

Если брать крайности, то максимальный экстент, который мы хотим получить, равен: [-300,-300],[500,500], это экстент мира, который мы хотим показать, чтобы круг оставался перекрывающимся с прямоугольником:

var height = 500;
var width = 500;

var zoom = d3.zoom()
   .translateExtent([[-300, -300], [500, 500]])
    .on("zoom", zoomed);

var svg = d3.select("body")
        .append("svg")
        .attr("width", height)
        .attr("height", width)
        .append("g")
        
svg.append("rect")
        .attr("x", 100)
        .attr("y", 100)
        .attr("height", 300)
        .attr("width", 300);
           
    var circle = svg.append("circle")
        .attr("cx", 100)
        .attr("cy", 100)
        .attr("r", 20)
        .style("fill", "red")
        
    svg.call(zoom);
    
    function zoomed() {
      circle.attr("transform", d3.event.transform);
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

Возможное уточнение

Если мы используем масштабирование с шириной и высотой, равными ширине и высотепрямоугольник:

.extent([[0,0],[300,300]])

Нам не нужно расширять наш translateExtent для учета пустого пространства вокруг прямоугольника, который все еще находится внутри SVG:

.translateExtent([[-300,-300],[300,300]])

var height = 500;
var width = 500;


//if extent is specified, sets the translate extent to the specified array of points [[x0, y0], [x1, y1]], where [x0, y0] is the top-left corner of the world and [x1, y1] is the bottom-right corner of the world, and returns this zoom behavior. 
var zoom = d3.zoom()
    .translateExtent([[-300,-300],[300,300]])
    .extent([[0,0],[300,300]])
    .on("zoom", zoomed);
    
    console.log(zoom.extent());
    
    // Feel free to change or delete any of the code you see in this editor!
    var svg = d3.select("body")
        .append("svg")
        .attr("width", height)
        .attr("height", width);
        
     svg.append("rect")
        .attr("x", 100)
        .attr("y", 100)
        .attr("height", 300)
        .attr("width", 300);
           
    var circle = svg.append("circle")
        .attr("cx", 100)
        .attr("cy", 100)
        .attr("r", 20)
        .style("fill", "red")
        
    svg.call(zoom);
    
    function zoomed() {
      circle.attr("transform", d3.event.transform);
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
...