commit
5f01a7f510
|
@ -18,7 +18,8 @@
|
||||||
"react-lazy-load": "^3.0.13",
|
"react-lazy-load": "^3.0.13",
|
||||||
"react-redux": "^7.2.0",
|
"react-redux": "^7.2.0",
|
||||||
"react-scripts": "3.4.1",
|
"react-scripts": "3.4.1",
|
||||||
"redux": "^4.0.5"
|
"redux": "^4.0.5",
|
||||||
|
"serialize-javascript": "^3.1.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
|
|
|
@ -36,3 +36,17 @@ export const loadDownloadData = (data) => ({
|
||||||
type: actionTypes.LOAD_DOWNLOAD_DATA,
|
type: actionTypes.LOAD_DOWNLOAD_DATA,
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const changeTitle = (title) => {
|
||||||
|
return {
|
||||||
|
type: actionTypes.CHANGE_TITLE,
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const changeIcon = (icon) => {
|
||||||
|
return {
|
||||||
|
type: actionTypes.CHANGE_ICON,
|
||||||
|
icon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -176,6 +176,7 @@
|
||||||
border: rgba(0,0,0,0.12) solid 2px;
|
border: rgba(0,0,0,0.12) solid 2px;
|
||||||
width: calc((100vw - 56px) / 2);
|
width: calc((100vw - 56px) / 2);
|
||||||
height: calc((100vw - 56px) / 2);
|
height: calc((100vw - 56px) / 2);
|
||||||
|
background: rgba(255,255,255,0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 500px) {
|
@media (min-width: 500px) {
|
||||||
|
@ -567,11 +568,15 @@ input[type="number"]{
|
||||||
}
|
}
|
||||||
|
|
||||||
.div-btn {
|
.div-btn {
|
||||||
white-space: nowrap;
|
|
||||||
overflow-x: hidden;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: 10px;
|
width: calc((100vw - 46px) / 1);
|
||||||
|
display: flex;
|
||||||
|
display: -webkit-flex; /* Safari */
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.div-btn .dl-btn {
|
||||||
|
margin: 0 0 10px!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ul-btn {
|
.ul-btn {
|
||||||
|
@ -603,6 +608,7 @@ input[type="number"]{
|
||||||
background: var(--bg-color);
|
background: var(--bg-color);
|
||||||
font-family: 'Futura', sans-serif;
|
font-family: 'Futura', sans-serif;
|
||||||
color: var(--input-font-color);
|
color: var(--input-font-color);
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 500px) {
|
@media (min-width: 500px) {
|
||||||
|
@ -640,6 +646,7 @@ input[type="number"]{
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 500px) {
|
@media (min-width: 500px) {
|
||||||
|
|
||||||
.div-btn {
|
.div-btn {
|
||||||
max-width: 410px;
|
max-width: 410px;
|
||||||
}
|
}
|
||||||
|
@ -649,6 +656,12 @@ input[type="number"]{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (min-width: 666px) {
|
||||||
|
.img-dl-btn {
|
||||||
|
max-width: 620px!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.Qr-footer {
|
.Qr-footer {
|
||||||
color: var(--footer-font-color);
|
color: var(--footer-font-color);
|
||||||
margin-bottom: -1em;
|
margin-bottom: -1em;
|
||||||
|
|
|
@ -15,7 +15,20 @@ const WxMessage = () => {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const PartDownload = ({ value, downloadCount, onSvgDownload, onJpgDownload }) => {
|
const ImgBox = ({ imgData }) => {
|
||||||
|
if (imgData.length > 0) {
|
||||||
|
return (
|
||||||
|
<div id="dl-image">
|
||||||
|
<div id="dl-image-inner">
|
||||||
|
<img id="dl-image-inner-jpg" src={imgData} alt="长按保存二维码" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const PartDownload = ({ value, downloadCount, onSvgDownload, onImgDownload }) => {
|
||||||
const [imgData, setImgData] = useState('');
|
const [imgData, setImgData] = useState('');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -29,23 +42,17 @@ const PartDownload = ({ value, downloadCount, onSvgDownload, onJpgDownload }) =>
|
||||||
</div>
|
</div>
|
||||||
<div className="Qr-Centered">
|
<div className="Qr-Centered">
|
||||||
<div className="btn-row">
|
<div className="btn-row">
|
||||||
<div className="div-btn">
|
<div className="div-btn img-dl-btn">
|
||||||
<button className="dl-btn" onClick={() => {
|
<button className="dl-btn" onClick={() => {onImgDownload("jpg").then(res => setImgData(res));}}>JPG</button>
|
||||||
onJpgDownload().then(res => setImgData(res));
|
<button className="dl-btn" onClick={() => {onImgDownload("png").then(res => setImgData(res));}}>PNG</button>
|
||||||
}}>
|
|
||||||
JPG
|
|
||||||
</button>
|
|
||||||
<button className="dl-btn" onClick={onSvgDownload}>SVG</button>
|
<button className="dl-btn" onClick={onSvgDownload}>SVG</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="wx-message">
|
<div id="wx-message">
|
||||||
<WxMessage/>
|
<WxMessage/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{
|
<ImgBox imgData={imgData} />
|
||||||
imgData.length > 0 ? <div id="dl-image"><div id="dl-image-inner"><img id="dl-image-inner-jpg" src={imgData} alt="长按保存二维码" /></div></div> : null
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -54,8 +61,9 @@ const PartDownload = ({ value, downloadCount, onSvgDownload, onJpgDownload }) =>
|
||||||
|
|
||||||
PartDownload.propTypes = {
|
PartDownload.propTypes = {
|
||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
|
downloadCount: PropTypes.number,
|
||||||
onSvgDownload: PropTypes.func.isRequired,
|
onSvgDownload: PropTypes.func.isRequired,
|
||||||
onJpgDownload: PropTypes.func.isRequired,
|
onImgDownload: PropTypes.func.isRequired,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PartDownload;
|
export default PartDownload;
|
||||||
|
|
|
@ -51,6 +51,7 @@ const PartMore = () => {
|
||||||
</ScrollContainer>
|
</ScrollContainer>
|
||||||
<div className="Qr-Centered">
|
<div className="Qr-Centered">
|
||||||
<h2>最新消息</h2>
|
<h2>最新消息</h2>
|
||||||
|
<p><b>2020.9.1</b><br/>新增 C3 样式、图标插入、 PNG 下载。</p>
|
||||||
<p><b>2020.6.29</b><br/>新的反馈渠道!我们开始征集好玩的二维码设计啦,可以是推送尾图、海报等等,快来上传吧。<LinkTrace
|
<p><b>2020.6.29</b><br/>新的反馈渠道!我们开始征集好玩的二维码设计啦,可以是推送尾图、海报等等,快来上传吧。<LinkTrace
|
||||||
href='https://qrbtf-com.mikecrm.com/J2wjEEq' rel="noopener noreferrer"
|
href='https://qrbtf-com.mikecrm.com/J2wjEEq' rel="noopener noreferrer"
|
||||||
target="_blank">点击提交</LinkTrace>。</p>
|
target="_blank">点击提交</LinkTrace>。</p>
|
||||||
|
@ -80,9 +81,10 @@ const PartMore = () => {
|
||||||
<p>这个工具开发的初衷之一就是便利设计师将其纳入自己的工作流程中。SVG 是一个优秀的、标准的矢量图片格式,各大设计软件如 Adobe Illustrator、Sketch 等都对 SVG
|
<p>这个工具开发的初衷之一就是便利设计师将其纳入自己的工作流程中。SVG 是一个优秀的、标准的矢量图片格式,各大设计软件如 Adobe Illustrator、Sketch 等都对 SVG
|
||||||
有着很好的支持。用户可以在下载 SVG 后导入这些软件进行二次加工,如删除中央的信息点 <b>放入自己的 Logo</b> 等。如果需要直接分享二维码图像,请直接下载 JPG 格式。
|
有着很好的支持。用户可以在下载 SVG 后导入这些软件进行二次加工,如删除中央的信息点 <b>放入自己的 Logo</b> 等。如果需要直接分享二维码图像,请直接下载 JPG 格式。
|
||||||
</p>
|
</p>
|
||||||
|
<h2>二维码无法识别的原因是什么?</h2>
|
||||||
|
<p>二维码无法识别有很多原因。比如定位点不匹配识别模式、信息点颜色对比不够、遮挡部分太大。建议尝试调整容错率、颜色、图标大小等参数并在各种二维码扫描器中测试,以保证二维码被识别的成功率</p>
|
||||||
<h2>使用遇到了问题,怎么反馈?</h2>
|
<h2>使用遇到了问题,怎么反馈?</h2>
|
||||||
<p>我们是两位大一的学生,忙于学业,可能在设计与开发的过程中有一些疏漏,敬请谅解。如果遇到浏览器兼容问题,请暂时选择更换软件或设备尝试。</p>
|
<p>我们是两位大一的学生,忙于学业,可能在设计与开发的过程中有一些疏漏,敬请谅解。如果遇到浏览器兼容问题,请暂时选择更换软件或设备尝试。</p>
|
||||||
<p>请注意,应用并不能保证二维码时刻可被识别,需要多加测试。</p>
|
|
||||||
<p>编写二维码样式是一个锻炼设计与开发(JavaScript)能力的绝佳机会,如果你有兴趣和我们一起玩这个项目,欢迎添加我的微信(微信号:<span
|
<p>编写二维码样式是一个锻炼设计与开发(JavaScript)能力的绝佳机会,如果你有兴趣和我们一起玩这个项目,欢迎添加我的微信(微信号:<span
|
||||||
style={{userSelect: "text"}}>nhciao</span>,请备注真实姓名)或发送邮件至 <LinkTrace
|
style={{userSelect: "text"}}>nhciao</span>,请备注真实姓名)或发送邮件至 <LinkTrace
|
||||||
href='mailto:contact@qrbtf.com'>contact@qrbtf.com</LinkTrace> 联系我们!</p>
|
href='mailto:contact@qrbtf.com'>contact@qrbtf.com</LinkTrace> 联系我们!</p>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||||
import './App.css';
|
import './App.css';
|
||||||
import ParamListViewer from "../../containers/param/ParamListViewer";
|
import ParamListViewer from "../../containers/param/ParamListViewer";
|
||||||
import ParamCorrectLevelViewer from "../../containers/param/ParamCorrectLevelViewer";
|
import ParamCorrectLevelViewer from "../../containers/param/ParamCorrectLevelViewer";
|
||||||
|
import ParamIconViewer from "../../containers/param/disposable/ParamIconViewer";
|
||||||
|
|
||||||
const PartParams = () => (
|
const PartParams = () => (
|
||||||
<div className="Qr-titled-nobg">
|
<div className="Qr-titled-nobg">
|
||||||
|
@ -12,6 +13,7 @@ const PartParams = () => (
|
||||||
<div className="Qr-Centered">
|
<div className="Qr-Centered">
|
||||||
<div className="Qr-div-table">
|
<div className="Qr-div-table">
|
||||||
<ParamCorrectLevelViewer/>
|
<ParamCorrectLevelViewer/>
|
||||||
|
<ParamIconViewer/>
|
||||||
<ParamListViewer/>
|
<ParamListViewer/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import '../Qrcode.css';
|
||||||
|
|
||||||
|
const FrameworkParam = ({ paramName, children, ...other }) => (
|
||||||
|
<table className="Qr-table" {...other}>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>{ paramName }</td>
|
||||||
|
<td>
|
||||||
|
{ children }
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default FrameworkParam;
|
|
@ -42,7 +42,7 @@ const ParamColor = ({ rendererIndex, paramIndex, value, onChange }) => {
|
||||||
<div style={styles.cover} onClick={() => setDisplay(false)} />
|
<div style={styles.cover} onClick={() => setDisplay(false)} />
|
||||||
<TwitterPicker
|
<TwitterPicker
|
||||||
key={"input_" + rendererIndex + "_" + paramIndex}
|
key={"input_" + rendererIndex + "_" + paramIndex}
|
||||||
triangle="none"
|
triangle="hide"
|
||||||
color={value}
|
color={value}
|
||||||
colors={['#FF6900', '#FCB900', '#7BDCB5', '#00D084', '#8ED1FC', '#0693E3', '#ABB8C3', '#EB144C', '#F78DA7', '#9900EF']}
|
colors={['#FF6900', '#FCB900', '#7BDCB5', '#00D084', '#8ED1FC', '#0693E3', '#ABB8C3', '#EB144C', '#F78DA7', '#9900EF']}
|
||||||
onChangeComplete={onChange}
|
onChangeComplete={onChange}
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import '../Qrcode.css';
|
|
||||||
|
|
||||||
const ParamCorrectLevel = ({value, onChange}) => (
|
|
||||||
<table className="Qr-table">
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>容错率</td>
|
|
||||||
<td>
|
|
||||||
<select
|
|
||||||
className="Qr-select"
|
|
||||||
value={value}
|
|
||||||
onChange={onChange}>
|
|
||||||
<option value={1}>7%</option>
|
|
||||||
<option value={0}>15%</option>
|
|
||||||
<option value={3}>25%</option>
|
|
||||||
<option value={2}>30%</option>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
)
|
|
||||||
|
|
||||||
ParamCorrectLevel.propTypes = {
|
|
||||||
value: PropTypes.number.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ParamCorrectLevel;
|
|
|
@ -6,6 +6,7 @@ import ParamSelectViewer from "../../containers/param/ParamSelectViewer";
|
||||||
import ParamColorViewer from "../../containers/param/ParamColorViewer";
|
import ParamColorViewer from "../../containers/param/ParamColorViewer";
|
||||||
import ParamUploadViewer from "../../containers/param/ParamUploadViewer";
|
import ParamUploadViewer from "../../containers/param/ParamUploadViewer";
|
||||||
import ParamCheckBoxViewer from "../../containers/param/ParamCheckBoxViewer";
|
import ParamCheckBoxViewer from "../../containers/param/ParamCheckBoxViewer";
|
||||||
|
import FrameworkParam from "./FrameworkParam";
|
||||||
|
|
||||||
const mapTypeToComponent = ({
|
const mapTypeToComponent = ({
|
||||||
[ParamTypes.TEXT_EDITOR]: ParamTextViewer,
|
[ParamTypes.TEXT_EDITOR]: ParamTextViewer,
|
||||||
|
@ -18,19 +19,12 @@ const mapTypeToComponent = ({
|
||||||
const ParamList = ({ rendererIndex, paramInfo }) => (
|
const ParamList = ({ rendererIndex, paramInfo }) => (
|
||||||
paramInfo.map((item, paramIndex) => {
|
paramInfo.map((item, paramIndex) => {
|
||||||
return (
|
return (
|
||||||
<table className="Qr-table" key={"tr_" + rendererIndex + "_" + paramIndex}>
|
<FrameworkParam key={"tr_" + rendererIndex + "_" + paramIndex} paramName={item.key}>
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>{item.key}</td>
|
|
||||||
<td>
|
|
||||||
{React.createElement(mapTypeToComponent[item.type], {
|
{React.createElement(mapTypeToComponent[item.type], {
|
||||||
rendererIndex: rendererIndex,
|
rendererIndex: rendererIndex,
|
||||||
paramIndex: paramIndex
|
paramIndex: paramIndex
|
||||||
})}
|
})}
|
||||||
</td>
|
</FrameworkParam>
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import '../../Qrcode.css';
|
||||||
|
import FrameworkParam from "../FrameworkParam";
|
||||||
|
|
||||||
|
const ParamCorrectLevel = ({value, onChange}) => (
|
||||||
|
<FrameworkParam paramName={"容错率"}>
|
||||||
|
<select
|
||||||
|
className="Qr-select"
|
||||||
|
value={value}
|
||||||
|
onChange={onChange}>
|
||||||
|
<option value={1}>7%</option>
|
||||||
|
<option value={0}>15%</option>
|
||||||
|
<option value={3}>25%</option>
|
||||||
|
<option value={2}>30%</option>
|
||||||
|
</select>
|
||||||
|
</FrameworkParam>
|
||||||
|
)
|
||||||
|
|
||||||
|
ParamCorrectLevel.propTypes = {
|
||||||
|
value: PropTypes.number.isRequired,
|
||||||
|
onChange: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ParamCorrectLevel;
|
|
@ -0,0 +1,60 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import '../../Qrcode.css';
|
||||||
|
import FrameworkParam from "../FrameworkParam";
|
||||||
|
import {getExactValue} from "../../../utils/util";
|
||||||
|
import ParamIconSrcViewer from "../../../containers/param/disposable/ParamIconSrcViewer";
|
||||||
|
|
||||||
|
const IconParams = ({ icon, onBlur, onKeyPress }) => {
|
||||||
|
const { enabled, src, scale } = icon;
|
||||||
|
const components = [];
|
||||||
|
|
||||||
|
if (getExactValue(enabled, 0) == 1) {
|
||||||
|
components.push(
|
||||||
|
<FrameworkParam paramName={"图标源"}>
|
||||||
|
<ParamIconSrcViewer icon={icon} onChange={onBlur}/>
|
||||||
|
</FrameworkParam>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getExactValue(enabled, 0) != 0) {
|
||||||
|
components.push(
|
||||||
|
<FrameworkParam paramName={"图标缩放"}>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="Qr-input small-input"
|
||||||
|
defaultValue={scale}
|
||||||
|
onBlur={(e) => onBlur({...icon, scale: e.target.value})}
|
||||||
|
onKeyPress={(e) => onKeyPress(e, {...icon, scale: e.target.value})}
|
||||||
|
/>
|
||||||
|
</FrameworkParam>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return components;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ParamIcon = ({icon, onBlur, onKeyPress}) => (
|
||||||
|
<React.Fragment>
|
||||||
|
<FrameworkParam paramName={"图标"}>
|
||||||
|
<select
|
||||||
|
className="Qr-select"
|
||||||
|
defaultValue={icon.enabled}
|
||||||
|
onChange={(e) => onBlur({...icon, enabled: e.target.value})}>
|
||||||
|
<option value={0}>无</option>
|
||||||
|
<option value={1}>自定义</option>
|
||||||
|
<option value={2}>微信 — 小</option>
|
||||||
|
<option value={3}>微信</option>
|
||||||
|
<option value={4}>微信支付</option>
|
||||||
|
<option value={5}>支付宝</option>
|
||||||
|
</select>
|
||||||
|
</FrameworkParam>
|
||||||
|
<IconParams icon={icon} onBlur={onBlur} onKeyPress={onKeyPress}/>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
|
||||||
|
ParamIcon.propTypes = {
|
||||||
|
icon: PropTypes.object.isRequired,
|
||||||
|
onChange: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ParamIcon;
|
|
@ -0,0 +1,67 @@
|
||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import '../../Qrcode.css';
|
||||||
|
import FrameworkParam from "../FrameworkParam";
|
||||||
|
import {getExactValue} from "../../../utils/util";
|
||||||
|
import ParamTitleColorViewer from "../../../containers/param/disposable/ParamTitleColorViewer";
|
||||||
|
|
||||||
|
const TitleParams = ({ title, onChange }) => {
|
||||||
|
const { enabled, text, color, size, align } = title;
|
||||||
|
if (getExactValue(enabled, 0)) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<FrameworkParam paramName={"标题内容"}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="Qr-input small-input"
|
||||||
|
value={text}
|
||||||
|
onChange={(e) => onChange({...title, text: e.target.value})}
|
||||||
|
/>
|
||||||
|
</FrameworkParam>
|
||||||
|
<FrameworkParam paramName={"标题颜色"}>
|
||||||
|
<ParamTitleColorViewer title={title} onChange={onChange}/>
|
||||||
|
</FrameworkParam>
|
||||||
|
<FrameworkParam paramName={"标题大小"}>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
className="Qr-input small-input"
|
||||||
|
value={size}
|
||||||
|
onChange={(e) => onChange({...title, size: e.target.value})}
|
||||||
|
/>
|
||||||
|
</FrameworkParam>
|
||||||
|
<FrameworkParam paramName={"标题对齐"}>
|
||||||
|
<select
|
||||||
|
className="Qr-select"
|
||||||
|
value={title.align}
|
||||||
|
onChange={(e) => onChange({...title, align: e.target.value})}>
|
||||||
|
<option value={"middle"}>中间</option>
|
||||||
|
<option value={"bottom"}>底部</option>
|
||||||
|
</select>
|
||||||
|
</FrameworkParam>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ParamTitle = ({title, onChange}) => (
|
||||||
|
<React.Fragment>
|
||||||
|
<FrameworkParam paramName={"启用标题"}>
|
||||||
|
<select
|
||||||
|
className="Qr-select"
|
||||||
|
value={title.enabled}
|
||||||
|
onChange={(e) => onChange({...title, enabled: e.target.value})}>
|
||||||
|
<option value={0}>否</option>
|
||||||
|
<option value={1}>是</option>
|
||||||
|
</select>
|
||||||
|
</FrameworkParam>
|
||||||
|
<TitleParams title={title} onChange={onChange}/>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
|
||||||
|
ParamTitle.propTypes = {
|
||||||
|
title: PropTypes.object.isRequired,
|
||||||
|
onChange: PropTypes.func.isRequired
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ParamTitle;
|
|
@ -2,8 +2,15 @@ import React from "react";
|
||||||
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 {createRenderer} from "../style/Renderer";
|
||||||
|
import {getExactValue, getIdNum} from "../../utils/util";
|
||||||
|
|
||||||
function listPoints(qrcode, params) {
|
const X = [ Math.sqrt(3)/2, 1/2];
|
||||||
|
const Y = [-Math.sqrt(3)/2, 1/2];
|
||||||
|
const Z = [0, 0];
|
||||||
|
|
||||||
|
const matrixString = 'matrix(' + String(X[0]) + ', ' + String(X[1]) + ', ' + String(Y[0]) + ', ' + String(Y[1]) + ', ' + String(Z[0]) + ', ' + String(Z[1]) + ')'
|
||||||
|
|
||||||
|
function listPoints({ qrcode, params, icon }) {
|
||||||
if (!qrcode) return []
|
if (!qrcode) return []
|
||||||
|
|
||||||
const nCount = qrcode.getModuleCount();
|
const nCount = qrcode.getModuleCount();
|
||||||
|
@ -19,12 +26,6 @@ function listPoints(qrcode, params) {
|
||||||
let rightColor = params[4];
|
let rightColor = params[4];
|
||||||
let id = 0;
|
let id = 0;
|
||||||
|
|
||||||
const X = [-Math.sqrt(3)/2, 1/2];
|
|
||||||
const Y = [ Math.sqrt(3)/2, 1/2];
|
|
||||||
const Z = [0, 0];
|
|
||||||
|
|
||||||
const matrixString = 'matrix(' + String(X[0]) + ', ' + String(X[1]) + ', ' + String(Y[0]) + ', ' + String(Y[1]) + ', ' + String(Z[0]) + ', ' + String(Z[1]) + ')'
|
|
||||||
|
|
||||||
if (height <= 0) height = 1.0;
|
if (height <= 0) height = 1.0;
|
||||||
if (height2 <= 0) height2 = 1.0;
|
if (height2 <= 0) height2 = 1.0;
|
||||||
|
|
||||||
|
@ -77,6 +78,149 @@ function getParamInfo() {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let defaultDrawIcon = function ({ qrcode, params, title, icon }) {
|
||||||
|
if (!qrcode) return []
|
||||||
|
|
||||||
|
let id = 0;
|
||||||
|
const nCount = qrcode.getModuleCount();
|
||||||
|
const pointList = [];
|
||||||
|
const sq25 = "M32.048565,-1.29480038e-15 L67.951435,1.29480038e-15 C79.0954192,-7.52316311e-16 83.1364972,1.16032014 87.2105713,3.3391588 C91.2846454,5.51799746 94.4820025,8.71535463 96.6608412,12.7894287 C98.8396799,16.8635028 100,20.9045808 100,32.048565 L100,67.951435 C100,79.0954192 98.8396799,83.1364972 96.6608412,87.2105713 C94.4820025,91.2846454 91.2846454,94.4820025 87.2105713,96.6608412 C83.1364972,98.8396799 79.0954192,100 67.951435,100 L32.048565,100 C20.9045808,100 16.8635028,98.8396799 12.7894287,96.6608412 C8.71535463,94.4820025 5.51799746,91.2846454 3.3391588,87.2105713 C1.16032014,83.1364972 5.01544207e-16,79.0954192 -8.63200256e-16,67.951435 L8.63200256e-16,32.048565 C-5.01544207e-16,20.9045808 1.16032014,16.8635028 3.3391588,12.7894287 C5.51799746,8.71535463 8.71535463,5.51799746 12.7894287,3.3391588 C16.8635028,1.16032014 20.9045808,7.52316311e-16 32.048565,-1.29480038e-15 Z";
|
||||||
|
|
||||||
|
// draw icon
|
||||||
|
if (icon) {
|
||||||
|
const iconEnabled = getExactValue(icon.enabled, 0);
|
||||||
|
const {src, scale} = icon;
|
||||||
|
|
||||||
|
const iconSize = Number(nCount * (scale > 33 ? 33 : scale) / 100);
|
||||||
|
const iconXY = (nCount - iconSize) / 2;
|
||||||
|
|
||||||
|
if (icon && iconEnabled) {
|
||||||
|
|
||||||
|
const randomIdDefs = getIdNum();
|
||||||
|
const randomIdClips = getIdNum();
|
||||||
|
pointList.push(
|
||||||
|
<g transform={matrixString}>
|
||||||
|
<path d={sq25} stroke="#FFF" strokeWidth={100/iconSize * 1} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} />
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
pointList.push(
|
||||||
|
<g key={id++} transform={matrixString}>
|
||||||
|
<defs>
|
||||||
|
<path id={"defs-path" + randomIdDefs} d={sq25} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} /> </defs>
|
||||||
|
<clipPath id={"clip-path" + randomIdClips}>
|
||||||
|
<use xlinkHref={"#defs-path" + randomIdDefs} overflow="visible"/>
|
||||||
|
</clipPath>
|
||||||
|
<g clipPath={"url(#clip-path" + randomIdClips + ")"}>
|
||||||
|
<image overflow="visible" key={id++} xlinkHref={src} width={iconSize} x={iconXY} y={iconXY} />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pointList;
|
||||||
|
}
|
||||||
|
|
||||||
|
let builtinDrawIcon = function ({ qrcode, params, title, icon }) {
|
||||||
|
if (!qrcode) return []
|
||||||
|
|
||||||
|
let id = 0;
|
||||||
|
const nCount = qrcode.getModuleCount();
|
||||||
|
const pointList = [];
|
||||||
|
const sq25 = "M32.048565,-1.29480038e-15 L67.951435,1.29480038e-15 C79.0954192,-7.52316311e-16 83.1364972,1.16032014 87.2105713,3.3391588 C91.2846454,5.51799746 94.4820025,8.71535463 96.6608412,12.7894287 C98.8396799,16.8635028 100,20.9045808 100,32.048565 L100,67.951435 C100,79.0954192 98.8396799,83.1364972 96.6608412,87.2105713 C94.4820025,91.2846454 91.2846454,94.4820025 87.2105713,96.6608412 C83.1364972,98.8396799 79.0954192,100 67.951435,100 L32.048565,100 C20.9045808,100 16.8635028,98.8396799 12.7894287,96.6608412 C8.71535463,94.4820025 5.51799746,91.2846454 3.3391588,87.2105713 C1.16032014,83.1364972 5.01544207e-16,79.0954192 -8.63200256e-16,67.951435 L8.63200256e-16,32.048565 C-5.01544207e-16,20.9045808 1.16032014,16.8635028 3.3391588,12.7894287 C5.51799746,8.71535463 8.71535463,5.51799746 12.7894287,3.3391588 C16.8635028,1.16032014 20.9045808,7.52316311e-16 32.048565,-1.29480038e-15 Z";
|
||||||
|
|
||||||
|
// draw icon
|
||||||
|
if (icon) {
|
||||||
|
const iconMode = getExactValue(icon.enabled, 0);
|
||||||
|
const {src, scale} = icon;
|
||||||
|
|
||||||
|
const iconSize = Number(nCount * (scale > 33 ? 33 : scale) / 100);
|
||||||
|
const iconXY = (nCount - iconSize) / 2;
|
||||||
|
|
||||||
|
const WeChatIconSmall = (
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#07c160"/>
|
||||||
|
<path d="M39.061,44.018a4.375,4.375,0,1,1,4.374-4.375,4.375,4.375,0,0,1-4.374,4.375m21.877,0a4.375,4.375,0,1,1,4.376-4.375,4.375,4.375,0,0,1-4.376,4.375M28.522,69.063a2.184,2.184,0,0,1,.92,1.782,2.581,2.581,0,0,1-.116.7c-.552,2.06-1.437,5.361-1.478,5.516a3.237,3.237,0,0,0-.177.8,1.093,1.093,0,0,0,1.094,1.093,1.243,1.243,0,0,0,.633-.2L36.581,74.6a3.427,3.427,0,0,1,1.742-.5,3.3,3.3,0,0,1,.965.144A38.825,38.825,0,0,0,50,75.739c18.123,0,32.816-12.242,32.816-27.346S68.122,21.049,50,21.049,17.185,33.29,17.185,48.393c0,8.239,4.42,15.656,11.337,20.67" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
const WeChatIcon = (
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#07c160"/>
|
||||||
|
<path d="M48.766,39.21a2.941,2.941,0,1,1,2.918-2.94,2.929,2.929,0,0,1-2.918,2.94m-16.455,0a2.941,2.941,0,1,1,2.918-2.941,2.93,2.93,0,0,1-2.918,2.941m8.227-17.039c-13.632,0-24.682,9.282-24.682,20.732,0,6.247,3.324,11.87,8.528,15.67a1.662,1.662,0,0,1,.691,1.352,1.984,1.984,0,0,1-.087.528c-.415,1.563-1.081,4.064-1.112,4.181a2.449,2.449,0,0,0-.132.607.825.825,0,0,0,.823.828.914.914,0,0,0,.474-.154l5.405-3.144a2.57,2.57,0,0,1,1.31-.382,2.442,2.442,0,0,1,.725.109,28.976,28.976,0,0,0,8.057,1.137c.455,0,.907-.012,1.356-.032a16.084,16.084,0,0,1-.829-5.082c0-10.442,10.078-18.908,22.511-18.908.45,0,.565.015,1.008.037-1.858-9.9-11.732-17.479-24.046-17.479" fill="#fff"/>
|
||||||
|
<path d="M70.432,55.582A2.589,2.589,0,1,1,73,52.994a2.578,2.578,0,0,1-2.568,2.588m-13.713,0a2.589,2.589,0,1,1,2.568-2.588,2.578,2.578,0,0,1-2.568,2.588m20.319,16a16.3,16.3,0,0,0,7.106-13.058c0-9.542-9.208-17.276-20.568-17.276s-20.57,7.734-20.57,17.276S52.216,75.8,63.576,75.8a24.161,24.161,0,0,0,6.714-.947,2.079,2.079,0,0,1,.6-.091,2.138,2.138,0,0,1,1.092.319l4.5,2.62a.78.78,0,0,0,.4.129.688.688,0,0,0,.685-.691,2.081,2.081,0,0,0-.11-.5l-.927-3.486a1.641,1.641,0,0,1-.073-.44,1.385,1.385,0,0,1,.577-1.126" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
const WeChatPayIcon = (
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#07c160"/>
|
||||||
|
<path d="M41.055,57.675a2.183,2.183,0,0,1-2.893-.883l-.143-.314L32.046,43.37a1.133,1.133,0,0,1-.105-.461,1.094,1.094,0,0,1,1.748-.877l7.049,5.019a3.249,3.249,0,0,0,2.914.333L76.8,32.63c-5.942-7-15.728-11.581-26.8-11.581-18.122,0-32.813,12.243-32.813,27.345,0,8.24,4.42,15.656,11.338,20.669a2.185,2.185,0,0,1,.919,1.781,2.569,2.569,0,0,1-.116.7c-.552,2.062-1.437,5.362-1.478,5.516a3.212,3.212,0,0,0-.177.8,1.094,1.094,0,0,0,1.1,1.094,1.236,1.236,0,0,0,.631-.2L36.583,74.6a3.438,3.438,0,0,1,1.742-.5,3.281,3.281,0,0,1,.965.145A38.844,38.844,0,0,0,50,75.739c18.122,0,32.813-12.243,32.813-27.345a23.668,23.668,0,0,0-3.738-12.671L41.3,57.537Z" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
const AlipayIcon = (
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#009ce1"/>
|
||||||
|
<path d="M100,67.856c-.761-.1-4.8-.8-17.574-5.066-4.012-1.339-9.4-3.389-15.395-5.552A80.552,80.552,0,0,0,75.4,36.156H55.633v-7.1H79.848V25.094H55.633V13.258H45.749a1.68,1.68,0,0,0-1.733,1.707V25.094H19.524v3.963H44.016v7.1H23.8V40.12H63.013a69.579,69.579,0,0,1-5.65,13.763c-12.724-4.187-26.3-7.58-34.834-5.491C17.074,49.733,13.56,52.125,11.5,54.63,2.02,66.125,8.815,83.585,28.824,83.585c11.831,0,23.228-6.579,32.061-17.417C73.49,72.211,97.914,82.4,100,83.267ZM26.956,76.9c-15.6,0-20.215-12.255-12.5-18.958,2.573-2.266,7.276-3.372,9.782-3.621,9.268-.913,17.846,2.613,27.972,7.541C45.087,71.118,36.023,76.9,26.956,76.9Z" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
function builtinIcon() {
|
||||||
|
if (iconMode === 2) {
|
||||||
|
return WeChatIconSmall
|
||||||
|
} else if (iconMode === 3) {
|
||||||
|
return WeChatIcon
|
||||||
|
} else if (iconMode === 4) {
|
||||||
|
return WeChatPayIcon
|
||||||
|
} else if (iconMode === 5) {
|
||||||
|
return AlipayIcon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icon && iconMode) {
|
||||||
|
const randomIdDefs = getIdNum();
|
||||||
|
const randomIdClips = getIdNum();
|
||||||
|
pointList.push(
|
||||||
|
<g transform={matrixString}>
|
||||||
|
<path d={sq25} stroke="#FFF" strokeWidth={100/iconSize * 1} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} />
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
pointList.push(
|
||||||
|
<g key={id++} transform={matrixString}>
|
||||||
|
<defs>
|
||||||
|
<path id={"defs-path" + randomIdDefs} d={sq25} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} /> </defs>
|
||||||
|
<clipPath id={"clip-path" + randomIdClips}>
|
||||||
|
<use xlinkHref={"#defs-path" + randomIdDefs} overflow="visible"/>
|
||||||
|
</clipPath>
|
||||||
|
<g clipPath={"url(#clip-path" + randomIdClips + ")"}>
|
||||||
|
<g transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} >
|
||||||
|
{builtinIcon()}
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pointList;
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawIcon({ qrcode, icon, params }) {
|
||||||
|
const iconMode = getExactValue(icon.enabled, 0);
|
||||||
|
if (iconMode === 1) {
|
||||||
|
|
||||||
|
// Custom
|
||||||
|
// default
|
||||||
|
return defaultDrawIcon({ qrcode, icon, params });
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return builtinDrawIcon({ qrcode, icon, params });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function viewBox(qrcode) {
|
function viewBox(qrcode) {
|
||||||
if (!qrcode) return '0 0 0 0';
|
if (!qrcode) return '0 0 0 0';
|
||||||
|
|
||||||
|
@ -87,7 +231,8 @@ function viewBox(qrcode) {
|
||||||
const Renderer25D = createRenderer({
|
const Renderer25D = createRenderer({
|
||||||
listPoints: listPoints,
|
listPoints: listPoints,
|
||||||
getParamInfo: getParamInfo,
|
getParamInfo: getParamInfo,
|
||||||
getViewBox: viewBox
|
getViewBox: viewBox,
|
||||||
|
drawIcon: drawIcon
|
||||||
})
|
})
|
||||||
|
|
||||||
export default Renderer25D
|
export default Renderer25D
|
||||||
|
|
|
@ -1,14 +1,25 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
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 {createRenderer, defaultDrawIcon} from "../style/Renderer";
|
||||||
import {rand} from "../../utils/util";
|
import {getExactValue, rand} from "../../utils/util";
|
||||||
import LinkTrace from "../link/LinkTrace";
|
import LinkTrace from "../link/LinkTrace";
|
||||||
|
|
||||||
function listPoints(qrcode, params) {
|
function listPoints({ qrcode, params, icon }) {
|
||||||
if (!qrcode) return []
|
if (!qrcode) return []
|
||||||
|
|
||||||
const nCount = qrcode.getModuleCount();
|
const nCount = qrcode.getModuleCount();
|
||||||
|
|
||||||
|
const iconEnabled = getExactValue(icon.enabled, 0);
|
||||||
|
|
||||||
|
const {src, scale} = icon;
|
||||||
|
|
||||||
|
const iconSize = Number(nCount * (scale > .33 ? .33 : scale));
|
||||||
|
const iconXY = (nCount - iconSize) / 2;
|
||||||
|
|
||||||
|
function nearIcon(x, y) {
|
||||||
|
return Math.pow((nCount - 1) / 2 - x, 2) + Math.pow((nCount - 1) / 2 - y, 2) < Math.pow(iconSize / 2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
const typeTable = getTypeTable(qrcode);
|
const typeTable = getTypeTable(qrcode);
|
||||||
const pointList = new Array(nCount);
|
const pointList = new Array(nCount);
|
||||||
|
|
||||||
|
@ -65,15 +76,17 @@ function listPoints(qrcode, params) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (type === 0)
|
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}/>)
|
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)
|
} else if (type === 1) {
|
||||||
|
if (!(iconEnabled && nearIcon(x, y))) {}
|
||||||
pointList.push(<circle opacity={opacity} r={size / 2} key={id++} fill={otherColor} cx={x + 0.5} cy={y + 0.5}/>)
|
pointList.push(<circle opacity={opacity} r={size / 2} key={id++} fill={otherColor} cx={x + 0.5} cy={y + 0.5}/>)
|
||||||
else if (type === 2)
|
} 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)} />)
|
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;
|
return pointList;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
||||||
import {createRenderer} from "../style/Renderer";
|
import {createRenderer} from "../style/Renderer";
|
||||||
import {rand} from "../../utils/util";
|
import {rand} from "../../utils/util";
|
||||||
|
|
||||||
function listPoints(qrcode, params) {
|
function listPoints({ qrcode, params, icon }) {
|
||||||
if (!qrcode) return []
|
if (!qrcode) return []
|
||||||
|
|
||||||
const nCount = qrcode.getModuleCount();
|
const nCount = qrcode.getModuleCount();
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
||||||
import {createRenderer} from "../style/Renderer";
|
import {createRenderer} from "../style/Renderer";
|
||||||
import LinkTrace from "../link/LinkTrace";
|
import LinkTrace from "../link/LinkTrace";
|
||||||
|
|
||||||
function listPoints(qrcode, params) {
|
function listPoints({ qrcode, params, icon }) {
|
||||||
if (!qrcode) return []
|
if (!qrcode) return []
|
||||||
|
|
||||||
const nCount = qrcode.getModuleCount();
|
const nCount = qrcode.getModuleCount();
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {ParamTypes} from "../../constant/ParamTypes";
|
||||||
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
||||||
import {createRenderer} from "../style/Renderer";
|
import {createRenderer} from "../style/Renderer";
|
||||||
|
|
||||||
function listPoints(qrcode, params) {
|
function listPoints({ qrcode, params, icon }) {
|
||||||
if (!qrcode) return []
|
if (!qrcode) return []
|
||||||
|
|
||||||
const nCount = qrcode.getModuleCount();
|
const nCount = qrcode.getModuleCount();
|
||||||
|
@ -13,7 +13,6 @@ function listPoints(qrcode, params) {
|
||||||
let type = params[0];
|
let type = params[0];
|
||||||
let size = params[1] / 100;
|
let size = params[1] / 100;
|
||||||
let funcType = params[1];
|
let funcType = params[1];
|
||||||
let opacity = params[2] / 100;
|
|
||||||
let posType = params[3];
|
let posType = params[3];
|
||||||
let id = 0;
|
let id = 0;
|
||||||
let otherColor = params[4];
|
let otherColor = params[4];
|
||||||
|
|
|
@ -4,7 +4,7 @@ import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
||||||
import {createRenderer} from "../style/Renderer";
|
import {createRenderer} from "../style/Renderer";
|
||||||
import {defaultImage} from "../../constant/References";
|
import {defaultImage} from "../../constant/References";
|
||||||
|
|
||||||
function listPoints(qrcode, params) {
|
function listPoints({ qrcode, params, icon }) {
|
||||||
if (!qrcode) return []
|
if (!qrcode) return []
|
||||||
|
|
||||||
const nCount = qrcode.getModuleCount();
|
const nCount = qrcode.getModuleCount();
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import React from "react";
|
||||||
|
import {ParamTypes} from "../../constant/ParamTypes";
|
||||||
|
import {createRenderer} from "../style/Renderer";
|
||||||
|
import {defaultImage} from "../../constant/References";
|
||||||
|
|
||||||
|
function listPoints({ qrcode, params, icon }) {
|
||||||
|
if (!qrcode) return []
|
||||||
|
|
||||||
|
const nCount = qrcode.getModuleCount();
|
||||||
|
const pointList = new Array(nCount);
|
||||||
|
|
||||||
|
let color = params[1];
|
||||||
|
let opacity = params[2] / 100;
|
||||||
|
let id = 0;
|
||||||
|
|
||||||
|
pointList.push(<image key={id++} x="-0.01" y="-0.01" width={nCount + 0.02} height={nCount + 0.02} xlinkHref={params[0]}/>);
|
||||||
|
pointList.push(<rect key={id++} x="-0.01" y="-0.01" width={nCount + 0.02} height={nCount + 0.02} fill={color} opacity={opacity}/>);
|
||||||
|
|
||||||
|
for (let x = 0; x < nCount; x++) {
|
||||||
|
for (let y = 0; y < nCount; y++) {
|
||||||
|
if (!qrcode.isDark(x, y)) {
|
||||||
|
pointList.push(<rect width={1.02} height={1.02} key={id++} fill="#FFF" x={x - 0.01} y={y - 0.01}/>);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pointList;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getParamInfo() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: ParamTypes.UPLOAD_BUTTON,
|
||||||
|
key: '背景图片',
|
||||||
|
default: defaultImage,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: ParamTypes.COLOR_EDITOR,
|
||||||
|
key: '覆盖颜色',
|
||||||
|
default: '#000000'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: ParamTypes.TEXT_EDITOR,
|
||||||
|
key: '覆盖不透明度',
|
||||||
|
default: 10,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
const RendererImageFill = createRenderer({
|
||||||
|
listPoints: listPoints,
|
||||||
|
getParamInfo: getParamInfo,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
export default RendererImageFill
|
||||||
|
|
||||||
|
RendererImageFill.detail = (
|
||||||
|
<div>图像填充</div>
|
||||||
|
);
|
|
@ -4,7 +4,7 @@ import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
||||||
import {createRenderer} from "../style/Renderer";
|
import {createRenderer} from "../style/Renderer";
|
||||||
import {rand} from "../../utils/util";
|
import {rand} from "../../utils/util";
|
||||||
|
|
||||||
function listPoints(qrcode, params) {
|
function listPoints({ qrcode, params, icon }) {
|
||||||
if (!qrcode) return []
|
if (!qrcode) return []
|
||||||
|
|
||||||
const nCount = qrcode.getModuleCount();
|
const nCount = qrcode.getModuleCount();
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from "react";
|
||||||
import {rand} from "../../utils/util";
|
import {rand} from "../../utils/util";
|
||||||
import {createRenderer} from "../style/Renderer";
|
import {createRenderer} from "../style/Renderer";
|
||||||
|
|
||||||
function listPoints(qrcode, params) {
|
function listPoints({ qrcode, params, icon }) {
|
||||||
if (!qrcode) return []
|
if (!qrcode) return []
|
||||||
|
|
||||||
const nCount = qrcode.getModuleCount();
|
const nCount = qrcode.getModuleCount();
|
||||||
|
|
|
@ -3,10 +3,11 @@ import {gamma} from "../../utils/imageUtils";
|
||||||
import {ParamTypes} from "../../constant/ParamTypes";
|
import {ParamTypes} from "../../constant/ParamTypes";
|
||||||
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
import {getTypeTable, QRPointType} from "../../utils/qrcodeHandler";
|
||||||
import {defaultResImage} from "../../constant/References";
|
import {defaultResImage} from "../../constant/References";
|
||||||
|
import {getExactValue, getIdNum} from "../../utils/util";
|
||||||
|
|
||||||
function listPoints(qrcode, params) {
|
function listPoints({ qrcode, params, icon }) {
|
||||||
if (!qrcode) return []
|
if (!qrcode) return []
|
||||||
|
console.log(icon)
|
||||||
const nCount = qrcode.getModuleCount();
|
const nCount = qrcode.getModuleCount();
|
||||||
const typeTable = getTypeTable(qrcode);
|
const typeTable = getTypeTable(qrcode);
|
||||||
const pointList = new Array(nCount);
|
const pointList = new Array(nCount);
|
||||||
|
@ -155,7 +156,141 @@ function getGrayPointList(params, size, black, white) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const RendererResImage = ({qrcode, params, setParamInfo}) => {
|
let defaultDrawIcon = function ({ qrcode, params, title, icon }) {
|
||||||
|
if (!qrcode) return []
|
||||||
|
|
||||||
|
let id = 0;
|
||||||
|
const nCount = qrcode.getModuleCount();
|
||||||
|
const pointList = [];
|
||||||
|
const sq25 = "M32.048565,-1.29480038e-15 L67.951435,1.29480038e-15 C79.0954192,-7.52316311e-16 83.1364972,1.16032014 87.2105713,3.3391588 C91.2846454,5.51799746 94.4820025,8.71535463 96.6608412,12.7894287 C98.8396799,16.8635028 100,20.9045808 100,32.048565 L100,67.951435 C100,79.0954192 98.8396799,83.1364972 96.6608412,87.2105713 C94.4820025,91.2846454 91.2846454,94.4820025 87.2105713,96.6608412 C83.1364972,98.8396799 79.0954192,100 67.951435,100 L32.048565,100 C20.9045808,100 16.8635028,98.8396799 12.7894287,96.6608412 C8.71535463,94.4820025 5.51799746,91.2846454 3.3391588,87.2105713 C1.16032014,83.1364972 5.01544207e-16,79.0954192 -8.63200256e-16,67.951435 L8.63200256e-16,32.048565 C-5.01544207e-16,20.9045808 1.16032014,16.8635028 3.3391588,12.7894287 C5.51799746,8.71535463 8.71535463,5.51799746 12.7894287,3.3391588 C16.8635028,1.16032014 20.9045808,7.52316311e-16 32.048565,-1.29480038e-15 Z";
|
||||||
|
|
||||||
|
// draw icon
|
||||||
|
if (icon) {
|
||||||
|
const iconEnabled = getExactValue(icon.enabled, 0);
|
||||||
|
const {src, scale} = icon;
|
||||||
|
|
||||||
|
const iconSize = Number(nCount * (scale > 33 ? 33 : scale) / 100 * 3);
|
||||||
|
const iconXY = (nCount*3 - iconSize) / 2;
|
||||||
|
|
||||||
|
if (icon && iconEnabled) {
|
||||||
|
const randomIdDefs = getIdNum();
|
||||||
|
const randomIdClips = getIdNum();
|
||||||
|
pointList.push(<path d={sq25} stroke="#FFF" strokeWidth={100/iconSize * 3} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} />);
|
||||||
|
pointList.push(
|
||||||
|
<g key={id++}>
|
||||||
|
<defs>
|
||||||
|
<path id={"defs-path" + randomIdDefs} d={sq25} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} /> </defs>
|
||||||
|
<clipPath id={"clip-path" + randomIdClips}>
|
||||||
|
<use xlinkHref={"#defs-path" + randomIdDefs} overflow="visible"/>
|
||||||
|
</clipPath>
|
||||||
|
<g clipPath={"url(#clip-path" + randomIdClips + ")"}>
|
||||||
|
<image overflow="visible" key={id++} xlinkHref={src} width={iconSize} x={iconXY} y={iconXY} />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return pointList;
|
||||||
|
}
|
||||||
|
|
||||||
|
let builtinDrawIcon = function ({ qrcode, params, title, icon }) {
|
||||||
|
if (!qrcode) return []
|
||||||
|
|
||||||
|
let id = 0;
|
||||||
|
const nCount = qrcode.getModuleCount();
|
||||||
|
const pointList = [];
|
||||||
|
const sq25 = "M32.048565,-1.29480038e-15 L67.951435,1.29480038e-15 C79.0954192,-7.52316311e-16 83.1364972,1.16032014 87.2105713,3.3391588 C91.2846454,5.51799746 94.4820025,8.71535463 96.6608412,12.7894287 C98.8396799,16.8635028 100,20.9045808 100,32.048565 L100,67.951435 C100,79.0954192 98.8396799,83.1364972 96.6608412,87.2105713 C94.4820025,91.2846454 91.2846454,94.4820025 87.2105713,96.6608412 C83.1364972,98.8396799 79.0954192,100 67.951435,100 L32.048565,100 C20.9045808,100 16.8635028,98.8396799 12.7894287,96.6608412 C8.71535463,94.4820025 5.51799746,91.2846454 3.3391588,87.2105713 C1.16032014,83.1364972 5.01544207e-16,79.0954192 -8.63200256e-16,67.951435 L8.63200256e-16,32.048565 C-5.01544207e-16,20.9045808 1.16032014,16.8635028 3.3391588,12.7894287 C5.51799746,8.71535463 8.71535463,5.51799746 12.7894287,3.3391588 C16.8635028,1.16032014 20.9045808,7.52316311e-16 32.048565,-1.29480038e-15 Z";
|
||||||
|
|
||||||
|
// draw icon
|
||||||
|
if (icon) {
|
||||||
|
const iconMode = getExactValue(icon.enabled, 0);
|
||||||
|
const {src, scale} = icon;
|
||||||
|
|
||||||
|
const iconSize = Number(nCount * (scale > 33 ? 33 : scale) / 100 * 3);
|
||||||
|
const iconXY = (nCount*3 - iconSize) / 2;
|
||||||
|
|
||||||
|
const WeChatIconSmall = (
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#07c160"/>
|
||||||
|
<path d="M39.061,44.018a4.375,4.375,0,1,1,4.374-4.375,4.375,4.375,0,0,1-4.374,4.375m21.877,0a4.375,4.375,0,1,1,4.376-4.375,4.375,4.375,0,0,1-4.376,4.375M28.522,69.063a2.184,2.184,0,0,1,.92,1.782,2.581,2.581,0,0,1-.116.7c-.552,2.06-1.437,5.361-1.478,5.516a3.237,3.237,0,0,0-.177.8,1.093,1.093,0,0,0,1.094,1.093,1.243,1.243,0,0,0,.633-.2L36.581,74.6a3.427,3.427,0,0,1,1.742-.5,3.3,3.3,0,0,1,.965.144A38.825,38.825,0,0,0,50,75.739c18.123,0,32.816-12.242,32.816-27.346S68.122,21.049,50,21.049,17.185,33.29,17.185,48.393c0,8.239,4.42,15.656,11.337,20.67" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
const WeChatIcon = (
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#07c160"/>
|
||||||
|
<path d="M48.766,39.21a2.941,2.941,0,1,1,2.918-2.94,2.929,2.929,0,0,1-2.918,2.94m-16.455,0a2.941,2.941,0,1,1,2.918-2.941,2.93,2.93,0,0,1-2.918,2.941m8.227-17.039c-13.632,0-24.682,9.282-24.682,20.732,0,6.247,3.324,11.87,8.528,15.67a1.662,1.662,0,0,1,.691,1.352,1.984,1.984,0,0,1-.087.528c-.415,1.563-1.081,4.064-1.112,4.181a2.449,2.449,0,0,0-.132.607.825.825,0,0,0,.823.828.914.914,0,0,0,.474-.154l5.405-3.144a2.57,2.57,0,0,1,1.31-.382,2.442,2.442,0,0,1,.725.109,28.976,28.976,0,0,0,8.057,1.137c.455,0,.907-.012,1.356-.032a16.084,16.084,0,0,1-.829-5.082c0-10.442,10.078-18.908,22.511-18.908.45,0,.565.015,1.008.037-1.858-9.9-11.732-17.479-24.046-17.479" fill="#fff"/>
|
||||||
|
<path d="M70.432,55.582A2.589,2.589,0,1,1,73,52.994a2.578,2.578,0,0,1-2.568,2.588m-13.713,0a2.589,2.589,0,1,1,2.568-2.588,2.578,2.578,0,0,1-2.568,2.588m20.319,16a16.3,16.3,0,0,0,7.106-13.058c0-9.542-9.208-17.276-20.568-17.276s-20.57,7.734-20.57,17.276S52.216,75.8,63.576,75.8a24.161,24.161,0,0,0,6.714-.947,2.079,2.079,0,0,1,.6-.091,2.138,2.138,0,0,1,1.092.319l4.5,2.62a.78.78,0,0,0,.4.129.688.688,0,0,0,.685-.691,2.081,2.081,0,0,0-.11-.5l-.927-3.486a1.641,1.641,0,0,1-.073-.44,1.385,1.385,0,0,1,.577-1.126" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
const WeChatPayIcon = (
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#07c160"/>
|
||||||
|
<path d="M41.055,57.675a2.183,2.183,0,0,1-2.893-.883l-.143-.314L32.046,43.37a1.133,1.133,0,0,1-.105-.461,1.094,1.094,0,0,1,1.748-.877l7.049,5.019a3.249,3.249,0,0,0,2.914.333L76.8,32.63c-5.942-7-15.728-11.581-26.8-11.581-18.122,0-32.813,12.243-32.813,27.345,0,8.24,4.42,15.656,11.338,20.669a2.185,2.185,0,0,1,.919,1.781,2.569,2.569,0,0,1-.116.7c-.552,2.062-1.437,5.362-1.478,5.516a3.212,3.212,0,0,0-.177.8,1.094,1.094,0,0,0,1.1,1.094,1.236,1.236,0,0,0,.631-.2L36.583,74.6a3.438,3.438,0,0,1,1.742-.5,3.281,3.281,0,0,1,.965.145A38.844,38.844,0,0,0,50,75.739c18.122,0,32.813-12.243,32.813-27.345a23.668,23.668,0,0,0-3.738-12.671L41.3,57.537Z" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
const AlipayIcon = (
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#009ce1"/>
|
||||||
|
<path d="M100,67.856c-.761-.1-4.8-.8-17.574-5.066-4.012-1.339-9.4-3.389-15.395-5.552A80.552,80.552,0,0,0,75.4,36.156H55.633v-7.1H79.848V25.094H55.633V13.258H45.749a1.68,1.68,0,0,0-1.733,1.707V25.094H19.524v3.963H44.016v7.1H23.8V40.12H63.013a69.579,69.579,0,0,1-5.65,13.763c-12.724-4.187-26.3-7.58-34.834-5.491C17.074,49.733,13.56,52.125,11.5,54.63,2.02,66.125,8.815,83.585,28.824,83.585c11.831,0,23.228-6.579,32.061-17.417C73.49,72.211,97.914,82.4,100,83.267ZM26.956,76.9c-15.6,0-20.215-12.255-12.5-18.958,2.573-2.266,7.276-3.372,9.782-3.621,9.268-.913,17.846,2.613,27.972,7.541C45.087,71.118,36.023,76.9,26.956,76.9Z" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
function builtinIcon() {
|
||||||
|
if (iconMode === 2) {
|
||||||
|
return WeChatIconSmall
|
||||||
|
} else if (iconMode === 3) {
|
||||||
|
return WeChatIcon
|
||||||
|
} else if (iconMode === 4) {
|
||||||
|
return WeChatPayIcon
|
||||||
|
} else if (iconMode === 5) {
|
||||||
|
return AlipayIcon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icon && iconMode) {
|
||||||
|
const randomIdDefs = getIdNum();
|
||||||
|
const randomIdClips = getIdNum();
|
||||||
|
pointList.push(<path d={sq25} stroke="#FFF" strokeWidth={100/iconSize * 3} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} />);
|
||||||
|
pointList.push(
|
||||||
|
<g key={id++}>
|
||||||
|
<defs>
|
||||||
|
<path id={"defs-path" + randomIdDefs} d={sq25} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} /> </defs>
|
||||||
|
<clipPath id={"clip-path" + randomIdClips}>
|
||||||
|
<use xlinkHref={"#defs-path" + randomIdDefs} overflow="visible"/>
|
||||||
|
</clipPath>
|
||||||
|
<g clipPath={"url(#clip-path" + randomIdClips + ")"}>
|
||||||
|
<g transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} >
|
||||||
|
{builtinIcon()}
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pointList;
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawIcon({ qrcode, icon, params }) {
|
||||||
|
const iconMode = getExactValue(icon.enabled, 0);
|
||||||
|
if (iconMode === 1) {
|
||||||
|
|
||||||
|
// Custom
|
||||||
|
// default
|
||||||
|
return defaultDrawIcon({ qrcode, icon, params });
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return builtinDrawIcon({ qrcode, icon, params });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const RendererResImage = ({qrcode, params, setParamInfo, icon}) => {
|
||||||
let otherColor = params[5];
|
let otherColor = params[5];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -178,7 +313,8 @@ const RendererResImage = ({qrcode, params, setParamInfo}) => {
|
||||||
<rect id="B" width={3.08} height={3.08}/>
|
<rect id="B" width={3.08} height={3.08}/>
|
||||||
<rect id="S" width={1.02} height={1.02}/>
|
<rect id="S" width={1.02} height={1.02}/>
|
||||||
</defs>
|
</defs>
|
||||||
{gpl.concat(listPoints(qrcode, params))}
|
{gpl.concat(listPoints({ qrcode, params, icon }))}
|
||||||
|
{drawIcon({ qrcode, params, icon })}
|
||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import React, {useEffect} from "react";
|
import React, {useEffect} from "react";
|
||||||
import {extend} from "../../utils/util";
|
import {extend, getExactValue, getIdNum} from "../../utils/util";
|
||||||
|
|
||||||
const Renderer = ({ rendererType, ...other }) => (
|
const Renderer = ({ rendererType, ...other }) => (
|
||||||
React.createElement(rendererType, other)
|
React.createElement(rendererType, other)
|
||||||
|
@ -9,24 +9,158 @@ 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) {
|
||||||
let defaultViewBox = function (qrcode) {
|
|
||||||
if (!qrcode) return '0 0 0 0';
|
if (!qrcode) return '0 0 0 0';
|
||||||
|
|
||||||
const nCount = qrcode.getModuleCount();
|
const nCount = qrcode.getModuleCount();
|
||||||
return String(-nCount / 5) + ' ' + String(-nCount / 5) + ' ' + String(nCount + nCount / 5 * 2) + ' ' + String(nCount + nCount / 5 * 2);
|
return String(-nCount / 5) + ' ' + String(-nCount / 5) + ' ' + String(nCount + nCount / 5 * 2) + ' ' + String(nCount + nCount / 5 * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
let defaultDrawIcon = function ({ qrcode, params, title, icon }) {
|
||||||
|
if (!qrcode) return []
|
||||||
|
|
||||||
|
let id = 0;
|
||||||
|
const nCount = qrcode.getModuleCount();
|
||||||
|
const pointList = [];
|
||||||
|
const sq25 = "M32.048565,-1.29480038e-15 L67.951435,1.29480038e-15 C79.0954192,-7.52316311e-16 83.1364972,1.16032014 87.2105713,3.3391588 C91.2846454,5.51799746 94.4820025,8.71535463 96.6608412,12.7894287 C98.8396799,16.8635028 100,20.9045808 100,32.048565 L100,67.951435 C100,79.0954192 98.8396799,83.1364972 96.6608412,87.2105713 C94.4820025,91.2846454 91.2846454,94.4820025 87.2105713,96.6608412 C83.1364972,98.8396799 79.0954192,100 67.951435,100 L32.048565,100 C20.9045808,100 16.8635028,98.8396799 12.7894287,96.6608412 C8.71535463,94.4820025 5.51799746,91.2846454 3.3391588,87.2105713 C1.16032014,83.1364972 5.01544207e-16,79.0954192 -8.63200256e-16,67.951435 L8.63200256e-16,32.048565 C-5.01544207e-16,20.9045808 1.16032014,16.8635028 3.3391588,12.7894287 C5.51799746,8.71535463 8.71535463,5.51799746 12.7894287,3.3391588 C16.8635028,1.16032014 20.9045808,7.52316311e-16 32.048565,-1.29480038e-15 Z";
|
||||||
|
|
||||||
|
// draw icon
|
||||||
|
if (icon) {
|
||||||
|
const iconEnabled = getExactValue(icon.enabled, 0);
|
||||||
|
const {src, scale} = icon;
|
||||||
|
|
||||||
|
const iconSize = Number(nCount * (scale > 33 ? 33 : scale) / 100);
|
||||||
|
const iconXY = (nCount - iconSize) / 2;
|
||||||
|
|
||||||
|
if (icon && iconEnabled) {
|
||||||
|
const randomIdDefs = getIdNum();
|
||||||
|
const randomIdClips = getIdNum();
|
||||||
|
pointList.push(<path d={sq25} stroke="#FFF" strokeWidth={100/iconSize * 1} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} />);
|
||||||
|
pointList.push(
|
||||||
|
<g key={id++}>
|
||||||
|
<defs>
|
||||||
|
<path id={"defs-path" + randomIdDefs} d={sq25} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} /> </defs>
|
||||||
|
<clipPath id={"clip-path" + randomIdClips}>
|
||||||
|
<use xlinkHref={"#defs-path" + randomIdDefs} overflow="visible"/>
|
||||||
|
</clipPath>
|
||||||
|
<g clipPath={"url(#clip-path" + randomIdClips + ")"}>
|
||||||
|
<image overflow="visible" key={id++} xlinkHref={src} width={iconSize} x={iconXY} y={iconXY} />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return pointList;
|
||||||
|
}
|
||||||
|
|
||||||
|
let builtinDrawIcon = function ({ qrcode, params, title, icon }) {
|
||||||
|
if (!qrcode) return []
|
||||||
|
|
||||||
|
let id = 0;
|
||||||
|
const nCount = qrcode.getModuleCount();
|
||||||
|
const pointList = [];
|
||||||
|
const sq25 = "M32.048565,-1.29480038e-15 L67.951435,1.29480038e-15 C79.0954192,-7.52316311e-16 83.1364972,1.16032014 87.2105713,3.3391588 C91.2846454,5.51799746 94.4820025,8.71535463 96.6608412,12.7894287 C98.8396799,16.8635028 100,20.9045808 100,32.048565 L100,67.951435 C100,79.0954192 98.8396799,83.1364972 96.6608412,87.2105713 C94.4820025,91.2846454 91.2846454,94.4820025 87.2105713,96.6608412 C83.1364972,98.8396799 79.0954192,100 67.951435,100 L32.048565,100 C20.9045808,100 16.8635028,98.8396799 12.7894287,96.6608412 C8.71535463,94.4820025 5.51799746,91.2846454 3.3391588,87.2105713 C1.16032014,83.1364972 5.01544207e-16,79.0954192 -8.63200256e-16,67.951435 L8.63200256e-16,32.048565 C-5.01544207e-16,20.9045808 1.16032014,16.8635028 3.3391588,12.7894287 C5.51799746,8.71535463 8.71535463,5.51799746 12.7894287,3.3391588 C16.8635028,1.16032014 20.9045808,7.52316311e-16 32.048565,-1.29480038e-15 Z";
|
||||||
|
|
||||||
|
// draw icon
|
||||||
|
if (icon) {
|
||||||
|
const iconMode = getExactValue(icon.enabled, 0);
|
||||||
|
const {src, scale} = icon;
|
||||||
|
|
||||||
|
const iconSize = Number(nCount * (scale > 33 ? 33 : scale) / 100);
|
||||||
|
const iconXY = (nCount - iconSize) / 2;
|
||||||
|
|
||||||
|
const WeChatIconSmall = (
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#07c160"/>
|
||||||
|
<path d="M39.061,44.018a4.375,4.375,0,1,1,4.374-4.375,4.375,4.375,0,0,1-4.374,4.375m21.877,0a4.375,4.375,0,1,1,4.376-4.375,4.375,4.375,0,0,1-4.376,4.375M28.522,69.063a2.184,2.184,0,0,1,.92,1.782,2.581,2.581,0,0,1-.116.7c-.552,2.06-1.437,5.361-1.478,5.516a3.237,3.237,0,0,0-.177.8,1.093,1.093,0,0,0,1.094,1.093,1.243,1.243,0,0,0,.633-.2L36.581,74.6a3.427,3.427,0,0,1,1.742-.5,3.3,3.3,0,0,1,.965.144A38.825,38.825,0,0,0,50,75.739c18.123,0,32.816-12.242,32.816-27.346S68.122,21.049,50,21.049,17.185,33.29,17.185,48.393c0,8.239,4.42,15.656,11.337,20.67" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
const WeChatIcon = (
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#07c160"/>
|
||||||
|
<path d="M48.766,39.21a2.941,2.941,0,1,1,2.918-2.94,2.929,2.929,0,0,1-2.918,2.94m-16.455,0a2.941,2.941,0,1,1,2.918-2.941,2.93,2.93,0,0,1-2.918,2.941m8.227-17.039c-13.632,0-24.682,9.282-24.682,20.732,0,6.247,3.324,11.87,8.528,15.67a1.662,1.662,0,0,1,.691,1.352,1.984,1.984,0,0,1-.087.528c-.415,1.563-1.081,4.064-1.112,4.181a2.449,2.449,0,0,0-.132.607.825.825,0,0,0,.823.828.914.914,0,0,0,.474-.154l5.405-3.144a2.57,2.57,0,0,1,1.31-.382,2.442,2.442,0,0,1,.725.109,28.976,28.976,0,0,0,8.057,1.137c.455,0,.907-.012,1.356-.032a16.084,16.084,0,0,1-.829-5.082c0-10.442,10.078-18.908,22.511-18.908.45,0,.565.015,1.008.037-1.858-9.9-11.732-17.479-24.046-17.479" fill="#fff"/>
|
||||||
|
<path d="M70.432,55.582A2.589,2.589,0,1,1,73,52.994a2.578,2.578,0,0,1-2.568,2.588m-13.713,0a2.589,2.589,0,1,1,2.568-2.588,2.578,2.578,0,0,1-2.568,2.588m20.319,16a16.3,16.3,0,0,0,7.106-13.058c0-9.542-9.208-17.276-20.568-17.276s-20.57,7.734-20.57,17.276S52.216,75.8,63.576,75.8a24.161,24.161,0,0,0,6.714-.947,2.079,2.079,0,0,1,.6-.091,2.138,2.138,0,0,1,1.092.319l4.5,2.62a.78.78,0,0,0,.4.129.688.688,0,0,0,.685-.691,2.081,2.081,0,0,0-.11-.5l-.927-3.486a1.641,1.641,0,0,1-.073-.44,1.385,1.385,0,0,1,.577-1.126" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
const WeChatPayIcon = (
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#07c160"/>
|
||||||
|
<path d="M41.055,57.675a2.183,2.183,0,0,1-2.893-.883l-.143-.314L32.046,43.37a1.133,1.133,0,0,1-.105-.461,1.094,1.094,0,0,1,1.748-.877l7.049,5.019a3.249,3.249,0,0,0,2.914.333L76.8,32.63c-5.942-7-15.728-11.581-26.8-11.581-18.122,0-32.813,12.243-32.813,27.345,0,8.24,4.42,15.656,11.338,20.669a2.185,2.185,0,0,1,.919,1.781,2.569,2.569,0,0,1-.116.7c-.552,2.062-1.437,5.362-1.478,5.516a3.212,3.212,0,0,0-.177.8,1.094,1.094,0,0,0,1.1,1.094,1.236,1.236,0,0,0,.631-.2L36.583,74.6a3.438,3.438,0,0,1,1.742-.5,3.281,3.281,0,0,1,.965.145A38.844,38.844,0,0,0,50,75.739c18.122,0,32.813-12.243,32.813-27.345a23.668,23.668,0,0,0-3.738-12.671L41.3,57.537Z" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
const AlipayIcon = (
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#009ce1"/>
|
||||||
|
<path d="M100,67.856c-.761-.1-4.8-.8-17.574-5.066-4.012-1.339-9.4-3.389-15.395-5.552A80.552,80.552,0,0,0,75.4,36.156H55.633v-7.1H79.848V25.094H55.633V13.258H45.749a1.68,1.68,0,0,0-1.733,1.707V25.094H19.524v3.963H44.016v7.1H23.8V40.12H63.013a69.579,69.579,0,0,1-5.65,13.763c-12.724-4.187-26.3-7.58-34.834-5.491C17.074,49.733,13.56,52.125,11.5,54.63,2.02,66.125,8.815,83.585,28.824,83.585c11.831,0,23.228-6.579,32.061-17.417C73.49,72.211,97.914,82.4,100,83.267ZM26.956,76.9c-15.6,0-20.215-12.255-12.5-18.958,2.573-2.266,7.276-3.372,9.782-3.621,9.268-.913,17.846,2.613,27.972,7.541C45.087,71.118,36.023,76.9,26.956,76.9Z" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
)
|
||||||
|
|
||||||
|
function builtinIcon() {
|
||||||
|
if (iconMode === 2) {
|
||||||
|
return WeChatIconSmall
|
||||||
|
} else if (iconMode === 3) {
|
||||||
|
return WeChatIcon
|
||||||
|
} else if (iconMode === 4) {
|
||||||
|
return WeChatPayIcon
|
||||||
|
} else if (iconMode === 5) {
|
||||||
|
return AlipayIcon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icon && iconMode) {
|
||||||
|
const randomIdDefs = getIdNum();
|
||||||
|
const randomIdClips = getIdNum();
|
||||||
|
pointList.push(<path d={sq25} stroke="#FFF" strokeWidth={100/iconSize * 1} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} />);
|
||||||
|
pointList.push(
|
||||||
|
<g key={id++}>
|
||||||
|
<defs>
|
||||||
|
<path id={"defs-path" + randomIdDefs} d={sq25} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} /> </defs>
|
||||||
|
<clipPath id={"clip-path" + randomIdClips}>
|
||||||
|
<use xlinkHref={"#defs-path" + randomIdDefs} overflow="visible"/>
|
||||||
|
</clipPath>
|
||||||
|
<g clipPath={"url(#clip-path" + randomIdClips + ")"}>
|
||||||
|
<g transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} >
|
||||||
|
{builtinIcon()}
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pointList;
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawIcon({ qrcode, icon, params }) {
|
||||||
|
const iconMode = getExactValue(icon.enabled, 0);
|
||||||
|
if (iconMode === 1) {
|
||||||
|
|
||||||
|
// Custom
|
||||||
|
// default
|
||||||
|
return defaultDrawIcon({ qrcode, icon, params });
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return builtinDrawIcon({ qrcode, icon, params });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createRenderer(renderer) {
|
||||||
renderer = extend({
|
renderer = extend({
|
||||||
getViewBox: defaultViewBox,
|
getViewBox: defaultViewBox,
|
||||||
listPoints: (qrcode, params) => { return []; },
|
listPoints: ({ qrcode, params, icon }) => { return []; },
|
||||||
getParamInfo: () => {return []; },
|
getParamInfo: () => {return []; },
|
||||||
beginRendering: ({ qrcode, params, setParamInfo }) => {},
|
beginRendering: ({ qrcode, params, setParamInfo }) => {},
|
||||||
beforeListing: ({ qrcode, params, setParamInfo }) => {},
|
beforeListing: ({ qrcode, params, setParamInfo }) => {},
|
||||||
afterListing: ({ qrcode, params, setParamInfo }) => {},
|
drawIcon: drawIcon
|
||||||
}, renderer);
|
}, renderer);
|
||||||
|
|
||||||
return ({ qrcode, params, setParamInfo}) => {
|
return ({ qrcode, params, title, icon, setParamInfo}) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setParamInfo(renderer.getParamInfo());
|
setParamInfo(renderer.getParamInfo());
|
||||||
}, [setParamInfo]);
|
}, [setParamInfo]);
|
||||||
|
@ -36,11 +170,12 @@ export function createRenderer(renderer) {
|
||||||
<svg className="Qr-item-svg" width="100%" height="100%" viewBox={renderer.getViewBox(qrcode)} fill="white"
|
<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">
|
xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink">
|
||||||
{renderer.beforeListing({ qrcode, params, setParamInfo })}
|
{renderer.beforeListing({ qrcode, params, setParamInfo })}
|
||||||
{renderer.listPoints(qrcode, params)}
|
{renderer.listPoints({ qrcode, params, icon })}
|
||||||
{renderer.afterListing({ qrcode, params, setParamInfo })}
|
{renderer.drawIcon({ qrcode, params, title, icon })}
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default React.memo(Renderer, areEqual)
|
export default React.memo(Renderer, areEqual)
|
||||||
|
export { defaultDrawIcon, defaultViewBox }
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
|
||||||
|
<title>资源 1</title>
|
||||||
|
<g>
|
||||||
|
<rect width="100" height="100" fill="#07c160"/>
|
||||||
|
<path d="M39.061,44.018a4.375,4.375,0,1,1,4.374-4.375,4.375,4.375,0,0,1-4.374,4.375m21.877,0a4.375,4.375,0,1,1,4.376-4.375,4.375,4.375,0,0,1-4.376,4.375M28.522,69.063a2.184,2.184,0,0,1,.92,1.782,2.581,2.581,0,0,1-.116.7c-.552,2.06-1.437,5.361-1.478,5.516a3.237,3.237,0,0,0-.177.8,1.093,1.093,0,0,0,1.094,1.093,1.243,1.243,0,0,0,.633-.2L36.581,74.6a3.427,3.427,0,0,1,1.742-.5,3.3,3.3,0,0,1,.965.144A38.825,38.825,0,0,0,50,75.739c18.123,0,32.816-12.242,32.816-27.346S68.122,21.049,50,21.049,17.185,33.29,17.185,48.393c0,8.239,4.42,15.656,11.337,20.67" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 767 B |
|
@ -0,0 +1,10 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
|
||||||
|
<title>资源 2</title>
|
||||||
|
<g id="图层_2" data-name="图层 2">
|
||||||
|
<g id="图层_1-2" data-name="图层 1">
|
||||||
|
<rect width="100" height="100" fill="#07c160"/>
|
||||||
|
<path d="M48.766,39.21a2.941,2.941,0,1,1,2.918-2.94,2.929,2.929,0,0,1-2.918,2.94m-16.455,0a2.941,2.941,0,1,1,2.918-2.941,2.93,2.93,0,0,1-2.918,2.941m8.227-17.039c-13.632,0-24.682,9.282-24.682,20.732,0,6.247,3.324,11.87,8.528,15.67a1.662,1.662,0,0,1,.691,1.352,1.984,1.984,0,0,1-.087.528c-.415,1.563-1.081,4.064-1.112,4.181a2.449,2.449,0,0,0-.132.607.825.825,0,0,0,.823.828.914.914,0,0,0,.474-.154l5.405-3.144a2.57,2.57,0,0,1,1.31-.382,2.442,2.442,0,0,1,.725.109,28.976,28.976,0,0,0,8.057,1.137c.455,0,.907-.012,1.356-.032a16.084,16.084,0,0,1-.829-5.082c0-10.442,10.078-18.908,22.511-18.908.45,0,.565.015,1.008.037-1.858-9.9-11.732-17.479-24.046-17.479" fill="#fff"/>
|
||||||
|
<path d="M70.432,55.582A2.589,2.589,0,1,1,73,52.994a2.578,2.578,0,0,1-2.568,2.588m-13.713,0a2.589,2.589,0,1,1,2.568-2.588,2.578,2.578,0,0,1-2.568,2.588m20.319,16a16.3,16.3,0,0,0,7.106-13.058c0-9.542-9.208-17.276-20.568-17.276s-20.57,7.734-20.57,17.276S52.216,75.8,63.576,75.8a24.161,24.161,0,0,0,6.714-.947,2.079,2.079,0,0,1,.6-.091,2.138,2.138,0,0,1,1.092.319l4.5,2.62a.78.78,0,0,0,.4.129.688.688,0,0,0,.685-.691,2.081,2.081,0,0,0-.11-.5l-.927-3.486a1.641,1.641,0,0,1-.073-.44,1.385,1.385,0,0,1,.577-1.126" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,8 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
|
||||||
|
<title>资源 3</title>
|
||||||
|
<g id="图层_2" data-name="图层 2"><g id="图层_1-2" data-name="图层 1">
|
||||||
|
<rect width="100" height="100" fill="#07c160"/>
|
||||||
|
<path d="M41.055,57.675a2.183,2.183,0,0,1-2.893-.883l-.143-.314L32.046,43.37a1.133,1.133,0,0,1-.105-.461,1.094,1.094,0,0,1,1.748-.877l7.049,5.019a3.249,3.249,0,0,0,2.914.333L76.8,32.63c-5.942-7-15.728-11.581-26.8-11.581-18.122,0-32.813,12.243-32.813,27.345,0,8.24,4.42,15.656,11.338,20.669a2.185,2.185,0,0,1,.919,1.781,2.569,2.569,0,0,1-.116.7c-.552,2.062-1.437,5.362-1.478,5.516a3.212,3.212,0,0,0-.177.8,1.094,1.094,0,0,0,1.1,1.094,1.236,1.236,0,0,0,.631-.2L36.583,74.6a3.438,3.438,0,0,1,1.742-.5,3.281,3.281,0,0,1,.965.145A38.844,38.844,0,0,0,50,75.739c18.122,0,32.813-12.243,32.813-27.345a23.668,23.668,0,0,0-3.738-12.671L41.3,57.537Z" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 940 B |
|
@ -0,0 +1,7 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100">
|
||||||
|
<title>资源 4</title>
|
||||||
|
<g id="图层_2" data-name="图层 2">
|
||||||
|
<rect width="100" height="100" fill="#009ce1"/>
|
||||||
|
<path d="M100,67.856c-.761-.1-4.8-.8-17.574-5.066-4.012-1.339-9.4-3.389-15.395-5.552A80.552,80.552,0,0,0,75.4,36.156H55.633v-7.1H79.848V25.094H55.633V13.258H45.749a1.68,1.68,0,0,0-1.733,1.707V25.094H19.524v3.963H44.016v7.1H23.8V40.12H63.013a69.579,69.579,0,0,1-5.65,13.763c-12.724-4.187-26.3-7.58-34.834-5.491C17.074,49.733,13.56,52.125,11.5,54.63,2.02,66.125,8.815,83.585,28.824,83.585c11.831,0,23.228-6.579,32.061-17.417C73.49,72.211,97.914,82.4,100,83.267ZM26.956,76.9c-15.6,0-20.215-12.255-12.5-18.958,2.573-2.266,7.276-3.372,9.782-3.621,9.268-.913,17.846,2.613,27.972,7.541C45.087,71.118,36.023,76.9,26.956,76.9Z" fill="#fff"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 871 B |
|
@ -5,4 +5,6 @@ export const actionTypes = {
|
||||||
CREATE_PARAM: 'CREATE_PARAM',
|
CREATE_PARAM: 'CREATE_PARAM',
|
||||||
CHANGE_PARAM: 'CHANGE_PARAM',
|
CHANGE_PARAM: 'CHANGE_PARAM',
|
||||||
LOAD_DOWNLOAD_DATA: 'LOAD_DOWNLOAD_DATA',
|
LOAD_DOWNLOAD_DATA: 'LOAD_DOWNLOAD_DATA',
|
||||||
|
CHANGE_TITLE: 'CHANGE_TITLE',
|
||||||
|
CHANGE_ICON: 'CHANGE_ICON'
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -3,7 +3,7 @@ import PartDownload from "../../components/app/PartDownload";
|
||||||
import {saveImg, saveSvg} from "../../utils/downloader";
|
import {saveImg, saveSvg} from "../../utils/downloader";
|
||||||
import {getDownloadCount, increaseDownloadData, recordDownloadDetail} from "../../api/TcbHandler";
|
import {getDownloadCount, increaseDownloadData, recordDownloadDetail} from "../../api/TcbHandler";
|
||||||
import {getParamDetailedValue, outerHtml} from "../../utils/util";
|
import {getParamDetailedValue, outerHtml} from "../../utils/util";
|
||||||
import {handleDownloadJpg, handleDownloadSvg} from "../../utils/gaHelper";
|
import {handleDownloadImg, handleDownloadSvg} from "../../utils/gaHelper";
|
||||||
|
|
||||||
function saveDB(state, type, updateDownloadData) {
|
function saveDB(state, type, updateDownloadData) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
|
@ -45,11 +45,11 @@ const mapStateToProps = (state, ownProps) => ({
|
||||||
saveDB(state, 'svg', ownProps.updateDownloadData);
|
saveDB(state, 'svg', ownProps.updateDownloadData);
|
||||||
handleDownloadSvg(state.value);
|
handleDownloadSvg(state.value);
|
||||||
},
|
},
|
||||||
onJpgDownload: () => {
|
onImgDownload: (type) => {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
saveImg(state.value, outerHtml(state.selectedIndex), 1500, 1500).then((res) => {
|
saveImg(state.value, outerHtml(state.selectedIndex), 1500, 1500, type).then((res) => {
|
||||||
saveDB(state, 'jpg', ownProps.updateDownloadData).then(() => {
|
saveDB(state, type, ownProps.updateDownloadData).then(() => {
|
||||||
handleDownloadJpg(state.value);
|
handleDownloadImg(state.value, type);
|
||||||
resolve(res)
|
resolve(res)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import {changeCorrectLevel} from "../../actions";
|
import {changeCorrectLevel} from "../../actions";
|
||||||
import ParamCorrectLevel from "../../components/param/ParamCorrectLevel";
|
import ParamCorrectLevel from "../../components/param/disposable/ParamCorrectLevel";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import {isPicture, toBase64} from "../../../utils/imageUtils";
|
||||||
|
import ParamUpload from "../../../components/param/ParamUpload";
|
||||||
|
|
||||||
|
const mapStateToProps = (state, ownProps) => ({
|
||||||
|
rendererIndex: -1,
|
||||||
|
paramIndex: -1,
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch, ownProps) => ({
|
||||||
|
onChange: (e) => {
|
||||||
|
if (e.target.files.length > 0) {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
if (isPicture(file)) {
|
||||||
|
toBase64(file, 1.0).then(res => {
|
||||||
|
ownProps.onChange({ ...ownProps.icon, src: res})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ParamUpload);
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import ParamIcon from "../../../components/param/disposable/ParamIcon";
|
||||||
|
import {changeIcon} from "../../../actions";
|
||||||
|
|
||||||
|
const mapStateToProps = (state, ownProps) => ({
|
||||||
|
icon: state.icon
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch, ownProps) => ({
|
||||||
|
onBlur: (icon) => {
|
||||||
|
dispatch(changeIcon(icon))
|
||||||
|
},
|
||||||
|
onKeyPress: (e, icon) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
dispatch(changeIcon(icon))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ParamIcon);
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import ParamColor from "../../../components/param/ParamColor";
|
||||||
|
|
||||||
|
const mapStateToProps = (state, ownProps) => ({
|
||||||
|
rendererIndex: -1,
|
||||||
|
paramIndex: -1,
|
||||||
|
value: state.title.color
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch, ownProps) => ({
|
||||||
|
onChange: (color) => {
|
||||||
|
ownProps.onChange({ ...ownProps.title, color: color.hex })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ParamColor);
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import ParamTitle from "../../../components/param/disposable/ParamTitle";
|
||||||
|
import {changeTitle} from "../../../actions";
|
||||||
|
|
||||||
|
const mapStateToProps = (state, ownProps) => ({
|
||||||
|
title: state.title
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch, ownProps) => ({
|
||||||
|
onChange: (title) => {
|
||||||
|
dispatch(changeTitle(title))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ParamTitle);
|
|
@ -7,6 +7,8 @@ const mapStateToProps = (state, ownProps) => ({
|
||||||
rendererIndex: ownProps.index,
|
rendererIndex: ownProps.index,
|
||||||
qrcode: state.qrcode,
|
qrcode: state.qrcode,
|
||||||
params: fillEmptyWith(state.paramValue[ownProps.index].slice(), 0),
|
params: fillEmptyWith(state.paramValue[ownProps.index].slice(), 0),
|
||||||
|
title: state.title,
|
||||||
|
icon: state.icon,
|
||||||
selected: state.selectedIndex === ownProps.index,
|
selected: state.selectedIndex === ownProps.index,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -12,17 +12,19 @@ import { RendererRandRound, RendererRect, RendererRound } from "../../components
|
||||||
import { RendererLine, RendererLine2 } from "../../components/renderer/RendererLine";
|
import { RendererLine, RendererLine2 } from "../../components/renderer/RendererLine";
|
||||||
import { RendererFuncA, RendererFuncB } from "../../components/renderer/RendererFunc";
|
import { RendererFuncA, RendererFuncB } from "../../components/renderer/RendererFunc";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import RendererImageFill from "../../components/renderer/RendererImageFill";
|
||||||
|
|
||||||
const styles = [
|
const styles = [
|
||||||
{value: "A1", renderer: RendererRect},
|
{value: "A1", renderer: RendererRect},
|
||||||
{value: "C2", renderer: RendererResImage},
|
{value: "C2", renderer: RendererResImage},
|
||||||
{value: "SP — 1", renderer: RendererDSJ},
|
{value: "SP — 1", renderer: RendererDSJ},
|
||||||
|
{value: "A — a1", renderer: RendererLine},
|
||||||
|
{value: "SP — 3", renderer: RendererCircle},
|
||||||
{value: "A2", renderer: RendererRound},
|
{value: "A2", renderer: RendererRound},
|
||||||
{value: "A3", renderer: RendererRandRound},
|
{value: "A3", renderer: RendererRandRound},
|
||||||
{value: "A — a1", renderer: RendererLine},
|
|
||||||
{value: "A — b2", renderer: RendererFuncB},
|
{value: "A — b2", renderer: RendererFuncB},
|
||||||
{value: "SP — 3", renderer: RendererCircle},
|
|
||||||
{value: "C1", renderer: RendererImage},
|
{value: "C1", renderer: RendererImage},
|
||||||
|
{value: "C3", renderer: RendererImageFill},
|
||||||
{value: "B1", renderer: Renderer25D},
|
{value: "B1", renderer: Renderer25D},
|
||||||
{value: "A — a2", renderer: RendererLine2},
|
{value: "A — a2", renderer: RendererLine2},
|
||||||
{value: "A — b1", renderer: RendererFuncA},
|
{value: "A — b1", renderer: RendererFuncA},
|
||||||
|
|
|
@ -13,6 +13,8 @@ const initialState = {
|
||||||
history: [],
|
history: [],
|
||||||
downloadData: [],
|
downloadData: [],
|
||||||
qrcode: encodeData({text: QRBTF_URL, correctLevel: 0}),
|
qrcode: encodeData({text: QRBTF_URL, correctLevel: 0}),
|
||||||
|
icon: { enabled: 0, src: '', scale: 22 },
|
||||||
|
title: { enabled: 0, text: '', color: 'black', size: 20, align: 'middle'},
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
@ -65,6 +67,16 @@ export default function appReducer(state = initialState, action) {
|
||||||
downloadData: action.data
|
downloadData: action.data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
case actionTypes.CHANGE_TITLE: {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
title: Object.assign({}, state.title, action.title)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
case actionTypes.CHANGE_ICON: {
|
||||||
|
return Object.assign({}, state, {
|
||||||
|
icon: Object.assign({}, state.icon, action.icon)
|
||||||
|
});
|
||||||
|
}
|
||||||
default: return state
|
default: return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
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"
|
||||||
|
|
||||||
|
const MIME = { "jpg": "image/jpeg", "png": "image/png" };
|
||||||
|
|
||||||
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"})
|
||||||
|
@ -13,9 +15,11 @@ export function saveSvg(value, content) {
|
||||||
a.click()
|
a.click()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveImg(value, content, width, height) {
|
export function saveImg(value, content, width, height, type) {
|
||||||
|
if (!MIME[type]) throw "Error image type";
|
||||||
|
|
||||||
// Finish creating downloadable data
|
// Finish creating downloadable data
|
||||||
let filename = "QRcode_" + value + ".jpg";
|
let filename = "QRcode_" + value + "." + type;
|
||||||
const wrap = document.createElement('div');
|
const wrap = document.createElement('div');
|
||||||
wrap.innerHTML = content;
|
wrap.innerHTML = content;
|
||||||
|
|
||||||
|
@ -40,15 +44,15 @@ export function saveImg(value, content, width, height) {
|
||||||
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
img.onload = () => {
|
img.onload = () => {
|
||||||
ctx.fillStyle = 'white'
|
ctx.fillStyle = 'white';
|
||||||
ctx.fillRect(0, 0, width, height)
|
if (type === 'jpg') ctx.fillRect(0, 0, width, height);
|
||||||
ctx.drawImage(img, 0, 0, width, height);
|
ctx.drawImage(img, 0, 0, width, height);
|
||||||
// `download` attr is not well supported
|
// `download` attr is not well supported
|
||||||
// Will result in a download popup for chrome and the
|
// Will result in a download popup for chrome and the
|
||||||
// image opening in a new tab for others.
|
// image opening in a new tab for others.
|
||||||
|
|
||||||
let a = document.createElement('a');
|
let a = document.createElement('a');
|
||||||
let data = canvas.toDataURL('image/jpeg', 0.8);
|
let data = canvas.toDataURL(MIME[type], 0.8);
|
||||||
a.setAttribute('href', data)
|
a.setAttribute('href', data)
|
||||||
a.setAttribute('target', 'download')
|
a.setAttribute('target', 'download')
|
||||||
a.setAttribute('download', filename);
|
a.setAttribute('download', filename);
|
||||||
|
|
|
@ -16,10 +16,10 @@ export function handleDownloadSvg(rendererName) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleDownloadJpg(rendererName) {
|
export function handleDownloadImg(rendererName, type) {
|
||||||
ReactGA.event({
|
ReactGA.event({
|
||||||
category: 'Style',
|
category: 'Style',
|
||||||
action: 'DownloadJpg',
|
action: 'Download' + type.charAt(0).toUpperCase() + type.slice(1),
|
||||||
label: rendererName,
|
label: rendererName,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
import {ParamTypes} from "../constant/ParamTypes";
|
import {ParamTypes} from "../constant/ParamTypes";
|
||||||
let seed = 0;
|
let seed = 0;
|
||||||
|
|
||||||
|
let idNum = 0;
|
||||||
|
|
||||||
export function rand(min, max) {
|
export function rand(min, max) {
|
||||||
seed = (seed * 9301 + 49297) % 233280;
|
seed = (seed * 9301 + 49297) % 233280;
|
||||||
return min + (seed / 233280.0) * (max - min);
|
return min + (seed / 233280.0) * (max - min);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getIdNum() {
|
||||||
|
idNum += 1
|
||||||
|
return idNum.toString()
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -8639,7 +8639,7 @@ raf@^3.4.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
performance-now "^2.1.0"
|
performance-now "^2.1.0"
|
||||||
|
|
||||||
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
|
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.npm.taobao.org/randombytes/download/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
resolved "https://registry.npm.taobao.org/randombytes/download/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
|
||||||
integrity sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo=
|
integrity sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo=
|
||||||
|
@ -9448,6 +9448,13 @@ serialize-javascript@^2.1.2:
|
||||||
resolved "https://registry.npm.taobao.org/serialize-javascript/download/serialize-javascript-2.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fserialize-javascript%2Fdownload%2Fserialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
|
resolved "https://registry.npm.taobao.org/serialize-javascript/download/serialize-javascript-2.1.2.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fserialize-javascript%2Fdownload%2Fserialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61"
|
||||||
integrity sha1-7OxTsOAxe9yV73arcHS3OEeF+mE=
|
integrity sha1-7OxTsOAxe9yV73arcHS3OEeF+mE=
|
||||||
|
|
||||||
|
serialize-javascript@^3.1.0:
|
||||||
|
version "3.1.0"
|
||||||
|
resolved "https://registry.npm.taobao.org/serialize-javascript/download/serialize-javascript-3.1.0.tgz#8bf3a9170712664ef2561b44b691eafe399214ea"
|
||||||
|
integrity sha1-i/OpFwcSZk7yVhtEtpHq/jmSFOo=
|
||||||
|
dependencies:
|
||||||
|
randombytes "^2.1.0"
|
||||||
|
|
||||||
serve-index@^1.9.1:
|
serve-index@^1.9.1:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
resolved "https://registry.npm.taobao.org/serve-index/download/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
|
resolved "https://registry.npm.taobao.org/serve-index/download/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
|
||||||
|
|
Loading…
Reference in New Issue