Greasy Fork is available in English.

Pixiv hover zoom

hover zoom for Pixiv

  1. /* global window, document, jQuery */
  2.  
  3. // ==UserScript==
  4. // @name Pixiv hover zoom
  5. // @namespace https://github.com/rplus
  6. // @version 1.1.2
  7. // @description hover zoom for Pixiv
  8. // @author Rplus
  9. // @include http://www.pixiv.net/*
  10. // @grant none
  11. // ==/UserScript==
  12.  
  13. ;(function(window, document, $) {
  14. 'use strict';
  15.  
  16. var phzw = $('#pixiv-hz-wrap');
  17. var phzwPos = [];
  18. var phzwPattern = /member_illust\.php\?mode=medium&illust_id=(\d+)/;
  19. var phzwAPI = '//www.pixiv.net/rpc/index.php?mode=get_illust_detail_by_ids&illust_ids=';
  20. var phzwAPICache = {};
  21. var imgSize = 'm'; // size: '240mw', m', 'big'
  22. var body = document.body;
  23. var isAutoLoadNextPage = true;
  24. var pager = {};
  25.  
  26. var phzwToggle = function(_switch) {
  27. if (_switch) {
  28. phzw.css({
  29. 'top': phzwPos[0],
  30. 'left': phzwPos[1],
  31. 'opacity': 1,
  32. 'visibility': 'visible',
  33. 'transform': 'translateX(' + phzwPos[2] + '%)'
  34. });
  35. } else {
  36. if ('0' !== phzw[0].style.opacity) {
  37. phzw.css({
  38. 'visibility': 'hidden',
  39. 'opacity': 0
  40. });
  41. }
  42. }
  43. };
  44.  
  45. var getAllId = function() {
  46. var ids = [];
  47.  
  48. $.each($('#wrapper').find('a'), function() {
  49. var _href = $(this).attr('href');
  50. var _match = _href && _href.match(phzwPattern);
  51. if (_match) {
  52. ids.push(_match.pop());
  53. }
  54. });
  55.  
  56. return ids;
  57. };
  58.  
  59. var pullIdsData = function(idsArr) {
  60. var deferred = $.Deferred();
  61.  
  62. $.getJSON(phzwAPI + idsArr.join())
  63. .done(function(data) {
  64.  
  65. if (!data.error) {
  66. for (var _item in data.body) {
  67. if (data.body.hasOwnProperty(_item)) {
  68. phzwAPICache[_item] = data.body[_item];
  69. }
  70. }
  71. deferred.resolve(); //update state
  72. } else {
  73. deferred.reject();
  74. }
  75.  
  76. })
  77. .fail(function() {
  78. deferred.reject();
  79. });
  80.  
  81. return deferred.promise();
  82. };
  83.  
  84. var render = function(_id) {
  85. var data = phzwAPICache[_id];
  86. if (!data) { return; }
  87.  
  88. if (_id !== phzw.data('id')) {
  89. var tpl = '<a href="/member_illust.php?mode=medium&illust_id=' + _id + '"><img src="' + data.url[imgSize] + '" title="' + data.illust_title + '"></a>';
  90. phzw.html(tpl);
  91.  
  92. phzw.data('id', _id);
  93. }
  94.  
  95. phzwToggle(true);
  96. };
  97.  
  98. var updatePos = function(ele) {
  99. var eleRect = ele.getBoundingClientRect();
  100. phzwPos = [eleRect.top + body.scrollTop + eleRect.height, eleRect.left, -100 * eleRect.left / body.scrollWidth];
  101. };
  102.  
  103. $(function() {
  104.  
  105. // phzw init
  106. if (!phzw.length) {
  107. $(body).append('<div id="pixiv-hz-wrap" />');
  108. phzw = $('#pixiv-hz-wrap').css({
  109. 'position': 'absolute',
  110. 'visibility': 'hidden',
  111. 'opacity': 0,
  112. 'box-shadow': '0 0 0 3px #fff, 0 0 3px 3px',
  113. 'transition': 'all .3s',
  114. 'z-index': '1000'
  115. });
  116.  
  117. phzw.on('mouseenter', function() {
  118. phzw.one('mouseleave', function() {
  119. phzwToggle(false);
  120. });
  121. });
  122. }
  123.  
  124. // delay pre-load data in page
  125. setTimeout(function() {
  126. pullIdsData(getAllId());
  127. }, 1000);
  128.  
  129. $('#wrapper').on('mouseenter.phzw', 'a', function(e) {
  130. var _match = $(this).attr('href').match(phzwPattern);
  131.  
  132. if (!_match) { return; }
  133.  
  134. var _id = _match.pop();
  135.  
  136. e.stopPropagation();
  137. updatePos(this);
  138.  
  139. if (phzwAPICache[_id]) {
  140. render(_id);
  141. } else {
  142. $.when(pullIdsData([_id]))
  143. .then(function() {
  144. render(_id);
  145. });
  146. }
  147. });
  148.  
  149. $(document).on('click.phzw', function() {
  150. phzwToggle(false);
  151. });
  152.  
  153. if (isAutoLoadNextPage) {
  154. pager.container = $('.pager-container').eq(0);
  155.  
  156. if (!pager.container.length) { return; }
  157.  
  158. pager.current = pager.container.find('li.current').text();
  159. pager.baseHref = pager.container.find('a')[0].href.replace(/&p=\d+/, '');
  160. pager.parent = $('._image-items').eq(0).parent();
  161.  
  162. var autoLoadNextPage = function() {
  163. var nextPage = pager.current * 1 + 1;
  164. var nextPageHref = pager.baseHref + '&p=' + nextPage;
  165. var separator = '<hr style="border: 1px dashed #ccc" /><a href="' + nextPageHref + '">::: page: ' + nextPage + '</a>';
  166.  
  167. if (nextPage > pager.max) {
  168. $(window).off('scroll.autoLoadNextPage');
  169. return;
  170. }
  171.  
  172. // prepare a div container for ajax lond next-page content
  173. $('<div />').appendTo( pager.parent.append(separator) )
  174. .load(nextPageHref + ' ._image-items', function(_html) {
  175. pager.current = nextPage;
  176. pager.loading = false;
  177.  
  178. // check for max page
  179. var nextPagerLists = _html.match(/pager-container.+?(<ul .+?<\/ul>)/).pop();
  180. pager.max = $(nextPagerLists).find('li').last().text() * 1;
  181. });
  182. };
  183.  
  184. $(window).on('scroll.autoLoadNextPage', function() {
  185. if (!pager.loading && (pager.parent[0].getBoundingClientRect().bottom < document.documentElement.clientHeight * .3)) {
  186. pager.loading = true;
  187. autoLoadNextPage();
  188. }
  189. });
  190. }
  191.  
  192. $('.link-item').eq(0).prepend('<button>-♥ preload all ♥-</button>').find('button').on('click', function(e) {
  193. e.preventDefault();
  194.  
  195. $.when(pullIdsData(getAllId()))
  196. .then(function() {
  197. $.each(phzwAPICache, function(key, val) {
  198. // forcedly preload
  199. $('<img src="' + val.url[imgSize] + '">');
  200. });
  201. });
  202.  
  203. });
  204. });
  205.  
  206. })(window, document, jQuery, undefined);