Add Actions

增加交互功能啦!你可以让你的看板娘提示一些更有趣的内容了~
This commit is contained in:
奇趣保罗 2018-10-12 15:51:33 +08:00
parent baf40e2aec
commit a125927adf
5 changed files with 375 additions and 33 deletions

View File

@ -4,7 +4,7 @@
*
* @package Pio
* @author Dreamer-Paul
* @version 1.3
* @version 2.0
* @link https://paugram.com
*/
@ -39,15 +39,15 @@ class Pio_Plugin implements Typecho_Plugin_Interface{
echo "</div>";
}
paul_update("Pio", "1.3");
paul_update("Pio", "2.0");
// 读取模型文件夹
$models = array();
$load = glob("../usr/plugins/Pio/models/*");
foreach($load as $key => &$value){
$aaa = substr($value, 26);
$models[$aaa] = ucfirst($aaa);
foreach($load as $key => $value){
$single = substr($value, 26);
$models[$single] = ucfirst($single);
};
// 自定义模型选择
@ -73,6 +73,33 @@ class Pio_Plugin implements Typecho_Plugin_Interface{
// 自定义模型
$custom_model = new Typecho_Widget_Helper_Form_Element_Text('custom_model', NULL, NULL, _t('自定义配置文件地址'), _t('在这里填入一个模型 JSON 配置文件地址,可供使用外链模型,不填则使用插件目录下的模型'));
$form -> addInput($custom_model);
// 展现模式
$custom_mode = new Typecho_Widget_Helper_Form_Element_Radio('custom_mode',
array(
'static' => _t('静态'),
'fixed' => _t('固定'),
'draggable' => _t('可移动'),
),
'static', _t('展现模式'), _t('自定义看板娘的展现模式。静态模式将不启用按钮交互功能'));
$form -> addInput($custom_mode);
// 是否在手机上隐藏
$hidden = new Typecho_Widget_Helper_Form_Element_Radio('hidden',
array(
'0' => _t('关闭'),
'1' => _t('开启'),
),
'0', _t('浏览体验'), _t('是否在手机版上隐藏看板娘'));
$form -> addInput($hidden);
// 自定义文字配置
$talk_content = new Typecho_Widget_Helper_Form_Element_Textarea('talk_content', NULL, '{}', _t('自定义提示内容'), _t('在这里填入你的自定义看板娘提示内容,如想保持默认,需要填写 "{}" 否则会导致插件无法运行'));
$form -> addInput($talk_content);
// 自定义选择器配置
$selector = new Typecho_Widget_Helper_Form_Element_Textarea('selector', NULL, '{}', _t('自定义内容选择器'), _t('在这里填入部分功能所用到的自定义选择器,如不想启用此类功能,需要填写 "{}" 否则会导致插件无法运行'));
$form -> addInput($selector);
}
/* 个人用户的配置方法 */
@ -80,36 +107,65 @@ class Pio_Plugin implements Typecho_Plugin_Interface{
/* 插件实现方法 */
public static function header(){
echo "<link href='" . Helper::options() -> pluginUrl . "/Pio/static/pio.css' rel='stylesheet' type='text/css'/>\n";
$pos = Typecho_Widget::widget('Widget_Options') -> Plugin('Pio') -> position;
echo "<style>#pio{ $pos: 0; bottom: 0; z-index: 520; position: fixed; pointer-events: none; } @media screen and (max-width: 768px){ #pio{ width: 8em; } }</style>";
echo "<style>.pio-container{ $pos: 0 }</style>";
}
public static function footer(){
$height = Typecho_Widget::widget('Widget_Options') -> Plugin('Pio') -> custom_height;
$width = Typecho_Widget::widget('Widget_Options') -> Plugin('Pio') -> custom_width;
// 生成画布
function getCanvas(){
$height = Typecho_Widget::widget('Widget_Options') -> Plugin('Pio') -> custom_height;
$width = Typecho_Widget::widget('Widget_Options') -> Plugin('Pio') -> custom_width;
if($height && $width){
echo "<canvas id='pio' width='".$width."' height='".$height."'></canvas>";
}
else if($height){
echo "<canvas id='pio' width='280' height='".$height."'></canvas>";
}
else if($width){
echo "<canvas id='pio' width='".$width."' height='250'></canvas>";
}
else{
echo "<canvas id='pio' width='280' height='250'></canvas>";
if(!$width){ $width = 280; }
if(!$height){ $height = 250; }
return "<canvas id='pio' width='".$width."' height='".$height."'></canvas>";
}
echo "<script src='" . Helper::options() -> pluginUrl . "/Pio/l2d.js'></script>" . "\n";
// 生成载入器
function getLoader(){
$config = array();
$plug = Typecho_Widget::widget('Widget_Options') -> Plugin('Pio');
if(Typecho_Widget::widget('Widget_Options') -> Plugin('Pio') -> custom_model){
echo "<script>loadlive2d('pio', '" . Typecho_Widget::widget('Widget_Options') -> Plugin('Pio') -> custom_model . "');</script>". "\n";
}
else if(Typecho_Widget::widget('Widget_Options') -> Plugin('Pio') -> choose_models){
echo "<script>loadlive2d('pio', '" . Helper::options() -> pluginUrl . "/Pio/models/" . Typecho_Widget::widget('Widget_Options') -> Plugin('Pio') -> choose_models . "/model.json');</script>". "\n";
}
else{
echo "<script>loadlive2d('pio', '" . Helper::options() -> pluginUrl . "/Pio/models/pio/model.json');</script>". "\n";
if($plug -> custom_model){
$model = $plug -> custom_model;
}
else if($plug -> choose_models){
$model = Helper::options() -> pluginUrl . "/Pio/models/" . $plug -> choose_models . "/model.json";
}
else{
$model = Helper::options() -> pluginUrl . "/Pio/models/pio/model.json";
}
$config["mode"] = $plug -> custom_mode;
$config["hidden"] = $plug -> hidden == 1 ? true : false;
$config["model"] = array();
$config["model"][0] = $model;
$config["content"] = json_decode($plug -> talk_content, true);
$config["selector"] = json_decode($plug -> selector, true);
return '<script>var pio = new poster_girl(' . json_encode($config, JSON_UNESCAPED_SLASHES) . ');</script>';
}
$canvas = getCanvas();
$loader = getLoader();
echo <<< Pio
<div class="pio-container">
<div class="action-menu">
<span class="home"></span>
<span class="skin"></span>
<span class="info"></span>
<span class="close"></span>
</div>
$canvas
</div>
Pio;
echo "<script src='" . Helper::options() -> pluginUrl . "/Pio/static/l2d.js'></script>" . "\n";
echo "<script src='" . Helper::options() -> pluginUrl . "/Pio/static/pio.js'></script>" . "\n";
echo $loader;
}
}

View File

@ -1,5 +1,7 @@
# Pio
一个简易的 Live2D 插件,供 Typecho 使用。
一个支持换模型的 Live2D 插件,供 Typecho 使用。
本插件不存在任何依赖的样式和库,在后续版本当中我会逐渐实现一些交互功能。
## 使用方法
1. Star 本项目
@ -7,12 +9,11 @@
3. 将插件文件夹重命名为 `Pio`
4. 上传本插件,并放置在 `usr/plugins/` 目录下
5. 登录你的 Typecho 后台,并进行安装即可食用~
6. 如果你有自己的模型,可以在插件设置更改,默认名称应该为 `model.json`
6. 如果你有自己的模型,可以将模型放在 `models` 目录下,并在插件设置里选择(需要确认模型的配置文件名称是否为 `model.json`)。或是在插件设置填写一个绝对链接
7. 保罗自己搭建了一个模型资源收集站点 - [梦象](https://mx.paugram.com),你可以在这里下载到更多的模型,如果你有能力的话欢迎为我提供更多资源~
## 项目故事
自 [Jad](https://github.com/journey-ad) 发了一篇关于 Live2D 的教程之后,看到各位大佬的博客逐渐增加了这个小挂件。我一直盼望自己的博客也增加一个,而之前一直想找个机会试水一下 Typecho 的插件开发,于是今天就抽时间做出来了。
目前本插件不存在任何依赖的样式和库。在新版本当中我会逐渐实现一些交互功能,而不需要任何的库。
详见我的博文:[给你的博客增加动态看板娘](https://paugram.com/coding/add-poster-girl-with-plugin.html)
## 开源协议
由于原项目使用 GPL 2.0 协议,故本项目也采用相同的开源协议进行授权。

82
static/pio.css Normal file
View File

@ -0,0 +1,82 @@
/* ----
# Pio Plugin
# By: Dreamer-Paul
# Last Update: 2018.10.12
一个支持换模型的 Live2D 插件 Typecho 使用
本代码为奇趣保罗原创并遵守 MIT 开源协议欢迎访问我的博客https://paugram.com
---- */
.pio-container{
left: 0;
bottom: 0;
position: fixed;
user-select: none;
}
.pio-container.active{ cursor: move }
.pio-container.static{ pointer-events: none }
.pio-container .action-menu{
top: 3em;
right: 0;
opacity: 0;
position: absolute;
transition: opacity .3s;
}
.pio-container:hover .action-menu{ opacity: 1 }
.pio-container .action-menu span{
color: #fff;
width: 1.5em;
height: 1.5em;
display: block;
cursor: pointer;
text-align: center;
border-radius: 66%;
margin-bottom: .5em;
border: 1px solid #666;
background: #fff center/70% no-repeat;
}
.pio-container .action-menu .home{
background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTg5My43IDUwNS45SDEyOS4zYy0xMyAwLTI0LjgtNy45LTI5LjgtMTkuOS01LTEyLTIuMi0yNS45IDctMzUuMmwzMDctMzA3YzI2LjEtMjYuMSA2MC45LTQwLjUgOTgtNDAuNXM3MS45IDE0LjQgOTggNDAuNWwzMDcgMzA3YzkuMiA5LjIgMTIgMjMuMSA3IDM1LjItNSAxMi4xLTE2LjcgMTkuOS0yOS44IDE5Ljl6TTY3My4yIDkxOS45aC0zMS41Yy0xNy44IDAtMzIuMy0xNC40LTMyLjMtMzIuM3YtNzcuNGMwLTIzLjEtMTguOC00Mi4xLTQxLjktNDIuNC0yMi4zIDAuMy00MS4xIDE5LjMtNDEuMSA0Mi40djc3LjRjMCAxNy44LTE0LjQgMzIuMy0zMi4zIDMyLjNIMzQ5LjhjLTcwLjkgMC0xMjguNy02My43LTEyOC43LTE0MS45VjU4MS45YzAtMTcuOCAxNC40LTMyLjMgMzIuMy0zMi4zaDUxNi4yYzE3LjggMCAzMi4zIDE0LjQgMzIuMyAzMi4zVjc3OGMtMC4xIDc4LjMtNTcuOCAxNDEuOS0xMjguNyAxNDEuOXoiPjwvcGF0aD48L3N2Zz4=);
}
.pio-container .action-menu .close{
background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTE1NS4yNTIgOTQzLjgyNWMtMTkuMjEzIDAtMzguNDI5LTcuMzMyLTUzLjA4OS0yMS45ODgtMjkuMzE3LTI5LjMyMS0yOS4zMTctNzYuODU1IDAtMTA2LjE3NWw3MTMuNDk0LTcxMy40OTRjMjkuMzE3LTI5LjMyMSA3Ni44NTMtMjkuMzIxIDEwNi4xNzUgMCAyOS4zMTcgMjkuMzE3IDI5LjMxNyA3Ni44NTUgMCAxMDYuMTc1bC03MTMuNDk0IDcxMy40OTRjLTE0LjY2IDE0LjY2LTMzLjg3NCAyMS45ODgtNTMuMDg5IDIxLjk4OHoiIGZpbGw9IiI+PC9wYXRoPjxwYXRoIGQ9Ik04NjguNzQ5IDk0My44MjRjLTE5LjIxMyAwLTM4LjQyOC03LjMzMi01My4wODktMjEuOTg4bC03MTMuNDk0LTcxMy40OTNjLTI5LjMxNy0yOS4zMTctMjkuMzE3LTc2Ljg1NyAwLTEwNi4xNzUgMjkuMzE2LTI5LjMxNyA3Ni44NTUtMjkuMzIxIDEwNi4xNzQgMGw3MTMuNDk0IDcxMy40OTJjMjkuMzE3IDI5LjMyMSAyOS4zMTcgNzYuODU1IDAgMTA2LjE3NS0xNC42NTcgMTQuNjYxLTMzLjg3MSAyMS45OTMtNTMuMDg3IDIxLjk5M3oiIGZpbGw9IiI+PC9wYXRoPjwvc3ZnPg==);
}
.pio-container .action-menu .skin{
background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTk2NS45MTEgMzEwLjUzMWwtMTc0LjQtMTc0LjM5OGMtMTMuMDIyLTEzLjAyMS0zMC45MzMtMTkuNjQ5LTQ5LjM4MS0xOC4yMjgtMS43NC0wLjE1LTMuNDIyLTAuMjI0LTUuMDctMC4yMjRsLTkyLjkxNCAwLTYuNTE3IDMuNjI1Yy0zNC40MjEgMTkuMTQ2LTc4LjM0MSAyOS42ODktMTIzLjY2OCAyOS42ODktNDUuMzI4IDAtODkuMjQ2LTEwLjU0My0xMjMuNjY3LTI5LjY4OWwtNi41MTgtMy42MjVMMjkwLjg2IDExNy42ODFjLTIzLjY5MSAwLTQ0Ljk4NiAxMi45MjQtNTUuOTk1IDMzLjQ1MUw2Mi40NzcgMzIzLjUyMWMtMTEuOSAxMS44OTktMTguNDU0IDI3LjcyLTE4LjQ1NCA0NC41NDggMCAxNi44MjkgNi41NTQgMzIuNjQ5IDE4LjQ1MyA0NC41NDlsMTI1Ljk1MyAxMjUuOTU1YzEwLjU0IDEwLjUzOCAyNC4xNTcgMTYuODc4IDM4LjgyNiAxOC4xODFsMCAzMDQuMzk5YzAgMzUuMDczIDI4LjUzMyA2My42MDYgNjMuNjA0IDYzLjYwNmw0NDYuMTk5IDBjMzUuMDc0IDAgNjMuNjA3LTI4LjUzMyA2My42MDctNjMuNjA2bC0wLjAwMS0zMTcuMzQ1YzE0Ljg0NC0xLjIxMSAyOC42MzktNy41NzcgMzkuMjg4LTE4LjIyNEw5NjUuOTEgMzk5LjYyOEM5OTAuNDc1IDM3NS4wNjQgOTkwLjQ3NSAzMzUuMDk1IDk2NS45MTEgMzEwLjUzMXoiPjwvcGF0aD48L3N2Zz4=);
}
.pio-container .action-menu .info{
background-image: url(data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTY4Mi45IDgyNS45SDI2Ny44Yy0yMS44IDAtMzkuNS0xNy43LTM5LjUtMzkuNXMxNy43LTM5LjUgMzkuNS0zOS41aDQxNS4xYzIxLjggMCAzOS41IDE3LjcgMzkuNSAzOS41cy0xNy43IDM5LjUtMzkuNSAzOS41ek04NjQuNyAxMDAuNGMtMTguNSAzLjctMzEuMyAyMC45LTMxLjMgMzkuN3Y2NDUuOGMwIDQ4LTM4LjkgODctODcgODdIMjE5LjNjLTE2LjQgMC0yOS42LTEzLjMtMjkuNi0yOS42VjczMi43YzAtMTYuMSAxMy4xLTI5LjIgMjkuMi0yOS4yaDM3NS45Yzg4LjEgMCAxNTkuNS03MS40IDE1OS41LTE1OS41VjE4NS41YzAtNjYuMi01My43LTExOS45LTExOS45LTExOS45aC00MDRjLTY2LjIgMC0xMTkuOSA1My43LTExOS45IDExOS45djY1Ny44YzAgNjAgNDguNyAxMDguNyAxMDguNyAxMDguN2g1MjcuMWM5MS43IDAgMTY2LjEtNzQuMyAxNjYuMS0xNjYuMVYxMzkuMWMwLjEtMjQuNi0yMi4yLTQzLjktNDcuNy0zOC43eiI+PC9wYXRoPjwvc3ZnPg==);
}
.pio-container .dialog{
top: -2em;
left: 1em;
right: 1em;
opacity: 0;
z-index: -1;
font-size: .8em;
background: #fff;
padding: .75em 1em;
border-radius: 1em;
visibility: hidden;
position: absolute;
word-break: break-all;
border: 1px solid #eee;
transition: opacity .3s, visibility .3s;
}
.pio-container .dialog.active{
opacity: 1;
visibility: visible;
}
#pio{ vertical-align: middle }
@media screen and (max-width: 768px){
#pio{ width: 8em }
.pio-container{ pointer-events: none }
.pio-container.hidden, .pio-container .action-menu, .pio-container .dialog{ display: none }
}

203
static/pio.js Normal file
View File

@ -0,0 +1,203 @@
/* ----
# Pio Plugin
# By: Dreamer-Paul
# Last Update: 2018.10.12
一个支持换模型的 Live2D 插件 Typecho 使用
本代码为奇趣保罗原创并遵守 MIT 开源协议欢迎访问我的博客https://paugram.com
---- */
var poster_girl = function (prop) {
var current = {
idol: 0,
canvas: document.getElementById("pio"),
body: document.getElementsByClassName("pio-container")[0],
root: document.location.protocol +'//' + document.location.hostname +'/'
};
var elements = {
home: current.body.getElementsByClassName("home")[0],
skin: current.body.getElementsByClassName("skin")[0],
info: current.body.getElementsByClassName("info")[0],
close: current.body.getElementsByClassName("close")[0]
};
var dialog = document.createElement("div");
dialog.className = "dialog";
current.body.appendChild(dialog);
/* - 方法 */
var modules = {
// 更换模型
idol: function () {
current.idol < (prop.model.length - 1) ? current.idol++ : current.idol = 0;
return current.idol;
},
// 随机内容
rand: function (arr) {
return arr[Math.floor(Math.random() * arr.length + 1) - 1];
},
// 创建对话框方法
render: function (text) {
if(text.constructor === Array){
dialog.innerText = modules.rand(text);
}
else if(text.constructor === String){
dialog.innerText = text;
}
else{
dialog.innerText = "输入内容出现问题了 X_X";
}
dialog.classList.add("active");
clearTimeout(this.t);
this.t = setTimeout(function () {
dialog.classList.remove("active");
}, 3000);
},
// 移除方法
destroy: function () {
current.body.parentNode.removeChild(current.body);
}
};
/* - 提示操作 */
var action = {
// 欢迎
welcome: function () {
if(document.referrer !== "" && document.referrer.indexOf(current.root) === -1){
var referrer = document.createElement('a');
referrer.href = document.referrer;
prop.content.welcome && prop.content.welcome[1] ? modules.render(prop.content.welcome[1].replace(/%t/, "“" + referrer.hostname + "”")) : modules.render("欢迎来自 “" + document.referrer + "” 的朋友!");
}
else{
prop.content.welcome && prop.content.welcome[0] ? modules.render(prop.content.welcome[0]) : modules.render("欢迎来到保罗的小窝!");
}
},
// 文章
article: function () {
if(prop.selector.articles){
var a = document.querySelectorAll(prop.selector.articles), b;
prop.content.article ? b = prop.content.article : b = "想阅读 %t 吗?";
for(var i = 0; i < a.length; i++){
a[i].onmouseover = function () {
modules.render(b.replace(/%t/, "“" + this.innerText + "”"));
}
}
}
},
// 触摸
touch: function () {
if(prop.content.touch){
current.canvas.onclick = function () {
modules.render(prop.content.touch);
}
}
else{
current.canvas.onclick = function () {
modules.render(["你在干什么?", "再摸我就报警了!", "HENTAI!", "你够了喔!"]);
}
}
},
// 右侧按钮
buttons: function () {
// 返回首页
if(elements.home){
elements.home.onclick = function () {
location.href = current.root;
};
elements.home.onmouseover = function () {
prop.content.home ? modules.render(prop.content.home) : modules.render("点击这里回到首页!");
};
}
// 更换模型
if(elements.skin){
elements.skin.onclick = function () {
loadlive2d("pio", prop.model[modules.idol()]);
prop.content.skin && prop.content.skin[1] ? modules.render(prop.content.skin[1]) : modules.render("新衣服真漂亮~");
};
elements.skin.onmouseover = function () {
prop.content.skin && prop.content.skin[0] ? modules.render(prop.content.skin[0]) : modules.render("想看看我的新衣服吗?");
};
}
// 关于我
if(elements.info){
elements.info.onclick = function () {
window.open("https://paugram.com/coding/add-poster-girl-with-plugin.html");
};
elements.info.onmouseover = function () {
modules.render("想了解更多关于我的信息吗?");
};
}
// 关闭看板娘
if(elements.close){
elements.close.onclick = function () {
modules.destroy();
};
elements.close.onmouseover = function () {
prop.content.close ? modules.render(prop.content.close) : modules.render("QWQ 下次再见吧~");
};
document.cookie = "posterGirl=false;" + "path=/";
}
}
};
/* - 运行 */
var begin = {
static: function () {
action.welcome(); action.article();
current.body.classList.add("static");
},
fixed: function () {
action.welcome(); action.article(); action.touch(); action.buttons();
},
draggable: function () {
action.welcome(); action.article(); action.touch(); action.buttons();
var body = current.body;
body.onmousedown = function () {
var location = {
x: event.clientX - this.offsetLeft,
y: event.clientY - this.offsetTop
};
function move(e) {
body.classList.add("active");
body.style.left = (event.clientX - location.x) + 'px';
body.style.top = (event.clientY - location.y) + 'px';
}
document.addEventListener("mousemove", move);
document.addEventListener("mouseup", function () {
body.classList.remove("active");
document.removeEventListener("mousemove", move);
});
};
}
};
// 判断模式并运行
switch (prop.mode){
case "static": begin.static(); break;
case "fixed": begin.fixed(); break;
case "draggable": begin.draggable(); break;
}
if(prop.hidden === true){ current.body.classList.add("hidden") }
loadlive2d("pio", prop.model[0]);
};
// 请保留版权说明
if (window.console && window.console.log) {
console.log("%c Pio %c https://paugram.com ","color: #fff; margin: 1em 0; padding: 5px 0; background: #673ab7;","margin: 1em 0; padding: 5px 0; background: #efefef;");
}