Merge branch 'dev-redux' of https://github.com/ciaochaos/qrbtf into dev-redux

This commit is contained in:
ciaochaos 2020-05-22 17:41:28 +08:00
commit 26548789eb
27 changed files with 338 additions and 484 deletions

View File

@ -24,3 +24,8 @@ export const changeParam = (rendererIndex, paramIndex, value) => ({
type: actionTypes.CHANGE_PARAM, type: actionTypes.CHANGE_PARAM,
rendererIndex, paramIndex, value rendererIndex, paramIndex, value
}) })
export const loadDownloadData = (data) => ({
type: actionTypes.LOAD_DOWNLOAD_DATA,
data
})

View File

@ -3,21 +3,26 @@ import * as tcb from 'tcb-js-sdk';
const app = tcb.init({ const app = tcb.init({
env: 'qrbtf-1d845d' env: 'qrbtf-1d845d'
}); });
const auth = app.auth();
async function login() { let isLogin;
const auth = app.auth();
const db = app.database();
const _ = db.command
export async function login() {
await auth.signInAnonymously(); await auth.signInAnonymously();
const loginState = await auth.getLoginState(); const loginState = await auth.getLoginState();
isLogin = loginState isLogin = loginState
} }
login(); export function getDownloadCount(callback) {
if (!isLogin) return;
db.collection('QRCounter').get().then(res => {
if (callback) callback(res);
});
}
let isLogin; export function increaseDownloadData(value, callback) {
const db = app.database();
const _ = db.command
export function increaseDownloadData(value) {
if (!isLogin) return; if (!isLogin) return;
db.collection('QRCounter').where({ db.collection('QRCounter').where({
value: _.eq(value) value: _.eq(value)
@ -28,6 +33,8 @@ export function increaseDownloadData(value) {
}).update({ }).update({
count: _.inc(1), count: _.inc(1),
date: new Date().toString() date: new Date().toString()
}).then(() => {
if (callback) callback();
}).catch(console.error) }).catch(console.error)
} }
else { else {
@ -35,6 +42,8 @@ export function increaseDownloadData(value) {
value: value, value: value,
count: 1, count: 1,
date: new Date().toString() date: new Date().toString()
}).then(() => {
if (callback) callback()
}).catch(console.error) }).catch(console.error)
} }
}) })

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, {useCallback, useEffect} from 'react';
import './App.css'; import './App.css';
import '../Qrcode.css'; import '../Qrcode.css';
import PartFooter from "./PartFooter"; import PartFooter from "./PartFooter";
@ -7,8 +7,25 @@ import PartMore from "./PartMore";
import PartParams from "./PartParams"; import PartParams from "./PartParams";
import PartDownloadViewer from "../../containers/app/PartDownloadViewer"; import PartDownloadViewer from "../../containers/app/PartDownloadViewer";
import PartStylesViewer from "../../containers/app/PartStylesViewer"; import PartStylesViewer from "../../containers/app/PartStylesViewer";
import {getDownloadCount, login} from "../../api/db";
import {connect} from 'react-redux';
import {loadDownloadData} from "../../actions";
function App({ dispatch }) {
const updateDownloadData = useCallback((downloadData) => dispatch(loadDownloadData(downloadData)), []);
useEffect(() => {
login().then(() => {
getDownloadCount((res) => {
let downloadData = [];
res.data.forEach((item) => {
downloadData[item.value] = item.count;
});
dispatch(loadDownloadData(downloadData));
});
})
})
function App() {
return ( return (
<div className="App"> <div className="App">
<header className="App-header"> <header className="App-header">
@ -17,7 +34,7 @@ function App() {
<PartHeader/> <PartHeader/>
<PartStylesViewer/> <PartStylesViewer/>
<PartParams/> <PartParams/>
<PartDownloadViewer/> <PartDownloadViewer updateDownloadData={updateDownloadData}/>
<PartMore/> <PartMore/>
<PartFooter/> <PartFooter/>
</div> </div>
@ -27,4 +44,4 @@ function App() {
); );
} }
export default App; export default connect()(App);

View File

@ -1,23 +1,31 @@
import React, {useState} from 'react'; import React, {useState} from 'react';
import './App.css'; import './App.css';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {isWeiXin} from "../../utils/util"; import {isWeiXin} from "../../utils/navigatorUtils";
const WxMessage = () => { const WxMessage = () => {
if (isWeiXin()) { if (isWeiXin()) {
return <div className="note-font" id="wx-message-inner">当前客户端不支持下载 SVG<br />请下载 JPG 并长按二维码保存</div> return (
<div className="note-font" id="wx-message-inner">
当前客户端不支持下载 SVG<br />
请下载 JPG 并长按二维码保存
</div>
)
} }
return null return null
} }
const PartDownload = ({ value, onSvgDownload, onJpgDownload }) => { const PartDownload = ({ value, downloadCount, onSvgDownload, onJpgDownload }) => {
const [imgData, setImgData] = useState(''); const [imgData, setImgData] = useState('');
return ( return (
<div className="Qr-titled"> <div className="Qr-titled">
<div className="Qr-Centered title-margin"> <div className="Qr-Centered title-margin">
<div className="Qr-s-title">Downloads</div> <div className="Qr-s-title">Downloads</div>
<p className="Qr-s-subtitle">下载二维码 {value}</p> <p className="Qr-s-subtitle">
下载二维码 {value}
<sup className="Gray"> {downloadCount}</sup>
</p>
</div> </div>
<div className="Qr-Centered"> <div className="Qr-Centered">
<div className="btn-row"> <div className="btn-row">

View File

@ -1,14 +1,7 @@
import React, {useEffect, useState} from 'react'; import React, {useEffect, useState} from 'react';
import './App.css'; import './App.css';
import StyleListViewer from "../../containers/style/StyleListViewer"; import StyleListViewer from "../../containers/style/StyleListViewer";
import {isPC} from "../../utils/util"; import {isPC} from "../../utils/navigatorUtils";
const PCMessage = () => {
if (isPC()) {
return <div className="Qr-style-hint">按住 shift 滚动</div>
}
return null
}
const PartStyles = ({ setParamInfo }) => { const PartStyles = ({ setParamInfo }) => {
const [loaded, setLoaded] = useState(false); const [loaded, setLoaded] = useState(false);
@ -21,7 +14,10 @@ const PartStyles = ({ setParamInfo }) => {
return (<div className="Qr-titled" id="Qr-style"> return (<div className="Qr-titled" id="Qr-style">
<div className="Qr-Centered title-margin"> <div className="Qr-Centered title-margin">
<div className="Qr-s-title">Styles</div> <div className="Qr-s-title">Styles</div>
<p className="Qr-s-subtitle Qr-rel">点击选择样式<PCMessage/></p> <div className="Qr-s-subtitle Qr-rel">
点击选择样式
{isPC() ? <div className="Qr-style-hint">按住 shift 滚动</div> : null}
</div>
</div> </div>
<div className="Qr-s" style={{visibility: loaded ? "visible" :"hidden"}}> <div className="Qr-s" style={{visibility: loaded ? "visible" :"hidden"}}>
{styleList} {styleList}

View File

@ -1,7 +1,7 @@
import React, { useEffect } from "react"; import React from "react";
import {defaultViewBox} from "../../utils/util";
import {ParamTypes} from "../../constant/ParamTypes"; import {ParamTypes} from "../../constant/ParamTypes";
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler"; import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
import {createRenderer} from "../style/Renderer";
function listPoints(qrcode, params) { function listPoints(qrcode, params) {
if (!qrcode) return [] if (!qrcode) return []
@ -84,17 +84,10 @@ function viewBox(qrcode) {
return String(-nCount) + ' ' + String(-nCount / 2) + ' ' + String(nCount * 2) + ' ' + String(nCount * 2); return String(-nCount) + ' ' + String(-nCount / 2) + ' ' + String(nCount * 2) + ' ' + String(nCount * 2);
} }
const Renderer25D = ({ qrcode, params, setParamInfo}) => { const Renderer25D = createRenderer({
useEffect(() => { listPoints: listPoints,
setParamInfo(getParamInfo()); getParamInfo: getParamInfo,
}, [setParamInfo]); getViewBox: viewBox
})
return (
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={viewBox(qrcode)} fill="white"
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
{listPoints(qrcode, params)}
</svg>
)
}
export default Renderer25D export default Renderer25D

View File

@ -1,7 +1,8 @@
import React, { useEffect } from "react"; import React from "react";
import {defaultViewBox, rand} from "../../utils/util";
import {ParamTypes} from "../../constant/ParamTypes"; import {ParamTypes} from "../../constant/ParamTypes";
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler"; import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
import {createRenderer} from "../style/Renderer";
import {rand} from "../../utils/util";
function listPoints(qrcode, params) { function listPoints(qrcode, params) {
if (!qrcode) return [] if (!qrcode) return []
@ -71,7 +72,7 @@ function listPoints(qrcode, params) {
return pointList; return pointList;
} }
function getParamInfo() { function getParamInfoRect() {
return [ return [
{ {
type: ParamTypes.SELECTOR, type: ParamTypes.SELECTOR,
@ -116,17 +117,107 @@ function getParamInfo() {
]; ];
} }
const RendererBase = ({ qrcode, params, setParamInfo}) => { function getParamInfoRound() {
useEffect(() => { return [
setParamInfo(getParamInfo()); {
}, [setParamInfo]); type: ParamTypes.SELECTOR,
key: '信息点样式',
return ( default: 1,
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(qrcode)} fill="white" choices: [
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink"> "矩形",
{listPoints(qrcode, params)} "圆形",
</svg> "随机"
) ]
},
{
type: ParamTypes.TEXT_EDITOR,
key: '信息点缩放',
default: 50
},
{
type: ParamTypes.TEXT_EDITOR,
key: '信息点不透明度',
default: 30,
},
{
type: ParamTypes.SELECTOR,
key: '定位点样式',
default: 1,
choices: [
"矩形",
"圆形",
"行星",
]
},
{
type: ParamTypes.COLOR_EDITOR,
key: '信息点颜色',
default: '#000000'
},
{
type: ParamTypes.COLOR_EDITOR,
key: '定位点点颜色',
default: '#000000'
}
];
} }
export default RendererBase function getParamInfoRandRound() {
return [
{
type: ParamTypes.SELECTOR,
key: '信息点样式',
default: 2,
choices: [
"矩形",
"圆形",
"随机"
]
},
{
type: ParamTypes.TEXT_EDITOR,
key: '信息点缩放',
default: 80
},
{
type: ParamTypes.TEXT_EDITOR,
key: '信息点不透明度',
default: 100,
},
{
type: ParamTypes.SELECTOR,
key: '定位点样式',
default: 2,
choices: [
"矩形",
"圆形",
"行星",
]
},
{
type: ParamTypes.COLOR_EDITOR,
key: '信息点颜色',
default: '#000000'
},
{
type: ParamTypes.COLOR_EDITOR,
key: '定位点点颜色',
default: '#000000'
}
];
}
export const RendererRect= createRenderer({
listPoints: listPoints,
getParamInfo: getParamInfoRect,
});
export const RendererRound = createRenderer({
listPoints: listPoints,
getParamInfo: getParamInfoRound,
});
export const RendererRandRound = createRenderer({
listPoints: listPoints,
getParamInfo: getParamInfoRandRound,
});

View File

@ -1,25 +1,6 @@
import React, { useEffect } from "react"; import React from "react";
import {defaultViewBox} from "../../utils/util"; import {createRenderer} from "../style/Renderer";
function listPoints(qrcode, params) { const RenderBlank = createRenderer()
return []
}
function getParamInfo() {
return [];
}
const RenderBlank = ({ qrcode, params, setParamInfo}) => {
useEffect(() => {
setParamInfo(getParamInfo());
}, [setParamInfo]);
return (
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(qrcode)} fill="white"
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
{listPoints(qrcode, params)}
</svg>
)
}
export default RenderBlank export default RenderBlank

View File

@ -1,7 +1,7 @@
import React, { useEffect } from "react"; import React from "react";
import {defaultViewBox} from "../../utils/util";
import {ParamTypes} from "../../constant/ParamTypes"; import {ParamTypes} from "../../constant/ParamTypes";
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler"; import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
import {createRenderer} from "../style/Renderer";
function listPoints(qrcode, params) { function listPoints(qrcode, params) {
if (!qrcode) return [] if (!qrcode) return []
@ -188,17 +188,9 @@ function getParamInfo() {
] ]
} }
const RenderDSJ = ({ qrcode, params, setParamInfo}) => { const RenderDSJ = createRenderer({
useEffect(() => { listPoints: listPoints,
setParamInfo(getParamInfo()); getParamInfo: getParamInfo,
}, [setParamInfo]); })
return (
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(qrcode)} fill="white"
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
{listPoints(qrcode, params)}
</svg>
)
}
export default RenderDSJ export default RenderDSJ

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,6 @@
import React, { useEffect } from "react"; import React from "react";
import {defaultViewBox, rand} from "../../utils/util"; import {rand} from "../../utils/util";
import {createRenderer} from "../style/Renderer";
function listPoints(qrcode, params) { function listPoints(qrcode, params) {
if (!qrcode) return [] if (!qrcode) return []
@ -40,17 +41,9 @@ function getParamInfo() {
return [] return []
} }
const RendererRandRect = ({ qrcode, params, setParamInfo}) => { const RendererRandRect = createRenderer({
useEffect(() => { listPoints: listPoints,
setParamInfo(getParamInfo()); getParamInfo: getParamInfo
}, [setParamInfo]); })
return (
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(qrcode)} fill="white"
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
{listPoints(qrcode, params)}
</svg>
)
}
export default RendererRandRect export default RendererRandRect

View File

@ -1,132 +0,0 @@
import React, { useEffect } from "react";
import {defaultViewBox, rand} from "../../utils/util";
import {ParamTypes} from "../../constant/ParamTypes";
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
function listPoints(qrcode, params) {
if (!qrcode) return []
const nCount = qrcode.getModuleCount();
const typeTable = getTypeTable(qrcode);
const pointList = new Array(nCount);
let type = params[0];
let size = params[1] / 100;
let opacity = params[2] / 100;
let posType = params[3];
let id = 0;
let otherColor = params[4];
let posColor = params[5];
const vw = [3, -3];
const vh = [3, -3];
if (size <= 0) size = 1.0
for (let x = 0; x < nCount; x++) {
for (let y = 0; y < nCount; y++) {
if (qrcode.isDark(x, y) == false) continue;
if (typeTable[x][y] == QRPointType.ALIGN_CENTER || typeTable[x][y] == QRPointType.ALIGN_OTHER || typeTable[x][y] == QRPointType.TIMING) {
if (type == 0)
pointList.push(<rect opacity={opacity} width={size} height={size} key={id++} fill={otherColor} x={x + (1 - size)/2} y={y + (1 - size)/2}/>)
else if (type == 1)
pointList.push(<circle opacity={opacity} r={size / 2} key={id++} fill={otherColor} cx={x + 0.5} cy={y + 0.5}/>)
else if (type == 2)
pointList.push(<circle key={id++} opacity={opacity} fill={otherColor} cx={x + 0.5} cy={y + 0.5} r={size / 2} />)
}
else if (typeTable[x][y] == QRPointType.POS_CENTER) {
if (posType == 0) {
pointList.push(<rect width={1} height={1} key={id++} fill={posColor} x={x} y={y}/>);
} else if (posType == 1) {
pointList.push(<circle key={id++} fill={posColor} cx={x + 0.5} cy={y + 0.5} r={1.5} />)
pointList.push(<circle key={id++} fill="none" strokeWidth="1" stroke={posColor} cx={x + 0.5} cy={y + 0.5} r={3} />)
} else if (posType == 2) {
pointList.push(<circle key={id++} fill={posColor} cx={x + 0.5} cy={y + 0.5} r={1.5} />)
pointList.push(<circle key={id++} fill="none" strokeWidth="0.15" strokeDasharray="0.5,0.5" stroke={posColor} cx={x + 0.5} cy={y + 0.5} r={3} />)
for (let w = 0; w < vw.length; w++) {
pointList.push(<circle key={id++} fill={posColor} cx={x + vw[w] + 0.5} cy={y + 0.5} r={0.5} />)
}
for (let h = 0; h < vh.length; h++) {
pointList.push(<circle key={id++} fill={posColor} cx={x + 0.5} cy={y + vh[h] + 0.5} r={0.5} />)
}
}
}
else if (typeTable[x][y] == QRPointType.POS_OTHER) {
if (posType == 0) {
pointList.push(<rect width={1} height={1} key={id++} fill={posColor} x={x} y={y}/>);
}
}
else {
if (type == 0)
pointList.push(<rect opacity={opacity} width={size} height={size} key={id++} fill={otherColor} x={x + (1 - size)/2} y={y + (1 - size)/2}/>)
else if (type == 1)
pointList.push(<circle opacity={opacity} r={size / 2} key={id++} fill={otherColor} cx={x + 0.5} cy={y + 0.5}/>)
else if (type == 2)
pointList.push(<circle opacity={opacity} key={id++} fill={otherColor} cx={x + 0.5} cy={y + 0.5} r={0.5 * rand(0.33,1.0)} />)
}
}
}
return pointList;
}
function getParamInfo() {
return [
{
type: ParamTypes.SELECTOR,
key: '信息点样式',
default: 2,
choices: [
"矩形",
"圆形",
"随机"
]
},
{
type: ParamTypes.TEXT_EDITOR,
key: '信息点缩放',
default: 80
},
{
type: ParamTypes.TEXT_EDITOR,
key: '信息点不透明度',
default: 100,
},
{
type: ParamTypes.SELECTOR,
key: '定位点样式',
default: 2,
choices: [
"矩形",
"圆形",
"行星",
]
},
{
type: ParamTypes.COLOR_EDITOR,
key: '信息点颜色',
default: '#000000'
},
{
type: ParamTypes.COLOR_EDITOR,
key: '定位点点颜色',
default: '#000000'
}
];
}
const RendererBase = ({ qrcode, params, setParamInfo}) => {
useEffect(() => {
setParamInfo(getParamInfo());
}, [setParamInfo]);
return (
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(qrcode)} fill="white"
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
{listPoints(qrcode, params)}
</svg>
)
}
export default RendererBase

File diff suppressed because one or more lines are too long

View File

@ -1,132 +0,0 @@
import React, { useEffect } from "react";
import {defaultViewBox, rand} from "../../utils/util";
import {ParamTypes} from "../../constant/ParamTypes";
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
function listPoints(qrcode, params) {
if (!qrcode) return []
const nCount = qrcode.getModuleCount();
const typeTable = getTypeTable(qrcode);
const pointList = new Array(nCount);
let type = params[0];
let size = params[1] / 100;
let opacity = params[2] / 100;
let posType = params[3];
let id = 0;
let otherColor = params[4];
let posColor = params[5];
const vw = [3, -3];
const vh = [3, -3];
if (size <= 0) size = 1.0
for (let x = 0; x < nCount; x++) {
for (let y = 0; y < nCount; y++) {
if (qrcode.isDark(x, y) == false) continue;
if (typeTable[x][y] == QRPointType.ALIGN_CENTER || typeTable[x][y] == QRPointType.ALIGN_OTHER || typeTable[x][y] == QRPointType.TIMING) {
if (type == 0)
pointList.push(<rect opacity={opacity} width={size} height={size} key={id++} fill={otherColor} x={x + (1 - size)/2} y={y + (1 - size)/2}/>)
else if (type == 1)
pointList.push(<circle opacity={opacity} r={size / 2} key={id++} fill={otherColor} cx={x + 0.5} cy={y + 0.5}/>)
else if (type == 2)
pointList.push(<circle key={id++} opacity={opacity} fill={otherColor} cx={x + 0.5} cy={y + 0.5} r={size / 2} />)
}
else if (typeTable[x][y] == QRPointType.POS_CENTER) {
if (posType == 0) {
pointList.push(<rect width={1} height={1} key={id++} fill={posColor} x={x} y={y}/>);
} else if (posType == 1) {
pointList.push(<circle key={id++} fill={posColor} cx={x + 0.5} cy={y + 0.5} r={1.5} />)
pointList.push(<circle key={id++} fill="none" strokeWidth="1" stroke={posColor} cx={x + 0.5} cy={y + 0.5} r={3} />)
} else if (posType == 2) {
pointList.push(<circle key={id++} fill={posColor} cx={x + 0.5} cy={y + 0.5} r={1.5} />)
pointList.push(<circle key={id++} fill="none" strokeWidth="0.15" strokeDasharray="0.5,0.5" stroke={posColor} cx={x + 0.5} cy={y + 0.5} r={3} />)
for (let w = 0; w < vw.length; w++) {
pointList.push(<circle key={id++} fill={posColor} cx={x + vw[w] + 0.5} cy={y + 0.5} r={0.5} />)
}
for (let h = 0; h < vh.length; h++) {
pointList.push(<circle key={id++} fill={posColor} cx={x + 0.5} cy={y + vh[h] + 0.5} r={0.5} />)
}
}
}
else if (typeTable[x][y] == QRPointType.POS_OTHER) {
if (posType == 0) {
pointList.push(<rect width={1} height={1} key={id++} fill={posColor} x={x} y={y}/>);
}
}
else {
if (type == 0)
pointList.push(<rect opacity={opacity} width={size} height={size} key={id++} fill={otherColor} x={x + (1 - size)/2} y={y + (1 - size)/2}/>)
else if (type == 1)
pointList.push(<circle opacity={opacity} r={size / 2} key={id++} fill={otherColor} cx={x + 0.5} cy={y + 0.5}/>)
else if (type == 2)
pointList.push(<circle opacity={opacity} key={id++} fill={otherColor} cx={x + 0.5} cy={y + 0.5} r={0.5 * rand(0.33,1.0)} />)
}
}
}
return pointList;
}
function getParamInfo() {
return [
{
type: ParamTypes.SELECTOR,
key: '信息点样式',
default: 1,
choices: [
"矩形",
"圆形",
"随机"
]
},
{
type: ParamTypes.TEXT_EDITOR,
key: '信息点缩放',
default: 50
},
{
type: ParamTypes.TEXT_EDITOR,
key: '信息点不透明度',
default: 30,
},
{
type: ParamTypes.SELECTOR,
key: '定位点样式',
default: 1,
choices: [
"矩形",
"圆形",
"行星",
]
},
{
type: ParamTypes.COLOR_EDITOR,
key: '信息点颜色',
default: '#000000'
},
{
type: ParamTypes.COLOR_EDITOR,
key: '定位点点颜色',
default: '#000000'
}
];
}
const RendererBase = ({ qrcode, params, setParamInfo}) => {
useEffect(() => {
setParamInfo(getParamInfo());
}, [setParamInfo]);
return (
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={defaultViewBox(qrcode)} fill="white"
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
{listPoints(qrcode, params)}
</svg>
)
}
export default RendererBase

View File

@ -1,4 +1,5 @@
import React from "react"; import React, {useEffect} from "react";
import {extend} from "../../utils/util";
const Renderer = ({ rendererType, ...other }) => ( const Renderer = ({ rendererType, ...other }) => (
React.createElement(rendererType, other) React.createElement(rendererType, other)
@ -8,4 +9,38 @@ function areEqual(prevProps, nextProps) {
return !(prevProps.selected == true || nextProps.selected == true) return !(prevProps.selected == true || nextProps.selected == true)
} }
export function createRenderer(renderer) {
let defaultViewBox = function (qrcode) {
if (!qrcode) return '0 0 0 0';
const nCount = qrcode.getModuleCount();
return String(-nCount / 5) + ' ' + String(-nCount / 5) + ' ' + String(nCount + nCount / 5 * 2) + ' ' + String(nCount + nCount / 5 * 2);
}
renderer = extend({
getViewBox: defaultViewBox,
listPoints: (qrcode, params) => { return []; },
getParamInfo: () => {return []; },
beginRendering: ({ qrcode, params, setParamInfo }) => {},
beforeListing: ({ qrcode, params, setParamInfo }) => {},
afterListing: ({ qrcode, params, setParamInfo }) => {},
}, renderer);
return ({ qrcode, params, setParamInfo}) => {
useEffect(() => {
setParamInfo(renderer.getParamInfo());
}, [setParamInfo]);
renderer.beginRendering({ qrcode, params, setParamInfo });
return (
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={renderer.getViewBox(qrcode)} fill="white"
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
{renderer.beforeListing({ qrcode, params, setParamInfo })}
{renderer.listPoints(qrcode, params)}
{renderer.afterListing({ qrcode, params, setParamInfo })}
</svg>
);
}
}
export default React.memo(Renderer, areEqual) export default React.memo(Renderer, areEqual)

View File

@ -4,4 +4,5 @@ export const actionTypes = {
CHANGE_CORRECT_LEVEL: 'CHANGE_CORRECT_LEVEL', CHANGE_CORRECT_LEVEL: 'CHANGE_CORRECT_LEVEL',
CREATE_PARAM: 'CREATE_PARAM', CREATE_PARAM: 'CREATE_PARAM',
CHANGE_PARAM: 'CHANGE_PARAM', CHANGE_PARAM: 'CHANGE_PARAM',
LOAD_DOWNLOAD_DATA: 'LOAD_DOWNLOAD_DATA',
} }

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
import {connect} from 'react-redux'; import {connect} from 'react-redux';
import {genQRInfo} from "../../actions"; import {genQRInfo} from "../../actions";
import React, {useRef} from "react"; import React, {useRef} from "react";
import {isPicture} from "../../utils/util"; import {isPicture} from "../../utils/imageUtils";
import {decodeData} from "../../utils/qrcodeHandler"; import {decodeData} from "../../utils/qrcodeHandler";
const InputText = ({dispatch}) => { const InputText = ({dispatch}) => {

View File

@ -1,11 +1,19 @@
import { connect } from 'react-redux'; import {connect} from 'react-redux';
import PartDownload from "../../components/app/PartDownload"; import PartDownload from "../../components/app/PartDownload";
import {saveImg, saveSvg} from "../../utils/downloader"; import {saveImg, saveSvg} from "../../utils/downloader";
import {increaseDownloadData, recordDownloadDetail} from "../../api/db"; import {getDownloadCount, increaseDownloadData, recordDownloadDetail} from "../../api/db";
import {getParamDetailedValue, outerHtml} from "../../utils/util"; import {getParamDetailedValue, outerHtml} from "../../utils/util";
function saveDB(state, type) { function saveDB(state, type, updateDownloadData) {
increaseDownloadData(state.value) increaseDownloadData(state.value, () => {
getDownloadCount((res) => {
let downloadData = [];
res.data.forEach((item) => {
downloadData[item.value] = item.count;
});
updateDownloadData(downloadData);
});
});
recordDownloadDetail({ recordDownloadDetail({
text: state.textUrl, text: state.textUrl,
value: state.value, value: state.value,
@ -23,14 +31,15 @@ function saveDB(state, type) {
}); });
} }
const mapStateToProps = (state) => ({ const mapStateToProps = (state, ownProps) => ({
value: state.value, value: state.value,
downloadCount: state.downloadData[state.value],
onSvgDownload: () => { onSvgDownload: () => {
saveSvg(state.value, outerHtml(state.selectedIndex)) saveSvg(state.value, outerHtml(state.selectedIndex))
saveDB(state, 'svg') saveDB(state, 'svg', ownProps.updateDownloadData)
}, },
onJpgDownload: () => { onJpgDownload: () => {
saveDB(state, 'jpg') saveDB(state, 'jpg', ownProps.updateDownloadData)
return saveImg(state.value, outerHtml(state.selectedIndex), 1500, 1500) return saveImg(state.value, outerHtml(state.selectedIndex), 1500, 1500)
} }
}) })

View File

@ -1,7 +1,7 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import {changeParam} from "../../actions"; import {changeParam} from "../../actions";
import ParamUpload from "../../components/param/ParamUpload"; import ParamUpload from "../../components/param/ParamUpload";
import {isPicture, toBase64} from "../../utils/util"; import {isPicture, toBase64} from "../../utils/imageUtils";
const mapStateToProps = (state, ownProps) => ({ const mapStateToProps = (state, ownProps) => ({
rendererIndex: ownProps.rendererIndex, rendererIndex: ownProps.rendererIndex,

View File

@ -2,18 +2,16 @@ import {connect} from 'react-redux';
import {changeStyle} from "../../actions"; import {changeStyle} from "../../actions";
import StyleList from "../../components/style/StyleList"; import StyleList from "../../components/style/StyleList";
import RendererViewer from "./RendererViewer"; import RendererViewer from "./RendererViewer";
import RendererBase from "../../components/renderer/RendererBase";
import RendererDSJ from "../../components/renderer/RendererDSJ"; import RendererDSJ from "../../components/renderer/RendererDSJ";
import RendererRound from "../../components/renderer/RendererRound";
import RendererRandRound from "../../components/renderer/RendererRandRound";
import RendererRandRect from "../../components/renderer/RendererRandRect"; import RendererRandRect from "../../components/renderer/RendererRandRect";
import Renderer25D from "../../components/renderer/Renderer25D"; import Renderer25D from "../../components/renderer/Renderer25D";
import RendererImage from "../../components/renderer/RendererImage"; import RendererImage from "../../components/renderer/RendererImage";
import * as React from "react";
import RendererResImage from "../../components/renderer/RendererResImage"; import RendererResImage from "../../components/renderer/RendererResImage";
import {RendererRandRound, RendererRect, RendererRound} from "../../components/renderer/RendererBase";
import * as React from "react";
const styles = [ const styles = [
{value: "A1", renderer: RendererBase}, {value: "A1", renderer: RendererRect},
{value: "A2", renderer: RendererRound}, {value: "A2", renderer: RendererRound},
{value: "A3", renderer: RendererRandRound}, {value: "A3", renderer: RendererRandRound},
{value: "SP — 1", renderer: RendererDSJ}, {value: "SP — 1", renderer: RendererDSJ},

View File

@ -1,16 +1,17 @@
import {encodeData} from "../utils/qrcodeHandler"; import {encodeData} from "../utils/qrcodeHandler";
import {actionTypes} from "../constant/ActionTypes"; import {actionTypes} from "../constant/ActionTypes";
import {QRBTF_URL} from "../constant/References"; import {QRBTF_URL} from "../constant/References";
import RendererBase from "../components/renderer/RendererBase";
import {getExactValue} from "../utils/util"; import {getExactValue} from "../utils/util";
import {RendererRect} from "../components/renderer/RendererBase";
const initialState = { const initialState = {
selectedIndex: 0, selectedIndex: 0,
value: 'A1', value: 'A1',
rendererType: RendererBase, rendererType: RendererRect,
correctLevel: 0, correctLevel: 0,
textUrl: QRBTF_URL, textUrl: QRBTF_URL,
history: [], history: [],
downloadData: [],
qrcode: encodeData({text: QRBTF_URL, correctLevel: 0}), qrcode: encodeData({text: QRBTF_URL, correctLevel: 0}),
paramInfo: new Array(16).fill(new Array(16)), paramInfo: new Array(16).fill(new Array(16)),
paramValue: new Array(16).fill(new Array(16)) paramValue: new Array(16).fill(new Array(16))
@ -59,6 +60,11 @@ export default function appReducer(state = initialState, action) {
}) })
}); });
} }
case actionTypes.LOAD_DOWNLOAD_DATA: {
return Object.assign({}, state, {
downloadData: action.data
});
}
default: return state default: return state
} }
} }

View File

@ -1,10 +1,6 @@
const svgHead = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n " + const svgHead = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n " +
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n" "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 20010904//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n"
export function isChrome() {
return navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
}
export function saveSvg(value, content) { export function saveSvg(value, content) {
let htmlContent = [svgHead + content] let htmlContent = [svgHead + content]
let bl = new Blob(htmlContent, {type: "image/svg+xml"}) let bl = new Blob(htmlContent, {type: "image/svg+xml"})

33
src/utils/imageUtils.js Normal file
View File

@ -0,0 +1,33 @@
const fileTypes =[
'image/jpeg',
'image/pjpeg',
'image/png'
]
export function isPicture(file) {
return fileTypes.includes(file.type);
}
export function toBase64(file, width, height) {
let canvas = document.createElement('canvas');
let ctx = canvas.getContext('2d');
let img = document.createElement('img');
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
img.setAttribute('src', URL.createObjectURL(file));
return new Promise(resolve => {
img.onload = () => {
ctx.fillStyle = 'white'
ctx.fillRect(0, 0, width, height)
ctx.drawImage(img, 0, 0, width, height);
resolve(canvas.toDataURL(file.type, 0.9));
};
})
}
export function gamma(r, g, b) {
return Math.pow((Math.pow(r, 2.2) + Math.pow(1.5 * g, 2.2) + Math.pow(0.6 * b, 2.2)) / (1 + Math.pow(1.5, 2.2) + Math.pow(0.6, 2.2)), 1/2.2)
}

View File

@ -0,0 +1,27 @@
export function isWeiXin(){
const ua = window.navigator.userAgent.toLowerCase();
if(ua.match(/MicroMessenger/i) == 'micromessenger'){
return true;
}else{
return false;
}
}
export function isPC() {
const userAgentInfo = navigator.userAgent;
const Agents = ["Android", "iPhone",
"SymbianOS", "Windows Phone",
"iPad", "iPod"];
let flag = true;
for (let v = 0; v < Agents.length; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
export function isChrome() {
return navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
}

View File

@ -1,12 +1,6 @@
import { qrcode as QRCodeEncoder } from "./qrcodeEncoder"; import { qrcode as QRCodeEncoder } from "./qrcodeEncoder";
import jsQR from "jsqr"; import jsQR from "jsqr";
import { extend } from "./util";
function extend(target, options) {
for (let name in options) {
target[name] = options[name]
}
return target
}
export var QRPointType = { export var QRPointType = {
DATA: 0, DATA: 0,

View File

@ -1,17 +1,6 @@
import {ParamTypes} from "../constant/ParamTypes"; import {ParamTypes} from "../constant/ParamTypes";
let seed = 0; let seed = 0;
const fileTypes =[
'image/jpeg',
'image/pjpeg',
'image/png'
]
export function isPicture(file) {
return fileTypes.includes(file.type);
}
export function srand(sd) { export function srand(sd) {
seed = sd; seed = sd;
} }
@ -21,47 +10,12 @@ export function rand(min, max) {
return min + (seed / 233280.0) * (max - min); return min + (seed / 233280.0) * (max - min);
} }
export function randRGB(minR, maxR, minG, maxG, minB, maxB) {
return 'rgb(' + parseInt(minR, maxR) + ',' + parseInt(minG, maxG) + ',' + parseInt(minB, maxB) + ')';
}
export function defaultViewBox(qrcode) {
if (!qrcode) return '0 0 0 0';
const nCount = qrcode.getModuleCount();
return String(-nCount / 5) + ' ' + String(-nCount / 5) + ' ' + String(nCount + nCount / 5 * 2) + ' ' + String(nCount + nCount / 5 * 2);
}
export function fillEmptyWith(arr, value) { export function fillEmptyWith(arr, value) {
for (let i = 0; i < arr.length; i++) for (let i = 0; i < arr.length; i++)
if (!arr[i]) arr[i] = value; if (!arr[i]) arr[i] = value;
return arr; return arr;
} }
export function isWeiXin(){
const ua = window.navigator.userAgent.toLowerCase();
if(ua.match(/MicroMessenger/i) == 'micromessenger'){
return true;
}else{
return false;
}
}
export function isPC() {
const userAgentInfo = navigator.userAgent;
const Agents = ["Android", "iPhone",
"SymbianOS", "Windows Phone",
"iPad", "iPod"];
let flag = true;
for (let v = 0; v < Agents.length; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}
export function getParamDetailedValue(item, paramValue) { export function getParamDetailedValue(item, paramValue) {
if (item.type == ParamTypes.SELECTOR) return item.choices[paramValue]; if (item.type == ParamTypes.SELECTOR) return item.choices[paramValue];
return paramValue; return paramValue;
@ -71,10 +25,6 @@ export function outerHtml(selectedIndex) {
return document.getElementsByClassName('Qr-item-svg')[selectedIndex].outerHTML; return document.getElementsByClassName('Qr-item-svg')[selectedIndex].outerHTML;
} }
export function gamma(r, g, b) {
return Math.pow((Math.pow(r, 2.2) + Math.pow(1.5 * g, 2.2) + Math.pow(0.6 * b, 2.2)) / (1 + Math.pow(1.5, 2.2) + Math.pow(0.6, 2.2)), 1/2.2)
}
export function getExactValue(value, defaultValue) { export function getExactValue(value, defaultValue) {
if (typeof value != "string") return value; if (typeof value != "string") return value;
if (value.length <= 0) value = defaultValue; if (value.length <= 0) value = defaultValue;
@ -82,22 +32,10 @@ export function getExactValue(value, defaultValue) {
return value; return value;
} }
export function toBase64(file, width, height) { export function extend(target, options) {
let canvas = document.createElement('canvas'); for (let name in options) {
let ctx = canvas.getContext('2d'); target[name] = options[name]
let img = document.createElement('img'); }
return target
canvas.setAttribute('width', width);
canvas.setAttribute('height', height);
img.setAttribute('src', URL.createObjectURL(file));
return new Promise(resolve => {
img.onload = () => {
ctx.fillStyle = 'white'
ctx.fillRect(0, 0, width, height)
ctx.drawImage(img, 0, 0, width, height);
resolve(canvas.toDataURL(file.type, 0.9));
};
})
} }