“Widget:TalkToc”与“Widget:网站维护时间线”:页面之间的差异

H萌娘,万物皆可H的百科全书!
(页面间差异)
跳到导航 跳到搜索
imported>=海豚=
([InPageEdit] 没有编辑摘要)
 
imported>=海豚=
无编辑摘要
 
第1行: 第1行:
<noinclude>Only for [[Talk:讨论版]] & [[Talk:提问求助区]]</noinclude><includeonly><!--{if !isset($wgTalkToc) || !$wgTalkToc}--><!--{assign var="wgTalkToc" value=true scope="global"}--><script>
<style>
window.RLQ = window.RLQ || [];
* {
window.RLQ.push(function() {
  margin: 0;
   if (location.hostname.includes("m.hmoegirl.com")) return;
   mw.loader.using(["oojs-ui"]).then(function() {
     if (!mw.config.get('talkTocLoaded', false)) {
       mw.config.set('talkTocLoaded', true);
       if (!$('#talkTocBox')[0]) {
         if (localStorage.getItem('widgetTalkToc') === 'disable') {
           $('body').addClass('widgetTalkTocDisable');
           $('.toctitle').after('<' + 'div style="text-align: center;">[<' + 'a class="enableWidgetTalkToc">启用讨论页面整理工具<' + '/a>]<' + '/div>');
           $('.enableWidgetTalkToc').on('click', function() {
             localStorage.setItem('widgetTalkToc', 'enable');
             $(this).text('启用成功!刷新页面中……');
             setTimeout(location.reload.bind(location), 150);
           });
           return;
         }
 
         $('body').addClass('widgetTalkTocEnable');
         var toclist = ['tocBox', 'talkTocBox', 'toc'],
           bgcolor = $('body').css('background-color'),
           $toc = $('#toc'),
           titlereg = {},
           $tocBox, $level2, $li, $svdDcs, $title, $toggle, $tocText,
           appendToggleButton;
 
         /* 预处理 */
         //备份目录
         $toc.after($toc.clone().hide().attr('id', 'tocClone'));
         //整理讨论串
         $('#mw-content-text > .mw-parser-output > h2').each(function() {
           var head = $(this);
           var container = $('<' + 'div/>');
           container.addClass('discussionContainer');
           head.addClass('discussionHead');
           head.before(container);
           head.nextUntil('h2').not('h2').appendTo(container);
           head.prependTo(container);
           if (container.find('.saveNotice')[0] && head.nextUntil(".saveNotice").length === 0) {
             $toc.find('a[href="#' + head.find('.mw-headline')[0].id.replace(/"/g, '\\\"') + '"]').parent().addClass("savedDiscussion hiddenDiscussion");
             container.addClass('savedDiscussion');
           } else if (window.CSS && CSS.supports && CSS.supports('position', 'sticky')) {
             head.css({
               position: 'sticky',
               top: 0,
               'background-color': bgcolor,
               'z-index': 2
             });
             container.css('position', 'relative');
           }
         });
 
         // Temporary padding fix for Microsoft Edge
         // TODO: Report this issue to Edge team
         if (/Edge/.test(navigator.userAgent)) {
           $('.discussionContainer').css('padding-top', '10px');
         }
 
         //整理标题列表
         $toc.append("<" + "ol style='margin-left: 1.7em;'><" + "/ol>").after('<' + 'div id="tocBox"><' + '/div>');
         $toc.children('ul').children().appendTo($toc.find('ol'));
         $toc.find(".toclevel-1 > a > .tocnumber").remove();
         $toc.appendTo("#tocBox");
 
         /* 定义变量 */
         $tocBox = $('#tocBox');
         $level2 = $toc.find('.toclevel-2').hide();
         $li = $toc.find('ol > li');
         $svdDcs = $toc.find('.savedDiscussion');
         $title = $toc.find('.toctitle').css("margin-right", "1em").append('<' + 'span id="toctoggle"><' + '/span>');
         $toggle = $title.append('<' + 'div id="toggle"><' + '/div>').find('#toggle');
         $tocText = $title.after('<' + 'div id="tocText"><' + '/div>').parents('#toc').find('#tocText');
         appendToggleButton = function($Obj, $set, shTx, hiTx, fun) {
           if (!$Obj[0]) return false;
           $set.append($('<' + 'a/>', {
             text: function() {
               if ($Obj.is(':visible')) return hiTx;
               else return shTx;
             },
             'class': 'toggleButton',
             href: 'javascript:void(0);',
             bind: {
               click: function() {
                 if ($Obj.is(':visible')) {
                   $Obj.hide();
                   $(this).text(shTx);
                 } else {
                   $Obj.show();
                   $(this).text(hiTx);
                 }
               }
             }
           }));
           if (typeof fun == 'function') fun();
         };
 
         /* 业务处理*/
         //添加存档讨论串标题toggle按钮
         if ($svdDcs[0]) {
           $toggle.append($('<' + 'a/>', {
             text: '显示已被存档标题',
             'class': 'toggleButton',
             href: 'javascript:void(0);',
             on: {
               click: function() {
                 if ($svdDcs.hasClass('hiddenDiscussion')) {
                   $svdDcs.removeClass('hiddenDiscussion');
                   $(this).text('隐藏已被存档标题');
                 } else {
                   $svdDcs.addClass('hiddenDiscussion');
                   $(this).text('显示已被存档标题');
                 }
               }
             }
           }));
           $tocText.append("<" + "div class='tocText'>(有下划线标题是已被存档标题)<" + "/div>");
         }
         //添加二三四五级标题toggle按钮和标题数量
         appendToggleButton($level2, $toggle, '显示段落', '隐藏段落', function() {
           $tocText.append("<" + "div class='tocText'>(中括号内数字是该大段下小段数量)<" + "/div>");
           $toc.find('.toclevel-1').each(function() {
             var subtitleLength = $(this).find('.toctext').length - 1;
             if (subtitleLength) $(this).children('a').after('[' + subtitleLength + ']');
           });
         });
         //添加整体toggle按钮
         appendToggleButton($toc.find('ol'), $title.find('#toctoggle'), '显示', '隐藏');
         $('#toc').addClass('noOrigin');
         /*
         $('.saveNotice').each(function() {
           $(this).prev('h2').addClass('savedNotice');
         });*/
         var containers = $('.discussionContainer');
         containers.first().before('<' + 'div id="talkTocBox"><' + 'table><' + '/table><' + '/div>');
         var self = $('#talkTocBox table'),
           a = $('<' + 'a/>').text('');
         self.append('<' + 'caption/>').find('caption').append(mw.config.get('wgTitle') + '现有讨论串').append(' [').append(a).append(']<' + 'br>').append('(这里的讨论串不会被存档,无用及已解决的即时讨论会被定期删除)')
           .end().append('<' + 'tbody/>');
         containers.not('.savedDiscussion').each(function(i) {
           if (i % 4 === 0) self.find('tbody:last').append('<' + 'tr/>');
           var that = $(this);
           /* var content = that.children().not('h2');
           content.find('a').each(function() {
             try {
               var href = $(this)[0].href;
               if (!href) return;
               var link = new mw.Uri(href);
               if (link.host !== 'www.moegirl.com') this.userNameErrorReason = "link.host !== 'www.moegirl.com'";
               else if (/^\/api\.php/i.test(link.path)) this.userNameErrorReason = "!!/^\\/api\\.php/i.test(link.path)";
               else if (!link.query.title && /\.php$/i.test(link.path)) this.userNameErrorReason = "!!(!link.query.title && /\\.php$/i.test(link.path))";
               else {
                 var t = link.query.title || decodeURIComponent(link.path.substring(1));
                 if (/^user([ _]talk)?:[^\/]+$/i.test(t)) $(this).data('userName', t.replace(/^user([ _]talk)?:/i, '')).addClass('userTalkPage');
                 else this.userNameErrorReason = "!!/^user([ _]talk)?:[^\\/]+$/i.test(t)";
               }
             } catch (e) {
               return;
             }
           });
           content.find('.userTalkPage').each(function() {
             var parent = $(this).closest(containers).clone();
             var now = Date.now() + (Math.random() + '').substring(2);
             parent.find('.userTalkPage').text(now);
             var regExec = RegExp(now + '(.*)(\\d{4}年([1-9]|1[0-2])月([1-9]|[12]\\d|3[01])日\\s{0,10}\\([一二三四五六日]\\)\\s{0,10}([01]\\d|2[0-3]):[0-5]\\d\\s{0,10}(\\([A-Z]{3}\\))?)').exec(parent.text());
             if (!regExec || regExec[1].length > 20) {
               this.userNameErrorReason = 'Too far away from timestamp (' + (regExec ? regExec[1].length : 'null') + ')';
               this.userNameErrorRegExec = regExec;
               $(this).removeClass('userTalkPage');
             } else $(this).data('userTalkTime', regExec[2]);
           });
           var userTalkPage = [];
           content.find('.userTalkPage').each(function() {
             var timestamp = $(this).data('userTalkTime').replace(/ \([A-Z]{3,4}\)$|\([日一二三四五六]\)/g, ''),
               date = new Date(),
               time = timestamp.split(/[年月日\s\(\)\:]+/).map(function(n) {
                 return +n;
               });
             if (!time || !time[4]) return $(this).removeClass('.userTalkPage')[0].userNameErrorReason = 'Error Timestamp(' + timestamp + ')';
             date.setFullYear(time[0]);
             date.setMonth(time[1] - 1);
             date.setDate(time[2]);
             date.setHours(time[3]);
             date.setMinutes(time[4]);
             userTalkPage.push([$(this).data('userName'), timestamp, date.getTime()]);
           });
           if (!userTalkPage[0]) userTalkPage.push(['Unsigned user/Nonstandard sign', 'Unknown Time']);
           else userTalkPage.sort(function(a, b) {
             return a[2] - b[2]
           });
           var firstName = userTalkPage[0],
             lastName = userTalkPage[userTalkPage.length - 1];
           titlereg[that.find('.mw-headline:first').attr('id')] = that;*/
           self.find('tr:last').append('<' + 'td><' + '/td>')
             .find('td:last').append(
               $('<' + 'a/>').attr('href', '#' + that.find('.mw-headline:first').attr('id').replace(/"/g, "&quot;")).append(that.find('.mw-headline:first').clone().find('a').replaceWith(function() {
                 return $(this).text();
               }).end().html())
             );
           /* .append(
             $('<' + 'div/>').addClass('signInfo').append('话题发起:' + (firstName[0] === 'Unsigned user/Nonstandard sign' ? 'Unsigned user/Nonstandard sign' : '<' + 'a href="/User_talk:' + firstName[0] + '" title="' + firstName[0] + '的讨论页" target="_blank">' + firstName[0].replace(/_/g, ' ') + '<' + '/a>'))
             .append('<' + 'br>最后回复:' + (lastName[0] === 'Unsigned user/Nonstandard sign' ? 'Unsigned user/Nonstandard sign' : '<' + 'a href="/User_talk:' + lastName[0] + '" title="' + lastName[0] + '的讨论页" target="_blank">' + lastName[0].replace(/_/g, ' ') + '<' + '/a>') + '(' + lastName[1] + ')')
           ); */
         });
         /* if ($('.signInfo').filter(function() {
             return $(this).text().indexOf('Unsigned user/Nonstandard sign') !== -1;
           }).length * 2 > $('.signInfo').length) $('.signInfo').hide(); */
         self.append('<' + 'tbody class="hr"><' + 'tr><' + 'td colspan="4"> <' + '/td><' + '/tr><' + '/tbody>').append('<' + 'tbody/>').find('tbody').not(':first').hide();
         containers.filter('.savedDiscussion').each(function(i) {
           if (i % 4 === 0) self.find('tbody:last').append('<' + 'tr/>');
           self.find('tr:last').append('<' + 'td><' + 'a class="savedTitle" href="#' + $(this).find('.mw-headline:first').attr('id').replace(/"/g, "&quot;") + '">' + $(this).clone().find('.mw-headline:first').children('.mw-headline-number').remove().end().prepend(containers.index(this) + 1 + ' ').text() + '<' + '/a><' + '/td>');
         });
         a.on('click', function() {
           self.find('tbody').not(':first').fadeToggle();
           $(this).text($(this).text() === '' ? '隐藏已存档讨论串标题' : '');
         });
         self.find('tbody').not('.hr').each(function() {
           var that = $(this).find('tr:last');
           that.append(("<" + "td>&#32;<" + "/td>").repeat(4 - that.find("td").length));
         });
         $('#talkTocBox caption').append('<' + 'br>[').append($('<' + 'a/>').addClass('cbutton')).append(']');
         $('#tocText').append('<' + 'br>[').append($('<' + 'a/>').addClass('cbutton')).append(']');
         $('.cbutton').on('click', function() {
           if (!localStorage.wgTocStyle || localStorage.wgTocStyle !== 'list') {
             $('#talkTocBox').hide();
             $('#tocBox').show();
             localStorage.setItem('wgTocStyle', 'list');
             $('.cbutton').text('点击切换至表格格式');
             $(toclist.filter(function(l) {
               return l !== "tocBox";
             }).map(function(l) {
               return 'a[href="#' + l + '"]';
             }).join(', ')).attr("href", "#tocBox");
           } else {
             $('#talkTocBox').show();
             $('#tocBox').hide();
             localStorage.setItem('wgTocStyle', 'table');
             $('.cbutton').text('点击切换至列表格式');
             $(toclist.filter(function(l) {
               return l !== "talkTocBox";
             }).map(function(l) {
               return 'a[href="#' + l + '"]';
             }).join(', ')).attr("href", "#talkTocBox");
           }
         });
         if (!localStorage.wgTocStyle || localStorage.wgTocStyle !== 'list') {
           $('#talkTocBox').show();
           $('.cbutton').text('点击切换至列表格式');
           $(toclist.filter(function(l) {
             return l !== "talkTocBox";
           }).map(function(l) {
             return 'a[href="#' + l + '"]';
           }).join(', ')).attr("href", "#talkTocBox");
         } else {
           $('#tocBox').show();
           $('.cbutton').text('点击切换至表格格式');
           $(toclist.filter(function(l) {
             return l !== "tocBox";
           }).map(function(l) {
             return 'a[href="#' + l + '"]';
           }).join(', ')).attr("href", "#tocBox");
         }
         $('.cbutton').parent().append(' [<' + 'a class="disableWidgetTalkToc">禁用讨论页面整理工具<' + '/a>]');
         $('.disableWidgetTalkToc').on('click', function() {
           localStorage.setItem('widgetTalkToc', 'disable');
           $(this).text('禁用成功!刷新页面中……');
           setTimeout(location.reload.bind(location), 150);
         });
         $tocBox.css({
           position: 'relative',
           'z-index': 10
         });
         $(window).on('hashchange', function(e) {
           try {
             var hash = location.hash.substring(1);
             var target = $('[id="' + decodeURIComponent(hash).replace(/"/g, '\\\"') + '"]');
             if (target[0]) {
               var scrollTop = target.offset().top;
               if (target.closest('.discussionHead').length === 0) {
                 var parent = target.closest('h1, h2, h3, h4, h5, h6');
                 if (parent.length > 0) {
                   scrollTop -= parent.outerHeight(true) - parent.height();
                   var h = parent.prevAll('h1, h2, h3, h4, h5, h6').filter(function() {
                     return $(this).css('position') === 'sticky';
                   });
                   if (h.length > 0) scrollTop -= h.outerHeight();
                 }
               } else scrollTop = target.closest('.discussionContainer').offset().top;
               setTimeout(function() {
                 $('html,body').animate({
                   scrollTop: scrollTop
                 }, 0);
               }, 1);
               return false;
             }
           } catch (e) {
             return;
           }
         }).trigger('hashchange');
         const g = ["sysop", "patroller"];
         if (mw.config.get("wgUserGroups").filter(n => g.includes(n)).length === 0 && mw.config.get("wgPageName").startsWith("讨论:讨论版")) {
           $("#right-navigation").addClass("no-need-to-edit-whole-page").find("#p-views > ul").append('<li id="ca-no-need-to-edit-whole-page-notice" class="collapsible"><span><a href="javascript:void(0);">请勿编辑全文</a></span></li>').find("#ca-no-need-to-edit-whole-page-notice a").on("click", function() {
             var messageDialog = new OO.ui.MessageDialog();
             var windowManager = new OO.ui.WindowManager();
             $("body").append(windowManager.$element);
             windowManager.addWindows([messageDialog]);
             messageDialog.title.$label.html("萌娘百科提醒您<br>公共讨论页无需编辑全文");
             messageDialog.message.$label.html("<br>提问求助区、讨论版属于公共讨论页,一般来说无须编辑全文,故我们隐藏了入口。<hr>您可以点击下方标题旁的<b>【编辑】链接</b>来编辑对应段落,也可以点击右上方<b>【添加话题】链接</b>来新增话题。");
             windowManager.openWindow(messageDialog, {
               actions: [{
                 action: 'accept',
                 label: '我知道了',
                 flags: 'primary'
               }]
             });
           });
         }
       }
     }
   });
});
</script><style>
/* <pre> */
.widgetTalkTocEnable #tocBox {
   max-width: 37%;
   min-width: 300px;
   float: left;
}
}
.widgetTalkTocEnable #toc.noOrigin {
.timeline {
   display: table;
  height: 100%;
  position: relative;
}
}
.widgetTalkTocEnable div.toc#toc {
.timeline canvas {
   min-width: 300px;
  position: absolute;
   box-sizing: border-box;
  width: 100%;
   margin-right: 37px;
  height: 100%;
   padding-right: 1em;
  left: 0;
   padding-left: 1em;
  top: 45px;
}
}
.widgetTalkTocEnable div.toc#toc div.toctitle h2 {
.timeline figcaption {
    margin-right: 1em;
  font-weight: 400;
    font-size: 24px;
  text-transform: uppercase;
  -webkit-text-stroke: .25px;
}
}
.widgetTalkTocEnable div.toc.noOrigin#toc .toctoggle {
.timeline h2 {
    display: none;
  font-weight: 400;
    font-size: 30px;
  padding-bottom: 20px;
  color: #b2cde9!important;
  text-transform: uppercase;
  line-height: 1.2 !important;
}
}
.widgetTalkTocEnable div#toc.toc #toctoggle,
.timeline h6 {
.widgetTalkTocEnable div#toc.toc #toggle {
  color: #0090F5!important;
    font-size: 94%;
    font-size: 17px;
    -webkit-user-select: none;
    font-weight: 400;
   -ms-user-select: none;
   -o-user-select: none;
   -moz-user-select: none;
   user-select: none;
}
}
.widgetTalkTocEnable div#toc.toc .toggleButton:before {
.timeline p,
   content: "[";
