Skip to content

Commit

Permalink
refactor image watermark to use mediaSize from pane
Browse files Browse the repository at this point in the history
  • Loading branch information
SlicedSilver committed Aug 8, 2024
1 parent 5340b16 commit 26636a2
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 70 deletions.
45 changes: 39 additions & 6 deletions src/plugins/image-watermark/pane-renderer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
CanvasRenderingTarget2D,
MediaCoordinatesRenderingScope,
Size,
} from 'fancy-canvas';

import { IPrimitivePaneRenderer } from '../../model/ipane-primitive';
Expand All @@ -15,8 +16,9 @@ export interface Placement {
}

export interface ImageWatermarkRendererOptions extends ImageWatermarkOptions {
placement: Placement | null;
imgElement: HTMLImageElement | null;
imgWidth: number;
imgHeight: number;
}

export class ImageWatermarkRenderer implements IPrimitivePaneRenderer {
Expand All @@ -29,15 +31,46 @@ export class ImageWatermarkRenderer implements IPrimitivePaneRenderer {
public draw(target: CanvasRenderingTarget2D): void {
target.useMediaCoordinateSpace((scope: MediaCoordinatesRenderingScope) => {
const ctx = scope.context;
const pos = this._data.placement;
if (!pos) {
const pos = this._determinePlacement(this._data, scope.mediaSize);
if (!pos || !this._data.imgElement) {
return;
}
if (!this._data.imgElement) {
throw new Error(`Image element missing.`);
}
ctx.globalAlpha = this._data.alpha ?? 1;
ctx.drawImage(this._data.imgElement, pos.x, pos.y, pos.width, pos.height);
});
}

private _determinePlacement(data: ImageWatermarkRendererOptions, paneSize: Size): Placement | null {
const { maxHeight, maxWidth, imgHeight, imgWidth, padding } = data;
const plotCentreX = Math.round(paneSize.width / 2);
const plotCentreY = Math.round(paneSize.height / 2);

const paddingSize = padding ?? 0;
let availableWidth = paneSize.width - 2 * paddingSize;
let availableHeight = paneSize.height - 2 * paddingSize;

if (maxHeight) {
availableHeight = Math.min(availableHeight, maxHeight);
}
if (maxWidth) {
availableWidth = Math.min(availableWidth, maxWidth);
}

const scaleX = availableWidth / imgWidth;
const scaleY = availableHeight / imgHeight;
const scaleToUse = Math.min(scaleX, scaleY);

const drawWidth = imgWidth * scaleToUse;
const drawHeight = imgHeight * scaleToUse;

const x = plotCentreX - 0.5 * drawWidth;
const y = plotCentreY - 0.5 * drawHeight;

return {
x,
y,
height: drawHeight,
width: drawWidth,
};
}
}
75 changes: 13 additions & 62 deletions src/plugins/image-watermark/pane-view.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { IChartApiBase } from '../../api/ichart-api';

import {
IPrimitivePaneRenderer,
IPrimitivePaneView,
Expand All @@ -10,14 +8,12 @@ import { ImageWatermarkOptions } from './options';
import {
ImageWatermarkRenderer,
ImageWatermarkRendererOptions,
Placement,
} from './pane-renderer';

interface ImageWatermarkPaneViewState<T> {
interface ImageWatermarkPaneViewState {
image: HTMLImageElement | null;
imageWidth: number;
imageHeight: number;
chart: IChartApiBase<T> | null;
}

export class ImageWatermarkPaneView<T> implements IPrimitivePaneView {
Expand All @@ -26,22 +22,18 @@ export class ImageWatermarkPaneView<T> implements IPrimitivePaneView {
private _image: HTMLImageElement | null = null;
private _imageWidth: number = 0; // don't draw until loaded
private _imageHeight: number = 0;
private _chart: IChartApiBase<T> | null = null;
private _placement: Placement | null = null;

public constructor(options: ImageWatermarkOptions) {
this._options = options;
this._rendererOptions = buildRendererOptions(
this._options,
this._placement,
this._image
this._image,
this._imageWidth,
this._imageHeight
);
}

public stateUpdate(state: ImageWatermarkPaneViewState<T>): void {
if (state.chart !== undefined) {
this._chart = state.chart;
}
public stateUpdate(state: ImageWatermarkPaneViewState): void {
if (state.imageWidth !== undefined) {
this._imageWidth = state.imageWidth;
}
Expand All @@ -64,70 +56,29 @@ export class ImageWatermarkPaneView<T> implements IPrimitivePaneView {
}

public update(): void {
this._placement = this._determinePlacement();
this._rendererOptions = buildRendererOptions(
this._options,
this._placement,
this._image
this._image,
this._imageWidth,
this._imageHeight
);
}

public renderer(): IPrimitivePaneRenderer {
return new ImageWatermarkRenderer(this._rendererOptions);
}

private _determinePlacement(): Placement | null {
if (!this._chart || !this._imageWidth || !this._imageHeight) {
return null;
}
const leftPriceScaleWidth = this._chart.priceScale('left').width();
const plotAreaWidth = this._chart.timeScale().width();
const startX = leftPriceScaleWidth;
const plotAreaHeight =
this._chart.chartElement().clientHeight -
this._chart.timeScale().height();

const plotCentreX = Math.round(plotAreaWidth / 2) + startX;
const plotCentreY = Math.round(plotAreaHeight / 2) + 0;

const padding = this._options.padding ?? 0;
let availableWidth = plotAreaWidth - 2 * padding;
let availableHeight = plotAreaHeight - 2 * padding;

if (this._options.maxHeight) {
availableHeight = Math.min(availableHeight, this._options.maxHeight);
}
if (this._options.maxWidth) {
availableWidth = Math.min(availableWidth, this._options.maxWidth);
}

const scaleX = availableWidth / this._imageWidth;
const scaleY = availableHeight / this._imageHeight;
const scaleToUse = Math.min(scaleX, scaleY);

const drawWidth = this._imageWidth * scaleToUse;
const drawHeight = this._imageHeight * scaleToUse;

const x = plotCentreX - 0.5 * drawWidth;
const y = plotCentreY - 0.5 * drawHeight;

return {
x,
y,
height: drawHeight,
width: drawWidth,
};
}
}

function buildRendererOptions(
options: ImageWatermarkOptions,
placement: Placement | null,
imgElement: HTMLImageElement | null
imgElement: HTMLImageElement | null,
imgWidth: number,
imgHeight: number
): ImageWatermarkRendererOptions {
return {
...options,
placement,
imgElement,
imgWidth,
imgHeight,
};
}
3 changes: 1 addition & 2 deletions src/plugins/image-watermark/primitive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class ImageWatermark<T = Time> implements IPanePrimitive<T> {
}

public attached(attachedParams: PaneAttachedParameter<T>): void {
const { requestUpdate, chart } = attachedParams;
const { requestUpdate } = attachedParams;
this._requestUpdate = requestUpdate;
this._imgElement = new Image();
this._imgElement.onload = () => {
Expand All @@ -75,7 +75,6 @@ export class ImageWatermark<T = Time> implements IPanePrimitive<T> {
imageHeight,
imageWidth,
image: this._imgElement,
chart,
})
);
if (this._requestUpdate) {
Expand Down

0 comments on commit 26636a2

Please sign in to comment.