2017-12-03 20 views
5

के साथ एक अंतहीन क्षैतिज अक्ष बनाना I d3 v4 (4.12.0) का उपयोग कर रहा हूं।डी 3 v4

मेरे पास एक एसवीजी कंटेनर है जिसमें मैं एक साधारण क्षैतिज अक्ष (एक्स-अक्ष, रैखिक पैमाने) खींच रहा हूं जो माउस के साथ पैनिंग का जवाब देता है।

मैं एक "अनंत" या "अंतहीन" क्षैतिज धुरी अनुकरण करना चाहता हूं।

इसके द्वारा, मेरा मतलब है कि मैं केवल एक बहुत बड़े डेटासेट का एक छोटा सा हिस्सा लोड करना और प्रस्तुत करना चाहता हूं, और केवल इतना अक्ष खींचता हूं जो इस बड़े सेट से तत्वों का बहुत छोटा सबसेट दिखाता है।

कहें कि मेरे पास क्षैतिज धुरी है जो वस्तुओं की एक बड़ी सरणी से 10 डेटा पॉइंट दिखाती है। मेरे पास offset पैरामीटर है जो इस सरणी के पहले दस बिंदु दिखाने के लिए 0 से शुरू होता है।

मेरे प्रक्रिया:

जब मैं करने के लिए धुरी स्क्रॉल दूर 11 वीं और बाद में डेटा बिंदु दिखाने के लिए पर्याप्त है, मैं फिर बाएं:

  1. अद्यतन offset पैरामीटर प्रतिबिंबित करने के लिए कितने इकाइयों मैं अनुवाद किया है

  2. अद्यतन x- अक्ष पैमाने पर, नए ऑफसेट मूल्य

  3. पुन बंद आधारित अद्यतन पैमाने की सीमा के साथ अक्ष लेबल आकर्षित (x_scale)

  4. अनुवाद समूह पिक्सल कि धुरी पर एक इकाई का प्रतिनिधित्व की संख्या से अक्ष युक्त तत्व (scroller_element_width)

मेरे प्रयास काम करता है चरण 3 पर। यह प्रक्रिया चरण 4 पर विफल होने लगती है, जिसमें अक्ष का अंतिम अनुवाद कभी नहीं होता है।

संपूर्ण धुरी बाईं ओर ले जाया गया है, और इसमें ताजा लेबल हैं, लेकिन यह उन अद्यतन लेबल के साथ दाईं ओर नहीं जाता है - यह मूल रूप से पृष्ठ से गिर जाता है।

मैं यहां डी 3 विशेषज्ञों से पूछना चाहता हूं कि यह चरण क्यों विफल रहा है और मैं इसे ठीक करने के लिए क्या कर सकता हूं।

