前言
好久都没更新了,主要是最近着手一个项目。弄完了,我干我自己的事,想给自己的域名备案,目前都已经到管局审核这一步了,估计最快也要等到下周三去
好了言归正传,都知道一个域名有它的‘域名证书’,所以闲着也是闲着,搞个ICP备案证书玩玩又如何呢
效果图见下:
七要素、一绘图、两控制
七要素
七个Input组件,七个Label组件
需要-网站域名、主办单位名、主办单位性质、审核通过日期、ICP备案号、网站名、网站内容
一绘图
一个Canvas组件
两控制
两个Button组件,一个在七要素下,一个在Canvas下
Example-Code
太简单了就不过多赘述了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ICP备案证书生成器</title>
<style>
body {
font-family: 'Arial', sans-serif;
background-color: #f4f4f9;
color: #333;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
min-height: 100vh;
}
.form-container {
width: 100%;
flex-grow: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.certificate-container {
width: 40%;
margin-right: 80px;
}
#certificate {
display: none;
border: 1px solid #333;
}
.input-area, .button-area {
display: flex;
justify-content: space-around;
width: 100%;
margin-bottom: 10px;
}
.input-area {
flex-wrap: wrap;
}
.button-area {
justify-content: space-between;
}
textarea, input, button {
margin: 10px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 5px;
margin-bottom: -18px;
}
textarea {
width: 100%;
height: 80px;
border-radius: 10px;
}
button {
background-color: #4CAF50;
color: white;
border: none;
cursor: pointer;
transition: background-color 0.3s;
flex-basis: 45%;
margin: 5px;
}
button:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<div id="form-forms" class="form-container">
<h1>ICP备案证书生成器</h1>
<form id="certForm">
<label for="domain">网站域名:</label>
<input type="text" id="domain" name="domain" required><br><br>
<label for="owner">主办单位名称:</label>
<input type="text" id="owner" name="owner" required><br><br>
<label for="owner">主办单位性质:</label>
<input type="text" id="ownerxz" name="ownerxz" required><br><br>
<label for="date">审核通过日期:</label>
<input type="date" id="date" name="date" required><br><br>
<label for="certNumber">ICP备案号:</label>
<input type="text" id="certNumber" name="certNumber" required><br><br>
<label for="websiteName">网站名称:</label>
<input type="text" id="websiteName" name="websiteName" required><br><br>
<label for="serviceContent">网站内容:</label>
<textarea id="serviceContent" name="serviceContent" rows="4" required></textarea><br><br>
<button type="button" onclick="thebookicpsc()">生成证书</button>
</form>
</div>
<div id="canvascsr" class="certificate-container">
<canvas id="certificate" width="650" height="400"></canvas>
<button id="buttontoshow" style="display: none;">重新修改</button>
</div>
</div>
<script src="certificate.js"></script>
<script>
</script>
</body>
</html>
Js实现
1. 定义全局变量
首先,我们需要定义两个全局变量
let chatlast;
let ysjlist = [];
chatlast
用于存储表单的原始HTML内容ysjlist
用于存储用户输入的信息
2. 生成序列号
我们需要为证书设计一个序列号元素,我们可以通过取时间戳和拼接随机生成的字符串完成
十六位
function xlhsc() {
let timestamp = (Date.now().toString()).substring(8, 14);
let randompart = (Math.random().toString(36).substring(7)).toUpperCase();
let serial = timestamp + randompart;
if (serial.length > 16) {
return serial.substring(0, 16);
} else {
while (serial.length < 16) {
randompart = (Math.random().toString(36).substring(7)).toUpperCase();
serial += randompart.charAt(0);
}
return serial.substring(0, 16);
}
}
- 生成一个16位的序列号,前8位是时间戳,后8位是随机生成的字符串
3. 文本换行
我们需要考虑,如果网站内容过多的情况。如果网站内容过多,那我们就让它换行
function wrapText(context, text, maxWidth, lineHeight, font) {
let wrappedText = [];
let line = '';
for (let char of text) {
let testLine = line + char;
let metrics = context.measureText(testLine);
let testWidth = metrics.width;
if (testWidth > maxWidth && line.length > 0) {
wrappedText.push(line);
line = char;
} else {
line = testLine;
}
}
if (line.length > 0) {
wrappedText.push(line);
}
return wrappedText;
}
- 根据最大宽度将文本自动换行。
4. 创建印章函数
我们同样可以为证书设计一个印章元素,使其更专业或有信赖度
function createSeal(id, company, name) {
var canvas = document.getElementById(id);
var context = canvas.getContext('2d');
var width = canvas.width / 2;
var height = canvas.height / 2;
context.lineWidth = 7;
context.strokeStyle = "#f00";
context.beginPath();
context.arc(width, height, 110, 0, Math.PI * 2);
context.stroke();
create5star(context, width, height, 30, "#f00", 0);
context.font = '22px Helvetica';
context.textBaseline = 'middle';
context.textAlign = 'center';
context.lineWidth = 1;
context.fillStyle = '#f00';
context.fillText(name, width, height + 65);
context.translate(width, height);
context.font = '30px Helvetica'
var count = company.length;
var angle = 4 * Math.PI / (3 * (count - 1));
var chars = company.split("");
var c;
for (var i = 0; i < count; i++){
c = chars[i];
if (i == 0)
context.rotate(5 * Math.PI / 6);
else
context.rotate(angle);
context.save();
context.translate(90, 0);
context.rotate(Math.PI / 2);
context.fillText(c, 0, 5);
context.restore();
}
}
5. New Canvas
但是,如果用户需要重新编辑内容,就需要重新生成证书一次,
我们直接删除原canvas,创建一个新的canvas用于印章的二次绘制
function creatnewcanvasdemo() {
var existingCanvas = document.getElementById('demo');
if (existingCanvas) {
existingCanvas.parentNode.removeChild(existingCanvas);
}
var canvas = document.createElement('canvas');
canvas.id = 'demo';
canvas.style.display = 'none';
canvas.width = 650;
canvas.height = 400;
document.body.appendChild(canvas);
return canvas;
}
6. 添加水印
水印是必不可少的,随机分布,且根据水印文本长度来调整位置,并不重复
function addwatermarks(canvas, watermarksCount, onepart, twopart, threepart) {
var ctx = canvas.getContext('2d');
var watermarkTexts = [onepart, twopart, threepart];
var usedPositions = new Set();
function isPositionAvailable(x, y, width, height) {
var position = x + ',' + y;
return !usedPositions.has(position) &&
x + width < canvas.width &&
y + height < canvas.height;
}
for (var i = 0; i < watermarksCount; i++) {
var textIndex = Math.floor(Math.random() * watermarkTexts.length);
var watermarkText = watermarkTexts[textIndex];
var x, y, positionAvailable;
do {
x = Math.random() * (canvas.width - 100) + 50;
y = Math.random() * (canvas.height - 30) + 30;
var textWidth = ctx.measureText(watermarkText).width;
var textHeight = 20;
positionAvailable = isPositionAvailable(x, y, textWidth, textHeight);
} while (!positionAvailable);
usedPositions.add(x + ',' + y);
ctx.font = '20px Arial';
ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
ctx.fillText(watermarkText, x, y);
}
}
7. 生成证书
拿到表单的所有内容,存入全局变量中,设置外背景以及内背景,填充元素
function thebookicpsc() {
chatlast = document.getElementById('form-forms').innerHTML;
const domain = document.getElementById('domain').value;
const owner = document.getElementById('owner').value;
const ownerxz = document.getElementById('ownerxz').value;
const date = document.getElementById('date').value;
const certNumber = document.getElementById('certNumber').value;
const websiteName = document.getElementById('websiteName').value;
const serviceContent = document.getElementById('serviceContent').value;
const canvas = document.getElementById('certificate');
if(domain === '' || owner === '' || ownerxz === '' || date === '' || certNumber === '' || websiteName === '' || serviceContent === '') {
alert('请键入完整信息');
return false;
}
document.getElementById('buttontoshow').style.display = 'block';
ysjlist['domain'] = domain;
ysjlist['owner'] = owner;
ysjlist['ownerxz'] = ownerxz;
ysjlist['date'] = date;
ysjlist['websiteName'] = websiteName;
ysjlist['serviceContent'] = serviceContent;
ysjlist['certNumber'] = certNumber;
const ctx = canvas.getContext('2d');
canvas.height = 600;
canvas.width = 650;
const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
gradient.addColorStop(0, '#efe8d1');
gradient.addColorStop(0.5, '#fbfbf3');
gradient.addColorStop(1, '#efe8d1');
ctx.fillStyle = '#5969a6';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = gradient;
ctx.fillRect(10, 10, canvas.width - 20, canvas.height - 20);
ctx.font = 'bold 34px Arial';
ctx.fillStyle = '#000';
ctx.textAlign = 'center';
ctx.fillText('ICP备案证书', canvas.width / 2, 60);
ctx.strokeStyle = "#000000";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(10, 75);
ctx.lineTo(640, 75);
ctx.stroke();
ctx.font = '28px Arial';
ctx.textAlign = 'left';
const contentX = 50;
const contentY = 120;
const lineHeight = 50;
ctx.fillText('网站域名:', contentX, contentY);
ctx.fillText(domain, contentX + 150, contentY);
ctx.fillText('主办单位名称:', contentX, contentY + lineHeight);
ctx.fillText(owner, contentX + 190, contentY + lineHeight);
ctx.fillText('主办单位性质:', contentX, contentY+2 * lineHeight);
ctx.fillText(ownerxz, contentX + 190, contentY +2* lineHeight);
ctx.fillText('审核通过日期:', contentX, contentY + 3 * lineHeight);
ctx.fillText(date, contentX + 190, contentY + 3 * lineHeight);
ctx.fillText('ICP备案号:', contentX, contentY + 4 * lineHeight);
ctx.fillText(certNumber, contentX + 150, contentY + 4 * lineHeight);
ctx.fillText('网站名称:', contentX, contentY + 5 * lineHeight);
ctx.fillText(websiteName, contentX + 150, contentY + 5 * lineHeight);
ctx.fillText('网站内容:', contentX, contentY + 6 * lineHeight);
const contentLines = wrapText(ctx, serviceContent, canvas.width - 230, lineHeight, '28px Arial');
let currentY = contentY + 6 * lineHeight;
contentLines.forEach(line => {
ctx.fillText(line, contentX + 150, currentY);
currentY += lineHeight;
});
const sealCanvas = creatnewcanvasdemo();
createSeal('demo', certNumber, '备案证书');
const sealX = canvas.width / 2;
const sealY = canvas.height - 100;
ctx.drawImage(sealCanvas, sealX - 80, sealY -180, 540, 340);
ctx.lineWidth = 2;
ctx.strokeStyle = '#000';
ctx.strokeRect(10, 10, canvas.width - 20, canvas.height - 20);
ctx.font = '15px Arial';
ctx.fillStyle = '#000';
ctx.fillText('发行日期:' + date, canvas.width - 180, canvas.height - 20);
ctx.fillText('证书序列号:' + xlhsc(), 50, canvas.height - 20);
addwatermarks(canvas,25,owner,certNumber,domain);
document.getElementById('form-forms').innerHTML = canvas.innerHTML;
document.getElementById('canvascsr').style.marginLeft = '360px';
canvas.style.display = 'block';
}
8.恢复表单
document.getElementById('buttontoshow').onclick = function () {
document.getElementById('form-forms').innerHTML = chatlast;
document.getElementById('buttontoshow').style.display = 'none';
document.getElementById('certificate').style.display = 'none';
document.getElementById('domain').value = ysjlist['domain'];
document.getElementById('owner').value = ysjlist['owner'];
document.getElementById('ownerxz').value = ysjlist['ownerxz'];
document.getElementById('date').value = ysjlist['date'];
document.getElementById('certNumber').value = ysjlist['certNumber'];
document.getElementById('websiteName').value = ysjlist['websiteName'];
document.getElementById('serviceContent').value = ysjlist['serviceContent'];
};