.timeline ol {
   color: black;
  font-weight: 400;
  padding: 3px 0 20px 0;
  color: #575757!important;
  text-align: justify;
  width: 70%;
}
}
.widgetTalkTocEnable div#toc.toc .toggleButton:after {
.timeline ol {
   content: "]";
  list-style: disc;
   color: black;
  margin-top: -20px;
  padding-left: 40px;
}
}
.widgetTalkTocEnable #toc .toggleButton:first-child {
.timeline figure {
   margin-right: 0.5em;
  float: right;
  width: 100%;
}
}
.widgetTalkTocEnable div#toc.toc .toggleButton:last-child {
.timeline article {
   margin-right: 0;
  position: relative;
  width: 38%;
  overflow: hidden;
}
}
.widgetTalkTocEnable div#toc.toc .hiddenDiscussion {
.timeline article:first-of-type {
   visibility: hidden;
  float: left;
   height: 0;
  text-align: right;
   margin: 0;
}
}
.widgetTalkTocEnable div.toc#toc li.savedDiscussion a {
.timeline article:first-of-type p,
   text-decoration: underline;
.timeline article:first-of-type figure {
  float: right;
}
}
.widgetTalkTocEnable #toc div#tocText {
.timeline article:last-of-type {
   text-align: center;
  float: right;
}
}
.widgetTalkTocEnable #toc div.tocText {
.timeline article:last-of-type h2 {
   display: inline-block;
  color: #c6e0aa!important;
}
}
.widgetTalkTocEnable
.timeline article:last-of-type h6,
/* 节操酱的beg */
.timeline article:last-of-type a {
.widgetTalkTocEnable #content ol,
  color: #40aa00!important;
.widgetTalkTocEnable #content ul {
   margin: 0 !important;
   padding: 0.3em 0 0 1.6em !important;
}
}
.widgetTalkTocEnable #toc .toclevel-1>ul {
.timeline article:last-of-type a:hover {
   padding-left: 0 !important;
  color: #95D40D!important;
}
}
.widgetTalkTocEnable
</style>
/* 由于节操酱的beg导致分类那边有秘制空白 */
</head>
.widgetTalkTocEnable #content #catlinks ol,
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
.widgetTalkTocEnable #content #catlinks ul {
<script>
   padding: 0 !important;
   function Timeline(cvs) {
}
 
