|
@@ -37,11 +37,19 @@ class ImageViewer extends Widget implements DocumentRegistry.IReadyWidget {
|
|
|
* Construct a new image widget.
|
|
|
*/
|
|
|
constructor(context: DocumentRegistry.Context) {
|
|
|
- super({ node: Private.createNode() });
|
|
|
+ super();
|
|
|
this.context = context;
|
|
|
this.node.tabIndex = -1;
|
|
|
this.addClass(IMAGE_CLASS);
|
|
|
|
|
|
+ this._orientation = document.createElement('div');
|
|
|
+ this._orientation.textContent = '↸';
|
|
|
+ this._orientation.classList.add('jp-ImageViewer-orientation')
|
|
|
+ this.node.appendChild(this._orientation);
|
|
|
+
|
|
|
+ this._img = document.createElement('img');
|
|
|
+ this.node.appendChild(this._img);
|
|
|
+
|
|
|
this._onTitleChanged();
|
|
|
context.pathChanged.connect(this._onTitleChanged, this);
|
|
|
|
|
@@ -83,58 +91,56 @@ class ImageViewer extends Widget implements DocumentRegistry.IReadyWidget {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * The rotation of the image.
|
|
|
+ * The color inversion of the image.
|
|
|
*/
|
|
|
- get rotation(): number {
|
|
|
- return this._rotation;
|
|
|
+ get colorinversion(): number {
|
|
|
+ return this._colorinversion;
|
|
|
}
|
|
|
- set rotation(value: number) {
|
|
|
- if (value === this._rotation) {
|
|
|
+ set colorinversion(value: number) {
|
|
|
+ if (value === this._colorinversion) {
|
|
|
return;
|
|
|
}
|
|
|
- this._rotation = value % 360;
|
|
|
+ this._colorinversion = value;
|
|
|
this.updateStyle();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * The horizontal flip of the image.
|
|
|
+ * Reset rotation and flip transformations.
|
|
|
*/
|
|
|
- get horizontalflip(): number {
|
|
|
- return this._horizontalflip;
|
|
|
- }
|
|
|
- set horizontalflip(value: number) {
|
|
|
- if (value === this._horizontalflip) {
|
|
|
- return;
|
|
|
- }
|
|
|
- this._horizontalflip = value;
|
|
|
+ resetRotationFlip(): void {
|
|
|
+ this._matrix = [1, 0, 0, 1];
|
|
|
this.updateStyle();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * The vertical flip of the image.
|
|
|
+ * Rotate the image left (counter-clockwise).
|
|
|
*/
|
|
|
- get verticalflip(): number {
|
|
|
- return this._verticalflip;
|
|
|
+ rotateLeft(): void {
|
|
|
+ this._matrix = Private.prod(this._matrix, Private.rotateLeftMatrix);
|
|
|
+ this.updateStyle();
|
|
|
}
|
|
|
- set verticalflip(value: number) {
|
|
|
- if (value === this._verticalflip) {
|
|
|
- return;
|
|
|
- }
|
|
|
- this._verticalflip = value;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Rotate the image right (clockwise).
|
|
|
+ */
|
|
|
+ rotateRight(): void {
|
|
|
+ this._matrix = Private.prod(this._matrix, Private.rotateRightMatrix);
|
|
|
this.updateStyle();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * The color inversion of the image.
|
|
|
+ * Flip the image horizontally.
|
|
|
*/
|
|
|
- get colorinversion(): number {
|
|
|
- return this._colorinversion;
|
|
|
+ flipHorizontal(): void {
|
|
|
+ this._matrix = Private.prod(this._matrix, Private.flipHMatrix);
|
|
|
+ this.updateStyle();
|
|
|
}
|
|
|
- set colorinversion(value: number) {
|
|
|
- if (value === this._colorinversion) {
|
|
|
- return;
|
|
|
- }
|
|
|
- this._colorinversion = value;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Flip the image vertically.
|
|
|
+ */
|
|
|
+ flipVertical(): void {
|
|
|
+ this._matrix = Private.prod(this._matrix, Private.flipVMatrix);
|
|
|
this.updateStyle();
|
|
|
}
|
|
|
|
|
@@ -172,31 +178,25 @@ class ImageViewer extends Widget implements DocumentRegistry.IReadyWidget {
|
|
|
return;
|
|
|
}
|
|
|
let content = context.model.toString();
|
|
|
- let src = `data:${cm.mimetype};${cm.format},${content}`;
|
|
|
- let node = this.node.querySelector('img') as HTMLImageElement;
|
|
|
- node.setAttribute('src', src);
|
|
|
+ this._img.src = `data:${cm.mimetype};${cm.format},${content}`;
|
|
|
}
|
|
|
|
|
|
private updateStyle(): void {
|
|
|
- let transformString: string;
|
|
|
- let filterString: string;
|
|
|
-
|
|
|
- transformString = `translate(-50%,-50%) `;
|
|
|
- transformString += `scale(${this._scale * this._horizontalflip},${this._scale * this._verticalflip}) `;
|
|
|
- transformString += `rotate(${this._rotation}deg)`;
|
|
|
- filterString = `invert(${this._colorinversion})`;
|
|
|
+ let [a, b, c, d] = this._matrix;
|
|
|
+ let [tX, tY] = Private.prodVec(this._matrix, [1, 1]);
|
|
|
+ let transform = `matrix(${a}, ${b}, ${c}, ${d}, 0, 0) translate(${tX < 0 ? -100 : 0}%, ${tY < 0 ? -100 : 0}%) `;
|
|
|
+ this._img.style.transform = `scale(${this._scale}) ${transform}`;
|
|
|
+ this._orientation.style.transform = transform;
|
|
|
|
|
|
- let rotNode = this.node.querySelector('div') as HTMLElement;
|
|
|
- rotNode.style.transform = transformString;
|
|
|
- rotNode.style.filter = filterString;
|
|
|
+ this._img.style.filter = `invert(${this._colorinversion})`;
|
|
|
}
|
|
|
|
|
|
private _scale = 1;
|
|
|
- private _rotation = 0;
|
|
|
- private _horizontalflip = 1;
|
|
|
- private _verticalflip = 1;
|
|
|
+ private _matrix = [1, 0, 0, 1];
|
|
|
private _colorinversion = 0;
|
|
|
private _ready = new PromiseDelegate<void>();
|
|
|
+ private _img: HTMLImageElement;
|
|
|
+ private _orientation: HTMLDivElement;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -218,15 +218,43 @@ class ImageViewerFactory extends ABCWidgetFactory<ImageViewer, DocumentRegistry.
|
|
|
*/
|
|
|
namespace Private {
|
|
|
/**
|
|
|
- * Create the node for the image widget.
|
|
|
+ * Multiply 2x2 matrices.
|
|
|
*/
|
|
|
export
|
|
|
- function createNode(): HTMLElement {
|
|
|
- let node = document.createElement('div');
|
|
|
- let innerNode = document.createElement('div');
|
|
|
- let image = document.createElement('img');
|
|
|
- node.appendChild(innerNode);
|
|
|
- innerNode.appendChild(image);
|
|
|
- return node;
|
|
|
+ function prod([a11, a12, a21, a22]: number[], [b11, b12, b21, b22]: number[]): number[] {
|
|
|
+ return [a11 * b11 + a12 * b21, a11 * b12 + a12 * b22,
|
|
|
+ a21 * b11 + a22 * b21, a21 * b12 + a22 * b22];
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Multiply a 2x2 matrix and a 2x1 vector.
|
|
|
+ */
|
|
|
+ export
|
|
|
+ function prodVec([a11, a12, a21, a22]: number[], [b1, b2]: number[]): number[] {
|
|
|
+ return [a11 * b1 + a12 * b2, a21 * b1 + a22 * b2];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Clockwise rotation transformation matrix.
|
|
|
+ */
|
|
|
+ export
|
|
|
+ const rotateRightMatrix = [0, 1, -1, 0];
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Counter-clockwise rotation transformation matrix.
|
|
|
+ */
|
|
|
+ export
|
|
|
+ const rotateLeftMatrix = [0, -1, 1, 0];
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Horizontal flip transformation matrix.
|
|
|
+ */
|
|
|
+ export
|
|
|
+ const flipHMatrix = [-1, 0, 0, 1];
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Vertical flip transformation matrix.
|
|
|
+ */
|
|
|
+ export
|
|
|
+ const flipVMatrix = [1, 0, 0, -1];
|
|
|
}
|