danoniplus 50.5.0 → 50.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/js/danoni_main.js CHANGED
@@ -4,12 +4,12 @@
4
4
  *
5
5
  * Source by tickle
6
6
  * Created : 2018/10/08
7
- * Revised : 2026/09/13
7
+ * Revised : 2026/09/15
8
8
  *
9
9
  * https://github.com/cwtickle/danoniplus
10
10
  */
11
- const g_version = `Ver 50.5.0`;
12
- const g_revisedDate = `2026/09/13`;
11
+ const g_version = `Ver 50.5.1`;
12
+ const g_revisedDate = `2026/09/15`;
13
13
 
14
14
  // カスタム用バージョン (danoni_custom.js 等で指定可)
15
15
  let g_localVersion = ``;
@@ -1986,6 +1986,34 @@ const getLoadingLabel = () => createDivCss2Label(`lblLoading`, g_lblNameObj.nowL
1986
1986
  siz: g_limitObj.setLblSiz, align: C_ALIGN_RIGHT,
1987
1987
  });
1988
1988
 
1989
+ /**
1990
+ * Canvasの作成 (拡張属性対応)
1991
+ * @param {string} _id
1992
+ * @param {number} [object.x=0]
1993
+ * @param {number} [object.y=0]
1994
+ * @param {number} [object.w]
1995
+ * @param {number} [object.h]
1996
+ * @param {string} [object.position='absolute']
1997
+ * @param {...any} [object.rest]
1998
+ * @returns {HTMLCanvasElement}
1999
+ */
2000
+ const createCanvas = (_id, { x = 0, y = 0, w, h, position = `absolute`, ...rest } = {}) => {
2001
+ const cvs = document.createElement(`canvas`);
2002
+ if (_id) cvs.id = _id;
2003
+ cvs.style.display = `block`;
2004
+
2005
+ if (position) {
2006
+ cvs.style.position = position;
2007
+ cvs.style.left = wUnit(x);
2008
+ cvs.style.top = wUnit(y);
2009
+ }
2010
+
2011
+ applyCanvasSize(cvs, w, h);
2012
+ Object.keys(rest).forEach(property => cvs.style[property] = rest[property]);
2013
+
2014
+ return cvs;
2015
+ };
2016
+
1989
2017
  /**
1990
2018
  * 指定された高さに基づいて分割されたCanvasリストを生成する
1991
2019
  * @param {number} _width
@@ -2002,30 +2030,20 @@ const createSplitCanvases = (_width, _totalHeight) => {
2002
2030
  if (_totalHeight <= 0) return [];
2003
2031
 
2004
2032
  const count = Math.ceil(_totalHeight / maxLogicalHeight);
2033
+ const id = Math.random().toString(36).substring(2, 10); // ランダムなIDを生成
2005
2034
  const list = [];
2006
2035
 
2007
2036
  for (let i = 0; i < count; i++) {
2008
- const cvs = document.createElement('canvas');
2009
2037
  // 残りの高さを計算
2010
2038
  const logicalH = (i === count - 1)
2011
2039
  ? _totalHeight - (maxLogicalHeight * i)
2012
2040
  : maxLogicalHeight;
2013
2041
 
2014
- // 実際の描画解像度をセット
2015
- cvs.width = _width * g_dpr;
2016
- cvs.height = logicalH * g_dpr;
2017
-
2018
- // ブラウザ上の表示サイズをセット
2019
- cvs.style.width = wUnit(_width);
2020
- cvs.style.height = wUnit(logicalH);
2021
- cvs.style.display = 'block';
2022
-
2023
- const ctx = cvs.getContext('2d');
2024
- ctx.scale(g_dpr, g_dpr);
2042
+ const cvs = createCanvas(`${id}_${i}`, { w: _width, h: logicalH, position: null });
2025
2043
 
2026
2044
  list.push({
2027
2045
  canvas: cvs,
2028
- ctx: ctx,
2046
+ ctx: cvs.getContext(`2d`),
2029
2047
  offsetTop: i * maxLogicalHeight,
2030
2048
  logicalHeight: logicalH
2031
2049
  });
@@ -2033,6 +2051,83 @@ const createSplitCanvases = (_width, _totalHeight) => {
2033
2051
  return list;
2034
2052
  };
2035
2053
 
2054
+ // ctxの任意プロパティのキャッシュ
2055
+ const g_ctxPropCache = {};
2056
+
2057
+ /**
2058
+ * ctxの任意プロパティをキャッシュ付きで設定(同一キーなら代入をスキップ)
2059
+ * @param {CanvasRenderingContext2D} _ctx
2060
+ * @param {string} _prop
2061
+ * @param {any} _key
2062
+ * @param {Function} _computeValue
2063
+ */
2064
+ const setCtxProp = (_ctx, _prop, _key, _computeValue = () => _key) => {
2065
+ const cache = (g_ctxPropCache[_prop] ??= new WeakMap());
2066
+ if (cache.get(_ctx) !== _key) {
2067
+ _ctx[_prop] = _computeValue();
2068
+ cache.set(_ctx, _key);
2069
+ }
2070
+ };
2071
+
2072
+ /**
2073
+ * Canvasの実ピクセルサイズ・表示サイズを設定し、scale済みのcontextを返す
2074
+ * @param {HTMLCanvasElement} cvs
2075
+ * @param {number} w
2076
+ * @param {number} h
2077
+ * @returns {CanvasRenderingContext2D}
2078
+ */
2079
+ const applyCanvasSize = (cvs, w, h) => {
2080
+ cvs.width = w * g_dpr;
2081
+ cvs.height = h * g_dpr;
2082
+ cvs.style.width = wUnit(w);
2083
+ cvs.style.height = wUnit(h);
2084
+
2085
+ const ctx = cvs.getContext(`2d`);
2086
+ // width/height代入によりctx状態がリセットされるため、setCtxPropのキャッシュも同期して破棄
2087
+ Object.values(g_ctxPropCache).forEach(cache => cache.delete(ctx));
2088
+ ctx.scale(g_dpr, g_dpr);
2089
+ return ctx;
2090
+ };
2091
+
2092
+ /**
2093
+ * 指定スタイルでテキストを描画する共通関数(font文字列は呼び出し側で完成させて渡す)
2094
+ * @param {CanvasRenderingContext2D} _ctx
2095
+ * @param {string} _text
2096
+ * @param {number} _x
2097
+ * @param {number} _y
2098
+ * @param {object} [object]
2099
+ * @param {string} [object.font]
2100
+ * @param {string} [object.color]
2101
+ * @param {string} [object.align=C_ALIGN_LEFT]
2102
+ * @param {string} [object.baseline]
2103
+ */
2104
+ const fillCanvasTextRaw = (_ctx, _text, _x, _y, { font, color, align = C_ALIGN_LEFT, baseline } = {}) => {
2105
+ if (font !== undefined) setCtxProp(_ctx, `font`, font);
2106
+ if (color !== undefined) setCtxProp(_ctx, `fillStyle`, color);
2107
+ setCtxProp(_ctx, `textAlign`, align);
2108
+ setCtxProp(_ctx, `textBaseline`, baseline);
2109
+ _ctx.fillText(_text, _x, _y);
2110
+ };
2111
+
2112
+ /**
2113
+ * wUnit/getBasicFont前提のテキスト描画(既存呼び出し元向け)
2114
+ * @param {CanvasRenderingContext2D} _ctx
2115
+ * @param {string} _text
2116
+ * @param {number} _x
2117
+ * @param {number} _y
2118
+ * @param {object} [object]
2119
+ * @param {number} [object.siz=15]
2120
+ * @param {string} [object.font]
2121
+ * @param {string} [object.color]
2122
+ * @param {string} [object.align=C_ALIGN_LEFT]
2123
+ * @param {string} [object.baseline]
2124
+ */
2125
+ const fillCanvasText = (_ctx, _text, _x, _y, { siz = 15, font, color, align = C_ALIGN_LEFT, baseline } = {}) =>
2126
+ fillCanvasTextRaw(_ctx, _text, _x, _y, {
2127
+ font: `${wUnit(siz)} ${getBasicFont(font)}`,
2128
+ color, align, baseline,
2129
+ });
2130
+
2036
2131
  /**
2037
2132
  * 画像表示
2038
2133
  * @param {string} _id
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2026/09/13
8
- * Revised :
8
+ * Revised : 2026/09/15 (v50.5.1)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -1479,14 +1479,7 @@ const keyconfigKeyboardPreview = (() => {
1479
1479
  const setupCanvasContext = (canvas) => {
1480
1480
  if (!canvas) return null;
1481
1481
  canvas.style.top = wUnit(40);
1482
- canvas.width = _state.cvsW * g_dpr;
1483
- canvas.height = _state.cvsH * g_dpr;
1484
- canvas.style.width = wUnit(_state.cvsW);
1485
- canvas.style.height = wUnit(_state.cvsH);
1486
-
1487
- const ctx = canvas.getContext(`2d`);
1488
- ctx.scale(g_dpr, g_dpr);
1489
- return ctx;
1482
+ return applyCanvasSize(canvas, _state.cvsW, _state.cvsH);
1490
1483
  };
1491
1484
 
1492
1485
  /**
@@ -1512,6 +1505,19 @@ const keyconfigKeyboardPreview = (() => {
1512
1505
  ctx.closePath();
1513
1506
  };
1514
1507
 
1508
+ // fill/strokeスタイルを設定して塗り・線を描く共通処理(roundRectなどと組み合わせて使う)
1509
+ const fillStrokeShape = (_ctx, { fill, stroke, lineWidth = 1 } = {}) => {
1510
+ if (fill !== undefined) {
1511
+ setCtxProp(_ctx, `fillStyle`, fill);
1512
+ _ctx.fill();
1513
+ }
1514
+ if (stroke !== undefined) {
1515
+ setCtxProp(_ctx, `strokeStyle`, stroke);
1516
+ setCtxProp(_ctx, `lineWidth`, lineWidth);
1517
+ _ctx.stroke();
1518
+ }
1519
+ };
1520
+
1515
1521
  /**
1516
1522
  * 単一キーを描画する(枠の描画と内部テキストの書き込みを一括化)
1517
1523
  * @param {CanvasRenderingContext2D} ctx
@@ -1524,11 +1530,7 @@ const keyconfigKeyboardPreview = (() => {
1524
1530
 
1525
1531
  // 1. キーの枠線・背景を描画
1526
1532
  roundRect(ctx, x + 0.5, y + 0.5, keyW - 1, keyH - 1, kr());
1527
- ctx.fillStyle = style.fill;
1528
- ctx.strokeStyle = style.stroke;
1529
- ctx.lineWidth = lw;
1530
- ctx.fill();
1531
- ctx.stroke();
1533
+ fillStrokeShape(ctx, { fill: style.fill, stroke: style.stroke, lineWidth: lw });
1532
1534
 
1533
1535
  // 2. キー内部のテキスト(メイン・サブ)を描画
1534
1536
  const [primary, sub] = getKeyLabels(code, label);
@@ -1539,28 +1541,27 @@ const keyconfigKeyboardPreview = (() => {
1539
1541
 
1540
1542
  // サブラベル(Shift面などの表記)がある場合
1541
1543
  if (sub) {
1542
- ctx.fillStyle = style.subText || style.text;
1543
- ctx.font = `bold ${Math.max(6, Math.floor(9 * _state.scale))}px monospace`;
1544
- ctx.textAlign = `right`;
1545
- ctx.textBaseline = `top`;
1546
- ctx.fillText(sub, x + keyW - 2, y + 2);
1544
+ fillCanvasTextRaw(ctx, sub, x + keyW - 2, y + 2, {
1545
+ font: `bold ${Math.max(6, Math.floor(9 * _state.scale))}px monospace`,
1546
+ color: style.subText || style.text,
1547
+ align: `right`, baseline: `top`,
1548
+ });
1547
1549
  }
1548
1550
 
1549
1551
  // メインラベルの描画(改行表記に対応)
1550
1552
  const [primary1, primary2] = primary.split(`\n`);
1551
- ctx.fillStyle = style.text;
1552
- ctx.textAlign = `center`;
1553
- ctx.textBaseline = `middle`;
1554
1553
  const subDiff = sub ? 2 : 0;
1555
1554
 
1556
1555
  if (primary2) {
1557
1556
  const siz = fs(Math.max(primary1.length, primary2.length));
1558
- ctx.font = `bold ${siz}px monospace`;
1559
- ctx.fillText(primary1, x + keyW / 2, y + keyH / 2 - siz / 2 + subDiff);
1560
- ctx.fillText(primary2, x + keyW / 2, y + keyH / 2 + siz / 2 + subDiff);
1557
+ const opt = { font: `bold ${siz}px monospace`, color: style.text, align: `center`, baseline: `middle` };
1558
+ fillCanvasTextRaw(ctx, primary1, x + keyW / 2, y + keyH / 2 - siz / 2 + subDiff, opt);
1559
+ fillCanvasTextRaw(ctx, primary2, x + keyW / 2, y + keyH / 2 + siz / 2 + subDiff, opt);
1561
1560
  } else {
1562
- ctx.font = `bold ${fs(primary.length)}px monospace`;
1563
- ctx.fillText(primary, x + keyW / 2, y + keyH / 2 + subDiff);
1561
+ fillCanvasTextRaw(ctx, primary, x + keyW / 2, y + keyH / 2 + subDiff, {
1562
+ font: `bold ${fs(primary.length)}px monospace`,
1563
+ color: style.text, align: `center`, baseline: `middle`,
1564
+ });
1564
1565
  }
1565
1566
  };
1566
1567
 
@@ -1619,7 +1620,7 @@ const keyconfigKeyboardPreview = (() => {
1619
1620
  if (!ctx) return;
1620
1621
 
1621
1622
  ctx.clearRect(0, 0, _state.cvsW, _state.cvsH);
1622
- ctx.fillStyle = C_COLOR.bgFill;
1623
+ setCtxProp(ctx, `fillStyle`, C_COLOR.bgFill);
1623
1624
  ctx.fillRect(0, 0, _state.cvsW, _state.cvsH);
1624
1625
 
1625
1626
  _state.keyDataList = [];
@@ -1644,9 +1645,7 @@ const keyconfigKeyboardPreview = (() => {
1644
1645
 
1645
1646
  // 凡例
1646
1647
  const ly = _state.cvsH - 10;
1647
- ctx.font = `${Math.max(9, Math.floor(12 * _state.scale))}px ${getBasicFont()}`;
1648
- ctx.textAlign = `left`;
1649
- ctx.textBaseline = `middle`;
1648
+ const legendFont = `${Math.max(9, Math.floor(12 * _state.scale))}px ${getBasicFont()}`;
1650
1649
 
1651
1650
  const legends = [
1652
1651
  { style: C_COLOR.normal, label: g_lblNameObj.unallocated },
@@ -1658,10 +1657,11 @@ const keyconfigKeyboardPreview = (() => {
1658
1657
  let lx = 8;
1659
1658
  legends.forEach(item => {
1660
1659
  roundRect(ctx, lx, ly - 5, 10, 10, 2);
1661
- ctx.fillStyle = item.style.fill; ctx.fill();
1662
- ctx.strokeStyle = item.style.stroke; ctx.lineWidth = 1; ctx.stroke();
1663
- ctx.fillStyle = C_COLOR.legendText;
1664
- ctx.fillText(item.label, lx + 14, ly);
1660
+ fillStrokeShape(ctx, { fill: item.style.fill, stroke: item.style.stroke, lineWidth: 1 });
1661
+
1662
+ fillCanvasTextRaw(ctx, item.label, lx + 14, ly, {
1663
+ font: legendFont, color: C_COLOR.legendText, align: `left`, baseline: `middle`,
1664
+ });
1665
1665
  lx += ctx.measureText(item.label).width + 28;
1666
1666
  });
1667
1667
  };
package/js/lib/result.js CHANGED
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2026/09/13
8
- * Revised :
8
+ * Revised : 2026/09/15 (v50.5.1)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -263,20 +263,12 @@ const resultInit = () => {
263
263
  // ゲージ推移グラフの描画
264
264
  const gaugeTransitionWindow = createEmptySprite(divRoot, `gaugeTransitionWindow`, g_windowObj.gaugeTransition, g_cssObj.result_PlayDataWindow);
265
265
  for (let j = 0; j < 2; j++) {
266
- const canvas = document.createElement(`canvas`);
267
- canvas.id = `graphGaugeTransition${j > 0 ? j + 1 : ``}`;
268
- canvas.width = g_limitObj.gaugeTransitionWidth * g_dpr;
269
- canvas.height = g_limitObj.gaugeTransitionHeight * g_dpr;
270
- canvas.style.width = wUnit(g_limitObj.gaugeTransitionWidth);
271
- canvas.style.height = wUnit(g_limitObj.gaugeTransitionHeight);
272
- canvas.getContext(`2d`).scale(g_dpr, g_dpr);
273
- canvas.style.left = wUnit(0);
274
- canvas.style.top = wUnit(0);
275
- canvas.style.position = `absolute`;
276
- if (j > 0) {
277
- canvas.style.pointerEvents = C_DIS_NONE;
278
- }
279
- gaugeTransitionWindow.appendChild(canvas);
266
+ gaugeTransitionWindow.appendChild(
267
+ createCanvas(`graphGaugeTransition${j > 0 ? j + 1 : ``}`, {
268
+ w: g_limitObj.gaugeTransitionWidth, h: g_limitObj.gaugeTransitionHeight,
269
+ pointerEvents: j > 0 ? C_DIS_NONE : C_DIS_AUTO,
270
+ })
271
+ );
280
272
  }
281
273
 
282
274
  multiAppend(divRoot,
@@ -578,28 +570,18 @@ const resultInit = () => {
578
570
  const copyResultImageData = _msg => {
579
571
  const tmpDiv = createEmptySprite(divRoot, `tmpDiv`, { x: 0, y: 0, w: g_sWidth, h: g_sHeight, pointerEvents: C_DIS_AUTO });
580
572
  tmpDiv.style.background = `#000000cc`;
581
- const canvas = document.createElement(`canvas`);
573
+
582
574
  const artistName = g_headerObj.artistNames[g_headerObj.musicNos[g_stateObj.scoreId]] || g_headerObj.artistName;
583
575
  const logicalWidth = 400;
584
576
  const logicalHeight = g_sHeight - 90;
585
577
  const flapWidth = 370;
586
578
 
587
- canvas.id = `resultImage`;
588
- canvas.width = logicalWidth * g_dpr;
589
- canvas.height = logicalHeight * g_dpr;
590
- canvas.style.width = wUnit(logicalWidth);
591
- canvas.style.height = wUnit(logicalHeight);
592
- canvas.style.left = wUnit((g_sWidth - parseFloat(canvas.style.width)) / 2);
593
- canvas.style.top = wUnit(20);
594
- canvas.style.position = `absolute`;
595
-
579
+ const canvas = createCanvas(`resultImage`, {
580
+ x: (g_sWidth - logicalWidth) / 2, y: 20, w: logicalWidth, h: logicalHeight
581
+ });
596
582
  const context = canvas.getContext(`2d`);
597
- context.scale(g_dpr, g_dpr);
598
583
  const drawText = (_text, { x = 30, dy = 0, hy, siz = 15, color = `#cccccc`, align = C_ALIGN_LEFT, font } = {}) => {
599
- context.font = `${wUnit(siz)} ${getBasicFont(font)}`;
600
- context.fillStyle = color;
601
- context.textAlign = align;
602
- context.fillText(_text, x, 35 + hy * 18 + dy);
584
+ fillCanvasText(context, _text, x, 35 + hy * 18 + dy, { siz, font, color, align });
603
585
  };
604
586
  makeBgCanvas(context, { w: logicalWidth, h: logicalHeight });
605
587
 
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Source by tickle
7
7
  * Created : 2026/09/13
8
- * Revised :
8
+ * Revised : 2026/09/15 (v50.5.1)
9
9
  *
10
10
  * https://github.com/cwtickle/danoniplus
11
11
  */
