vap-frame-parser.ts 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /*
  2. * Tencent is pleased to support the open source community by making vap available.
  3. *
  4. * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
  5. *
  6. * Licensed under the MIT License (the "License"); you may not use this file except in
  7. * compliance with the License. You may obtain a copy of the License at
  8. *
  9. * http://opensource.org/licenses/MIT
  10. *
  11. * Unless required by applicable law or agreed to in writing, software distributed under the License is
  12. * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  13. * either express or implied. See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. export default class FrameParser {
  17. constructor(source, headData) {
  18. this.config = source || {};
  19. this.headData = headData;
  20. this.frame = [];
  21. this.textureMap = {}
  22. }
  23. private config;
  24. private headData;
  25. private frame;
  26. private textureMap;
  27. private canvas:HTMLCanvasElement;
  28. private ctx:CanvasRenderingContext2D | null;
  29. private srcData;
  30. async init() {
  31. this.initCanvas();
  32. // 判断是url还是json对象
  33. if(/\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]\.json$/.test(this.config)){
  34. this.config = await this.getConfigBySrc(this.config);
  35. }
  36. await this.parseSrc(this.config);
  37. this.canvas.parentNode.removeChild(this.canvas);
  38. this.frame = this.config.frame || [];
  39. return this;
  40. }
  41. initCanvas() {
  42. const canvas = document.createElement('canvas');
  43. const ctx = canvas.getContext('2d');
  44. canvas.style.display = 'none';
  45. document.body.appendChild(canvas);
  46. this.ctx = ctx;
  47. this.canvas = canvas;
  48. }
  49. loadImg(url:string) {
  50. return new Promise((resolve, reject) => {
  51. // console.log('load img:', url)
  52. const img = new Image();
  53. img.crossOrigin = 'anonymous';
  54. img.onload = function() {
  55. resolve(this);
  56. };
  57. img.onerror = function(e) {
  58. console.error('frame 资源加载失败:' + url);
  59. reject(new Error('frame 资源加载失败:' + url));
  60. };
  61. img.src = url;
  62. })
  63. }
  64. parseSrc(dataJson) {
  65. const src = (this.srcData = {});
  66. return Promise.all(
  67. (dataJson.src || []).map(async item => {
  68. item.img = null;
  69. if (!this.headData[item.srcTag.slice(1, item.srcTag.length - 1)]) {
  70. console.warn(`vap: 融合信息没有传入:${item.srcTag}`);
  71. } else {
  72. if (item.srcType === 'txt') {
  73. item.textStr = item.srcTag.replace(/\[(.*)\]/, ($0, $1) => {
  74. return this.headData[$1];
  75. });
  76. item.img = this.makeTextImg(item);
  77. } else if (item.srcType === 'img') {
  78. item.imgUrl = item.srcTag.replace(/\[(.*)\]/, ($0, $1) => {
  79. return this.headData[$1]
  80. });
  81. try {
  82. item.img = await this.loadImg(item.imgUrl + '?t=' + Date.now());
  83. } catch (e) {}
  84. }
  85. if (item.img) {
  86. src[item.srcId] = item;
  87. }
  88. }
  89. })
  90. )
  91. }
  92. /**
  93. * 下载json文件
  94. * @param jsonUrl json外链
  95. * @returns {Promise}
  96. */
  97. getConfigBySrc(jsonUrl:string) {
  98. return new Promise((resolve, reject) => {
  99. const xhr = new XMLHttpRequest();
  100. xhr.open("GET", jsonUrl, true);
  101. xhr.responseType = "json";
  102. xhr.onload = function() {
  103. if (xhr.status === 200 || xhr.status === 304 && xhr.response) {
  104. const res = xhr.response;
  105. resolve(res);
  106. } else {
  107. reject(new Error("http response invalid" + xhr.status));
  108. }
  109. };
  110. xhr.send();
  111. });
  112. }
  113. /**
  114. * 文字转换图片
  115. * @param {*} param0
  116. */
  117. makeTextImg({ textStr, w, h, color, style }) {
  118. const ctx = this.ctx;
  119. ctx.canvas.width = w;
  120. ctx.canvas.height = h;
  121. const fontSize = Math.min(w / textStr.length, h - 8); // 需留一定间隙
  122. const font = [`${fontSize}px`, 'Arial'];
  123. if (style === 'b') {
  124. font.unshift('bold');
  125. }
  126. ctx.font = font.join(' ');
  127. ctx.textBaseline = 'middle';
  128. ctx.textAlign = 'center';
  129. ctx.fillStyle = color;
  130. ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  131. ctx.fillText(textStr, w / 2, h / 2);
  132. // console.log('frame : ' + textStr, ctx.canvas.toDataURL('image/png'))
  133. return ctx.getImageData(0, 0, w, h);
  134. }
  135. getFrame(frame) {
  136. return this.frame.find(item => {
  137. return item.i === frame;
  138. })
  139. }
  140. }