commit message

This commit is contained in:
Chopper
2021-05-13 11:03:32 +08:00
commit 23804939eb
2158 changed files with 149684 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
/// <reference types="@dcloudio/types" />
/** 当前环境类型 */
export declare type UniPlatforms = 'app-plus' | 'app-plus-nvue' | 'h5' | 'mp-weixin' | 'mp-alipay' | 'mp-baidu' | 'mp-toutiao' | 'mp-qq' | 'mp-360' | 'mp' | 'quickapp-webview' | 'quickapp-webview-union' | 'quickapp-webview-huawei' | undefined;
export declare const PLATFORM: UniPlatforms;
/** 全局对象 */
declare const _uni: UniApp.Uni;
export default _uni;

View File

@@ -0,0 +1,11 @@
var _a;
export const PLATFORM = typeof process !== 'undefined' ? (_a = process === null || process === void 0 ? void 0 : process.env) === null || _a === void 0 ? void 0 : _a.VUE_APP_PLATFORM : undefined;
/** 全局对象 */
const _uni = (function () {
if (typeof uni != "undefined")
return uni;
if (typeof wx != "undefined")
return wx;
return uni;
})();
export default _uni;

View File

@@ -0,0 +1,175 @@
/// <reference types="@dcloudio/types" />
import DrawPoster from "../draw-poster";
import { ImageFitOption } from '../extends/draw-function/draw-image-fit';
import { CreateLayerOpts, DrawRowOpt } from "../extends/create-from-list";
import { PainterContainerOption } from "../extends/draw-painter";
/** 绘制容器 */
export declare type Execute = Array<() => Promise<boolean>>;
export interface drawPosterExtends {
from: {
height: number;
padding: number;
margin: number;
};
createLayer: (afferOpts: CreateLayerOpts, rowList: DrawRowOpt[]) => number;
setFromOptions: (opts: Partial<{
height: number;
padding: number;
margin: number;
}>) => void;
gcanvas: {
WeexBridge: any;
Image: any;
enable: (el: any, options: {
bridge?: any;
debug?: boolean;
disableAutoSwap?: any;
disableComboCommands?: any;
}) => Canvas;
};
painter: (option: PainterContainerOption) => void;
}
/** 构建器配置 */
export interface DrawPosterBuildOpts {
/** 查询选择器; 注意不需要加# */
selector: string;
/** 选取组件范围 */
componentThis?: any;
/** 绘制类型为2d绘制, 默认开启, 在微信小程序的时候动态加载 */
type2d?: boolean;
/** 是否在绘制时进行加载提示 */
loading?: boolean;
/** 当存在绘制图片时, 等待绘画完毕的时间仅App中生效
*
* 具体查看文档说明https://github.com/TuiMao233/uni-draw-poster
*/
drawImageTime?: number;
/** 是否开启调试模式 */
debugging?: boolean;
/** 加载提示文字 */
loadingText?: string;
/** 创建图片提示文字 */
createText?: string;
/** 是否启动gcanvas(nvue) */
gcanvas?: boolean;
}
/** 绘制换行配置 */
export interface FillWarpTextOpts {
text: string;
maxWidth?: number;
lineHeight?: number;
layer?: number;
x?: number;
y?: number;
splitText?: string;
notFillText?: boolean;
}
/** 绘制二维码配置 */
export interface DrawQrCodeOpts {
text: string;
x?: number;
y?: number;
size?: number;
margin?: number;
backgroundColor?: string;
foregroundColor?: string;
}
/** 绘制换行, 单行信息 */
export interface FillWarpTextItemInfo {
text: string;
y: number;
x: number;
}
/** 绘制画笔 */
export interface DrawPosterCanvasCtx extends UniApp.CanvasContext {
[key: string]: any;
createImageData: () => ImageData;
textAlign: CanvasTextDrawingStyles["textAlign"];
textBaseline: CanvasTextDrawingStyles["textBaseline"];
transform: CanvasTransform["transform"];
/** 绘制图片原型 */
drawImageProto: UniApp.CanvasContext['drawImage'];
/** 当前绘制类型 */
drawType: 'context' | 'type2d';
/** 等待绘制图片
*
* 说明文档: https://tuimao233.gitee.io/mao-blog/my-extends/u-draw-poste
*/
drawImage(url: string, dx?: number | undefined, dy?: number | undefined, dWidth?: number | undefined, dHeigt?: number | undefined, sx?: number | undefined, sy?: number | undefined, sWidth?: number | undefined, sHeight?: number | undefined): Promise<boolean>;
/** 绘制圆角图片
*
* 说明文档: https://tuimao233.gitee.io/mao-blog/my-extends/u-draw-poste
*/
drawRoundImage(url: string, x: number, y: number, w: number, h: number, r?: number): Promise<boolean>;
/** 绘制 Object-Fit 模式图片
*
* 说明文档: https://tuimao233.gitee.io/mao-blog/my-extends/u-draw-poste
*/
drawImageFit(url: string, opts?: ImageFitOption): Promise<boolean>;
/** 绘制换行字体
*
* 说明文档: https://tuimao233.gitee.io/mao-blog/my-extends/u-draw-poste
*/
fillWarpText(options: FillWarpTextOpts): Array<FillWarpTextItemInfo>;
/** 绘制圆角矩形(原型)
*
*/
roundRect(x: number, y: number, w: number, h: number, r: number, fill?: boolean, stroke?: boolean): void;
/** 绘制圆角矩形(填充)
*
* 说明文档: https://tuimao233.gitee.io/mao-blog/my-extends/u-draw-poste
*/
fillRoundRect(x: number, y: number, w: number, h: number, r: number): void;
/** 绘制圆角矩形(边框)
*
* 说明文档: https://tuimao233.gitee.io/mao-blog/my-extends/u-draw-poste
*/
strokeRoundRect(x: number, y: number, w: number, h: number, r: number): void;
/** 绘制二维码
*
* 说明文档: https://tuimao233.gitee.io/mao-blog/my-extends/u-draw-poste
*/
drawQrCode(options: DrawQrCodeOpts): void;
}
/** Canvas2d实例 */
export interface Canvas {
width: number;
height: number;
getContext(contextType: "2d" | "webgl"): DrawPosterCanvasCtx | WebGLRenderingContext;
createImage(): {
src: string;
width: number;
height: number;
onload: () => void;
onerror: () => void;
};
requestAnimationFrame(callback: Function): number;
cancelAnimationFrame(requestID: number): void;
createImageData(): ImageData;
createPath2D(path: Path2D): Path2D;
toDataURL(type: string, encoderOptions: number): string;
}
/** 创建图片路径配置项 */
export interface CreateImagePathOptions {
x?: number;
y?: number;
width?: number;
height?: number;
destWidth?: number;
destHeight?: number;
}
/** 绘制实例扩展配置 */
export interface DrawPosterUseOpts {
name: string;
init?: (dp: InstanceType<typeof DrawPoster>) => void;
handle: (dp: InstanceType<typeof DrawPoster>, ...args: any[]) => any;
createImage?: (dp: InstanceType<typeof DrawPoster>) => void;
[key: string]: any;
}
/** 绘制画笔实例扩展配置 */
export interface DrawPosterUseCtxOpts {
name: string;
init?: (canvas: Canvas, ctx: DrawPosterCanvasCtx) => void;
handle: (canvas: Canvas, ctx: DrawPosterCanvasCtx, ...args: any[]) => any;
[key: string]: any;
}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,38 @@
export declare type ObjectFit = "contain" | "cover";
export declare type ObjectPosition = ["left" | "center" | "right", "top" | "center" | "bottom"];
export interface Size {
width: number;
height: number;
}
/**
* 用于计算图片的宽高比例
* @see https://drafts.csswg.org/css-images-3/#sizing-terms
*
* ## 名词解释
* ### intrinsic dimensions
* 图片本身的尺寸
*
* ### specified size
* 用户指定的元素尺寸
*
* ### concrete object size
* 应用了 `objectFit` 之后图片的显示尺寸
*
* ### default object size
*/
export declare function calculateConcreteRect(style: {
/** @see https://developer.mozilla.org/zh-CN/docs/Web/CSS/object-fit */
objectFit?: ObjectFit;
/** @see https://developer.mozilla.org/zh-CN/docs/Web/CSS/object-position */
intrinsicPosition?: ObjectPosition;
specifiedPosition?: [number, number];
}, intrinsicSize: Size, specifiedSize: Size): {
sx: number;
sy: number;
sw: number;
sh: number;
dx: number;
dy: number;
dw: number;
dh: number;
};