#toc,
   var self = this,
#tocBox,
     paused = true,
#talkTocBox {
     rafid = 0,
    display: none;
     mouse = { x: 0, y: 0 },
}
     canvas = cvs,
.widgetTalkTocDisable #toc {
     ctx = null;
    display: table;
 
}
   self.lines = [];
.widgetTalkTocEnable #talkTocBox td {
 
   text-align: center;
   self.isOK = false;
   border: 1px solid #a7d7f9;
   self.options = {
   width: 25%;
     speed: 0.1,
   padding: 0 1em;
     density: 8,
}
     radius: 600,
.widgetTalkTocEnable #talkTocBox .hr td {
   };
    width: 100%;
   self.targets = [
}
     [29, 32, 48, 68],
.widgetTalkTocEnable #talkTocBox table {
     [29, 33, 38]
   border-collapse: collapse;
   ];
   margin-bottom: 1em;
   self.dotColors = [
   width: 100%;
     ['#13669b', 'rgba(19, 102, 155, 0.3)', 'rgba(19, 102, 155, 0.08)'],
}
     ['#7dd317', 'rgba(113, 222, 15, 0.3)', 'rgba(91, 164, 22, 0.12)'],
.widgetTalkTocEnable #talkTocBox a {
    ];
   cursor: pointer;
 
}
   self.isPaused = function () {
.widgetTalkTocEnable #talkTocBox .savedTitle {
     return paused;
   text-decoration: underline;
    };
}
 
