Skip to content

Commit

Permalink
feat: optimize code
Browse files Browse the repository at this point in the history
  • Loading branch information
kiner-tang committed Jun 20, 2024
1 parent d820c8e commit 8a34f62
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 218 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@kiner/rc-qrcode",
"name": "@react-component/qrcode",
"version": "1.0.2",
"description": "base abstract trigger component for react",
"engines": {
Expand Down
35 changes: 12 additions & 23 deletions src/QRCodeCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import React, { useCallback, useEffect, useRef, useState } from 'react';
import { useQRCode } from './hooks/useQRCode';
import type { QRPropsCanvas } from './interface';
import {
DEFAULT_BGCOLOR,
DEFAULT_FGCOLOR,
DEFAULT_INCLUDEMARGIN,
DEFAULT_BACKGROUND_COLOR,
DEFAULT_FRONT_COLOR,
DEFAULT_NEED_MARGIN,
DEFAULT_LEVEL,
DEFAULT_MINVERSION,
DEFAULT_SIZE,
SUPPORTS_PATH2D,
isSupportPath2d,
excavateModules,
generatePath,
} from './utils';
Expand All @@ -19,9 +19,9 @@ const QRCodeCanvas = React.forwardRef<HTMLCanvasElement, QRPropsCanvas>(
value,
size = DEFAULT_SIZE,
level = DEFAULT_LEVEL,
bgColor = DEFAULT_BGCOLOR,
fgColor = DEFAULT_FGCOLOR,
includeMargin = DEFAULT_INCLUDEMARGIN,
bgColor = DEFAULT_BACKGROUND_COLOR,
fgColor = DEFAULT_FRONT_COLOR,
includeMargin = DEFAULT_NEED_MARGIN,
minVersion = DEFAULT_MINVERSION,
marginSize,
style,
Expand All @@ -32,7 +32,6 @@ const QRCodeCanvas = React.forwardRef<HTMLCanvasElement, QRPropsCanvas>(
const _canvas = useRef<HTMLCanvasElement | null>(null);
const _image = useRef<HTMLImageElement>(null);

// Set the local ref (_canvas) and also the forwarded ref from outside
const setCanvasRef = useCallback(
(node: HTMLCanvasElement | null) => {
_canvas.current = node;
Expand All @@ -45,9 +44,7 @@ const QRCodeCanvas = React.forwardRef<HTMLCanvasElement, QRPropsCanvas>(
[forwardedRef],
);

// We're just using this state to trigger rerenders when images load. We
// Don't actually read the value anywhere. A smarter use of useEffect would
// depend on this value.

const [, setIsImageLoaded] = useState(false);

const { margin, cells, numCells, calculatedImageSettings } = useQRCode({
Expand All @@ -61,8 +58,6 @@ const QRCodeCanvas = React.forwardRef<HTMLCanvasElement, QRPropsCanvas>(
});

useEffect(() => {
// Always update the canvas. It's cheap enough and we want to be correct
// with the current state.
if (_canvas.current != null) {
const canvas = _canvas.current;

Expand All @@ -89,23 +84,17 @@ const QRCodeCanvas = React.forwardRef<HTMLCanvasElement, QRPropsCanvas>(
}
}

// We're going to scale this so that the number of drawable units
// matches the number of cells. This avoids rounding issues, but does
// result in some potentially unwanted single pixel issues between
// blocks, only in environments that don't support Path2D.
const pixelRatio = window.devicePixelRatio || 1;
canvas.height = canvas.width = size * pixelRatio;
const scale = (size / numCells) * pixelRatio;
ctx.scale(scale, scale);
// console.log('scale', scale, 'size', size, 'numCells', numCells, 'pixelRatio', pixelRatio);

// Draw solid background, only paint dark modules.

ctx.fillStyle = bgColor;
ctx.fillRect(0, 0, numCells, numCells);

ctx.fillStyle = fgColor;
if (SUPPORTS_PATH2D) {
// $FlowFixMe: Path2D c'tor doesn't support args yet.
if (isSupportPath2d) {
ctx.fill(new Path2D(generatePath(cellsToDraw, margin)));
} else {
cells.forEach(function (row, rdx) {
Expand Down Expand Up @@ -133,8 +122,6 @@ const QRCodeCanvas = React.forwardRef<HTMLCanvasElement, QRPropsCanvas>(
}
});

// Ensure we mark image loaded as false here so we trigger updating the
// canvas in our other effect.
useEffect(() => {
setIsImageLoaded(false);
}, [imgSrc]);
Expand All @@ -151,6 +138,8 @@ const QRCodeCanvas = React.forwardRef<HTMLCanvasElement, QRPropsCanvas>(
setIsImageLoaded(true);
}}
ref={_image}
// when crossOrigin is not set, the image will be tainted
// and the canvas cannot be exported to an image
crossOrigin={calculatedImageSettings?.crossOrigin}
/>
);
Expand Down
21 changes: 8 additions & 13 deletions src/QRCodeSVG.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import type { QRPropsSVG } from './interface';
import {
DEFAULT_BGCOLOR,
DEFAULT_FGCOLOR,
DEFAULT_INCLUDEMARGIN,
DEFAULT_BACKGROUND_COLOR,
DEFAULT_FRONT_COLOR,
DEFAULT_NEED_MARGIN,
DEFAULT_LEVEL,
DEFAULT_MINVERSION,
DEFAULT_SIZE,
Expand All @@ -18,9 +18,9 @@ const QRCodeSVG = React.forwardRef<SVGSVGElement, QRPropsSVG>(
value,
size = DEFAULT_SIZE,
level = DEFAULT_LEVEL,
bgColor = DEFAULT_BGCOLOR,
fgColor = DEFAULT_FGCOLOR,
includeMargin = DEFAULT_INCLUDEMARGIN,
bgColor = DEFAULT_BACKGROUND_COLOR,
fgColor = DEFAULT_FRONT_COLOR,
includeMargin = DEFAULT_NEED_MARGIN,
minVersion = DEFAULT_MINVERSION,
title,
marginSize,
Expand Down Expand Up @@ -57,18 +57,13 @@ const QRCodeSVG = React.forwardRef<SVGSVGElement, QRPropsSVG>(
y={calculatedImageSettings.y + margin}
preserveAspectRatio="none"
opacity={calculatedImageSettings.opacity}
// Note: specified here always, but undefined will result in no attribute.
// when crossOrigin is not set, the image will be tainted
// and the canvas cannot be exported to an image
crossOrigin={calculatedImageSettings.crossOrigin}
/>
);
}

// Drawing strategy: instead of a rect per module, we're going to create a
// single path for the dark modules and layer that on top of a light rect,
// for a total of 2 DOM nodes. We pay a bit more in string concat but that's
// way faster than DOM ops.
// For level 1, 441 nodes -> 2
// For level 40, 31329 -> 2
const fgPath = generatePath(cellsToDraw, margin);

return (
Expand Down
Loading

0 comments on commit 8a34f62

Please sign in to comment.