View File

@@ -0,0 +1,78 @@
/**
* 用于计算图片的宽高比例
* @see https://drafts.csswg.org/css-images-3/#sizing-terms
*
* ## 名词解释
* ### intrinsic dimensions
* 图片本身的尺寸
*
* ### specified size
* 用户指定的元素尺寸
*
* ### concrete object size
* 应用了 `objectFit` 之后图片的显示尺寸
*
* ### default object size
*/
export function calculateConcreteRect(style, intrinsicSize, specifiedSize) {
var _a, _b;
const isContain = style.objectFit === 'contain';
const specifiedPosition = style.specifiedPosition || [0, 0];
// ratio 越大表示矩形越"扁"
let intrinsicRatio = intrinsicSize.width / intrinsicSize.height;
let specifiedRatio = specifiedSize.width / specifiedSize.height;
/** 图片原始尺寸与最终尺寸之比 */
let concreteScale = 1;
if (intrinsicRatio > specifiedRatio && style.objectFit == "contain" ||
intrinsicRatio <= specifiedRatio && style.objectFit == "cover")
// 图片较"胖"时完整显示图片,图片较"瘦"时完全覆盖容器
// 这两种情况下有 concreteRect.width = specifiedSize.width
// 因为 concreteRect.width = intrinsicSize.width * concreteScale
// 所以:
concreteScale = specifiedSize.width / intrinsicSize.width;
else if (intrinsicRatio > specifiedRatio && style.objectFit == "cover" ||
intrinsicRatio <= specifiedRatio && style.objectFit == "contain")
// 图片较"瘦"时完整显示图片,图片较"胖"时完全覆盖容器
// 这两种情况下有 concreteRect.height = specifiedSize.height
// 因为 concreteRect.height = intrinsicSize.height * concreteScale
// 所以:
concreteScale = specifiedSize.height / intrinsicSize.height;
else
throw new Error("Unkonwn concreteScale");
let concreteRectWidth = intrinsicSize.width * concreteScale;
let concreteRectHeight = intrinsicSize.height * concreteScale;
// 这里可以把 left top 的计算想象成投影
let xRelativeOrigin = { left: 0, center: .5, right: 1 }[((_a = style.intrinsicPosition) === null || _a === void 0 ? void 0 : _a[0]) || "center"];
let yRelativeOrigin = { top: 0, center: .5, bottom: 1 }[((_b = style.intrinsicPosition) === null || _b === void 0 ? void 0 : _b[1]) || "center"];
let concreteRectLeft = (specifiedSize.width - concreteRectWidth) * xRelativeOrigin;
let concreteRectTop = (specifiedSize.height - concreteRectHeight) * yRelativeOrigin;
if (isContain) {
concreteRectLeft += specifiedPosition[0];
concreteRectTop += specifiedPosition[1];
}
// 这里有两个坐标系,一个是 specified (dist) 的坐标系,一个是 intrinsic (src) 的坐标系
// 这里将两个坐标系的点位置进行变换
// 例: 带入 x=0, y=0, 得到的结果就是 specifiedRect 的左上角在 intrinsic 坐标系下的坐标位置
// 在 specified 坐标系下, intrinsic 的零点在 (concreteRectLeft, concreteRectTop), 缩放为 concreteScale
// 所以有 x_dist = x_src * concreteScale + concreteRectLeft
// y_dist = y_src * concreteScale + concreteRectTop
let dist2src = (distX, distY) => [
/* srcX = */ (distX - concreteRectLeft) / concreteScale,
/* srcY = */ (distY - concreteRectTop) / concreteScale
];
let [srcLeft, srcTop] = dist2src(0, 0);
// srcRight = 图片 specified 框右边在 src 坐标系下的 x 坐标
// srcBottom = 图片 specified 框下边在 src 坐标系下的 y 坐标
let [srcRight, srcBottom] = dist2src(specifiedSize.width, specifiedSize.height);
// 这里要对 src 和 disc 两个框进行约束
return {
sx: Math.max(srcLeft, 0),
sy: Math.max(srcTop, 0),
sw: Math.min(srcRight - srcLeft, intrinsicSize.width),
sh: Math.min(srcBottom - srcTop, intrinsicSize.height),
dx: isContain ? Math.max(concreteRectLeft, 0) : specifiedPosition[0],
dy: isContain ? Math.max(concreteRectTop, 0) : specifiedPosition[1],
dw: Math.min(concreteRectWidth, specifiedSize.width),
dh: Math.min(concreteRectHeight, specifiedSize.height)
};
}

