calculator.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. function drawSummaries() {
  2. for (var oHtml = $('<div class="j-tree-summaries"></div>'), tree = 0; 3 > tree; tree++) oHtml.append($("<div>").addClass("tree-summary").addClass(treeNames[tree]).attr("data-idx", tree).text(treeNames[tree] + ": 0").css({
  3. left: TREE_OFFSET * tree + 10,
  4. cursor: "pointer"
  5. }));
  6. return oHtml
  7. }
  8. function drawCalculator() {
  9. for (var $calculator = $('<div class="j-calculator tallent__list"></div>'), tree = 0; 3 > tree; tree++)
  10. for (var index = 0; index < data[tree].length; index++) {
  11. drawButton(tree, index, $calculator);
  12. }
  13. var tip, maxDims = {
  14. width: $calculator.parent().width(),
  15. height: $calculator.parent().height()
  16. };
  17. return $calculator.append($("<div>").addClass("j-tooltip").append($("<strong>")).append($("<div>").addClass("rank")).append($("<div>").addClass("req")).append($("<p>").addClass("tooltip-text").addClass("first")).append($("<p>").addClass("tooltip-text").addClass("second").append($("<div>").addClass("nextRank").text("下一层:")).append($("<div>").addClass("content")))), tip = $calculator.find(".j-tooltip"), $calculator.mousemove(function(event) {
  18. if (tip.is(":visible")) {
  19. var pos = $calculator.offset(),
  20. offsetX = 20,
  21. offsetY = 20;
  22. event.pageY - pos.top + tip.height() > maxDims.height && (offsetY = -tip.height() - 30), event.pageX - pos.left > tip.width() && (offsetX = -tip.width()), tip.css({
  23. left: event.pageX - pos.left + offsetX,
  24. top: event.pageY - pos.top + offsetY
  25. })
  26. }
  27. }), $calculator
  28. }
  29. function deltaMastery(tree, index, rank, deltaR) {
  30. if (isValidState(tree, index, rank, deltaR)) {
  31. var previous = masteryTierFull(tree, index);
  32. previous >= 0 && deltaR > 0 ? setState(tree, previous, state[tree][previous], -deltaR) : deltaR > 0 && masteryTierEmpty(tree, data[tree][index].tier) && data[tree][index].ranks > 1 && totalPoints + data[tree][index].ranks <= MAX_POINTS && (deltaR = data[tree][index].ranks), setState(tree, index, rank, deltaR)
  33. }
  34. }
  35. function drawButton(tree, index, $root) {
  36. var spritePos = masterySpritePos(tree, index),
  37. buttonPos = masteryButtonPosition(tree, index),
  38. status = 0 == data[tree][index].tier ? "available" : "unavailable",
  39. rank = 0,
  40. tier = data[tree][index].tier;
  41. $root.append($("<div>").addClass("button").addClass(status).css({
  42. left: buttonPos.x + "px",
  43. top: buttonPos.y + "px",
  44. backgroundPosition: ("full" == status ? -2 : "available" == status ? -2 - BUTTON_SIZE : -2 - 2 * BUTTON_SIZE) + "px " + (spritePos - 1) + "px"
  45. }).append($("<div>").addClass("buttonFrame").css({
  46. backgroundPosition: ("full" == status ? tier % 2 == 1 ? 1 == tier ? -76 : -38 * tier : -38 : "available" == status ? -38 : 0) + "px " + ("full" == status ? 3 == tier ? -38 : 5 == tier ? -76 : 0 : 0) + "px"
  47. })).append($("<div>").addClass("counter").addClass("counter-" + status).text("0/" + data[tree][index].ranks).css({
  48. visibility: data[tree][index].tier % 2 == 0 ? "visible" : "hidden"
  49. })).mouseenter(function() {
  50. var $tooltip = $(this).parents(".j-calculator").find(".j-tooltip"),
  51. tooltipText = masteryTooltip(tree, index, rank);
  52. formatTooltip($tooltip.show(), tooltipText), $(this).data("hover", !0), $(this).parent().mousemove()
  53. }).mouseleave(function() {
  54. var $tooltip = $(this).parents(".j-calculator").find(".j-tooltip");
  55. $tooltip.hide(), $tooltip.data("hover", !1)
  56. }).data("update", function() {
  57. rank = state[tree][index] || 0, rank > 0 ? status = "full" : (status = masteryPointReq(tree, index) <= treePoints(tree) ? "available" : "unavailable", totalPoints >= MAX_POINTS && (status = masteryTierFull(tree, index) >= 0 ? "available" : "unavailable")), $(this).hasClass(status) || $(this).removeClass(buttonClasses.join(" ")).addClass(status).css({
  58. backgroundPosition: ("full" == status ? -2 : "available" == status ? -2 - BUTTON_SIZE : -2 - 2 * BUTTON_SIZE) + "px " + (spritePos - 2) + "px"
  59. });
  60. var counter = $(this).find(".counter").text(rank + "/" + data[tree][index].ranks);
  61. counter.hasClass("counter-" + status) || counter.removeClass(counterClasses.join(" ")).addClass("counter-" + status), $(this).find(".buttonFrame").css({
  62. backgroundPosition: ("full" == status ? tier % 2 == 1 ? 1 == tier ? -76 : -38 * tier : -38 : "available" == status ? -38 : 0) + "px " + ("full" == status ? 3 == tier ? -38 : 5 == tier ? -76 : 0 : 0) + "px"
  63. }), $(this).data("hover") && $(this).mouseover()
  64. }))
  65. }
  66. function customTooltip(tooltip, tooltipText) {
  67. tooltip.addClass("custom"), tooltip.children(":not(p.first)").hide(), tooltip.find("p.first").text(tooltipText)
  68. }
  69. function formatTooltip(tooltip, tooltipText) {
  70. tooltip.removeClass("custom");
  71. var head = tooltip.find("strong").text(tooltipText.header).show();
  72. head.hasClass(treeNames[tooltipText.tree]) || head.removeClass(treeNames.join(" ")).addClass(treeNames[tooltipText.tree]);
  73. var rank = tooltip.find(".rank").text(tooltipText.rank).show();
  74. rank.hasClass(tooltipText.rankClass) || rank.removeClass(rankClasses.join(" ")).addClass(tooltipText.rankClass), tooltip.find(".req").text(tooltipText.req).show(), tooltip.find("p.first").html(tooltipText.body);
  75. var second = tooltip.find("p.second");
  76. null == tooltipText.bodyNext ? second.hide() : second.show().find(".content").html(tooltipText.bodyNext)
  77. }
  78. function masteryTooltip(tree, index, rank) {
  79. var mastery = data[tree][index],
  80. showNext = !(1 > rank || rank >= mastery.ranks),
  81. text = {
  82. tree: tree,
  83. header: mastery.name,
  84. rank: "等级: " + rank + "/" + mastery.ranks,
  85. rankClass: rank == mastery.ranks ? rankClasses[2] : isValidState(tree, index, rank, 1) ? rankClasses[1] : rankClasses[0],
  86. req: masteryTooltipReq(tree, index),
  87. body: masteryTooltipBody(mastery, rank),
  88. bodyNext: showNext ? masteryTooltipBody(mastery, rank + 1) : null
  89. };
  90. return text
  91. }
  92. function masteryTooltipBody(mastery, rank) {
  93. rank = Math.max(0, rank - 1);
  94. var desc = mastery.desc;
  95. return desc = desc.replace(/#/, mastery.rankInfo[rank]), desc = desc.replace(/\n/g, "<br>"), desc = desc.replace(/\|(.+?)\|/g, "<span class='highlight'>$1</span>"), mastery.rankInfo2 && (desc = desc.replace(/#/, mastery.rankInfo2[rank])), mastery.perLevel && (desc = desc.replace(/#/, Math.round(100 * mastery.perLevel[rank]) / 100)), mastery.perLevel2 && (desc = desc.replace(/#/, Math.round(100 * mastery.perLevel[rank]) / 100)), desc
  96. }
  97. function masteryTooltipReq(tree, index) {
  98. var missing = [],
  99. pointReq = masteryPointReq(tree, index);
  100. if (pointReq > treePoints(tree) && missing.push("需要" + pointReq + "点天赋投入" + treeNames[tree]), (state[tree][index] || 0) < data[tree][index].ranks) {
  101. var existing = masteryTierFull(tree, index);
  102. existing >= 0 && missing.push("选择这个将会移除在" + data[tree][existing].name + "的天赋点数。")
  103. }
  104. return missing.join("\n")
  105. }
  106. function masteryButtonPosition(tree, index) {
  107. var idx = data[tree][index].index - 1,
  108. ix = idx % 4,
  109. iy = data[tree][index].tier,
  110. x = 0,
  111. y = 0;
  112. x += TREE_OFFSET * tree;
  113. x += SPACING.margin_left;
  114. if((tree==0 || tree==1) && index >=2 && index <= 4){
  115. }else{
  116. if (iy % 2 == 1 && iy != 5 && iy != 1) x += SPACING.margin_keystone; // 偶数行的偏移
  117. }
  118. y += SPACING.margin_top;
  119. x += ix * (BUTTON_SIZE + SPACING.spacing_x); //x 的最终偏移 单行第2个为2 * (54 + 13) 偶数为 1* (54+13)
  120. y += iy * (BUTTON_SIZE + SPACING.spacing_y); // y的最终偏移 为 (54+上边距) * 行数
  121. var dwOffset = 10;
  122. if(tree==0){
  123. if(index==2||index==7||index==12){x=20 + dwOffset;}
  124. if(index==3||index==8||index==13){x=61 + dwOffset;}
  125. if(index==4||index==9||index==14){x=100 + dwOffset;}
  126. if(index==0||index==5||index==10){x=39 + dwOffset;}
  127. if(index==1||index==6||index==11){x=83 + dwOffset;}
  128. }
  129. if(tree==1){
  130. if(index==2||index==7||index==12){x=184 + dwOffset;}
  131. if(index==3||index==8||index==13){x=225 + dwOffset;}
  132. if(index==4||index==9||index==14){x=266 + dwOffset;}
  133. if(index==0||index==5||index==10){x=202 + dwOffset;}
  134. if(index==1||index==6||index==11){x=246 + dwOffset;}
  135. }
  136. if(tree==2){
  137. if(index==2||index==7||index==12){x=352 + dwOffset;}
  138. if(index==3||index==8||index==13){x=393 + dwOffset;}
  139. if(index==4||index==9||index==14){x=434 + dwOffset;}
  140. if(index==0||index==5||index==10){x=371 + dwOffset;}
  141. if(index==1||index==6||index==11){x=415 + dwOffset;}
  142. }
  143. return {x: x, y: y};
  144. }
  145. function masterySpritePos(tree, index) {
  146. return 0 - BUTTON_SIZE * (treeOffsets[tree] + index)
  147. }
  148. function masteryTier(tree, index) {
  149. return data[tree][index].tier
  150. }
  151. function masteryPointReq(tree, index) {
  152. return TIER_REQS[masteryTier(tree, index)]
  153. }
  154. function masteryTierFull(tree, index) {
  155. var tier = data[tree][index].tier;
  156. for (var i in data[tree])
  157. if (i != index && data[tree][i].tier == tier && (state[tree][i] || 0) + (state[tree][index] || 0) >= data[tree][i].ranks) return i;
  158. return -1
  159. }
  160. function masteryTierEmpty(tree, tier) {
  161. for (var i in data[tree])
  162. if (data[tree][i].tier == tier && (state[tree][i] || 0) > 0) return !1;
  163. return !0
  164. }
  165. function treePoints(tree, treeTier) {
  166. var points = 0;
  167. for (var i in state[tree])(!treeTier || treeTier > masteryTier(tree, i)) && (points += state[tree][i]);
  168. return points
  169. }
  170. function isValidState(tree, index, rank, mod) {
  171. var mastery = data[tree][index];
  172. if (0 > rank + mod || rank + mod > mastery.ranks) return !1;
  173. if (mod > 0) {
  174. if (totalPoints + mod > MAX_POINTS) return masteryTierFull(tree, index) >= 0 ? !0 : !1;
  175. if (masteryPointReq(tree, index) > treePoints(tree) - rank) return !1
  176. }
  177. if (0 > mod) {
  178. for (var i in state[tree])
  179. if (i != index && state[tree][i] > 0 && masteryPointReq(tree, i) > treePoints(tree, masteryTier(tree, i)) - (masteryTier(tree, index) < masteryTier(tree, i))) return !1;
  180. for (var i in state[tree])
  181. if (i != index && state[tree][i] > 0 && data[tree][i].parent == index) return !1
  182. }
  183. return !0
  184. }
  185. function setState(tree, index, rank, mod) {
  186. state[tree][index] = rank + mod, totalPoints += mod, updateButtons(), updateLabels()
  187. }
  188. function resetStates(quiet) {
  189. for (var tree = 0; 3 > tree; tree++) resetTree(tree);
  190. 1 != quiet && (updateButtons(), updateLabels())
  191. }
  192. function resetTree(tree) {
  193. totalPoints -= treePoints(tree);
  194. for (var index in state[tree]) state[tree][index] = 0
  195. }
  196. function updateButtons($dom) {
  197. $dom.find(".button").each(function() {
  198. $(this).data("update").call(this, 0)
  199. })
  200. }
  201. function updateLabels($dom, $con) {
  202. for (var tree = 0; 3 > tree; tree++) {
  203. var points = treePoints(tree);
  204. $dom.find("div[data-idx=" + tree + "]").text(treeNames[tree] + ": " + points), $con.find(".meda" + (tree + 1)).html(points)
  205. }
  206. }
  207. function escapeHtml(str) {
  208. var entityMap = {
  209. "&": "&amp;",
  210. "<": "&lt;",
  211. ">": "&gt;",
  212. '"': "&quot;",
  213. "'": "&#39;",
  214. "/": "&#x2F;"
  215. };
  216. return String(str).replace(/[&<>"'\/]/g, function(s) {
  217. return entityMap[s]
  218. })
  219. }
  220. function exportMasteries() {
  221. var tree, str = "",
  222. bits = 0,
  223. collected = 0,
  224. jumpStart = -1,
  225. flush = function() {
  226. str += exportChars[(jumpStart > -1) << maxbits | bits], bits = 0, collected = 0, jumpStart = -1
  227. };
  228. for (tree = 0; 3 > tree; tree++) {
  229. for (var index = 0; index < data[tree].length; index++) {
  230. var space = bitfit(tree, index, maxbits - collected);
  231. if (1 > space && (flush(), space = bitfit(tree, index, maxbits)), !(jumpStart > -1) || state[tree][index] > 0)
  232. if (collected > 0 || [0, 1, 2, 3, 4].filter(function(a) {
  233. return space > a
  234. }).map(function(a) {
  235. return state[tree][index + a] || 0
  236. }).some(function(a) {
  237. return a > 0
  238. })) {
  239. jumpStart > -1 && (bits = index - jumpStart, flush());
  240. var len = bitlen(tree, index);
  241. bits = bits << len | (state[tree][index] || 0), collected += len
  242. } else 0 > jumpStart && (collected > 0 && flush(), jumpStart = index)
  243. }
  244. jumpStart > -1 ? (bits = index - jumpStart, flush()) : collected > 0 && flush()
  245. }
  246. return str
  247. }
  248. function importMasteries(param, $list, $sum, $con, championsId) {
  249. var str = param.talent_link,
  250. title = param.talent_title;
  251. resetStates(true);
  252. for (var tree = 0, index = 0, i = 0; i < str.length; i++) {
  253. var cur = importChars[str.charAt(i)];
  254. if (void 0 == cur) return;
  255. if (0 == (32 & cur))
  256. for (var num = bitfit(tree, index, maxbits), sizes = [0, 1, 2, 3, 4].filter(function(a) {
  257. return num > a
  258. }).map(function(a) {
  259. return bitlen(tree, index + a)
  260. }), j = 0; j < sizes.length; j++, index++) {
  261. var shift = sizes.slice(j + 1).reduce(function(a, b) {
  262. return a + b
  263. }, 0),
  264. value = cur >> shift & (1 << sizes[j]) - 1;
  265. state[tree][index] = value, totalPoints += value
  266. } else {
  267. var dist = 31 & cur;
  268. index += dist
  269. }
  270. if (index >= data[tree].length && (tree++, index = 0, tree >= data.length)) break
  271. }
  272. var returnData = {
  273. talent_title: title,
  274. talent_data: state
  275. },
  276. $apply = $con.find(".btn_apply");
  277. $apply.attr("href", $apply.attr("href") + "?championsId=" + championsId + "&data=" + $.base64.btoa(encodeURIComponent(JSON.stringify(returnData))));
  278. updateButtons($list);
  279. updateLabels($sum, $con)
  280. }
  281. for (var treeNames = ["凶猛", "诡诈", "坚决"], treeOffsets = [0, data[0].length, data[0].length + data[1].length], MAX_POINTS = 30, TIER_REQS = [0, 5, 6, 11, 12, 17], TREE_OFFSET = 166, SPACING = {
  282. margin_left: 32,
  283. margin_top: 10,
  284. margin_keystone: 26,
  285. spacing_x: 10,
  286. spacing_y: 12
  287. }, BUTTON_SIZE = 28, state = [{}, {}, {}], totalPoints = 0, buttonClasses = ["unavailable", "available", "full"], rankClasses = ["num-unavailable", "num-available", "num-full"], counterClasses = ["counter-unavailable", "counter-available", "counter-full"], maxbits = 5, exportChars = "WvlgUCsA7pGZ3zSjakbP2x0mTB6htH8JuKMq1yrnwEQDLY5IVNXdcioe9fF4OR_-", bitlen = function(tree, index) {
  288. return void 0 == data[tree][index] ? 0 : Math.floor(data[tree][index].ranks / 2) + 1
  289. }, bitfit = function(tree, index, bits) {
  290. for (var start = index;;) {
  291. var len = bitlen(tree, index);
  292. if (len > bits || 0 == len) return index - start;
  293. bits -= len, index++
  294. }
  295. }, importChars = {}, i = 0; i < exportChars.length; i++) importChars[exportChars.charAt(i)] = i;
  296. Array.prototype.filter || (Array.prototype.filter = function(fun) {
  297. "use strict";
  298. if (void 0 === this || null === this) throw new TypeError;
  299. var t = Object(this),
  300. len = t.length >>> 0;
  301. if ("function" != typeof fun) throw new TypeError;
  302. for (var res = [], thisArg = arguments.length >= 2 ? arguments[1] : void 0, i = 0; len > i; i++)
  303. if (i in t) {
  304. var val = t[i];
  305. fun.call(thisArg, val, i, t) && res.push(val)
  306. }
  307. return res
  308. }), Array.prototype.map || (Array.prototype.map = function(callback, thisArg) {
  309. var T, A, k;
  310. if (null == this) throw new TypeError(" this is null or not defined");
  311. var O = Object(this),
  312. len = O.length >>> 0;
  313. if ("function" != typeof callback) throw new TypeError(callback + " is not a function");
  314. for (arguments.length > 1 && (T = thisArg), A = new Array(len), k = 0; len > k;) {
  315. var kValue, mappedValue;
  316. k in O && (kValue = O[k], mappedValue = callback.call(T, kValue, k, O), A[k] = mappedValue), k++
  317. }
  318. return A
  319. }), Array.prototype.some || (Array.prototype.some = function(fun) {
  320. "use strict";
  321. if (null == this) throw new TypeError("Array.prototype.some called on null or undefined");
  322. if ("function" != typeof fun) throw new TypeError;
  323. for (var t = Object(this), len = t.length >>> 0, thisArg = arguments.length >= 2 ? arguments[1] : void 0, i = 0; len > i; i++)
  324. if (i in t && fun.call(thisArg, t[i], i, t)) return !0;
  325. return !1
  326. }), Array.prototype.reduce || (Array.prototype.reduce = function(callback) {
  327. if (null == this) throw new TypeError("Array.prototype.reduce called on null or undefined");
  328. if ("function" != typeof callback) throw new TypeError(callback + " is not a function");
  329. var value, t = Object(this),
  330. len = t.length >>> 0,
  331. k = 0;
  332. if (2 == arguments.length) value = arguments[1];
  333. else {
  334. for (; len > k && !(k in t);) k++;
  335. if (k >= len) throw new TypeError("Reduce of empty array with no initial value");
  336. value = t[k++]
  337. }
  338. for (; len > k; k++) k in t && (value = callback(value, t[k], k, t));
  339. return value
  340. });