wx-canvas.js 11 KB

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