2016-06-28 141 views
0

我一直在努力工作,這是一個特殊的圖形,它是Mike Bostock模板中的一個修改過的子彈圖。我想用一些按鈕事件來增強它,特別是:當你點擊一個按鈕時,它會調用一個過渡動畫來改變圖形標記爲新的值。原始數據表單中的代碼都提供了新值和舊值。爲了清晰和上下文,我已經將代碼包括在內。搜索我的評論「//混淆下面」來到我定義我的按鈕功能的部分。D3.js + CSS按鈕功能

<!DOCTYPE html> 
 
<html> 
 
<head> 
 
    <title>Bullet Chart</title> 
 
    <meta charset="utf-8"> 
 
</head> 
 
<style> 
 
    body { 
 
    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 
 
    margin: auto; 
 
    padding-top: 40px; 
 
    position: relative; 
 
    /*width: 100%;*/ 
 
} 
 
table{ 
 
    width:60%; 
 
    margin-left:auto; 
 
    margin-right:auto; 
 
} 
 
td{width:50%;} 
 
.bulleT { font: 10px sans-serif; margin-left:auto;margin-right:auto;} 
 
.bulleT .marker { stroke: #4D4D4D; stroke-width: 2px;} 
 
.bulleT .marker.s0 { fill-opacity:0; stroke: #999999; stroke-width: 2px; } 
 
.bulleT .marker.s1 { fill-opacity:0; stroke: #000; stroke-width: 2px; } 
 
.bulleT .tick line { stroke: #666; stroke-width: .5px; } 
 

 
.bulleT .range.s0 { fill: #005C7A; } 
 
.bulleT .range.s1 { fill: #29A3CC; } 
 
.bulleT .range.s2 { fill: #c6dbef; } 
 
.bulleT .range.s3 { fill: #29A3CC; } 
 
.bulleT .range.s4 { fill: #005C7A; } 
 

 
.bulleT .measure.s0 { fill: #4D4D4D; } 
 
.bulleT .measure.s1 { fill: #999999; } 
 
.bulleT .measure.s2 { fill: #eeeeee; } 
 
.bulleT .measure.s3 { fill: #999999; } 
 
.bulleT .measure.s4 { fill: #4D4D4D; } 
 

 
.bulleT .title { font-size: 12px; font-weight: bold; } 
 
.bulleT .subtitle.s04 { fill: #000000; font-size: 16px; font-weight: bold;} 
 
.bulleT .subtitle.s13 { fill: #999999; font-size: 12px; font-weight: bold;} 
 
.bulleT .subtitle.s2 { fill: #999999; font-size: 10px;} 
 
    
 
.option { 
 
\t font-family: Play; 
 
\t color: #ffffff; 
 
\t font-size: 12px; 
 
    width: 6%; 
 
\t background: #303030; 
 
\t padding: 10px 20px 10px 20px; 
 
} 
 

 
.option:hover { 
 
\t background: #4c4d4d; 
 
} 
 

 
div#option2{ 
 
    position:relative; 
 
    top: 10px; 
 
} 
 

 
</style> 
 
<body> 
 
    <script src="http://d3js.org/d3.v3.min.js"></script> 
 
<div id="canvas-svg"> 
 
<div id="canvas-svg"> 
 
    <table> 
 
    <tr> 
 
     <td> 
 
     <div id="BulleT_horizontal"></div> 
 
     </td> 
 
    </tr> 
 
    </table> 
 
</div> 
 

 
<div id="option1" class="option"> Outcome 1</div> 
 
<div id="option2" class="option"> Outcome 2</div> 
 
<p>The Bullet Chart is here.</p> 
 
<script> 
 

 
(function() { 
 
// Simple modification based on mbostock's Bullet Charts. 
 
d3.bulleT = function() { 
 
    var orient = "left", 
 
     reverse = false, 
 
     vertical = false, 
 
     terjedelem = bulleTTerjedelem, 
 
     ranges = bulleTRanges, 
 
     markers = bulleTMarkers, 
 
     measures = bulleTMeasures, 
 
     width = 380, 
 
     height = 30, 
 
     tickFormat = null; 
 

 
    // For each small multiple 
 
    function bulleT(g) { 
 
    g.each(function(d, i) { 
 
     var terjedelemz = terjedelem.call(this, d, i), 
 
      rangez = ranges.call(this, d, i).slice().sort(d3.descending), 
 
      markerz = markers.call(this, d, i), 
 
      measurez = measures.call(this, d, i).slice().sort(d3.descending), 
 
      g = d3.select(this); 
 

 
     var wrap = g.select("g.wrap"); 
 

 
     if (wrap.empty()) wrap = g.append("g").attr("class", "wrap"); 
 
     // Compute the x-scale. 
 
     var x0 = d3.scale.linear() 
 
      .domain([terjedelemz[0], terjedelemz[1]]) 
 
      .range(reverse ? [width, 0] : [0, width]); 
 

 
     // Stash the new scale. 
 
     this.__chart__ = x0; 
 

 
     // Derive width-scales from the x-scales. 
 
     var w = bulleTWidth(x0,terjedelemz[0]); 
 

 
     // Update the range rects. 
 
     rangez.unshift(terjedelemz[1]); 
 
     var range = wrap.selectAll("rect.range") 
 
      .data(rangez); 
 
     range.enter().append("rect") 
 
      .filter(function(d, i){ if(i != 3){ return d} }) 
 
      .attr("class", function(d, i) { return "range s" + i; }) 
 
      .attr("width", w) 
 
      .attr("y", 0) 
 
      .attr("height",height) 
 
      .attr("x", reverse ? x0 : 0); 
 
     range.enter().append("line") 
 
      .filter(function(d, i){ if(i == 3){ return d} }) 
 
      .attr("class", "marker") 
 
      .attr("x1", x0) 
 
      .attr("x2", x0) 
 
      .attr("y1", 0) 
 
      .attr("y2", height); 
 

 
     // Append the measure rects. 
 
     measurez.unshift(terjedelemz[1]); 
 
     var measure = wrap.selectAll("rect.measure") 
 
      .data(measurez); 
 
     measure.enter().append("rect") 
 
      .attr("class", function(d, i) { return "measure s" + i; }) 
 
      .attr("width", w) 
 
      .attr("height", height/2) 
 
      .attr("x", reverse ? x0 : 0) 
 
      .attr("y", height/4); 
 
     // Append rect and line marker. 
 
     var marker = wrap.selectAll("rect.marker") 
 
      .data(markerz); 
 
     marker.enter().append("rect") 
 
      .filter(function(d, i){ if(i == 1){ return d} }) 
 
      .attr("class", "marker s1") 
 
      .attr("width", 6) 
 
      .attr("y", -(height/10)) 
 
      .attr("height",function(d) {return height+(height/5);}) 
 
      .attr("x", x0) 
 
      .attr("transform", "translate(-3,0)"); 
 
//confusion below 
 
     var option1 = d3.select("#option1"); 
 
     option1.on('click.outcome', outcome1); 
 
     //option1.on('click.val', val=[100,200,1000,20]); 
 

 
     var option2 = d3.select("#option2"); 
 
     option2.on('click.outcome', outcome2); 
 

 
     function outcome1(val) { 
 
     d.markerz = [1000, 2000, 10, 20] 
 
     d3.selectAll('rect.marker') 
 
     .transition() 
 
     .duration(3000) 
 
     .attr("x", function(d) {return d}) 
 
     } 
 

 
     function outcome2(val) { 
 
     d.markerz = [-1000, -2000, -10, -20] 
 
     d3.selectAll('rect.marker') 
 
     .transition() 
 
     .duration(3000) 
 
     .attr("x", function(d) {return d}) 
 
     }; 
 

 
     marker.enter().append("line") 
 
      .filter(function(d, i){ if(i == 0){ return d} }) 
 
      .attr("class", "marker s0") 
 
      .attr("x1", x0) 
 
      .attr("x2", x0) 
 
      .attr("y1", height/4) 
 
      .attr("y2", height-(height/4)); 
 

 
     // Compute the tick format. 
 
     var format = tickFormat || x0.tickFormat(8); 
 

 
     // Update the tick groups. 
 
     var tick = g.selectAll("tick") 
 
      .data(x0.ticks(8), function(d) { 
 
      return this.textContent || format(d); 
 
      }); 
 

 
     // Initialize the ticks with the old scale, x0. 
 
     var tickEnter = tick.enter().append("g") 
 
      .attr("class", "tick") 
 
      .attr("transform", bulleTTranslate(x0)) 
 
      .style("opacity", 1); 
 

 
     tickEnter.append("line") 
 
      .attr("y1", height) 
 
      .attr("y2", height * 7/6); 
 

 
     tickEnter.append("text") 
 
      .attr("text-anchor", "middle") 
 
      .attr("transform", function(d){ 
 
      if (vertical) { 
 
       return "rotate(90)"; 
 
      } 
 
      }) 
 
      .attr("dy", function(d){ 
 
      if(vertical){return width/60; }else{ return height+15 } 
 
      }) 
 
      .attr("dx", function(d){ 
 
      if(vertical){return height+15 ;} 
 
      }) 
 
      .text(format); 
 
    }); 
 
    } 
 

 
    // left, right, top, bottom 
 
    bulleT.orient = function(x) { 
 
    if (!arguments.length) return orient; 
 
    orient = x; 
 
    reverse = orient == "right" || orient == "bottom"; 
 
    return bulleT; 
 
    }; 
 

 
    // terjedelem 
 
    bulleT.terjedelem = function(x) { 
 
    if (!arguments.length) return terjedelem; 
 
    terjedelem = x; 
 
    return bulleT; 
 
    }; 
 

 
    // ranges (bad, satisfactory, good) 
 
    bulleT.ranges = function(x) { 
 
    if (!arguments.length) return ranges; 
 
    ranges = x; 
 
    return bulleT; 
 
    }; 
 
//* 
 
    // markers (previous, goal) 
 
    bulleT.markers = function(x) { 
 
    if (!arguments.length) return markers; 
 
    markers = x; 
 
    return bulleT; 
 
    }; 
 

 
    // measures (actual, forecast) 
 
    bulleT.measures = function(x) { 
 
    if (!arguments.length) return measures; 
 
    measures = x; 
 
    return bulleT; 
 
    }; 
 
//*/ 
 
    bulleT.vertical = function(x) { 
 
    if (!arguments.length) return vertical; 
 
    vertical = x; 
 
    return bulleT; 
 
    }; 
 
    bulleT.width = function(x) { 
 
    if (!arguments.length) return width; 
 
    width = x; 
 
    return bulleT; 
 
    }; 
 

 
    bulleT.height = function(x) { 
 
    if (!arguments.length) return height; 
 
    height = x; 
 
    return bulleT; 
 
    }; 
 

 
    bulleT.tickFormat = function(x) { 
 
    if (!arguments.length) return tickFormat; 
 
    tickFormat = x; 
 
    return bulleT; 
 
    }; 
 
    return bulleT; 
 
}; 
 

 
function bulleTTerjedelem(d) { 
 
    return d.terjedelem; 
 
} 
 

 
function bulleTRanges(d) { 
 
    return d.ranges; 
 
} 
 

 
function bulleTMarkers(d) { 
 
    return d.markers; 
 
} 
 

 
function bulleTMeasures(d) { 
 
    return d.measures; 
 
} 
 

 
function bulleTTranslate(x) { 
 
    return function(d) { 
 
    return "translate(" + x(d) + ",0)"; 
 
    }; 
 
} 
 

 
function bulleTWidth(x,y) { 
 
    var x0 = x(0); 
 
    return function(d) { 
 
    return Math.abs(x(d-y) - x0); 
 
    }; 
 
} 
 

 
})(); 
 

 
var Tscore_Man_Height = -1019; 
 
var Tscore_Woman_Height = -261; 
 
var Tscore_Man_Weight = -4.64; 
 
var Tscore_Woman_Weight = -1.6; 
 

 
var Tscore2 = 1300 
 
// terjedelem is the hungarian translation of the statistical term of range 
 
var data = [ 
 
    {"title":"Exper","dimension":"(diff)","subtitle":Tscore_Man_Height,"terjedelem":[-3000,3000],"ranges":[ -2000, -1000, 0, 1000, 2000],"measures":[-1366,-676,605,1108.81],"markers":[-23,Tscore_Man_Height]}, 
 
    {"title":"Gold","dimension":"(diff)","subtitle":Tscore_Woman_Height,"terjedelem":[-8000,8000],"ranges":[-5250,-2750,0,2750,5250],"measures":[-901,110,845.5,2107.5],"markers":[412,Tscore_Woman_Height]}, 
 
    {"title":"Tech","dimension":"(diff)","subtitle":Tscore_Man_Weight,"terjedelem":[-20,20],"ranges":[-13.33,-6.66,0,6.66,13.33],"measures":[-8.7,-.9,4.9,10.7],"markers":[1,Tscore_Man_Weight]}, 
 
    {"title":"Units","dimension":"(diff)","subtitle":Tscore_Woman_Weight,"terjedelem":[-80,80],"ranges":[-53.33,-26.66,0,26.66,53.33],"measures":[-18,-7.8,3.8,23],"markers":[-3,Tscore_Woman_Weight]} 
 
] 
 
var Width = 400, Height = 50; 
 

 
var margin = {top: 5, right: 20, bottom: 20, left: 60}, 
 
    width = Width - margin.left - margin.right, 
 
    height = Height - margin.top - margin.bottom; 
 

 
var chart = d3.bulleT() 
 
    .width(width) 
 
    .height(height); 
 

 
function bulleT(whichData,whereToPut,direction) { 
 
    var a=Width, b=Height; 
 
    if(direction == "vertical"){ 
 
    Height=a;Width=b+30; 
 
    vertical = true; 
 
    }else{ 
 
    Height=a-20;Width=b; 
 
    vertical = false; 
 
    } 
 

 
    var svg = d3.select(whereToPut).selectAll("svg") 
 
     .data(whichData) 
 
    .enter().append("svg") 
 
     .attr("class", "bulleT") 
 
     .attr("width", Width) 
 
     .attr("height", Height) 
 
    .append("g") 
 
     .attr("transform", function(){ 
 
     if(direction == "vertical"){ 
 
      return "rotate(-90)translate("+ -(Height-margin.left) +",10)"; 
 
     }else{ 
 
      return "translate("+ margin.left +","+ margin.top +")"; 
 
     } 
 
     }) 
 
     .call(chart.vertical(vertical)); 
 

 
    var title = svg.append("g") 
 
     .style("text-anchor", function(){ 
 
     if(direction == "vertical"){ 
 
      return "middle"; 
 
     }else{ 
 
      return "end"; 
 
     } 
 
     }) 
 
     .attr("transform", function(){ 
 
     if(direction == "vertical"){ 
 
      return "rotate(90)translate("+ Width/4 +",20)"; 
 
     }else{ 
 
      return "translate(-16," + height/3 + ")"; 
 
     } 
 
     }); 
 

 
    title.append("text") 
 
     .attr("class", "title") 
 
     .text(function(d) { return d.title; }); 
 

 
    title.append("text") 
 
     .attr("dy", "1.2em") 
 
     .text(function(d) { return d.dimension; }) 
 

 
    title.append("text") 
 
     .attr("class",function(d) { 
 
      switch (true) 
 
      { 
 
      case ((d.markers[1] < 30) || (70 < d.markers[1])): 
 
       return "subtitle s04"; 
 
       break; 
 
       break; 
 
      case ((30 <= d.markers[1]) && (d.markers[1] < 40)): 
 
       return "subtitle s13"; 
 
       break; 
 
      case ((40 <= d.markers[1]) && (d.markers[1] <= 60)): 
 
       return "subtitle s2"; 
 
       break; 
 
      case ((60 < d.markers[1]) && (d.markers[1] <= 70)): 
 
       return "subtitle s13"; 
 
       break; 
 
      } 
 
     } 
 
    ) 
 
     .attr("dy", function(){ 
 
     return "2.4em"; 
 
     }) 
 
     .text(function(d) { return d.subtitle; }); 
 
}; 
 

 

 
bulleT(data,"#BulleT_vertical","vertical"); // "horizontal" or "vertical" 
 
bulleT(data,"#BulleT_horizontal","horizontal"); 
 
</script> 
 
</body> 
 
</html>

當我點擊按鈕,他們都做同樣的事情,即使我改變markerz不同的值。而且,他們甚至沒有做正確的事情,這些價值觀似乎是錯誤的,因爲一些標記從圖形邊界飛出。所以無論我做什麼似乎都不會改變數據解析的方式。另外,我並不完全相信這個原始數值數據會隨着圖的x比例縮放,或者當我通過按鈕功能時需要再次縮放它。縮放似乎與上面代碼中的x0有關。出於某種原因,我無法使用我的按鈕。

這裏有一個類似的更新塊具有功能按鈕的功能:

http://bl.ocks.org/CodeXmonk/6187523

我的圖是在不同的我不會改變比在該標記定位等措施或任何東西。而且我沒有隨機化數據,我已經預先編碼了原始數據,我想使用我的css按鈕來回切換。

所以我在尋找的是如何編碼按鈕來處理預先存在的比例尺並加載原始數據並將其放入markerz或.transition()動畫的其他變量中。這樣,這些按鈕就可以在整個圖形上移動標記。

對不起,我不能讓這個縮短。我希望這將是值得每個人的,雖然因爲d3.js + css界面是一個非常強大的組合。我希望我們都可以從這個例子中學習。

感謝您閱讀

回答

0

經過進一步的努力,我有個好消息。我通過純粹的試驗和錯誤獲得了它的工作。我會在這裏發表部分答案。我設法使用.transition()和以像素形式預編碼的原始數據來獲得功能圖表。注:我得到這個工作的唯一方法是通過爲轉換放入x的像素值。理想情況下,我想只輸入原始數據(以數據形式),並使現有比例處理它以自動計算像素值。我現在不會太挑剔。這是我到目前爲止所做的。我不厭其煩地發佈我自己的要點,因爲我希望比上面冗長的代碼更容易查看。

https://bl.ocks.org/diggetybo/83188e161c39f2d0f7025087598ec075

我還需要在以下答案:

  1. 如何利用現有的秤旁邊我的耦合與我的CSS按鈕功能的原始數據

  2. 我如何更新字幕文字?它不知道我更新了這些值,所以他們總是讀「1153,1506,8.63,5.86」。理想情況下,當我點擊成果1時,我希望他們反映新的標記位置:「-1019,-261,-4.64,-1.6」。然後,點擊結果2按鈕後仍能恢復到「1153,1506,8.63,5.86」。

至於2,我試圖複製和粘貼的標記值title.append片段,並用另一隻小鼠事件爲線索,但每次這樣,我這樣做是返回一個錯誤。任何有經驗的d3人都知道該怎麼做?

最後,我不確定爲什麼,但每次點擊按鈕時,開發工具錯誤計數都會增加1.錯誤是,「某件事不是函數」。我猜這不是一個好兆頭。但是,該圖大部分工作。我不知道我應該對這些錯誤感到驚訝。

再次感謝

-1

我認爲你必須使用的document.ready功能爲每個變量,然後給了。對點擊功能。