@@ -478,14 +478,14 @@ const drawSpeedGraph = _scoreId => {
478
478
  context.moveTo(lineX[j], lineY);
479
479
  context.lineTo(lineX[j] + 25, lineY);
480
480
  context.stroke();
481
- context.font = `${wUnit(g_limitObj.mainSiz)} ${getBasicFont()}`;
482
- context.fillText(g_lblNameObj[`s_${speedType}`], lineX[j] + 30, lineY + 3);
481
+ fillCanvasText(context, g_lblNameObj[`s_${speedType}`], lineX[j] + 30, lineY + 3, { siz: g_limitObj.mainSiz });
483
482
 
484
483
  const maxSpeed = Math.max(...speed);
485
484
  const minSpeed = Math.min(...speed);
486
- context.font = `${wUnit(g_limitObj.graphMiniSiz)} ${getBasicFont()}`;
487
- context.fillText(`(${minSpeed.toFixed(2)}x` + (minSpeed === maxSpeed ? `` : ` -- ${Math.max(...speed).toFixed(2)}x`) + `)`, lineX[j] + 30, lineY + 16);
488
- context.fillText(`Avg. ` + (avgX[j] === 1 ? `----` : `${(avgSubX[j]).toFixed(2)}x`), lineX[j] + 30, lineY + 29);
485
+ const speedText = `(${minSpeed.toFixed(2)}x` + (minSpeed === maxSpeed ? `` : ` -- ${Math.max(...speed).toFixed(2)}x`) + `)`;
486
+ const avgText = `Avg. ` + (avgX[j] === 1 ? `----` : `${(avgSubX[j]).toFixed(2)}x`);
487
+ fillCanvasText(context, speedText, lineX[j] + 30, lineY + 16, { siz: g_limitObj.graphMiniSiz });
488
+ fillCanvasText(context, avgText, lineX[j] + 30, lineY + 29, { siz: g_limitObj.graphMiniSiz });
489
489
  updateScoreDetailLabel(`Speed`, `${speedType}S`, speedObj[speedType].cnt, j, g_lblNameObj[`s_${speedType}`]);
490
490
  });
