| (function() { | 
|   | 
|     // Chart design based on the recommendations of Stephen Few. Implementation | 
|     // based on the work of Clint Ivy, Jamie Love, and Jason Davies. | 
|     // http://projects.instantcognition.com/protovis/bulletchart/ | 
|     d3.bullet = function() { | 
|       var orient = "left", // TODO top & bottom | 
|           reverse = false, | 
|           duration = 3000,           | 
|           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 rangez = ranges.call(this, d, i).slice().sort(d3.descending), | 
|               markerz = markers.call(this, d, i).slice().sort(d3.descending), | 
|               measurez = measures.call(this, d, i).slice().sort(d3.descending), | 
|               state = !!d["state"]?d["state"]:0, | 
|               g = d3.select(this) // 柱状图 分组 | 
|               .append("g") | 
|               .attr("transform", "translate(75)"); | 
|           // Compute the new x-scale. | 
|               var x1 = d3.scale.linear() | 
|                   .domain([0, Math.max(rangez[0], markerz[0], measurez[0])]) | 
|                   .range(reverse ? [width, 0] : [0, width]); | 
|      | 
|           // Retrieve the old x-scale, if this is an update. | 
|           var x0 = this.__chart__ || d3.scale.linear() | 
|               .domain([0, Infinity]) | 
|               .range(x1.range()); | 
|      | 
|           // Stash the new scale. | 
|           this.__chart__ = x1; | 
|      | 
|           // Derive width-scales from the x-scales. | 
|           var w0 = bulletWidth(x0), | 
|               w1 = bulletWidth(x1); | 
|      | 
|           // Update the range rects. | 
|           var range = g.selectAll("rect.range") | 
|               .data(rangez); | 
|      | 
|           range.enter().append("rect") | 
|               .attr("class", function(d, i) { return "range s" + i; }) | 
|               .attr("width", w0) | 
|               .attr("height", height) | 
|               .attr("x", reverse ? x0 : 0) | 
|             .transition() | 
|               .duration(0) | 
|               .attr("width", w1) | 
|               .attr("x", reverse ? x1 : 0); | 
|      | 
|           range.transition() | 
|               .duration(0) | 
|               .attr("x", reverse ? x1 : 0) | 
|               .attr("width", w1) | 
|               .attr("height", height); | 
|           //  // 判断状态; | 
|            var measureNum = markerz[0]; | 
|           //  for(var index=1;index<rangez.length;index++){ | 
|           //        var rangeNum = rangez[index]; | 
|           //        if(measureNum >= rangeNum){ | 
|           //            break; | 
|           //        } | 
|           //  } | 
|           // var state = 4-index; | 
|           // Update the measure rects. | 
|           var measure = g.selectAll("rect.measure") | 
|               .data(measurez); | 
|           measure.enter().append("rect") | 
|               .attr("class", function(d, i) { | 
|                   return "measure s" + i+"_"+state;  | 
|                 }) | 
|               .attr("width", w0) | 
|               .attr("height", height) | 
|               .attr("x", reverse ? x0 : 0) | 
|               .attr("y", 0) | 
|             .transition() | 
|               .duration(duration) | 
|               .attr("width", w1) | 
|               .attr("x", reverse ? x1 : 0); | 
|      | 
|           measure.transition() | 
|               .duration(duration) | 
|               .attr("width", w1) | 
|               .attr("height", height) | 
|               .attr("x", reverse ? x1 : 0) | 
|               .attr("y", 0); | 
|      | 
|           // Update the marker lines. | 
|         //   var marker = g.selectAll("line.marker") | 
|         //       .data(markerz); | 
|      | 
|         //   marker.enter().append("line") | 
|         //       .attr("class", "marker") | 
|         //       .attr("x1", x0) | 
|         //       .attr("x2", x0) | 
|         //     //   .attr("y1", height / 6) | 
|         //     //   .attr("y2", height * 5 / 6) | 
|         //         .attr("y1", height*0.025) | 
|         //         .attr("y2", height*0.95) | 
|         //       .transition() | 
|         //       .duration(duration) | 
|         //       .attr("x1", x1) | 
|         //       .attr("x2", x1); | 
|      | 
|         //   marker.transition() | 
|         //       .duration(duration) | 
|         //       .attr("x1", x1) | 
|         //       .attr("x2", x1) | 
|         //       .attr("y1", height*0.025) | 
|         //       .attr("y2", height*0.95); | 
|             //   .attr("y1", height / 6) | 
|             //   .attr("y2", height * 5 / 6); | 
|             // console.log("w1============"); | 
|             // debugger; | 
|           // 添加状态说明 | 
|           var meaningState = g.selectAll("meaning.state") | 
|           .data(measurez); | 
|            meaningState.enter().append("text") | 
|            .attr("display","none") | 
|            .attr("class","meaning state") | 
|            .attr("x", x1) | 
|            .attr("transform", "translate(-80)") | 
|            .attr("y", height*0.72) | 
|            .text(function () { | 
|                 var txt; | 
|                 switch(state){                | 
|                 case 1 : txt = "轻度";break; | 
|                 case 2 : txt = "中度";break; | 
|                 case 3 : txt = "重度";break; | 
|                 default : txt = "";break; | 
|                 } | 
|               return txt; | 
|             }); | 
|           // 添加数字 | 
|           var meaningText = g.selectAll("meaning.text") | 
|           .data(measurez); | 
|            meaningText.enter().append("text") | 
|            .attr("display","none") | 
|            .attr("class","meaning text") | 
|            .attr("x", x1) | 
|            .attr("transform", "translate(8)") | 
|            .attr("y", height*0.75) | 
|            .text(function () { | 
|             return measureNum; | 
|            }) | 
|            .transition() | 
|            .call(function (){ | 
|               setTimeout(function(){ | 
|                 $(".meaning.state,.meaning.text").fadeIn(duration*0.6); | 
|               }, duration*0.8); | 
|            });            | 
|           // Compute the tick format. | 
|         //   var format = tickFormat || x1.tickFormat(8); | 
|      | 
|         //   // Update the tick groups. | 
|         //   var tick = g.selectAll("g.tick") | 
|         //       .data(x1.ticks(3), 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", 1e-6); | 
|      | 
|         //   tickEnter.append("line") | 
|         //       .attr("y1", height) | 
|         //       .attr("y2", height * 7 / 6); | 
|      | 
|         //   tickEnter.append("text") | 
|         //       .attr("text-anchor", "middle") | 
|         //       .attr("dy", "1em") | 
|         //       .attr("y", height * 7 / 6) | 
|         //       .text(format); | 
|      | 
|         //   // Transition the entering ticks to the new scale, x1. | 
|         //   tickEnter.transition() | 
|         //       .duration(duration) | 
|         //       .attr("transform", bulletTranslate(x1)) | 
|         //       .style("opacity", 1); | 
|      | 
|           // Transition the updating ticks to the new scale, x1. | 
|         //   var tickUpdate = tick.transition() | 
|         //       .duration(duration) | 
|         //       .attr("transform", bulletTranslate(x1)) | 
|         //       .style("opacity", 1); | 
|      | 
|         //   tickUpdate.select("line") | 
|         //       .attr("y1", height) | 
|         //       .attr("y2", height * 7 / 6); | 
|      | 
|         //   tickUpdate.select("text") | 
|         //       .attr("y", height * 7 / 6); | 
|      | 
|           // Transition the exiting ticks to the new scale, x1. | 
|         //   tick.exit().transition() | 
|         //       .duration(duration) | 
|         //       .attr("transform", bulletTranslate(x1)) | 
|         //       .style("opacity", 1e-6) | 
|         //       .remove(); | 
|         } | 
|         ); | 
|         d3.timer.flush(); | 
|       } | 
|      | 
|       // left, right, top, bottom | 
|       bullet.orient = function(x) { | 
|         if (!arguments.length) return orient; | 
|         orient = x; | 
|         reverse = orient == "right" || orient == "bottom"; | 
|         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.width = function(x) { | 
|         if (!arguments.length) return width; | 
|         width = x*0.9; // 改变宽度 | 
|         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; | 
|       }; | 
|      | 
|       bullet.duration = function(x) { | 
|         if (!arguments.length) return duration; | 
|         duration = x; | 
|         return bullet; | 
|       }; | 
|      | 
|       return bullet; | 
|     }; | 
|      | 
|     function bulletRanges(d) { | 
|       var ranges = []; | 
|       var start = !!d['startPoint']?d['startPoint']:0; | 
|         d.ranges.forEach(function (value, index) { | 
|             var _value = Math.abs(value-start); | 
|             _value = _value==0?100:_value; | 
|             ranges[index] = _value; | 
|         }); | 
|        var endRange =  ranges[ranges.length-1]; | 
|         endRange += (!!d.state&&d.state)>0?(Math.abs(endRange-start)/ranges.length):0; | 
|         ranges.push(endRange); | 
|       return ranges; | 
|     } | 
|      | 
|     function bulletMarkers(d) { | 
|       return d.markers; | 
|     } | 
|      | 
|     function bulletMeasures(d) { | 
|       var measures = []; | 
|       d.measures.forEach(function (value, index) { | 
|           var _value = Math.abs(value); | 
|           measures[index] = _value; | 
|       }); | 
|       return measures; | 
|     } | 
|      | 
|     function bulletTranslate(x) { | 
|       return function(d) { | 
|         return "translate(" + x(d) + ",0)"; | 
|       }; | 
|     } | 
|      | 
|     function bulletWidth(x) { | 
|       var x0 = x(0); | 
|       return function(d) { | 
|         return Math.abs(x(d) - x0); | 
|       }; | 
|     } | 
|      | 
|     })(); |