2016-02-05 13 views
14

Mam zoom i pan działa na osi X, ale chciałbym dodać panoramowanie dla osi Y. Próbowałem użyć d3.behavior.zoom i d3.event.translate[1], aby uzyskać wartość translacji y i użyć tej wartości, ale wartość translate zmienia się podczas powiększania, więc podczas gdy przeciąganie z kliknięciem przesuwa oś y, powiększanie powoduje również przesunięcie osi y (w sposób nieintuicyjny).D3: Czy możliwe jest powiększanie + przesuwanie jednej osi i przesuwanie tylko drugiej?

Próbowałem również użyć dwóch instancji d3.behavior.zoom, jednej dla osi X i jednej dla osi Y, ale tylko ostatnia dodana jest wywoływana na zdarzeniach powiększania.

Oto przykład, który działa na zoom i pan w kierunku x, że Chciałbym również dodać y panoramowanie też (ale nie y powiększanie):

var x = d3.scale.linear() 
 
    .domain([0, 800]) 
 
    .range([0, 800]); 
 

 
var y = d3.scale.linear() 
 
    .domain([0, 800]) 
 
    .range([0, 800]); 
 

 
var rectangleSelector = d3.select('svg') 
 
    .append('g') 
 
    .selectAll('rect') 
 
    .data([[0, 0], [50, 50], [100, 100]]) 
 
    .enter() 
 
    .append('rect') 
 
    .attr('fill', 'black') 
 
    .attr('x', d => x(d[0])) 
 
    .attr('y', d => y(d[1])) 
 
    .attr('width', d => x(d[0] + 40) - x(d[0])) 
 
    .attr('height', d => y(40)); 
 
    
 
d3.select('svg') 
 
    .call(d3.behavior.zoom().x(x).on('zoom',() => { 
 
    rectangleSelector 
 
     .attr('x', d => x(d[0])) 
 
     .attr('y', d => y(d[1])) 
 
     .attr('width', d => x(d[0] + 40) - x(d[0])) 
 
     .attr('height', d => y(40)); 
 
    }));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<svg width="800" height="800"></svg>

W ten Przykład Podejmuję próbę użycia wartości y z d3.event.translate[1] i działa ona w przypadku przeciągania, ale niepożądane zachowanie polega na tym, że w zależności od tego, gdzie mysz jest powiększana, zmienia ona również wartość translacji dla osi y.

var x = d3.scale.linear() 
 
    .domain([0, 800]) 
 
    .range([0, 800]); 
 

 
var y = d3.scale.linear() 
 
    .domain([0, 800]) 
 
    .range([0, 800]); 
 

 
var rectangleSelector = d3.select('svg') 
 
    .append('g') 
 
    .selectAll('rect') 
 
    .data([[0, 0], [50, 50], [100, 100]]) 
 
    .enter() 
 
    .append('rect') 
 
    .attr('fill', 'black') 
 
    .attr('x', d => x(d[0])) 
 
    .attr('y', d => y(d[1])) 
 
    .attr('width', d => x(d[0] + 40) - x(d[0])) 
 
    .attr('height', d => y(40)); 
 
    
 
d3.select('svg') 
 
    .call(d3.behavior.zoom().x(x).on('zoom',() => { 
 
    var translateY = d3.event.translate[1]; 
 
    
 
    rectangleSelector 
 
     .attr('x', d => x(d[0])) 
 
     .attr('y', d => y(d[1] + translateY)) 
 
     .attr('width', d => x(d[0] + 40) - x(d[0])) 
 
     .attr('height', d => y(40)); 
 
    }));
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<svg width="800" height="800"></svg>

+0

'd3.behavior.zoom()' jest chainable z 'x() 'i' y()'; Podaję tylko 'x()', więc zachowanie zoomu zmienia tylko oś X. Ale wciąż zgłasza tłumienie wartości dla osi Y, które chciałbym wykorzystać do przetłumaczenia tej osi - problem polega na tym, że są one powiększane, a nie tylko przesuwane. – Beau

+1

Jestem również w trakcie tworzenia JSFiddle. – Beau

+0

Może to: http://bl.ocks.org/jgbos/9752277 – altocumulus

Odpowiedz

10

JSFIDDLE: https://jsfiddle.net/sladav/o8vaecyn/

