效果图如下:
实现功能:根据后台数据按轨迹点亮心形,点亮字母,并添加点亮日期,两个人的头像跟随轨迹平行移动,
(移动到第几个字母、日期、头像均通过后台获取,测试时需要自定义才能显示出来)
附加功能:移动端播放声音,H5移动端交互方法
直接上代码(后再详细解说)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>first line</title>
<style type="text/css">
* {margin: 0;padding: 0;}
html,body{
width: 100%;
height: 100%;
background: #F6F2FF;
overflow-y: auto;
cursor: pointer;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
.canvas {
display: block;
width: 100%;
height: 100%;
cursor: pointer;
}
.canvas canvas {
position:absolute;
left:0px;
top:0px;
border: none;
cursor: pointer;
}
.voice{
position: fixed;
right: 60px;
top: 100px;
}
.audio{
display: none;
}
</style>
</head>
<body>
<div class="canvas">
<canvas id="cvs" width="600" height="800"></canvas>
<canvas id="arcXY" width="600" height="800"></canvas>
<canvas id="arcXY1" width="600" height="800"></canvas>
<canvas id="arc-little-yellow" width="600" height="800"></canvas>
<img class="voice" id="myvoice" src="cpMemoryImages/voice@3x.png" width="100" height="100" onclick="play();" />
<audio class="audio" id="myaudio" controls="controls" loop></audio>
<iframe id="myframe" allow="autoplay" style="display:none;" src="http://www.baidu.com/"></iframe>
</div>
<script src="http://wechatfe.github.io/vconsole/lib/vconsole.min.js?v=3.2.0"></script>
<script src="script/jquery.min.js"></script>
<script type="text/javascript">
var vConsole = new VConsole();
var yourMusicUrl = '';
var url = yourMusicUrl;
var flag = true;
var isOnload = false;
var myaudio = document.getElementById('myaudio');
var myvoice = document.getElementById('myvoice');
var myframe = document.getElementById('myframe');
//声音播放
window.onload = function (e) {
myaudio.src = url;
myaudio.oncanplay = function () {
if(!isOnload) play()
};
};
if(ismobile() == '0') audioAutoPlay()
function audioAutoPlay() {
var play = function () {
myaudio.play();
document.removeEventListener("touchstart", play, false);
};
myaudio.play();
document.addEventListener("WeixinJSBridgeReady", function () {
play();
}, false);
document.addEventListener('YixinJSBridgeReady', function () {
play();
}, false);
document.addEventListener("touchstart", play, false);
}
function play(){
isOnload = true;
if(flag){
myaudio.play();
flag = false;
myvoice.src = "cpMemoryImages/voice@3x.png";
}else{
myaudio.pause();
myaudio.load();
flag = true;
myvoice.src = "cpMemoryImages/quiet@3x.png";
}
}
/**
* [isMobile 判断平台]
* @param test: 0:iPhone 1:Android
*/
function ismobile() {
var u = navigator.userAgent, app = navigator.appVersion;
if (/AppleWebKit.*Mobile/i.test(navigator.userAgent) || (/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE/.test(navigator.userAgent))) {
if (window.location.href.indexOf("?mobile") < 0) {
try {
if (/iPhone|mac|iPod|iPad/i.test(navigator.userAgent)) {
return '0';
} else {
return '1';
}
} catch (e) { }
}
} else if (u.indexOf('iPad') > -1) {
return '0';
} else {
return '1';
}
};
const isIphonex = () => { // X XS, XS Max, XR
const xSeriesConfig = [
{
devicePixelRatio: 3,
width: 375,
height: 812,
},
{
devicePixelRatio: 3,
width: 414,
height: 896,
},
{
devicePixelRatio: 2,
width: 414,
height: 896,
},
]; // h5
if (typeof window !== 'undefined' && window) {
const isIOS = /iphone/gi.test(window.navigator.userAgent);
if (!isIOS) return false;
const { devicePixelRatio, screen } = window;
const { width, height } = screen;
return xSeriesConfig.some(item => item.devicePixelRatio === devicePixelRatio && item.width === width && item.height === height);
}
return false;
}
//画图开始
var canvas = document.querySelector('canvas'),
context = canvas.getContext('2d');
var startx = 140, //起始点x轴坐标
starty = 0, //起始点y轴坐标
r = 200, //弯道半径
lineHeight = 200, //起始点竖线长度
lineWidth = 300, //弯道之间直线距离长度
y = 0,
step = 0,
serverData = {}; //从服务器端获取的数据
if(isIphonex()){
lineHeight = 280;
}
var w, h, w1, h1;
w = canvas.width = window.innerWidth;
h = canvas.height = lineHeight + 14 * r + 800;
var interVal;
context.fillStyle = "#F6F2FF";
context.font = "normal 600 50px 苹方-简";//绘制文字
context.fillStyle = "#333333";// 设置颜色
context.textAlign = "center";// 设置水平对齐方式
context.textBaseline = "middle";// 设置垂直对齐方式
context.fillText("我们的回忆", 480, lineHeight - 120);// 绘制文字(参数:要写的字,x坐标,y坐标)
//画点亮后的日期
function lightDate(date, x, y) {
context.font = "normal 500 40px 苹方-简";
context.fillStyle = "#898FA3";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText(date, parseInt(x), parseInt(y));
}
//画点亮后的文字
function lightText(text, x, y){
context.font = "normal 500 40px 苹方-简";
context.fillStyle = "#8B63FF";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText(text, parseInt(x), parseInt(y));
}
//加载图片
var img_mine = new Image(),
img_mycp = new Image(),
img_tree = new Image(),
img_plan = new Image(),
img_people1 = new Image(),
img_people2 = new Image(),
img_mew = new Image(),
img_t = new Image(),
img_t_ = new Image(),
img_h = new Image(),
img_h_ = new Image(),
img_e = new Image(),
img_e_ = new Image(),
img_o = new Image(),
img_o_ = new Image(),
img_n = new Image(),
img_n_ = new Image(),
img_cp = new Image(),
img_cp_ = new Image();
img_gocp = new Image();
img_gocp_ = new Image();
// img_mine.src = serverData.icon;
// img_cp.src = serverData.cpIcon;
img_tree.src = 'cpMemoryImages/tree@3x.png';
img_plan.src = 'cpMemoryImages/plan@3x.png';
img_people1.src = 'cpMemoryImages/people1@3x.png';
img_people2.src = 'cpMemoryImages/people2@3x.png';
img_mew.src = 'cpMemoryImages/mew@3x.png';
img_t.src = 'cpMemoryImages/t_s@3x.png';
img_t_.src = 'cpMemoryImages/t_d@3x.png';
img_h.src = 'cpMemoryImages/h_s@3x.png';
img_h_.src = 'cpMemoryImages/h_d@3x.png';
img_e.src = 'cpMemoryImages/e_s@3x.png';
img_e_.src = 'cpMemoryImages/e_d@3x.png';
img_o.src = 'cpMemoryImages/o_s@3x.png';
img_o_.src = 'cpMemoryImages/o_d@3x.png';
img_n.src = 'cpMemoryImages/n_s@3x.png';
img_n_.src = 'cpMemoryImages/n_d@3x.png';
img_cp.src = 'cpMemoryImages/cp_s@3x.png';
img_cp_.src = 'cpMemoryImages/cp_d@3x.png';
img_gocp.src = 'cpMemoryImages/Rectangle@3x.png';
img_gocp_.src = 'cpMemoryImages/Rectangle_@3x.png';
//图片加载完后,将其显示在canvas中
img_gocp.onload = function () {
context.drawImage(img_plan, 400, lineHeight - 50);// context.drawImage(this, 0, 0, 1080, 980)改变图片大小到1080*980
context.drawImage(img_tree, 800, lineHeight - 50);
context.drawImage(img_tree, 30, lineHeight + 150);
context.drawImage(img_tree, 800, lineHeight + 1600);
context.drawImage(img_tree, 30, lineHeight + 2750);
context.drawImage(img_mew, 750, lineHeight + 900);
context.drawImage(img_people1, 850, lineHeight + 550);
context.drawImage(img_people2, 30, lineHeight + 1800);
context.font = "normal 600 50px 苹方 粗体";
context.fillStyle = "#333333";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("那么,一起走吧?", 495, lineHeight + 3130);
context.drawImage(img_gocp, 30, lineHeight + 3200);
context.font = "normal 400 50px 苹方-港";
context.fillStyle = "#640000";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("进入CP空间", 475, lineHeight + 3270);
context.drawImage(img_t_, 480, lineHeight + 250, 1.5 * r, 1.8 * r);
context.drawImage(img_h_, 190, lineHeight + 650, 1.5 * r, 1.8 * r);
context.drawImage(img_e_, 480, lineHeight + 1050, 1.5 * r, 1.8 * r);
context.drawImage(img_o_, 190, lineHeight + 1450, 1.5 * r, 1.8 * r);
context.drawImage(img_n_, 480, lineHeight + 1850, 1.5 * r, 1.8 * r);
context.drawImage(img_e_, 190, lineHeight + 2250, 1.5 * r, 1.8 * r);
context.drawImage(img_cp_, 480, lineHeight + 2650, 1.5 * r, 1.8 * r);
}
function mousePosition(e) {
if (e.pageX && e.pageY) {
return {
x: e.pageX,
y: e.pageY
};
}
var scrollElem = (document.compatMode && document.compatMode != "BackCompat") ? document.documentElement : document.body;
return {
x: e.clientX + scrollElem.scrollLeft,
y: e.clientY + scrollElem.scrollTop
};
}
onclick = ()=>{
var allowX = mousePosition(event).x,
allowY = mousePosition(event).y;
if(allowX > 60 && allowX < 950 && allowY > (lineHeight + 3200) && allowY < (lineHeight + 3350)) goCp();
}
document.body.addEventListener('touchstart', function () {
var allowX = mousePosition(event).x,
allowY = mousePosition(event).y;
if (allowX > 60 && allowX < 950 && allowY > (lineHeight + 3200) && allowY < (lineHeight + 3350)) goCp();
});
//画路径尽头的黄色圆圈(弧线)arc-little-yellow
function movePhotoArcLittleYellow(x0, y0, r, a0) {
var sins = Math.sin(2 * Math.PI / 360 * a0);
var coss = Math.cos(2 * Math.PI / 360 * a0);
var centerX = coss * r + x0;//圆弧中间点坐标x
var centerY = sins * r + y0;//圆弧中间点坐标y
var cas = document.getElementById('arc-little-yellow');
var ctx = cas.getContext('2d');
cas.width = window.innerWidth;
cas.height = lineHeight + 14 * r + 800;
ctx.fillStyle = "#000000";
//ctx.fillRect(x0, y0, 100, 100);
ctx.arc(centerX, centerY, 30, 0, Math.PI * 2, false);
}
//画路径尽头的黄色圆圈(弧线)
function movePhotoLineLittleYellow(x0, y0) {
var cas = document.getElementById('arc-little-yellow');
var ctx = cas.getContext('2d');
cas.width = window.innerWidth;
cas.height = lineHeight + 14 * r + 800;
ctx.fillStyle = "#000000";
//ctx.fillRect(x0, y0, 100, 100);
context.arc(x0, y0, 30, 0, Math.PI * 2, false);
}
//已知圆心,半径,角度,求圆上的点坐标,并画出移动头像
var arrXY = [], arrXY1 = [];
function movePhotoArc(x0, y0, r, a0) {
var sins = Math.sin(2 * Math.PI / 360 * a0);
var coss = Math.cos(2 * Math.PI / 360 * a0);
var centerX = coss * r + x0;//圆弧中间点坐标x
var centerY = sins * r + y0;//圆弧中间点坐标y
var cas = document.getElementById('arcXY');
var ctx = cas.getContext('2d');
cas.width = window.innerWidth;
cas.height = lineHeight + 14 * r + 800;
ctx.fillStyle = "rgba(0,0,0,0)";
if (arrXY.length != 0) {
ctx.clearRect(arrXY[0], arrXY[1], 100, 100);
}
ctx.fillRect(centerX, centerY, 100, 100);
// ctx.clearRect(0, 0, width, height);
//开始路径画圆,剪切处理
//ctx.save();
ctx.beginPath();
ctx.arc(centerX + 30, centerY + 30, 30, 0, Math.PI * 2, false);
ctx.clip(); //剪切路径
ctx.drawImage(img_mine, centerX, centerY, 60, 60);
arrXY = [centerX, centerY];
if (centerY >= window.innerHeight / 2) {
scrollTo(300, centerY - window.innerHeight / 2);
}
}
function movePhotoArc1(x0, y0, r, a0) {
var sins = Math.sin(2 * Math.PI / 360 * a0);
var coss = Math.cos(2 * Math.PI / 360 * a0);
var centerX = coss * r + x0;//圆弧中间点坐标x
var centerY = sins * r + y0;//圆弧中间点坐标y
var cas1 = document.getElementById('arcXY1');
var ctx1 = cas1.getContext('2d');
cas1.width = window.innerWidth;
cas1.height = lineHeight + 14 * r + 800
;
ctx1.fillStyle = "rgba(0,0,0,0)";
if (arrXY1.length != 0) {
ctx1.clearRect(arrXY1[0] + 60, arrXY1[1], 100, 100);
}
ctx1.fillRect(centerX + 60, centerY, 100, 100);
ctx1.beginPath();
ctx1.arc(centerX + 90, centerY + 30, 30, 0, Math.PI * 2, false);
ctx1.clip(); //剪切路径
ctx1.drawImage(img_mycp, centerX + 60, centerY, 60, 60);
arrXY1 = [centerX + 60, centerY];
}
//画头像1运动轨迹
function movePhotoLine(x0, y0){
var cas = document.getElementById('arcXY');
var ctx = cas.getContext('2d');
cas.width = window.innerWidth;
cas.height = lineHeight + 14 * r + 800;
ctx.fillStyle = "rgba(0,0,0,0)";
if (arrXY.length != 0) {
ctx.clearRect(arrXY[0], arrXY[1], 100, 100);
}
ctx.fillRect(x0, y0, 100, 100);
ctx.arc(x0+30, y0+30, 30, 0, Math.PI * 2, false);
ctx.clip(); //剪切路径
ctx.drawImage(img_mine, x0, y0, 60, 60);
arrXY = [x0, y0];
if (y0 >= window.innerHeight / 2) {
scrollTo(300, y0 - window.innerHeight / 2);
}
}
//画头像2运动轨迹
function movePhotoLine1(x0, y0) {
var cas1 = document.getElementById('arcXY1');
var ctx1 = cas1.getContext('2d');
cas1.width = window.innerWidth;
cas1.height = lineHeight + 14 * r + 800;
ctx1.fillStyle = "rgba(0,0,0,0)";
if (arrXY1.length != 0) {
ctx1.clearRect(arrXY1[0] + 60, arrXY1[1], 100, 100);
}
ctx1.fillRect(x0 + 60, y0, 100, 100);
ctx1.arc(x0 + 90, y0 + 30, 30, 0, Math.PI * 2, false);
ctx1.clip(); //剪切路径
ctx1.drawImage(img_mycp, x0 + 60, y0, 60, 60);
arrXY1 = [x0 + 60, y0];
}
//日期格式化
function timestampToTime(timestamp) {
var date = new Date(timestamp);//时间戳为10位需*1000,时间戳为13位的话不需乘1000
Y = date.getFullYear();
M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1);
D = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
return Y + '年' + M + '月' + D + '日';
}
//画白线
function drawWhiteLine() {
// img_t_.onload = function () {
// context.drawImage(img_t_, 480, lineHeight + 250, 1.5 * r, 1.8 * r);
// context.drawImage(img_h_, 190, lineHeight + 650, 1.5 * r, 1.8 * r);
// context.drawImage(img_e_, 480, lineHeight + 1050, 1.5 * r, 1.8 * r);
// context.drawImage(img_o_, 190, lineHeight + 1450, 1.5 * r, 1.8 * r);
// context.drawImage(img_n_, 480, lineHeight + 1850, 1.5 * r, 1.8 * r);
// context.drawImage(img_e_, 190, lineHeight + 2250, 1.5 * r, 1.8 * r);
// context.drawImage(img_cp_, 480, lineHeight + 2650, 1.5 * r, 1.8 * r);
// }
context.beginPath();
context.moveTo(startx, starty);
context.lineTo(startx, lineHeight);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.arc(startx + r, lineHeight, r, Math.PI * 1, Math.PI * 1 - (Math.PI * 0.5), true);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.moveTo(startx + r, lineHeight + r);
context.lineTo(startx + r + lineWidth, lineHeight + r);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.arc(startx + r + lineWidth, lineHeight + 2 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1), false);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.moveTo(startx + r + lineWidth, lineHeight + 3 * r);
context.lineTo(startx + r, lineHeight + 3 * r);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.arc(startx + r, lineHeight + 4 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1), true);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.moveTo(startx + r, lineHeight + 5 * r);
context.lineTo(startx + r + lineWidth, lineHeight + 5 * r);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.arc(startx + r + lineWidth, lineHeight + 6 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1), false);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.moveTo(startx + r + lineWidth, lineHeight + 7 * r);
context.lineTo(startx + r, lineHeight + 7 * r);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.arc(startx + r, lineHeight + 8 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1), true);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.moveTo(startx + r, lineHeight + 9 * r);
context.lineTo(startx + r + lineWidth, lineHeight + 9 * r);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.arc(startx + r + lineWidth, lineHeight + 10 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1), false);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.moveTo(startx + r + lineWidth, lineHeight + 11 * r);
context.lineTo(startx + r, lineHeight + 11 * r);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.arc(startx + r, lineHeight + 12 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1), true);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.moveTo(startx + r, lineHeight + 13 * r);
context.lineTo(startx + r + lineWidth, lineHeight + 13 * r);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.arc(startx + r + lineWidth, lineHeight + 14 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1), false);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
context.beginPath();
context.moveTo(startx + r + lineWidth, lineHeight + 15 * r);
context.lineTo(0, lineHeight + 15 * r);
context.strokeStyle = "#FFFFFF";
context.lineWidth = 60;
context.stroke();
context.closePath();
}
//画灰线
function drawStep() {
interVal = window.requestAnimationFrame(drawStep, canvas);
if (lineHeight >= y && y >= 0) {//起始竖线
movePhotoLineLittleYellow(startx, y += 10);
movePhotoLine(startx, y += 10);
movePhotoLine1(startx, y += 10);
context.beginPath();
context.moveTo(startx, starty);
context.lineTo(startx, y += 10);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashLine(startx, starty, startx, y += 10);
}else if((lineHeight + 100) >= y && y > lineHeight){//第一道直角弯
y += 5;
movePhotoArcLittleYellow(startx + r, lineHeight, r, (1 - 0.5 * ((y - lineHeight) / 100)) * 180);
movePhotoArc(startx + r, lineHeight, r, (1 - 0.5 * ((y - lineHeight) / 100)) * 180)
movePhotoArc1(startx + r, lineHeight, r, (1 - 0.5 * ((y - lineHeight) / 100)) * 180)
context.beginPath();
context.arc(startx + r, lineHeight, r, Math.PI * 1, Math.PI * 1 - (Math.PI * 0.5) * ((y - lineHeight) / 100) , true);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashArc(startx + r, lineHeight, r, Math.PI * 1, Math.PI * 1 - (Math.PI * 0.5) * ((y - lineHeight) / 100), true);
} else if((lineHeight + 400) >= y && y > (lineHeight + 100)){//第一条从左到右直线
y += 10;
movePhotoLine(startx + r + (y - (lineHeight + 100)), lineHeight + r);
movePhotoLine1(startx + r + (y - (lineHeight + 100)), lineHeight + r);
context.beginPath();
context.moveTo(startx + r, lineHeight + r);
context.lineTo(startx + r + (y - (lineHeight + 100)), lineHeight + r);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashLine(startx + r, lineHeight + r, startx + r + (y - (lineHeight + 100)), lineHeight + r);
} else if ((lineHeight + 500) >= y && y > (lineHeight + 400)) {//第一道顺时针半圆弯
y += 2.5;
movePhotoArc(startx + r + lineWidth, lineHeight + 2 * r, r, (1.5 + (y - (lineHeight + 400)) / 100) * 180);
movePhotoArc1(startx + r + lineWidth, lineHeight + 2 * r, r, (1.5 + (y - (lineHeight + 400)) / 100) * 180);
context.beginPath();
context.arc(startx + r + lineWidth, lineHeight + 2 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 400)) / 100), false);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashArc(startx + r + lineWidth, lineHeight + 2 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 400)) / 100), false);
} else if ((lineHeight + 800) >= y && y > (lineHeight + 500)) {//第一条从右到左直线
y += 10;
movePhotoLine(startx + r + lineWidth - (y - (lineHeight + 500)), lineHeight + 3 * r);
movePhotoLine1(startx + r + lineWidth - (y - (lineHeight + 500)), lineHeight + 3 * r);
context.beginPath();
context.moveTo(startx + r + lineWidth, lineHeight + 3 * r);
context.lineTo(startx + r + lineWidth - (y - (lineHeight + 500)), lineHeight + 3 * r);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashLine(startx + r + lineWidth, lineHeight + 3 * r, startx + r + lineWidth - (y - (lineHeight + 500)), lineHeight + 3 * r);
if (y >= (lineHeight + 510)) {
if (y == (lineHeight + 512.5)) {
lightDate(timestampToTime(serverData.memory["1"].timestamp), 320, 600);
lightText(serverData.memory["1"].content, 320, 650);
if (step == 1) y = 99999;
}
context.drawImage(img_t, 480, lineHeight + 250, 1.5 * r, 1.8 * r);//点亮T
}
} else if ((lineHeight + 900) >= y && y > (lineHeight + 800)) {//第一道逆时针半圆弯
y += 2.5;
movePhotoArc(startx + r, lineHeight + 4 * r, r, (1.5 - (y - (lineHeight + 800)) / 100) * 180);
movePhotoArc1(startx + r, lineHeight + 4 * r, r, (1.5 - (y - (lineHeight + 800)) / 100) * 180);
context.beginPath();
context.arc(startx + r, lineHeight + 4 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1) * ((y - (lineHeight + 800)) / 100), true);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashArc(startx + r, lineHeight + 4 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1) * ((y - (lineHeight + 800)) / 100), true);
} else if ((lineHeight + 1200) >= y && y > (lineHeight + 900)) {//第二道从左到右直线
y += 10;
movePhotoLine(startx + r + (y - (lineHeight + 900)), lineHeight + 5 * r);
movePhotoLine1(startx + r + (y - (lineHeight + 900)), lineHeight + 5 * r);
context.beginPath();
context.moveTo(startx + r, lineHeight + 5 * r);
context.lineTo(startx + r + (y - (lineHeight + 900)), lineHeight + 5 * r);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashLine(startx + r, lineHeight + 5 * r, startx + r + (y - (lineHeight + 900)), lineHeight + 5 * r);
if (y >= (lineHeight + 910)) {
if (y == (lineHeight + 912.5)) {
lightDate(timestampToTime(serverData.memory["2"].timestamp), 650, 1000);
lightText(serverData.memory["2"].content, 650, 1050);
if (step == 2) y = 99999;
}
context.drawImage(img_h, 190, lineHeight + 650, 1.5 * r, 1.8 * r);//点亮H
}
} else if ((lineHeight + 1300) >= y && y > (lineHeight + 1200)) {//第二道顺时针半圆弯
y += 2.5;
movePhotoArc(startx + r + lineWidth, lineHeight + 6 * r, r, (1.5 + (y - (lineHeight + 1200)) / 100) * 180);
movePhotoArc1(startx + r + lineWidth, lineHeight + 6 * r, r, (1.5 + (y - (lineHeight + 1200)) / 100) * 180);
context.beginPath();
context.arc(startx + r + lineWidth, lineHeight + 6 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 1200)) / 100), false);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashArc(startx + r + lineWidth, lineHeight + 6 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 1200)) / 100), false);
} else if ((lineHeight + 1600) >= y && y > (lineHeight + 1300)) {//第二条从右到左直线
y += 10;
movePhotoLine(startx + r + lineWidth - (y - (lineHeight + 1300)), lineHeight + 7 * r);
movePhotoLine1(startx + r + lineWidth - (y - (lineHeight + 1300)), lineHeight + 7 * r);
context.beginPath();
context.moveTo(startx + r + lineWidth, lineHeight + 7 * r);
context.lineTo(startx + r + lineWidth - (y - (lineHeight + 1300)), lineHeight + 7 * r);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashLine(startx + r + lineWidth, lineHeight + 7 * r, startx + r + lineWidth - (y - (lineHeight + 1300)), lineHeight + 7 * r);
if (y >= (lineHeight + 1310)) {
if (y == (lineHeight + 1312.5)) {
lightDate(timestampToTime(serverData.memory["3"].timestamp), 320, 1400);
lightText(serverData.memory["3"].content, 320, 1450);
if (step == 3) y = 99999;
}
context.drawImage(img_e, 480, lineHeight + 1050, 1.5 * r, 1.8 * r);//点亮E
}
} else if ((lineHeight + 1700) >= y && y > (lineHeight + 1600)) {//第二道逆时针弯
y += 2.5;
movePhotoArc(startx + r, lineHeight + 8 * r, r, (1.5 - (y - (lineHeight + 1600)) / 100) * 180);
movePhotoArc1(startx + r, lineHeight + 8 * r, r, (1.5 - (y - (lineHeight + 1600)) / 100) * 180);
context.beginPath();
context.arc(startx + r, lineHeight + 8 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1) * ((y - (lineHeight + 1600)) / 100), true);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashArc(startx + r, lineHeight + 8 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1) * ((y - (lineHeight + 1600)) / 100), true);
} else if ((lineHeight + 2000) >= y && y > (lineHeight + 1700)) {//第三条从左到右直线
y += 10;
movePhotoLine(startx + r + (y - (lineHeight + 1700)), lineHeight + 9 * r);
movePhotoLine1(startx + r + (y - (lineHeight + 1700)), lineHeight + 9 * r);
context.beginPath();
context.moveTo(startx + r, lineHeight + 9 * r);
context.lineTo(startx + r + (y - (lineHeight + 1700)), lineHeight + 9 * r);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashLine(startx + r, lineHeight + 9 * r, startx + r + (y - (lineHeight + 1700)), lineHeight + 9 * r);
if (y >= (lineHeight + 1710)) {
if (y == (lineHeight + 1712.5)) {
lightDate(timestampToTime(serverData.memory["4"].timestamp), 650, 1800);
lightText(serverData.memory["4"].content, 650, 1850);
if (step == 4) y = 99999;
}
context.drawImage(img_o, 190, lineHeight + 1450, 1.5 * r, 1.8 * r);//点亮O
}
} else if ((lineHeight + 2100) >= y && y > (lineHeight + 2000)) {//第三道顺时针弯
y += 2.5;
movePhotoArc(startx + r + lineWidth, lineHeight + 10 * r, r, (1.5 + (y - (lineHeight + 2000)) / 100) * 180);
movePhotoArc1(startx + r + lineWidth, lineHeight + 10 * r, r, (1.5 + (y - (lineHeight + 2000)) / 100) * 180);
context.beginPath();
context.arc(startx + r + lineWidth, lineHeight + 10 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 2000)) / 100), false);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashArc(startx + r + lineWidth, lineHeight + 10 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 2000)) / 100), false);
} else if ((lineHeight + 2400) >= y && y > (lineHeight + 2100)) {//第三条从右到左直线
y += 10;
movePhotoLine(startx + r + lineWidth - (y - (lineHeight + 2100)), lineHeight + 11 * r);
movePhotoLine1(startx + r + lineWidth - (y - (lineHeight + 2100)), lineHeight + 11 * r);
context.beginPath();
context.moveTo(startx + r + lineWidth, lineHeight + 11 * r);
context.lineTo(startx + r + lineWidth - (y - (lineHeight + 2100)), lineHeight + 11 * r);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashLine(startx + r + lineWidth, lineHeight + 11 * r, startx + r + lineWidth - (y - (lineHeight + 2100)), lineHeight + 11 * r);
if (y >= (lineHeight + 2110)) {
if(y == (lineHeight + 2112.5)){
lightDate(timestampToTime(serverData.memory["5"].timestamp), 320, 2200);
lightText(serverData.memory["5"].content, 320, 2250);
if (step == 5) y = 99999;
}
context.drawImage(img_n, 480, lineHeight + 1850, 1.5 * r, 1.8 * r);//点亮N
}
} else if ((lineHeight + 2500) >= y && y > (lineHeight + 2400)) {//第三道逆时针弯
y += 2.5;
movePhotoArc(startx + r, lineHeight + 12 * r, r, (1.5 - (y - (lineHeight + 2400)) / 100) * 180);
movePhotoArc1(startx + r, lineHeight + 12 * r, r, (1.5 - (y - (lineHeight + 2400)) / 100) * 180);
context.beginPath();
context.arc(startx + r, lineHeight + 12 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1) * ((y - (lineHeight + 2400)) / 100), true);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashArc(startx + r, lineHeight + 12 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1) * ((y - (lineHeight + 2400)) / 100), true);
} else if ((lineHeight + 2800) >= y && y > (lineHeight + 2500)) {//第四条从左到右直线
y += 10;
movePhotoLine(startx + r + (y - (lineHeight + 2500)), lineHeight + 13 * r);
movePhotoLine1(startx + r + (y - (lineHeight + 2500)), lineHeight + 13 * r);
context.beginPath();
context.moveTo(startx + r, lineHeight + 13 * r);
context.lineTo(startx + r + (y - (lineHeight + 2500)), lineHeight + 13 * r);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashLine(startx + r, lineHeight + 13 * r, startx + r + (y - (lineHeight + 2500)), lineHeight + 13 * r);
if (y >= (lineHeight + 2510)) {
if(y == (lineHeight + 2512.5)){
lightDate(timestampToTime(serverData.memory["6"].timestamp), 650, 2600);
lightText(serverData.memory["6"].content, 650, 2650);
if (step == 6) y = 99999;
}
context.drawImage(img_e, 190, lineHeight + 2250, 1.5 * r, 1.8 * r);//点亮E
}
} else if ((lineHeight + 2900) >= y && y > (lineHeight + 2800)) {//第四道顺时针弯
y += 2.5;
movePhotoArc(startx + r + lineWidth, lineHeight + 14 * r, r, (1.5 + (y - (lineHeight + 2800)) / 100) * 180);
movePhotoArc1(startx + r + lineWidth, lineHeight + 14 * r, r, (1.5 + (y - (lineHeight + 2800)) / 100) * 180);
context.beginPath();
context.arc(startx + r + lineWidth, lineHeight + 14 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 2800)) / 100), false);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashArc(startx + r + lineWidth, lineHeight + 14 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 2800)) / 100), false);
} else if ((lineHeight + 2950) >= y && y > (lineHeight + 2900)) {//第四条从左到右直线
y += 10;
movePhotoLine(startx + r + lineWidth - (y - (lineHeight + 2900)), lineHeight + 15 * r);
movePhotoLine1(startx + r + lineWidth - (y - (lineHeight + 2900)), lineHeight + 15 * r);
context.beginPath();
context.moveTo(startx + r + lineWidth, lineHeight + 15 * r);
context.lineTo(startx + r + lineWidth - (y - (lineHeight + 2900)), lineHeight + 15 * r);
context.strokeStyle = "#898FA3";
context.lineWidth = 60;
context.stroke();
context.closePath();
drawDashLine(startx + r + lineWidth, lineHeight + 15 * r, startx + r + lineWidth - (y - (lineHeight + 2900)), lineHeight + 15 * r);
if (y >= (lineHeight + 2910)) {
if(y == (lineHeight + 2912.5)){
lightDate(timestampToTime(serverData.memory["7"].timestamp), 320, 3000);
lightText("成为专属CP", 320, 3050);
context.drawImage(img_gocp_, 30, lineHeight + 3200);
context.font = "normal 400 50px 苹方-港";
context.fillStyle = "#640000";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText("进入CP空间", 475, lineHeight + 3270);
if (step == 7) y = 99999;
}
context.drawImage(img_cp, 480, lineHeight + 2650, 1.5 * r, 1.8 * r);//点亮cp
}
}else{
window.cancelAnimationFrame(interVal);
}
}
//画虚线圆弧
/**
* @param x0: 起始点x轴坐标
* @param y0: 起始点y轴坐标
* @param r: 半径
* @param angleStart: 起始角
* @param angleEnd: 结束角
* @param anticlockwise: 是否逆时针
**/
function drawDashArc(x0, y0, r, angleStart, angleEnd, anticlockwise) {
context.setLineDash([20, 20]);
context.lineWidth = 6;
context.strokeStyle = '#FFFFFF';
context.beginPath();
context.arc(x0, y0, r, angleStart, angleEnd, anticlockwise);
context.stroke();
context.setLineDash([]);
}
//画虚线
/**
* @param x0: 起始点x轴坐标
* @param y0: 起始点y轴坐标
* @param x1: 结束点x轴坐标
* @param y1: 结束点y轴坐标
* @param lineWidth: 线的宽度
* @param strokeStyle: 线的颜色
* @param dashArray: 虚线的样式数组
**/
function drawDashLine(x0, y0, x1, y1) {
context.setLineDash([20, 20]);
context.lineWidth = 6;
context.strokeStyle = '#FFFFFF';
context.beginPath();
context.moveTo(x0, y0);
context.lineTo(x1, y1);
context.stroke();
context.setLineDash([]);
}
//移动端对接
function setupWebViewJavascriptBridge(callback) {
var ua = navigator.userAgent,
android = ua.indexOf('Android') > -1 ? true : false,
ipad = ua.indexOf('iPad') > -1 ? true : false,
ipod = ua.indexOf('iPod') > -1 ? true : false,
iphone = !ipad && ua.indexOf('iPhone') > -1 ? true : false;
//android使用
if(android){
if (window.WebViewJavascriptBridge) {
callback(window.WebViewJavascriptBridge)
} else {
document.addEventListener(
'WebViewJavascriptBridgeReady'
, function () {
callback(window.WebViewJavascriptBridge)
},
false
);
}
}else if(ipad || ipod || iphone){
//ios使用
if (window.WebViewJavascriptBridge) {
return callback(WebViewJavascriptBridge);
}
if (window.WVJBCallbacks) {
return window.WVJBCallbacks.push(callback);
}
window.WVJBCallbacks = [callback];
var WVJBIframe = document.createElement('iframe');
WVJBIframe.style.display = 'none';
WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
document.documentElement.appendChild(WVJBIframe);
setTimeout(function () {
document.documentElement.removeChild(WVJBIframe)
}, 0)
}else{}
}
//移动端交互
let appData = {};
var ua = navigator.userAgent,
android = ua.indexOf('Android') > -1 ? true : false,
ipad = ua.indexOf('iPad') > -1 ? true : false,
ipod = ua.indexOf('iPod') > -1 ? true : false,
iphone = !ipad && ua.indexOf('iPhone') > -1 ? true : false,
language = (navigator.browserLanguage || navigator.language).toLowerCase();
function getAppData() {
if (ipad || ipod || iphone) {
setupWebViewJavascriptBridge(function (bridge) {
bridge.callHandler('getToken', function (responseData) {
getUserInfo(responseData.token, responseData.i);
});
})
}else if(android){
setupWebViewJavascriptBridge(function (bridge) {
bridge.callHandler('getToken', '', function (responseData) {
getUserInfo(JSON.parse(responseData).token, JSON.parse(responseData).i);
});
})
}else{}
}
function goCp() {
if (ipad || ipod || iphone) {
setupWebViewJavascriptBridge(function (bridge) {
bridge.callHandler('jumpToCpSpace');
})
}else if(android){
setupWebViewJavascriptBridge(function (bridge) {
bridge.callHandler('jumpToCpSpace');
})
}else{}
}
let yourUrl = '';
//ajax调后台数据
function getUserInfo(token, i){
$.ajax({
url: yourUrl
type: 'POST',
data: { i: i },
dataType: 'json',
success: function (res) {
serverData = res.data;
let sp;
for(var key in serverData.memory){
sp = parseInt(key);
}
step = sp;//运动到第几个字母
img_mine.src = serverData.icon;//头像1
img_mycp.src = serverData.cpIcon;//头像2
drawWhiteLine();//画线
context.moveTo(startx, starty);//切换起始点
drawStep();//画路径
},
beforeSend: function (XMLHttpRequest) {
XMLHttpRequest.setRequestHeader('token', token);
XMLHttpRequest.setRequestHeader('source', 'h5');
XMLHttpRequest.setRequestHeader('lang', 'CHS');
},
error: function (err) {
console.log("err", JSON.stringify(err))
}
});
}
//按需运行方法
//getAppData();//正式方法
step = 7; //测试方法 自定义运行到第几个字母
drawWhiteLine(); //测试方法
context.moveTo(startx, starty);//测试方法
drawStep(); //测试方法
//todo:自定义头像、自定义每个子母被点亮时的日期
</script>
</body>
</html>
(此文原创,转载请注明出处)