|
@@ -34,6 +34,8 @@ export class Image extends Control {
|
|
|
private _sliceTop: number;
|
|
|
private _sliceBottom: number;
|
|
|
|
|
|
+ private _detectPointerOnOpaqueOnly: boolean;
|
|
|
+
|
|
|
/**
|
|
|
* Observable notified when the content is loaded
|
|
|
*/
|
|
@@ -66,6 +68,22 @@ export class Image extends Control {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
+ * Gets or sets a boolean indicating if pointers should only be validated on pixels with alpha > 0.
|
|
|
+ * Beware using this as this will comsume more memory as the image has to be stored twice
|
|
|
+ */
|
|
|
+ public get detectPointerOnOpaqueOnly(): boolean {
|
|
|
+ return this._detectPointerOnOpaqueOnly;
|
|
|
+ }
|
|
|
+
|
|
|
+ public set detectPointerOnOpaqueOnly(value: boolean) {
|
|
|
+ if (this._detectPointerOnOpaqueOnly === value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this._detectPointerOnOpaqueOnly = value;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
* Gets or sets the left value for slicing (9-patch)
|
|
|
*/
|
|
|
public get sliceLeft(): number {
|
|
@@ -405,6 +423,35 @@ export class Image extends Control {
|
|
|
this.source = url;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * Tests if a given coordinates belong to the current control
|
|
|
+ * @param x defines x coordinate to test
|
|
|
+ * @param y defines y coordinate to test
|
|
|
+ * @returns true if the coordinates are inside the control
|
|
|
+ */
|
|
|
+ public contains(x: number, y: number): boolean {
|
|
|
+ if (!super.contains(x, y)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!this._detectPointerOnOpaqueOnly || !Image._WorkingCanvas) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ const canvas = Image._WorkingCanvas;
|
|
|
+ const context = canvas.getContext("2d")!;
|
|
|
+ const width = this._currentMeasure.width | 0;
|
|
|
+ const height = this._currentMeasure.height | 0;
|
|
|
+ const imageData = context.getImageData(0, 0, width, height).data;
|
|
|
+
|
|
|
+ x = (x - this._currentMeasure.left) | 0;
|
|
|
+ y = (y - this._currentMeasure.top) | 0;
|
|
|
+
|
|
|
+ const pickedPixel = imageData[(x + y * this._currentMeasure.width) * 4 + 3];
|
|
|
+
|
|
|
+ return pickedPixel > 0;
|
|
|
+ }
|
|
|
+
|
|
|
protected _getTypeName(): string {
|
|
|
return "Image";
|
|
|
}
|
|
@@ -428,6 +475,8 @@ export class Image extends Control {
|
|
|
break;
|
|
|
case Image.STRETCH_UNIFORM:
|
|
|
break;
|
|
|
+ case Image.STRETCH_NINE_PATCH:
|
|
|
+ break;
|
|
|
case Image.STRETCH_EXTEND:
|
|
|
if (this._autoScale) {
|
|
|
this.synchronizeSizeWithContent();
|
|
@@ -443,6 +492,42 @@ export class Image extends Control {
|
|
|
super._processMeasures(parentMeasure, context);
|
|
|
}
|
|
|
|
|
|
+ private _prepareWorkingCanvasForOpaqueDetection() {
|
|
|
+ if (!this._detectPointerOnOpaqueOnly) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!Image._WorkingCanvas) {
|
|
|
+ Image._WorkingCanvas = document.createElement('canvas');
|
|
|
+ }
|
|
|
+ const canvas = Image._WorkingCanvas;
|
|
|
+ const width = this._currentMeasure.width;
|
|
|
+ const height = this._currentMeasure.height;
|
|
|
+ const context = canvas.getContext("2d")!;
|
|
|
+
|
|
|
+ canvas.width = width;
|
|
|
+ canvas.height = height;
|
|
|
+
|
|
|
+ context.clearRect(0, 0, width, height);
|
|
|
+ }
|
|
|
+
|
|
|
+ private _drawImage(context: CanvasRenderingContext2D, sx: number, sy: number, sw: number, sh: number, tx: number, ty: number, tw: number, th: number) {
|
|
|
+ context.drawImage(this._domImage,
|
|
|
+ sx, sy, sw, sh,
|
|
|
+ tx, ty, tw, th);
|
|
|
+
|
|
|
+ if (!this._detectPointerOnOpaqueOnly) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const canvas = Image._WorkingCanvas!;
|
|
|
+ context = canvas.getContext("2d")!;
|
|
|
+
|
|
|
+ context.drawImage(this._domImage,
|
|
|
+ sx, sy, sw, sh,
|
|
|
+ tx - this._currentMeasure.left, ty - this._currentMeasure.top, tw, th);
|
|
|
+ }
|
|
|
+
|
|
|
public _draw(context: CanvasRenderingContext2D): void {
|
|
|
context.save();
|
|
|
|
|
@@ -472,15 +557,17 @@ export class Image extends Control {
|
|
|
height = this.cellHeight;
|
|
|
}
|
|
|
|
|
|
+ this._prepareWorkingCanvasForOpaqueDetection();
|
|
|
+
|
|
|
this._applyStates(context);
|
|
|
if (this._loaded) {
|
|
|
switch (this._stretch) {
|
|
|
case Image.STRETCH_NONE:
|
|
|
- context.drawImage(this._domImage, x, y, width, height,
|
|
|
+ this._drawImage(context, x, y, width, height,
|
|
|
this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
|
|
|
break;
|
|
|
case Image.STRETCH_FILL:
|
|
|
- context.drawImage(this._domImage, x, y, width, height,
|
|
|
+ this._drawImage(context, x, y, width, height,
|
|
|
this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
|
|
|
break;
|
|
|
case Image.STRETCH_UNIFORM:
|
|
@@ -490,11 +577,11 @@ export class Image extends Control {
|
|
|
var centerX = (this._currentMeasure.width - width * ratio) / 2;
|
|
|
var centerY = (this._currentMeasure.height - height * ratio) / 2;
|
|
|
|
|
|
- context.drawImage(this._domImage, x, y, width, height,
|
|
|
+ this._drawImage(context, x, y, width, height,
|
|
|
this._currentMeasure.left + centerX, this._currentMeasure.top + centerY, width * ratio, height * ratio);
|
|
|
break;
|
|
|
case Image.STRETCH_EXTEND:
|
|
|
- context.drawImage(this._domImage, x, y, width, height,
|
|
|
+ this._drawImage(context, x, y, width, height,
|
|
|
this._currentMeasure.left, this._currentMeasure.top, this._currentMeasure.width, this._currentMeasure.height);
|
|
|
break;
|
|
|
case Image.STRETCH_NINE_PATCH:
|
|
@@ -507,7 +594,7 @@ export class Image extends Control {
|
|
|
}
|
|
|
|
|
|
private _renderCornerPatch(context: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, targetX: number, targetY: number): void {
|
|
|
- context.drawImage(this._domImage, x, y, width, height, this._currentMeasure.left + targetX, this._currentMeasure.top + targetY, width, height);
|
|
|
+ this._drawImage(context, x, y, width, height, this._currentMeasure.left + targetX, this._currentMeasure.top + targetY, width, height);
|
|
|
}
|
|
|
|
|
|
private _renderNinePatch(context: CanvasRenderingContext2D): void {
|
|
@@ -541,20 +628,20 @@ export class Image extends Control {
|
|
|
this._renderCornerPatch(context, this._sliceRight, this._sliceBottom, rightWidth, height - this._sliceBottom, this._currentMeasure.width - rightWidth, targetTopHeight);
|
|
|
|
|
|
// Center
|
|
|
- context.drawImage(this._domImage, this._sliceLeft, this._sliceTop, centerWidth, this._sliceBottom - this._sliceTop + 1,
|
|
|
+ this._drawImage(context, this._sliceLeft, this._sliceTop, centerWidth, this._sliceBottom - this._sliceTop + 1,
|
|
|
this._currentMeasure.left + leftWidth, this._currentMeasure.top + topHeight, targetCenterWidth, targetTopHeight - topHeight + 1);
|
|
|
|
|
|
// Borders
|
|
|
- context.drawImage(this._domImage, left, this._sliceTop, leftWidth, this._sliceBottom - this._sliceTop,
|
|
|
+ this._drawImage(context, left, this._sliceTop, leftWidth, this._sliceBottom - this._sliceTop,
|
|
|
this._currentMeasure.left, this._currentMeasure.top + topHeight, leftWidth, targetTopHeight - topHeight);
|
|
|
|
|
|
- context.drawImage(this._domImage, this._sliceRight, this._sliceTop, leftWidth, this._sliceBottom - this._sliceTop,
|
|
|
+ this._drawImage(context, this._sliceRight, this._sliceTop, leftWidth, this._sliceBottom - this._sliceTop,
|
|
|
this._currentMeasure.left + this._currentMeasure.width - rightWidth, this._currentMeasure.top + topHeight, leftWidth, targetTopHeight - topHeight);
|
|
|
|
|
|
- context.drawImage(this._domImage, this._sliceLeft, top, centerWidth, topHeight,
|
|
|
+ this._drawImage(context, this._sliceLeft, top, centerWidth, topHeight,
|
|
|
this._currentMeasure.left + leftWidth, this._currentMeasure.top, targetCenterWidth, topHeight);
|
|
|
|
|
|
- context.drawImage(this._domImage, this._sliceLeft, this._sliceBottom, centerWidth, bottomHeight,
|
|
|
+ this._drawImage(context, this._sliceLeft, this._sliceBottom, centerWidth, bottomHeight,
|
|
|
this._currentMeasure.left + leftWidth, this._currentMeasure.top + targetTopHeight, targetCenterWidth, bottomHeight);
|
|
|
}
|
|
|
|