Files
wordpress-theme-aksrt/assets/js/poster-share.js
T

200 lines
8.9 KiB
JavaScript

/**
* Reference-theme poster sharing runtime.
*
* @package AKSRT
*/
(function (window, document, $) {
'use strict';
var WIDTH = 768;
var HEIGHT = 1168;
var FONT = '-apple-system,BlinkMacSystemFont,"Segoe UI","Microsoft YaHei",Arial,sans-serif';
function notice(message, type) {
if (typeof window.notyf === 'function') window.notyf(message, type || '');
}
function ajaxUrl() {
return (window.aksrtData && window.aksrtData.ajaxUrl) || (window._win && window._win.ajax_url) || '';
}
function nonce() {
return (window.aksrtData && window.aksrtData.nonce) || '';
}
function loadImage(sources) {
sources = sources.filter(Boolean);
return new Promise(function (resolve, reject) {
var index = 0;
function next() {
if (index >= sources.length) { reject(new Error('image unavailable')); return; }
var image = new Image();
image.crossOrigin = 'anonymous';
image.onload = function () { resolve(image); };
image.onerror = function () { index += 1; next(); };
image.src = sources[index];
}
next();
});
}
function qrCodeDataUrl(text) {
return new Promise(function (resolve) {
if (!text || typeof window.tbquire !== 'function') { resolve(''); return; }
window.tbquire(['qrcode'], function () {
var host = $('<div>').css({ position: 'fixed', left: '-9999px', top: '-9999px' }).appendTo('body');
try {
host.qrcode({ width: 160, height: 160, correctLevel: 0, text: text, background: '#fff', foreground: '#333' });
var canvas = host.find('canvas').get(0);
resolve(canvas ? canvas.toDataURL('image/png') : '');
} catch (error) {
resolve('');
} finally {
host.remove();
}
});
});
}
function coverRect(boxWidth, boxHeight, sourceWidth, sourceHeight) {
var sx = 0, sy = 0, sw = sourceWidth, sh = sourceHeight;
if (sourceWidth / sourceHeight > boxWidth / boxHeight) {
sw = boxWidth * sourceHeight / boxHeight;
sx = (sourceWidth - sw) / 2;
} else {
sh = boxHeight * sourceWidth / boxWidth;
sy = (sourceHeight - sh) / 2;
}
return { sx: sx, sy: sy, sw: sw, sh: sh };
}
function containRect(x, y, boxWidth, boxHeight, sourceWidth, sourceHeight) {
var ratio = Math.min(boxWidth / sourceWidth, boxHeight / sourceHeight);
var width = sourceWidth * ratio;
var height = sourceHeight * ratio;
return { x: x + (boxWidth - width) / 2, y: y + (boxHeight - height) / 2, width: width, height: height };
}
function drawLines(ctx, text, maxWidth, maxRows, x, y, lineHeight) {
var chars = String(text || '').replace(/[\r\n]+/g, ' ').split('');
var rows = [], line = '';
chars.forEach(function (char) {
var next = line + char;
if (line && ctx.measureText(next).width > maxWidth) { rows.push(line); line = char; }
else line = next;
});
if (line) rows.push(line);
if (rows.length > maxRows) {
rows = rows.slice(0, maxRows);
while (rows[maxRows - 1] && ctx.measureText(rows[maxRows - 1] + '...').width > maxWidth) {
rows[maxRows - 1] = rows[maxRows - 1].slice(0, -1);
}
rows[maxRows - 1] += '...';
}
rows.forEach(function (row, index) { ctx.fillText(row, x, y + index * lineHeight); });
}
function renderPoster(data) {
return Promise.all([
loadImage([data.banner, data.banner_default, data.banner_spare]),
data.logo ? loadImage([data.logo]).catch(function () { return null; }) : Promise.resolve(null),
qrCodeDataUrl(data.url).then(function (src) { return src ? loadImage([src]).catch(function () { return null; }) : null; })
]).then(function (assets) {
var banner = assets[0], logo = assets[1], qr = assets[2];
var canvas = document.createElement('canvas');
canvas.width = WIDTH; canvas.height = HEIGHT;
var ctx = canvas.getContext('2d');
var imageHeight = HEIGHT / 2;
ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, WIDTH, HEIGHT);
var crop = coverRect(WIDTH, imageHeight, banner.width, banner.height);
ctx.drawImage(banner, crop.sx, crop.sy, crop.sw, crop.sh, 0, 0, WIDTH, imageHeight);
var now = new Date();
ctx.fillStyle = '#fff'; ctx.font = '35px ' + FONT; ctx.fillText('周' + '日一二三四五六'.charAt(now.getDay()), 30, 70);
ctx.font = '28px ' + FONT; ctx.fillText((now.getMonth() + 1) + ' / ' + now.getDate(), 30, 115);
ctx.strokeStyle = '#00a1ff'; ctx.lineWidth = 7; ctx.lineCap = 'round'; ctx.beginPath();
ctx.moveTo(40, imageHeight + 38); ctx.lineTo(40, imageHeight + 74); ctx.stroke();
ctx.fillStyle = '#424242'; ctx.font = 'bold 35px ' + FONT;
drawLines(ctx, data.title, WIDTH - 120, 2, 58, imageHeight + 68, 52);
ctx.fillStyle = '#fc4e1f'; ctx.font = '24px ' + FONT;
drawLines(ctx, data.tags, WIDTH - 80, 1, 40, imageHeight + 172, 36);
ctx.fillStyle = '#585858'; ctx.font = '25px ' + FONT;
drawLines(ctx, data.content, WIDTH - 80, 4, 40, imageHeight + 232, 39);
ctx.strokeStyle = 'rgba(122,122,122,.2)'; ctx.lineWidth = 2; ctx.strokeRect(30, HEIGHT - 230, WIDTH - 60, 200);
if (logo) {
var logoRect = containRect(80, HEIGHT - 190, 300, 100, logo.width, logo.height);
ctx.drawImage(logo, logoRect.x, logoRect.y, logoRect.width, logoRect.height);
}
if (qr) ctx.drawImage(qr, WIDTH - 200, HEIGHT - 200, 120, 120);
ctx.fillStyle = '#b4b4b4'; ctx.font = '22px ' + FONT; ctx.textAlign = 'center';
ctx.fillText(data.description || '扫一扫 立即查看', WIDTH / 2, HEIGHT - 52);
return canvas.toDataURL('image/png');
});
}
function modalId(postId) { return 'modal_poster_' + postId; }
function createModal(postId) {
var id = modalId(postId);
var html = '<div class="modal fade flex jc" id="' + id + '" tabindex="-1" role="dialog" aria-hidden="true">' +
'<div class="modal-dialog poster-share hover-show" role="document"><div class="modal-content" style="height:220px;overflow:hidden">' +
'<div class="poster-imgbox hover-show"></div><div class="flex jc loading-mask absolute main-bg radius8">' +
'<div class="loading zts fa-2x"></div><div class="muted-2-color box-body">正在生成图片,请稍候...</div></div></div>' +
'<div class="padding-6 abs-center hover-show-con text-center poster-share-actions" style="top:auto">' +
'<a href="#" class="but cir jb-blue poster-download hide"><i class="fa fas fa-download" aria-hidden="true"></i></a>' +
'<button type="button" data-dismiss="modal" class="but cir jb-yellow ml10"><svg aria-hidden="true" class="icon em12"><use xlink:href="#icon-close"></use></svg></button>' +
'</div></div></div>';
$('body').append(html);
return $('#' + id);
}
function showPoster($modal, postId, src) {
var $box = $modal.find('.poster-imgbox').empty().append($('<img>', { src: src, alt: '分享海报', class: 'loaded-img' })).addClass('loaded');
$modal.find('.poster-download').attr({ href: src, download: 'poster_' + postId + '.png' }).removeClass('hide');
$modal.find('.loading-mask').fadeOut(160);
$modal.find('.modal-content').css({ height: $box.outerHeight(), transition: '.2s' });
window.setTimeout(function () { $modal.find('.modal-content').css({ height: '', overflow: '', transition: '' }); }, 220);
}
function requestPoster($trigger, postId, $modal) {
$.ajax({
type: 'POST', url: ajaxUrl(), dataType: 'json',
data: { action: 'aksrt_poster_share_data', id: postId, nonce: nonce() }
}).done(function (response) {
if (!response || !response.success || !response.data) {
notice((response && response.data && response.data.message) || '海报数据加载失败', 'danger');
$modal.modal('hide');
$modal.remove();
return;
}
renderPoster(response.data).then(function (src) { showPoster($modal, postId, src); }).catch(function () {
notice('海报加载失败,请检查图片跨域设置', 'danger');
$modal.modal('hide');
$modal.remove();
});
}).fail(function (xhr) {
var message = xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message;
notice(message || '海报数据加载失败', 'danger');
$modal.modal('hide');
}).always(function () { $trigger.removeAttr('disabled'); });
}
$('body').off('click.aksrtPosterShare', '[poster-share]').on('click.aksrtPosterShare', '[poster-share]', function (event) {
event.preventDefault();
var $trigger = $(this);
var postId = parseInt($trigger.attr('poster-share'), 10) || 0;
if (!postId || $trigger.attr('disabled')) return;
var $modal = $('#' + modalId(postId));
if ($modal.length) { $modal.modal('show'); return; }
$trigger.attr('disabled', 'disabled');
$('.modal').modal('hide');
$modal = createModal(postId);
$modal.modal('show');
requestPoster($trigger, postId, $modal);
});
})(window, document, window.jQuery);