不是专门做前端的,代码写的不太好,权当抛砖引玉。
整体思路:
共有5层,除了背景颜色的div没什么用之外,canvas1用来读取图片作为背景,canvas2把文字展示出来,并记录拖拽文字的位置,canvas4 绘制拖拽后文字的位置,canvas3在最后保存的时候,把背景图片和文字重新绘制出来,canvas4用来把canvas1背景图片和canvas3拖拽后的文字给画到一个canvas上,保存图片,还有一个canvas,判断canvas1是不是空的。
除此之外,还用到了判断当前浏览器支持的字体,和颜色选择器,网络上都可以找到就不说了。
下边儿是效果和代码
代码如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script type="text/javascript" src="js/jquery-1.12.3.min.js"></script>
<script type="text/javascript" src="js/font-ch-en.js" charset="utf-8"></script>
<script type="text/javascript" src="js/isSupportFontFamily.js" charset="utf-8"></script>
<script type="text/javascript" src="js/jquery1.4.3.js" charset="utf-8"></script>
<script type="text/javascript" src="js/jquery.colorpicker.js" charset="utf-8"></script>
<style>
td{
text-align: center;
}
</style>
</head>
<body style="background-color: #F1F2F6;">
<div>
<div id="canvas_box" style="overflow: hidden;position: relative;">
<div style="width: 900px;height: 600px;background: #333;float: left;border-radius: 10px;margin-left: 100px;margin-top: 40px;"></div>
<canvas id="canvas3" style="width: 900px;height: 600px;display: block;position: absolute;margin-left: 100px;margin-top: 40px;" ></canvas>
<canvas id="canvas4" style="width: 900px;height: 600px;display: block;position: absolute;margin-left: 100px;margin-top: 40px;" ></canvas>
<canvas id="canvas1" style="width: 900px;height: 600px;display: block;position: absolute;margin-left: 100px;margin-top: 40px;" ></canvas>
<canvas id="canvas2" style="width: 900px;height: 600px;display: block;position: absolute;margin-left: 100px;margin-top: 40px;" ></canvas>
</div>
<div style="position: absolute;margin-left: 1100px;margin-top: -500px;">
<table style="border: solid 3px #7399cd;width: 280px;height: 360px;border-radius: 10px;">
<tr>
<td >
<input type="button" value="请选择图片" onclick="javascript:$('input[name=\'file\']').click();" style="border-radius: 5px;background-color: #337AB7;color: #F2FFFF;border: none;height: 35px;width: 90px;"/>
<input name="fileName" readonly style="background-color: transparent;border:0;display: none;"/>
<input type="file" name="file" id="fileOne" accept=".jpg,.png" style="display: none;" onchange="javascript:$('input[name=\'fileName\']').val(this.files[0].name);" />
</td>
</tr>
<td>
<div >请输入名字
<input id="name" type="text" style="border-radius: 5px;border: 1px solid #3F3F40;width: 80px;" oninput="changeFont()" />
</div>
</td>
<tr>
<td>
<div >请选择字体
<select id="fontFam" style="border-radius: 5px;border-color: black;width: 88px;height: 22px;" onchange="changeFont()">
<option>请选择</option>
</select>
</div>
</td>
</tr>
<tr>
<td>
<div >请选择样式
<select id="fontSty" style="border-radius: 5px;border-color: black;width: 88px;height: 22px;" onchange="changeFont()">
<option value="normal">正常</option>
<option value="oblique">斜体</option>
</select>
</div>
</td>
</tr>
<tr>
<td>
<div >请选择粗细
<select id="fontSty" style="border-radius: 5px;border-color: black;width: 88px;height: 22px;" onchange="changeFont()">
<option value="normal">常规</option>
<option value="600">斜体</option>
<option value="900">斜体</option>
</select>
</div>
</td>
</tr>
<tr>
<td>
<div >请选择字号
<input id="Btn1" type="button" value="+" name=""/>
<input id="fontSize" value="12" style="border-radius: 5px;border: 1px solid #3F3F40;width: 30px;text-align: center;height: 18px;" onchange="changeFont()"/>
<input id="Btn2" type="button" value="-" name=""/>
</div>
</td>
</tr>
<tr>
<td>
<div >请选择颜色
<input type="text" id="fontCol" value="#DBD71E" style="border-radius: 5px;border: 1px solid #3F3F40;width: 80px;" oninput="changeFont()" onchange="changeFont()"/>
</div>
</td>
</tr>
<tr>
<td>
<font style="color: red;" size="2">拖动左侧文字以调整位置</font>
</td>
</tr>
<tr>
<td >
<input type="button" id="btn" value="下载图片" style="border-radius: 5px;background: #5CB85C;color: #fcfcf9;border: none;height: 35px;width: 90px;" onclick="downloadimg()"/>
</td>
</tr>
</table>
<div id="result">
</div>
</div>
</div>
<script>
/* canvas1 显示背景图片
canvas2 显示文字,并记录拖拽文字的位置
canvas4 绘制拖拽后文字的位置
canvas3 最后保存的时候,把背景图片和文字重新绘制出来
*/
// 文字样式
const fontSty = document.getElementById('fontSty');
// 文字内容
const name = document.getElementById("name");
// 文字字体
const fontFam = document.getElementById('fontFam');
// 文字大小
const fontSi = document.getElementById("fontSize");
// 文字颜色
const fontCol = document.getElementById("fontCol");
const oBtn1=document.getElementById("Btn1");
const oBtn2=document.getElementById("Btn2");
const canvas1 = document.getElementById('canvas1');
const ctx1 = canvas1.getContext('2d');
const canvas2 = document.getElementById('canvas2');
const ctx2 = canvas2.getContext('2d');
const canvas3 = document.getElementById('canvas3');
const ctx3 = canvas3.getContext('2d');
const canvas4 = document.getElementById('canvas4');
const ctx4 = canvas4.getContext('2d');
const canvas5 = document.getElementById('canvas5');
const inputOne = document.getElementById('fileOne');
window.onload= function(){
// 获取浏览器支持的字体
loadFontFamily()
}
// 字号+-点击动作
oBtn1.onclick = function(){
num = fontSi.value;
num++;
fontSi.value = num;
if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
fontSi.dispatchEvent(evt);
} else {
fontSi.fireEvent("onchange");
}
};
oBtn2.onclick = function(){
num = fontSi.value;
num--;
fontSi.value = num;
if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
fontSi.dispatchEvent(evt);
} else {
fontSi.fireEvent("onchange");
}
}
//颜色拾取器
$("#fontCol").colorpicker({
target:'#title',
success:function(o,color){
fontCol.value = color
if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents");
evt.initEvent("change", false, true);
fontCol.dispatchEvent(evt);
} else {
fontCol.fireEvent("onchange");
}
},
reset:function(o){
fontCol.value = '#000000'
}
});
// 获取浏览器支持的字体
function loadFontFamily(){
// 数据
var arrFont = dataFont['windows'].concat(dataFont['OS X'], dataFont['office'], dataFont['open']);
var option = '';
arrFont.forEach(function (obj) {
var fontFamily = obj.en;
if (isSupportFontFamily(fontFamily)) {
option = option + '<option value="'+ fontFamily +'">'+ obj.ch +'</option>';
}
});
fontFam.innerHTML = option;
fontFam.value = "STXingkai";
}
//读取本地文件
inputOne.onchange = function () {
//1.获取选中的文件列表
var fileList = inputOne.files;
var file = fileList[0];
//读取文件内容
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function (e) {
//将结果显示到canvas
showCanvas(reader.result);
}
}
//指定图片内容显示
function showCanvas(dataUrl) {
//加载图片
var img = new Image();
img.src = dataUrl;
img.onload = function(){
//设置宽高一定要在canvas节点添加之后
canvas1.width = img.width;
canvas1.height = img.height;
canvas2.width = img.width;
canvas2.height = img.height;
ctx1.drawImage(this, 0, 0,img.width,img.height);
}
}
//canvas2的拖拽动作
var aa = 0
var bb = 0
canvas2.onmousedown = function(args){
var evt = args || event;
var StartX = evt.clientX;
var StartY = evt.clientY;
let initleft = Number((canvas2.style.left).replace('px',''))
let inittop = Number((canvas2.style.top).replace('px',''))
document.onmousemove = function(ev){
var iEvent = ev||event;
// 鼠标移动的距离
let left = iEvent.clientX - StartX;
let top = iEvent.clientY - StartY;
// 鼠标移动的距离 + 最开始的top 或者 left 就是最终的位置
canvas2.style.left = left + initleft + 'px';
canvas2.style.top = top + inittop +'px';
aa = (left + initleft)/900;
bb = (top + inittop)/600;
}
document.onmouseup = function(){
document.onmousedown = null;
document.onmousemove = null;
};
return false;
}
//验证canvas画布是否为空函数
function isCanvasBlank(canvas) {
var blank = document.createElement('canvas');//系统获取一个空canvas对象
blank.width = canvas.width;
blank.height = canvas.height;
return canvas.toDataURL() == blank.toDataURL();//比较值相等则为空
}
//修改文字属性
var fontStyle = ''
var fontFamily = ''
var fontSize = ''
var fontt = ''
var fontColor = ''
function changeFont(){
if(isCanvasBlank(canvas1)){
alert("请先选择图片");
return;
}
var text = name.value;
fontStyle = fontSty.value;
fontFamily = fontFam.value;
fontSize = fontSi.value;
fontt = fontStyle+' '+fontSize+'0px'+' '+ fontFamily;
fontColor = fontCol.value;
canvas2.width = canvas2.width
canvas3.width = canvas3.width
if(canvas2.getContext){
ctx2.beginPath();
ctx2.fillStyle = fontColor;// 设置填充画笔颜色为红色,即字体颜色
ctx2.font = fontt;// 设置字体大小
ctx2.fillText(text,700,1030);// 绘制 "实心" 文字
// fillText(str, x, y, maxW):str绘制的文字,(x, y)起始坐标,maxW是最大宽度,绘制文字超过该宽度则不显示。
ctx2.closePath();
}else{
alert('不支持');
}
}
//保存图片
function downloadimg() {
document.getElementById("btn").disabled = true;
canvas3.getContext('2d');
canvas3.width = canvas1.width;
canvas3.height = canvas1.height;
canvas4.width = canvas1.width;
canvas4.height = canvas1.height;
ctx4.beginPath();
ctx4.fillStyle = fontColor;// 设置填充画笔颜色为红色,即字体颜色
ctx4.font = fontt;// 设置字体大小
ctx4.fillText(name.value,700+aa*canvas2.width,1030+bb*canvas2.height);// 绘制 "实心" 文字
ctx4.closePath();
ctx3.drawImage(canvas1, 0, 0, canvas1.width, canvas1.height);
ctx3.drawImage(canvas4, 0, 0, canvas1.width, canvas1.height);
// 创建一个 a 标签,并设置 href 和 download 属性
const el = document.createElement('a');
// 设置 href 为图片经过 base64 编码后的字符串,默认为 png 格式
el.href = canvas3.toDataURL();
el.download = name.value;
// 创建一个点击事件并对 a 标签进行触发
const event = new MouseEvent('click');
el.dispatchEvent(event);
canvas4.width = canvas1.width;
document.getElementById("btn").disabled = false;
}
</script>
</body>
</html>
tips:实际应用的时候,发现判断canvas为空这个比较耗资源,会导致填写文字的时候卡卡的。