浏览代码

Refactoring wave/caption

Noah 7 年前
父节点
当前提交
32095455d5
共有 7 个文件被更改,包括 85 次插入68 次删除
  1. 11 5
      audiogram/draw-frames.js
  2. 4 0
      audiogram/index.js
  3. 6 12
      audiogram/initialize-canvas.js
  4. 11 6
      client/preview.js
  5. 0 0
      client/sample-wave.js
  6. 39 31
      renderer/index.js
  7. 14 14
      renderer/text-wrapper.js

+ 11 - 5
audiogram/draw-frames.js 查看文件

1
 var fs = require("fs"),
1
 var fs = require("fs"),
2
     path = require("path"),
2
     path = require("path"),
3
+    Canvas = require("canvas"),
3
     queue = require("d3").queue;
4
     queue = require("d3").queue;
4
 
5
 
5
 function drawFrames(renderer, options, cb) {
6
 function drawFrames(renderer, options, cb) {
6
 
7
 
7
-  var frameQueue = queue(10);
8
+  var frameQueue = queue(10),
9
+      canvas = new Canvas(options.width, options.height),
10
+      context = canvas.getContext("2d");
8
 
11
 
9
   for (var i = 0; i < options.numFrames; i++) {
12
   for (var i = 0; i < options.numFrames; i++) {
10
-
11
     frameQueue.defer(drawFrame, i);
13
     frameQueue.defer(drawFrame, i);
12
-
13
   }
14
   }
14
 
15
 
15
   frameQueue.awaitAll(cb);
16
   frameQueue.awaitAll(cb);
16
 
17
 
17
   function drawFrame(frameNumber, frameCallback) {
18
   function drawFrame(frameNumber, frameCallback) {
18
 
19
 
19
-    renderer.drawFrame(frameNumber);
20
-    fs.writeFile(path.join(options.frameDir, zeropad(frameNumber + 1, 6) + ".png"), renderer.context.canvas.toBuffer(), function(err) {
20
+    renderer.drawFrame(context, {
21
+      caption: options.caption,
22
+      waveform: options.waveform[frameNumber],
23
+      frame: frameNumber
24
+    });
25
+
26
+    fs.writeFile(path.join(options.frameDir, zeropad(frameNumber + 1, 6) + ".png"), canvas.toBuffer(), function(err) {
21
       if (err) {
27
       if (err) {
22
         return frameCallback(err);
28
         return frameCallback(err);
23
       }
29
       }

+ 4 - 0
audiogram/index.js 查看文件

115
     self.status("frames");
115
     self.status("frames");
116
 
116
 
117
     drawFrames(renderer, {
117
     drawFrames(renderer, {
118
+      width: self.settings.width,
119
+      height: self.settings.height,
118
       numFrames: self.numFrames,
120
       numFrames: self.numFrames,
119
       frameDir: self.frameDir,
121
       frameDir: self.frameDir,
122
+      caption: self.settings.caption,
123
+      waveform: self.settings.waveform,
120
       tick: function() {
124
       tick: function() {
121
         transports.incrementField(self.id, "framesComplete");
125
         transports.incrementField(self.id, "framesComplete");
122
       }
126
       }

+ 6 - 12
audiogram/initialize-canvas.js 查看文件

1
 var fs = require("fs"),
1
 var fs = require("fs"),
2
     path = require("path"),
2
     path = require("path"),
3
     Canvas = require("canvas"),
3
     Canvas = require("canvas"),
4
-    getRenderer = require("../renderer/"),
5
-    serverSettings = require("../settings/");
4
+    getRenderer = require("../renderer/");
6
 
5
 
7
-function initializeCanvas(options, cb) {
6
+function initializeCanvas(theme, cb) {
8
 
7
 
9
   // Fonts pre-registered in bin/worker
8
   // Fonts pre-registered in bin/worker
9
+  var renderer = getRenderer(theme);
10
 
10
 
11
-  var canvas = new Canvas(options.width, options.height),
12
-      context = canvas.getContext("2d"),
13
-      renderer = getRenderer(context).update(options);
14
-
15
-  renderer.caption = options.caption;
16
-
17
-  if (!options.backgroundImage) {
11
+  if (!theme.backgroundImage) {
18
     return cb(null, renderer);
12
     return cb(null, renderer);
19
   }
13
   }
20
 
14
 
21
   // Load background image from file (done separately so renderer code can work in browser too)
15
   // Load background image from file (done separately so renderer code can work in browser too)
22
-  fs.readFile(path.join(__dirname, "..", "settings", "backgrounds", options.backgroundImage), function(err, raw){
16
+  fs.readFile(path.join(__dirname, "..", "settings", "backgrounds", theme.backgroundImage), function(err, raw){
23
 
17
 
24
     if (err) {
18
     if (err) {
25
       return cb(err);
19
       return cb(err);
27
 
21
 
28
     var bg = new Canvas.Image;
22
     var bg = new Canvas.Image;
29
     bg.src = raw;
23
     bg.src = raw;
30
-    renderer.backgroundImage = bg;
24
+    renderer.backgroundImage(bg);
31
 
25
 
32
     return cb(null, renderer);
26
     return cb(null, renderer);
33
 
27
 

+ 11 - 6
client/preview.js 查看文件

2
     audio = require("./audio.js"),
2
     audio = require("./audio.js"),
3
     video = require("./video.js"),
3
     video = require("./video.js"),
4
     minimap = require("./minimap.js"),
4
     minimap = require("./minimap.js"),
5
+    sampleWave = require("./sample-wave.js"),
6
+    getRenderer = require("../renderer/"),
5
     getWaveform = require("./waveform.js");
7
     getWaveform = require("./waveform.js");
6
 
8
 
7
 var context = d3.select("canvas").node().getContext("2d");
9
 var context = d3.select("canvas").node().getContext("2d");
8
 
10
 
9
-var renderer = require("../renderer/")(context);
10
-
11
 var theme,
11
 var theme,
12
     caption,
12
     caption,
13
     file,
13
     file,
74
 
74
 
75
   video.kill();
75
   video.kill();
76
 
76
 
77
-  renderer.update(theme);
78
-  renderer.caption = caption;
79
-  renderer.backgroundImage = theme.backgroundImageFile || null;
80
-  renderer.drawFrame(0);
77
+  var renderer = getRenderer(theme);
78
+
79
+  renderer.backgroundImage(theme.backgroundImageFile || null);
80
+
81
+  renderer.drawFrame(context, {
82
+    caption: caption,
83
+    waveform: sampleWave,
84
+    frame: 0
85
+  });
81
 
86
 
82
 }
87
 }
83
 
88
 

renderer/sample-wave.js → client/sample-wave.js 查看文件


+ 39 - 31
renderer/index.js 查看文件

1
 var d3 = require("d3"),
1
 var d3 = require("d3"),
2
     patterns = require("./patterns.js"),
2
     patterns = require("./patterns.js"),
3
-    sample = require("./sample-wave.js"),
4
     textWrapper = require("./text-wrapper.js");
3
     textWrapper = require("./text-wrapper.js");
5
 
4
 
6
-module.exports = function(context) {
5
+module.exports = function(t) {
7
 
6
 
8
-  context.patternQuality = "best";
7
+  var renderer = {},
8
+      backgroundImage,
9
+      wrapText,
10
+      theme;
9
 
11
 
10
-  var renderer = {};
12
+  renderer.backgroundImage = function(_) {
13
+    if (!arguments.length) return backgroundImage;
14
+    backgroundImage = _;
15
+    return this;
16
+  };
11
 
17
 
12
-  renderer.context = context;
18
+  renderer.theme = function(_) {
19
+    if (!arguments.length) return theme;
13
 
20
 
14
-  renderer.update = function(options) {
21
+    theme = _;
15
 
22
 
16
-    // TODO cleaner defaults
17
-    options.backgroundColor = options.backgroundColor || "#fff";
18
-    options.waveColor = options.waveColor || options.foregroundColor || "#000";
19
-    options.captionColor = options.captionColor || options.foregroundColor || "#000";
23
+    // Default colors
24
+    theme.backgroundColor = theme.backgroundColor || "#fff";
25
+    theme.waveColor = theme.waveColor || theme.foregroundColor || "#000";
26
+    theme.captionColor = theme.captionColor || theme.foregroundColor || "#000";
20
 
27
 
21
-    if (typeof options.waveTop !== "number") options.waveTop = 0;
22
-    if (typeof options.waveBottom !== "number") options.waveBottom = options.height;
23
-    if (typeof options.waveLeft !== "number") options.waveLeft = 0;
24
-    if (typeof options.waveRight !== "number") options.waveRight = options.width;
28
+    // Default wave dimensions
29
+    if (typeof theme.waveTop !== "number") theme.waveTop = 0;
30
+    if (typeof theme.waveBottom !== "number") theme.waveBottom = theme.height;
31
+    if (typeof theme.waveLeft !== "number") theme.waveLeft = 0;
32
+    if (typeof theme.waveRight !== "number") theme.waveRight = theme.width;
25
 
33
 
26
-    this.wrapText = textWrapper(context, options);
27
-    this.options = options;
28
-    this.waveform = options.waveform || [sample.slice(0, options.samplesPerFrame)];
29
-    return this;
30
-  };
34
+    wrapText = textWrapper(theme);
31
 
35
 
32
-  // Get the waveform data for this frame
33
-  renderer.getWaveform = function(frameNumber) {
34
-    return this.waveform[Math.min(this.waveform.length - 1, frameNumber)];
36
+    return this;
35
   };
37
   };
36
 
38
 
37
   // Draw the frame
39
   // Draw the frame
38
-  renderer.drawFrame = function(frameNumber) {
40
+  renderer.drawFrame = function(context, options){
41
+
42
+    context.patternQuality = "best";
39
 
43
 
40
     // Draw the background image and/or background color
44
     // Draw the background image and/or background color
41
-    context.clearRect(0, 0, this.options.width, this.options.height);
45
+    context.clearRect(0, 0, theme.width, theme.height);
42
 
46
 
43
-    context.fillStyle = this.options.backgroundColor;
44
-    context.fillRect(0, 0, this.options.width, this.options.height);
47
+    context.fillStyle = theme.backgroundColor;
48
+    context.fillRect(0, 0, theme.width, theme.height);
45
 
49
 
46
-    if (this.backgroundImage) {
47
-      context.drawImage(this.backgroundImage, 0, 0, this.options.width, this.options.height);
50
+    if (backgroundImage) {
51
+      context.drawImage(backgroundImage, 0, 0, theme.width, theme.height);
48
     }
52
     }
49
 
53
 
50
-    patterns[this.options.pattern || "wave"](context, this.getWaveform(frameNumber), this.options);
54
+    patterns[theme.pattern || "wave"](context, options.waveform, theme);
51
 
55
 
52
     // Write the caption
56
     // Write the caption
53
-    if (this.caption) {
54
-      this.wrapText(this.caption);
57
+    if (options.caption) {
58
+      wrapText(context, options.caption);
55
     }
59
     }
56
 
60
 
57
     return this;
61
     return this;
58
 
62
 
59
   };
63
   };
60
 
64
 
65
+  if (t) {
66
+    renderer.theme(t);
67
+  }
68
+
61
   return renderer;
69
   return renderer;
62
 
70
 
63
 }
71
 }

+ 14 - 14
renderer/text-wrapper.js 查看文件

1
 var smartquotes = require("smartquotes").string;
1
 var smartquotes = require("smartquotes").string;
2
 
2
 
3
-module.exports = function(context, options) {
4
-
5
-  context.font = options.captionFont;
6
-  context.textBaseline = "top";
7
-  context.textAlign = options.captionAlign || "center";
3
+module.exports = function(theme) {
8
 
4
 
9
   // Do some typechecking
5
   // Do some typechecking
10
-  var left = ifNumeric(options.captionLeft, 0),
11
-      right = ifNumeric(options.captionRight, options.width),
12
-      bottom = ifNumeric(options.captionBottom, null),
13
-      top = ifNumeric(options.captionTop, null);
6
+  var left = ifNumeric(theme.captionLeft, 0),
7
+      right = ifNumeric(theme.captionRight, theme.width),
8
+      bottom = ifNumeric(theme.captionBottom, null),
9
+      top = ifNumeric(theme.captionTop, null);
14
 
10
 
15
   if (bottom === null && top === null) {
11
   if (bottom === null && top === null) {
16
     top = 0;
12
     top = 0;
18
 
14
 
19
   var captionWidth = right - left;
15
   var captionWidth = right - left;
20
 
16
 
21
-  return function(caption) {
17
+  return function(context, caption) {
22
 
18
 
23
     if (!caption) {
19
     if (!caption) {
24
       return;
20
       return;
28
         maxWidth = 0,
24
         maxWidth = 0,
29
         words = smartquotes(caption + "").trim().replace(/\s\s+/g, " \n").split(/ /g);
25
         words = smartquotes(caption + "").trim().replace(/\s\s+/g, " \n").split(/ /g);
30
 
26
 
27
+    context.font = theme.captionFont;
28
+    context.textBaseline = "top";
29
+    context.textAlign = theme.captionAlign || "center";
30
+
31
     // Check whether each word exceeds the width limit
31
     // Check whether each word exceeds the width limit
32
     // Wrap onto next line as needed
32
     // Wrap onto next line as needed
33
     words.forEach(function(word,i){
33
     words.forEach(function(word,i){
50
 
50
 
51
     });
51
     });
52
 
52
 
53
-    var totalHeight = lines.length * options.captionLineHeight + (lines.length - 1) * options.captionLineSpacing;
53
+    var totalHeight = lines.length * theme.captionLineHeight + (lines.length - 1) * theme.captionLineSpacing;
54
 
54
 
55
     // horizontal alignment
55
     // horizontal alignment
56
-    var x = options.captionAlign === "left" ? left : options.captionAlign === "right" ? right : (left + right) / 2;
56
+    var x = theme.captionAlign === "left" ? left : theme.captionAlign === "right" ? right : (left + right) / 2;
57
 
57
 
58
     // Vertical alignment
58
     // Vertical alignment
59
     var y;
59
     var y;
69
       y = top;
69
       y = top;
70
     }
70
     }
71
 
71
 
72
-    context.fillStyle = options.captionColor;
72
+    context.fillStyle = theme.captionColor;
73
     lines.forEach(function(line, i){
73
     lines.forEach(function(line, i){
74
-      context.fillText(line.join(" "), x, y + i * (options.captionLineHeight + options.captionLineSpacing));
74
+      context.fillText(line.join(" "), x, y + i * (theme.captionLineHeight + theme.captionLineSpacing));
75
     });
75
     });
76
 
76
 
77
  };
77
  };