PageSourceSearch

https://visualbaseball.com/pub/js/stat-format.js?v=1

js visualbaseball.com collected 2026-10-02 00:59:49 UTC 7,198 bytes, 194 lines download raw bytes

1/* ═══════════════════════════════════════════════════
2   stat-format.js — 통계 포맷 헬퍼 단일 출처
3
4   정본 정의: application/config/stat_defs.php
5   로딩 위치: data.js 직후 (다른 모든 JS 파일이 의존)
6
7   기존 fmtIp 가 game.js / render.js / beeswarm.js 3 곳에 중복
8   정의되어 있던 문제를 해소. window.VBStat.* 네임스페이스 + 하위
9   호환을 위한 window.fmtIp / window.fmtRate2 alias 동시 노출.
10   ═══════════════════════════════════════════════════ */
11(function (root) {
12  'use strict';
13
14  // ── 이닝(IP) ──────────────────────────────────────
15  // outs 정수가 정본. 표기 3 종을 모두 outs 또는 KBO 표기 string("5.1")
16  // 입력으로 받아서 분수/KBO/십진으로 변환한다.
17  function ipInputToOuts(v) {
18    if (v == null || v === '') return null;
19    if (typeof v === 'number' && isFinite(v)) {
20      // 십진 또는 KBO 표기 모두 *3 후 round 가 정확
21      // - "5.0" → 5.0 → 15  (5 * 3)
22      // - "5.1" → 5.1 → 15.3 → 15  (오류! KBO 표기를 십진으로 받으면 불일치)
23      // 따라서 number 는 십진(이닝 1.667 같은 raw)일 때만 사용. KBO 표기는 반드시 string.
24      return Math.round(v * 3);
25    }
26    var s = String(v).trim();
27    if (s === '' || s === '-' || s === '—') return null;
28    // 분수 표기 "5 1/3" 같은 입력
29    var m = s.match(/^(\d+)\s+(\d)\/3$/);
30    if (m) return parseInt(m[1], 10) * 3 + parseInt(m[2], 10);
31    // KBO 표기 "5.1" / "5.2" / "5"
32    var dot = s.indexOf('.');
33    if (dot < 0) {
34      var n = parseInt(s, 10);
35      return isNaN(n) ? null : n * 3;
36    }
37    var full = parseInt(s.substring(0, dot), 10);
38    var rem = s.charAt(dot + 1);
39    if (isNaN(full)) return null;
40    if (rem === '0') return full * 3;
41    if (rem === '1') return full * 3 + 1;
42    if (rem === '2') return full * 3 + 2;
43    // "5.5" 같은 진짜 십진은 number 로 들어와야 함. 여기 도달하면 fallback.
44    var f = parseFloat(s);
45    return isNaN(f) ? null : Math.round(f * 3);
46  }
47
48  // outs(정수) → KBO 표기 "5.1"
49  function ipKbo(outs) {
50    if (outs == null || outs === '') return '-';
51    var n = parseInt(outs, 10);
52    if (isNaN(n)) return '-';
53    var full = Math.floor(n / 3);
54    var rem = n % 3;
55    return rem === 0 ? String(full) : (full + '.' + rem);
56  }
57
58  // outs(정수) → HTML 분수 "5<sup>1</sup>/<sub>3</sub>"
59  function ipFraction(outs) {
60    if (outs == null || outs === '') return '-';
61    var n = parseInt(outs, 10);
62    if (isNaN(n)) return '-';
63    var full = Math.floor(n / 3);
64    var rem = n % 3;
65    if (rem === 0) return String(full);
66    var frac = rem === 1
67      ? '<sup>1</sup>/<sub>3</sub>'
68      : '<sup>2</sup>/<sub>3</sub>';
69    return (full === 0 ? '' : full) + frac;
70  }
71
72  // outs(정수) → 유니코드 분수 "5⅓" (SVG/text 용)
73  function ipFractionText(outs) {
74    if (outs == null || outs === '') return '-';
75    var n = parseInt(outs, 10);
76    if (isNaN(n)) return '-';
77    var full = Math.floor(n / 3);
78    var rem = n % 3;
79    if (rem === 0) return String(full);
80    var frac = rem === 1 ? '⅓' : '⅔';
81    return (full === 0 ? '' : full) + frac;
82  }
83
84  // outs(정수) → 십진 1.667 형태 (정렬·비교용)
85  function ipDecimal(outs) {
86    if (outs == null || outs === '') return null;
87    var n = parseInt(outs, 10);
88    if (isNaN(n)) return null;
89    return Math.round(n / 3 * 1000) / 1000;
90  }
91
92  // ── 호환용: 기존 fmtIp("5.1") 시그니처 그대로 받음 ──
93  // 기존 game.js / render.js / beeswarm.js 의 fmtIp 가
94  // `String("5.1")` 또는 `Number(5.1)` 등 다양한 입력을 받았는데,
95  // 모두 outs 로 환산 후 분수 HTML 반환.
96  function fmtIp(v) {
97    if (v == null) return '-';
98    var outs;
99    if (typeof v === 'number') {
100      // beeswarm 의 ipNum 처럼 십진 이닝(36.667) 으로 들어오는 케이스
101      outs = Math.round(v * 3);
102    } else {
103      outs = ipInputToOuts(v);
104    }
105    if (outs == null) return String(v);
106    return ipFraction(outs);
107  }
108
109  // ── 비율 포맷 ─────────────────────────────────────
110  function rate2(v) {
111    if (v == null || v === '' || v === '-') return '-';
112    var n = parseFloat(v);
113    return isNaN(n) ? String(v) : n.toFixed(2);
114  }
115
116  function rate3(v) {
117    if (v == null || v === '' || v === '-') return '-';
118    var n = parseFloat(v);
119    return isNaN(n) ? String(v) : n.toFixed(3);
120  }
121
122  function pct1(v) {
123    if (v == null || v === '' || v === '-') return '-';
124    var n = parseFloat(v);
125    return isNaN(n) ? String(v) : n.toFixed(1) + '%';
126  }
127
128  // 0.391 → ".391", 1.049 → "1.049"
129  function avg3(v) {
130    if (v == null || v === '' || v === '-') return '-';
131    var n = parseFloat(v);
132    if (isNaN(n)) return String(v);
133    var s = n.toFixed(3);
134    return Math.abs(n) < 1
135      ? s.replace(/^-?0/, function (m) { return m === '-0' ? '-' : ''; })
136      : s;
137  }
138
139  function intFmt(v) {
140    if (v == null || v === '' || v === '-') return '-';
141    var n = parseFloat(v);
142    return isNaN(n) ? String(v) : String(Math.round(n));
143  }
144
145  // ── outs 기반 안전 합산 (parseFloat("5.1") 사고 차단) ──
146  // rows: 각 row 가 .outs 또는 .ip 필드를 가진 배열
147  function sumIpOuts(rows, outsKey) {
148    outsKey = outsKey || 'outs';
149    var total = 0;
150    for (var i = 0; i < rows.length; i++) {
151      var r = rows[i];
152      if (r == null) continue;
153      var o = parseInt(r[outsKey], 10);
154      if (!isNaN(o)) {
155        total += o;
156        continue;
157      }
158      // outs 필드 없으면 ip 문자열로 폴백
159      var fromIp = ipInputToOuts(r.ip);
160      if (fromIp != null) total += fromIp;
161    }
162    return total;
163  }
164
165  // ── 노출 ──────────────────────────────────────────
166  var VBStat = {
167    // IP
168    ipInputToOuts: ipInputToOuts,
169    ipKbo: ipKbo,
170    ipFraction: ipFraction,
171    ipFractionText: ipFractionText,
172    ipDecimal: ipDecimal,
173    fmtIp: fmtIp,            // 호환용 별칭
174    sumIpOuts: sumIpOuts,
175    // 비율
176    rate2: rate2,
177    rate3: rate3,
178    pct1: pct1,
179    avg3: avg3,
180    intFmt: intFmt,
181    fmtRate2: rate2          // 호환용 별칭
182  };
183
184  root.VBStat = VBStat;
185
186  // 기존 코드 하위 호환 — game.js / render.js / beeswarm.js 의
187  // 자체 fmtIp 정의를 제거하고 alias 만 남길 수 있도록 미리 노출.
188  if (typeof root.fmtIp !== 'function')      root.fmtIp = fmtIp;
189  if (typeof root.fmtIpText !== 'function')  root.fmtIpText = function (v) {
190    var outs = (typeof v === 'number') ? Math.round(v * 3) : ipInputToOuts(v);
191    return outs == null ? String(v) : ipFractionText(outs);
192  };
193  if (typeof root.fmtRate2 !== 'function')   root.fmtRate2 = rate2;
194})(typeof window !== 'undefined' ? window : this);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.