Skip to content

Commit

Permalink
feat(图形码): 二维码条形码功能
Browse files Browse the repository at this point in the history
  • Loading branch information
nihaojob committed Jun 7, 2024
1 parent 1517819 commit da5c9f0
Show file tree
Hide file tree
Showing 10 changed files with 1,010 additions and 18 deletions.
4 changes: 3 additions & 1 deletion packages/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @Author: 秦少卫
* @Date: 2023-02-03 23:29:34
* @LastEditors: 秦少卫
* @LastEditTime: 2024-05-27 16:09:57
* @LastEditTime: 2024-06-06 20:03:08
* @Description: 核心入口文件
*/
import Editor from './Editor';
Expand Down Expand Up @@ -32,6 +32,8 @@ export { default as FreeDrawPlugin } from './plugin/FreeDrawPlugin';
export { default as PathTextPlugin } from './plugin/PathTextPlugin';
export { default as PsdPlugin } from './plugin/PsdPlugin';
export { default as SimpleClipImagePlugin } from './plugin/SimpleClipImagePlugin';
export { default as BarCodePlugin } from './plugin/BarCodePlugin';
export { default as QrCodePlugin } from './plugin/QrCodePlugin';
import EventType from './eventType';
import Utils from './utils/utils';

Expand Down
4 changes: 3 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
"fabric-history": "^1.6.0",
"fontfaceobserver": "^2.1.0",
"hotkeys-js": "^3.8.8",
"jsbarcode": "^3.11.6",
"qr-code-styling": "1.6.0-rc.1",
"qs": "^6.12.1",
"tapable": "^2.2.1",
"uuid": "^8.3.2"
Expand All @@ -25,4 +27,4 @@
"jsdom": "^24.0.0",
"vitest": "^1.6.0"
}
}
}
110 changes: 110 additions & 0 deletions packages/core/plugin/BarCodePlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* @Author: 秦少卫
* @Date: 2024-06-06 14:12:24
* @LastEditors: 秦少卫
* @LastEditTime: 2024-06-06 21:23:34
* @Description: 条形码生成工具
*/

import { fabric } from 'fabric';
import Editor from '../Editor';
import JsBarcode from 'JsBarcode';
type IEditor = Editor;

// 条形码生成参数
// https://github.com/lindell/JsBarcode/wiki/Options

enum CodeType {
CODE128 = 'CODE128',
EAN8 = 'EAN8',
EAN13 = 'EAN13',
ITF14 = 'ITF14',
codabar = 'codabar',
pharmacode = 'pharmacode',
}

class BarCodePlugin {
public canvas: fabric.Canvas;
public editor: IEditor;
static pluginName = 'BarCodePlugin';
static apis = ['addBarcode', 'setBarcode', 'getBarcodeTypes'];
constructor(canvas: fabric.Canvas, editor: IEditor) {
this.canvas = canvas;
this.editor = editor;
}

_getBase64Str(option: any) {
const canvas = document.createElement('canvas');
JsBarcode(canvas, option.value, {
...option,
});
const url = canvas.toDataURL('image/png', 1);
return url;
}

_defaultBarcodeOption() {
return {
value: '123456',
format: CodeType.CODE128,
text: 'hi kuaitu',
textAlign: 'left',
textPosition: 'bottom',
fontSize: 12,
};
}

addBarcode() {
const option = this._defaultBarcodeOption();
const url = this._getBase64Str(JSON.parse(JSON.stringify(option)));
fabric.Image.fromURL(
url,
(imgEl) => {
imgEl.set({
extensionType: 'barcode',
extension: option,
});
this.canvas.add(imgEl);

this.canvas.setActiveObject(imgEl);

this.editor.position('center');
},
{ crossOrigin: 'anonymous' }
);
}

setBarcode(option: any) {
try {
const url = this._getBase64Str(option);
const activeObject = this.canvas.getActiveObjects()[0];
fabric.Image.fromURL(
url,
(imgEl) => {
imgEl.set({
left: activeObject.left,
top: activeObject.top,
extensionType: 'barcode',
extension: { ...option },
});
imgEl.scaleToWidth(activeObject.getScaledWidth());
this.editor.del();
this.canvas.add(imgEl);
this.canvas.setActiveObject(imgEl);
},
{ crossOrigin: 'anonymous' }
);
} catch (error) {
console.log(error);
}
}

getBarcodeTypes() {
return Object.values(CodeType);
}

destroy() {
console.log('pluginDestroy');
}
}

