722 lines
30 KiB
Plaintext
722 lines
30 KiB
Plaintext
@page
|
||
@model IndexModel
|
||
@{
|
||
// ViewData["Title"] = "Home page";
|
||
Layout = null;
|
||
}
|
||
|
||
<!doctype html>
|
||
<html>
|
||
|
||
<head>
|
||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||
<script type="text/javascript" src="~/js/turn.min.js"></script>
|
||
<!-- 引入水波纹效果插件 -->
|
||
<script src="~/js/jquery.ripples.js"></script>
|
||
<!-- 引入SignalR客户端 -->
|
||
<script src="~/lib/microsoft-signalr/signalr.min.js"></script>
|
||
<style type="text/css">
|
||
/* 页面基础样式 */
|
||
body {
|
||
background: #ccc;
|
||
margin: 0;
|
||
padding: 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
align-items: center;
|
||
height: 100vh;
|
||
/* 设置高度为视口高度 */
|
||
overflow: hidden;
|
||
/* 防止页面滚动 */
|
||
}
|
||
|
||
/* 杂志容器样式 */
|
||
#magazine {
|
||
width: 100%;
|
||
height: 100vh;
|
||
margin: 0 auto;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 翻页效果的页面样式 */
|
||
#magazine .turn-page {
|
||
background-color: #ccc;
|
||
background-size: 100% 100%;
|
||
}
|
||
|
||
/* 文字倒影效果 */
|
||
.reflection-text {
|
||
-webkit-box-reflect: below 20px linear-gradient(transparent, rgba(0, 0, 0, 0.2));
|
||
}
|
||
|
||
.r-container-text {
|
||
font-size: 40px;
|
||
font-weight: 700;
|
||
font-style: italic;
|
||
text-align: left;
|
||
width: 70%;
|
||
}
|
||
|
||
/* 垂直文字容器样式 */
|
||
.vertical-text-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
width: 70%;
|
||
margin-left: 15%;
|
||
padding-top: 10%;
|
||
}
|
||
|
||
/* 文字样式 */
|
||
.vertical-text {
|
||
text-orientation: mixed;
|
||
font-size: 16px;
|
||
margin: 9px 0px;
|
||
color: #333;
|
||
font-weight: 400;
|
||
width: 100%;
|
||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.r-container {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
height: 90%;
|
||
width: 100%;
|
||
}
|
||
|
||
/* 设置奇数页的样式,包括页面右侧的阴影效果 */
|
||
#magazine .odd {
|
||
background-image: url(img/l.jpg);
|
||
background-size: 100% 100%;
|
||
}
|
||
|
||
/* 设置偶数页的样式,包括页面左侧的阴影效果 */
|
||
#magazine .even {
|
||
background-image: url(img/r.jpg);
|
||
background-size: 100% 100%;
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
<!-- 水波纹效果层 -->
|
||
<div class="water-effect"
|
||
style="background-color: transparent; background-size: 100% 100%;width: 100vw;height: 100vh;position: absolute;top: 0;left: 0; z-index: 999;">
|
||
</div>
|
||
|
||
<!-- 杂志内容容器 -->
|
||
<div id="magazine">
|
||
<!-- 封面 -->
|
||
<div id="bool_page_1" class="even"></div>
|
||
<!-- 第一页:文字内容,左侧文字 -->
|
||
<div id="bool_page_2" class="odd">
|
||
<div id="l_container_2" class="vertical-text-container">
|
||
</div>
|
||
</div>
|
||
<!-- 第二页:带倒影效果的文字,右侧文字 -->
|
||
<div id="bool_page_3" class="even">
|
||
<div class="r-container">
|
||
<div id="r_container_3" class="reflection-text r-container-text"></div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
<script type="text/javascript">
|
||
// 全局配置对象
|
||
const CONFIG = {
|
||
// 左侧容器配置
|
||
leftContainer: {
|
||
turnPageHeight: 0.55, // 左侧容器翻页的高度比例
|
||
fontSize: '16px', // 左侧列表文字大小
|
||
typewriterSpeed: 50 // 左侧文字打字机速度(毫秒)
|
||
},
|
||
// 右侧容器配置
|
||
rightContainer: {
|
||
fontSize: '40px', // 右侧文字大小
|
||
fontWeight: '700', // 右侧文字粗细
|
||
fontStyle: 'italic', // 右侧文字样式
|
||
typewriterSpeed: 2000, // 右侧文字打字机速度(毫秒),增加到2000毫秒
|
||
fadeChars: 4, // 渐变字符数量,值越大渐变效果越长
|
||
fadeStepTime: 500, // 字符透明度过渡时间(毫秒)
|
||
fadeDelayFactor: 0.25 // 每个字符的透明度递减因子(0-1)
|
||
},
|
||
// 水波纹效果配置
|
||
waterEffect: {
|
||
enabled: true, // 是否开启水波纹
|
||
minInterval: 1600, // 最小触发间隔(毫秒)
|
||
maxInterval: 8000, // 最大触发间隔(毫秒)
|
||
simultaneousDrops: 2, // 同时触发的波纹数量
|
||
fadeOutSpeed: 5000, // 文字渐隐效果的速度(毫秒),增加到5000毫秒
|
||
centerBias: 0.6, // 涟漪靠近中心区域的偏好值(0-1)
|
||
largeDrop: {
|
||
probability: 0.2, // 大涟漪出现的概率
|
||
size: 80 // 大涟漪的大小
|
||
}
|
||
},
|
||
|
||
};
|
||
|
||
let currentSentenceIndex = 0; // 当前句子索引
|
||
let isAnimating = false; // 动画状态标志
|
||
// 设置总页数为1000页,实际上是循环使用有限的内容
|
||
var numberOfPages = 11;
|
||
|
||
/**
|
||
* 检查文字容器是否需要翻页
|
||
* @@param {string} containerSelector - 容器选择器
|
||
* @@returns {boolean} - 是否需要翻页
|
||
*/
|
||
function checkNeedTurnPage(containerSelector) {
|
||
const container = $(containerSelector);
|
||
const containerHeight = container.height();
|
||
const parentHeight = container.parent().height();
|
||
return (containerHeight > parentHeight * CONFIG.leftContainer.turnPageHeight);
|
||
}
|
||
|
||
/**
|
||
* 文字渐隐效果
|
||
* @@param {string} selector - 目标元素选择器
|
||
* @@param {Function} callback - 渐隐完成后的回调函数
|
||
*/
|
||
function fadeOutText(selector, callback) {
|
||
$(selector).fadeOut(CONFIG.waterEffect.fadeOutSpeed, function () {
|
||
$(this).html('');
|
||
$(this).show();
|
||
if (callback) callback();
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 打字机效果函数(带渐显)
|
||
* @@param {string} selector - 目标元素选择器
|
||
* @@param {string} text - 要显示的文本
|
||
* @@param {number} speed - 打字速度(毫秒)
|
||
* @@param {Function} callback - 完成后的回调函数
|
||
*/
|
||
function typewriterEffect(selector, text, speed, callback) {
|
||
if (isAnimating) return;
|
||
isAnimating = true;
|
||
|
||
// 获取渐变相关配置
|
||
const fadeChars = CONFIG.rightContainer.fadeChars || 4; // 渐变字符数量
|
||
const fadeStepTime = CONFIG.rightContainer.fadeStepTime || 500; // 过渡时间
|
||
const fadeDelayFactor = CONFIG.rightContainer.fadeDelayFactor || 0.25; // 透明度递减因子
|
||
|
||
// 清空容器并设置初始可见度
|
||
$(selector).html('').css('opacity', 1);
|
||
|
||
// 创建所有字符元素,但初始透明度为0
|
||
for (let i = 0; i < text.length; i++) {
|
||
const charSpan = $('<span></span>').text(text.charAt(i));
|
||
charSpan.css({
|
||
'opacity': 0,
|
||
'display': 'inline-block', // 确保每个字符是独立的块
|
||
'transition': `opacity ${fadeStepTime}ms ease-in-out` // 平滑的透明度过渡效果
|
||
});
|
||
$(selector).append(charSpan);
|
||
}
|
||
|
||
// 获取所有字符span元素
|
||
const chars = $(selector).find('span');
|
||
const totalChars = chars.length;
|
||
|
||
// 设置初始不透明度,形成从左到右的渐变效果
|
||
// 左侧字符较深,右侧字符较浅
|
||
const setInitialOpacity = () => {
|
||
for (let i = 0; i < totalChars; i++) {
|
||
// 计算不透明度:第一个字符不透明度最高,往后逐渐降低
|
||
let position = i / totalChars; // 字符在文本中的相对位置 (0-1)
|
||
let opacity = Math.max(0, 0.8 - (position * fadeChars * 0.2));
|
||
|
||
// 超出可见范围的字符完全透明
|
||
if (i >= fadeChars) {
|
||
opacity = 0;
|
||
}
|
||
|
||
// 设置不透明度
|
||
$(chars[i]).css('opacity', opacity);
|
||
}
|
||
};
|
||
|
||
// 执行渐变动画
|
||
const animateText = () => {
|
||
let progress = 0;
|
||
|
||
const step = () => {
|
||
if (progress >= 1) {
|
||
// 完成动画
|
||
chars.css('opacity', 1);
|
||
isAnimating = false;
|
||
if (callback) callback();
|
||
|
||
// 等待随机4-7秒后请求下一条文本
|
||
const delay = Math.floor(Math.random() * 3000) + 4000; // 4000-7000毫秒
|
||
console.log(`文本显示完成,将在${delay/1000}秒后请求下一条文本`);
|
||
setTimeout(requestNextText, delay);
|
||
return;
|
||
}
|
||
|
||
// 更新每个字符的透明度
|
||
for (let i = 0; i < totalChars; i++) {
|
||
let targetOpacity = 1; // 目标不透明度(完全显示)
|
||
let currentPosition = i / totalChars; // 字符的相对位置
|
||
|
||
// 计算当前动画进度下该位置的字符应有的透明度
|
||
// 小于当前进度的字符应该更不透明
|
||
let opacity = targetOpacity * Math.max(0, 1 - Math.max(0, (currentPosition - progress) * 3));
|
||
|
||
// 设置不透明度
|
||
$(chars[i]).css('opacity', opacity);
|
||
}
|
||
|
||
// 增加进度
|
||
progress += 0.02;
|
||
|
||
// 继续下一步动画
|
||
setTimeout(step, speed / 50);
|
||
};
|
||
|
||
// 开始动画
|
||
step();
|
||
};
|
||
|
||
// 设置初始不透明度并开始动画
|
||
setInitialOpacity();
|
||
setTimeout(animateText, 50);
|
||
}
|
||
|
||
/**
|
||
* 添加文字到左侧历史记录
|
||
* @@param {string} text - 要添加的文字
|
||
*/
|
||
function addToHistory(text, id) {
|
||
// 检查是否需要翻页
|
||
if (checkNeedTurnPage(id)) {
|
||
let currentPage = $("#magazine").turn("page");
|
||
if (numberOfPages <= currentPage + 1) {
|
||
//说明页数已经到最后一页了,跳转到之前页面
|
||
$('#magazine').turn('page', 2);
|
||
} else {
|
||
// 执行翻页
|
||
$('#magazine').turn('next');
|
||
}
|
||
|
||
console.log(currentPage, '翻页后');
|
||
|
||
let l_id = '#l_container_' + (currentPage);
|
||
setTimeout(() => {
|
||
let currentPage1 = $("#magazine").turn("page");
|
||
let l_id = '#l_container_' + (currentPage1);
|
||
addToHistory(text, l_id);
|
||
//把之前的页面清空掉
|
||
$('#l_container_' + (currentPage1 - 2)).html('');
|
||
$('#r_container_' + (currentPage1 - 1)).html('');
|
||
console.log('#r_container_' + (currentPage1 - 1), $('#r_container_' + (currentPage1 - 1)));
|
||
}, 600); // 增加延时以配合更慢的翻页速度
|
||
return false;
|
||
}
|
||
const container = $(id);
|
||
// 创建新的段落元素
|
||
const newP = $('<p class="vertical-text"></p>');
|
||
// 将新段落添加到容器的末尾(而不是开头)
|
||
container.append(newP);
|
||
|
||
// 设置初始透明度为0
|
||
newP.css('opacity', 0);
|
||
// 设置文本内容
|
||
newP.text(text);
|
||
// 整条文字渐显效果
|
||
newP.animate(
|
||
{ opacity: 1 },
|
||
2000, // 设置动画时长为2秒
|
||
'swing'
|
||
);
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 显示用户说话内容
|
||
* @@param {string} text - 用户说话内容
|
||
*/
|
||
function displayText(text) {
|
||
if (isAnimating) return;
|
||
|
||
var currentPage = $("#magazine").turn("page");
|
||
let r_id = '#r_container_' + (currentPage + 1);
|
||
let l_id = '#l_container_' + (currentPage);
|
||
const rightText = $(r_id);
|
||
|
||
// 如果右侧已有文字,先淡出
|
||
if (rightText.text()) {
|
||
const originalText = rightText.text(); // 保存原文字
|
||
fadeOutText(r_id, function () {
|
||
// 将原文字添加到历史
|
||
let s = addToHistory(originalText, l_id);
|
||
if (s) {
|
||
typewriterEffect(r_id, text, CONFIG.rightContainer.typewriterSpeed);
|
||
} else {
|
||
setTimeout(() => {
|
||
displayText(text);
|
||
}, 500);
|
||
}
|
||
});
|
||
} else {
|
||
// 直接显示新文字
|
||
typewriterEffect(r_id, text, CONFIG.rightContainer.typewriterSpeed);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 添加页面到书本中的函数
|
||
* @@param {number} page - 页码
|
||
* @@param {object} book - 书本对象
|
||
*/
|
||
function addPage(page, book) {
|
||
// 首先检查页面是否已经在书本中
|
||
if (!book.turn('hasPage', page)) {
|
||
let page_type = page % 2;
|
||
let element = null;
|
||
if (page_type == 0) {
|
||
element = $('<div />', { 'class': 'page odd', 'id': 'bool_page_' + page })
|
||
.html('<div id="l_container_' + page + '" class="vertical-text-container"></div>'); // 添加空的内容区域
|
||
} else {
|
||
element = $('<div />', { 'class': 'page even', 'id': 'bool_page_' + page })
|
||
.html('<div class="r-container"><div id="r_container_' + page + '" class="reflection-text r-container-text"></div></div>'); // 添加空的内容区域
|
||
}
|
||
// 将页面添加到书本中
|
||
book.turn('addPage', element, page);
|
||
}
|
||
}
|
||
|
||
// SignalR连接变量
|
||
let hubConnection;
|
||
|
||
// 初始化SignalR连接
|
||
function initializeSignalRConnection() {
|
||
// 创建连接
|
||
hubConnection = new signalR.HubConnectionBuilder()
|
||
.withUrl("/audioHub")
|
||
.withAutomaticReconnect()
|
||
.build();
|
||
|
||
// 接收显示文本的处理函数
|
||
hubConnection.on("ReceiveDisplayText", function (text) {
|
||
console.log("收到显示文本:", text);
|
||
displayText(text);
|
||
});
|
||
|
||
// 接收显示配置的处理函数
|
||
hubConnection.on("ReceiveDisplayConfig", function (configJson) {
|
||
console.log("收到显示配置");
|
||
try {
|
||
const newConfig = JSON.parse(configJson);
|
||
// 更新全局配置
|
||
updateConfig(newConfig);
|
||
console.log("已更新显示配置");
|
||
} catch (error) {
|
||
console.error("解析显示配置失败:", error);
|
||
}
|
||
});
|
||
|
||
// 启动连接
|
||
hubConnection.start()
|
||
.then(function () {
|
||
console.log("SignalR连接成功");
|
||
// 注册为显示客户端
|
||
hubConnection.invoke("RegisterClient", 3, "Display")
|
||
.then(function() {
|
||
console.log("注册为显示客户端成功");
|
||
// 获取显示配置
|
||
return hubConnection.invoke("GetDisplayConfig");
|
||
})
|
||
.then(function(configJson) {
|
||
if(configJson) {
|
||
console.log("已获取显示配置");
|
||
try {
|
||
const config = JSON.parse(configJson);
|
||
updateConfig(config);
|
||
} catch (error) {
|
||
console.error("解析显示配置失败:", error);
|
||
}
|
||
}
|
||
// 开始请求第一条显示文本
|
||
requestNextText();
|
||
})
|
||
.catch(function(err) {
|
||
console.error("客户端操作失败:", err);
|
||
});
|
||
})
|
||
.catch(function (err) {
|
||
console.error("SignalR连接失败:", err);
|
||
// 5秒后重试
|
||
setTimeout(initializeSignalRConnection, 5000);
|
||
});
|
||
|
||
// 连接关闭的处理
|
||
hubConnection.onclose(function() {
|
||
console.log("SignalR连接已关闭,尝试重新连接...");
|
||
setTimeout(initializeSignalRConnection, 5000);
|
||
});
|
||
}
|
||
|
||
// 更新配置
|
||
function updateConfig(newConfig) {
|
||
// 更新左侧容器配置
|
||
if (newConfig.leftContainer) {
|
||
CONFIG.leftContainer.turnPageHeight = newConfig.leftContainer.turnPageHeight || CONFIG.leftContainer.turnPageHeight;
|
||
CONFIG.leftContainer.fontSize = newConfig.leftContainer.fontSize || CONFIG.leftContainer.fontSize;
|
||
CONFIG.leftContainer.typewriterSpeed = newConfig.leftContainer.typewriterSpeed || CONFIG.leftContainer.typewriterSpeed;
|
||
|
||
// 应用字体大小到CSS
|
||
document.documentElement.style.setProperty('--left-font-size', CONFIG.leftContainer.fontSize);
|
||
}
|
||
|
||
// 更新右侧容器配置
|
||
if (newConfig.rightContainer) {
|
||
CONFIG.rightContainer.fontSize = newConfig.rightContainer.fontSize || CONFIG.rightContainer.fontSize;
|
||
CONFIG.rightContainer.fontWeight = newConfig.rightContainer.fontWeight || CONFIG.rightContainer.fontWeight;
|
||
CONFIG.rightContainer.fontStyle = newConfig.rightContainer.fontStyle || CONFIG.rightContainer.fontStyle;
|
||
CONFIG.rightContainer.typewriterSpeed = newConfig.rightContainer.typewriterSpeed || CONFIG.rightContainer.typewriterSpeed;
|
||
|
||
// 更新渐显效果相关的配置
|
||
if (newConfig.rightContainer.fadeChars !== undefined) {
|
||
CONFIG.rightContainer.fadeChars = newConfig.rightContainer.fadeChars;
|
||
}
|
||
if (newConfig.rightContainer.fadeStepTime !== undefined) {
|
||
CONFIG.rightContainer.fadeStepTime = newConfig.rightContainer.fadeStepTime;
|
||
}
|
||
if (newConfig.rightContainer.fadeDelayFactor !== undefined) {
|
||
CONFIG.rightContainer.fadeDelayFactor = newConfig.rightContainer.fadeDelayFactor;
|
||
}
|
||
|
||
// 应用到CSS
|
||
document.documentElement.style.setProperty('--right-font-size', CONFIG.rightContainer.fontSize);
|
||
document.documentElement.style.setProperty('--right-font-weight', CONFIG.rightContainer.fontWeight);
|
||
document.documentElement.style.setProperty('--right-font-style', CONFIG.rightContainer.fontStyle);
|
||
}
|
||
|
||
// 更新水波纹效果配置
|
||
if (newConfig.waterEffect) {
|
||
CONFIG.waterEffect.enabled = newConfig.waterEffect.enabled !== undefined ? newConfig.waterEffect.enabled : CONFIG.waterEffect.enabled;
|
||
CONFIG.waterEffect.minInterval = newConfig.waterEffect.minInterval || CONFIG.waterEffect.minInterval;
|
||
CONFIG.waterEffect.maxInterval = newConfig.waterEffect.maxInterval || CONFIG.waterEffect.maxInterval;
|
||
CONFIG.waterEffect.simultaneousDrops = newConfig.waterEffect.simultaneousDrops || CONFIG.waterEffect.simultaneousDrops;
|
||
CONFIG.waterEffect.fadeOutSpeed = newConfig.waterEffect.fadeOutSpeed || CONFIG.waterEffect.fadeOutSpeed;
|
||
CONFIG.waterEffect.centerBias = newConfig.waterEffect.centerBias !== undefined ? newConfig.waterEffect.centerBias : CONFIG.waterEffect.centerBias;
|
||
|
||
if (newConfig.waterEffect.largeDrop) {
|
||
CONFIG.waterEffect.largeDrop.probability = newConfig.waterEffect.largeDrop.probability !== undefined ?
|
||
newConfig.waterEffect.largeDrop.probability : CONFIG.waterEffect.largeDrop.probability;
|
||
CONFIG.waterEffect.largeDrop.size = newConfig.waterEffect.largeDrop.size || CONFIG.waterEffect.largeDrop.size;
|
||
}
|
||
|
||
// 应用水波纹效果配置
|
||
if ($('.water-effect').data('ripples')) {
|
||
// 如果ripples已初始化,先销毁
|
||
$('.water-effect').ripples('destroy');
|
||
}
|
||
|
||
if (CONFIG.waterEffect.enabled) {
|
||
$('.water-effect').show();
|
||
$('.water-effect').ripples({
|
||
resolution: 1024,
|
||
dropRadius: 1.5,
|
||
perturbance: 0
|
||
});
|
||
} else {
|
||
$('.water-effect').hide();
|
||
}
|
||
}
|
||
|
||
console.log("配置已更新:", CONFIG);
|
||
}
|
||
|
||
// 页面加载完成后初始化
|
||
$(window).ready(function () {
|
||
$('#magazine').turn({
|
||
display: 'double',
|
||
acceleration: true,
|
||
pages: numberOfPages,
|
||
gradients: !$.isTouch,
|
||
elevation: 50,
|
||
duration: 2000, // 增加翻页动画时长到2000毫秒(原来的两倍)
|
||
when: {
|
||
// 翻页过程中的回调函数
|
||
turning: function (e, page, view) {
|
||
// 获取当前需要的页面范围
|
||
var range = $(this).turn('range', page);
|
||
console.log('当前页码:', range);
|
||
// 确保页面范围内的每一页都被添加到书本中
|
||
for (page = range[0]; page <= range[1]; page++) {
|
||
addPage(page, $(this));
|
||
// console.log('需要有的页码:', page);
|
||
}
|
||
},
|
||
turned: function (e, page) {
|
||
console.log('当前页码:', page);
|
||
}
|
||
}
|
||
});
|
||
|
||
// 清空左侧初始文字
|
||
$('.vertical-text-container').html('');
|
||
|
||
// 设置初始页面
|
||
$('#magazine').turn('page', 2);
|
||
|
||
// 初始化SignalR连接
|
||
initializeSignalRConnection();
|
||
|
||
// 不再需要模拟定时说话
|
||
// setInterval(simulateUserSpeak, 3000);
|
||
});
|
||
|
||
// 绑定键盘事件
|
||
$(window).bind('keydown', function (e) {
|
||
if (e.keyCode == 37)
|
||
$('#magazine').turn('previous');
|
||
else if (e.keyCode == 39)
|
||
$('#magazine').turn('next');
|
||
// 空格键请求下一条文本
|
||
else if (e.keyCode == 32) {
|
||
requestNextText();
|
||
}
|
||
});
|
||
|
||
// 初始化页面效果
|
||
$(function () {
|
||
// 设置CSS变量
|
||
document.documentElement.style.setProperty('--left-font-size', CONFIG.leftContainer.fontSize);
|
||
document.documentElement.style.setProperty('--right-font-size', CONFIG.rightContainer.fontSize);
|
||
document.documentElement.style.setProperty('--right-font-weight', CONFIG.rightContainer.fontWeight);
|
||
document.documentElement.style.setProperty('--right-font-style', CONFIG.rightContainer.fontStyle);
|
||
|
||
if (!CONFIG.waterEffect.enabled) {
|
||
$('.water-effect').hide();
|
||
} else {
|
||
$('.water-effect').ripples({
|
||
resolution: 1024,
|
||
dropRadius: 1.5,
|
||
perturbance: 0
|
||
});
|
||
|
||
/**
|
||
* 创建单个水波纹定时器
|
||
* @@returns {Function} 定时器函数
|
||
*/
|
||
function createRippleTimer() {
|
||
return function randomRipple() {
|
||
let width = $(".water-effect").width();
|
||
let height = $(".water-effect").height();
|
||
|
||
// 中心坐标
|
||
let centerX = width / 2;
|
||
let centerY = height / 2;
|
||
|
||
// 根据中心偏好生成随机位置
|
||
let randomX, randomY;
|
||
|
||
if (Math.random() > CONFIG.waterEffect.centerBias) {
|
||
// 随机位置
|
||
randomX = Math.random() * width;
|
||
randomY = Math.random() * height;
|
||
|
||
// 避免位于上1/3区域
|
||
if (randomY < height / 3) {
|
||
randomY += height / 3;
|
||
}
|
||
} else {
|
||
// 靠近中心位置
|
||
let radius = Math.min(width, height) * 0.3; // 中心区域半径
|
||
let angle = Math.random() * Math.PI * 2; // 随机角度
|
||
let distance = Math.random() * radius; // 随机距离,但不超过radius
|
||
|
||
randomX = centerX + Math.cos(angle) * distance;
|
||
randomY = centerY + Math.sin(angle) * distance;
|
||
}
|
||
|
||
// 决定是否创建大涟漪
|
||
let dropSize = Math.random() < CONFIG.waterEffect.largeDrop.probability ?
|
||
CONFIG.waterEffect.largeDrop.size : 50;
|
||
|
||
triggerRipple(".water-effect", randomX, randomY, dropSize);
|
||
|
||
let nextTime = Math.random() * (CONFIG.waterEffect.maxInterval - CONFIG.waterEffect.minInterval) + CONFIG.waterEffect.minInterval;
|
||
setTimeout(randomRipple, nextTime);
|
||
};
|
||
}
|
||
|
||
// 创建多个水波纹定时器
|
||
for (let i = 0; i < CONFIG.waterEffect.simultaneousDrops; i++) {
|
||
const rippleTimer = createRippleTimer();
|
||
rippleTimer();
|
||
}
|
||
}
|
||
|
||
// 延迟2秒后开始打字机效果
|
||
// setTimeout(() => {
|
||
// typewriterEffect('#r_container_3', '记得每到夏天傍晚,您就摇看蒲扇坐在藤椅里,把切好的西瓜最甜那块硬塞给我。', 100);
|
||
// }, 2000);
|
||
});
|
||
|
||
/**
|
||
* 触发水波纹效果
|
||
* @@param {string} selector - 目标元素选择器
|
||
* @@param {number} x - X坐标
|
||
* @@param {number} y - Y坐标
|
||
* @@param {number} size - 涟漪大小
|
||
*/
|
||
function triggerRipple(selector, x, y, size = 50) {
|
||
$(selector).ripples("drop", x, y, size, 0.15);
|
||
}
|
||
|
||
// 页面可见性变化检测,用于处理页面切换到后台时暂停涟漪效果
|
||
document.addEventListener('visibilitychange', function() {
|
||
if (document.hidden) {
|
||
// 页面不可见时,停止涟漪生成
|
||
console.log("页面切换到后台,停止涟漪生成");
|
||
// 可以添加额外逻辑来暂停或减少涟漪效果
|
||
} else {
|
||
// 页面可见时,可以恢复涟漪生成
|
||
console.log("页面回到前台,继续涟漪生成");
|
||
// 可以添加额外逻辑来恢复涟漪效果
|
||
|
||
// 如果需要,可以重置涟漪效果
|
||
if (CONFIG.waterEffect.enabled) {
|
||
$('.water-effect').ripples("destroy");
|
||
$('.water-effect').ripples({
|
||
resolution: 1024,
|
||
dropRadius: 1.5,
|
||
perturbance: 0
|
||
});
|
||
}
|
||
}
|
||
});
|
||
|
||
/**
|
||
* 请求下一条文本
|
||
*/
|
||
function requestNextText() {
|
||
if (hubConnection && hubConnection.state === signalR.HubConnectionState.Connected) {
|
||
console.log("正在向服务器请求下一条文本...");
|
||
hubConnection.invoke("GetNextDisplayText")
|
||
.catch(function(err) {
|
||
console.error("请求下一条文本失败:", err);
|
||
// 如果请求失败,稍后重试
|
||
setTimeout(requestNextText, 5000);
|
||
});
|
||
} else {
|
||
console.warn("SignalR连接未就绪,无法请求下一条文本");
|
||
// 如果连接未就绪,稍后重试
|
||
setTimeout(requestNextText, 3000);
|
||
}
|
||
}
|
||
</script>
|
||
</body>
|
||
|
||
</html> |