X
Namespaces

dojox/charting/plot2d/Spider.js

  • Provides:

    • dojox.charting.plot2d.Spider
  • Requires:

    • dojox.charting.Element in common
    • dojox.charting.plot2d._PlotEvents in common
    • dojox.charting.axis2d.common in common
    • dojox.charting.plot2d.common in common
    • dojox.charting.scaler.primitive in common
    • dojox.lang.functional in common
    • dojox.lang.utils in common
    • dojox.gfx in common
    • dojo.fx in common in project dojo
    • dojo.fx.easing in common in project dojo
    • dojox.gfx.fx in common
  • dojox.charting.plot2d.Spider

    • type
      Function
    • chains:
      • dojox.charting.Element: (prototype)
      • dojox.charting.Element: (call)
      • dojox.charting.plot2d._PlotEvents: (call)
    • mixins:
      • dojox.charting.plot2d._PlotEvents.prototype: (prototype)
    • summary
      Create a Spider plot.
    • parameters:
      • chart: (typeof )
      • kwArgs: (typeof )
    • source: [view]
         this.opt = dojo.clone(this.defaultParams);
         du.updateWithObject(this.opt, kwArgs);
         du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
         this.series = [];
         this.dyn = [];
         this.datas = {};
         this.labelKey = [];
         this.oldSeriePoints = {};
         this.animations = {};
  • dojox.charting.plot2d.Spider.defaultParams

    • type
      Object
    • summary
  • dojox.charting.plot2d.Spider.optionalParams

    • type
      Object
    • summary
  • dojox.charting.plot2d.Spider.clear

    • type
      Function
    • source: [view]
         this.dirty = true;
         this.dyn = [];
         this.series = [];
         this.datas = {};
         this.labelKey = [];
         this.oldSeriePoints = {};
         this.animations = {};
         return this; // dojox.charting.plot2d.Spider
    • summary
      Clear out all of the information tied to this plot.
    • return_summary
      dojox.charting.plot2d.Spider
      A reference to this plot for functional chaining.
    • returns
      dojox.charting.plot2d.Spider
  • dojox.charting.plot2d.Spider.setAxis

    • type
      Function
    • parameters:
      • axis: (typeof )
    • source: [view]
         return this; // dojox.charting.plot2d.Spider
    • summary
      Dummy method, since axes are irrelevant with a Spider chart.
    • return_summary
      dojox.charting.plot2d.Spider
      The reference to this plot for functional chaining.
    • returns
      dojox.charting.plot2d.Spider
  • dojox.charting.plot2d.Spider.addSeries

    • type
      Function
    • parameters:
      • run: (typeof dojox.charting.Series)
        The series to be added.
    • source: [view]
         var matched = false;
         this.series.push(run);
         for(var key in run.data){
          var val = run.data[key],
           data = this.datas[key];
          if(data){
           data.vlist.push(val);
           data.min = Math.min(data.min, val);
           data.max = Math.max(data.max, val);
          }else{
           this.datas[key] = {min: val, max: val, vlist: [val]};
          }
         }
         if (this.labelKey.length <= 0) {
          for (var key in run.data) {
           this.labelKey.push(key);
          }
         }
         return this; // dojox.charting.plot2d.Base
    • summary
      Add a data series to this plot.
    • return_summary
      dojox.charting.plot2d.Base
      A reference to this plot for functional chaining.
    • returns
      dojox.charting.plot2d.Base
  • dojox.charting.plot2d.Spider.getSeriesStats

    • type
      Function
    • source: [view]
         return dojox.charting.plot2d.common.collectSimpleStats(this.series);
    • summary
      Calculate the min/max on all attached series in both directions.
    • return_summary
      Object
      {hmin, hmax, vmin, vmax} min/max in both directions.
  • dojox.charting.plot2d.Spider.calculateAxes

    • type
      Function
    • parameters:
      • dim: (typeof Object)
        An object of the form { width, height }
    • source: [view]
         this.initializeScalers(dim, this.getSeriesStats());
         return this; // dojox.charting.plot2d.Base
    • summary
      Stub function for running the axis calculations (depricated).
    • return_summary
      dojox.charting.plot2d.Base
      A reference to this plot for functional chaining.
    • returns
      dojox.charting.plot2d.Base
  • dojox.charting.plot2d.Spider.getRequiredColors

    • type
      Function
    • source: [view]
         return this.series.length; // Number
    • summary
      Get how many data series we have, so we know how many colors to use.
    • return_summary
      Number
      The number of colors needed.
    • returns
      Number
  • dojox.charting.plot2d.Spider.initializeScalers

    • type
      Function
    • parameters:
      • dim: (typeof Object)
        Size of a plot area in pixels as {width, height}.
      • stats: (typeof Object)
        Min/max of data in both directions as {hmin, hmax, vmin, vmax}.
    • source: [view]
         if(this._hAxis){
          if(!this._hAxis.initialized()){
           this._hAxis.calculate(stats.hmin, stats.hmax, dim.width);
          }
          this._hScaler = this._hAxis.getScaler();
         }else{
          this._hScaler = dojox.charting.scaler.primitive.buildScaler(stats.hmin, stats.hmax, dim.width);
         }
         if(this._vAxis){
          if(!this._vAxis.initialized()){
           this._vAxis.calculate(stats.vmin, stats.vmax, dim.height);
          }
          this._vScaler = this._vAxis.getScaler();
         }else{
          this._vScaler = dojox.charting.scaler.primitive.buildScaler(stats.vmin, stats.vmax, dim.height);
         }
         return this; // dojox.charting.plot2d.Base
    • summary
      Initializes scalers using attached axes.
    • return_summary
      dojox.charting.plot2d.Base
      A reference to this plot for functional chaining.
    • returns
      dojox.charting.plot2d.Base
  • dojox.charting.plot2d.Spider.render

    • type
      Function
    • parameters:
      • dim: (typeof Object)
        An object of the form { width, height }.
      • offsets: (typeof Object)
        An object of the form { l, r, t, b }.
    • source: [view]
         if(!this.dirty){ return this; }
         this.dirty = false;
         this.cleanGroup();
         var s = this.group, t = this.chart.theme;
         this.resetEvents();


         if(!this.series || !this.series.length){
          return this;
         }


         // calculate the geometry
         var o = this.opt, ta = t.axis,
          rx = (dim.width  - offsets.l - offsets.r) / 2,
          ry = (dim.height - offsets.t - offsets.b) / 2,
          r = Math.min(rx, ry),
          axisTickFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font) || "normal normal normal 7pt Tahoma",
          axisFont = o.axisFont || (ta.tick && ta.tick.titleFont) || "normal normal normal 11pt Tahoma",
          axisTickFontColor = o.axisTickFontColor || (ta.majorTick && ta.majorTick.fontColor) || (ta.tick && ta.tick.fontColor) || "silver",
          axisFontColor = o.axisFontColor || (ta.tick && ta.tick.titleFontColor) || "black",
          axisColor = o.axisColor || (ta.tick && ta.tick.axisColor) || "silver",
          spiderColor = o.spiderColor || (ta.tick && ta.tick.spiderColor) || "silver",
          axisWidth = o.axisWidth || (ta.stroke && ta.stroke.width) || 2,
          spiderWidth = o.spiderWidth || (ta.stroke && ta.stroke.width) || 2,
          seriesWidth = o.seriesWidth || (ta.stroke && ta.stroke.width) || 2,
          asize = g.normalizedLength(g.splitFontString(axisFont).size),
          startAngle = m._degToRad(o.startAngle),
          start = startAngle, step, filteredRun, slices, labels, shift, labelR,
          outerPoints, innerPoints, divisionPoints, divisionRadius, labelPoints,
          ro = o.spiderOrigin, dv = o.divisions >= 3 ? o.divisions : 3, ms = o.markerSize,
          spt = o.spiderType, at = o.animationType, lboffset = o.labelOffset < -10 ? o.labelOffset : -10,
          axisExtra = 0.2;

         
         if(o.labels){
          labels = dojo.map(this.series, function(s){
           return s.name;
          }, this);
          shift = df.foldl1(df.map(labels, function(label, i){
           var font = t.series.font;
           return dojox.gfx._base._getTextBox(label, {
            font: font
           }).w;
          }, this), "Math.max(a, b)") / 2;
          r = Math.min(rx - 2 * shift, ry - asize) + lboffset;
          labelR = r - lboffset;
         }
         if ("radius" in o) {
          r = o.radius;
          labelR = r - lboffset;
         }
         r /= (1+axisExtra);
         var circle = {
          cx: offsets.l + rx,
          cy: offsets.t + ry,
          r: r
         };

         
         for (var i = this.series.length - 1; i >= 0; i--) {
          var serieEntry = this.series[i];
          if (!this.dirty && !serieEntry.dirty) {
           t.skip();
           continue;
          }
          serieEntry.cleanGroup();
          var run = serieEntry.data;
          if (run !== null) {
           var len = this._getObjectLength(run);
           //construct connect points
           if (!outerPoints || outerPoints.length <= 0) {
            outerPoints = [], innerPoints = [], labelPoints = [];
            this._buildPoints(outerPoints, len, circle, r, start, true);
            this._buildPoints(innerPoints, len, circle, r*ro, start, true);
            this._buildPoints(labelPoints, len, circle, labelR, start);
            if(dv > 2){
             divisionPoints = [], divisionRadius = [];
             for (var j = 0; j < dv - 2; j++) {
              divisionPoints[j] = [];
              this._buildPoints(divisionPoints[j], len, circle, r*(ro + (1-ro)*(j+1)/(dv-1)), start, true);
              divisionRadius[j] = r*(ro + (1-ro)*(j+1)/(dv-1));
             }
            }
           }
          }
         }

         
         //draw Spider
         //axis
         var axisGroup = s.createGroup(), axisStroke = {color: axisColor, width: axisWidth},
          spiderStroke = {color: spiderColor, width: spiderWidth};
         for (var j = outerPoints.length - 1; j >= 0; --j) {
          var point = outerPoints[j],
           st = {
            x: point.x + (point.x - circle.cx) * axisExtra,
            y: point.y + (point.y - circle.cy) * axisExtra
           },
           nd = {
            x: point.x + (point.x - circle.cx) * axisExtra / 2,
            y: point.y + (point.y - circle.cy) * axisExtra / 2
           };
          axisGroup.createLine({
           x1: circle.cx,
           y1: circle.cy,
           x2: st.x,
           y2: st.y
          }).setStroke(axisStroke);
          //arrow
          this._drawArrow(axisGroup, st, nd, axisStroke);
         }

         
         // draw the label
         var labelGroup = s.createGroup();
         for (var j = labelPoints.length - 1; j >= 0; --j) {
          var point = labelPoints[j],
           fontWidth = dojox.gfx._base._getTextBox(this.labelKey[j], {font: axisFont}).w || 0,
           render = this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx";
           elem = da.createText[render](this.chart, labelGroup, (!dojo._isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y,
             "middle", this.labelKey[j], axisFont, axisFontColor);
          if (this.opt.htmlLabels) {
           this.htmlElements.push(elem);
          }
         }

         
         //spider web: polygon or circle
         var spiderGroup = s.createGroup();
         if(spt == "polygon"){
          spiderGroup.createPolyline(outerPoints).setStroke(spiderStroke);
          spiderGroup.createPolyline(innerPoints).setStroke(spiderStroke);
          if (divisionPoints.length > 0) {
           for (var j = divisionPoints.length - 1; j >= 0; --j) {
            spiderGroup.createPolyline(divisionPoints[j]).setStroke(spiderStroke);
           }
          }
         }else{//circle
          var ccount = this._getObjectLength(this.datas);
          spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r}).setStroke(spiderStroke);
          spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r*ro}).setStroke(spiderStroke);
          if (divisionRadius.length > 0) {
           for (var j = divisionRadius.length - 1; j >= 0; --j) {
            spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: divisionRadius[j]}).setStroke(spiderStroke);
           }
          }
         }
         //text
         var textGroup = s.createGroup(), len = this._getObjectLength(this.datas), k = 0;
         for(var key in this.datas){
          var data = this.datas[key], min = data.min, max = data.max, distance = max - min,
           end = start + 2 * Math.PI * k / len;
          for (var i = 0; i < dv; i++) {
           var text = min + distance*i/(dv-1), point = this._getCoordinate(circle, r*(ro + (1-ro)*i/(dv-1)), end);
           text = this._getLabel(text);
           var fontWidth = dojox.gfx._base._getTextBox(text, {font: axisTickFont}).w || 0,
            render = this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx";
           if (this.opt.htmlLabels) {
            this.htmlElements.push(da.createText[render]
             (this.chart, textGroup, (!dojo._isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y,
              "start", text, axisTickFont, axisTickFontColor));
           }
          }
          k++;
         }

         
         //draw series (animation)
         this.chart.seriesShapes = {};
         var animationConnections = [];
         for (var i = this.series.length - 1; i >= 0; i--) {
          var serieEntry = this.series[i], run = serieEntry.data;
          if (run !== null) {
           //series polygon
           var seriePoints = [], k = 0, tipData = [];
           for(var key in run){
            var data = this.datas[key], min = data.min, max = data.max, distance = max - min,
             entry = run[key], end = start + 2 * Math.PI * k / len,
             point = this._getCoordinate(circle, r*(ro + (1-ro)*(entry-min)/distance), end);
            seriePoints.push(point);
            tipData.push({sname: serieEntry.name, key: key, data: entry});
            k++;
           }
           seriePoints[seriePoints.length] = seriePoints[0];
           tipData[tipData.length] = tipData[0];
           var polygonBoundRect = this._getBoundary(seriePoints),
            theme = t.next("spider", [o, serieEntry]), ts = serieEntry.group,
            f = g.normalizeColor(theme.series.fill), sk = {color: theme.series.fill, width: seriesWidth};
           f.a = o.seriesFillAlpha;
           serieEntry.dyn = {fill: f, stroke: sk};

           
           var osps = this.oldSeriePoints[serieEntry.name];
           var cs = this._createSeriesEntry(ts, (osps || innerPoints), seriePoints, f, sk, r, ro, ms, at);
           this.chart.seriesShapes[serieEntry.name] = cs;
           this.oldSeriePoints[serieEntry.name] = seriePoints;

           
           var po = {
            element: "spider_poly",
            index:  i,
            id:   "spider_poly_"+serieEntry.name,
            run:  serieEntry,
            plot:  this,
            shape:  cs.poly,
            parent:  ts,
            brect:  polygonBoundRect,
            cx:   circle.cx,
            cy:   circle.cy,
            cr:   r,
            f:   f,
            s:   s
           };
           this._connectEvents(po);

           
           var so = {
            element: "spider_plot",
            index:  i,
            id:   "spider_plot_"+serieEntry.name,
            run:  serieEntry,
            plot:  this,
            shape:  serieEntry.group
           };
           this._connectEvents(so);

           
           dojo.forEach(cs.circles, function(c, i){
            var shape = c.getShape(),
             co = {
              element: "spider_circle",
              index:  i,
              id:   "spider_circle_"+serieEntry.name+i,
              run:  serieEntry,
              plot:  this,
              shape:  c,
              parent:  ts,
              tdata:  tipData[i],
              cx:   seriePoints[i].x,
              cy:   seriePoints[i].y,
              f:   f,
              s:   s
             };
            this._connectEvents(co);
           }, this);
          }
         }
         return this; // dojox.charting.plot2d.Spider
    • summary
      Render the plot on the chart.
    • return_summary
      dojox.charting.plot2d.Spider
      A reference to this plot for functional chaining.
    • returns
      dojox.charting.plot2d.Spider
  • dojox.charting.plot2d.Spider._createSeriesEntry

    • type
      Function
    • parameters:
      • ts: (typeof )
      • osps: (typeof )
      • sps: (typeof )
      • f: (typeof )
      • sk: (typeof )
      • r: (typeof )
      • ro: (typeof )
      • ms: (typeof )
      • at: (typeof )
    • source: [view]
      dojo.provide("dojox.charting.plot2d.Spider");


      dojo.experimental("dojox.charting.plot2d.Spider");


      dojo.require("dojox.charting.Element");
      dojo.require("dojox.charting.plot2d._PlotEvents");
      dojo.require("dojox.charting.axis2d.common");
      dojo.require("dojox.charting.plot2d.common");
      dojo.require("dojox.charting.scaler.primitive");


      dojo.require("dojox.lang.functional");
      dojo.require("dojox.lang.utils");
      dojo.require("dojox.gfx");
      dojo.require("dojo.fx");
      dojo.require("dojo.fx.easing");
      dojo.require("dojox.gfx.fx");


      (function(){
       var df = dojox.lang.functional, du = dojox.lang.utils,
        dc = dojox.charting.plot2d.common,
        da = dojox.charting.axis2d.common,
        g = dojox.gfx, m = g.matrix,
        FUDGE_FACTOR = 0.2; // use to overlap fans


       dojo.declare("dojox.charting.plot2d.Spider", [dojox.charting.Element, dojox.charting.plot2d._PlotEvents], {
        // summary:
        //  The plot that represents a typical Spider chart.
        defaultParams: {
         labels:   true,
         ticks:   false,
         fixed:   true,
         precision:  1,
         labelOffset: -10,
         labelStyle:  "default", // default/rows/auto
         htmlLabels:  true,  // use HTML to draw labels
         startAngle:  -90,  // start angle for slices in degrees
         divisions:   3,   // radius tick count
         axisColor:   "",  // spider axis color
         axisWidth:   0,   // spider axis stroke width
         spiderColor:  "",  // spider web color
         spiderWidth:  0,   // spider web stroke width
         seriesWidth:  0,   // plot border with
         seriesFillAlpha: 0.2,  // plot fill alpha
         spiderOrigin:  0.16,
         markerSize:   3,   // radius of plot vertex (px)
         spiderType:   "polygon", //"circle"
         animationType:  dojo.fx.easing.backOut,
         axisTickFont:  "",
         axisTickFontColor: "",
         axisFont:   "",
         axisFontColor:  ""
        },
        optionalParams: {
         radius:  0,
         font:  "",
         fontColor: ""
        },


        constructor: function(chart, kwArgs){
         // summary:
         //  Create a Spider plot.
         this.opt = dojo.clone(this.defaultParams);
         du.updateWithObject(this.opt, kwArgs);
         du.updateWithPattern(this.opt, kwArgs, this.optionalParams);
         this.series = [];
         this.dyn = [];
         this.datas = {};
         this.labelKey = [];
         this.oldSeriePoints = {};
         this.animations = {};
        },
        clear: function(){
         // summary:
         //  Clear out all of the information tied to this plot.
         // returns: dojox.charting.plot2d.Spider
         //  A reference to this plot for functional chaining.
         this.dirty = true;
         this.dyn = [];
         this.series = [];
         this.datas = {};
         this.labelKey = [];
         this.oldSeriePoints = {};
         this.animations = {};
         return this; // dojox.charting.plot2d.Spider
        },
        setAxis: function(axis){
         // summary:
         //  Dummy method, since axes are irrelevant with a Spider chart.
         // returns: dojox.charting.plot2d.Spider
         //  The reference to this plot for functional chaining.
         return this; // dojox.charting.plot2d.Spider
        },
        addSeries: function(run){
         // summary:
         //  Add a data series to this plot.
         // run: dojox.charting.Series
         //  The series to be added.
         // returns: dojox.charting.plot2d.Base
         //  A reference to this plot for functional chaining.
         var matched = false;
         this.series.push(run);
         for(var key in run.data){
          var val = run.data[key],
           data = this.datas[key];
          if(data){
           data.vlist.push(val);
           data.min = Math.min(data.min, val);
           data.max = Math.max(data.max, val);
          }else{
           this.datas[key] = {min: val, max: val, vlist: [val]};
          }
         }
         if (this.labelKey.length <= 0) {
          for (var key in run.data) {
           this.labelKey.push(key);
          }
         }
         return this; // dojox.charting.plot2d.Base
        },
        getSeriesStats: function(){
         // summary:
         //  Calculate the min/max on all attached series in both directions.
         // returns: Object
         //  {hmin, hmax, vmin, vmax} min/max in both directions.
         return dojox.charting.plot2d.common.collectSimpleStats(this.series);
        },
        calculateAxes: function(dim){
         // summary:
         //  Stub function for running the axis calculations (depricated).
         // dim: Object
         //  An object of the form { width, height }
         // returns: dojox.charting.plot2d.Base
         //  A reference to this plot for functional chaining.
         this.initializeScalers(dim, this.getSeriesStats());
         return this; // dojox.charting.plot2d.Base
        },
        getRequiredColors: function(){
         // summary:
         //  Get how many data series we have, so we know how many colors to use.
         // returns: Number
         //  The number of colors needed.
         return this.series.length; // Number
        },
        initializeScalers: function(dim, stats){
         // summary:
         //  Initializes scalers using attached axes.
         // dim: Object:
         //  Size of a plot area in pixels as {width, height}.
         // stats: Object:
         //  Min/max of data in both directions as {hmin, hmax, vmin, vmax}.
         // returns: dojox.charting.plot2d.Base
         //  A reference to this plot for functional chaining.
         if(this._hAxis){
          if(!this._hAxis.initialized()){
           this._hAxis.calculate(stats.hmin, stats.hmax, dim.width);
          }
          this._hScaler = this._hAxis.getScaler();
         }else{
          this._hScaler = dojox.charting.scaler.primitive.buildScaler(stats.hmin, stats.hmax, dim.width);
         }
         if(this._vAxis){
          if(!this._vAxis.initialized()){
           this._vAxis.calculate(stats.vmin, stats.vmax, dim.height);
          }
          this._vScaler = this._vAxis.getScaler();
         }else{
          this._vScaler = dojox.charting.scaler.primitive.buildScaler(stats.vmin, stats.vmax, dim.height);
         }
         return this; // dojox.charting.plot2d.Base
        },
        render: function(dim, offsets){
         // summary:
         //  Render the plot on the chart.
         // dim: Object
         //  An object of the form { width, height }.
         // offsets: Object
         //  An object of the form { l, r, t, b }.
         // returns: dojox.charting.plot2d.Spider
         //  A reference to this plot for functional chaining.
         if(!this.dirty){ return this; }
         this.dirty = false;
         this.cleanGroup();
         var s = this.group, t = this.chart.theme;
         this.resetEvents();


         if(!this.series || !this.series.length){
          return this;
         }


         // calculate the geometry
         var o = this.opt, ta = t.axis,
          rx = (dim.width  - offsets.l - offsets.r) / 2,
          ry = (dim.height - offsets.t - offsets.b) / 2,
          r = Math.min(rx, ry),
          axisTickFont = o.font || (ta.majorTick && ta.majorTick.font) || (ta.tick && ta.tick.font) || "normal normal normal 7pt Tahoma",
          axisFont = o.axisFont || (ta.tick && ta.tick.titleFont) || "normal normal normal 11pt Tahoma",
          axisTickFontColor = o.axisTickFontColor || (ta.majorTick && ta.majorTick.fontColor) || (ta.tick && ta.tick.fontColor) || "silver",
          axisFontColor = o.axisFontColor || (ta.tick && ta.tick.titleFontColor) || "black",
          axisColor = o.axisColor || (ta.tick && ta.tick.axisColor) || "silver",
          spiderColor = o.spiderColor || (ta.tick && ta.tick.spiderColor) || "silver",
          axisWidth = o.axisWidth || (ta.stroke && ta.stroke.width) || 2,
          spiderWidth = o.spiderWidth || (ta.stroke && ta.stroke.width) || 2,
          seriesWidth = o.seriesWidth || (ta.stroke && ta.stroke.width) || 2,
          asize = g.normalizedLength(g.splitFontString(axisFont).size),
          startAngle = m._degToRad(o.startAngle),
          start = startAngle, step, filteredRun, slices, labels, shift, labelR,
          outerPoints, innerPoints, divisionPoints, divisionRadius, labelPoints,
          ro = o.spiderOrigin, dv = o.divisions >= 3 ? o.divisions : 3, ms = o.markerSize,
          spt = o.spiderType, at = o.animationType, lboffset = o.labelOffset < -10 ? o.labelOffset : -10,
          axisExtra = 0.2;

         
         if(o.labels){
          labels = dojo.map(this.series, function(s){
           return s.name;
          }, this);
          shift = df.foldl1(df.map(labels, function(label, i){
           var font = t.series.font;
           return dojox.gfx._base._getTextBox(label, {
            font: font
           }).w;
          }, this), "Math.max(a, b)") / 2;
          r = Math.min(rx - 2 * shift, ry - asize) + lboffset;
          labelR = r - lboffset;
         }
         if ("radius" in o) {
          r = o.radius;
          labelR = r - lboffset;
         }
         r /= (1+axisExtra);
         var circle = {
          cx: offsets.l + rx,
          cy: offsets.t + ry,
          r: r
         };

         
         for (var i = this.series.length - 1; i >= 0; i--) {
          var serieEntry = this.series[i];
          if (!this.dirty && !serieEntry.dirty) {
           t.skip();
           continue;
          }
          serieEntry.cleanGroup();
          var run = serieEntry.data;
          if (run !== null) {
           var len = this._getObjectLength(run);
           //construct connect points
           if (!outerPoints || outerPoints.length <= 0) {
            outerPoints = [], innerPoints = [], labelPoints = [];
            this._buildPoints(outerPoints, len, circle, r, start, true);
            this._buildPoints(innerPoints, len, circle, r*ro, start, true);
            this._buildPoints(labelPoints, len, circle, labelR, start);
            if(dv > 2){
             divisionPoints = [], divisionRadius = [];
             for (var j = 0; j < dv - 2; j++) {
              divisionPoints[j] = [];
              this._buildPoints(divisionPoints[j], len, circle, r*(ro + (1-ro)*(j+1)/(dv-1)), start, true);
              divisionRadius[j] = r*(ro + (1-ro)*(j+1)/(dv-1));
             }
            }
           }
          }
         }

         
         //draw Spider
         //axis
         var axisGroup = s.createGroup(), axisStroke = {color: axisColor, width: axisWidth},
          spiderStroke = {color: spiderColor, width: spiderWidth};
         for (var j = outerPoints.length - 1; j >= 0; --j) {
          var point = outerPoints[j],
           st = {
            x: point.x + (point.x - circle.cx) * axisExtra,
            y: point.y + (point.y - circle.cy) * axisExtra
           },
           nd = {
            x: point.x + (point.x - circle.cx) * axisExtra / 2,
            y: point.y + (point.y - circle.cy) * axisExtra / 2
           };
          axisGroup.createLine({
           x1: circle.cx,
           y1: circle.cy,
           x2: st.x,
           y2: st.y
          }).setStroke(axisStroke);
          //arrow
          this._drawArrow(axisGroup, st, nd, axisStroke);
         }

         
         // draw the label
         var labelGroup = s.createGroup();
         for (var j = labelPoints.length - 1; j >= 0; --j) {
          var point = labelPoints[j],
           fontWidth = dojox.gfx._base._getTextBox(this.labelKey[j], {font: axisFont}).w || 0,
           render = this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx";
           elem = da.createText[render](this.chart, labelGroup, (!dojo._isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y,
             "middle", this.labelKey[j], axisFont, axisFontColor);
          if (this.opt.htmlLabels) {
           this.htmlElements.push(elem);
          }
         }

         
         //spider web: polygon or circle
         var spiderGroup = s.createGroup();
         if(spt == "polygon"){
          spiderGroup.createPolyline(outerPoints).setStroke(spiderStroke);
          spiderGroup.createPolyline(innerPoints).setStroke(spiderStroke);
          if (divisionPoints.length > 0) {
           for (var j = divisionPoints.length - 1; j >= 0; --j) {
            spiderGroup.createPolyline(divisionPoints[j]).setStroke(spiderStroke);
           }
          }
         }else{//circle
          var ccount = this._getObjectLength(this.datas);
          spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r}).setStroke(spiderStroke);
          spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: r*ro}).setStroke(spiderStroke);
          if (divisionRadius.length > 0) {
           for (var j = divisionRadius.length - 1; j >= 0; --j) {
            spiderGroup.createCircle({cx: circle.cx, cy: circle.cy, r: divisionRadius[j]}).setStroke(spiderStroke);
           }
          }
         }
         //text
         var textGroup = s.createGroup(), len = this._getObjectLength(this.datas), k = 0;
         for(var key in this.datas){
          var data = this.datas[key], min = data.min, max = data.max, distance = max - min,
           end = start + 2 * Math.PI * k / len;
          for (var i = 0; i < dv; i++) {
           var text = min + distance*i/(dv-1), point = this._getCoordinate(circle, r*(ro + (1-ro)*i/(dv-1)), end);
           text = this._getLabel(text);
           var fontWidth = dojox.gfx._base._getTextBox(text, {font: axisTickFont}).w || 0,
            render = this.opt.htmlLabels && dojox.gfx.renderer != "vml" ? "html" : "gfx";
           if (this.opt.htmlLabels) {
            this.htmlElements.push(da.createText[render]
             (this.chart, textGroup, (!dojo._isBodyLtr() && render == "html") ? (point.x + fontWidth - dim.width) : point.x, point.y,
              "start", text, axisTickFont, axisTickFontColor));
           }
          }
          k++;
         }

         
         //draw series (animation)
         this.chart.seriesShapes = {};
         var animationConnections = [];
         for (var i = this.series.length - 1; i >= 0; i--) {
          var serieEntry = this.series[i], run = serieEntry.data;
          if (run !== null) {
           //series polygon
           var seriePoints = [], k = 0, tipData = [];
           for(var key in run){
            var data = this.datas[key], min = data.min, max = data.max, distance = max - min,
             entry = run[key], end = start + 2 * Math.PI * k / len,
             point = this._getCoordinate(circle, r*(ro + (1-ro)*(entry-min)/distance), end);
            seriePoints.push(point);
            tipData.push({sname: serieEntry.name, key: key, data: entry});
            k++;
           }
           seriePoints[seriePoints.length] = seriePoints[0];
           tipData[tipData.length] = tipData[0];
           var polygonBoundRect = this._getBoundary(seriePoints),
            theme = t.next("spider", [o, serieEntry]), ts = serieEntry.group,
            f = g.normalizeColor(theme.series.fill), sk = {color: theme.series.fill, width: seriesWidth};
           f.a = o.seriesFillAlpha;
           serieEntry.dyn = {fill: f, stroke: sk};

           
           var osps = this.oldSeriePoints[serieEntry.name];
           var cs = this._createSeriesEntry(ts, (osps || innerPoints), seriePoints, f, sk, r, ro, ms, at);
           this.chart.seriesShapes[serieEntry.name] = cs;
           this.oldSeriePoints[serieEntry.name] = seriePoints;

           
           var po = {
            element: "spider_poly",
            index:  i,
            id:   "spider_poly_"+serieEntry.name,
            run:  serieEntry,
            plot:  this,
            shape:  cs.poly,
            parent:  ts,
            brect:  polygonBoundRect,
            cx:   circle.cx,
            cy:   circle.cy,
            cr:   r,
            f:   f,
            s:   s
           };
           this._connectEvents(po);

           
           var so = {
            element: "spider_plot",
            index:  i,
            id:   "spider_plot_"+serieEntry.name,
            run:  serieEntry,
            plot:  this,
            shape:  serieEntry.group
           };
           this._connectEvents(so);

           
           dojo.forEach(cs.circles, function(c, i){
            var shape = c.getShape(),
             co = {
              element: "spider_circle",
              index:  i,
              id:   "spider_circle_"+serieEntry.name+i,
              run:  serieEntry,
              plot:  this,
              shape:  c,
              parent:  ts,
              tdata:  tipData[i],
              cx:   seriePoints[i].x,
              cy:   seriePoints[i].y,
              f:   f,
              s:   s
             };
            this._connectEvents(co);
           }, this);
          }
         }
         return this; // dojox.charting.plot2d.Spider
        },
        _createSeriesEntry: function(ts, osps, sps, f, sk, r, ro, ms, at){
         //polygon
         var spoly = ts.createPolyline(osps).setFill(f).setStroke(sk), scircle = [];
         for (var j = 0; j < osps.length; j++) {
          var point = osps[j], cr = ms;
          var circle = ts.createCircle({cx: point.x, cy: point.y, r: cr}).setFill(f).setStroke(sk);
          scircle.push(circle);
         }

         
         var anims = dojo.map(sps, function(np, j){
          // create animation
          var sp = osps[j],
           anim = new dojo._Animation({
           duration: 1000,
           easing:  at,
           curve:  [sp.y, np.y]
          });
          var spl = spoly, sc = scircle[j];
          dojo.connect(anim, "onAnimate", function(y){
           //apply poly
           var pshape = spl.getShape();
           pshape.points[j].y = y;
           spl.setShape(pshape);
           //apply circle
           var cshape = sc.getShape();
           cshape.cy = y;
           sc.setShape(cshape);
          });
          return anim;
         });

         
         var anims1 = dojo.map(sps, function(np, j){
          // create animation
          var sp = osps[j],
           anim = new dojo._Animation({
           duration: 1000,
           easing:  at,
           curve:  [sp.x, np.x]
          });
          var spl = spoly, sc = scircle[j];
          dojo.connect(anim, "onAnimate", function(x){
           //apply poly
           var pshape = spl.getShape();
           pshape.points[j].x = x;
           spl.setShape(pshape);
           //apply circle
           var cshape = sc.getShape();
           cshape.cx = x;
           sc.setShape(cshape);
          });
          return anim;
         });
         var masterAnimation = dojo.fx.combine(anims.concat(anims1)); //dojo.fx.chain(anims);
         masterAnimation.play();
         return {group :ts, poly: spoly, circles: scircle};
    • returns
      dojox.charting.plot2d.Spider|dojox.charting.plot2d.Base|Number
    • summary
  • dojox.charting.plot2d.Spider.plotEvent

    • type
      Function
    • parameters:
      • o: (typeof Object)
        An object intended to represent event parameters.
    • source: [view]
         var runName = o.id ? o.id : "default", a;
         if (runName in this.animations) {
          a = this.animations[runName];
          a.anim && a.anim.stop(true);
         } else {
          a = this.animations[runName] = {};
         }
         if(o.element == "spider_poly"){
          if(!a.color){
           var color = o.shape.getFill();
           if(!color || !(color instanceof dojo.Color)){
            return;
           }
           a.color = {
            start: color,
            end: transColor(color)
           };
          }
          var start = a.color.start, end = a.color.end;
          if(o.type == "onmouseout"){
           // swap colors
           var t = start; start = end; end = t;
          }
          a.anim = dojox.gfx.fx.animateFill({
           shape:  o.shape,
           duration: 800,
           easing:  dojo.fx.easing.backOut,
           color:  {start: start, end: end}
          });
          a.anim.play();
         }else if(o.element == "spider_circle"){
          var init, scale, defaultScale = 1.5;
          if(o.type == "onmouseover"){
           init = dojox.gfx.matrix.identity;
           scale = defaultScale;
           //show tooltip
           var aroundRect = {type: "rect"};
           aroundRect.x = o.cx;
           aroundRect.y = o.cy;
           aroundRect.width = aroundRect.height = 1;
           var lt = dojo.coords(this.chart.node, true);
           aroundRect.x += lt.x;
           aroundRect.y += lt.y;
           aroundRect.x = Math.round(aroundRect.x);
           aroundRect.y = Math.round(aroundRect.y);
           aroundRect.width = Math.ceil(aroundRect.width);
           aroundRect.height = Math.ceil(aroundRect.height);
           this.aroundRect = aroundRect;
           var position = ["after", "before"];
           if(dijit && dijit.Tooltip){
            dijit.showTooltip(o.tdata.sname + "
      " + o.tdata.key + "
      " + o.tdata.data, this.aroundRect, position);
           }
          }else{
           init = dojox.gfx.matrix.scaleAt(defaultScale, o.cx, o.cy);
           scale = 1/defaultScale;
           if(dijit && dijit.Tooltip){
            this.aroundRect && dijit.hideTooltip(this.aroundRect);
           }
          }
          var cs = o.shape.getShape(),
           init = m.scaleAt(defaultScale, cs.cx, cs.cy),
           kwArgs = {
            shape: o.shape,
            duration: 200,
            easing:  dojo.fx.easing.backOut,
            transform: [
             {name: "scaleAt", start: [1, cs.cx, cs.cy], end: [scale, cs.cx, cs.cy]},
             init
            ]
           };
          a.anim = dojox.gfx.fx.animateTransform(kwArgs);
          a.anim.play();
         }else if(o.element == "spider_plot"){
          //dojo gfx function "moveToFront" not work in IE
          if (o.type == "onmouseover" && !dojo.isIE) {
           o.shape.moveToFront();
          }
         }
    • summary
      Stub function for use by specific plots.
  • dojox.charting.plot2d.Spider._getBoundary

    • type
      Function
    • parameters:
      • points: (typeof )
    • source: [view]
         var xmax = points[0].x,
          xmin = points[0].x,
          ymax = points[0].y,
          ymin = points[0].y;
         for(var i = 0; i < points.length; i++){
          var point = points[i];
          xmax = Math.max(point.x, xmax);
          ymax = Math.max(point.y, ymax);
          xmin = Math.min(point.x, xmin);
          ymin = Math.min(point.y, ymin);
         }
         return {
          x: xmin,
          y: ymin,
          width: xmax - xmin,
          height: ymax - ymin
         };
    • summary
  • dojox.charting.plot2d.Spider._drawArrow

    • type
      Function
    • parameters:
      • s: (typeof )
      • start: (typeof )
      • end: (typeof )
      • stroke: (typeof )
    • source: [view]
         var len = Math.sqrt(Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2)),
          sin = (end.y - start.y)/len, cos = (end.x - start.x)/len,
          point2 = {x: end.x + (len/3)*(-sin), y: end.y + (len/3)*cos},
          point3 = {x: end.x + (len/3)*sin, y: end.y + (len/3)*(-cos)};
         s.createPolyline([start, point2, point3]).setFill(stroke.color).setStroke(stroke);
    • summary
  • dojox.charting.plot2d.Spider._buildPoints

    • type
      Function
    • parameters:
      • points: (typeof )
      • count: (typeof )
      • circle: (typeof )
      • radius: (typeof )
      • angle: (typeof )
      • recursive: (typeof )
    • source: [view]
         for (var i = 0; i < count; i++) {
          var end = angle + 2 * Math.PI * i / count;
          points.push(this._getCoordinate(circle, radius, end));
         }
         if(recursive){
          points.push(this._getCoordinate(circle, radius, angle + 2 * Math.PI));
         }
    • summary
  • dojox.charting.plot2d.Spider._getCoordinate

    • type
      Function
    • parameters:
      • circle: (typeof )
      • radius: (typeof )
      • angle: (typeof )
    • source: [view]
         return {
          x: circle.cx + radius * Math.cos(angle),
          y: circle.cy + radius * Math.sin(angle)
         }
    • summary
  • dojox.charting.plot2d.Spider._getObjectLength

    • type
      Function
    • parameters:
      • obj: (typeof )
    • source: [view]
         var count = 0;
         if(dojo.isObject(obj)){
          for(var key in obj){
           count++;
          }
         }
         return count;
    • summary
  • dojox.charting.plot2d.Spider._getLabel

    • type
      Function
    • parameters:
      • number: (typeof )
    • source: [view]
         return dc.getLabel(number, this.opt.fixed, this.opt.precision);
    • summary
  • dojox.charting.plot2d.Spider.defaultParams.labels

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.ticks

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.fixed

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.precision

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.labelOffset

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.labelStyle

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.htmlLabels

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.startAngle

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.divisions

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.axisColor

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.axisWidth

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.spiderColor

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.spiderWidth

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.seriesWidth

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.seriesFillAlpha

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.spiderOrigin

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.markerSize

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.spiderType

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.animationType

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.axisTickFont

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.axisTickFontColor

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.axisFont

    • summary
  • dojox.charting.plot2d.Spider.defaultParams.axisFontColor

    • summary
  • dojox.charting.plot2d.Spider.optionalParams.radius

    • summary
  • dojox.charting.plot2d.Spider.optionalParams.font

    • summary
  • dojox.charting.plot2d.Spider.optionalParams.fontColor

    • summary
  • dojox.charting.plot2d.Spider.dirty

    • summary
  • dojox.charting.plot2d.Spider.dyn

    • summary
  • dojox.charting.plot2d.Spider.series

    • summary
  • dojox.charting.plot2d.Spider.datas

    • summary
  • dojox.charting.plot2d.Spider.labelKey

    • summary
  • dojox.charting.plot2d.Spider.oldSeriePoints

    • summary
  • dojox.charting.plot2d.Spider.animations

    • summary
  • dojox.charting.plot2d.Spider._hScaler

    • summary
  • dojox.charting.plot2d.Spider._vScaler

    • summary
  • dojox.charting.plot2d.Spider.chart.seriesShapes

    • summary
  • dojox.charting.plot2d.Spider.aroundRect

    • summary
  • dojox.charting.plot2d.Spider.opt

    • summary
  • dc

    • summary
  • da

    • summary
  • g

    • summary
  • FUDGE_FACTOR

    • summary
  • x

    • summary
  • x.l

    • summary
  • x.s

    • summary
  • color.a

    • summary
  • spiderStroke.color

    • summary
  • spiderStroke.width

    • summary
  • spiderStroke

    • type
      Object
    • summary
  • st.x

    • summary
  • st.y

    • summary
  • st

    • type
      Object
    • summary
  • nd.x

    • summary
  • nd.y

    • summary
  • nd

    • type
      Object
    • summary
  • co.element

    • summary
  • co.index

    • summary
  • co.id

    • summary
  • co.run

    • summary
  • co.plot

    • summary
  • co.shape

    • summary
  • co.parent

    • summary
  • co.tdata

    • summary
  • co.cx

    • summary
  • co.cy

    • summary
  • co.f

    • summary
  • co.s

    • summary
  • co

    • type
      Object
    • summary
  • kwArgs.shape

    • summary
  • kwArgs.duration

    • summary
  • kwArgs.easing

    • summary
  • kwArgs.transform

    • summary
  • kwArgs

    • type
      Object
    • summary
  • point2.x

    • summary
  • point2.y

    • summary
  • point2

    • type
      Object
    • summary
  • point3.x

    • summary
  • point3.y

    • summary
  • point3

    • type
      Object
    • summary
  • dojox.charting.plot2d

    • type
      Object
    • summary
  • dojox.charting

    • type
      Object
    • summary
  • dojox

    • type
      Object
    • summary