20
js_sdk/u-draw-poster/utils/utils.d.ts vendored Normal file
View File

@@ -0,0 +1,20 @@
import { DrawPosterBuildOpts } from "./interface";
/** 是否是base64本地地址 */
export declare const isBaseUrl: (str: string) => boolean;
/** 是否是小程序本地地址 */
export declare const isTmpUrl: (str: string) => boolean;
/** 是否是网络地址 */
export declare const isNetworkUrl: (str: string) => boolean;
/** 对象target挂载到对象current */
export declare const extendMount: (current: Record<any, any>, target: Record<any, any>, handle?: (extend: Function, target?: Record<any, any> | undefined) => any) => void;
/** 处理构建配置 */
export declare const handleBuildOpts: (options: string | DrawPosterBuildOpts) => {
selector: string;
componentThis: any;
type2d: boolean;
loading: boolean;
debugging: boolean;
loadingText: string;
createText: string;
gcanvas: boolean;
};

View File

@@ -0,0 +1,49 @@
import { PLATFORM } from "./global";
/** 是否是base64本地地址 */
export const isBaseUrl = (str) => {
return /^\s*data:(?:[a-z]+\/[a-z0-9-+.]+(?:;[a-z-]+=[a-z0-9-]+)?)?(?:;base64)?,([a-z0-9!$&',()*+;=\-._~:@\/?%\s]*?)\s*$/i.test(str);
};
/** 是否是小程序本地地址 */
export const isTmpUrl = (str) => {
return /http:\/\/temp\/wx/.test(str);
};
/** 是否是网络地址 */
export const isNetworkUrl = (str) => {
return /^(((ht|f)tps?):\/\/)?[\w-]+(\.[\w-]+)+([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?$/.test(str);
};
/** 对象target挂载到对象current */
export const extendMount = (current, target, handle = (extend, target) => undefined) => {
for (const key in target) {
current[key] = handle(target[key].handle, target[key]) || target[key].handle;
}
};
/** 处理构建配置 */
export const handleBuildOpts = (options) => {
let defaultOpts = {
selector: '',
componentThis: undefined,
type2d: true,
loading: false,
debugging: false,
loadingText: '绘制海报中...',
createText: '生成图片中...',
gcanvas: false
};
if (typeof options === "string") {
defaultOpts.selector = options;
}
else {
defaultOpts = Object.assign(Object.assign({}, defaultOpts), options);
}
const oldSelector = defaultOpts.selector;
if (PLATFORM === 'mp-weixin' && defaultOpts.type2d) {
defaultOpts.selector = '#' + defaultOpts.selector;
}
if (!PLATFORM) {
console.error('注意! draw-poster未开启uni条件编译! 当环境是微信小程序将不会动态切换为type2d模式');
console.error(`请在vue.config.js中的transpileDependencies中添加'uni-draw-poster'`);
console.error(`或者可以在选择器字符串前缀中添加#来切换为type2d绘制`);
defaultOpts.selector = oldSelector;
}
return defaultOpts;
};

View File

@@ -0,0 +1,3 @@
import { Canvas } from "./interface";
export declare const downloadImgUrl: (url: string) => Promise<string>;
export declare const getCanvas2dContext: (selector: string, componentThis?: any) => Promise<Canvas | {}>;

View File

@@ -0,0 +1,37 @@
/*
* @Author: Mr.Mao
* @LastEditors: Mr.Mao
* @Date: 2020-10-12 08:49:27
* @LastEditTime: 2020-12-09 13:54:10
* @Description:
* @任何一个傻子都能写出让电脑能懂的代码,而只有好的程序员可以写出让人能看懂的代码
*/
import uni from "./global";
import { isBaseUrl, isNetworkUrl, isTmpUrl } from './utils';
// 下载指定地址图片, 如果不符合下载图片, 则直接返回
export const downloadImgUrl = (url) => {
const isLocalFile = isBaseUrl(url) || isTmpUrl(url) || !isNetworkUrl(url);
return new Promise((resolve, reject) => {
if (isLocalFile) {
return resolve(url);
}
uni.downloadFile({
url,
success: (res) => resolve(res.tempFilePath),
fail: reject
});
});
};
// 获取当前指定 node 节点
export const getCanvas2dContext = (selector, componentThis) => {
return new Promise(resolve => {
const query = (componentThis ?
uni.createSelectorQuery().in(componentThis) :
uni.createSelectorQuery());
query.select(selector)
.fields({ node: true }, res => {
const node = res === null || res === void 0 ? void 0 : res.node;
resolve(node || {});
}).exec();
});
};