5

我知道 2.3 的 android 浏览器不支持 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);
}
4

2 回答 2

8

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

d3中其实可以直接使用canvas;这是 Mike Bostock 进行的比较,通过一个简单的示例展示了使用 SVG 和 Canvas 之间的区别:

帆布群/ SVG 群

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

于 2012-07-23T17:41:18.700 回答
1

实际上,您可以使用 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("style" 代替:

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

d3 内部也有使用 style 方法的函数,如axis,因此您可能还需要在库中进行这种替换。

于 2013-02-21T21:26:07.403 回答