Source: core/renderers/canvas/CanvasRenderer.js

core/renderers/canvas/CanvasRenderer.js

  1. import SystemRenderer from '../SystemRenderer';
  2. import CanvasMaskManager from './utils/CanvasMaskManager';
  3. import CanvasRenderTarget from './utils/CanvasRenderTarget';
  4. import mapCanvasBlendModesToPixi from './utils/mapCanvasBlendModesToPixi';
  5. import { pluginTarget } from '../../utils';
  6. import { RENDERER_TYPE, SCALE_MODES, BLEND_MODES } from '../../const';
  7. import settings from '../../settings';
  8. //引入小程序补丁
  9. import { navigator } from '@ali/pixi-miniprogram-adapter';
  10. /**
  11. * The CanvasRenderer draws the scene and all its content onto a 2d canvas. This renderer should
  12. * be used for browsers that do not support WebGL. Don't forget to add the CanvasRenderer.view to
  13. * your DOM or you will not see anything :)
  14. *
  15. * @class
  16. * @memberof PIXI
  17. * @extends PIXI.SystemRenderer
  18. */
  19. export default class CanvasRenderer extends SystemRenderer
  20. {
  21. // eslint-disable-next-line valid-jsdoc
  22. /**
  23. * @param {object} [options] - The optional renderer parameters
  24. * @param {number} [options.width=800] - the width of the screen
  25. * @param {number} [options.height=600] - the height of the screen
  26. * @param {HTMLCanvasElement} [options.view] - the canvas to use as a view, optional
  27. * @param {boolean} [options.transparent=false] - If the render view is transparent, default false
  28. * @param {boolean} [options.autoResize=false] - If the render view is automatically resized, default false
  29. * @param {boolean} [options.antialias=false] - sets antialias (only applicable in chrome at the moment)
  30. * @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer. The
  31. * resolution of the renderer retina would be 2.
  32. * @param {boolean} [options.preserveDrawingBuffer=false] - enables drawing buffer preservation,
  33. * enable this if you need to call toDataUrl on the webgl context.
  34. * @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear the canvas or
  35. * not before the new render pass.
  36. * @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area
  37. * (shown if not transparent).
  38. * @param {boolean} [options.roundPixels=false] - If true PixiJS will Math.floor() x/y values when rendering,
  39. * stopping pixel interpolation.
  40. */
  41. constructor(options, arg2, arg3)
  42. {
  43. super('Canvas', options, arg2, arg3);
  44. this.type = RENDERER_TYPE.CANVAS;
  45. /**
  46. * The root canvas 2d context that everything is drawn with.
  47. *
  48. * @member {CanvasRenderingContext2D}
  49. */
  50. this.rootContext = this.view.getContext('2d', { alpha: this.transparent });
  51. /**
  52. * The currently active canvas 2d context (could change with renderTextures)
  53. *
  54. * @member {CanvasRenderingContext2D}
  55. */
  56. this.context = this.rootContext;
  57. /**
  58. * Boolean flag controlling canvas refresh.
  59. *
  60. * @member {boolean}
  61. */
  62. this.refresh = true;
  63. /**
  64. * Instance of a CanvasMaskManager, handles masking when using the canvas renderer.
  65. *
  66. * @member {PIXI.CanvasMaskManager}
  67. */
  68. this.maskManager = new CanvasMaskManager(this);
  69. /**
  70. * The canvas property used to set the canvas smoothing property.
  71. *
  72. * @member {string}
  73. */
  74. this.smoothProperty = 'imageSmoothingEnabled';
  75. if (!this.rootContext.imageSmoothingEnabled)
  76. {
  77. if (this.rootContext.webkitImageSmoothingEnabled)
  78. {
  79. this.smoothProperty = 'webkitImageSmoothingEnabled';
  80. }
  81. else if (this.rootContext.mozImageSmoothingEnabled)
  82. {
  83. this.smoothProperty = 'mozImageSmoothingEnabled';
  84. }
  85. else if (this.rootContext.oImageSmoothingEnabled)
  86. {
  87. this.smoothProperty = 'oImageSmoothingEnabled';
  88. }
  89. else if (this.rootContext.msImageSmoothingEnabled)
  90. {
  91. this.smoothProperty = 'msImageSmoothingEnabled';
  92. }
  93. }
  94. this.initPlugins();
  95. this.blendModes = mapCanvasBlendModesToPixi();
  96. this._activeBlendMode = null;
  97. this.renderingToScreen = false;
  98. this.resize(this.options.width, this.options.height);
  99. /**
  100. * Fired after rendering finishes.
  101. *
  102. * @event PIXI.CanvasRenderer#postrender
  103. */
  104. /**
  105. * Fired before rendering starts.
  106. *
  107. * @event PIXI.CanvasRenderer#prerender
  108. */
  109. }
  110. /**
  111. * Renders the object to this canvas view
  112. *
  113. * @param {PIXI.DisplayObject} displayObject - The object to be rendered
  114. * @param {PIXI.RenderTexture} [renderTexture] - A render texture to be rendered to.
  115. * If unset, it will render to the root context.
  116. * @param {boolean} [clear=false] - Whether to clear the canvas before drawing
  117. * @param {PIXI.Matrix} [transform] - A transformation to be applied
  118. * @param {boolean} [skipUpdateTransform=false] - Whether to skip the update transform
  119. */
  120. render(displayObject, renderTexture, clear, transform, skipUpdateTransform)
  121. {
  122. if (!this.view)
  123. {
  124. return;
  125. }
  126. // can be handy to know!
  127. this.renderingToScreen = !renderTexture;
  128. this.emit('prerender');
  129. const rootResolution = this.resolution;
  130. if (renderTexture)
  131. {
  132. renderTexture = renderTexture.baseTexture || renderTexture;
  133. if (!renderTexture._canvasRenderTarget)
  134. {
  135. renderTexture._canvasRenderTarget = new CanvasRenderTarget(
  136. renderTexture.width,
  137. renderTexture.height,
  138. renderTexture.resolution
  139. );
  140. renderTexture.source = renderTexture._canvasRenderTarget.canvas;
  141. renderTexture.valid = true;
  142. }
  143. this.context = renderTexture._canvasRenderTarget.context;
  144. this.resolution = renderTexture._canvasRenderTarget.resolution;
  145. }
  146. else
  147. {
  148. this.context = this.rootContext;
  149. }
  150. const context = this.context;
  151. if (!renderTexture)
  152. {
  153. this._lastObjectRendered = displayObject;
  154. }
  155. if (!skipUpdateTransform)
  156. {
  157. // update the scene graph
  158. const cacheParent = displayObject.parent;
  159. const tempWt = this._tempDisplayObjectParent.transform.worldTransform;
  160. if (transform)
  161. {
  162. transform.copy(tempWt);
  163. // lets not forget to flag the parent transform as dirty...
  164. this._tempDisplayObjectParent.transform._worldID = -1;
  165. }
  166. else
  167. {
  168. tempWt.identity();
  169. }
  170. displayObject.parent = this._tempDisplayObjectParent;
  171. displayObject.updateTransform();
  172. displayObject.parent = cacheParent;
  173. // displayObject.hitArea = //TODO add a temp hit area
  174. }
  175. context.save();
  176. context.setTransform(1, 0, 0, 1, 0, 0);
  177. context.globalAlpha = 1;
  178. this._activeBlendMode = BLEND_MODES.NORMAL;
  179. context.globalCompositeOperation = this.blendModes[BLEND_MODES.NORMAL];
  180. if (navigator.isCocoonJS && this.view.screencanvas)
  181. {
  182. context.fillStyle = 'black';
  183. context.clear();
  184. }
  185. if (clear !== undefined ? clear : this.clearBeforeRender)
  186. {
  187. if (this.renderingToScreen)
  188. {
  189. if (this.transparent)
  190. {
  191. context.clearRect(0, 0, this.width, this.height);
  192. }
  193. else
  194. {
  195. context.fillStyle = this._backgroundColorString;
  196. context.fillRect(0, 0, this.width, this.height);
  197. }
  198. } // else {
  199. // TODO: implement background for CanvasRenderTarget or RenderTexture?
  200. // }
  201. }
  202. // TODO RENDER TARGET STUFF HERE..
  203. const tempContext = this.context;
  204. this.context = context;
  205. displayObject.renderCanvas(this);
  206. this.context = tempContext;
  207. context.restore();
  208. this.resolution = rootResolution;
  209. this.emit('postrender');
  210. }
  211. /**
  212. * Clear the canvas of renderer.
  213. *
  214. * @param {string} [clearColor] - Clear the canvas with this color, except the canvas is transparent.
  215. */
  216. clear(clearColor)
  217. {
  218. const context = this.context;
  219. clearColor = clearColor || this._backgroundColorString;
  220. if (!this.transparent && clearColor)
  221. {
  222. context.fillStyle = clearColor;
  223. context.fillRect(0, 0, this.width, this.height);
  224. }
  225. else
  226. {
  227. context.clearRect(0, 0, this.width, this.height);
  228. }
  229. }
  230. /**
  231. * Sets the blend mode of the renderer.
  232. *
  233. * @param {number} blendMode - See {@link PIXI.BLEND_MODES} for valid values.
  234. */
  235. setBlendMode(blendMode)
  236. {
  237. if (this._activeBlendMode === blendMode)
  238. {
  239. return;
  240. }
  241. this._activeBlendMode = blendMode;
  242. this.context.globalCompositeOperation = this.blendModes[blendMode];
  243. }
  244. /**
  245. * Removes everything from the renderer and optionally removes the Canvas DOM element.
  246. *
  247. * @param {boolean} [removeView=false] - Removes the Canvas element from the DOM.
  248. */
  249. destroy(removeView)
  250. {
  251. this.destroyPlugins();
  252. // call the base destroy
  253. super.destroy(removeView);
  254. this.context = null;
  255. this.refresh = true;
  256. this.maskManager.destroy();
  257. this.maskManager = null;
  258. this.smoothProperty = null;
  259. }
  260. /**
  261. * Resizes the canvas view to the specified width and height.
  262. *
  263. * @extends PIXI.SystemRenderer#resize
  264. *
  265. * @param {number} screenWidth - the new width of the screen
  266. * @param {number} screenHeight - the new height of the screen
  267. */
  268. resize(screenWidth, screenHeight)
  269. {
  270. super.resize(screenWidth, screenHeight);
  271. // reset the scale mode.. oddly this seems to be reset when the canvas is resized.
  272. // surely a browser bug?? Let PixiJS fix that for you..
  273. if (this.smoothProperty)
  274. {
  275. this.rootContext[this.smoothProperty] = (settings.SCALE_MODE === SCALE_MODES.LINEAR);
  276. }
  277. }
  278. /**
  279. * Checks if blend mode has changed.
  280. */
  281. invalidateBlendMode()
  282. {
  283. this._activeBlendMode = this.blendModes.indexOf(this.context.globalCompositeOperation);
  284. }
  285. }
  286. /**
  287. * Collection of installed plugins. These are included by default in PIXI, but can be excluded
  288. * by creating a custom build. Consult the README for more information about creating custom
  289. * builds and excluding plugins.
  290. * @name PIXI.CanvasRenderer#plugins
  291. * @type {object}
  292. * @readonly
  293. * @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
  294. * @property {PIXI.extract.CanvasExtract} extract Extract image data from renderer.
  295. * @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
  296. * @property {PIXI.prepare.CanvasPrepare} prepare Pre-render display objects.
  297. */
  298. /**
  299. * Adds a plugin to the renderer.
  300. *
  301. * @method PIXI.CanvasRenderer#registerPlugin
  302. * @param {string} pluginName - The name of the plugin.
  303. * @param {Function} ctor - The constructor function or class for the plugin.
  304. */
  305. pluginTarget.mixin(CanvasRenderer);