2012-11-21 16 views
6

क्या उपयोगकर्ता ज़ूम की गति को समायोजित कर सकता है जब उपयोगकर्ता mousewheel का उपयोग करके अंदर और बाहर स्क्रॉल करता है?डी 3 में ज़ूम इन और आउट करते समय अनुवाद और स्केल की गति को कैसे बदलें (zoom.on और d3.event.translate, d3.event.zoom का उपयोग करके)?

मेरे समझ के साथ कि zoom.on (https://github.com/mbostock/d3/wiki/Zoom-Behavior#wiki-on) श्रोता का उत्पादन दो घटनाओं & d3.event.zoom, जो मैट्रिक्स हैं या निर्देशांक है कि जब अनुवाद या पैमाने कार्यों के लिए पारित कर दिया, पैनिंग अनुमति देते हैं d3.event.translate है और ग्राफिक के rescaling।

लेकिन मैं इसे कैसे गति दूं, ताकि यदि उपयोगकर्ता अपने मूसहेल को थोड़ा सा स्थानांतरित कर लेता है, तो वह तेजी से ज़ूम इन या आउट हो जाती है? मेरे पास एक बड़ा विज़ुअलाइजेशन है कि मैं उपयोगकर्ताओं को मूसहेल के साथ तेजी से ज़ूम इन और आउट करने की अनुमति देना चाहता हूं। क्या मैं उपरोक्त मौजूदा घटनाओं और कार्यों में तर्क को संशोधित/जोड़ सकता हूं या क्या मुझे अपना खुद का बनाना है? मुझे लगता है कि उपरोक्त में से कुछ समझने के मामले में गलत/पैची है, इसलिए कृपया बताएं।

बहुत ही सरल jsfiddle यहाँ उदाहरण: http://jsfiddle.net/fiddler86/6jJe6/, नीचे दिए गए समान कोड के साथ:

var svg = d3.select("body").append("svg:svg") 
     .attr("width", 1000) 
     .attr("height", 2000)  
     .append("svg:g") 
      .call(d3.behavior.zoom().on("zoom", redraw)) 
     .append("svg:g"); 

svg.append("svg:rect") 
.attr("width", 200) 
.attr("height", 300) 
.attr("fill", 'green'); 

function redraw() { 
    svg.attr("transform", "translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")"); 
};  
+0

क्या आपने इसे समझ लिया? – kishanio

+1

@ किशनानियो मैंने एक समाधान का प्रस्ताव दिया –

उत्तर

5

जब आप समारोह महत्वपूर्ण चयन एक गणितीय समारोह के साथ समारोह के अंदर पैमाने को समायोजित की जरूरत है कि x = 0 के लिए y = 0 आप इस मामले में पाउ का उपयोग आसान कर सकते हैं Math.pow(d3.event.scale,.1) दूसरा पैरामीटर ज़ूम अधिक धीरे-धीरे ज़ूम करता है।

यह एक अच्छा विचार नहीं है कि एक बहुत ही जटिल कार्य का उपयोग करें क्योंकि ब्राउज़र धीमा हो जाएगा।

जब आपके पास नया स्तर है, तो आपको अनुवाद को फिर से समझना होगा। आप समस्या को जटिल नहीं करते हैं, एसवीजी में आपके पास this.getBBox().height के साथ वास्तविक ऊंचाई है, लेकिन यह ठीक नहीं है क्योंकि आप पीछे एक पुनरावृत्ति हैं। आप (originalHeight * scale) के साथ नए ऊंचाई की गणना कर सकते हैं और साथ (originalHeight - (originalHeight * scale))/2

  • खैर origialHeight * पैमाने newHeight

  • originalHeight है का अनुवाद - newHeight अंतर है, और आप केंद्र चाहते हैं, आप विभाजन की जरूरत है 2 के लिए, वर्ग का आधा हिस्सा और नीचे आधा हिस्सा।

  • अब हमें चौड़ाई के साथ कार्रवाई करने की आवश्यकता है। यह वही

कोड है:

var svg = d3.select("body").append("svg:svg") 
       .attr("width", 1000) 
       .attr("height", 2000)  
       .append("svg:g") 
        .call(d3.behavior.zoom().on("zoom", redraw)) 
       .append("svg:g"); 

    svg.append("svg:rect") 
     .attr("width", 200) 
     .attr("height", 300) 
     .attr("fill", 'green'); 

    function redraw() { 
     var velocity = 1/10; 
     var scale = Math.pow(d3.event.scale,velocity); 
     var translateY = (300 - (300 * scale))/2; 
     var translateX = (200 - (200 * scale))/2; 

     svg.attr("transform", "translate(" + [translateX,translateY] + ")" + " scale(" +scale+ ")");    
    }; 

ध्यान दें कि मैं 200 और 300 डाल हार्डकोडेड, आप एक संपत्ति का उपयोग कर सकते, निरंतर का उपयोग करें ...

मेरे द्वारा बनाए गए एक फिडलर: http://jsfiddle.net/t0j5b3e2/

1

मैंने 4x ज़ूम गति रखने के लिए mbostock के drag+zoom example को संशोधित किया है और इसेमें रखा है 210। मैंने नीचे अपनी सोच समझाई है। यह एक स्टैक ओवरफ़्लो उत्तर पर मेरा पहला प्रयास है, कृपया अच्छा रहें।

जैसा कि राउल मार्टिन के उत्तर में बताया गया है, आप ज़ूम की दर बदलने के लिए redraw() फ़ंक्शन के भीतर एक सूत्र का उपयोग कर सकते हैं। आपको यह सुनिश्चित करने के लिए कुछ अतिरिक्त कदम उठाने होंगे कि डी 3 व्यवहार अभी भी संशोधित ज़ूम दर के साथ अच्छी तरह से काम करता है।

ज़ूम (जैसे कर्सर) एक चुने हुए बिंदु पर केंद्रित
डिफ़ॉल्ट d3 व्यवहार करके माउस सूचक पर, उदाहरण के लिए ज़ूम केंद्रित अगर आपके पास छवि के ऊपरी बाईं ओर माउस पॉइंटर है तो यह छवि के केंद्र की बजाय ऊपरी बाईं ओर ज़ूम करता है। इस प्रभाव को प्राप्त करने के लिए यह छवि को स्केल करता है और फिर छवि के अनुवाद को भी बदलता है ताकि माउस कर्सर के नीचे बिंदु स्क्रीन पर एक ही स्थान पर रहता है। यही कारण है कि जब आप mousewheel स्क्रॉल करते हैं तो zoom.translate() का मान बदलता है, भले ही छवि ऐसा दिखाई न दे, यह स्क्रीन पर आगे बढ़ रहा है।

यदि आप ज़ूम गति बदलते हैं तो d3 zoom.translate() मान अब सही नहीं हैं। तो

var prev_translate = [100,100] // x, y translation of the image in last redraw 
var prev_scale = 0.1   // Scale applied to the image last redraw 
var new_scale = 0.4   // The new scale being applied 
var zoom_cp = [150, 150]  // The zoom "center point" e.g. mouse pointer 

सूत्र new_translate बाहर काम करने के छवि के लिए लागू करने के लिए किया गया है:: सही अनुवाद बाहर काम करने के लिए आप निम्नलिखित जानकारी (संख्यात्मक मान ध्यान न दें) पता करने की जरूरत

new_translate[0] = zoom_cp[0] - (zoom_cp[0] - prev_translate[0]) 
    * new_scale/prev_scale; 
new_translate[1] = zoom_cp[1] - (zoom_cp[1] - prev_translate[1]) 
    * new_scale/prev_scale; 

आप के साथ अपने नए पैमाने के साथ छवि के लिए लागू कर सकते हैं:

svg.attr("transform", "translate(" + new_translate + ")scale(" + new_scale + ")"); 

फिर आप अद्यतन करने के लिए prev_scale = new_scale और prev_translate = new_translate के लिए तैयार होगा

d3 ज़ूम व्यवहार स्केलिंग के बिना redraw()

पान की अगले चरण आप क्लिक करके और खींचकर स्केलिंग के बिना पैन करने के लिए अनुमति देता है। यदि आप क्लिक करते हैं और खींचते हैं तो zoom.scale() वही रहता है लेकिन zoom.translate() परिवर्तन रहता है। ज़ूम गति को संशोधित करने के बाद भी नया zoom.translate() मान अभी भी सही है। हालांकि, आपको यह जानने की आवश्यकता है कि इस zoom.translate() मान का उपयोग कब करें और उस अनुवाद मूल्य का उपयोग कब करें जब आप केंद्र बिंदु पर ज़ूम करने के लिए गणना करते हैं।

new scale जैसा ही है या नहीं, यह देखकर आप काम कर सकते हैं कि पैन या ज़ूम हो रहा है या नहीं। यदि दो मान समान हैं तो आप जानते हैं कि एक पैन हो रहा है और आप छवि को स्थानांतरित करने के लिए new_translate = zoom.translate() का उपयोग कर सकते हैं। अन्यथा, आप जानते हैं कि ज़ूम हो रहा है और आप ऊपर वर्णित अनुसार new_translate मान की गणना कर सकते हैं। मैं zoomstart ईवेंट में एक फ़ंक्शन जोड़ कर ऐसा करता हूं।

var zoom_type = "?"; 
var scale_grad = 4; // Zoom speed multiple 
var intercept = 1 * (1 - scale_grad) 

var svg = d3.select("body").append("svg:svg") 
      .attr("width", 1000) 
      .attr("height", 2000)  
      .append("svg:g") 
       .call(d3.behavior.zoom() 
         .on("zoom", redraw) 
         .on("zoomstart", zoomstarted)) 
      .append("svg:g"); 

function zoomstarted() { 
    zoom_type = "?"; 
} 

function redraw() { 
    var scale = d3.event.scale; 

    // Use a linear scale, don't let it go below the minimum scale 
    // extent 
    var new_scale = Math.max(scale_grad * scale + intercept, 
         scale_extent[0]); 

    // If hit the minimum scale extent then stop d3 zoom from 
    // going any further 
    if (new_scale == scale_extent[0]) { 
     zoom.scale((scale_extent[0] - intercept)/scale_grad); 
    } 

    // Set up zoom_type if have just started 
    // If the scale hasn't changed then a pure translation is 
    // taking place, otherwise it is a scale 
    if (zoom_type == "?") { 
     if (new_scale == prev_scale) { 
      zoom_type = "translate" 
     } else { 
      zoom_type = "scale" 
     } 
    } 

    // zoom_cp is the static point during the zoom, set as 
    // mouse pointer position (you need to define a listener to track) 
    var new_translate = [0, 0]; 
    zoom_cp = [mouse_x, mouse_y]; 

    // If the event is a translate just apply d3 translate 
    // Otherwise calculate what translation is required to 
    // keep the zoom center point static 
    if (zoom_type == "translate") { 
     new_translate = d3.event.translate 
    } else if (zoom_type == "scale") { 
     new_translate[0] = zoom_cp[0] 
      - (zoom_cp[0] - prev_translate[0]) * new_scale/prev_scale; 
     new_translate[1] = zoom_cp[1] 
      - (zoom_cp[1] - prev_translate[1]) * new_scale/prev_scale; 
} 

     // Update the variables that track the last iteration of the 
     // zoom 
     prev_translate = new_translate; 
     prev_scale = new_scale; 
     zoom.translate(new_translate); 

     // Apply scale and translate behaviour 
     svg.attr("transform", "translate(" + new_translate + 
      ")scale(" + new_scale + ")"); 
}