feat: emphasize active skill windows by score impact
Publish GitHub Pages output / publish (push) Successful in 50s
Publish GitHub Pages output / publish (push) Successful in 50s
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { ANALYSIS_TRANSFER_KEY, parseAnalysisTransfer, transferredAnalysisKey } from '$lib/models/analysis-transfer.ts';
|
||||
import { onMount, tick } from 'svelte';
|
||||
import { activeWindowKey, calculateActiveImpacts } from '$lib/engine/active-impact.ts';
|
||||
import LeaderSongRanking from '$lib/components/LeaderSongRanking.svelte';
|
||||
import { analytics } from '$lib/analytics.ts';
|
||||
import AnalysisHistory from '$lib/components/AnalysisHistory.svelte';
|
||||
@@ -133,6 +134,13 @@
|
||||
excludedActiveWindows = [];
|
||||
}
|
||||
$: displayedResult = simulatedResult ?? result;
|
||||
$: activeImpacts = result && simulationContext && mode === 'analysis'
|
||||
? calculateActiveImpacts(
|
||||
result.order.map((id) => simulationContext!.cards.find((card) => card.id === id)!),
|
||||
result.cooldownReductions, simulationContext.chart,
|
||||
{ ...simulationContext.options, excludedActiveWindows }, result.activeWindows
|
||||
)
|
||||
: new Map<string, { scoreChange: number; strength: number }>();
|
||||
|
||||
function isExcluded(window: SkillWindow): boolean {
|
||||
return excludedActiveWindows.some((excluded) => excluded.cardId === window.cardId && excluded.startSeconds === window.startSeconds);
|
||||
@@ -1197,7 +1205,7 @@
|
||||
</ol>
|
||||
</details>
|
||||
{/if}
|
||||
<p class="simulation-guide" aria-live="polite">카드별 색칠된 구간을 클릭하면 해당 액티브만 미발동으로 계산합니다. 다시 클릭하면 복원됩니다. 배치와 쿨타임은 유지됩니다.
|
||||
<p class="simulation-guide" aria-live="polite">카드별 색칠된 구간을 클릭하면 해당 액티브만 미발동으로 계산합니다. 다시 클릭하면 복원됩니다. 배치와 쿨타임은 유지됩니다. 색이 진하고 테두리가 굵을수록 현재 설정에서 토글할 때 최고점 변화가 큽니다. 빗금은 미발동 상태이며, 해당 구간은 복원 시 영향력을 표시합니다.
|
||||
{#if excludedActiveWindows.length}
|
||||
<strong>{excludedActiveWindows.length}회 미발동 적용 중</strong>
|
||||
<button type="button" on:click={resetActiveWindows}>모두 복원</button>
|
||||
@@ -1213,14 +1221,15 @@
|
||||
<strong class="lane-label"><small style={`--member-color: ${memberColor(cardId)};`}>{slot + 1}</small>{resultCardName(cardId)}</strong>
|
||||
<div class="timeline-track skill-track" style={timelineTrackStyle(timelineWidth, timelineDuration)}>
|
||||
{#each result.activeWindows.filter((window) => window.cardId === cardId) as window}
|
||||
{@const impact = activeImpacts.get(activeWindowKey(window))}
|
||||
<button
|
||||
type="button"
|
||||
class="skill-window active-window"
|
||||
class:excluded={excludedActiveWindows.some((excluded) => excluded.cardId === window.cardId && excluded.startSeconds === window.startSeconds)}
|
||||
disabled={mode !== 'analysis' || !simulationContext || running}
|
||||
style={coloredWindowStyle(window, timelineDuration)}
|
||||
title={`${resultCardName(cardId)} 액티브 ${formatSeconds(window.startSeconds)}~${formatSeconds(window.endSeconds)} · ${window.scoreUpPercent}% · 클릭하여 미발동/복원`}
|
||||
aria-label={`${resultCardName(cardId)} 액티브 ${formatSeconds(window.startSeconds)}부터 ${formatSeconds(window.endSeconds)}까지 미발동 처리`}
|
||||
style={coloredWindowStyle(window, timelineDuration) + (impact ? ` --impact-opacity: ${0.25 + 0.75 * Math.sqrt(impact.strength)}; --impact-border: ${impact.strength > 0 ? 1 + 2 * impact.strength : 0}px;` : '')}
|
||||
title={`${resultCardName(cardId)} 액티브 ${formatSeconds(window.startSeconds)}~${formatSeconds(window.endSeconds)} · ${window.scoreUpPercent}% · 클릭하여 미발동/복원${impact ? ` · 토글 시 최고점 ${signedScoreChange(impact.scoreChange)}` : ''}`}
|
||||
aria-label={`${resultCardName(cardId)} 액티브 ${formatSeconds(window.startSeconds)}부터 ${formatSeconds(window.endSeconds)}까지 미발동 처리${impact ? ` · 토글 시 최고점 ${signedScoreChange(impact.scoreChange)}` : ''}`}
|
||||
aria-pressed={excludedActiveWindows.some((excluded) => excluded.cardId === window.cardId && excluded.startSeconds === window.startSeconds)}
|
||||
on:click={() => toggleActiveWindow(window)}
|
||||
></button>
|
||||
@@ -1405,9 +1414,9 @@
|
||||
.timeline-track::before { content: ''; position: absolute; inset: 0; background: linear-gradient(90deg, rgb(255 255 255 / 9%) 1px, transparent 1px); background-size: var(--time-grid-step, 10%) 100%; pointer-events: none; }
|
||||
.skill-track { height: 36px; }
|
||||
.skill-window { position: absolute; min-width: 2px; border-radius: 3px; background: var(--member-color); }
|
||||
.active-window { top: 8px; height: 20px; opacity: .72; padding: 0; border: 0; cursor: pointer; }
|
||||
.active-window { top: 8px; height: 20px; opacity: var(--impact-opacity, .72); padding: 0; border: 0; box-shadow: inset 0 0 0 var(--impact-border, 0px) rgb(255 255 255 / 85%); cursor: pointer; }
|
||||
.active-window:hover:not(:disabled), .active-window:focus-visible { opacity: 1; outline: 2px solid #fff; outline-offset: 2px; }
|
||||
.active-window.excluded { opacity: .28; border: 1px dashed var(--member-color); background: repeating-linear-gradient(135deg, transparent 0 3px, var(--member-color) 3px 4px); }
|
||||
.active-window.excluded { opacity: var(--impact-opacity, .28); border: 1px dashed var(--member-color); background: repeating-linear-gradient(135deg, transparent 0 3px, var(--member-color) 3px 4px); }
|
||||
.active-window:disabled { cursor: default; }
|
||||
.timeline-score-summary { display: flex; flex-wrap: wrap; gap: 16px 32px; padding: 16px; margin-bottom: 12px; border: 1px solid #454052; border-radius: 10px; background: #22202a; }
|
||||
.timeline-score-summary > div { display: grid; gap: 6px; }
|
||||
|
||||
Reference in New Issue
Block a user