原生js实现三维可拖动旋转的卡通地球效果代码
代码语言:html
所属分类:三维
代码描述:原生js实现三维可拖动旋转的卡通地球效果代码,纯原生js编写,没有使用three引擎。
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Pirata+One&display=block'>
<style>
body { margin: 0; background-color: #f7f6f2; overflow: hidden;}.container { display: flex; justify-content: center; max-height: 100vmin; max-width: 100vmin; margin: 0 auto;}.globe { height: 100vmin; width: auto; cursor: -webkit-grab; cursor: grab;}.globe--dragging { cursor: -webkit-grabbing; cursor: grabbing;}
</style>
</head>
<body>
<!-- partial:index.partial.html -->
<div class="container"><canvas class="globe" width="1800" height="1600"></canvas></div>
<!-- partial -->
<script>
const markers = [{
name: 'Uluru',
lat: -25,
long: 131
},
{
name: 'Machu Picchu',
lat: -13,
long: -70
},
{
name: 'Valley of the Kings',
lat: 25,
long: 32
},
{
name: 'Stonehenge',
lat: 51,
long: -2
}];
const $ = {
canvas: null,
ctx: null,
vCenter: 820,
scroll: {
lat: 0,
long: 20
},
markers: [],
timing: {
speed: 16,
delta: 0,
last: 0
},
drag: {
start: { x: 0, y: 0 },
force: 0,
prevX: 0,
isDragging: false
},
colors: {
pushPinBase: '#969799',
pushPin: '#ed5c50',
land: '#fac648', //'#ffc975',
landShade: '#2c606e',
ocean: '#2A7B96'
},
complexShapes: {
// put complex shapes here
}
}
const lerp = (norm, min, max) => {
return (max - min) * norm + min;
}
const norm = (value, min, max) => {
return (value - min) / (max - min);
}
const map = (value, sourceMin, sourceMax, destMin, destMax) => {
return lerp(norm(value, sourceMin, sourceMax), destMin, destMax);
}
const dragMove = (e) => {
if($.drag.isDragging) {
let long = $.drag.start.long,
clientX = e.targetTouches ? e.targetTouches[0].clientX : e.clientX,
change = clientX - $.drag.start.x,
prevChange = clientX - $.drag.prevX,
canvasWidth = $.canvas.getBoundingClientRect().width;
long += map(change, 0, canvasWidth, 0, 200);
while(long < 0) {
long += 360;
}
if(prevChange > 0 && $.drag.force < 0) {
$.drag.force = 0;
} else if(prevChange < 0 && $.drag.force > 0) {
$.drag.force = 0;
}
$.drag.force += prevChange * (600 / canvasWidth);
$.drag.prevX = clientX;
$.scroll.long = Math.abs(long) % 360;
}
}
const dragStart = (e) => {
if (e.targetTouches) {
e.preventDefault();
$.drag.start = {
x: e.targetTouches[0].clientX,
y: e.targetTouches[0].clientY,
long: $.scroll.long
};
} else {
$.drag.start = {
x: e.clientX,
y: e.clientY,
long: $.scroll.long
};
}
$.timing.speed = 0;
$.drag.isDragging = true;
$.canvas.classList.add('globe--dragging');
}
const dragEnd = (e) => {
if($.drag.isDragging) {
$.timing.speed = map($.drag.force, 0, 220, 0, 40);
$.drag.isDragging = false;
$.canvas.classList.remove('globe--dragging');
}
}
const getRadius = (latitude) => {
let yPart = Math.PI*2,
radius = 600,
frame = map(latitude, 90, -90, 0, 1.65);
return Math.max(Math.sin(yPart + frame) * radius, 0);
}
const latLongSphere = (lat, lon, radius) => {
let x = 900,
y = $.vCenter,
z = 0;
lon = -lon;
let phi = (90-lat) * (Math.PI/180),
teta = (lon + 180) * (Math.PI/180);
x -= -(radius * Math.sin(phi) * Math.cos(teta));
y -= radius * Math.cos(phi);
z = radius * Math.sin(phi) * Math.sin(teta);
return {
x, y, z
};
}
const drawGlobe = (ctx, color) => {
ctx.beginPath();
ctx.arc(900, $.vCenter, 600, 0, 2 * Math.PI);
ctx.closePath();
ctx.fillStyle = color;
ctx.fill();
}
const getLandMassPaths = (name, radius, thickness) => {
let landmassBasic = continents[name],
landmass = null,
first = true,
rotated = false,
paths = {
ground: new Path2D(),
top: new Path2D(),
sections: [],
isVisible: false
},
section = {
ground: [],
top: []
};
// Complexify
if($.complexShapes[name]) {
landmass = $.complexShapes[name];
} else {
landmass = complexify(landmassBasic, 1);
$.complexShapes[name] = landmass;
}
for (let i = 0; i < landmass.length; i++) {
let point = landmass[0],
p = latLongSphere(point.lat + $.scroll.lat, point.long + $.scroll.long, radius);
if(p.z < 0) {
landmass.splice(0, 0, landmass.pop());
rotated = true;
} else {
break;
}
}
let drawCurve = false,
curveStart = null,
sectionIsVisible = false;
landmass.forEach((point) => {
let p = latLongSphere(point.lat + $.scroll.lat, point.long + $.scroll.long, radius),
p2 = latLongSphere(point.lat + $.scroll.lat, point.long + $.scroll.long, radius + thickness);
if(!sectionIsVisible && p.z > -200) {
sectionIsVisible = true;
}
section.ground.push({
x: p.x,
y: p.y,
z: p.z
});
section.top.push({
x: p2.x,
y: p2.y,
z: p2.z
});
if(point.edge && !first) {
if(sectionIsVisible) {
paths.sections.push(Object.assign({}, section));
}
section = {
ground: [{x: p.x, y: p.y, z: p.z }],
top: [{x: p2.x, y: p2.y, z: p2.z }]
};
sectionIsVisible = false;
}
first = false;
if(p.z > 0) {
if(drawCurve) {
drawCurve = false;
clo.........完整代码请登录后点击上方下载按钮下载查看
网友评论0