Turn audio into a shareable video. forked from nypublicradio/audiogram

text-wrapper.js 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. var smartquotes = require("smartquotes").string;
  2. module.exports = function(theme) {
  3. // Do some typechecking
  4. var left = ifNumeric(theme.captionLeft, 0),
  5. right = ifNumeric(theme.captionRight, theme.width),
  6. bottom = ifNumeric(theme.captionBottom, null),
  7. top = ifNumeric(theme.captionTop, null),
  8. labelLeft = ifNumeric(theme.labelLeft, 0),
  9. labelRight = ifNumeric(theme.labelRight, theme.width),
  10. labelBottom = ifNumeric(theme.labelBottom, null),
  11. labelTop = ifNumeric(theme.labelTop, null),
  12. renderfunctions ;
  13. if (bottom === null && top === null) {
  14. top = 0;
  15. }
  16. if (labelBottom === null && labelTop === null) {
  17. labelTop = 0;
  18. }
  19. var captionWidth = right - left,
  20. labelWidth = labelRight - labelLeft;
  21. return function(context, caption, type) {
  22. if (!caption) {
  23. return;
  24. }
  25. if (type === 'caption') {
  26. var lines = [[]],
  27. maxWidth = 0,
  28. words = smartquotes(caption + "").trim().replace(/\s\s+/g, " \n").split(/ /g);
  29. context.font = theme.captionFont;
  30. context.textBaseline = "top";
  31. context.textAlign = theme.captionAlign || "center";
  32. // Check whether each word exceeds the width limit
  33. // Wrap onto next line as needed
  34. words.forEach(function(word,i){
  35. var width = context.measureText(lines[lines.length - 1].concat([word]).join(" ")).width;
  36. if (word[0] === "\n" || (lines[lines.length - 1].length && width > captionWidth)) {
  37. word = word.trim();
  38. lines.push([word]);
  39. width = context.measureText(word).width;
  40. } else {
  41. lines[lines.length - 1].push(word);
  42. }
  43. maxWidth = Math.max(maxWidth,width);
  44. });
  45. var totalHeight = lines.length * theme.captionLineHeight + (lines.length - 1) * theme.captionLineSpacing;
  46. // horizontal alignment
  47. var x = theme.captionAlign === "left" ? left : theme.captionAlign === "right" ? right : (left + right) / 2;
  48. // Vertical alignment
  49. var y;
  50. if (top !== null && bottom !== null) {
  51. // Vertical center
  52. y = (bottom + top - totalHeight) / 2;
  53. } else if (bottom !== null) {
  54. // Vertical align bottom
  55. y = bottom - totalHeight;
  56. } else {
  57. // Vertical align top
  58. y = top;
  59. }
  60. // draw caption
  61. context.fillStyle = theme.captionColor;
  62. lines.forEach(function(line, i){
  63. // negative indentation for opening quotes
  64. var indented_x = (x + 28);
  65. if (i === 0 && /^“/.test(line[0])) {
  66. context.fillText(line.join(" "), x, y + i * (theme.captionLineHeight + theme.captionLineSpacing));
  67. }
  68. else {
  69. context.fillText(line.join(" "), indented_x, y + i * (theme.captionLineHeight + theme.captionLineSpacing));
  70. }
  71. });
  72. } // end if caption
  73. if (type === 'label' && caption != 'None') {
  74. var lines = [[]],
  75. maxWidth = 0,
  76. words = smartquotes(caption + "").trim().replace(/\s\s+/g, " \n").split(/ /g);
  77. context.font = theme.labelFont;
  78. context.textBaseline = "top";
  79. context.textAlign = theme.labelAlign || "center";
  80. // Check whether each word exceeds the width limit
  81. // Wrap onto next line as needed
  82. words.forEach(function(word,i){
  83. var width = context.measureText(lines[lines.length - 1].concat([word]).join(" ")).width;
  84. if (word[0] === "\n" || (lines[lines.length - 1].length && width > labelWidth)) {
  85. word = word.trim();
  86. lines.push([word]);
  87. width = context.measureText(word).width;
  88. } else {
  89. lines[lines.length - 1].push(word);
  90. }
  91. maxWidth = Math.max(maxWidth,width);
  92. });
  93. var totalHeight = lines.length * theme.labelLineHeight + (lines.length - 1) * theme.labelLineSpacing;
  94. // horizontal alignment
  95. var x = theme.labelAlign === "left" ? labelLeft : theme.labelAlign === "right" ? labelRight : (labelLeft + labelRight) / 2;
  96. // Vertical alignment
  97. var y;
  98. if (labelTop !== null && labelBottom !== null) {
  99. // Vertical center
  100. y = (labelBottom + labelTop - totalHeight) / 2;
  101. } else if (labelBottom !== null) {
  102. // Vertical align bottom
  103. y = labelBottom - totalHeight;
  104. } else {
  105. // Vertical align top
  106. y = labelTop;
  107. }
  108. // draw label
  109. context.fillStyle = theme.labelColor;
  110. lines.forEach(function(line, i){
  111. context.fillText(line.join(" "), x, y + i * (theme.labelLineHeight + theme.labelLineSpacing));
  112. });
  113. }
  114. };
  115. }
  116. function ifNumeric(val, alt) {
  117. return (typeof val === "number" && !isNaN(val)) ? val : alt;
  118. }