内容简介:最近接触到的需求,前端生成一个带企业logo的二维码,并支持点击下载它。在前面的文章有讲到如何用 canvas 画二维码,在此基础上再画一个公司logo,并提供下载的方法供调用,再封装成 npm 插件模块名称:
背景
最近接触到的需求,前端生成一个带企业logo的二维码,并支持点击下载它。
实现
在前面的文章有讲到如何用 canvas 画二维码,在此基础上再画一个公司logo,并提供下载的方法供调用,再封装成 npm 插件
模块名称: qrcode-with-logos
github地址: https://github.com/zxpsuper/qrcode-with-logos
npm地址: https://www.npmjs.com/package/qrcode-with-logos
核心代码
将整个封装成一个 QrCodeWithLogo 类,并提供三个方法:
interface IQrCodeWithLogo {
toCanvas(): Promise<any>;
toImage(): Promise<any>;
downloadImage(name: string): void;
}
class QrCodeWithLogo implements IQrCodeWithLogo {
option: BaseOptions;
constructor(option: BaseOptions) {
this.option = option;
return this;
}
toCanvas = () => {
return toCanvas.call(this, this.option);
};
toImage = () => {
return toImage.call(this, this.option);
};
downloadImage = (name: string) => {
saveImage(this.option.image, name);
};
}
1. toCanvas()
此方法用到了库 qrcode 的 toCanvas 方法
export const toCanvas = (options: BaseOptions) => {
return renderQrCode(options)
.then(() => options)
.then(drawLogo);
};
这里先用 qrcode 库画出二维码的canvas
import QRCode = require("qrcode");
const toCanvas = promisify(QRCode.toCanvas);
export const renderQrCode = ({
canvas,
content,
width = 0,
nodeQrCodeOptions = {}
}: BaseOptions) => {
// 容错率,默认对内容少的二维码采用高容错率,内容多的二维码采用低容错率
// according to the content length to choose different errorCorrectionLevel
nodeQrCodeOptions.errorCorrectionLevel =
nodeQrCodeOptions.errorCorrectionLevel || getErrorCorrectionLevel(content);
return getOriginWidth(content, nodeQrCodeOptions).then((_width: number) => {
// 得到原始比例后还原至设定值,再放大4倍以获取高清图
// Restore to the set value according to the original ratio, and then zoom in 4 times to get the HD image.
nodeQrCodeOptions.scale = width === 0 ? undefined : (width / _width) * 4;
// @ts-ignore
return toCanvas(canvas, content, nodeQrCodeOptions);
});
};
promisify()是封装的一个方法,用于减少return promise时的代码,方便书写
export const promisify = (f: Function): Function => {
return function() {
const args = Array.prototype.slice.call(arguments);
return new Promise(function(resolve, reject) {
args.push(function(err: object, result: object) {
if (err) reject(err);
else resolve(result);
});
f.apply(null, args);
});
};
};
画出canvas,紧接着判断是否有logo, 如果有就画logo,这里有两种模式:
ctx.drawImage(image, logoXY, logoXY, logoWidth, logoWidth); ctx.createPattern(canvasImage, "no-repeat");
export const drawLogo = ({ canvas, content, logo }: BaseOptions) => {
if (!logo) {
return;
}
// @ts-ignore
const canvasWidth = canvas.width;
const {
logoSize = 0.15,
borderColor = "#ffffff",
bgColor = borderColor || "#ffffff",
borderSize = 0.05,
crossOrigin,
borderRadius = 8,
logoRadius = 0
} = logo;
let logoSrc = typeof logo === "string" ? logo : logo.src;
let logoWidth = canvasWidth * logoSize;
let logoXY = (canvasWidth * (1 - logoSize)) / 2;
let logoBgWidth = canvasWidth * (logoSize + borderSize);
let logoBgXY = (canvasWidth * (1 - logoSize - borderSize)) / 2;
// @ts-ignore
const ctx = canvas.getContext("2d");
// logo 底色, draw logo background color
canvasRoundRect(ctx)(
logoBgXY,
logoBgXY,
logoBgWidth,
logoBgWidth,
borderRadius
);
ctx.fillStyle = bgColor;
ctx.fill();
// logo
const image = new Image();
if (crossOrigin || logoRadius) {
image.setAttribute("crossOrigin", crossOrigin || "anonymous");
}
image.src = logoSrc;
// 使用image绘制可以避免某些跨域情况
// Use image drawing to avoid some cross-domain situations
const drawLogoWithImage = (image: any) => {
ctx.drawImage(image, logoXY, logoXY, logoWidth, logoWidth);
};
// 使用canvas绘制以获得更多的功能
// Use canvas to draw more features, such as borderRadius
const drawLogoWithCanvas = (image: any) => {
const canvasImage = document.createElement("canvas");
canvasImage.width = logoXY + logoWidth;
canvasImage.height = logoXY + logoWidth;
canvasImage
.getContext("2d")
.drawImage(image, logoXY, logoXY, logoWidth, logoWidth);
canvasRoundRect(ctx)(logoXY, logoXY, logoWidth, logoWidth, logoRadius);
ctx.fillStyle = ctx.createPattern(canvasImage, "no-repeat");
ctx.fill();
};
// 将 logo绘制到 canvas上
// Draw the logo on the canvas
return new Promise((resolve, reject) => {
image.onload = () => {
logoRadius ? drawLogoWithCanvas(image) : drawLogoWithImage(image);
resolve();
};
});
};
2. toImage()
此方法利用之前的 toCanvas() 方法,生成canvas后拿到 canvas.toDataURL() 的值,赋给 <img> 的 src 即可。这里,我们加入了 download downloadName 属性用于下载,因此在 toImage() 方法中判断,代码如下:
export const toImage = (options: BaseOptions) => {
const canvas = document.createElement("canvas");
console.log("options", options);
options.canvas = canvas;
if (options.logo) {
if (isString(options.logo)) {
// @ts-ignore
options.logo = { src: options.logo };
}
// @ts-ignore
options.logo.crossOrigin = "Anonymous";
}
// @ts-ignore
return toCanvas(options).then(() => {
const { image = new Image(), downloadName = "qr-code" } = options;
let { download } = options;
// @ts-ignore
image.src = canvas.toDataURL();
if (download !== true && !isFunction(download)) {
return;
}
download = download === true ? (start: Function) => start() : download;
const startDownload: Function = () => {
saveImage(image, downloadName);
};
download && download(startDownload);
return new Promise((resolve, reject) => {
resolve();
});
});
};
export const saveImage = (image: Element, name: string) => {
// @ts-ignore
const dataURL = image.src;
const link = document.createElement("a");
link.download = name;
link.href = dataURL;
link.dispatchEvent(new MouseEvent("click"));
};
3. downloadImage(name)
提供一个主动调用下载图片的方法,传入文件名name, 其中用到 saveImage() 方法,这个在 toImage() 中也有用到。
下载文件的流程是:生成一个 <a> 标签, 设置 href 值为 image 的 src 值, download 属性赋值文件名,然后给 <a> 主动一次点击事件即可。
downloadImage = (name: string) => {
saveImage(this.option.image, name);
};
npm 发布
初次尝试 typescript , 用的不够优美但无妨使用。 npm run build 构建出支持 umd 的文件,然后 npm login , npm publish 即可。webpack 配置可查看 github 代码。
插件使用
下面是详细代码
<canvas id="canvas"></canvas> <img src="" alt="" id="image" /> <img id="image" alt="">
npm 模块导入:
import QrCodeWithLogo from "qrcode-with-logos";
let qrcode = new QrCodeWithLogo({
canvas: document.getElementById("canvas"),
content: "https://github.com/zxpsuper",
width: 380,
// download: true,
image: document.getElementById("image"),
logo: {
src: "https://avatars1.githubusercontent.com/u/28730619?s=460&v=4"
}
});
qrcode.toCanvas().then(() => {
qrcode.toImage().then(() => {
setTimeout(() => {
qrcode.downloadImage("hello world");
}, 2000);
});
});
当然你也可以 <script> 引入使用
<script src="https://zxpsuper.github.io/qrcode-with-logos/dist/QRcode-with-logo.js"></script>
<script>
let qrcode = new QrCodeWithLogo({
canvas: document.getElementById("canvas"),
content: "https://github.com/zxpsuper",
width: 380,
// download: true,
image: document.getElementById("image"),
logo: {
src: "https://avatars1.githubusercontent.com/u/28730619?s=460&v=4"
}
});
qrcode.toCanvas().then(() => {
qrcode.toImage().then(() => {
setTimeout(() => {
qrcode.downloadImage("hello world");
}, 2000);
});
});
</script>
That is all.
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- changelog 日志自动生成插件
- 用protobuf生成json结构插件实现
- 如何实现一行命令自动生成 Flutter 插件
- 使用Gradle插件生成资源ID映射文件
- IDEA 插件: EasyCode一键生成所需代码~
- web-flash发布了代码生成插件
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Hacking Growth
Sean Ellis、Morgan Brown / Crown Business / 2017-4-25 / USD 29.00
The definitive playbook by the pioneers of Growth Hacking, one of the hottest business methodologies in Silicon Valley and beyond. It seems hard to believe today, but there was a time when Airbnb w......一起来看看 《Hacking Growth》 这本书的介绍吧!