UNPKG

fcr-core

Version:

Core APIs for building online scenes

273 lines (271 loc) 8.35 kB
import "core-js/modules/es.array.push.js"; import { md5 } from 'js-md5'; import { ApplianceNames, FcrBoardShape, FcrBoardToolType, ShapeType } from './enum'; import { EStrokeType } from '@netless/appliance-plugin'; export const heightPerTool = 36; export const heightPerColor = 18; export const defaultToolsRetain = heightPerTool * 6; export const verticalPadding = 10; export const sceneNavHeight = heightPerTool + verticalPadding; export const widgetContainerClassName = 'netless-whiteboard-wrapper'; export const layoutContentClassName = 'fcr-layout-content-main-view'; export const videoRowClassName = 'fcr-layout-content-video-list-row'; export const toolbarClassName = 'fcr-board-toolbar'; export const windowClassName = 'netless-whiteboard-wrapper'; export const WINDOW_TITLE_HEIGHT = 28; // width / height export const WINDOW_ASPECT_RATIO = 1836 / 847; export const WINDOW_MIN_SIZE = { width: 653, height: 336 }; export const WINDOW_REMAIN_SIZE = { width: 783, height: 388 }; export const WINDOW_REMAIN_POSITION = { x: 0, y: 171 }; /** * 根据 * @param imageInnerSize * @returns */ export const getImageSize = (imageInnerSize, containerSize) => { const windowSize = containerSize; const widthHeightProportion = imageInnerSize.width / imageInnerSize.height; const maxSize = 960; if (imageInnerSize.width > maxSize && windowSize.width > maxSize || imageInnerSize.height > maxSize && windowSize.height > maxSize) { if (widthHeightProportion > 1) { return { width: maxSize, height: maxSize / widthHeightProportion }; } else { return { width: maxSize * widthHeightProportion, height: maxSize }; } } else { if (imageInnerSize.width > windowSize.width || imageInnerSize.height > windowSize.height) { if (widthHeightProportion > 1) { return { width: windowSize.width, height: windowSize.width / widthHeightProportion }; } else { return { width: windowSize.height * widthHeightProportion, height: windowSize.height }; } } else { return { width: imageInnerSize.width, height: imageInnerSize.height }; } } }; /** * * @param url * @returns */ export const fetchImageInfoByUrl = async (url, containerSize) => { try { const res = await fetch(url); const blob = await res.blob(); const contentType = blob.type; const image = new Image(); const reader = new FileReader(); const file = new File([blob], url, { type: contentType }); const result = await new Promise(resolve => { reader.readAsDataURL(blob); reader.onload = () => { image.addEventListener('load', () => { const uuid = md5(reader.result); const res = getImageSize(image, containerSize); const result = { width: res.width, height: res.height, file: file, url, uuid }; resolve(result); }, false); image.src = reader.result; }; }); return result; } catch (err) { throw err; } }; export const mergeCanvasImage = async scenes => { let width = 0, height = 0; const bigCanvas = document.createElement('canvas'); const ctx = bigCanvas.getContext('2d'); const canvasArray = []; for (const canvasPromise of scenes) { const canvas = await canvasPromise(); if (canvas) { width = Math.max(canvas.width, width); height = Math.max(canvas.height, height); canvasArray.push(canvas); } } bigCanvas.setAttribute('width', `${width}`); bigCanvas.setAttribute('height', `${height * canvasArray.length}`); canvasArray.forEach((canvas, index) => { ctx && ctx.drawImage(canvas, 0, index * height, width, height); }); return bigCanvas; }; export const textColors = ['#ffffff', '#9b9b9b', '#4a4a4a', '#000000', '#d0021b', '#f5a623', '#f8e71c', '#7ed321', '#9013fe', '#50e3c2', '#0073ff', '#ffc8e2']; export const defaultStrokeColor = { r: 0, g: 115, b: 255 }; export const defaultTextSize = 24; export const mediaMimeTypes = { opus: 'video/ogg', ogv: 'video/ogg', mp4: 'video/mp4', mov: 'video/mp4', m4v: 'video/mp4', mkv: 'video/x-matroska', m4a: 'audio/mp4', mp3: 'audio/mpeg', aac: 'audio/aac', caf: 'audio/x-caf', flac: 'audio/flac', oga: 'audio/ogg', wav: 'audio/wav', m3u8: 'application/x-mpegURL', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', png: 'image/png', svg: 'image/svg+xml', webp: 'image/webp' }; export const convertToNetlessBoardTool = tool => { switch (tool) { case FcrBoardToolType.SELECTOR: return [ApplianceNames.selector]; case FcrBoardToolType.ERASER: return [ApplianceNames.pencilEraser]; case FcrBoardToolType.LASER_POINTER: return [ApplianceNames.laserPointer]; case FcrBoardToolType.HAND: return [ApplianceNames.hand]; case FcrBoardToolType.TEXT: return [ApplianceNames.text]; case FcrBoardToolType.ARROW: return [ApplianceNames.arrow]; case FcrBoardToolType.RECTANGLE: return [ApplianceNames.rectangle]; case FcrBoardToolType.ELLIPSE: return [ApplianceNames.ellipse]; case FcrBoardToolType.STRAIGHT: return [ApplianceNames.straight]; case FcrBoardToolType.CURVE: return [ApplianceNames.pencil]; case FcrBoardToolType.TRIANGLE: return [ApplianceNames.shape, ShapeType.Triangle]; case FcrBoardToolType.PENTAGRAM: return [ApplianceNames.shape, ShapeType.Pentagram]; case FcrBoardToolType.RHOMBUS: return [ApplianceNames.shape, ShapeType.Rhombus]; case FcrBoardToolType.DOTTED_LINE: case FcrBoardToolType.LONG_DOTTED_LINE: return [ApplianceNames.straight]; case FcrBoardToolType.NONE: return [ApplianceNames.clicker]; default: return []; } }; export const convertToNetlessStorkeType = type => { switch (type) { case FcrBoardToolType.DOTTED_LINE: return EStrokeType.Dotted; case FcrBoardToolType.LONG_DOTTED_LINE: return EStrokeType.LongDotted; default: return EStrokeType.Normal; } }; export const convertToFcrBoardToolShape = (tool, shape) => { switch (tool) { case ApplianceNames.selector: return [FcrBoardToolType.SELECTOR]; case ApplianceNames.eraser: return [FcrBoardToolType.ERASER]; case ApplianceNames.laserPointer: return [FcrBoardToolType.LASER_POINTER]; case ApplianceNames.text: return [FcrBoardToolType.TEXT]; case ApplianceNames.hand: return [FcrBoardToolType.HAND]; } switch (`${tool || ''}${shape || ''}`) { case `${ApplianceNames.rectangle}`: return [, FcrBoardShape.Rectangle]; case `${ApplianceNames.ellipse}`: return [, FcrBoardShape.Ellipse]; case `${ApplianceNames.straight}`: return [, FcrBoardShape.Straight]; case `${ApplianceNames.arrow}`: return [, FcrBoardShape.Arrow]; case `${ApplianceNames.pencil}`: return [, FcrBoardShape.Curve]; case `${ApplianceNames.shape}${ShapeType.Triangle}`: return [, FcrBoardShape.Triangle]; case `${ApplianceNames.shape, ShapeType.Pentagram}`: return [, FcrBoardShape.Pentagram]; case `${ApplianceNames.shape}${ShapeType.Rhombus}`: return [, FcrBoardShape.Rhombus]; } return []; }; export const hexColorToWhiteboardColor = val => { const pattern = /^(#?)[a-fA-F0-9]{6}$/; // 16进制颜色校验规则 if (!pattern.test(val)) { return [255, 255, 255]; } const v = val.replace(/#/, ''); const rgbArr = []; for (let i = 0; i < 3; i++) { const item = v.substring(i * 2, i * 2 + 2); const num = parseInt(item, 16); rgbArr.push(num); } return rgbArr; }; export const src2DataURL = src => { return new Promise((resolve, reject) => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const image = new Image(); image.onload = () => { canvas.setAttribute('width', `${image.width}`); canvas.setAttribute('height', `${image.height}`); ctx?.drawImage(image, 0, 0); resolve(canvas.toDataURL('image/jpeg', 0.8)); }; image.onerror = () => { reject('error'); }; image.crossOrigin = 'anonymous'; image.src = src; }); };