@takagaki/cortex-decisions-viewer 0.12.114 → 0.12.115
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/dist/render.js +149 -27
- package/package.json +1 -1
package/dist/render.js
CHANGED
|
@@ -20603,6 +20603,12 @@ ${calendarAddUrl.toString()}
|
|
|
20603
20603
|
(inAdj[e.b.id] = inAdj[e.b.id] || []).push(e.a.id);
|
|
20604
20604
|
});
|
|
20605
20605
|
|
|
20606
|
+
// 描き直しの間引き(engine #551 のカクつき対策)。操作・検索・期間の切り替え・ホバーの波の間は毎フレーム描き、
|
|
20607
|
+
// それが済んで止まっている間は、星の瞬き(ゆっくり)のためだけに IDLE_FRAME_MS ごとに描く
|
|
20608
|
+
var IDLE_FRAME_MS = 100;
|
|
20609
|
+
var activeUntil = 0;
|
|
20610
|
+
function poke(ms) { activeUntil = Math.max(activeUntil, performance.now() + ms); }
|
|
20611
|
+
|
|
20606
20612
|
// 検索: 一致ノード(matched)が光り、その隣接(lit)は残し、他は減光する
|
|
20607
20613
|
var matched = {}, lit = {}, searching = false;
|
|
20608
20614
|
// 期間(engine #551)を選んでいるときは、その期間に生まれた・変わった記録だけが一致になる(キーワードと両方なら両方を満たす記録)
|
|
@@ -20611,6 +20617,7 @@ ${calendarAddUrl.toString()}
|
|
|
20611
20617
|
var range = graphPeriodRange(graphState.period.unit === "all" ? null : graphState.period);
|
|
20612
20618
|
searching = q.length > 0 || !!range;
|
|
20613
20619
|
matched = {}; lit = {};
|
|
20620
|
+
poke(250);
|
|
20614
20621
|
if (!searching) {
|
|
20615
20622
|
countEl.textContent = "点 " + nodes.length + " / つながり " + edges.length;
|
|
20616
20623
|
return;
|
|
@@ -20659,6 +20666,8 @@ ${calendarAddUrl.toString()}
|
|
|
20659
20666
|
var UPSTREAM_HOPS = 1; // 参照元(入辺)を辿る深さ
|
|
20660
20667
|
var SWEEP_STEP_MS = 120; // 波が1段(1ホップ)進むごとの間隔
|
|
20661
20668
|
var SWEEP_GROW_MS = 200; // 辺・点が灯り切るまでの時間
|
|
20669
|
+
// ホバーの波が流れ切るまで毎フレーム描く時間(参照元 1 段+参照先 2 段=順番 3 まで+灯り切る時間に余裕を見る)
|
|
20670
|
+
var HOVER_SWEEP_MS = (DOWNSTREAM_HOPS + UPSTREAM_HOPS + 2) * SWEEP_STEP_MS + SWEEP_GROW_MS + 300;
|
|
20662
20671
|
function computeFitTarget() {
|
|
20663
20672
|
if (!nodes.length) return null;
|
|
20664
20673
|
var minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
@@ -20686,7 +20695,10 @@ ${calendarAddUrl.toString()}
|
|
|
20686
20695
|
view.x += (t.x - view.x) * 0.18;
|
|
20687
20696
|
view.y += (t.y - view.y) * 0.18;
|
|
20688
20697
|
}
|
|
20698
|
+
// まだ目に見えて動いているか(止まっていれば描き直しを間引ける)
|
|
20699
|
+
return Math.abs(t.scale - view.scale) > view.scale * 0.0005 || Math.abs(t.x - view.x) > 0.1 || Math.abs(t.y - view.y) > 0.1;
|
|
20689
20700
|
}
|
|
20701
|
+
var fitMoving = true;
|
|
20690
20702
|
|
|
20691
20703
|
// ロード時に1回だけ: Goldの中心から外へ「ふわっ」と光が広がるイントロ。
|
|
20692
20704
|
// 金色(#fcd34d)はホバー連鎖・検索の専用色なので、イントロは寒色で別物として見せる。
|
|
@@ -20700,6 +20712,7 @@ ${calendarAddUrl.toString()}
|
|
|
20700
20712
|
resetBtn.addEventListener("click", function () {
|
|
20701
20713
|
autoFit = true; // 全ノードが収まる表示へ滑らかに戻す
|
|
20702
20714
|
resize();
|
|
20715
|
+
poke(250);
|
|
20703
20716
|
if (!reduceMotion) introStart = performance.now(); // 中心から光が広がるイントロを再生
|
|
20704
20717
|
});
|
|
20705
20718
|
canvas.parentNode.appendChild(resetBtn);
|
|
@@ -20834,6 +20847,96 @@ ${calendarAddUrl.toString()}
|
|
|
20834
20847
|
return n.recordId && n.glow !== null ? 0.4 + 0.6 * n.glow : 1;
|
|
20835
20848
|
}
|
|
20836
20849
|
|
|
20850
|
+
// 点の光(にじみ・shadowBlur)は、点ごとに毎フレーム描くと 700 点で 1 フレーム 30ms を超える(engine #551 のカクつき)。
|
|
20851
|
+
// にじみだけを小さな絵に前もって描いて使い回し、本体の円はその上に正確な半径で描く。
|
|
20852
|
+
// 絵は画面の画素(device px)で作る(shadowBlur は座標変換に影響されない=元の描き方と同じ幅)。
|
|
20853
|
+
// 半径は 0.25px・にじみの幅は小さいうちは 0.5 刻み、大きいと約 4% 刻みに丸めて、絵の数を抑える
|
|
20854
|
+
// (小さい点のにじみの明るさは円の面積に比例するので、1px 刻みでは引いた表示で明るさが ±数十% ずれる)
|
|
20855
|
+
var TAU = Math.PI * 2;
|
|
20856
|
+
// 使い回しの置き場は「最近使った順」の上限つき(上限を超えたら一番古いものから捨てる=ズームし続けても一度に作り直さない)
|
|
20857
|
+
function spriteStore(max) {
|
|
20858
|
+
var m = new Map();
|
|
20859
|
+
return {
|
|
20860
|
+
get: function (k) { var v = m.get(k); if (v) { m.delete(k); m.set(k, v); } return v; },
|
|
20861
|
+
set: function (k, v) { m.set(k, v); if (m.size > max) m.delete(m.keys().next().value); },
|
|
20862
|
+
};
|
|
20863
|
+
}
|
|
20864
|
+
var haloCache = spriteStore(800);
|
|
20865
|
+
// これより大きいにじみ(大きく寄ったとき・画面にわずかな点しか無い)は絵にせず直接描く(大きな絵を溜めない)
|
|
20866
|
+
var HALO_SPRITE_MAX = 512;
|
|
20867
|
+
function haloBlurStep(blur) {
|
|
20868
|
+
if (blur < 0.25) return 0;
|
|
20869
|
+
if (blur <= 12) return Math.round(blur * 2) / 2;
|
|
20870
|
+
return Math.round(12 * Math.pow(1.04, Math.round(Math.log(blur / 12) / Math.log(1.04))) * 2) / 2;
|
|
20871
|
+
}
|
|
20872
|
+
function haloSprite(color, R, blur) {
|
|
20873
|
+
var bq = haloBlurStep(blur);
|
|
20874
|
+
if (!bq) return null;
|
|
20875
|
+
var rq = Math.max(0.25, Math.round(R * 4) / 4);
|
|
20876
|
+
var half = Math.ceil(rq + bq * 1.5 + 2); // にじみ(σ=blur/2)が見える範囲 ≒ 3σ
|
|
20877
|
+
if (half * 2 > HALO_SPRITE_MAX) return false;
|
|
20878
|
+
var key = color + "|" + rq + "|" + bq;
|
|
20879
|
+
var sp = haloCache.get(key);
|
|
20880
|
+
if (sp) return sp;
|
|
20881
|
+
var size = half * 2;
|
|
20882
|
+
var c = document.createElement("canvas");
|
|
20883
|
+
c.width = size; c.height = size;
|
|
20884
|
+
var g = c.getContext("2d");
|
|
20885
|
+
if (!g) return null;
|
|
20886
|
+
// 円は絵の外(左へ size ずらす)に描き、影だけを絵の中央へ落とす=にじみだけが残る
|
|
20887
|
+
g.shadowColor = color;
|
|
20888
|
+
g.shadowBlur = bq;
|
|
20889
|
+
g.shadowOffsetX = size;
|
|
20890
|
+
g.fillStyle = color;
|
|
20891
|
+
g.beginPath();
|
|
20892
|
+
g.arc(half - size, half, rq, 0, TAU);
|
|
20893
|
+
g.fill();
|
|
20894
|
+
sp = { c: c, h: half };
|
|
20895
|
+
haloCache.set(key, sp);
|
|
20896
|
+
return sp;
|
|
20897
|
+
}
|
|
20898
|
+
// X・Y は画素の境目に揃えた値を渡す(半端な位置だと絵の引き伸ばしが入り、1 枚ごとに何倍も重くなる)
|
|
20899
|
+
function drawHalo(color, R, blur, X, Y) {
|
|
20900
|
+
var sp = haloSprite(color, R, blur);
|
|
20901
|
+
if (sp) { ctx.drawImage(sp.c, X - sp.h, Y - sp.h); return; }
|
|
20902
|
+
if (sp === false) {
|
|
20903
|
+
ctx.save();
|
|
20904
|
+
ctx.shadowColor = color;
|
|
20905
|
+
ctx.shadowBlur = blur;
|
|
20906
|
+
ctx.fillStyle = color;
|
|
20907
|
+
ctx.beginPath();
|
|
20908
|
+
ctx.arc(X, Y, R, 0, TAU);
|
|
20909
|
+
ctx.fill();
|
|
20910
|
+
ctx.restore();
|
|
20911
|
+
}
|
|
20912
|
+
}
|
|
20913
|
+
// ラベルも文字を絵にして使い回す(検索で数百のラベルを毎フレーム文字から描くと 1 フレーム 100ms を超える)。
|
|
20914
|
+
// 文字の大きさは画面の画素で一定(11px)なので、ズームしても同じ絵が使える
|
|
20915
|
+
var labelCache = spriteStore(3000);
|
|
20916
|
+
function labelFont(bold) { return (bold ? "600 " : "") + (11 * dpr) + "px 'Noto Sans JP', sans-serif"; }
|
|
20917
|
+
function drawLabel(text, color, bold, X, baseY) {
|
|
20918
|
+
var key = color + "|" + (bold ? 1 : 0) + "|" + text;
|
|
20919
|
+
var sp = labelCache.get(key);
|
|
20920
|
+
if (!sp) {
|
|
20921
|
+
var font = labelFont(bold);
|
|
20922
|
+
var c = document.createElement("canvas");
|
|
20923
|
+
var g = c.getContext("2d");
|
|
20924
|
+
if (!g) return;
|
|
20925
|
+
g.font = font;
|
|
20926
|
+
var asc = Math.ceil(13 * dpr), desc = Math.ceil(4 * dpr); // 11px の文字の上下+少しの余白
|
|
20927
|
+
c.width = Math.max(1, Math.ceil(g.measureText(text).width) + 2);
|
|
20928
|
+
c.height = asc + desc;
|
|
20929
|
+
g.font = font; // 大きさを変えると描き方の設定が戻るので、もう一度
|
|
20930
|
+
g.fillStyle = color;
|
|
20931
|
+
g.fillText(text, 0, asc);
|
|
20932
|
+
sp = { c: c, asc: asc };
|
|
20933
|
+
labelCache.set(key, sp);
|
|
20934
|
+
}
|
|
20935
|
+
ctx.drawImage(sp.c, Math.round(X), Math.round(baseY - sp.asc));
|
|
20936
|
+
}
|
|
20937
|
+
// ホバーの連鎖(参照先・参照元)は触った点が変わったときだけ辿り直す
|
|
20938
|
+
var linFor = null, linCache = null;
|
|
20939
|
+
|
|
20837
20940
|
function draw() {
|
|
20838
20941
|
var rect = canvas.getBoundingClientRect();
|
|
20839
20942
|
var now = performance.now();
|
|
@@ -20862,7 +20965,7 @@ ${calendarAddUrl.toString()}
|
|
|
20862
20965
|
ctx.fill();
|
|
20863
20966
|
});
|
|
20864
20967
|
ctx.globalAlpha = 1;
|
|
20865
|
-
|
|
20968
|
+
fitMoving = autoFit ? !!applyFit(false) : false; // 全ノードが収まる位置・倍率へ滑らかに追従
|
|
20866
20969
|
ctx.translate(view.x, view.y);
|
|
20867
20970
|
ctx.scale(view.scale, view.scale);
|
|
20868
20971
|
|
|
@@ -20882,7 +20985,8 @@ ${calendarAddUrl.toString()}
|
|
|
20882
20985
|
}
|
|
20883
20986
|
return hop;
|
|
20884
20987
|
}
|
|
20885
|
-
if (hovered)
|
|
20988
|
+
if (hovered && linFor === hovered) lin = linCache;
|
|
20989
|
+
else if (hovered) {
|
|
20886
20990
|
var downHop = bfsDir(outAdj, DOWNSTREAM_HOPS); // 参照先
|
|
20887
20991
|
var upHop = bfsDir(inAdj, UPSTREAM_HOPS); // 参照元
|
|
20888
20992
|
var maxUp = 0;
|
|
@@ -20897,6 +21001,7 @@ ${calendarAddUrl.toString()}
|
|
|
20897
21001
|
if (id === hovered.id || lin[id] !== undefined) return;
|
|
20898
21002
|
lin[id] = { order: maxUp + downHop[id], hop: downHop[id], dir: "down" };
|
|
20899
21003
|
});
|
|
21004
|
+
linFor = hovered; linCache = lin;
|
|
20900
21005
|
}
|
|
20901
21006
|
function hopAlpha(d) {
|
|
20902
21007
|
return d <= 1 ? 1 : Math.max(0.6, 1 - d * 0.1);
|
|
@@ -20915,7 +21020,13 @@ ${calendarAddUrl.toString()}
|
|
|
20915
21020
|
reference: "rgba(180,196,230,0.32)", source: "rgba(180,196,230,0.32)", link: "rgba(180,196,230,0.22)",
|
|
20916
21021
|
about: "rgba(196,181,253,0.22)",
|
|
20917
21022
|
};
|
|
21023
|
+
// 画面に入っている範囲(世界座標)。両端が同じ側の外にある線は描かない
|
|
21024
|
+
var em = 4 / view.scale; // 線の太さの分の余白(画面で 4px)
|
|
21025
|
+
var wx0 = -view.x / view.scale - em, wy0 = -view.y / view.scale - em;
|
|
21026
|
+
var wx1 = (rect.width - view.x) / view.scale + em, wy1 = (rect.height - view.y) / view.scale + em;
|
|
20918
21027
|
edges.forEach(function (e) {
|
|
21028
|
+
if ((e.a.x < wx0 && e.b.x < wx0) || (e.a.x > wx1 && e.b.x > wx1) ||
|
|
21029
|
+
(e.a.y < wy0 && e.b.y < wy0) || (e.a.y > wy1 && e.b.y > wy1)) return;
|
|
20919
21030
|
// ホバー中: リネージに入った辺だけ、波の順に「order の低い側→高い側」へ伸びながら金色に。
|
|
20920
21031
|
if (hovered) {
|
|
20921
21032
|
var la = lin[e.a.id], lb = lin[e.b.id];
|
|
@@ -20955,6 +21066,10 @@ ${calendarAddUrl.toString()}
|
|
|
20955
21066
|
ctx.stroke();
|
|
20956
21067
|
});
|
|
20957
21068
|
|
|
21069
|
+
// 点は画面の画素の座標で描く(にじみの絵をそのまま置くため)
|
|
21070
|
+
var k = view.scale * dpr, ox = view.x * dpr, oy = view.y * dpr;
|
|
21071
|
+
var cw = canvas.width, ch = canvas.height;
|
|
21072
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
20958
21073
|
nodes.forEach(function (n) {
|
|
20959
21074
|
var style = GROUP_STYLE[n.group] || GROUP_STYLE.phantom;
|
|
20960
21075
|
var alphaN = 1;
|
|
@@ -20977,46 +21092,45 @@ ${calendarAddUrl.toString()}
|
|
|
20977
21092
|
}
|
|
20978
21093
|
var dim = alphaN < 0.3;
|
|
20979
21094
|
var isGold = !!n.recordId;
|
|
21095
|
+
var r0 = nodeRadius(n);
|
|
21096
|
+
// 画面の画素での位置と半径(ラベル・輪・にじみはすべて画素で描く)
|
|
21097
|
+
// 中心は画素の境目に揃える(にじみの絵と本体の円の中心を合わせる。dpr 2 なら 0.25px 以内の差)
|
|
21098
|
+
var X = Math.round(n.x * k + ox), Y = Math.round(n.y * k + oy), R = r0 * k;
|
|
21099
|
+
var inChain = hovered && n !== hovered && lin[n.id] !== undefined;
|
|
21100
|
+
var blur =
|
|
21101
|
+
(isGold ? (n.glow === null || matched[n.id] ? Math.max(16, n.glow === null ? 16 : 6 + 22 * n.glow) : 6 + 22 * n.glow) : 7) * (dim ? 0.3 : 1) * (inChain ? 1.7 : 1) * (1 + introFlash * 1.8);
|
|
21102
|
+
// ラベル: Gold層レコードはズームイン時のみ表示(引いて全体表示中は出さない)。
|
|
21103
|
+
// それ以外はホバーの連鎖に入ったときか検索ヒット時のみ(ズームに関係なく表示)。
|
|
21104
|
+
var showLabel = (n.recordId && view.scale >= LABEL_MIN_SCALE) || (hovered && lin[n.id] !== undefined && sweepRamp(lin[n.id]) > 0.15) || (searching && lit[n.id]);
|
|
21105
|
+
// 画面の外の点は描かない(にじみの届く幅・輪・右に出るラベルの幅を見込む)
|
|
21106
|
+
var reach = R + Math.max(blur, 18) * 1.5 + 6 * dpr;
|
|
21107
|
+
if (X + reach + (showLabel ? 300 * dpr : 0) < 0 || X - reach > cw || Y + reach < 0 || Y - reach > ch) return;
|
|
20980
21108
|
// Gold以外の星はゆっくり瞬く
|
|
20981
21109
|
var tw = isGold ? 1 : 0.72 + 0.28 * (0.5 + 0.5 * Math.sin(now * 0.0017 + n.phase));
|
|
20982
21110
|
ctx.globalAlpha = alphaN * tw * glowAlpha(n);
|
|
20983
|
-
var r0 = nodeRadius(n);
|
|
20984
21111
|
var fill = isGold ? style.color : "#c9d6f2";
|
|
20985
21112
|
// 検索一致ノードとホバー中のノードは金色のリングで発光させる
|
|
20986
21113
|
if ((matched[n.id] || n === hovered) && !dim) {
|
|
20987
|
-
|
|
20988
|
-
ctx.shadowColor = "#fcd34d";
|
|
20989
|
-
ctx.shadowBlur = 18;
|
|
21114
|
+
drawHalo("#fcd34d", R + 2 * dpr, 18, X, Y);
|
|
20990
21115
|
ctx.beginPath();
|
|
20991
|
-
ctx.arc(
|
|
21116
|
+
ctx.arc(X, Y, R + 2 * dpr, 0, TAU);
|
|
20992
21117
|
ctx.fillStyle = fill;
|
|
20993
21118
|
ctx.fill();
|
|
20994
|
-
ctx.restore();
|
|
20995
21119
|
ctx.strokeStyle = "#fcd34d";
|
|
20996
|
-
ctx.lineWidth = 2.5
|
|
21120
|
+
ctx.lineWidth = 2.5 * dpr;
|
|
20997
21121
|
ctx.beginPath();
|
|
20998
|
-
ctx.arc(
|
|
21122
|
+
ctx.arc(X, Y, R + 3.5 * dpr, 0, TAU);
|
|
20999
21123
|
ctx.stroke();
|
|
21000
21124
|
}
|
|
21001
21125
|
// 星本体(色のにじみ=グロー付き)
|
|
21002
|
-
|
|
21003
|
-
ctx.save();
|
|
21004
|
-
ctx.shadowColor =
|
|
21005
|
-
introFlash > 0.01 ? "#bcd0ff" : isGold ? style.color : "#9fb4e8";
|
|
21006
|
-
ctx.shadowBlur =
|
|
21007
|
-
(isGold ? (n.glow === null || matched[n.id] ? Math.max(16, n.glow === null ? 16 : 6 + 22 * n.glow) : 6 + 22 * n.glow) : 7) * (dim ? 0.3 : 1) * (inChain ? 1.7 : 1) * (1 + introFlash * 1.8);
|
|
21126
|
+
drawHalo(introFlash > 0.01 ? "#bcd0ff" : isGold ? style.color : "#9fb4e8", R, blur, X, Y);
|
|
21008
21127
|
ctx.beginPath();
|
|
21009
|
-
ctx.arc(
|
|
21128
|
+
ctx.arc(X, Y, R, 0, TAU);
|
|
21010
21129
|
ctx.fillStyle = fill;
|
|
21011
21130
|
ctx.fill();
|
|
21012
|
-
|
|
21013
|
-
// ラベル: Gold層レコードはズームイン時のみ表示(引いて全体表示中は出さない)。
|
|
21014
|
-
// それ以外はホバーの連鎖に入ったときか検索ヒット時のみ(ズームに関係なく表示)。
|
|
21015
|
-
if ((n.recordId && view.scale >= LABEL_MIN_SCALE) || (hovered && lin[n.id] !== undefined && sweepRamp(lin[n.id]) > 0.15) || (searching && lit[n.id])) {
|
|
21016
|
-
ctx.fillStyle = dim ? "#3d4763" : matched[n.id] ? "#fde68a" : isGold ? "#e7edfb" : "#9fb0d6";
|
|
21017
|
-
ctx.font = (matched[n.id] ? "600 " : "") + (11 / view.scale) + "px 'Noto Sans JP', sans-serif";
|
|
21131
|
+
if (showLabel) {
|
|
21018
21132
|
var label = n.label.length > 24 ? n.label.slice(0, 23) + "…" : n.label;
|
|
21019
|
-
|
|
21133
|
+
drawLabel(label, dim ? "#3d4763" : matched[n.id] ? "#fde68a" : isGold ? "#e7edfb" : "#9fb0d6", !!matched[n.id], X + R + 4 * dpr, Y + 4 * dpr);
|
|
21020
21134
|
}
|
|
21021
21135
|
});
|
|
21022
21136
|
ctx.globalAlpha = 1;
|
|
@@ -21054,7 +21168,7 @@ ${calendarAddUrl.toString()}
|
|
|
21054
21168
|
return;
|
|
21055
21169
|
}
|
|
21056
21170
|
var nh = nodeAt(ev.clientX, ev.clientY);
|
|
21057
|
-
if (nh !== hovered) { hovered = nh; hoverStart = nh ? performance.now() : 0; } // 別ノードでスイープ再生
|
|
21171
|
+
if (nh !== hovered) { hovered = nh; hoverStart = nh ? performance.now() : 0; poke(HOVER_SWEEP_MS); } // 別ノードでスイープ再生
|
|
21058
21172
|
canvas.style.cursor = hovered ? "pointer" : "grab";
|
|
21059
21173
|
});
|
|
21060
21174
|
canvas.addEventListener("mousedown", function (ev) {
|
|
@@ -21086,6 +21200,7 @@ ${calendarAddUrl.toString()}
|
|
|
21086
21200
|
view.x = mx - (mx - view.x) * factor;
|
|
21087
21201
|
view.y = my - (my - view.y) * factor;
|
|
21088
21202
|
view.scale *= factor;
|
|
21203
|
+
poke(250);
|
|
21089
21204
|
}, { passive: false });
|
|
21090
21205
|
|
|
21091
21206
|
// ビルド時に座標計算済みなら、ウォームアップ(重い同期計算)を完全に省略する=開いた瞬間ゼロ待ち。
|
|
@@ -21104,10 +21219,17 @@ ${calendarAddUrl.toString()}
|
|
|
21104
21219
|
if (!running || !document.body.contains(canvas)) { running = false; return; }
|
|
21105
21220
|
// 収束後(alpha減衰しきり・無操作)は O(n²) の物理計算 tick を止める。これが「固まり続ける」主因。
|
|
21106
21221
|
// ドラッグ/パン中は動かす必要があるので回す。描画(draw)はホバー演出・イントロのため毎フレーム続ける。
|
|
21107
|
-
|
|
21108
|
-
|
|
21222
|
+
var moving = alpha > 0.004 || draggingNode || panning;
|
|
21223
|
+
if (moving) tick();
|
|
21224
|
+
// 動いている・操作の直後・イントロ・自動フレーミングの途中は毎フレーム描く。止まっている間は瞬きのためだけに間引いて描く(engine #551)
|
|
21225
|
+
var now = performance.now();
|
|
21226
|
+
if (moving || introStart || fitMoving || now < activeUntil || now - lastDrawAt >= IDLE_FRAME_MS) {
|
|
21227
|
+
lastDrawAt = now;
|
|
21228
|
+
draw();
|
|
21229
|
+
}
|
|
21109
21230
|
requestAnimationFrame(loop);
|
|
21110
21231
|
}
|
|
21232
|
+
var lastDrawAt = 0;
|
|
21111
21233
|
loop();
|
|
21112
21234
|
}
|
|
21113
21235
|
|
package/package.json
CHANGED