终于搞定了canvas上插入图片的问题了。
先说说我遇到的问题:
- 跨域问题
- 多个图片加载问题
跨域问题
- 这个好说,首先我们接收到的图片资源必须可以跨域访(Access-Control-Allow-Origi), 然后再img标签中加上crossOrigin = "anonymous", 如果是用JS创建的img(let img = new Image ), 可以使用img.crossOrigiin = true 或者是 "anonymous"都可以,用来设置可以接收到跨域的图片资源
多个图片加载问题
- 一个图片都好说,在它的onload事件中 去drawImage,但是多个有图片呢?
- 如果不确定各个图片的加载完成顺序,就会导致我不知道应该在哪个图片的onload事件中执行其它操作(写字等)。这时我想到了一个(不太好的)办法:每当onlaod执行时,我给这个图片设置一个flag为true,然后用setInterval()写一个周期函数,周期函数用来监听当所有图片的flag为true时,执行其它操作
- 上个方法有个隐藏的坑,当图片存在层次关系式,先draw的图片会覆盖住后draw的图片,所有如果有高宽为canvas高宽的背景图时,我们就必须确保这个背景图最先draw,那么上一个方法就行不通了,因为它无法确定图片的onload事件执行顺序(onload事件中会执行drawImage)
- 如果我们要确定onlaod的执行顺序又该如何做呢?这就要想想onload什么时候被触发(img图片加载完成时触发)。所以,如果我们不给img.src赋值(img = new Image),onload事件永远都不会触发,通过这个原理,我们可以在img1的onload事件中去给img2的src赋值(img1.src必须在onload事件外面赋值),这样的设置只有在img1加载完成后,img2才会加载。 不过这样做也有缺点:图片的加载变成了同步,想对于上个方法,时间可能会久点,所以:只有当我们需要加载的多张图片存在覆盖问题时,才来采用这种方法
canvas转化为的图片的预览图:
代码如下:
- props中的数据都是父组件传输过来的
- backImg必须最先draw,因为其他图片要覆盖它,如果它最后才draw,必然会覆盖其他图片
// 邀请卡模板2 -- UI
// 图片自己去照一张可用的
const cardModel2 = require('../statics/images/card_model_2.png');
const CardModel2 = React.createClass({
propTypes: {
type: React.PropTypes.string,
backImg: React.PropTypes.string,
avatar: React.PropTypes.string,
nickname: React.PropTypes.string,
startTime: React.PropTypes.number,
fileName: React.PropTypes.string,
title: React.PropTypes.string,
shareDesc: React.PropTypes.string,
expireDateTime: React.PropTypes.number
},
render: function () {
return (
<div>
<canvas id="myCanvas" ref="canvas" width="750" height="1000">您的浏览器不支持canvas</canvas>
{/*<img src={cardModel2} ref="backImg" style={{display: 'none'}} crossOrigin="anonymous"/>*/}
{/*<img src={this.props.avatar} ref="avatar" style={{display: 'none'}} crossOrigin="anonymous"/>*/}
<img src={this.props.fileName} ref="fileName" style={{display: 'none'}} crossOrigin="anonymous"/>
<img ref="showImg" className="showImg" crossOrigin="anonymous"/>
</div>
)
},
componentDidMount: function () {
const _this = this;
this.timer = setTimeout(() => {
_this.generateImage();
}, 100);
},
componentWillUnmount: function () {
this.timer && clearTimeout(this.timer);
this.imgListener && clearInterval(this.imgListener);
},
generateImage: function () {
const _this = this;
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext('2d');
let avatarFlag, backImgFlag, codeImgFlag;
// 图片加载顺序: 背景图 -> 二维码 -> 用户头像
//添加头像
let avatar = new Image;
// avatar.crossOrigin = "anonymous";
avatar.crossOrigin = true;
avatar.onload = function () {
ctx.drawImage(avatar, 112, 168, 80, 80);
avatarFlag = true;
_this.canvas2Img();
};
// 二维码
let codeImg = new Image;
// codeImg.crossOrigin = "anonymous";
codeImg.crossOrigin = true;
codeImg.onload = function () {
ctx.drawImage(codeImg, 146, 712, 156, 156);
codeImgFlag = true;
avatar.src = _this.props.avatar || defaultUserAvatar;
};
//添加背景图
let backImg = new Image;
backImg.crossOrigin = "anonymous";
backImg.onload = function () {
ctx.drawImage(backImg, 0, 0, 750, 1000);
backImgFlag = true;
codeImg.src = _this.props.fileName;
};
backImg.src = cardModel2;
// 周期监测
// this.imgListener = setInterval(() => {
// if (avatarFlag == true && backImgFlag == true && codeImgFlag == true) {
// _this.canvas2Img();
// clearInterval(_this.imgListener);
// }
// }, 100);
},
canvas2Img: function () {
const canvas = this.refs.canvas;
const ctx = canvas.getContext('2d');
let ts, date;
const _this = this;
// 姓名
ctx.font = "24px Yahei";
ctx.fillStyle = "#f46a7c";
const nickname = this.props.nickname || "";
ctx.fillText("你的好友 " + nickname, 212, 196);
// 提示
ctx.font = "24px Yahei";
ctx.fillStyle = "#f46a7c";
ctx.fillText("我发现好内容 想与你分享", 212, 236);
// 课程名称
ctx.font = "36px Yahei";
ctx.fillStyle = "#f8f7f5";
ctx.textAlign = "center";
let courseTitle = this.props.title || "";
if (courseTitle.slice(0, 11)) {
ctx.fillText(courseTitle.slice(0, 10), 375, 354);
}
if (courseTitle.slice(10, 20)) {
ctx.fillText(courseTitle.slice(10, 20), 375, 394);
}
// 课程描述
ctx.font = "26px Yahei";
ctx.fillStyle = "#4ec4ce";
ctx.textAlign = "center";
const shareDesc = this.props.shareDesc;
if (shareDesc && shareDesc.length > 0) {
ctx.fillText(shareDesc.slice(0, 18), 375, 466);
if (shareDesc.slice(18, 36)) {
ctx.fillText(shareDesc.slice(18, 36), 375, 498);
}
if (shareDesc.slice(36, 53)) {
ctx.fillText(shareDesc.slice(36, 53) + "...", 375, 540);
}
}
// 开课时间
if (this.props.type == '1' && this.props.startTime) {
ts = new Date(this.props.startTime);
date = "开课时间 " + (ts.getMonth() + 1) + "月" + ts.getDate() + "日 ";
ts = ts.toTimeString().split(":");
date += ts[0] + ":" + ts[1];
ctx.font = "26px Yahei";
ctx.fillStyle = "#f8f7f5";
ctx.textAlign = "center";
ctx.fillText(date, 375, 636);
}
// 邀请卡到期时间
if (this.props.expireDateTime) {
ts = new Date(this.props.expireDateTime);
date = "邀请卡到期时间:" + ts.getFullYear() + "年" + (ts.getMonth() + 1) + "月" + ts.getDate() + "日";
ctx.font = "24px Yahei";
ctx.fillStyle = "#285778";
ctx.textAlign = "center";
ctx.fillText(date, 375, 924);
}
let imgUrl = canvas.toDataURL();
_this.refs.showImg.src = imgUrl;
}
});