491
491
  updateScoreDetailLabel(`Speed`, `avgS`, `${(avgX[0] * avgX[1]).toFixed(2)}x`, 2, g_lblNameObj.s_avg);
@@ -599,13 +599,11 @@ const drawDensityGraph = _scoreId => {
599
599
 
600
600
  context.beginPath();
601
601
  context.lineWidth = 3;
602
- context.fillStyle = g_rankObj.rankColorAllPerfect;
603
602
  context.strokeStyle = g_graphColorObj[val];
604
603
  context.moveTo(lineX, 215);
605
604
  context.lineTo(lineX + 20, 215);
606
605
  context.stroke();
607
- context.font = `${wUnit(g_limitObj.difSelectorSiz)} ${getBasicFont()}`;
608
- context.fillText(lineNames[j], lineX + 20, 218);
606
+ fillCanvasText(context, lineNames[j], lineX + 20, 218, { siz: g_limitObj.difSelectorSiz, color: g_rankObj.rankColorAllPerfect });
609
607
  });
610
608
 
611
609
  const obj = getScoreBaseData(_scoreId);
@@ -684,9 +682,7 @@ const drawLine = (_context, _y, _lineType, { _fixed, _mark, _a, _b } = {}) => {
684
682
  const textBaseObj = document.getElementById(`lnkDifficulty`);
685
683
  const textColor = window.getComputedStyle(textBaseObj, ``).color;
686
684
  _context.strokeStyle = textColor;
687
- _context.font = `${wUnit(12)} ${getBasicFont()}`;
688
- _context.fillStyle = textColor;
689
- _context.fillText(_y.toFixed(_fixed) + _mark, 2, lineY + 4);
685
+ fillCanvasText(_context, _y.toFixed(_fixed) + _mark, 2, lineY + 4, { siz: 12, color: textColor });
690
686
  } else {
691
687
  _context.strokeStyle = `#646464`;
692
688
  }
