text: /**
   * Created by JXP1195 on 7/6/2015.
   */
  Meteor.googleGuage = {
  
      googleGuage: function (placeholderName, configuration) {
          this.placeholderName = placeholderName;
  
          var self = this; // for internal d3 functions
  
          this.configure = function (configuration) {
              this.config = configuration;
  
              this.config.size = this.config.size * 0.9;
  
              this.config.raduis = this.config.size * 0.97 / 2;
              this.config.cx = this.config.size / 2;
              this.config.cy = this.config.size / 2;
  
              this.config.min = undefined != configuration.min ? configuration.min : 0;
              this.config.max = undefined != configuration.max ? configuration.max : 100;
              this.config.range = this.config.max - this.config.min;
  
              this.config.majorTicks = configuration.majorTicks || 5;
              this.config.minorTicks = configuration.minorTicks || 2;
  
              this.config.greenColor = configuration.greenColor || "#109618";
              this.config.yellowColor = configuration.yellowColor || "#FF9900";
              this.config.redColor = configuration.redColor || "#DC3912";
  
              this.config.transitionDuration = configuration.transitionDuration || 500;
          };
  
          this.render = function () {
              this.body = d3.select("#" + this.placeholderName)
                  .append("svg:svg")
                  .attr("class", "gauge")
                  .attr("width", this.config.size)
                  .attr("height", this.config.size);
  
              this.body.append("svg:circle")
                  .attr("cx", this.config.cx)
                  .attr("cy", this.config.cy)
                  .attr("r", this.config.raduis)
                  .style("fill", "#ccc")
                  .style("stroke", "#000")
                  .style("stroke-width", "0.5px");
  
              this.body.append("svg:circle")
                  .attr("cx", this.config.cx)
                  .attr("cy", this.config.cy)
                  .attr("r", 0.9 * this.config.raduis)
                  .style("fill", "#fff")
                  .style("stroke", "#e0e0e0")
                  .style("stroke-width", "2px");
  
              for (var index in this.config.greenZones) {
                  this.drawBand(this.config.greenZones[index].from, this.config.greenZones[index].to, self.config.greenColor);
              }
  
              for (var index in this.config.yellowZones) {
                  this.drawBand(this.config.yellowZones[index].from, this.config.yellowZones[index].to, self.config.yellowColor);
              }
  
              for (var index in this.config.redZones) {
                  this.drawBand(this.config.redZones[index].from, this.config.redZones[index].to, self.config.redColor);
              }
  
              if (undefined != this.config.label) {
                  var fontSize = Math.round(this.config.size / 9);
                  this.body.append("svg:text")
                      .attr("x", this.config.cx)
                      .attr("y", this.config.cy / 2 + fontSize / 2)
                      .attr("dy", fontSize / 2)
                      .attr("text-anchor", "middle")
                      .text(this.config.label)
                      .style("font-size", fontSize + "px")
                      .style("fill", "#333")
                      .style("stroke-width", "0px");
              }
  
              var fontSize = Math.round(this.config.size / 16);
              var majorDelta = this.config.range / (this.config.majorTicks - 1);
              for (var major = this.config.min; major <= this.config.max; major += majorDelta) {
                  var minorDelta = majorDelta / this.config.minorTicks;
                  for (var minor = major + minorDelta; minor < Math.min(major + majorDelta, this.config.max); minor += minorDelta) {
                      var point1 = this.valueToPoint(minor, 0.75);
                      var point2 = this.valueToPoint(minor, 0.85);
  
                      this.body.append("svg:line")
                          .attr("x1", point1.x)
                          .attr("y1", point1.y)
                          .attr("x2", point2.x)
                          .attr("y2", point2.y)
                          .style("stroke", "#666")
                          .style("stroke-width", "1px");
                  }
  
                  var point1 = this.valueToPoint(major, 0.7);
                  var point2 = this.valueToPoint(major, 0.85);
  
                  this.body.append("svg:line")
                      .attr("x1", point1.x)
                      .attr("y1", point1.y)
                      .attr("x2", point2.x)
                      .attr("y2", point2.y)
                      .style("stroke", "#333")
                      .style("stroke-width", "2px");
  
                  if (major == this.config.min || major == this.config.max) {
                      var point = this.valueToPoint(major, 0.63);
  
                      this.body.append("svg:text")
                          .attr("x", point.x)
                          .attr("y", point.y)
                          .attr("dy", fontSize / 3)
                          .attr("text-anchor", major == this.config.min ? "start" : "end")
                          .text(major)
                          .style("font-size", fontSize + "px")
                          .style("fill", "#333")
                          .style("stroke-width", "0px");
                  }
              };
  
              var pointerContainer = this.body.append("svg:g").attr("class", "pointerContainer");
  
              var midValue = (this.config.min + this.config.max) / 2;
  
              var pointerPath = this.buildPointerPath(midValue);
  
              var pointerLine = d3.svg.line()
                  .x(function (d) {
                      return d.x;
                  })
                  .y(function (d) {
                      return d.y;
                  })
                  .interpolate("basis");
  
              pointerContainer.selectAll("path")
                  .data([pointerPath])
                  .enter()
                  .append("svg:path")
                  .attr("d", pointerLine)
                  .style("fill", "#dc3912")
                  .style("stroke", "#c63310")
                  .style("fill-opacity", 0.7);
  
              pointerContainer.append("svg:circle")
                  .attr("cx", this.config.cx)
                  .attr("cy", this.config.cy)
                  .attr("r", 0.12 * this.config.raduis)
                  .style("fill", "#4684EE")
                  .style("stroke", "#666")
                  .style("opacity", 1);
  
              var fontSize = Math.round(this.config.size / 10);
              pointerContainer.selectAll("text")
                  .data([midValue])
                  .enter()
                  .append("svg:text")
                  .attr("x", this.config.cx)
                  .attr("y", this.config.size - this.config.cy / 4 - fontSize)
                  .attr("dy", fontSize / 2)
                  .attr("text-anchor", "middle")
                  .style("font-size", fontSize + "px")
                  .style("fill", "#000")
                  .style("stroke-width", "0px");
  
              this.redraw(this.config.min, 0);
          };
  
          this.buildPointerPath = function (value) {
              var delta = this.config.range / 13;
  
              var head = valueToPoint(value, 0.85);
              var head1 = valueToPoint(value - delta, 0.12);
              var head2 = valueToPoint(value + delta, 0.12);
  
              var tailValue = value - (this.config.range * (1 / (270 / 360)) / 2);
              var tail = valueToPoint(tailValue, 0.28);
              var tail1 = valueToPoint(tailValue - delta, 0.12);
              var tail2 = valueToPoint(tailValue + delta, 0.12);
  
              return [head, head1, tail2, tail, tail1, head2, head];
  
              function valueToPoint(value, factor) {
                  var point = self.valueToPoint(value, factor);
                  point.x -= self.config.cx;
                  point.y -= self.config.cy;
                  return point;
              }
          };
  
          this.drawBand = function (start, end, color) {
              if (0 >= end - start) return;
  
              this.body.append("svg:path")
                  .style("fill", color)
                  .attr("d", d3.svg.arc()
                      .startAngle(this.valueToRadians(start))
                      .endAngle(this.valueToRadians(end))
                      .innerRadius(0.65 * this.config.raduis)
                      .outerRadius(0.85 * this.config.raduis))
                  .attr("transform", function () {
                      return "translate(" + self.config.cx + ", " + self.config.cy + ") rotate(270)";
                  });
          };
  
          this.redraw = function (value, transitionDuration) {
              var pointerContainer = this.body.select(".pointerContainer");
  
              pointerContainer.selectAll("text").text(Math.round(value));
  
              var pointer = pointerContainer.selectAll("path");
              pointer.transition()
                  .duration(undefined != transitionDuration ? transitionDuration : this.config.transitionDuration)
                  //.delay(0)
                  //.ease("linear")
                  //.attr("transform", function(d)
                  .attrTween("transform", function () {
                      var pointerValue = value;
                      if (value > self.config.max) pointerValue = self.config.max + 0.02 * self.config.range;
                      else if (value < self.config.min) pointerValue = self.config.min - 0.02 * self.config.range;
                      var targetRotation = (self.valueToDegrees(pointerValue) - 90);
                      var currentRotation = self._currentRotation || targetRotation;
                      self._currentRotation = targetRotation;
  
                      return function (step) {
                          var rotation = currentRotation + (targetRotation - currentRotation) * step;
                          return "translate(" + self.config.cx + ", " + self.config.cy + ") rotate(" + rotation + ")";
                      };
                  });
          };
  
          this.valueToDegrees = function (value) {
              // thanks @closealert
              //return value / this.config.range * 270 - 45;
              return value / this.config.range * 270 - (this.config.min / this.config.range * 270 + 45);
          };
  
          this.valueToRadians = function (value) {
              return this.valueToDegrees(value) * Math.PI / 180;
          };
  
          this.valueToPoint = function (value, factor) {
              return {
                  x: this.config.cx - this.config.raduis * factor * Math.cos(this.valueToRadians(value)),
                  y: this.config.cy - this.config.raduis * factor * Math.sin(this.valueToRadians(value))
              };
          };
  
          // initialization
          this.configure(configuration);
      }
  };
  