Resize patterns
Optimize dark patterns
This commit is contained in:
parent
da5f6a87c8
commit
45b5cedeb7
@ -85,6 +85,7 @@ export default class Chat extends EventListenerBase<{
|
|||||||
public patternCanvas: HTMLCanvasElement;
|
public patternCanvas: HTMLCanvasElement;
|
||||||
public backgroundTempId: number;
|
public backgroundTempId: number;
|
||||||
public setBackgroundPromise: Promise<void>;
|
public setBackgroundPromise: Promise<void>;
|
||||||
|
// public renderDarkPattern: () => Promise<void>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public appImManager: AppImManager,
|
public appImManager: AppImManager,
|
||||||
@ -159,6 +160,7 @@ export default class Chat extends EventListenerBase<{
|
|||||||
this.patternRenderer =
|
this.patternRenderer =
|
||||||
this.gradientCanvas =
|
this.gradientCanvas =
|
||||||
this.patternCanvas =
|
this.patternCanvas =
|
||||||
|
// this.renderDarkPattern =
|
||||||
undefined;
|
undefined;
|
||||||
|
|
||||||
const intensity = theme.background.intensity && theme.background.intensity / 100;
|
const intensity = theme.background.intensity && theme.background.intensity / 100;
|
||||||
@ -179,11 +181,28 @@ export default class Chat extends EventListenerBase<{
|
|||||||
patternRenderer = this.patternRenderer = ChatBackgroundPatternRenderer.getInstance({
|
patternRenderer = this.patternRenderer = ChatBackgroundPatternRenderer.getInstance({
|
||||||
url,
|
url,
|
||||||
width: rect.width,
|
width: rect.width,
|
||||||
height: rect.height
|
height: rect.height,
|
||||||
|
mask: isDarkPattern
|
||||||
});
|
});
|
||||||
|
|
||||||
patternCanvas = this.patternCanvas = patternRenderer.createCanvas();
|
patternCanvas = this.patternCanvas = patternRenderer.createCanvas();
|
||||||
patternCanvas.classList.add('chat-background-item-canvas', 'chat-background-item-pattern-canvas');
|
patternCanvas.classList.add('chat-background-item-canvas', 'chat-background-item-pattern-canvas');
|
||||||
|
|
||||||
|
if(isDarkPattern) {
|
||||||
|
item.classList.add('is-dark');
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(isDarkPattern) {
|
||||||
|
// this.renderDarkPattern = () => {
|
||||||
|
// return patternRenderer.exportCanvasPatternToImage(patternCanvas).then(url => {
|
||||||
|
// if(this.backgroundTempId !== tempId) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// gradientCanvas.style.webkitMaskImage = `url(${url})`;
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
// }
|
||||||
} else if(theme.background.slug) {
|
} else if(theme.background.slug) {
|
||||||
item.classList.add('is-image');
|
item.classList.add('is-image');
|
||||||
}
|
}
|
||||||
@ -236,7 +255,11 @@ export default class Chat extends EventListenerBase<{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const append = [gradientCanvas, isDarkPattern ? undefined : patternCanvas].filter(Boolean);
|
const append = [
|
||||||
|
gradientCanvas,
|
||||||
|
// isDarkPattern && this.renderDarkPattern ? undefined : patternCanvas
|
||||||
|
patternCanvas
|
||||||
|
].filter(Boolean);
|
||||||
if(append.length) {
|
if(append.length) {
|
||||||
item.append(...append);
|
item.append(...append);
|
||||||
}
|
}
|
||||||
@ -261,18 +284,16 @@ export default class Chat extends EventListenerBase<{
|
|||||||
if(patternRenderer) {
|
if(patternRenderer) {
|
||||||
const renderPatternPromise = patternRenderer.renderToCanvas(patternCanvas);
|
const renderPatternPromise = patternRenderer.renderToCanvas(patternCanvas);
|
||||||
renderPatternPromise.then(() => {
|
renderPatternPromise.then(() => {
|
||||||
let promise: Promise<any>;
|
|
||||||
if(isDarkPattern) {
|
|
||||||
promise = patternRenderer.exportCanvasPatternToImage(patternCanvas).then(url => {
|
|
||||||
if(this.backgroundTempId !== tempId) {
|
if(this.backgroundTempId !== tempId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gradientCanvas.style.webkitMaskImage = `url(${url})`;
|
let promise: Promise<any>;
|
||||||
});
|
// if(isDarkPattern && this.renderDarkPattern) {
|
||||||
} else {
|
// promise = this.renderDarkPattern();
|
||||||
|
// } else {
|
||||||
promise = Promise.resolve();
|
promise = Promise.resolve();
|
||||||
}
|
// }
|
||||||
|
|
||||||
promise.then(cb);
|
promise.then(cb);
|
||||||
});
|
});
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IS_SAFARI } from "../../environment/userAgent";
|
|
||||||
import { indexOfAndSplice } from "../../helpers/array";
|
import { indexOfAndSplice } from "../../helpers/array";
|
||||||
import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
|
import { renderImageFromUrlPromise } from "../../helpers/dom/renderImageFromUrl";
|
||||||
import { deepEqual } from "../../helpers/object";
|
import { deepEqual } from "../../helpers/object";
|
||||||
@ -12,19 +11,21 @@ import { deepEqual } from "../../helpers/object";
|
|||||||
type ChatBackgroundPatternRendererInitOptions = {
|
type ChatBackgroundPatternRendererInitOptions = {
|
||||||
url: string,
|
url: string,
|
||||||
width: number,
|
width: number,
|
||||||
height: number
|
height: number,
|
||||||
|
mask?: boolean
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class ChatBackgroundPatternRenderer {
|
export default class ChatBackgroundPatternRenderer {
|
||||||
private static INSTANCES: ChatBackgroundPatternRenderer[] = [];
|
private static INSTANCES: ChatBackgroundPatternRenderer[] = [];
|
||||||
|
|
||||||
private pattern: CanvasPattern;
|
// private pattern: CanvasPattern;
|
||||||
private objectUrl: string;
|
private objectUrl: string;
|
||||||
private options: ChatBackgroundPatternRendererInitOptions;
|
private options: ChatBackgroundPatternRendererInitOptions;
|
||||||
private canvases: Set<HTMLCanvasElement>;
|
private canvases: Set<HTMLCanvasElement>;
|
||||||
private createCanvasPatternPromise: Promise<void>;
|
// private createCanvasPatternPromise: Promise<CanvasPattern>;
|
||||||
private exportCanvasPatternToImagePromise: Promise<string>;
|
// private exportCanvasPatternToImagePromise: Promise<string>;
|
||||||
// private img: HTMLImageElement;
|
private renderImageFromUrlPromise: Promise<HTMLImageElement>;
|
||||||
|
private img: HTMLImageElement;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.canvases = new Set();
|
this.canvases = new Set();
|
||||||
@ -45,21 +46,38 @@ export default class ChatBackgroundPatternRenderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public init(options: ChatBackgroundPatternRendererInitOptions) {
|
public init(options: ChatBackgroundPatternRendererInitOptions) {
|
||||||
|
// if(this.options) {
|
||||||
|
// if(this.options.width !== options.width || this.options.height !== options.height) {
|
||||||
|
// this.createCanvasPatternPromise =
|
||||||
|
// this.pattern =
|
||||||
|
// this.exportCanvasPatternToImagePromise =
|
||||||
|
// undefined;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderToCanvas(canvas: HTMLCanvasElement) {
|
public renderToCanvas(canvas: HTMLCanvasElement) {
|
||||||
return this.createCanvasPattern(canvas).then(() => {
|
// return this.createCanvasPattern(canvas).then(() => {
|
||||||
|
// return this.fillCanvas(canvas);
|
||||||
|
// });
|
||||||
|
|
||||||
|
return this.renderImageFromUrl(this.options.url).then(() => {
|
||||||
return this.fillCanvas(canvas);
|
return this.fillCanvas(canvas);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private createCanvasPattern(canvas: HTMLCanvasElement) {
|
private renderImageFromUrl(url: string) {
|
||||||
if(this.createCanvasPatternPromise) return this.createCanvasPatternPromise;
|
if(this.renderImageFromUrlPromise) return this.renderImageFromUrlPromise;
|
||||||
return this.createCanvasPatternPromise = new Promise((resolve) => {
|
const img = this.img = document.createElement('img');
|
||||||
const img = document.createElement('img');
|
|
||||||
img.crossOrigin = 'anonymous';
|
img.crossOrigin = 'anonymous';
|
||||||
renderImageFromUrlPromise(img, this.options.url, false).then(() => {
|
return this.renderImageFromUrlPromise = renderImageFromUrlPromise(img, url, false).then(() => img);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* private createCanvasPattern(canvas: HTMLCanvasElement) {
|
||||||
|
if(this.createCanvasPatternPromise) return this.createCanvasPatternPromise;
|
||||||
|
return this.createCanvasPatternPromise = this.renderImageFromUrl(this.options.url).then((img) => {
|
||||||
let createPatternFrom: HTMLImageElement | HTMLCanvasElement;
|
let createPatternFrom: HTMLImageElement | HTMLCanvasElement;
|
||||||
if(IS_SAFARI) {
|
if(IS_SAFARI) {
|
||||||
const canvas = createPatternFrom = document.createElement('canvas');
|
const canvas = createPatternFrom = document.createElement('canvas');
|
||||||
@ -71,10 +89,11 @@ export default class ChatBackgroundPatternRenderer {
|
|||||||
createPatternFrom = img;
|
createPatternFrom = img;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this.img = img;
|
const perf = performance.now();
|
||||||
this.pattern = canvas.getContext('2d').createPattern(createPatternFrom, 'repeat-x');
|
this.pattern = canvas.getContext('2d').createPattern(createPatternFrom, 'repeat-x');
|
||||||
resolve();
|
console.warn('creating pattern time:', performance.now() - perf);
|
||||||
});
|
|
||||||
|
return this.pattern;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +105,7 @@ export default class ChatBackgroundPatternRenderer {
|
|||||||
resolve(newUrl);
|
resolve(newUrl);
|
||||||
}, 'image/png');
|
}, 'image/png');
|
||||||
});
|
});
|
||||||
}
|
} */
|
||||||
|
|
||||||
public cleanup(canvas: HTMLCanvasElement) {
|
public cleanup(canvas: HTMLCanvasElement) {
|
||||||
this.canvases.delete(canvas);
|
this.canvases.delete(canvas);
|
||||||
@ -102,9 +121,34 @@ export default class ChatBackgroundPatternRenderer {
|
|||||||
|
|
||||||
public fillCanvas(canvas: HTMLCanvasElement) {
|
public fillCanvas(canvas: HTMLCanvasElement) {
|
||||||
const context = canvas.getContext('2d');
|
const context = canvas.getContext('2d');
|
||||||
context.fillStyle = this.pattern;
|
if(context.fillStyle instanceof CanvasPattern) {
|
||||||
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// const perf = performance.now();
|
||||||
|
const img = this.img;
|
||||||
|
|
||||||
|
let imageWidth = img.width, imageHeight = img.height;
|
||||||
|
// if(imageHeight < canvas.height) {
|
||||||
|
const ratio = canvas.height / imageHeight;
|
||||||
|
imageWidth *= ratio;
|
||||||
|
imageHeight = canvas.height;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if(this.options.mask) {
|
||||||
|
context.fillStyle = '#000';
|
||||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
// context.drawImage(this.img, 0, 0, canvas.width, canvas.height);
|
context.globalCompositeOperation = 'destination-out';
|
||||||
|
} else {
|
||||||
|
context.globalCompositeOperation = 'source-over';
|
||||||
|
}
|
||||||
|
|
||||||
|
for(let x = 0; x < canvas.width; x += imageWidth) {
|
||||||
|
context.drawImage(img, x, 0);
|
||||||
|
}
|
||||||
|
// context.fillStyle = this.pattern;
|
||||||
|
// context.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
// console.warn('fill canvas time', performance.now() - perf);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setCanvasDimensions(canvas: HTMLCanvasElement) {
|
public setCanvasDimensions(canvas: HTMLCanvasElement) {
|
||||||
@ -118,4 +162,34 @@ export default class ChatBackgroundPatternRenderer {
|
|||||||
this.setCanvasDimensions(canvas);
|
this.setCanvasDimensions(canvas);
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public resize(width: number, height: number) {
|
||||||
|
this.init({
|
||||||
|
...this.options,
|
||||||
|
width,
|
||||||
|
height
|
||||||
|
});
|
||||||
|
|
||||||
|
const promises: Promise<any>[] = [];
|
||||||
|
for(const canvas of this.canvases) {
|
||||||
|
this.setCanvasDimensions(canvas);
|
||||||
|
promises.push(this.renderToCanvas(canvas));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.all(promises);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static resizeInstances(width: number, height: number) {
|
||||||
|
return Promise.all(this.INSTANCES.map(instance => instance.resize(width, height)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* public setResizeMode(resizing: boolean) {
|
||||||
|
const canvases = Array.from(this.canvases);
|
||||||
|
const canvas = canvases[canvases.length - 1];
|
||||||
|
canvas.style.display = resizing ? 'none' : '';
|
||||||
|
const img = this.img;
|
||||||
|
img.style.display = resizing ? '' : 'none';
|
||||||
|
|
||||||
|
return {img, canvas};
|
||||||
|
} */
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ export default function renderImageFromUrl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function renderImageFromUrlPromise(elem: Parameters<typeof renderImageFromUrl>[0], url: string, useCache?: boolean) {
|
export function renderImageFromUrlPromise(elem: Parameters<typeof renderImageFromUrl>[0], url: string, useCache?: boolean) {
|
||||||
return new Promise((resolve) => {
|
return new Promise<Event>((resolve) => {
|
||||||
renderImageFromUrl(elem, url, resolve, useCache);
|
renderImageFromUrl(elem, url, resolve, useCache);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,7 @@ import htmlToSpan from '../../helpers/dom/htmlToSpan';
|
|||||||
import getVisibleRect from '../../helpers/dom/getVisibleRect';
|
import getVisibleRect from '../../helpers/dom/getVisibleRect';
|
||||||
import { simulateClickEvent } from '../../helpers/dom/clickEvent';
|
import { simulateClickEvent } from '../../helpers/dom/clickEvent';
|
||||||
import appReactionsManager from './appReactionsManager';
|
import appReactionsManager from './appReactionsManager';
|
||||||
|
import ChatBackgroundPatternRenderer from '../../components/chat/patternRenderer';
|
||||||
|
|
||||||
//console.log('appImManager included33!');
|
//console.log('appImManager included33!');
|
||||||
|
|
||||||
@ -229,11 +230,17 @@ export class AppImManager {
|
|||||||
this.appendEmojiAnimationContainer(to);
|
this.appendEmojiAnimationContainer(to);
|
||||||
});
|
});
|
||||||
|
|
||||||
const resizeBackgroundDebounced = debounce(() => {
|
|
||||||
this.setBackground(this.lastBackgroundUrl, false);
|
|
||||||
}, 200, false, true);
|
|
||||||
mediaSizes.addEventListener('resize', () => {
|
mediaSizes.addEventListener('resize', () => {
|
||||||
resizeBackgroundDebounced();
|
// const perf = performance.now();
|
||||||
|
const rect = this.chatsContainer.getBoundingClientRect();
|
||||||
|
ChatBackgroundPatternRenderer.resizeInstances(rect.width, rect.height).then(() => {
|
||||||
|
// this.log.warn('resize bg time:', performance.now() - perf);
|
||||||
|
// for(const chat of this.chats) {
|
||||||
|
// if(chat.renderDarkPattern) {
|
||||||
|
// chat.renderDarkPattern();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
rootScope.addEventListener('history_focus', (e) => {
|
rootScope.addEventListener('history_focus', (e) => {
|
||||||
|
@ -722,7 +722,7 @@ $background-transition-total-time: #{$input-transition-time - $background-transi
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-pattern-canvas {
|
&:not(.is-dark) &-pattern-canvas {
|
||||||
mix-blend-mode: overlay;
|
mix-blend-mode: overlay;
|
||||||
// height: 100%;
|
// height: 100%;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user