renderScroller() { 
    console.log("renderScroller called"); 
    if ((this.state.scrollerWidth == 0) || (this.state.scrollerHeight == 0)) return; 

    const self = this; 
    const scroller = this.scrollerContainer; 
    const scroller_content = this.scrollerContent; 
    const scroller_width = this.state.scrollerWidth; 
    const scroller_height = this.state.scrollerHeight; 

    var offset = 0, 
     limit = 10, 
     current_index = 10; 

    var min_translate_x = 0, 
     max_translate_x; 

    var scroller_data = Constants.test_data.slice(offset, limit); 

    var x_extent = d3.extent(scroller_data, function(d) { return d.window; }); 
    var y_extent = [0, d3.max(scroller_data, function(d) { return d.total; })]; 

    var x_scale = d3.scaleLinear(); 
    var y_scale = d3.scaleLinear(); 

    var x_axis_call = d3.axisTop(); 

    x_scale.domain(x_extent).range([0, scroller_width]); 
    y_scale.domain(y_extent).range([scroller_height, 0]); 

    x_axis_call.scale(x_scale); 

    d3.select(scroller_content) 
     .append("g") 
     .attr("class", "x axis") 
     .attr("transform", "translate(" + [0, scroller_height] + ")") 
     .call(x_axis_call); 

    var scroller_element_width = parseFloat(scroller_width/(x_scale.domain()[1] - x_scale.domain()[0])); 

    var pan = d3.zoom() 
     .on("zoom", function() { 

     var t = parseSvg(d3.select(scroller_content).attr("transform")); 
     var x_offset = parseFloat((t.translateX + d3.event.transform.x)/scroller_element_width); 

     // 
     // lock scale and prevent y-axis pan 
     // 
     d3.event.transform.y = 0; 
     if (d3.event.transform.k == 1) { 
      d3.event.transform.x = (x_offset > 0) ? 0 : d3.event.transform.x; 
     } 
     else { 
      d3.event.transform.k = 1; 
      d3.event.transform.x = t.translateX; 
     } 
     d3.select(scroller_content).attr("transform", d3.event.transform); 

     t = parseSvg(d3.select(scroller_content).attr("transform")); 
     x_offset = parseFloat(t.translateX/scroller_element_width); 

     var test_offset = Math.abs(parseInt(x_offset)); 

     if (test_offset != offset) { 
      scroller_data = updateScrollerData(test_offset); 
      x_extent = d3.extent(scroller_data, function(d) { return d.window; }); 
      y_extent = [0, d3.max(scroller_data, function(d) { return d.total; })]; 
      x_scale.domain(x_extent).range([0, scroller_width]); 
      y_scale.domain(y_extent).range([scroller_height, 0]); 
      x_axis_call.scale(x_scale); 

      // 
      // update axis labels 
      // 
      d3.select(scroller_content) 
      .selectAll(".x.axis") 
      .call(x_axis_call); 

      // 
      // shift the axis backwards to simulate an endless horizontal axis 
      // 
      var pre_shift = parseSvg(d3.select(scroller_content).attr("transform")); 
      console.log("pre_shift", pre_shift.translateX); 
      console.log("scroller_element_width", scroller_element_width); 
      var expected_post_shift = pre_shift.translateX + scroller_element_width; 
      console.log("(expected) post_shift", expected_post_shift); 

      d3.zoom().translateBy(d3.select(scroller_content), expected_post_shift, 0); 

      //    
      // observed and expected translate values do not match! 
      // 
      var post_shift = parseSvg(d3.select(scroller_content).attr("transform")); 
      console.log("(observed) post_shift", post_shift.translateX); 
     } 

     }); 

    d3.select(scroller).call(pan); 

    max_translate_x = this.state.scrollerWidth - x_scale(x_extent[1]); 
    d3.zoom().translateBy(d3.select(scroller), max_translate_x, 0); 

    // fetch test data 
    function updateScrollerData(updated_offset) { 
     offset = updated_offset; 
     return Constants.test_data.slice(updated_offset - 1, updated_offset + limit - 1); 
    } 
    } 

यह एक घटक प्रतिक्रिया के भीतर एक समारोह है:

यहाँ समारोह है कि धुरी खींचता है और जूम घटना ऊपर हुक है। प्रतिक्रिया चीजें महत्वपूर्ण हैं इसलिए प्रासंगिक नहीं है, लेकिन यहाँ है कि घटक के render() समारोह, माता-पिता और बच्चे एसवीजी समूह तत्वों को दिखाने के लिए है:

render() { 
    return (
     <svg 
     className="scroller" 
     ref={(scroller) => { this.scrollerContainer = scroller; }} 
     width={this.state.scrollerWidth} 
     height={this.state.scrollerHeight}> 
     <g 
      className="scroller-content" 
      ref={(scrollerContent) => { this.scrollerContent = scrollerContent; }} 
     /> 
     </svg> 
    ); 
    } 

दिखाया गया है, scrollerContainer रेफरी एसवीजी कि समूह तत्व शामिल है scrollerContent। यह scrollerContent क्षैतिज अक्ष है जिसमें है।

एक्स-अक्ष को पैन या स्क्रॉल करते समय, परिवर्तन scrollerContent पर लागू होते हैं।

रूपांतरण पैरामीटर प्राप्त करने के लिए, मैं सहायक विधि d3-interpolate से उपयोग कर रहा हूं, यानी।ES6 के माध्यम से:

export const test_data = [ 
    { 
    "total": 29.86, 
    "signal": [ 
     4.842, 
     1.608, 
     1.837, 
     3.052, 
     1.677, 
     0.8041, 
     3.09, 
     1.813, 
     2.106, 
     2.38, 
     1.773, 
     0.8128, 
     2.047, 
     1.658, 
     0.3588 
    ], 
    "window": 0, 
    "chr": "chr1" 
    }, 
    { 
    "total": 35.67, 
    "signal": [ 
     0.6111, 
     1.995, 
     0.5715, 
     2.51, 
     3.318, 
     1.523, 
     3.94, 
     2.743, 
     4.445, 
     0.759, 
     4.938, 
     2.61, 
     3.379, 
     1.27, 
     1.057 
    ], 
    "window": 1, 
    "chr": "chr1" 
    }, 
    { 
    "total": 39.14, 
    "signal": [ 
     0.0589, 
     0.1608, 
     2.426, 
     4.673, 
     3.511, 
     3.912, 
     2.809, 
     4.197, 
     4.648, 
     2.069, 
     2.84, 
     3.878, 
     0.2681, 
     3.622, 
     0.06911 
    ], 
    "window": 2, 
    "chr": "chr1" 
    }, 
    { 
    "total": 37.45, 
    "signal": [ 
     2.688, 
     1.235, 
     2.358, 
     1.994, 
     1.541, 
     1.189, 
     0.8078, 
     4.872, 
     2.287, 
     4.266, 
     2.24, 
     3.349, 
     3.519, 
     1.896, 
     3.21 
    ], 
    "window": 3, 
    "chr": "chr1" 
    }, 
    { 
    "total": 47.17, 
    "signal": [ 
     3.338, 
     3.613, 
     3.872, 
     1.166, 
     1.828, 
     4.24, 
     1.476, 
     4.025, 
     4.144, 
     4.922, 
     2.183, 
     2.701, 
     3.825, 
     4.346, 
     1.494 
    ], 
    "window": 4, 
    "chr": "chr1" 
    }, 
    { 
    "total": 41.7, 
    "signal": [ 
     0.2787, 
     1.74, 
     0.7557, 
     4.236, 
     2.865, 
     4.542, 
     4.113, 
     1.265, 
     4.826, 
     3.731, 
     4.931, 
     2.392, 
     2.014, 
     0.6566, 
     3.352 
    ], 
    "window": 5, 
    "chr": "chr1" 
    }, 
    { 
    "total": 31.43, 
    "signal": [ 
     3.025, 
     4.399, 
     1.001, 
     4.859, 
     0.9173, 
     2.851, 
     2.916, 
     1.821, 
     1.228, 
     1.646, 
     0.1008, 
     2.09, 
     2.502, 
     0.1476, 
     1.924 
    ], 
    "window": 6, 
    "chr": "chr1" 
    }, 
    { 
    "total": 38.23, 
    "signal": [ 
     1.123, 
     1.972, 
     0.5079, 
     4.808, 
     0.5669, 
     4.647, 
     2.598, 
     1.874, 
     0.8699, 
     4.876, 
     3.981, 
     1.503, 
     4.683, 
     2.853, 
     1.366 
    ], 
    "window": 7, 
    "chr": "chr1" 
    }, 
    { 
    "total": 44.2, 
    "signal": [ 
     3.895, 
     0.7457, 
     2.208, 
     1.837, 
     3.219, 
     3.98, 
     3.494, 
     4.225, 
     3.117, 
     3.162, 
     3.171, 
     2.449, 
     0.1419, 
     3.745, 
     4.807 
    ], 
    "window": 8, 
    "chr": "chr1" 
    }, 
    { 
    "total": 36.33, 
    "signal": [ 
     0.3164, 
     2.753, 
     4.094, 
     2.237, 
     4.748, 
     2.483, 
     1.541, 
     4.113, 
     0.1874, 
     3.71, 
     1.313, 
     0.221, 
     2.736, 
     1.208, 
     4.671 
    ], 
    "window": 9, 
    "chr": "chr1" 
    }, 
    { 
    "total": 43.05, 
    "signal": [ 
     1.924, 
     0.4136, 
     3.057, 
     4.686, 
     1.263, 
     0.1333, 
     0.8786, 
     4.715, 
     4.845, 
     4.282, 
     2.112, 
     4.597, 
     3.822, 
     1.322, 
     4.999 
    ], 
    "window": 10, 
    "chr": "chr1" 
    }, 
    { 
    "total": 31.28, 
    "signal": [ 
     4.216, 
     0.6655, 
     2.078, 
     1.235, 
     0.5526, 
     1.556, 
     1.005, 
     3.196, 
     1.907, 
     4.932, 
     0.006601, 
     1.269, 
     3.964, 
     4.608, 
     0.09109 
    ], 
    "window": 11, 
    "chr": "chr1" 
    }, 
    { 
    "total": 48.3, 
    "signal": [ 
     4.469, 
     1.138, 
     3.958, 
     2.801, 
     3.404, 
     4.988, 
     2.649, 
     3.818, 
     3.284, 
     0.9281, 
     3.982, 
     0.496, 
     4.28, 
     3.258, 
     4.845 
    ], 
    "window": 12, 
    "chr": "chr1" 
    }, 
    { 
    "total": 42.1, 
    "signal": [ 
     1.087, 
     3.127, 
     0.493, 
     3.276, 
     4.195, 
     1.561, 
     2.638, 
     4.897, 
     3.675, 
     4.937, 
     0.05847, 
     4.272, 
     2.33, 
     1.776, 
     3.776 
    ], 
    "window": 13, 
    "chr": "chr1" 
    }, 
    { 
    "total": 40.1, 
    "signal": [ 
     1.275, 
     4.574, 
     2.805, 
     1.646, 
     0.8759, 
     4.948, 
     3.637, 
     3.227, 
     2.259, 
     2.983, 
     2.905, 
     4.134, 
     3.133, 
     0.08384, 
     1.617 
    ], 
    "window": 14, 
    "chr": "chr1" 
    }, 
    { 
    "total": 50.31, 
    "signal": [ 
     2.228, 
     0.7037, 
     4.977, 
     1.143, 
     2.506, 
     4.348, 
     4.344, 
     3.998, 
     4.213, 
     2.745, 
     4.374, 
     3.411, 
     4.504, 
     4.417, 
     2.396 
    ], 
    "window": 15, 
    "chr": "chr1" 
    }, 
    { 
    "total": 34.7, 
    "signal": [ 
     2.729, 
     3.891, 
     3.873, 
     2.973, 
     0.1487, 
     1.573, 
     1.781, 
     2.788, 
     2.191, 
     2.912, 
     1.355, 
     2.582, 
     2.374, 
     3.164, 
     0.3641 
    ], 
    "window": 16, 
    "chr": "chr1" 
    }, 
    { 
    "total": 32.89, 
    "signal": [ 
     3.619, 
     2.119, 
     1.854, 
     4.083, 
     0.9916, 
     0.5065, 
     0.8343, 
     4.835, 
     1.723, 
     3.926, 
     2.675, 
     2.281, 
     0.1531, 
     2.239, 
     1.049 
    ], 
    "window": 17, 
    "chr": "chr1" 
    }, 
    { 
    "total": 38.94, 
    "signal": [ 
     1.976, 
     1.587, 
     3.808, 
     0.1173, 
     3.823, 
     4.349, 
     3.652, 
     1.308, 
     3.434, 
     3.855, 
     1.622, 
     0.2916, 
     2.382, 
     3.091, 
     3.647 
    ], 
    "window": 18, 
    "chr": "chr1" 
    }, 
    { 
    "total": 34.18, 
    "signal": [ 
     0.339, 
     3.695, 
     3.108, 
     3.267, 
     0.08282, 
     3.53, 
     2.316, 
     1.11, 
     4.504, 
     4.111, 
     0.007636, 
     0.5581, 
     2.985, 
     1.707, 
     2.857 
    ], 
    "window": 19, 
    "chr": "chr1" 
    }, 
    { 
    "total": 29.62, 
    "signal": [ 
     2.695, 
     0.8477, 
     4.417, 
     3.012, 
     2.454, 
     2.686, 
     0.6529, 
     0.2275, 
     1.052, 
     0.2092, 
     2.968, 
     3.268, 
     0.7144, 
     0.4441, 
     3.973 
    ], 
    "window": 20, 
    "chr": "chr1" 
    } 
]; 