Na początek, zachowanie zoom obsługuje zarówno przesuwania i powiększania na osi x, a to jest obsługiwane przez ...

var zoom = d3.behavior.zoom() 
    .x(x) 
    .scaleExtent([1, 10]) 
    .on("zoom", zoomed); 

Więc użyjemy zoomu do obsłużyć rzeczy osi X.

DLA osi Y, aby uzyskać WŁAŚNIE pan zachowanie ...

Utwórz osobny zachowanie przeciągania że oddaje „dy”, przesuwa domenę Y i występuje ponownie go.

  1. Dodaj w zachowaniu przeciągania

    var drag = d3.behavior.drag() 
        .on("drag", dragging) 
    
  2. Niech domeny skali y za być zmienna (będziemy modyfikować że jak przeciągnąć)

    var yPan = 0; 
    var yMin = (-height/2); 
    var yMax = (height/2); 
    
    var y = d3.scale.linear() 
        .domain([yMin, yMax]) 
        .range([height, 0]); 
    
  3. dodać funkcję do przeskalowania oś Y na zdarzeniu przeciągania

    function dragging(d) { 
        yPan = d3.event.dy; 
        yMin += yPan; 
        yMax += yPan; 
        y.domain([yMin, yMax]) 
        d3.select(".y.axis").call(yAxis)}; 
    
  4. funkcję oporu połączeń z elementem SVG

    var svg = d3.select("body").append("svg") 
        .attr("width", width + margin.left + margin.right) 
        .attr("height", height + margin.top + margin.bottom) 
        .append("g") 
         .attr("transform", "translate(" + margin.left + "," + margin.top + ")") 
         .call(zoom) 
         .call(drag); 
    
2

Mam zorientowali się jeden sposób, aby to zrobić, ale wydaje się, jakby gigantyczny Hack:

var lastY = 0; 

var zoom = d3.behavior.zoom().x(x); 

zoom.on('zoom',() => { 
    var translateY; 

    if (d3.event.sourceEvent.type === 'mousemove') { 
    // if it's a drag event then use the value from the drag 
    translateY = d3.event.translate[1]; 
    lastY = translateY; 
    } else { 
    // if it's a wheel event then set the y translation to the last value 
    translateY = lastY; 
    zoom.translate([d3.event.translate[0], translateY]); 
    } 

    // translateY can now be used here as an offset to any drawing like so: 
    rectangleSelector.attr('y', y(d[1] + translateY)); 
}); 
0

Można użyć

zoom.center
celu uzyskania kodu nieco czystsze, tak:

var lastY = 0; 
 
var x = d3.scale.linear() 
 
    .domain([0, 800]) 
 
    .range([0, 800]); 
 

 
var y = d3.scale.linear() 
 
    .domain([0, 800]) 
 
    .range([0, 800]); 
 

 
var rectangleSelector = d3.select('svg') 
 
    .append('g') 
 
    .selectAll('rect') 
 
    .data([[0, 0], [50, 50], [100, 100]]) 
 
    .enter() 
 
    .append('rect') 
 
    .attr('fill', 'black') 
 
    .attr('x', d => x(d[0])) 
 
    .attr('y', d => y(d[1])) 
 
    .attr('width', d => x(d[0] + 40) - x(d[0])) 
 
    .attr('height', d => y(40)); 
 
    
 
var zoom = d3.behavior.zoom().center([400, 400]).x(x); 
 
zoom.on('zoom',() => { 
 
    var translateY = d3.event.translate[1]; 
 
    zoom.center([400, translateY]); 
 
    rectangleSelector.attr('x', d => x(d[0])) 
 
         .attr('y', d => y(d[1] + translateY)) 
 
         .attr('width', d => x(d[0] + 40) - x(d[0])) 
 
         .attr('height', d => y(40)); 
 
}); 
 

 
d3.select('svg').call(zoom);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 
 
<svg width="800" height="800"></svg>

+0

Początkowy zoom wciąż zmienia oś pionową czasami, gdy próbuję tego fragmentu kodu. – Beau

+0

Zależy od tego, do czego zostało ustawione początkowe centrum. Możesz spróbować zmienić początkowy zoom na osi Y na 50 (który w twoim przypadku jest środkiem początkowej osi Y) – Doktorn

Powiązane problemy