.widgetTalkTocEnable .cbutton {
   function InitDots() {
   cursor: pointer;
     var tl = $('.timeline');
}
     var top = tl.find('h2').outerHeight();
.signInfo {
 
   display: none !important;
     self.lines[0].dots = [];
}
     var y = top;
#right-navigation.no-need-to-edit-whole-page ul {
     tl.find('article:first figure').each(function () {
   display: flex;
 
}
       self.lines[0].dots.push([$(this).outerWidth() + 20, y + 20]);
#right-navigation.no-need-to-edit-whole-page ul>li {
 
   order: 999;
       y += $(this).outerHeight();
}
     });
#right-navigation.no-need-to-edit-whole-page ul>li#ca-view {
 
   order: 1;
     self.lines[1].dots = [];
}
     var y = top;
#right-navigation.no-need-to-edit-whole-page ul>li#ca-no-need-to-edit-whole-page-notice {
     tl.find('article:last figure').each(function () {
   order: 2;
 
    font-style: italic;
       self.lines[1].dots.push([canvas.width - $(this).outerWidth() - 20, y + 20]);
}
 
#right-navigation.no-need-to-edit-whole-page ul>li#ca-no-need-to-edit-whole-page-notice a,
       y += $(this).outerHeight();
#right-navigation.no-need-to-edit-whole-page ul>li#ca-no-need-to-edit-whole-page-notice a:visited {
     });
   color: #222;
   }
   text-decoration: none;
 
}
    function OnResize() {
#right-navigation.no-need-to-edit-whole-page ul>li#Wikiplus-Edit-TopBtn,
     canvas.width = canvas.offsetWidth;
#right-navigation.no-need-to-edit-whole-page ul>li#ca-edit,
     canvas.height = canvas.offsetHeight;
#right-navigation.no-need-to-edit-whole-page ul>li#ca-editTopSection {
 
    display: none;
     var wasPaused = paused;
}
     self.toggle(false);
