|
@@ -47,142 +47,87 @@
|
|
|
*/
|
|
|
public static CACHESTRATEGY_DONTCACHE = 4;
|
|
|
|
|
|
- /**
|
|
|
- * Create a new 2D ScreenSpace Rendering Canvas, it is a 2D rectangle that has a size (width/height) and a position relative to the bottom/left corner of the screen.
|
|
|
- * ScreenSpace Canvas will be drawn in the Viewport as a 2D Layer lying to the top of the 3D Scene. Typically used for traditional UI.
|
|
|
- * All caching strategies will be available.
|
|
|
- * PLEASE NOTE: the origin of a Screen Space Canvas is set to [0;0] (bottom/left) which is different than the default origin of a Primitive which is centered [0.5;0.5]
|
|
|
- * @param scene the Scene that owns the Canvas
|
|
|
- * Options:
|
|
|
- * - id: a text identifier, for information purpose only
|
|
|
- * - pos: the position of the canvas, relative from the bottom/left of the scene's viewport. Alternatively you can set the x and y properties directly. Default value is [0, 0]
|
|
|
- * - size: the Size of the canvas. Alternatively the width and height properties can be set. If null two behaviors depend on the cachingStrategy: if it's CACHESTRATEGY_CACHECANVAS then it will always auto-fit the rendering device, in all the other modes it will fit the content of the Canvas
|
|
|
- * - cachingStrategy: either CACHESTRATEGY_TOPLEVELGROUPS, CACHESTRATEGY_ALLGROUPS, CACHESTRATEGY_CANVAS, CACHESTRATEGY_DONTCACHE. Please refer to their respective documentation for more information. Default is Canvas2D.CACHESTRATEGY_DONTCACHE
|
|
|
- * - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property. Default is true.
|
|
|
- * - isVisible: true if the canvas must be visible, false for hidden. Default is true.
|
|
|
- * - marginTop/Left/Right/Bottom: define the margin for the corresponding edge, if all of them are null, margin is not used in layout computing. Default Value is null for each.
|
|
|
- * - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
|
|
|
- * - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
|
|
|
- */
|
|
|
- static CreateScreenSpace(scene: Scene, options: { id?: string, x?: number, y?: number, position?: Vector2, origin?: Vector2, width?: number, height?: number, size?: Size, cachingStrategy?: number, enableInteraction?: boolean, isVisible?: boolean, marginTop?: number, marginLeft?: number, marginRight?: number, marginBottom?: number, hAlignment?: number, vAlignment?: number }): Canvas2D {
|
|
|
- let c = new Canvas2D();
|
|
|
-
|
|
|
- if (!options) {
|
|
|
- c.setupCanvas(scene, null, null, 1, true, Canvas2D.CACHESTRATEGY_DONTCACHE, true, Vector2.Zero(), true, null, null, null, null, null, null);
|
|
|
- c.position = Vector2.Zero();
|
|
|
- } else {
|
|
|
- let pos = options.position || new Vector2(options.x || 0, options.y || 0);
|
|
|
- let size = (!options.size && !options.width && !options.height) ? null : (options.size || (new Size(options.width || 0, options.height || 0)));
|
|
|
-
|
|
|
- c.setupCanvas(scene, options.id || null, size, 1, true, options.cachingStrategy || Canvas2D.CACHESTRATEGY_DONTCACHE, options.enableInteraction || true, options.origin || Vector2.Zero(), options.isVisible || true, options.marginTop, options.marginLeft, options.marginRight, options.marginBottom, options.hAlignment || Prim2DBase.HAlignLeft, options.vAlignment || Prim2DBase.VAlignTop);
|
|
|
- c.position = pos;
|
|
|
+ constructor(scene: Scene, settings?: {
|
|
|
+ id ?: string,
|
|
|
+ children ?: Array<Prim2DBase>,
|
|
|
+ size ?: Size,
|
|
|
+ renderScaleFactor ?: number,
|
|
|
+ isScreenSpace ?: boolean,
|
|
|
+ cachingStrategy ?: number,
|
|
|
+ enableInteraction ?: boolean,
|
|
|
+ origin ?: Vector2,
|
|
|
+ isVisible ?: boolean,
|
|
|
+ backgroundRoundRadius ?: number,
|
|
|
+ backgroundFill ?: IBrush2D | string,
|
|
|
+ backgroundBorder ?: IBrush2D | string,
|
|
|
+ backgroundBorderThickNess ?: number,
|
|
|
+ }) {
|
|
|
+ super(settings);
|
|
|
+
|
|
|
+ Prim2DBase._isCanvasInit = false;
|
|
|
+
|
|
|
+ if (!settings) {
|
|
|
+ settings = {};
|
|
|
}
|
|
|
|
|
|
- return c;
|
|
|
- }
|
|
|
+ let renderScaleFactor = (settings.renderScaleFactor == null) ? 1 : settings.renderScaleFactor;
|
|
|
+ if (this._cachingStrategy !== Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) {
|
|
|
+ this._background = new Rectangle2D({ parent: this, id: "###CANVAS BACKGROUND###", size: settings.size }); //TODO CHECK when size is null
|
|
|
+ this._background.zOrder = 1.0;
|
|
|
+ this._background.isPickable = false;
|
|
|
+ this._background.origin = Vector2.Zero();
|
|
|
+ this._background.levelVisible = false;
|
|
|
|
|
|
- /**
|
|
|
- * Create a new 2D WorldSpace Rendering Canvas, it is a 2D rectangle that has a size (width/height) and a world transformation information to place it in the world space.
|
|
|
- * This kind of canvas can't have its Primitives directly drawn in the Viewport, they need to be cached in a bitmap at some point, as a consequence the DONT_CACHE strategy is unavailable. For now only CACHESTRATEGY_CANVAS is supported, but the remaining strategies will be soon.
|
|
|
- * @param scene the Scene that owns the Canvas
|
|
|
- * @param size the dimension of the Canvas in World Space
|
|
|
- * Options:
|
|
|
- * - id: a text identifier, for information purpose only, default is null.
|
|
|
- * - position the position of the Canvas in World Space, default is [0,0,0]
|
|
|
- * - rotation the rotation of the Canvas in World Space, default is Quaternion.Identity()
|
|
|
- * - renderScaleFactor A scale factor applied to create the rendering texture that will be mapped in the Scene Rectangle. If you set 2 for instance the texture will be twice large in width and height. A greater value will allow to achieve a better rendering quality. Default value is 1.
|
|
|
- * BE AWARE that the Canvas true dimension will be size*renderScaleFactor, then all coordinates and size will have to be express regarding this size.
|
|
|
- * TIPS: if you want a renderScaleFactor independent reference of frame, create a child Group2D in the Canvas with position 0,0 and size set to null, then set its scale property to the same amount than the renderScaleFactor, put all your primitive inside using coordinates regarding the size property you pick for the Canvas and you'll be fine.
|
|
|
- * - sideOrientation: Unexpected behavior occur if the value is different from Mesh.DEFAULTSIDE right now, so please use this one, which is the default.
|
|
|
- * - cachingStrategy Must be CACHESTRATEGY_CANVAS for now, which is the default.
|
|
|
- * - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property. Default is false (the opposite of ScreenSpace).
|
|
|
- * - isVisible: true if the canvas must be visible, false for hidden. Default is true.
|
|
|
- * - customWorldSpaceNode: if specified the Canvas will be rendered in this given Node. But it's the responsibility of the caller to set the "worldSpaceToNodeLocal" property to compute the hit of the mouse ray into the node (in world coordinate system) as well as rendering the cached bitmap in the node itself. The properties cachedRect and cachedTexture of Group2D will give you what you need to do that.
|
|
|
- */
|
|
|
- static CreateWorldSpace(scene: Scene, size: Size, options: { id?: string, position?: Vector3, rotation?: Quaternion, renderScaleFactor?: number, sideOrientation?: number, cachingStrategy?: number, enableInteraction?: boolean, isVisible?: boolean, customWorldSpaceNode?: Node }): Canvas2D {
|
|
|
+ if (settings.backgroundRoundRadius != null) {
|
|
|
+ this.backgroundRoundRadius = settings.backgroundRoundRadius;
|
|
|
+ }
|
|
|
|
|
|
- let cs = options && options.cachingStrategy || Canvas2D.CACHESTRATEGY_CANVAS;
|
|
|
+ if (settings.backgroundBorder != null) {
|
|
|
+ this.backgroundBorder = <IBrush2D>settings.backgroundBorder; // TOFIX
|
|
|
+ }
|
|
|
|
|
|
- if (cs !== Canvas2D.CACHESTRATEGY_CANVAS) {
|
|
|
- throw new Error("Right now only the CACHESTRATEGY_CANVAS cache Strategy is supported for WorldSpace Canvas. More will come soon!");
|
|
|
- }
|
|
|
+ if (settings.backgroundBorderThickNess != null) {
|
|
|
+ this.backgroundBorderThickness = settings.backgroundBorderThickNess;
|
|
|
+ }
|
|
|
|
|
|
- //if (cachingStrategy === Canvas2D.CACHESTRATEGY_DONTCACHE) {
|
|
|
- // throw new Error("CACHESTRATEGY_DONTCACHE cache Strategy can't be used for WorldSpace Canvas");
|
|
|
- //}
|
|
|
+ if (settings.backgroundFill != null) {
|
|
|
+ this.backgroundFill = <IBrush2D>settings.backgroundFill;
|
|
|
+ }
|
|
|
|
|
|
- let enableInteraction = options ? options.enableInteraction : true;
|
|
|
- let createWorldSpaceNode = !options || (options.customWorldSpaceNode == null);
|
|
|
- let isVisible = options ? options.isVisible || true : true;
|
|
|
- let id = options ? options.id || null : null;
|
|
|
- let rsf = options ? options.renderScaleFactor || 1 : 1;
|
|
|
+ this._background._patchHierarchy(this);
|
|
|
+ }
|
|
|
|
|
|
- let c = new Canvas2D();
|
|
|
- c.setupCanvas(scene, id, new Size(size.width, size.height), rsf, false, cs, enableInteraction, new Vector2(0.5, 0.5), isVisible, null, null, null, null, null, null);
|
|
|
+ let engine = scene.getEngine();
|
|
|
|
|
|
- if (createWorldSpaceNode) {
|
|
|
- let plane = new WorldSpaceCanvas2D(id, scene, c);
|
|
|
- let vertexData = VertexData.CreatePlane({
|
|
|
- width: size.width,
|
|
|
- height: size.height,
|
|
|
- sideOrientation: options && options.sideOrientation || Mesh.DEFAULTSIDE
|
|
|
- });
|
|
|
- let mtl = new StandardMaterial(id + "_Material", scene);
|
|
|
+ this.__engineData = engine.getOrAddExternalDataWithFactory("__BJSCANVAS2D__", k => new Canvas2DEngineBoundData());
|
|
|
+ this._renderScaleFactor = renderScaleFactor;
|
|
|
+ this._primPointerInfo = new PrimitivePointerInfo();
|
|
|
+ this._capturedPointers = new StringDictionary<Prim2DBase>();
|
|
|
+ this._pickStartingPosition = Vector2.Zero();
|
|
|
+ this._hierarchyLevelMaxSiblingCount = 10;
|
|
|
+ this._hierarchyDepthOffset = 0;
|
|
|
+ this._siblingDepthOffset = 1 / this._hierarchyLevelMaxSiblingCount;
|
|
|
+ this._scene = scene;
|
|
|
+ this._engine = engine;
|
|
|
+ this._renderingSize = new Size(0, 0);
|
|
|
|
|
|
- c.applyCachedTexture(vertexData, mtl);
|
|
|
- vertexData.applyToMesh(plane, false);
|
|
|
+ this._patchHierarchy(this);
|
|
|
|
|
|
- mtl.specularColor = new Color3(0, 0, 0);
|
|
|
- mtl.disableLighting = true;
|
|
|
- mtl.useAlphaFromDiffuseTexture = true;
|
|
|
- plane.position = options && options.position || Vector3.Zero();
|
|
|
- plane.rotationQuaternion = options && options.rotation || Quaternion.Identity();
|
|
|
- plane.material = mtl;
|
|
|
- c._worldSpaceNode = plane;
|
|
|
- } else {
|
|
|
- c._worldSpaceNode = options.customWorldSpaceNode;
|
|
|
- }
|
|
|
- return c;
|
|
|
- }
|
|
|
+ let enableInteraction = (settings.enableInteraction == null) ? true : settings.enableInteraction;
|
|
|
|
|
|
- protected setupCanvas(scene: Scene, name: string, size: Size, renderScaleFactor: number, isScreenSpace: boolean, cachingstrategy: number, enableInteraction: boolean, origin: Vector2, isVisible: boolean, marginTop: number, marginLeft: number, marginRight: number, marginBottom: number, hAlign: number, vAlign: number) {
|
|
|
- let engine = scene.getEngine();
|
|
|
- this._fitRenderingDevice = !size;
|
|
|
- if (!size) {
|
|
|
- size = new Size(engine.getRenderWidth(), engine.getRenderHeight());
|
|
|
+ this._fitRenderingDevice = !settings.size;
|
|
|
+ if (!settings.size) {
|
|
|
+ settings.size = new Size(engine.getRenderWidth(), engine.getRenderHeight());
|
|
|
} else {
|
|
|
- size.height *= renderScaleFactor;
|
|
|
- size.width *= renderScaleFactor;
|
|
|
+ settings.size.height *= renderScaleFactor;
|
|
|
+ settings.size.width *= renderScaleFactor;
|
|
|
}
|
|
|
- this.__engineData = engine.getOrAddExternalDataWithFactory("__BJSCANVAS2D__", k => new Canvas2DEngineBoundData());
|
|
|
- this._renderScaleFactor = renderScaleFactor;
|
|
|
- this._cachingStrategy = cachingstrategy;
|
|
|
- this._primPointerInfo = new PrimitivePointerInfo();
|
|
|
- this._capturedPointers = new StringDictionary<Prim2DBase>();
|
|
|
- this._pickStartingPosition = Vector2.Zero();
|
|
|
-
|
|
|
- this.setupGroup2D(this, null, name, Vector2.Zero(), origin, size, isVisible, this._cachingStrategy === Canvas2D.CACHESTRATEGY_ALLGROUPS ? Group2D.GROUPCACHEBEHAVIOR_DONTCACHEOVERRIDE : Group2D.GROUPCACHEBEHAVIOR_FOLLOWCACHESTRATEGY, marginTop, marginLeft, marginRight, marginBottom, hAlign, vAlign);
|
|
|
-
|
|
|
- this._hierarchyLevelMaxSiblingCount = 10;
|
|
|
- this._hierarchyDepthOffset = 0;
|
|
|
- this._siblingDepthOffset = 1 / this._hierarchyLevelMaxSiblingCount;
|
|
|
- this._scene = scene;
|
|
|
- this._engine = engine;
|
|
|
- this._renderingSize = new Size(0, 0);
|
|
|
|
|
|
// Register scene dispose to also dispose the canvas when it'll happens
|
|
|
scene.onDisposeObservable.add((d, s) => {
|
|
|
this.dispose();
|
|
|
});
|
|
|
|
|
|
- if (cachingstrategy !== Canvas2D.CACHESTRATEGY_TOPLEVELGROUPS) {
|
|
|
- this._background = Rectangle2D.Create(this, { id: "###CANVAS BACKGROUND###", width: size.width, height: size.height });
|
|
|
- this._background.isPickable = false;
|
|
|
- this._background.origin = Vector2.Zero();
|
|
|
- this._background.levelVisible = false;
|
|
|
- }
|
|
|
- this._isScreeSpace = isScreenSpace;
|
|
|
-
|
|
|
if (this._isScreeSpace) {
|
|
|
this._afterRenderObserver = this._scene.onAfterRenderObservable.add((d, s) => {
|
|
|
this._engine.clear(null, false, true);
|
|
@@ -195,15 +140,19 @@
|
|
|
}
|
|
|
|
|
|
this._supprtInstancedArray = this._engine.getCaps().instancedArrays !== null;
|
|
|
- // this._supprtInstancedArray = false; // TODO REMOVE!!!
|
|
|
+// this._supprtInstancedArray = false; // TODO REMOVE!!!
|
|
|
|
|
|
this._setupInteraction(enableInteraction);
|
|
|
}
|
|
|
|
|
|
- public get hierarchyLevelMaxSiblingCount(): number {
|
|
|
- return this._hierarchyLevelMaxSiblingCount;
|
|
|
+ protected _canvasPreInit(settings: any) {
|
|
|
+ let cachingStrategy = (settings.cachingStrategy == null) ? Canvas2D.CACHESTRATEGY_DONTCACHE : settings.cachingStrategy;
|
|
|
+ this._cachingStrategy = cachingStrategy;
|
|
|
+ this._isScreeSpace = (settings.isScreenSpace == null) ? true : settings.isScreenSpace;
|
|
|
}
|
|
|
|
|
|
+ public static hierarchyLevelMaxSiblingCount: number = 10;
|
|
|
+
|
|
|
private _setupInteraction(enable: boolean) {
|
|
|
// No change detection
|
|
|
if (enable === this._interactionEnabled) {
|
|
@@ -229,7 +178,7 @@
|
|
|
|
|
|
// Register the observable
|
|
|
this._scenePrePointerObserver = this.scene.onPrePointerObservable.add((e, s) => {
|
|
|
- let hs = 1 / this.engine.getHardwareScalingLevel();
|
|
|
+ let hs = 1/this.engine.getHardwareScalingLevel();
|
|
|
let localPos = e.localPosition.multiplyByFloats(hs, hs);
|
|
|
this._handlePointerEventForInteraction(e, localPos, s);
|
|
|
});
|
|
@@ -273,11 +222,11 @@
|
|
|
mtx.invert();
|
|
|
let v = Vector3.TransformCoordinates(worldPos, mtx);
|
|
|
let rsf = this._renderScaleFactor;
|
|
|
- let res = new Vector2(v.x * rsf, v.y * rsf);
|
|
|
+ let res = new Vector2(v.x*rsf, v.y*rsf);
|
|
|
let size = this.actualSize;
|
|
|
let o = this.origin;
|
|
|
- res.x += size.width * o.x;
|
|
|
- res.y += size.width * o.y;
|
|
|
+ res.x += size.width * 0.5; // res is centered, make it relative to bottom/left
|
|
|
+ res.y += size.width * 0.5;
|
|
|
return res;
|
|
|
}
|
|
|
|
|
@@ -340,7 +289,7 @@
|
|
|
}
|
|
|
return this._capturedPointers.get(pointerId.toString());
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
private static _interInfo = new IntersectInfo2D();
|
|
|
private _handlePointerEventForInteraction(eventData: PointerInfoBase, localPosition: Vector2, eventState: EventState) {
|
|
|
// Dispose check
|
|
@@ -355,7 +304,7 @@
|
|
|
|
|
|
// Make sure the intersection list is up to date, we maintain this list either in response of a mouse event (here) or before rendering the canvas.
|
|
|
// Why before rendering the canvas? because some primitives may move and get away/under the mouse cursor (which is not moving). So we need to update at both location in order to always have an accurate list, which is needed for the hover state change.
|
|
|
- this._updateIntersectionList(this._primPointerInfo.canvasPointerPos, capturedPrim !== null);
|
|
|
+ this._updateIntersectionList(this._primPointerInfo.canvasPointerPos, capturedPrim!==null);
|
|
|
|
|
|
// Update the over status, same as above, it's could be done here or during rendering, but will be performed only once per render frame
|
|
|
this._updateOverStatus();
|
|
@@ -401,8 +350,8 @@
|
|
|
var x = localPosition.x - viewport.x;
|
|
|
var y = localPosition.y - viewport.y;
|
|
|
|
|
|
- pii.canvasPointerPos.x = x - this.position.x;
|
|
|
- pii.canvasPointerPos.y = engine.getRenderHeight() - y - this.position.y;
|
|
|
+ pii.canvasPointerPos.x = x - this.actualPosition.x;
|
|
|
+ pii.canvasPointerPos.y = engine.getRenderHeight() -y - this.actualPosition.y;
|
|
|
} else {
|
|
|
pii.canvasPointerPos.x = localPosition.x;
|
|
|
pii.canvasPointerPos.y = localPosition.y;
|
|
@@ -417,20 +366,20 @@
|
|
|
pii.mouseWheelDelta = -event.detail / PrimitivePointerInfo.MouseWheelPrecision;
|
|
|
}
|
|
|
} else {
|
|
|
- var pe = <PointerEvent>eventData.event;
|
|
|
- pii.ctrlKey = pe.ctrlKey;
|
|
|
- pii.altKey = pe.altKey;
|
|
|
- pii.shiftKey = pe.shiftKey;
|
|
|
- pii.metaKey = pe.metaKey;
|
|
|
- pii.button = pe.button;
|
|
|
- pii.buttons = pe.buttons;
|
|
|
- pii.pointerId = pe.pointerId;
|
|
|
- pii.width = pe.width;
|
|
|
- pii.height = pe.height;
|
|
|
- pii.presssure = pe.pressure;
|
|
|
- pii.tilt.x = pe.tiltX;
|
|
|
- pii.tilt.y = pe.tiltY;
|
|
|
- pii.isCaptured = this.getCapturedPrimitive(pe.pointerId) !== null;
|
|
|
+ var pe = <PointerEvent>eventData.event;
|
|
|
+ pii.ctrlKey = pe.ctrlKey;
|
|
|
+ pii.altKey = pe.altKey;
|
|
|
+ pii.shiftKey = pe.shiftKey;
|
|
|
+ pii.metaKey = pe.metaKey;
|
|
|
+ pii.button = pe.button;
|
|
|
+ pii.buttons = pe.buttons;
|
|
|
+ pii.pointerId = pe.pointerId;
|
|
|
+ pii.width = pe.width;
|
|
|
+ pii.height = pe.height;
|
|
|
+ pii.presssure = pe.pressure;
|
|
|
+ pii.tilt.x = pe.tiltX;
|
|
|
+ pii.tilt.y = pe.tiltY;
|
|
|
+ pii.isCaptured = this.getCapturedPrimitive(pe.pointerId)!==null;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -439,6 +388,11 @@
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
+ // A little safe guard, it might happens than the event is triggered before the first render and nothing is computed, this simple check will make sure everything will be fine
|
|
|
+ if (!this._globalTransform) {
|
|
|
+ this.updateCachedStates(true);
|
|
|
+ }
|
|
|
+
|
|
|
let ii = Canvas2D._interInfo;
|
|
|
ii.pickPosition.x = mouseLocalPos.x;
|
|
|
ii.pickPosition.y = mouseLocalPos.y;
|
|
@@ -447,18 +401,18 @@
|
|
|
// Fast rejection: test if the mouse pointer is outside the canvas's bounding Info
|
|
|
if (!isCapture && !this.boundingInfo.doesIntersect(ii.pickPosition)) {
|
|
|
this._previousIntersectionList = this._actualIntersectionList;
|
|
|
- this._actualIntersectionList = null;
|
|
|
- this._previousOverPrimitive = this._actualOverPrimitive;
|
|
|
- this._actualOverPrimitive = null;
|
|
|
+ this._actualIntersectionList = null;
|
|
|
+ this._previousOverPrimitive = this._actualOverPrimitive;
|
|
|
+ this._actualOverPrimitive = null;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
this.intersect(ii);
|
|
|
|
|
|
this._previousIntersectionList = this._actualIntersectionList;
|
|
|
- this._actualIntersectionList = ii.intersectedPrimitives;
|
|
|
- this._previousOverPrimitive = this._actualOverPrimitive;
|
|
|
- this._actualOverPrimitive = ii.topMostIntersectedPrimitive;
|
|
|
+ this._actualIntersectionList = ii.intersectedPrimitives;
|
|
|
+ this._previousOverPrimitive = this._actualOverPrimitive;
|
|
|
+ this._actualOverPrimitive = ii.topMostIntersectedPrimitive;
|
|
|
|
|
|
this._intersectionRenderId = this.scene.getRenderId();
|
|
|
}
|
|
@@ -471,14 +425,14 @@
|
|
|
|
|
|
// Detect a change of over
|
|
|
let prevPrim = this._previousOverPrimitive ? this._previousOverPrimitive.prim : null;
|
|
|
- let actualPrim = this._actualOverPrimitive ? this._actualOverPrimitive.prim : null;
|
|
|
+ let actualPrim = this._actualOverPrimitive ? this._actualOverPrimitive.prim : null;
|
|
|
|
|
|
if (prevPrim !== actualPrim) {
|
|
|
// Detect if the current pointer is captured, only fire event if they belong to the capture primitive
|
|
|
let capturedPrim = this.getCapturedPrimitive(this._primPointerInfo.pointerId);
|
|
|
|
|
|
// Notify the previous "over" prim that the pointer is no longer over it
|
|
|
- if ((capturedPrim && capturedPrim === prevPrim) || (!capturedPrim && prevPrim)) {
|
|
|
+ if ((capturedPrim && capturedPrim===prevPrim) || (!capturedPrim && prevPrim)) {
|
|
|
this._primPointerInfo.updateRelatedTarget(prevPrim, this._previousOverPrimitive.intersectionLocation);
|
|
|
this._bubbleNotifyPrimPointerObserver(prevPrim, PrimitivePointerInfo.PointerOut, null);
|
|
|
}
|
|
@@ -525,9 +479,9 @@
|
|
|
private _bubbleNotifyPrimPointerObserver(prim: Prim2DBase, mask: number, eventData: any) {
|
|
|
let ppi = this._primPointerInfo;
|
|
|
|
|
|
- // In case of PointerOver/Out we will first notify the children (but the deepest to the closest) with PointerEnter/Leave
|
|
|
+ // In case of PointerOver/Out we will first notify the parent with PointerEnter/Leave
|
|
|
if ((mask & (PrimitivePointerInfo.PointerOver | PrimitivePointerInfo.PointerOut)) !== 0) {
|
|
|
- this._notifChildren(prim, mask);
|
|
|
+ this._notifParents(prim, mask);
|
|
|
}
|
|
|
|
|
|
let bubbleCancelled = false;
|
|
@@ -578,6 +532,11 @@
|
|
|
|
|
|
private _triggerActionManager(prim: Prim2DBase, ppi: PrimitivePointerInfo, mask: number, eventData) {
|
|
|
|
|
|
+ // A little safe guard, it might happens than the event is triggered before the first render and nothing is computed, this simple check will make sure everything will be fine
|
|
|
+ if (!this._globalTransform) {
|
|
|
+ this.updateCachedStates(true);
|
|
|
+ }
|
|
|
+
|
|
|
// Process Trigger related to PointerDown
|
|
|
if ((mask & PrimitivePointerInfo.PointerDown) !== 0) {
|
|
|
// On pointer down, record the current position and time to be able to trick PickTrigger and LongPressTrigger
|
|
@@ -591,15 +550,15 @@
|
|
|
let actionEvent = ActionEvent.CreateNewFromPrimitive(prim, ppi.primitivePointerPos, eventData);
|
|
|
|
|
|
switch (eventData.button) {
|
|
|
- case 0:
|
|
|
- prim.actionManager.processTrigger(ActionManager.OnLeftPickTrigger, actionEvent);
|
|
|
- break;
|
|
|
- case 1:
|
|
|
- prim.actionManager.processTrigger(ActionManager.OnCenterPickTrigger, actionEvent);
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- prim.actionManager.processTrigger(ActionManager.OnRightPickTrigger, actionEvent);
|
|
|
- break;
|
|
|
+ case 0:
|
|
|
+ prim.actionManager.processTrigger(ActionManager.OnLeftPickTrigger, actionEvent);
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ prim.actionManager.processTrigger(ActionManager.OnCenterPickTrigger, actionEvent);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ prim.actionManager.processTrigger(ActionManager.OnRightPickTrigger, actionEvent);
|
|
|
+ break;
|
|
|
}
|
|
|
prim.actionManager.processTrigger(ActionManager.OnPickDownTrigger, actionEvent);
|
|
|
}
|
|
@@ -664,27 +623,27 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- _notifChildren(prim: Prim2DBase, mask: number) {
|
|
|
+ _notifParents(prim: Prim2DBase, mask: number) {
|
|
|
let pii = this._primPointerInfo;
|
|
|
|
|
|
- prim.children.forEach(curChild => {
|
|
|
- // Recurse first, we want the deepest to be notified first
|
|
|
- this._notifChildren(curChild, mask);
|
|
|
+ let curPrim: Prim2DBase = this;
|
|
|
|
|
|
- this._updatePrimPointerPos(curChild);
|
|
|
+ while (curPrim) {
|
|
|
+ this._updatePrimPointerPos(curPrim);
|
|
|
|
|
|
// Fire the proper notification
|
|
|
if (mask === PrimitivePointerInfo.PointerOver) {
|
|
|
- this._debugExecObserver(curChild, PrimitivePointerInfo.PointerEnter);
|
|
|
- curChild._pointerEventObservable.notifyObservers(pii, PrimitivePointerInfo.PointerEnter);
|
|
|
+ this._debugExecObserver(curPrim, PrimitivePointerInfo.PointerEnter);
|
|
|
+ curPrim._pointerEventObservable.notifyObservers(pii, PrimitivePointerInfo.PointerEnter);
|
|
|
}
|
|
|
|
|
|
// Trigger a PointerLeave corresponding to the PointerOut
|
|
|
else if (mask === PrimitivePointerInfo.PointerOut) {
|
|
|
- this._debugExecObserver(curChild, PrimitivePointerInfo.PointerLeave);
|
|
|
- curChild._pointerEventObservable.notifyObservers(pii, PrimitivePointerInfo.PointerLeave);
|
|
|
+ this._debugExecObserver(curPrim, PrimitivePointerInfo.PointerLeave);
|
|
|
+ curPrim._pointerEventObservable.notifyObservers(pii, PrimitivePointerInfo.PointerLeave);
|
|
|
}
|
|
|
- });
|
|
|
+ curPrim = curPrim.parent;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -802,6 +761,27 @@
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * Property that defines the thickness of the border object used to draw the background of the Canvas.
|
|
|
+ * @returns If the background is not set, null will be returned, otherwise a valid number matching the thickness is returned.
|
|
|
+ */
|
|
|
+ public get backgroundBorderThickness(): number {
|
|
|
+ if (!this._background || !this._background.isVisible) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return this._background.borderThickness;
|
|
|
+ }
|
|
|
+
|
|
|
+ public set backgroundBorderThickness(value: number) {
|
|
|
+ this.checkBackgroundAvailability();
|
|
|
+
|
|
|
+ if (value === this._background.borderThickness) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this._background.borderThickness = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* You can set the roundRadius of the background
|
|
|
* @returns The current roundRadius
|
|
|
*/
|
|
@@ -863,7 +843,7 @@
|
|
|
private _capturedPointers: StringDictionary<Prim2DBase>;
|
|
|
private _scenePrePointerObserver: Observer<PointerInfoPre>;
|
|
|
private _scenePointerObserver: Observer<PointerInfo>;
|
|
|
- private _worldSpaceNode: Node;
|
|
|
+ protected _worldSpaceNode: Node;
|
|
|
private _mapCounter = 0;
|
|
|
private _background: Rectangle2D;
|
|
|
private _scene: Scene;
|
|
@@ -876,7 +856,7 @@
|
|
|
private _groupCacheMaps: MapTexture[];
|
|
|
private _beforeRenderObserver: Observer<Scene>;
|
|
|
private _afterRenderObserver: Observer<Scene>;
|
|
|
- private _supprtInstancedArray: boolean;
|
|
|
+ private _supprtInstancedArray : boolean;
|
|
|
|
|
|
public _renderingSize: Size;
|
|
|
|
|
@@ -890,20 +870,36 @@
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- this._renderingSize.width = this.engine.getRenderWidth();
|
|
|
- this._renderingSize.height = this.engine.getRenderHeight();
|
|
|
+ // Detect a change of rendering size
|
|
|
+ let renderingSizeChanged = false;
|
|
|
+ let newWidth = this.engine.getRenderWidth();
|
|
|
+ if (newWidth !== this._renderingSize.width) {
|
|
|
+ renderingSizeChanged = true;
|
|
|
+ }
|
|
|
+ this._renderingSize.width = newWidth;
|
|
|
+
|
|
|
+ let newHeight = this.engine.getRenderHeight();
|
|
|
+ if (newHeight !== this._renderingSize.height) {
|
|
|
+ renderingSizeChanged = true;
|
|
|
+ }
|
|
|
+ this._renderingSize.height = newHeight;
|
|
|
+
|
|
|
|
|
|
- if (this._fitRenderingDevice) {
|
|
|
+ // If the canvas fit the rendering size and it changed, update
|
|
|
+ if (renderingSizeChanged && this._fitRenderingDevice) {
|
|
|
this.size = this._renderingSize;
|
|
|
if (this._background) {
|
|
|
this._background.size = this.size;
|
|
|
}
|
|
|
+
|
|
|
+ // Dirty the Layout at the Canvas level to recompute as the size changed
|
|
|
+ this._setLayoutDirty();
|
|
|
}
|
|
|
|
|
|
var context = new PrepareRender2DContext();
|
|
|
|
|
|
++this._globalTransformProcessStep;
|
|
|
- this.updateGlobalTransVis(false);
|
|
|
+ this.updateCachedStates(false);
|
|
|
|
|
|
this._prepareGroupRender(context);
|
|
|
|
|
@@ -921,7 +917,8 @@
|
|
|
this._updateIntersectionList(this._primPointerInfo.canvasPointerPos, false);
|
|
|
this._updateOverStatus(); // TODO this._primPointerInfo may not be up to date!
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ this.engine.setState(false);
|
|
|
this._groupRender();
|
|
|
|
|
|
// If the canvas is cached at canvas level, we must manually render the sprite that will display its content
|
|
@@ -941,7 +938,7 @@
|
|
|
let size = group.actualSize;
|
|
|
size = new Size(Math.ceil(size.width), Math.ceil(size.height));
|
|
|
if (minSize) {
|
|
|
- size.width = Math.max(minSize.width, size.width);
|
|
|
+ size.width = Math.max(minSize.width, size.width);
|
|
|
size.height = Math.max(minSize.height, size.height);
|
|
|
}
|
|
|
|
|
@@ -985,14 +982,14 @@
|
|
|
// Special case if the canvas is entirely cached: create a group that will have a single sprite it will be rendered specifically at the very end of the rendering process
|
|
|
if (this._cachingStrategy === Canvas2D.CACHESTRATEGY_CANVAS) {
|
|
|
this._cachedCanvasGroup = Group2D._createCachedCanvasGroup(this);
|
|
|
- let sprite = Sprite2D.Create(this._cachedCanvasGroup, map, { id: "__cachedCanvasSprite__", spriteSize: node.contentSize, spriteLocation: node.pos });
|
|
|
+ let sprite = new Sprite2D(map, { parent: this._cachedCanvasGroup, id: "__cachedCanvasSprite__", spriteSize:node.contentSize, spriteLocation:node.pos});
|
|
|
sprite.zOrder = 1;
|
|
|
sprite.origin = Vector2.Zero();
|
|
|
}
|
|
|
|
|
|
// Create a Sprite that will be used to render this cache, the "__cachedSpriteOfGroup__" starting id is a hack to bypass exception throwing in case of the Canvas doesn't normally allows direct primitives
|
|
|
else {
|
|
|
- let sprite = Sprite2D.Create(parent, map, { id: `__cachedSpriteOfGroup__${group.id}`, x: group.position.x, y: group.position.y, spriteSize: node.contentSize, spriteLocation: node.pos });
|
|
|
+ let sprite = new Sprite2D(map, { parent: parent, id:`__cachedSpriteOfGroup__${group.id}`, x: group.actualPosition.x, y: group.actualPosition.y, spriteSize:node.contentSize, spriteLocation:node.pos});
|
|
|
sprite.origin = group.origin.clone();
|
|
|
res.sprite = sprite;
|
|
|
}
|
|
@@ -1028,7 +1025,232 @@
|
|
|
return Canvas2D._gradientColorBrushes.getOrAddWithFactory(GradientColorBrush2D.BuildKey(color1, color2, translation, rotation, scale), () => new GradientColorBrush2D(color1, color2, translation, rotation, scale, true));
|
|
|
}
|
|
|
|
|
|
+ public static GetBrushFromString(brushString: string): IBrush2D {
|
|
|
+ // Note: yes, I hate/don't know RegEx.. Feel free to add your contribution to the cause!
|
|
|
+
|
|
|
+ brushString = brushString.trim();
|
|
|
+ let split = brushString.split(",");
|
|
|
+
|
|
|
+ // Solid, formatted as: "[solid:]#FF808080"
|
|
|
+ if (split.length === 1) {
|
|
|
+ let value: string = null;
|
|
|
+ if (brushString.indexOf("solid:") === 0) {
|
|
|
+ value = brushString.substr(6).trim();
|
|
|
+ } else if (brushString.indexOf("#") === 0) {
|
|
|
+ value = brushString;
|
|
|
+ } else {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return Canvas2D.GetSolidColorBrushFromHex(value);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Gradient, formatted as: "[gradient:]#FF808080, #FFFFFFF[, [10:20], 180, 1]" [10:20] is a real formatting expected not a EBNF notation
|
|
|
+ // Order is: gradient start, gradient end, translation, rotation (degree), scale
|
|
|
+ else {
|
|
|
+ if (split[0].indexOf("gradient:") === 0) {
|
|
|
+ split[0] = split[0].substr(9).trim();
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ let start = Color4.FromHexString(split[0].trim());
|
|
|
+ let end = Color4.FromHexString(split[1].trim());
|
|
|
+
|
|
|
+ let t: Vector2 = Vector2.Zero();
|
|
|
+ if (split.length > 2) {
|
|
|
+ let v = split[2].trim();
|
|
|
+ if (v.charAt(0) !== "[" || v.charAt(v.length - 1) !== "]") {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ let sep = v.indexOf(":");
|
|
|
+ let x = parseFloat(v.substr(1, sep));
|
|
|
+ let y = parseFloat(v.substr(sep + 1, v.length - (sep + 1)));
|
|
|
+ t = new Vector2(x, y);
|
|
|
+ }
|
|
|
+
|
|
|
+ let r: number = 0;
|
|
|
+ if (split.length > 3) {
|
|
|
+ r = Tools.ToRadians(parseFloat(split[3].trim()));
|
|
|
+ }
|
|
|
+
|
|
|
+ let s: number = 1;
|
|
|
+ if (split.length > 4) {
|
|
|
+ s = parseFloat(split[4].trim());
|
|
|
+ }
|
|
|
+
|
|
|
+ return Canvas2D.GetGradientColorBrush(start, end, t, r, s);
|
|
|
+ } catch (e) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private static _solidColorBrushes: StringDictionary<IBrush2D> = new StringDictionary<IBrush2D>();
|
|
|
private static _gradientColorBrushes: StringDictionary<IBrush2D> = new StringDictionary<IBrush2D>();
|
|
|
}
|
|
|
+ @className("WorldSpaceCanvas2D")
|
|
|
+ export class WorldSpaceCanvas2D extends Canvas2D {
|
|
|
+ /**
|
|
|
+ * Create a new 2D WorldSpace Rendering Canvas, it is a 2D rectangle that has a size (width/height) and a world transformation information to place it in the world space.
|
|
|
+ * This kind of canvas can't have its Primitives directly drawn in the Viewport, they need to be cached in a bitmap at some point, as a consequence the DONT_CACHE strategy is unavailable. For now only CACHESTRATEGY_CANVAS is supported, but the remaining strategies will be soon.
|
|
|
+ * @param scene the Scene that owns the Canvas
|
|
|
+ * @param size the dimension of the Canvas in World Space
|
|
|
+ * Options:
|
|
|
+ * - id: a text identifier, for information purpose only, default is null.
|
|
|
+ * - position the position of the Canvas in World Space, default is [0,0,0]
|
|
|
+ * - rotation the rotation of the Canvas in World Space, default is Quaternion.Identity()
|
|
|
+ * - renderScaleFactor A scale factor applied to create the rendering texture that will be mapped in the Scene Rectangle. If you set 2 for instance the texture will be twice large in width and height. A greater value will allow to achieve a better rendering quality. Default value is 1.
|
|
|
+ * BE AWARE that the Canvas true dimension will be size*renderScaleFactor, then all coordinates and size will have to be express regarding this size.
|
|
|
+ * TIPS: if you want a renderScaleFactor independent reference of frame, create a child Group2D in the Canvas with position 0,0 and size set to null, then set its scale property to the same amount than the renderScaleFactor, put all your primitive inside using coordinates regarding the size property you pick for the Canvas and you'll be fine.
|
|
|
+ * - sideOrientation: Unexpected behavior occur if the value is different from Mesh.DEFAULTSIDE right now, so please use this one, which is the default.
|
|
|
+ * - cachingStrategy Must be CACHESTRATEGY_CANVAS for now, which is the default.
|
|
|
+ * - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property. Default is false (the opposite of ScreenSpace).
|
|
|
+ * - isVisible: true if the canvas must be visible, false for hidden. Default is true.
|
|
|
+ * - customWorldSpaceNode: if specified the Canvas will be rendered in this given Node. But it's the responsibility of the caller to set the "worldSpaceToNodeLocal" property to compute the hit of the mouse ray into the node (in world coordinate system) as well as rendering the cached bitmap in the node itself. The properties cachedRect and cachedTexture of Group2D will give you what you need to do that.
|
|
|
+ */
|
|
|
+ constructor(scene: Scene, size: Size, settings?: {
|
|
|
+
|
|
|
+ children ?: Array<Prim2DBase>,
|
|
|
+ id ?: string,
|
|
|
+ worldPosition ?: Vector3,
|
|
|
+ worldRotation ?: Quaternion,
|
|
|
+ renderScaleFactor ?: number,
|
|
|
+ sideOrientation ?: number,
|
|
|
+ cachingStrategy ?: number,
|
|
|
+ enableInteraction ?: boolean,
|
|
|
+ isVisible ?: boolean,
|
|
|
+ backgroundRoundRadius ?: number,
|
|
|
+ backgroundFill ?: IBrush2D | string,
|
|
|
+ backgroundBorder ?: IBrush2D | string,
|
|
|
+ backgroundBorderThickNess?: number,
|
|
|
+ customWorldSpaceNode ?: Node,
|
|
|
+ marginTop ?: number | string,
|
|
|
+ marginLeft ?: number | string,
|
|
|
+ marginRight ?: number | string,
|
|
|
+ marginBottom ?: number | string,
|
|
|
+ margin ?: number | string,
|
|
|
+ marginHAlignment ?: number,
|
|
|
+ marginVAlignment ?: number,
|
|
|
+ marginAlignment ?: string,
|
|
|
+
|
|
|
+ }) {
|
|
|
+ Prim2DBase._isCanvasInit = true;
|
|
|
+ let s = <any>settings;
|
|
|
+ s.isScreenSpace = false;
|
|
|
+ s.size = size.clone();
|
|
|
+ settings.cachingStrategy = (settings.cachingStrategy==null) ? Canvas2D.CACHESTRATEGY_CANVAS : settings.cachingStrategy;
|
|
|
+
|
|
|
+ if (settings.cachingStrategy !== Canvas2D.CACHESTRATEGY_CANVAS) {
|
|
|
+ throw new Error("Right now only the CACHESTRATEGY_CANVAS cache Strategy is supported for WorldSpace Canvas. More will come soon!");
|
|
|
+ }
|
|
|
+
|
|
|
+ super(scene, settings);
|
|
|
+ Prim2DBase._isCanvasInit = false;
|
|
|
+
|
|
|
+
|
|
|
+ //if (cachingStrategy === Canvas2D.CACHESTRATEGY_DONTCACHE) {
|
|
|
+ // throw new Error("CACHESTRATEGY_DONTCACHE cache Strategy can't be used for WorldSpace Canvas");
|
|
|
+ //}
|
|
|
+
|
|
|
+ //let enableInteraction = settings ? settings.enableInteraction : true;
|
|
|
+ let createWorldSpaceNode = !settings || (settings.customWorldSpaceNode == null);
|
|
|
+ //let isVisible = settings ? settings.isVisible || true : true;
|
|
|
+ let id = settings ? settings.id || null : null;
|
|
|
+ //let rsf = settings ? settings.renderScaleFactor || 1 : 1;
|
|
|
+
|
|
|
+ //let c = new Canvas2D();
|
|
|
+ //c.setupCanvas(scene, id, new Size(size.width, size.height), rsf, false, cs, enableInteraction, new Vector2(0.5, 0.5), isVisible, null, null, null, null, null, null);
|
|
|
+
|
|
|
+ if (createWorldSpaceNode) {
|
|
|
+ let plane = new WorldSpaceCanvas2DNode(id, scene, this);
|
|
|
+ let vertexData = VertexData.CreatePlane({
|
|
|
+ width: size.width,
|
|
|
+ height: size.height,
|
|
|
+ sideOrientation: settings && settings.sideOrientation || Mesh.DEFAULTSIDE
|
|
|
+ });
|
|
|
+ let mtl = new StandardMaterial(id + "_Material", scene);
|
|
|
+
|
|
|
+ this.applyCachedTexture(vertexData, mtl);
|
|
|
+ vertexData.applyToMesh(plane, false);
|
|
|
+
|
|
|
+ mtl.specularColor = new Color3(0, 0, 0);
|
|
|
+ mtl.disableLighting = true;
|
|
|
+ mtl.useAlphaFromDiffuseTexture = true;
|
|
|
+ plane.position = settings && settings.worldPosition || Vector3.Zero();
|
|
|
+ plane.rotationQuaternion = settings && settings.worldRotation || Quaternion.Identity();
|
|
|
+ plane.material = mtl;
|
|
|
+ this._worldSpaceNode = plane;
|
|
|
+ } else {
|
|
|
+ this._worldSpaceNode = settings.customWorldSpaceNode;
|
|
|
+ }
|
|
|
+ // return c;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @className("ScreenSpaceCanvas2D")
|
|
|
+ export class ScreenSpaceCanvas2D extends Canvas2D {
|
|
|
+ /**
|
|
|
+ * Create a new 2D ScreenSpace Rendering Canvas, it is a 2D rectangle that has a size (width/height) and a position relative to the bottom/left corner of the screen.
|
|
|
+ * ScreenSpace Canvas will be drawn in the Viewport as a 2D Layer lying to the top of the 3D Scene. Typically used for traditional UI.
|
|
|
+ * All caching strategies will be available.
|
|
|
+ * PLEASE NOTE: the origin of a Screen Space Canvas is set to [0;0] (bottom/left) which is different than the default origin of a Primitive which is centered [0.5;0.5]
|
|
|
+ * @param scene the Scene that owns the Canvas
|
|
|
+ * Options:
|
|
|
+ * - id: a text identifier, for information purpose only
|
|
|
+ * - pos: the position of the canvas, relative from the bottom/left of the scene's viewport. Alternatively you can set the x and y properties directly. Default value is [0, 0]
|
|
|
+ * - size: the Size of the canvas. Alternatively the width and height properties can be set. If null two behaviors depend on the cachingStrategy: if it's CACHESTRATEGY_CACHECANVAS then it will always auto-fit the rendering device, in all the other modes it will fit the content of the Canvas
|
|
|
+ * - cachingStrategy: either CACHESTRATEGY_TOPLEVELGROUPS, CACHESTRATEGY_ALLGROUPS, CACHESTRATEGY_CANVAS, CACHESTRATEGY_DONTCACHE. Please refer to their respective documentation for more information. Default is Canvas2D.CACHESTRATEGY_DONTCACHE
|
|
|
+ * - enableInteraction: if true the pointer events will be listened and rerouted to the appropriate primitives of the Canvas2D through the Prim2DBase.onPointerEventObservable observable property. Default is true.
|
|
|
+ * - isVisible: true if the canvas must be visible, false for hidden. Default is true.
|
|
|
+ * - marginTop/Left/Right/Bottom: define the margin for the corresponding edge, if all of them are null, margin is not used in layout computing. Default Value is null for each.
|
|
|
+ * - hAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
|
|
|
+ * - vAlighment: define horizontal alignment of the Canvas, alignment is optional, default value null: no alignment.
|
|
|
+ */
|
|
|
+ constructor(scene: Scene, settings?: {
|
|
|
+
|
|
|
+ children ?: Array<Prim2DBase>,
|
|
|
+ id ?: string,
|
|
|
+ x ?: number,
|
|
|
+ y ?: number,
|
|
|
+ position ?: Vector2,
|
|
|
+ origin ?: Vector2,
|
|
|
+ width ?: number,
|
|
|
+ height ?: number,
|
|
|
+ size ?: Size,
|
|
|
+ cachingStrategy ?: number,
|
|
|
+ enableInteraction ?: boolean,
|
|
|
+ isVisible ?: boolean,
|
|
|
+ backgroundRoundRadius ?: number,
|
|
|
+ backgroundFill ?: IBrush2D | string,
|
|
|
+ backgroundBorder ?: IBrush2D | string,
|
|
|
+ backgroundBorderThickNess ?: number,
|
|
|
+ marginTop ?: number | string,
|
|
|
+ marginLeft ?: number | string,
|
|
|
+ marginRight ?: number | string,
|
|
|
+ marginBottom ?: number | string,
|
|
|
+ margin ?: string,
|
|
|
+ marginHAlignment ?: number,
|
|
|
+ marginVAlignment ?: number,
|
|
|
+ marginAlignment ?: string,
|
|
|
+
|
|
|
+ }) {
|
|
|
+ Prim2DBase._isCanvasInit = true;
|
|
|
+ super(scene, settings);
|
|
|
+
|
|
|
+ //let c = new Canvas2D();
|
|
|
+
|
|
|
+ //if (!settings) {
|
|
|
+ // c.setupCanvas(scene, null, null, 1, true, Canvas2D.CACHESTRATEGY_DONTCACHE, true, Vector2.Zero(), true, null, null, null, null, null, null);
|
|
|
+ // c.position = Vector2.Zero();
|
|
|
+ //} else {
|
|
|
+ // let pos = settings.position || new Vector2(settings.x || 0, settings.y || 0);
|
|
|
+ // let size = (!settings.size && !settings.width && !settings.height) ? null : (settings.size || (new Size(settings.width || 0, settings.height || 0)));
|
|
|
+
|
|
|
+ // c.setupCanvas(scene, settings.id || null, size, 1, true, settings.cachingStrategy || Canvas2D.CACHESTRATEGY_DONTCACHE, settings.enableInteraction || true, settings.origin || Vector2.Zero(), settings.isVisible || true, settings.marginTop, settings.marginLeft, settings.marginRight, settings.marginBottom, settings.hAlignment || PrimitiveAlignment.AlignLeft, settings.vAlignment || PrimitiveAlignment.AlignTop);
|
|
|
+ // c.position = pos;
|
|
|
+ //}
|
|
|
+
|
|
|
+ //return c;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
}
|