@@ -1100,31 +1096,17 @@ const createMinimapHeader = (_config, _keyCtrlPtn, _keyNum) => {
1100
1096
  const { timeMargin, laneWidth, logicalWidth } = _config;
1101
1097
  const headerHeight = 15; // ヘッダーの固定高
1102
1098
 
1103
- const canvas = document.createElement('canvas');
1099
+ const canvas = createCanvas(null, { w: logicalWidth, h: headerHeight, position: null });
1104
1100
  const ctx = canvas.getContext('2d');
1105
1101
 
1106
- // 解像度と表示サイズの設定
1107
- canvas.width = logicalWidth * g_dpr;
1108
- canvas.height = headerHeight * g_dpr;
1109
- canvas.style.width = wUnit(logicalWidth);
1110
- canvas.style.height = wUnit(headerHeight);
1111
- canvas.style.display = 'block';
1112
-
1113
- ctx.scale(g_dpr, g_dpr);
1114
-
1115
- // テキストのスタイル設定
1116
- ctx.fillStyle = '#999';
1117
- ctx.font = `10px ${getBasicFont()}`;
1118
- ctx.textAlign = 'center';
1119
- ctx.textBaseline = 'middle';
1120
-
1121
1102
  // 各レーンのキー名を描画
1122
1103
  for (let j = 0; j < _keyNum; j++) {
1123
1104
  // config.laneWidth を使って中央座標を計算
1124
1105
  const x = timeMargin + j * laneWidth + laneWidth / 2;
1125
1106
  const keyText = g_kCd[g_keyObj[`keyCtrl${_keyCtrlPtn}`][j][0]].split(` `).join(``);
1126
1107
 
1127
- ctx.fillText(keyText, x, headerHeight / 2 + 2); // 視覚的な中央調整で +2px
1108
+ // 視覚的な中央調整で +2px
1109
+ fillCanvasText(ctx, keyText, x, headerHeight / 2 + 2, { siz: 10, color: '#999', align: C_ALIGN_CENTER, baseline: `middle` });
1128
1110
  }
1129
1111
 
1130
1112
  return canvas;
@@ -1231,6 +1213,8 @@ const generateMinimapData = (_params, _isReverse) => {
1231
1213
  * @param {number} _h
1232
1214
  * @param {number} _dpr
1233
1215
  * @param {Function} _drawFunc
1216
+ * - 描画関数。前後に ctx.save() / ctx.restore() が自動で呼ばれるためctxキャッシュを使った関数
1217
+ * (setCtxProp, fillCanvasText, fillCanvasRect など) は使用できない
1234
1218
  */
1235
1219
  const distributeDrawing = (_canvases, _y, _h, _dpr, _drawFunc) => {
1236
1220
  _canvases.forEach(item => {
@@ -1666,23 +1650,14 @@ const createOptionWindow = _sprite => {
1666
1650
 
1667
1651
  if (_graphUseFlg) {
1668
1652
  for (let j = 0; j < _graphNum; j++) {
1669
- const graphObj = document.createElement(`canvas`);
1670
1653
  const textBaseObj = document.getElementById(`lnkDifficulty`);
1671
1654
  const bkColor = window.getComputedStyle(textBaseObj, ``).backgroundColor;
1672
-
1673
- graphObj.id = `graph${_name}${j > 0 ? j + 1 : ``}`;
1674
- graphObj.width = g_limitObj.graphWidth * g_dpr;
1675
- graphObj.height = g_limitObj.graphHeight * g_dpr;
1676
- graphObj.style.width = wUnit(g_limitObj.graphWidth);
1677
- graphObj.style.height = wUnit(g_limitObj.graphHeight);
1678
- graphObj.style.left = wUnit(125);
1679
- graphObj.style.top = wUnit(0);
1680
- graphObj.style.position = `absolute`;
1681
- graphObj.style.background = j === 0 ? bkColor : `#ffffff00`;
1682
- const ctx = graphObj.getContext(`2d`);
1683
- ctx.scale(g_dpr, g_dpr);
1684
-
1685
- detailObj.appendChild(graphObj);
1655
+ detailObj.appendChild(
1656
+ createCanvas(`graph${_name}${j > 0 ? j + 1 : ``}`, {
1657
+ x: 125, y: 0, w: g_limitObj.graphWidth, h: g_limitObj.graphHeight,
1658
+ background: j === 0 ? bkColor : `#ffffff00`,
1659
+ })
1660
+ );
1686
1661
  }
1687
1662
  }
1688
1663
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "danoniplus",
3
- "version": "50.5.0",
3
+ "version": "50.5.1",
4
4
  "description": "Dancing☆Onigiri (CW Edition) - Web-based Rhythm Game",
5
5
  "main": "./js/danoni_main.js",
6
6
  "jsdelivr": "./js/danoni_main.js",