.cloaked-element.transparent-shield {
     // Init lines
   z-index: 9999999;
     self.lines[0].reset(canvas.offsetWidth / 2 - 15);
}
     self.lines[1].reset(canvas.offsetWidth / 2 + 15);
.navpopup {
 
    z-index: 1000000;
     InitDots();
 
     self.toggle(!wasPaused);
   }
 
   function init() {
     var result = false;
     try {
       result = !!(canvas.getContext && (ctx = canvas.getContext('2d')));
 
       self.lines[0] = new Line(0, canvas.offsetHeight - 100, '#4789a3', self.options, mouse);
       self.lines[1] = new Line(0, canvas.offsetHeight - 100, '#a0d59c', self.options, mouse);
 
     } catch (e) {
       return false;
     }
 
     $(canvas).mousemove(function (e) {
 
       if (e.offsetX) {
         mouse.x = e.offsetX;
         mouse.y = e.offsetY;
       }
       else if (e.layerX) {
         mouse.x = e.layerX;
         mouse.y = e.layerY;
       }
       else {
         mouse.x = e.pageX - $(canvas).offset().left;
         mouse.y = e.pageY - $(canvas).offset().top;
       }
     });
 
     $(window).resize(OnResize);
 
     OnResize();
 
     return result;
   }
 
   function Line(y, height, color, options, mouse) {
     var self = this;
 
     self.color = color;
     self.options = options;
     self.mouse = mouse;
     self.height = height;
     self.dots = [];
     self.y = y;
 
     self.points = [];
 
     self.reset = function (x, f) {
       self.points = [];
       for (var y = self.y; y < self.height; y += self.options.density)
         self.points.push(new Point(x, y, self.color));
     }
 
     self.update = function () {
       for (var i = 0; i < self.points.length; i++)
         self.points[i].update(self.mouse, self.options);
     }
 
     function Point(x, y) {
       this.y = y;
       this.x = x;
       this.base = { x: x, y: y };
 
       this.update = function (mouse, options) {
         var dx = this.x - mouse.x,
           dy = this.y - mouse.y,
           alpha = Math.atan2(dx, dy),
           alpha = (alpha > 0 ? alpha : 2 * Math.PI + alpha),
           d = options.radius / Math.sqrt(dx * dx + dy * dy);
 
         this.y += Math.cos(alpha) * d + (this.base.y - this.y) * options.speed;
         this.x += Math.sin(alpha) * d + (this.base.x - this.x) * options.speed;
       }
     }
   }
 
   function drawCircle(p, r, color) {
     ctx.fillStyle = color;
     ctx.beginPath();
     ctx.arc(p.x, p.y, r, 0, 2 * Math.PI, true);
     ctx.closePath();
     ctx.fill();
   }
 
    function drawLine(p1, p2) {
     ctx.beginPath();
     ctx.moveTo(p1.x, p1.y);
     ctx.lineTo(p2.x, p2.y);
     ctx.stroke();
     ctx.closePath();
   }
 
   function redraw() {
     ctx.clearRect(0, 0, canvas.width, canvas.height);
 
     for (var i = 0; i < 2; i++) {
       var points = self.lines[i].points;
 
       ctx.beginPath();
       ctx.lineWidth = 2;
       ctx.strokeStyle = self.lines[i].color;
       ctx.moveTo(points[15].x, points[15].y);
 
       for (var j = 15; j < points.length - 2; j++) {
         var point = points[j];
 
         var xc = (points[j + 1].x + point.x) / 2;
         var yc = (points[j + 1].y + point.y) / 2;
 
 
         ctx.quadraticCurveTo(point.x, point.y, xc, yc);
       }
       ctx.stroke();
       ctx.closePath();
 
 
       // Dots
       ctx.lineWidth = 1.2;
       ctx.strokeStyle = self.dotColors[i][2];
       for (var j = 0; j < self.lines[i].dots.length; j++) {
         var dot = self.lines[i].dots[j],
           id = self.targets[i][j];
           dot2 = [
             (self.lines[i].points[id].x + self.lines[i].points[id + 1].x) / 2,
             (self.lines[i].points[id].y + self.lines[i].points[id + 1].y) / 2,
           ];
 
         var p1 = { x: dot[0], y: dot[1] };
         var p2 = { x: dot2[0], y: dot2[1] };
 
 
         drawLine(p1, p2);
         drawCircle(p1, 3, self.dotColors[i][0]);
 
         drawCircle(p2, 11, self.dotColors[i][1]);
         drawCircle(p2, 5.5, self.dotColors[i][0]);
       }
     }
   }
 
    function animate() {
     rafid = requestAnimationFrame(animate);
 
     self.lines[0].update();
     self.lines[1].update();
 
     redraw();
   }
 
   self.toggle = function (run) {
     if (!self.isOK) return false;
 
     if (run === undefined)
       self.toggle(!paused);
 
     else if (!!run && paused) {
       paused = false;
       animate();
     }
     else if (!!!run) {
       paused = true;
       cancelAnimationFrame(rafid);
     }
     return true;
    }
 
 
   self.isOK = init();
}
}
/* </pre> */
new Timeline($('#cvs3').get(0)).toggle(true);
</style><!--{/if}--></includeonly>
</script>

