wx-canvas.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. // @ts-check
  2. export default class WxCanvas {
  3. ctx;
  4. type;
  5. canvasId;
  6. canvasNode;
  7. stepList = [];
  8. canvasPrototype = {};
  9. constructor(type, ctx, canvasId, isNew, canvasNode) {
  10. this.ctx = ctx;
  11. this.canvasId = canvasId;
  12. this.type = type;
  13. if (isNew) {
  14. this.canvasNode = canvasNode || {};
  15. }
  16. }
  17. set width(w) {
  18. if (this.canvasNode) {
  19. this.canvasNode.width = w;
  20. // 经测试,在 2d 接口中如果不设置这个值,IOS 端有一定几率会出现图片显示不全的情况。
  21. this.canvasNode._width = w;
  22. }
  23. }
  24. get width() {
  25. if (this.canvasNode) return this.canvasNode.width;
  26. return 0;
  27. }
  28. set height(h) {
  29. if (this.canvasNode) {
  30. this.canvasNode.height = h;
  31. // 经测试,在 2d 接口中如果不设置这个值,IOS 端有一定几率会出现图片显示不全的情况。
  32. this.canvasNode._height = h;
  33. }
  34. }
  35. get height() {
  36. if (this.canvasNode) return this.canvasNode.height;
  37. return 0;
  38. }
  39. set lineWidth(args) {
  40. this.canvasPrototype.lineWidth = args;
  41. this.stepList.push({
  42. action: "lineWidth",
  43. args,
  44. actionType: "set",
  45. });
  46. }
  47. get lineWidth() {
  48. return this.canvasPrototype.lineWidth;
  49. }
  50. set lineCap(args) {
  51. this.canvasPrototype.lineCap = args;
  52. this.stepList.push({
  53. action: "lineCap",
  54. args,
  55. actionType: "set",
  56. });
  57. }
  58. get lineCap() {
  59. return this.canvasPrototype.lineCap;
  60. }
  61. set lineJoin(args) {
  62. this.canvasPrototype.lineJoin = args;
  63. this.stepList.push({
  64. action: "lineJoin",
  65. args,
  66. actionType: "set",
  67. });
  68. }
  69. get lineJoin() {
  70. return this.canvasPrototype.lineJoin;
  71. }
  72. set miterLimit(args) {
  73. this.canvasPrototype.miterLimit = args;
  74. this.stepList.push({
  75. action: "miterLimit",
  76. args,
  77. actionType: "set",
  78. });
  79. }
  80. get miterLimit() {
  81. return this.canvasPrototype.miterLimit;
  82. }
  83. set lineDashOffset(args) {
  84. this.canvasPrototype.lineDashOffset = args;
  85. this.stepList.push({
  86. action: "lineDashOffset",
  87. args,
  88. actionType: "set",
  89. });
  90. }
  91. get lineDashOffset() {
  92. return this.canvasPrototype.lineDashOffset;
  93. }
  94. set font(args) {
  95. this.canvasPrototype.font = args;
  96. this.ctx.font = args;
  97. this.stepList.push({
  98. action: "font",
  99. args,
  100. actionType: "set",
  101. });
  102. }
  103. get font() {
  104. return this.canvasPrototype.font;
  105. }
  106. set textAlign(args) {
  107. this.canvasPrototype.textAlign = args;
  108. this.stepList.push({
  109. action: "textAlign",
  110. args,
  111. actionType: "set",
  112. });
  113. }
  114. get textAlign() {
  115. return this.canvasPrototype.textAlign;
  116. }
  117. set textBaseline(args) {
  118. this.canvasPrototype.textBaseline = args;
  119. this.stepList.push({
  120. action: "textBaseline",
  121. args,
  122. actionType: "set",
  123. });
  124. }
  125. get textBaseline() {
  126. return this.canvasPrototype.textBaseline;
  127. }
  128. set fillStyle(args) {
  129. this.canvasPrototype.fillStyle = args;
  130. this.stepList.push({
  131. action: "fillStyle",
  132. args,
  133. actionType: "set",
  134. });
  135. }
  136. get fillStyle() {
  137. return this.canvasPrototype.fillStyle;
  138. }
  139. set strokeStyle(args) {
  140. this.canvasPrototype.strokeStyle = args;
  141. this.stepList.push({
  142. action: "strokeStyle",
  143. args,
  144. actionType: "set",
  145. });
  146. }
  147. get strokeStyle() {
  148. return this.canvasPrototype.strokeStyle;
  149. }
  150. set globalAlpha(args) {
  151. this.canvasPrototype.globalAlpha = args;
  152. this.stepList.push({
  153. action: "globalAlpha",
  154. args,
  155. actionType: "set",
  156. });
  157. }
  158. get globalAlpha() {
  159. return this.canvasPrototype.globalAlpha;
  160. }
  161. set globalCompositeOperation(args) {
  162. this.canvasPrototype.globalCompositeOperation = args;
  163. this.stepList.push({
  164. action: "globalCompositeOperation",
  165. args,
  166. actionType: "set",
  167. });
  168. }
  169. get globalCompositeOperation() {
  170. return this.canvasPrototype.globalCompositeOperation;
  171. }
  172. set shadowColor(args) {
  173. this.canvasPrototype.shadowColor = args;
  174. this.stepList.push({
  175. action: "shadowColor",
  176. args,
  177. actionType: "set",
  178. });
  179. }
  180. get shadowColor() {
  181. return this.canvasPrototype.shadowColor;
  182. }
  183. set shadowOffsetX(args) {
  184. this.canvasPrototype.shadowOffsetX = args;
  185. this.stepList.push({
  186. action: "shadowOffsetX",
  187. args,
  188. actionType: "set",
  189. });
  190. }
  191. get shadowOffsetX() {
  192. return this.canvasPrototype.shadowOffsetX;
  193. }
  194. set shadowOffsetY(args) {
  195. this.canvasPrototype.shadowOffsetY = args;
  196. this.stepList.push({
  197. action: "shadowOffsetY",
  198. args,
  199. actionType: "set",
  200. });
  201. }
  202. get shadowOffsetY() {
  203. return this.canvasPrototype.shadowOffsetY;
  204. }
  205. set shadowBlur(args) {
  206. this.canvasPrototype.shadowBlur = args;
  207. this.stepList.push({
  208. action: "shadowBlur",
  209. args,
  210. actionType: "set",
  211. });
  212. }
  213. get shadowBlur() {
  214. return this.canvasPrototype.shadowBlur;
  215. }
  216. save() {
  217. this.stepList.push({
  218. action: "save",
  219. args: null,
  220. actionType: "func",
  221. });
  222. }
  223. restore() {
  224. this.stepList.push({
  225. action: "restore",
  226. args: null,
  227. actionType: "func",
  228. });
  229. }
  230. setLineDash(...args) {
  231. this.canvasPrototype.lineDash = args;
  232. this.stepList.push({
  233. action: "setLineDash",
  234. args,
  235. actionType: "func",
  236. });
  237. }
  238. moveTo(...args) {
  239. this.stepList.push({
  240. action: "moveTo",
  241. args,
  242. actionType: "func",
  243. });
  244. }
  245. closePath() {
  246. this.stepList.push({
  247. action: "closePath",
  248. args: null,
  249. actionType: "func",
  250. });
  251. }
  252. lineTo(...args) {
  253. this.stepList.push({
  254. action: "lineTo",
  255. args,
  256. actionType: "func",
  257. });
  258. }
  259. quadraticCurveTo(...args) {
  260. this.stepList.push({
  261. action: "quadraticCurveTo",
  262. args,
  263. actionType: "func",
  264. });
  265. }
  266. bezierCurveTo(...args) {
  267. this.stepList.push({
  268. action: "bezierCurveTo",
  269. args,
  270. actionType: "func",
  271. });
  272. }
  273. arcTo(...args) {
  274. this.stepList.push({
  275. action: "arcTo",
  276. args,
  277. actionType: "func",
  278. });
  279. }
  280. arc(...args) {
  281. this.stepList.push({
  282. action: "arc",
  283. args,
  284. actionType: "func",
  285. });
  286. }
  287. rect(...args) {
  288. this.stepList.push({
  289. action: "rect",
  290. args,
  291. actionType: "func",
  292. });
  293. }
  294. scale(...args) {
  295. this.stepList.push({
  296. action: "scale",
  297. args,
  298. actionType: "func",
  299. });
  300. }
  301. rotate(...args) {
  302. this.stepList.push({
  303. action: "rotate",
  304. args,
  305. actionType: "func",
  306. });
  307. }
  308. translate(...args) {
  309. this.stepList.push({
  310. action: "translate",
  311. args,
  312. actionType: "func",
  313. });
  314. }
  315. transform(...args) {
  316. this.stepList.push({
  317. action: "transform",
  318. args,
  319. actionType: "func",
  320. });
  321. }
  322. setTransform(...args) {
  323. this.stepList.push({
  324. action: "setTransform",
  325. args,
  326. actionType: "func",
  327. });
  328. }
  329. clearRect(...args) {
  330. this.stepList.push({
  331. action: "clearRect",
  332. args,
  333. actionType: "func",
  334. });
  335. }
  336. fillRect(...args) {
  337. this.stepList.push({
  338. action: "fillRect",
  339. args,
  340. actionType: "func",
  341. });
  342. }
  343. strokeRect(...args) {
  344. this.stepList.push({
  345. action: "strokeRect",
  346. args,
  347. actionType: "func",
  348. });
  349. }
  350. fillText(...args) {
  351. this.stepList.push({
  352. action: "fillText",
  353. args,
  354. actionType: "func",
  355. });
  356. }
  357. strokeText(...args) {
  358. this.stepList.push({
  359. action: "strokeText",
  360. args,
  361. actionType: "func",
  362. });
  363. }
  364. beginPath() {
  365. this.stepList.push({
  366. action: "beginPath",
  367. args: null,
  368. actionType: "func",
  369. });
  370. }
  371. fill() {
  372. this.stepList.push({
  373. action: "fill",
  374. args: null,
  375. actionType: "func",
  376. });
  377. }
  378. stroke() {
  379. this.stepList.push({
  380. action: "stroke",
  381. args: null,
  382. actionType: "func",
  383. });
  384. }
  385. drawFocusIfNeeded(...args) {
  386. this.stepList.push({
  387. action: "drawFocusIfNeeded",
  388. args,
  389. actionType: "func",
  390. });
  391. }
  392. clip() {
  393. this.stepList.push({
  394. action: "clip",
  395. args: null,
  396. actionType: "func",
  397. });
  398. }
  399. isPointInPath(...args) {
  400. this.stepList.push({
  401. action: "isPointInPath",
  402. args,
  403. actionType: "func",
  404. });
  405. }
  406. drawImage(...args) {
  407. this.stepList.push({
  408. action: "drawImage",
  409. args,
  410. actionType: "func",
  411. });
  412. }
  413. addHitRegion(...args) {
  414. this.stepList.push({
  415. action: "addHitRegion",
  416. args,
  417. actionType: "func",
  418. });
  419. }
  420. removeHitRegion(...args) {
  421. this.stepList.push({
  422. action: "removeHitRegion",
  423. args,
  424. actionType: "func",
  425. });
  426. }
  427. clearHitRegions(...args) {
  428. this.stepList.push({
  429. action: "clearHitRegions",
  430. args,
  431. actionType: "func",
  432. });
  433. }
  434. putImageData(...args) {
  435. this.stepList.push({
  436. action: "putImageData",
  437. args,
  438. actionType: "func",
  439. });
  440. }
  441. getLineDash() {
  442. return this.canvasPrototype.lineDash;
  443. }
  444. createLinearGradient(...args) {
  445. return this.ctx.createLinearGradient(...args);
  446. }
  447. createRadialGradient(...args) {
  448. if (this.type === "2d") {
  449. return this.ctx.createRadialGradient(...args);
  450. } else {
  451. return this.ctx.createCircularGradient(...args.slice(3, 6));
  452. }
  453. }
  454. createPattern(...args) {
  455. return this.ctx.createPattern(...args);
  456. }
  457. measureText(...args) {
  458. return this.ctx.measureText(...args);
  459. }
  460. createImageData(...args) {
  461. return this.ctx.createImageData(...args);
  462. }
  463. getImageData(...args) {
  464. return this.ctx.getImageData(...args);
  465. }
  466. async draw(reserve, func) {
  467. const realstepList = this.stepList.slice();
  468. this.stepList.length = 0;
  469. if (this.type === "mina") {
  470. if (realstepList.length > 0) {
  471. for (const step of realstepList) {
  472. this.implementMinaStep(step);
  473. }
  474. realstepList.length = 0;
  475. }
  476. this.ctx.draw(reserve, func);
  477. } else if (this.type === "2d") {
  478. if (!reserve) {
  479. this.ctx.clearRect(0, 0, this.canvasNode.width, this.canvasNode.height);
  480. }
  481. if (realstepList.length > 0) {
  482. for (const step of realstepList) {
  483. await this.implement2DStep(step);
  484. }
  485. realstepList.length = 0;
  486. }
  487. if (func) {
  488. func();
  489. }
  490. }
  491. realstepList.length = 0;
  492. }
  493. implementMinaStep(step) {
  494. switch (step.action) {
  495. case "textAlign": {
  496. this.ctx.setTextAlign(step.args);
  497. break;
  498. }
  499. case "textBaseline": {
  500. this.ctx.setTextBaseline(step.args);
  501. break;
  502. }
  503. default: {
  504. if (step.actionType === "set") {
  505. this.ctx[step.action] = step.args;
  506. } else if (step.actionType === "func") {
  507. if (step.args) {
  508. this.ctx[step.action](...step.args);
  509. } else {
  510. this.ctx[step.action]();
  511. }
  512. }
  513. break;
  514. }
  515. }
  516. }
  517. implement2DStep(step) {
  518. return new Promise((resolve) => {
  519. if (step.action === "drawImage") {
  520. const img = this.canvasNode.createImage();
  521. img.src = step.args[0];
  522. img.onload = () => {
  523. this.ctx.drawImage(img, ...step.args.slice(1));
  524. resolve();
  525. };
  526. } else {
  527. if (step.actionType === "set") {
  528. this.ctx[step.action] = step.args;
  529. } else if (step.actionType === "func") {
  530. if (step.args) {
  531. this.ctx[step.action](...step.args);
  532. } else {
  533. this.ctx[step.action]();
  534. }
  535. }
  536. resolve();
  537. }
  538. });
  539. }
  540. }