android 2.3上的d3.js可视化

d3.js visualization on android 2.3

本文关键字:js 可视化 d3 上的 android      更新时间:2024-01-06

我知道android浏览器2.3不支持SVG,但我想知道是否可以在客户端使用Canvg将d3.js SVG可视化转换为画布。浏览器是否能够解析SVG元素,或者是否需要在服务器端进行从SVG到Canvas的转换?提前感谢!

// Grab data from server...
var btoken = window.location.search.split( 'bearer_token=')[1].split('&')[0]; 
var endpoint = "http://dcaps-staging.media.mit.edu:8080/api/reality_analysis_service/get_reality_analysis_data?document_key=radialData&bearer_token=" + btoken;
console.log(endpoint);
  d3.json(endpoint, function(json){
  console.log(json);
  var data = json.radialData.data;
  var csvdata; 
      csvdata = data;
    //var data

var output_ = '';
for( property in data) {
output_ += property +':' + data[property]+';';
}
console.log(output_);
  var meta = json.radialData.meta;
  var capitalMeta = [];
  for (i = 0; i < meta.length; i++){
      capitalMeta.push(capitaliseFirstLetter(meta[i]));
  }
console.log(window.innerWidth, window.innerHeight )
//var width = 335,
  //  height = 340,
  var width = window.innerWidth - 5,
      height = window.innerHeight - (window.innerHeight * .35),
    outerRadius = height / 2 - 10,
    innerRadius = 120;
var angle = d3.scale.linear()
    .range([0, 2 * Math.PI]);
var radius = d3.scale.linear()
    .range([0, outerRadius]);
var z = d3.scale.category20();
var whiteColor = d3.rgb(255,255,255);
var redColor = d3.rgb(200,100,50);
var newColor = d3.rgb(100,100,100);
var pink = d3.rgb(238,98,226);
var stack = d3.layout.stack()
    .offset("zero")//.offset(function(d) { return d.y0; })
    .values(function(d) { return d.values; })
    .x(function(d, i) { return i; })
    .y(function(d) { return d.value; });
var replaceY0 = 0;
var nest = d3.nest()
    .key(function(d) { return d.layer; });
var line = d3.svg.line.radial()
    .interpolate("cardinal-closed")
    .angle(function(d,i) { return angle(i); })
    .radius(function(d) { return radius(replaceY0 + d.y); });

var lowestValues = [];
// parse response for lowest values
for (i = 0; i < csvdata.length; i++){
  if (csvdata[i].layer == "averageLow"){
      lowestValues.push(csvdata[i].value);
  }
}
var area = d3.svg.area.radial()
    .interpolate("cardinal-closed")
    .angle(function(d, i) { return angle(i); })
    //.innerRadius(function(d) { return radius(replaceY0); })
    .innerRadius(function(d, i) {
        if (d.layer == "User"){ // Hardcoded check right now, might change later...data tag must have USER in it...
          return radius(d.y);
        }
        else{
        return radius(lowestValues[i]);
      }
    })
    .outerRadius(function(d) { return radius(replaceY0 + d.y); });
var heightPadding = 20;
var widthPadding = 2;
var svg = d3.select("#radial_chart").append("svg")
    .attr("width", width)
    .attr("height", height)
  .append("g")
    .attr("transform", "translate(" + ((width / 2) + widthPadding) + "," + ((height / 2) + heightPadding) + ")");
//console.log("data : ", data);
//console.log("svg : ", svg);
var output_SVG = '';
for( property in svg[0][0]) {
output_SVG += property +':' + data[property]+';';
}
console.log(output_SVG);
  var layers = stack(nest.entries(data));
  // Hardcoded swap for User and Average High
  var swapper = layers[2];
  layers[2] = layers[1];
  layers[1] = swapper;

//  console.log("LAYERS : ",layers);
console.log(capitalMeta[0]);
  // Extend the domain slightly to match the range of [0, 2π].
  angle.domain([0, layers.length]);
  //radius.domain([0, d3.max(data, function(d) { console.log("d.y0: ",d.y0); console.log("d.y: ",d.y); return d.y + replaceY0; })]);
  radius.domain([0, 10]);
  var x = svg.selectAll(".axis");
  alert(svg.toString());
  // create Axis
  svg.selectAll(".axis")
      .data(d3.range(angle.domain()[1]))
    .enter().append("g")
      .attr("class", "axis")
      .attr("transform", function(d) { return "rotate(" + angle(d) * 180 / Math.PI + ")"; })
    .call(d3.svg.axis()
      .scale(radius.copy().range([-5, -outerRadius]))
      .ticks(5)
      .orient("left"))
    .append("text")
      .attr("y", 
        function (d) {
          if (window.innerWidth < 455){
            console.log("innerWidth less than 455: ",window.innerWidth);
            return -(window.innerHeight * .33);
          }
          else{
            console.log("innerWidth greater than 455: ",window.innerWidth);
            return -(window.innerHeight * .33);
          }
        })
      .attr("dy", ".71em")
      .attr("text-anchor", "middle")
      .text(function(d, i) { return capitalMeta[i]; })
      .attr("style","font-size:12px;");
  svg.selectAll(".layer")
      .data(layers)
    .enter().append("path")
      .attr("class", "layer")
      .attr("d", function(d) { return area(d.values); })
      .style("fill",
        function(d, i) 
        {
          if (i === 0){
            return whiteColor;
          }
          else if (i == 1){
            return z(i);
          }
          else
          return newColor; 
        })
      .style("opacity",.6)
      .style("stroke",function(d, i){
       if (i == 0)
        return whiteColor;
      else if (i == 2)
        return pink;
      else if (i == 1)
        return whiteColor;
      })
      .style("stroke-width",function(d, i){
       if (i == 1){
          return 0;
        }
        else if (i == 0)
          return 0;
        else
          return 7;
      });
alert('finished');

/*
 // Create the svg drawing canvas...
      var canvas = d3.select("#radial_chart")
        .append("svg:svg")
          .attr("width", 300)//canvasWidth)
          .attr("height", 75)//canvasHeight);
          .attr("id","legend");
legendOffset = 35;
  legendMarginLeft = 60;
var arrayOfTypes = ["User","Average High-Low"];
      // Plot the bullet circles...
      canvas.selectAll("circle")
        .data(arrayOfTypes).enter().append("svg:circle") // Append circle elements
          .attr("cx", legendMarginLeft)// barsWidthTotal + legendBulletOffset)
    .attr("cy", function(d, i) { return legendOffset + i*25; } )
          .attr("stroke-width", ".5")
          .style("fill", function(d, i) { 
          if (i == 0)
            return pink;
          else
            return z(i) }) // Bar fill color
          .attr("r", 10);
      // Create hyper linked text at right that acts as label key...
      canvas.selectAll("a.legend_link")
        .data(arrayOfTypes) // Instruct to bind dataSet to text elements
        .enter().append("svg:a") // Append legend elements
      .append("text")
              .attr("text-anchor", "left")
              .attr("x", legendMarginLeft+15)
        .attr("y", function(d, i) { return legendOffset + i*24 - 10; })
              .attr("dx", 5)
              .attr("dy", "1em") // Controls padding to place text above bars
              .text(function(d, i) { return arrayOfTypes[i];})
              .style("color","white")
*/
//                 canvg();
    alert('finished');

  });