2021年8月13日 (五) 18:31的版本

<style>

  • {
 margin: 0;

} .timeline {

 height: 100%;
 position: relative;

} .timeline canvas {

 position: absolute;
 width: 100%;
 height: 100%;
 left: 0;
 top: 45px;

} .timeline figcaption {

 font-weight: 400;
   font-size: 24px;
 text-transform: uppercase;
 -webkit-text-stroke: .25px;

} .timeline h2 {

 font-weight: 400;
   font-size: 30px;
 padding-bottom: 20px;
 color: #b2cde9!important;
  text-transform: uppercase;
  line-height: 1.2 !important;

} .timeline h6 {

 color: #0090F5!important;
   font-size: 17px;
   font-weight: 400;

} .timeline p, .timeline ol {

 font-weight: 400;
 padding: 3px 0 20px 0;
 color: #575757!important;
 text-align: justify;
 width: 70%;

} .timeline ol {

 list-style: disc;
 margin-top: -20px;
 padding-left: 40px;

} .timeline figure {

 float: right;
 width: 100%;

} .timeline article {

 position: relative;
 width: 38%;
 overflow: hidden;

} .timeline article:first-of-type {

 float: left;
 text-align: right;

} .timeline article:first-of-type p, .timeline article:first-of-type figure {

 float: right;

} .timeline article:last-of-type {

 float: right;

} .timeline article:last-of-type h2 {

 color: #c6e0aa!important;

} .timeline article:last-of-type h6, .timeline article:last-of-type a {

 color: #40aa00!important;

} .timeline article:last-of-type a:hover {

 color: #95D40D!important;

} </style> </head> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> <script>

   function Timeline(cvs) {
   var self = this,
       paused = true,
       rafid = 0,
       mouse = { x: 0, y: 0 },
       canvas = cvs,
       ctx = null;
   self.lines = [];
   self.isOK = false;
   self.options = {
       speed: 0.1,
       density: 8,
       radius: 600,
   };
   self.targets = [
       [29, 32, 48, 68],
       [29, 33, 38]
   ];
   self.dotColors = [
       ['#13669b', 'rgba(19, 102, 155, 0.3)', 'rgba(19, 102, 155, 0.08)'],
       ['#7dd317', 'rgba(113, 222, 15, 0.3)', 'rgba(91, 164, 22, 0.12)'],
   ];
   self.isPaused = function () {
       return paused;
   };
   function InitDots() {
       var tl = $('.timeline');
       var top = tl.find('h2').outerHeight();
       self.lines[0].dots = [];
       var y = top;
       tl.find('article:first figure').each(function () {
           self.lines[0].dots.push([$(this).outerWidth() + 20, y + 20]);
           y += $(this).outerHeight();
       });
       self.lines[1].dots = [];
       var y = top;
       tl.find('article:last figure').each(function () {
           self.lines[1].dots.push([canvas.width - $(this).outerWidth() - 20, y + 20]);
           y += $(this).outerHeight();
       });
   }
   function OnResize() {
       canvas.width = canvas.offsetWidth;
       canvas.height = canvas.offsetHeight;
       var wasPaused = paused;
       self.toggle(false);
       // Init lines
       self.lines[0].reset(canvas.offsetWidth / 2 - 15);
       self.lines[1].reset(canvas.offsetWidth / 2 + 15);
       InitDots();
       self.toggle(!wasPaused);
   }
   function init() {
       var result = false;
       try {
           result = !!(canvas.getContext && (ctx = canvas.getContext('2d')));
           self.lines[0] = new Line(0, canvas.offsetHeight - 100, '#4789a3', self.options, mouse);
           self.lines[1] = new Line(0, canvas.offsetHeight - 100, '#a0d59c', self.options, mouse);
       } catch (e) {
           return false;
       }
       $(canvas).mousemove(function (e) {
           if (e.offsetX) {
               mouse.x = e.offsetX;
               mouse.y = e.offsetY;
           }
           else if (e.layerX) {
               mouse.x = e.layerX;
               mouse.y = e.layerY;
           }
           else {
               mouse.x = e.pageX - $(canvas).offset().left;
               mouse.y = e.pageY - $(canvas).offset().top;
           }
       });
       $(window).resize(OnResize);
       OnResize();
       return result;
   }
   function Line(y, height, color, options, mouse) {
       var self = this;
       self.color = color;
       self.options = options;
       self.mouse = mouse;
       self.height = height;
       self.dots = [];
       self.y = y;
       self.points = [];
       self.reset = function (x, f) {
           self.points = [];
           for (var y = self.y; y < self.height; y += self.options.density)
               self.points.push(new Point(x, y, self.color));
       }
       self.update = function () {
           for (var i = 0; i < self.points.length; i++)
               self.points[i].update(self.mouse, self.options);
       }
       function Point(x, y) {
           this.y = y;
           this.x = x;
           this.base = { x: x, y: y };
           this.update = function (mouse, options) {
               var dx = this.x - mouse.x,
                   dy = this.y - mouse.y,
                   alpha = Math.atan2(dx, dy),
                   alpha = (alpha > 0 ? alpha : 2 * Math.PI + alpha),
                   d = options.radius / Math.sqrt(dx * dx + dy * dy);
               this.y += Math.cos(alpha) * d + (this.base.y - this.y) * options.speed;
               this.x += Math.sin(alpha) * d + (this.base.x - this.x) * options.speed;
           }
       }
   }
   function drawCircle(p, r, color) {
       ctx.fillStyle = color;
       ctx.beginPath();
       ctx.arc(p.x, p.y, r, 0, 2 * Math.PI, true);
       ctx.closePath();
       ctx.fill();
   }
   function drawLine(p1, p2) {
       ctx.beginPath();
       ctx.moveTo(p1.x, p1.y);
       ctx.lineTo(p2.x, p2.y);
       ctx.stroke();
       ctx.closePath();
   }
   function redraw() {
       ctx.clearRect(0, 0, canvas.width, canvas.height);
       for (var i = 0; i < 2; i++) {
           var points = self.lines[i].points;
           ctx.beginPath();
           ctx.lineWidth = 2;
           ctx.strokeStyle = self.lines[i].color;
           ctx.moveTo(points[15].x, points[15].y);
           for (var j = 15; j < points.length - 2; j++) {
               var point = points[j];
               var xc = (points[j + 1].x + point.x) / 2;
               var yc = (points[j + 1].y + point.y) / 2;


               ctx.quadraticCurveTo(point.x, point.y, xc, yc);
           }
           ctx.stroke();
           ctx.closePath();


           // Dots
           ctx.lineWidth = 1.2;
           ctx.strokeStyle = self.dotColors[i][2];
           for (var j = 0; j < self.lines[i].dots.length; j++) {
               var dot = self.lines[i].dots[j],
                   id = self.targets[i][j];
                   dot2 = [
                       (self.lines[i].points[id].x + self.lines[i].points[id + 1].x) / 2,
                       (self.lines[i].points[id].y + self.lines[i].points[id + 1].y) / 2,
                   ];
               var p1 = { x: dot[0], y: dot[1] };
               var p2 = { x: dot2[0], y: dot2[1] };


               drawLine(p1, p2);
               drawCircle(p1, 3, self.dotColors[i][0]);
               drawCircle(p2, 11, self.dotColors[i][1]);
               drawCircle(p2, 5.5, self.dotColors[i][0]);
           }
       }
   }
   function animate() {
       rafid = requestAnimationFrame(animate);
       self.lines[0].update();
       self.lines[1].update();
       redraw();
   }
   self.toggle = function (run) {
       if (!self.isOK) return false;
       if (run === undefined)
           self.toggle(!paused);
       else if (!!run && paused) {
           paused = false;
           animate();
       }
       else if (!!!run) {
           paused = true;
           cancelAnimationFrame(rafid);
       }
       return true;
   }


   self.isOK = init();

} new Timeline($('#cvs3').get(0)).toggle(true); </script>