export default BarCodePlugin;
179 changes: 179 additions & 0 deletions packages/core/plugin/QrCodePlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
* @Author: 秦少卫
* @Date: 2024-06-06 19:58:26
* @LastEditors: 秦少卫
* @LastEditTime: 2024-06-07 11:03:27
* @Description: 二维码生成工具
*/

import { fabric } from 'fabric';
import Editor from '../Editor';
import QRCodeStyling from 'qr-code-styling';

type IEditor = Editor;

// 二维码生成参数

enum DotsType {
rounded = 'rounded',
dots = 'dots',
classy = 'classy',
classy_rounded = 'classy-rounded',
square = 'square',
extra_rounded = 'extra-rounded',
}

enum CornersType {
dot = 'dot',
square = 'square',
extra_rounded = 'extra-rounded',
}

enum cornersDotType {
dot = 'dot',
square = 'square',
}

enum errorCorrectionLevelType {
L = 'L',
M = 'M',
Q = 'Q',
H = 'H',
}

class QrCodePlugin {
public canvas: fabric.Canvas;
public editor: IEditor;
static pluginName = 'QrCodePlugin';
static apis = ['addQrCode', 'setQrCode', 'getQrCodeTypes'];
constructor(canvas: fabric.Canvas, editor: IEditor) {
this.canvas = canvas;
this.editor = editor;
}

async _getBase64Str(options: any) {
const qrCode = new QRCodeStyling(options);
const blob = await qrCode.getRawData('png');
const base64Str = await this._blobToBase64(blob);
return base64Str || '';
}

_defaultBarcodeOption() {
return {
data: 'https://kuaitu.cc',
width: 300,
margin: 10,
errorCorrectionLevel: 'M',
dotsColor: 'black',
dotsType: 'rounded',
cornersSquareColor: 'black',
cornersSquareType: 'dot',
cornersDotColor: 'black',
cornersDotType: 'square',
background: '#ffffff',
};
}

_paramsToOption(option: any) {
return {
width: option.width,
height: option.width,
type: 'canvas',
data: option.data,
margin: option.margin,
qrOptions: {
errorCorrectionLevel: option.errorCorrectionLevel,
},
// 点
dotsOptions: {
color: option.dotsColor,
type: option.dotsType,
},
// 三个角
cornersSquareOptions: {
color: option.cornersSquareColor,
type: option.cornersSquareType,
},
// 圆点选项
cornersDotOptions: {
color: option.cornersDotColor,
type: option.cornersDotType,
},
// 背景
backgroundOptions: {
color: option.background,
},
};
}

_blobToBase64(blob: Blob) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(blob);
//读取后,result属性中将包含一个data:URL格式的Base64字符串用来表示所读取的文件
reader.onload = function (e) {
resolve(e.target.result);
};
});
}

async addQrCode() {
const option = this._defaultBarcodeOption();
const paramsOption = this._paramsToOption(option);
const url = await this._getBase64Str(paramsOption);
fabric.Image.fromURL(
url,
(imgEl) => {
imgEl.set({
extensionType: 'qrcode',
extension: option,
});
this.canvas.add(imgEl);
this.canvas.setActiveObject(imgEl);
this.editor.position('center');
},
{ crossOrigin: 'anonymous' }
);
}

async setQrCode(option: any) {
try {
const paramsOption = this._paramsToOption(option);
const url = await this._getBase64Str(paramsOption);
const activeObject = this.canvas.getActiveObjects()[0];
fabric.Image.fromURL(
url,
(imgEl) => {
imgEl.set({
left: activeObject.left,
top: activeObject.top,
extensionType: 'qrcode',
extension: { ...option },
});
imgEl.scaleToWidth(activeObject.getScaledWidth());
this.editor.del();
this.canvas.add(imgEl);
this.canvas.setActiveObject(imgEl);
},
{ crossOrigin: 'anonymous' }
);
} catch (error) {
console.log(error);
}
}

getQrCodeTypes() {
return {
DotsType: Object.values(DotsType),
CornersType: Object.values(CornersType),
cornersDotType: Object.values(cornersDotType),
errorCorrectionLevelType: Object.values(errorCorrectionLevelType),
};
}

destroy() {
console.log('pluginDestroy');
}
}

export default QrCodePlugin;
Loading

0 comments on commit da5c9f0

Please sign in to comment.