S
S
SEOD2019-12-25 10:23:29
JavaScript
SEOD, 2019-12-25 10:23:29

How to automate the process of capturing video (ScreenCapture) for SVG animation?

It is necessary to automate the process of capturing video (ScreenCapture) for the SVG element (animated via D3.js) in which the animation takes place. But how to automate - I have no idea. Just run a third-party recording program on the forehead and then cut both in time and cut out the desired area.
Sample thoughts: can translate SVG -> Canvas 60 times per second. It's weird, I guess... can svg->canvas even handle 60fps? Then send each frame to the script for assembling frames in WebM video. And all this at 60 frames per second. I think it might start to slow down. How else?
Environment: Linux.

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Andrew, 2019-12-25
@deepblack

Maybe this will fit?
Converting an SVG animation to a video with the MediaRecorder API and a hidden canvas.
https://gist.github.com/veltman/ff864215009174bc5d...

S
Sergey Sokolov, 2019-12-25
@sergiks

Here's an SVG animation to video option :
use the Media Recorder API and a hidden elementcanvas

index.html
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<svg width="960" height="500"></svg>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.3/d3.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<script>
var svg = d3.select("svg"),
    canvas = document.createElement("canvas"),
    width = canvas.width = +svg.attr("width"),
    height = canvas.height = +svg.attr("height"),
    context = canvas.getContext("2d");

var projection = d3.geoOrthographic()
  .scale(195)
  .translate([width / 2, height / 2])
  .precision(0.1);

var path = d3.geoPath().projection(projection);

d3.json("/mbostock/raw/4090846/world-110m.json", function(err, world) {
  var data = [],
    stream = canvas.captureStream(),
    recorder = new MediaRecorder(stream, { mimeType: "video/webm" });

  recorder.ondataavailable = function(event) {
    if (event.data && event.data.size) {
      data.push(event.data);
    }
  };

  recorder.onstop = () => {
    var url = URL.createObjectURL(new Blob(data, { type: "video/webm" }));
    d3.selectAll("canvas, svg").remove();
    d3.select("body")
      .append("video")
      .attr("src", url)
      .attr("controls", true)
      .attr("autoplay", true);
  };

  var background = svg.append("rect")
    .attr("width", width)
    .attr("height", height)
    .attr("fill", "#fff");

  svg.append("path")
    .datum({ type: "Sphere" })
    .attr("stroke", "#222")
    .attr("fill", "none");

  svg.append("path")
    .datum(topojson.feature(world, world.objects.land))
    .attr("fill", "#222")
    .attr("stroke", "none");

  svg.append("path")
    .datum(topojson.mesh(world, world.objects.countries, function(a, b) {
      return a !== b;
    }))
    .attr("fill", "none")
    .attr("stroke", "#fff");

  var queue = d3.queue(1);

  d3.range(120).forEach(function(frame){
    queue.defer(drawFrame, frame / 120);
  });

  queue.awaitAll(function(err, frames){
    recorder.start();
    drawFrame();

    function drawFrame() {
      if (frames.length) {
        context.drawImage(frames.shift(), 0, 0, width, height);
        requestAnimationFrame(drawFrame);
      } else {
        recorder.stop();
      }
    }
  });

  function drawFrame(t, cb) {
    projection.rotate([360 * t]);
    svg.selectAll("path").attr("d", path);

    var img = new Image(),
        serialized = new XMLSerializer().serializeToString(svg.node()),
        url = URL.createObjectURL(new Blob([serialized], {type: "image/svg+xml"}));

    img.onload = function(){
      cb(null, img);
    };

    img.src = url;

  }
});
</script>

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question