function capitaliseFirstLetter(string) {
      return string.charAt(0).toUpperCase() + string.slice(1);
}

Android确实支持Canvas,所以这当然是一个不错的选择(就SVG支持而言,Android 2.3不兼容是正确的)。

实际上,您可以在d3中直接使用canvas;下面是Mike Bostock做的一个比较,显示了使用SVG和Canvas之间的差异,使用了一个简单的例子:

Canvas Swarm/SVG Swarm

请记住,您不仅仅局限于SVG或Canvas;例如,已经看到www.nytimes.com-interactive使用带有HTML元素的d3.js进行可视化(我怀疑是为了更好地支持跨浏览器)
请参阅:http://www.nytimes.com/interactive/2012/02/13/us/politics/2013-budget-proposal-graphic.html

实际上,您可以使用Canvg在客户端将d3的SVG显示为画布。遵循此处的代码:http://jsfiddle.net/plaliberte/HAXyd/您只需将带有生成的SVG的div提供给Canvg函数。唯一的问题是,如果在d3操作的一部分中使用".style",它会因为某种原因引发错误。例如:

.style("text-anchor","middle")

在Android 2.x中,它抛出:

TypeError: Result of expression 'this.style' [null] is not an object

因此,您需要修改这些方法以使用.attr("样式":

.attr("style", "text-anchor:middle")

d3中也有使用类似axis的样式方法的函数,因此您可能还需要在库中进行这种替换。