उम्मीद है कि यह सब काम समस्या की व्याख्या करने की जरूरत है पता चलता है:

import * as d3 from 'd3'; 
import { parseSvg } from "d3-interpolate/src/transform/parse"; 

पूर्णता के लिए, यहाँ परीक्षण डेटा का एक टुकड़ा है। किसी भी सलाह या मार्गदर्शन के लिए धन्यवाद।

+3

axample काम कर कोड प्रदान करें – KEKUATAN

उत्तर

4

मुझे आपके कोड को पूर्ण पुनरुत्पादित उदाहरण के बिना पालन करना मुश्किल लगता है। इसलिए मैंने जो कुछ करने की कोशिश कर रहे हैं उसका एक सरल उदाहरण तैयार किया। शायद यह मदद करेंगे:

<!DOCTYPE html> 
 
<html> 
 

 
<head> 
 
    <meta charset="utf-8" /> 
 
    <script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> 
 
    <style> 
 
    .axis path { 
 
     display: none; 
 
    } 
 
    
 
    .axis line { 
 
     stroke-opacity: 0.3; 
 
     shape-rendering: crispEdges; 
 
    } 
 
    
 
    .view { 
 
     fill: url(#gradient); 
 
     stroke: #000; 
 
    } 
 
    
 
    button { 
 
     position: absolute; 
 
     top: 20px; 
 
     left: 20px; 
 
    } 
 
    </style> 
 
</head> 
 

 
<body> 
 
    <svg width="500" height="500"></svg> 
 
    <script src="//d3js.org/d3.v4.min.js"></script> 
 
    <script> 
 
    
 
    // 10,000 random data points 
 
    var data = d3.range(1, 10000).map(function(d) { 
 
     return { 
 
     i: d, 
 
     x: Math.random() < 0.5 ? Math.random() * 1000 : Math.random() * -1000, 
 
     y: Math.random() < 0.5 ? Math.random() * 1000 : Math.random() * -1000, 
 
     } 
 
    }); 
 

 
    var svg = d3.select("svg"), 
 
     margin = { 
 
     top: 10, 
 
     right: 10, 
 
     bottom: 10, 
 
     left: 10 
 
     }, 
 
     width = +svg.attr("width") - margin.left - margin.right, 
 
     height = +svg.attr("height") - margin.top - margin.bottom, 
 
     g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 
 

 
    // large "endless" zoom 
 
    var zoom = d3.zoom() 
 
     .scaleExtent([-1e100, 1e100]) 
 
     .translateExtent([ 
 
     [-1e100, -1e100], 
 
     [1e100, 1e100] 
 
     ]) 
 
     .on("zoom", zoomed); 
 

 
    var x = d3.scaleLinear() 
 
     .domain([-100, 100]) 
 
     .range([0, width]); 
 

 
    var y = d3.scaleLinear() 
 
     .domain([-100, 100]) 
 
     .range([height, 0]); 
 

 
    var xAxis = d3.axisBottom(x) 
 
     .ticks((width + 2)/(height + 2) * 10) 
 
     .tickSize(-height); 
 

 
    var yAxis = d3.axisRight(y) 
 
     .ticks(10) 
 
     .tickSize(width) 
 
     .tickPadding(8 - width); 
 

 
    var gX = svg.append("g") 
 
     .attr("transform", "translate(0," + height + ")") 
 
     .attr("class", "axis axis--x") 
 
     .call(xAxis); 
 

 
    var gY = svg.append("g") 
 
     .attr("class", "axis axis--y") 
 
     .call(yAxis); 
 

 
    svg.call(zoom); 
 

 
    // plot our data initially 
 
    updateData(x, y); 
 

 
    function zoomed() { 
 
     var t = d3.event.transform, 
 
     sx = t.rescaleX(x), //<-- rescale the scales 
 
     sy = t.rescaleY(x); 
 

 
     // swap out axis 
 
     gX.call(xAxis.scale(sx)); 
 
     gY.call(yAxis.scale(sy)); 
 

 
     updateData(sx, sy) 
 
    } 
 

 
    // classic enter, update, exit pattern 
 
    function updateData(sx, sy) { 
 

 
     // filter are data to those points in range 
 
     var f = data.filter(function(d) { 
 
     return (
 
      d.x > sx.domain()[0] && 
 
      d.x < sx.domain()[1] && 
 
      d.y > sy.domain()[0] && 
 
      d.y < sy.domain()[1] 
 
     ) 
 
     }); 
 

 
     var s = g.selectAll(".point") 
 
     .data(f, function(d) { 
 
      return d.i; 
 
     }); 
 

 
     // remove those out of range 
 
     s.exit().remove(); 
 

 
     // add the new ones in range 
 
     s = s.enter() 
 
     .append('circle') 
 
     .attr('class', 'point') 
 
     .attr('r', 10) 
 
     .style('fill', 'steelblue') 
 
     .merge(s); 
 

 
     // update all in range 
 
     s.attr('cx', function(d) { 
 
      return sx(d.x); 
 
     }) 
 
     .attr('cy', function(d) { 
 
      return sy(d.y); 
 
     }); 
 
    } 
 
    </script> 
 
</body> 
 

 
</html>