Files
mama-box/demo/gch/v2.js

150 lines
8.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 首页「孕妈广场」效果稿 V2 · 广场人群:一块俯视的广场空地,十几位妈妈近大远小站着,3 位头上冒话题气泡轮换;
下方分类胶囊切换时人群换一批;右下角一个虚线「空位」是投稿入口。只在 ?gcv=2 时加载。 */
(function () {
var sec = document.getElementById('gcHome');
var ALL = window.GC_TOPICS;
if (!sec || !ALL || !ALL.length) return;
var esc = function (s) { return String(s).replace(/[&<>"']/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]; }); };
var fmt = function (n) { return n >= 1000 ? (n / 1000).toFixed(1).replace(/\.0$/, '') + 'k' : String(n); };
var go = function (id) { location.href = (id ? 'guangchang/?t=' + id : 'guangchang/') + location.hash; };
var CATS = [['', '全部'], ['family', '家庭婚姻'], ['work', '职场'], ['baby', '经验']];
var CATN = { family: '家庭婚姻', work: '职场', baby: '经验' };
var MOMS = [];
for (var i = 1; i <= 22; i++) MOMS.push('m' + (i < 10 ? '0' : '') + i);
for (i = 1; i <= 14; i++) MOMS.push('p' + (i < 10 ? '0' : '') + i);
var reduce = window.matchMedia && matchMedia('(prefers-reduced-motion: reduce)').matches;
/* 站位(x 为宽度百分比,y 为头像中心距空地顶 px,s 为直径):上远小、下近大;z 为气泡区 A 左上 / B 右上 / C 前排 */
var SLOTS = [
{ x: 9, y: 22, s: 24 }, { x: 33, y: 16, s: 22 }, { x: 54, y: 30, s: 26 }, { x: 76, y: 15, s: 22 },
{ x: 20, y: 74, s: 28 }, { x: 78, y: 82, s: 28 },
{ x: 11, y: 148, s: 40, z: 'A' }, { x: 36, y: 154, s: 40, z: 'A' }, { x: 63, y: 140, s: 40, z: 'B' }, { x: 88, y: 152, s: 40, z: 'B' },
{ x: 58, y: 222, s: 40 }, { x: 87, y: 212, s: 34 },
{ x: 12, y: 278, s: 50, z: 'C' }, { x: 35, y: 264, s: 48, z: 'C' }
];
var BW = 158, PAD = 5; // 气泡宽(按空地宽度再收窄)、离空地边距
var hash = function (s) { var x = 7; for (var k = 0; k < s.length; k++) x = (x * 31 + s.charCodeAt(k)) | 0; return Math.abs(x); };
var shuffle = function (arr, seed) { var a = arr.slice(), r = seed || 1; for (var k = a.length - 1; k > 0; k--) { r = (r * 9301 + 49297) % 233280; var j = Math.floor(r / 233280 * (k + 1)); var t = a[k]; a[k] = a[j]; a[j] = t; } return a; };
var cat = '', pool = [], qi = 0, faces = [], topicOf = [], speak = { A: -1, B: -1, C: -1 }, timer = 0, turn = 0, batch = 0;
sec.classList.add('gv2');
sec.classList.remove('hide');
sec.innerHTML =
'<div class="g2-head">' +
'<h2 class="g2-title"><span>孕妈广场</span></h2>' +
'<button type="button" class="g2-more" data-go="">去逛逛<i aria-hidden="true">›</i></button>' +
'</div>' +
'<div class="g2-sub"><i class="g2-live" aria-hidden="true"></i><b id="g2Cnt"></b> 位妈妈正在广场上聊<span class="g2-mark">效果稿 V2</span></div>' +
'<div class="g2-ground" id="g2Ground">' +
'<div class="g2-floor" aria-hidden="true"></div>' +
SLOTS.map(function (p, k) {
return '<button type="button" class="g2-mom' + (p.z ? ' near' : '') + '" data-k="' + k + '" style="left:' + p.x + '%;top:' + p.y + 'px;--s:' + p.s + 'px;--d:' + (2.6 + (k % 5) * 0.45).toFixed(2) + 's;--dl:-' + (k * 0.37 % 2.4).toFixed(2) + 's">' +
'<i class="g2-shadow" aria-hidden="true"></i><span class="g2-face"><img alt="" loading="lazy" decoding="async"></span></button>';
}).join('') +
'<div class="g2-bub" data-z="A"></div><div class="g2-bub" data-z="B"></div><div class="g2-bub" data-z="C"></div>' +
'<button type="button" class="g2-seat" data-go=""><span class="g2-seat-o">你</span><span class="g2-seat-t"><b>坐下来说说</b><em>¥30+500兜豆</em></span></button>' +
'</div>' +
'<div class="g2-foot">' +
'<div class="g2-cats" role="tablist" aria-label="话题分类">' +
CATS.map(function (c) { return '<button type="button" role="tab" data-cat="' + c[0] + '"' + (c[0] ? ' style="--ck:' + ({ family: '#E0566F', work: '#3A72B8', baby: '#2E8A7C' })[c[0]] + '"' : '') + '>' + c[1] + '</button>'; }).join('') +
'</div>' +
'</div>';
var ground = sec.querySelector('#g2Ground');
var moms = [].slice.call(sec.querySelectorAll('.g2-mom'));
var bubs = {}; [].forEach.call(sec.querySelectorAll('.g2-bub'), function (b) { bubs[b.getAttribute('data-z')] = b; });
function nextTopic() { var t = pool[qi % pool.length]; qi++; return t; }
function bubbleHTML(t) {
return '<span class="g2-bub-cat" style="color:' + t.ink + '">' + CATN[t.cat] + ' · ' + fmt(t.talk) + ' 在聊</span>' +
'<span class="g2-bub-t">' + esc(t.name) + '</span><i class="g2-tail" aria-hidden="true"></i>';
}
function place(z, k) {
var b = bubs[z], p = SLOTS[k], W = ground.clientWidth || 340, cx = W * p.x / 100;
BW = Math.min(158, Math.floor((W - PAD * 3) / 2));
b.style.width = BW + 'px';
var left = z === 'A' ? PAD : z === 'B' ? W - PAD - BW : Math.max(PAD, Math.min(W - PAD - BW, cx - BW / 2));
var t = topicOf[k];
b.innerHTML = bubbleHTML(t);
b.style.left = left + 'px';
b.style.bottom = (ground.clientHeight - (p.y - p.s / 2) + 7) + 'px';
b.style.setProperty('--tx', Math.max(14, Math.min(BW - 14, cx - left)) + 'px');
b.style.setProperty('--bc', t.c[1]);
b.style.setProperty('--bg', t.c[0]);
b.setAttribute('data-k', k);
b.setAttribute('role', 'button');
b.setAttribute('aria-label', t.name);
moms.forEach(function (m) { if (+m.getAttribute('data-k') === k) { m.classList.add('talk'); m.style.setProperty('--ring', t.ink); } });
}
function candidates(z) { var r = []; SLOTS.forEach(function (p, k) { if (p.z === z) r.push(k); }); return r; }
function rotate(z, first) {
var b = bubs[z], old = speak[z], c = candidates(z), k;
do { k = c[Math.floor(Math.random() * c.length)]; } while (c.length > 1 && k === old);
if (first) k = c[(batch + (z === 'B' ? 1 : 0)) % c.length];
var show = function () {
if (old >= 0) moms[old].classList.remove('talk');
topicOf[k] = nextTopic();
speak[z] = k;
place(z, k);
b.classList.add('on');
};
if (first || reduce) { show(); return; }
b.classList.remove('on');
setTimeout(show, 420);
}
function setCat(c, first) {
cat = c;
batch++;
pool = shuffle(ALL.filter(function (t) { return !c || t.cat === c; }), hash(c || 'all') + batch);
qi = 0;
var picks = shuffle(MOMS, hash('m' + c) + batch * 7);
[].forEach.call(sec.querySelectorAll('.g2-cats button'), function (b) { var on = b.getAttribute('data-cat') === c; b.classList.toggle('on', on); b.setAttribute('aria-selected', on ? 'true' : 'false'); });
sec.querySelector('#g2Cnt').textContent = pool.reduce(function (a, t) { return a + t.talk; }, 0).toLocaleString('en-US');
var apply = function () {
moms.forEach(function (m, k) {
faces[k] = picks[k % picks.length];
topicOf[k] = nextTopic();
m.querySelector('img').src = 'assets/img/mom/' + faces[k] + '.jpg';
m.classList.remove('talk');
m.setAttribute('aria-label', topicOf[k].name);
});
speak = { A: -1, B: -1, C: -1 };
['A', 'B', 'C'].forEach(function (z) { rotate(z, true); });
ground.classList.remove('swap');
};
if (first || reduce) { apply(); return; }
ground.classList.add('swap');
['A', 'B', 'C'].forEach(function (z) { bubs[z].classList.remove('on'); });
setTimeout(apply, 380);
}
function loop() {
clearInterval(timer);
if (reduce) return;
timer = setInterval(function () {
if (document.hidden) return;
rotate(['A', 'C', 'B'][turn++ % 3]);
}, 3200);
}
sec.addEventListener('click', function (e) {
var el = e.target.closest('[data-cat],[data-go],.g2-mom,.g2-bub');
if (!el || !sec.contains(el)) return;
if (el.hasAttribute('data-cat')) { var c = el.getAttribute('data-cat'); if (c !== cat) { setCat(c); loop(); } return; }
if (el.hasAttribute('data-go')) { go(''); return; }
var k = +el.getAttribute('data-k');
if (topicOf[k]) go(topicOf[k].id);
});
setCat('', true);
loop();
})();