mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 14:32:22 -04:00
Merge branch 'main' into patch-2
This commit is contained in:
commit
9384938ed3
10 changed files with 142 additions and 62 deletions
2
.version
2
.version
|
@ -1 +1 @@
|
||||||
25.08b4
|
25.08b5
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit a0d0e232d296ccf5750e39df2442b133267b222b
|
Subproject commit a599715d3c27ff2eb895c749f3534ab73d83dad1
|
|
@ -517,7 +517,6 @@ deck-config-smooth-graph = Smooth graph
|
||||||
deck-config-suspend-leeches = Suspend leeches
|
deck-config-suspend-leeches = Suspend leeches
|
||||||
deck-config-save-options-to-preset = Save Changes to Preset
|
deck-config-save-options-to-preset = Save Changes to Preset
|
||||||
deck-config-save-options-to-preset-confirm = Overwrite the options in your current preset with the options that are currently set in the simulator?
|
deck-config-save-options-to-preset-confirm = Overwrite the options in your current preset with the options that are currently set in the simulator?
|
||||||
deck-config-plotted-on-x-axis = (Plotted on the X-axis)
|
|
||||||
# Radio button in the FSRS simulation diagram (Deck options -> FSRS) selecting
|
# Radio button in the FSRS simulation diagram (Deck options -> FSRS) selecting
|
||||||
# to show the total number of cards that can be recalled or retrieved on a
|
# to show the total number of cards that can be recalled or retrieved on a
|
||||||
# specific date.
|
# specific date.
|
||||||
|
@ -545,6 +544,7 @@ deck-config-fsrs-good-fit = Health Check:
|
||||||
|
|
||||||
## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future.
|
## NO NEED TO TRANSLATE. This text is no longer used by Anki, and will be removed in the future.
|
||||||
|
|
||||||
|
deck-config-plotted-on-x-axis = (Plotted on the X-axis)
|
||||||
deck-config-a-100-day-interval =
|
deck-config-a-100-day-interval =
|
||||||
{ $days ->
|
{ $days ->
|
||||||
[one] A 100 day interval will become { $days } day.
|
[one] A 100 day interval will become { $days } day.
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 9639c96fe5862459aa1ff4e599079cac72a9fd7c
|
Subproject commit bb4207f3b8e9a7c428db282d12c75b850be532f3
|
|
@ -46,6 +46,7 @@ struct State {
|
||||||
uv_lock_path: std::path::PathBuf,
|
uv_lock_path: std::path::PathBuf,
|
||||||
sync_complete_marker: std::path::PathBuf,
|
sync_complete_marker: std::path::PathBuf,
|
||||||
launcher_trigger_file: std::path::PathBuf,
|
launcher_trigger_file: std::path::PathBuf,
|
||||||
|
mirror_path: std::path::PathBuf,
|
||||||
pyproject_modified_by_user: bool,
|
pyproject_modified_by_user: bool,
|
||||||
previous_version: Option<String>,
|
previous_version: Option<String>,
|
||||||
resources_dir: std::path::PathBuf,
|
resources_dir: std::path::PathBuf,
|
||||||
|
@ -71,6 +72,7 @@ pub enum MainMenuChoice {
|
||||||
Version(VersionKind),
|
Version(VersionKind),
|
||||||
ToggleBetas,
|
ToggleBetas,
|
||||||
ToggleCache,
|
ToggleCache,
|
||||||
|
DownloadMirror,
|
||||||
Uninstall,
|
Uninstall,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +110,7 @@ fn run() -> Result<()> {
|
||||||
uv_lock_path: uv_install_root.join("uv.lock"),
|
uv_lock_path: uv_install_root.join("uv.lock"),
|
||||||
sync_complete_marker: uv_install_root.join(".sync_complete"),
|
sync_complete_marker: uv_install_root.join(".sync_complete"),
|
||||||
launcher_trigger_file: uv_install_root.join(".want-launcher"),
|
launcher_trigger_file: uv_install_root.join(".want-launcher"),
|
||||||
|
mirror_path: uv_install_root.join("mirror"),
|
||||||
pyproject_modified_by_user: false, // calculated later
|
pyproject_modified_by_user: false, // calculated later
|
||||||
previous_version: None,
|
previous_version: None,
|
||||||
resources_dir,
|
resources_dir,
|
||||||
|
@ -155,12 +158,7 @@ fn run() -> Result<()> {
|
||||||
|
|
||||||
check_versions(&mut state);
|
check_versions(&mut state);
|
||||||
|
|
||||||
let first_run = !state.venv_folder.exists();
|
main_menu_loop(&state)?;
|
||||||
if first_run {
|
|
||||||
handle_version_install_or_update(&state, MainMenuChoice::Latest)?;
|
|
||||||
} else {
|
|
||||||
main_menu_loop(&state)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write marker file to indicate we've completed the sync process
|
// Write marker file to indicate we've completed the sync process
|
||||||
write_sync_marker(&state)?;
|
write_sync_marker(&state)?;
|
||||||
|
@ -379,6 +377,11 @@ fn main_menu_loop(state: &State) -> Result<()> {
|
||||||
println!();
|
println!();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
MainMenuChoice::DownloadMirror => {
|
||||||
|
show_mirror_submenu(state)?;
|
||||||
|
println!();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
MainMenuChoice::Uninstall => {
|
MainMenuChoice::Uninstall => {
|
||||||
if handle_uninstall(state)? {
|
if handle_uninstall(state)? {
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
|
@ -443,8 +446,13 @@ fn get_main_menu_choice(state: &State) -> Result<MainMenuChoice> {
|
||||||
"6) Cache downloads: {}",
|
"6) Cache downloads: {}",
|
||||||
if cache_enabled { "on" } else { "off" }
|
if cache_enabled { "on" } else { "off" }
|
||||||
);
|
);
|
||||||
|
let mirror_enabled = is_mirror_enabled(state);
|
||||||
|
println!(
|
||||||
|
"7) Download mirror: {}",
|
||||||
|
if mirror_enabled { "on" } else { "off" }
|
||||||
|
);
|
||||||
println!();
|
println!();
|
||||||
println!("7) Uninstall");
|
println!("8) Uninstall");
|
||||||
print!("> ");
|
print!("> ");
|
||||||
let _ = stdout().flush();
|
let _ = stdout().flush();
|
||||||
|
|
||||||
|
@ -483,7 +491,8 @@ fn get_main_menu_choice(state: &State) -> Result<MainMenuChoice> {
|
||||||
}
|
}
|
||||||
"5" => MainMenuChoice::ToggleBetas,
|
"5" => MainMenuChoice::ToggleBetas,
|
||||||
"6" => MainMenuChoice::ToggleCache,
|
"6" => MainMenuChoice::ToggleCache,
|
||||||
"7" => MainMenuChoice::Uninstall,
|
"7" => MainMenuChoice::DownloadMirror,
|
||||||
|
"8" => MainMenuChoice::Uninstall,
|
||||||
_ => {
|
_ => {
|
||||||
println!("Invalid input. Please try again.");
|
println!("Invalid input. Please try again.");
|
||||||
continue;
|
continue;
|
||||||
|
@ -652,7 +661,7 @@ fn fetch_versions(state: &State) -> Result<Vec<String>> {
|
||||||
let mut cmd = Command::new(&state.uv_path);
|
let mut cmd = Command::new(&state.uv_path);
|
||||||
cmd.current_dir(&state.uv_install_root)
|
cmd.current_dir(&state.uv_install_root)
|
||||||
.args(["run", "--no-project", "--no-config", "--managed-python"])
|
.args(["run", "--no-project", "--no-config", "--managed-python"])
|
||||||
.args(["--with", "pip-system-certs"]);
|
.args(["--with", "pip-system-certs,requests[socks]"]);
|
||||||
|
|
||||||
let python_version = read_file(&state.dist_python_version_path)?;
|
let python_version = read_file(&state.dist_python_version_path)?;
|
||||||
let python_version_str =
|
let python_version_str =
|
||||||
|
@ -716,7 +725,15 @@ fn apply_version_kind(version_kind: &VersionKind, state: &State) -> Result<()> {
|
||||||
&format!("anki-release=={version}\",\n \"anki=={version}\",\n \"aqt=={version}"),
|
&format!("anki-release=={version}\",\n \"anki=={version}\",\n \"aqt=={version}"),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
write_file(&state.user_pyproject_path, &updated_content)?;
|
|
||||||
|
// Add mirror configuration if enabled
|
||||||
|
let final_content = if let Some((python_mirror, pypi_mirror)) = get_mirror_urls(state)? {
|
||||||
|
format!("{updated_content}\n\n[[tool.uv.index]]\nname = \"mirror\"\nurl = \"{pypi_mirror}\"\ndefault = true\n\n[tool.uv]\npython-install-mirror = \"{python_mirror}\"\n")
|
||||||
|
} else {
|
||||||
|
updated_content
|
||||||
|
};
|
||||||
|
|
||||||
|
write_file(&state.user_pyproject_path, &final_content)?;
|
||||||
|
|
||||||
// Update .python-version based on version kind
|
// Update .python-version based on version kind
|
||||||
match version_kind {
|
match version_kind {
|
||||||
|
@ -750,6 +767,9 @@ fn update_pyproject_for_version(menu_choice: MainMenuChoice, state: &State) -> R
|
||||||
MainMenuChoice::ToggleCache => {
|
MainMenuChoice::ToggleCache => {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
MainMenuChoice::DownloadMirror => {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
MainMenuChoice::Uninstall => {
|
MainMenuChoice::Uninstall => {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
|
@ -939,6 +959,70 @@ fn build_python_command(state: &State, args: &[String]) -> Result<Command> {
|
||||||
Ok(cmd)
|
Ok(cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_mirror_enabled(state: &State) -> bool {
|
||||||
|
state.mirror_path.exists()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mirror_urls(state: &State) -> Result<Option<(String, String)>> {
|
||||||
|
if !state.mirror_path.exists() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = read_file(&state.mirror_path)?;
|
||||||
|
let content_str = String::from_utf8(content).context("Invalid UTF-8 in mirror file")?;
|
||||||
|
|
||||||
|
let lines: Vec<&str> = content_str.lines().collect();
|
||||||
|
if lines.len() >= 2 {
|
||||||
|
Ok(Some((
|
||||||
|
lines[0].trim().to_string(),
|
||||||
|
lines[1].trim().to_string(),
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_mirror_submenu(state: &State) -> Result<()> {
|
||||||
|
loop {
|
||||||
|
println!("Download mirror options:");
|
||||||
|
println!("1) No mirror");
|
||||||
|
println!("2) China");
|
||||||
|
print!("> ");
|
||||||
|
let _ = stdout().flush();
|
||||||
|
|
||||||
|
let mut input = String::new();
|
||||||
|
let _ = stdin().read_line(&mut input);
|
||||||
|
let input = input.trim();
|
||||||
|
|
||||||
|
match input {
|
||||||
|
"1" => {
|
||||||
|
// Remove mirror file
|
||||||
|
if state.mirror_path.exists() {
|
||||||
|
let _ = remove_file(&state.mirror_path);
|
||||||
|
}
|
||||||
|
println!("Mirror disabled.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
"2" => {
|
||||||
|
// Write China mirror URLs
|
||||||
|
let china_mirrors = "https://registry.npmmirror.com/-/binary/python-build-standalone/\nhttps://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/";
|
||||||
|
write_file(&state.mirror_path, china_mirrors)?;
|
||||||
|
println!("China mirror enabled.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
"" => {
|
||||||
|
// Empty input - return to main menu
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("Invalid input. Please try again.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
import urllib.request
|
|
||||||
|
|
||||||
import pip_system_certs.wrapt_requests
|
import pip_system_certs.wrapt_requests
|
||||||
|
import requests
|
||||||
|
|
||||||
pip_system_certs.wrapt_requests.inject_truststore()
|
pip_system_certs.wrapt_requests.inject_truststore()
|
||||||
|
|
||||||
|
@ -15,25 +15,26 @@ def main():
|
||||||
url = "https://pypi.org/pypi/aqt/json"
|
url = "https://pypi.org/pypi/aqt/json"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with urllib.request.urlopen(url, timeout=30) as response:
|
response = requests.get(url, timeout=30)
|
||||||
data = json.loads(response.read().decode("utf-8"))
|
response.raise_for_status()
|
||||||
releases = data.get("releases", {})
|
data = response.json()
|
||||||
|
releases = data.get("releases", {})
|
||||||
|
|
||||||
# Create list of (version, upload_time) tuples
|
# Create list of (version, upload_time) tuples
|
||||||
version_times = []
|
version_times = []
|
||||||
for version, files in releases.items():
|
for version, files in releases.items():
|
||||||
if files: # Only include versions that have files
|
if files: # Only include versions that have files
|
||||||
# Use the upload time of the first file for each version
|
# Use the upload time of the first file for each version
|
||||||
upload_time = files[0].get("upload_time_iso_8601")
|
upload_time = files[0].get("upload_time_iso_8601")
|
||||||
if upload_time:
|
if upload_time:
|
||||||
version_times.append((version, upload_time))
|
version_times.append((version, upload_time))
|
||||||
|
|
||||||
# Sort by upload time
|
# Sort by upload time
|
||||||
version_times.sort(key=lambda x: x[1])
|
version_times.sort(key=lambda x: x[1])
|
||||||
|
|
||||||
# Extract just the version names
|
# Extract just the version names
|
||||||
versions = [version for version, _ in version_times]
|
versions = [version for version, _ in version_times]
|
||||||
print(json.dumps(versions))
|
print(json.dumps(versions))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error fetching versions: {e}", file=sys.stderr)
|
print(f"Error fetching versions: {e}", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
|
@ -105,7 +105,7 @@ impl Card {
|
||||||
|
|
||||||
/// Returns true if the card has a due date in terms of days.
|
/// Returns true if the card has a due date in terms of days.
|
||||||
fn is_due_in_days(&self) -> bool {
|
fn is_due_in_days(&self) -> bool {
|
||||||
self.original_or_current_due() <= 365_000 // keep consistent with SQL
|
self.ctype != CardType::New && self.original_or_current_due() <= 365_000 // keep consistent with SQL
|
||||||
|| matches!(self.queue, CardQueue::DayLearn | CardQueue::Review)
|
|| matches!(self.queue, CardQueue::DayLearn | CardQueue::Review)
|
||||||
|| (self.ctype == CardType::Review && self.is_undue_queue())
|
|| (self.ctype == CardType::Review && self.is_undue_queue())
|
||||||
}
|
}
|
||||||
|
@ -132,15 +132,14 @@ impl Card {
|
||||||
pub(crate) fn seconds_since_last_review(&self, timing: &SchedTimingToday) -> Option<u32> {
|
pub(crate) fn seconds_since_last_review(&self, timing: &SchedTimingToday) -> Option<u32> {
|
||||||
if let Some(last_review_time) = self.last_review_time {
|
if let Some(last_review_time) = self.last_review_time {
|
||||||
Some(timing.now.elapsed_secs_since(last_review_time) as u32)
|
Some(timing.now.elapsed_secs_since(last_review_time) as u32)
|
||||||
} else if !self.is_due_in_days() {
|
} else if self.is_due_in_days() {
|
||||||
let last_review_time =
|
|
||||||
TimestampSecs(self.original_or_current_due() as i64 - self.interval as i64);
|
|
||||||
Some(timing.now.elapsed_secs_since(last_review_time) as u32)
|
|
||||||
} else {
|
|
||||||
self.due_time(timing).map(|due| {
|
self.due_time(timing).map(|due| {
|
||||||
(due.adding_secs(-86_400 * self.interval as i64)
|
(due.adding_secs(-86_400 * self.interval as i64)
|
||||||
.elapsed_secs()) as u32
|
.elapsed_secs()) as u32
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
let last_review_time = TimestampSecs(self.original_or_current_due() as i64);
|
||||||
|
Some(timing.now.elapsed_secs_since(last_review_time) as u32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,8 +44,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
import Warning from "./Warning.svelte";
|
import Warning from "./Warning.svelte";
|
||||||
import type { ComputeRetentionProgress } from "@generated/anki/collection_pb";
|
import type { ComputeRetentionProgress } from "@generated/anki/collection_pb";
|
||||||
import Modal from "bootstrap/js/dist/modal";
|
import Modal from "bootstrap/js/dist/modal";
|
||||||
import Row from "$lib/components/Row.svelte";
|
|
||||||
import Col from "$lib/components/Col.svelte";
|
|
||||||
|
|
||||||
export let state: DeckOptionsState;
|
export let state: DeckOptionsState;
|
||||||
export let simulateFsrsRequest: SimulateFsrsReviewRequest;
|
export let simulateFsrsRequest: SimulateFsrsReviewRequest;
|
||||||
|
@ -373,23 +371,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
{tr.deckConfigDesiredRetention()}
|
{tr.deckConfigDesiredRetention()}
|
||||||
</SettingTitle>
|
</SettingTitle>
|
||||||
</SpinBoxFloatRow>
|
</SpinBoxFloatRow>
|
||||||
{:else}
|
|
||||||
<Row --cols={13}>
|
|
||||||
<Col --col-size={7} breakpoint="xs">
|
|
||||||
<SettingTitle
|
|
||||||
on:click={() => openHelpModal("desiredRetention")}
|
|
||||||
>
|
|
||||||
{tr.deckConfigDesiredRetention()}
|
|
||||||
</SettingTitle>
|
|
||||||
</Col>
|
|
||||||
<Col --col-size={6} breakpoint="xs">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
disabled
|
|
||||||
value={tr.deckConfigPlottedOnXAxis()}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<SpinBoxRow
|
<SpinBoxRow
|
||||||
|
|
|
@ -55,7 +55,10 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: nowrap;
|
flex-wrap: nowrap;
|
||||||
justify-content: space-between;
|
&:has(li:nth-child(3)) {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
justify-content: space-around;
|
||||||
padding-inline: 0;
|
padding-inline: 0;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
|
|
@ -74,6 +74,13 @@ export function renderWorkloadChart(
|
||||||
: n.toString();
|
: n.toString();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const formatter = new Intl.NumberFormat(undefined, {
|
||||||
|
style: "percent",
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 0,
|
||||||
|
});
|
||||||
|
const xTickFormat = (n: number) => formatter.format(n / 100);
|
||||||
|
|
||||||
const formatY: (value: number) => string = ({
|
const formatY: (value: number) => string = ({
|
||||||
[SimulateWorkloadSubgraph.ratio]: (value: number) =>
|
[SimulateWorkloadSubgraph.ratio]: (value: number) =>
|
||||||
tr.deckConfigFsrsSimulatorRatioTooltip({ time: timeSpan(value) }),
|
tr.deckConfigFsrsSimulatorRatioTooltip({ time: timeSpan(value) }),
|
||||||
|
@ -85,7 +92,7 @@ export function renderWorkloadChart(
|
||||||
})[subgraph];
|
})[subgraph];
|
||||||
|
|
||||||
function formatX(dr: number) {
|
function formatX(dr: number) {
|
||||||
return `Desired Retention: ${dr}%<br>`;
|
return `${tr.deckConfigDesiredRetention()}: ${xTickFormat(dr)}<br>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _renderSimulationChart(
|
return _renderSimulationChart(
|
||||||
|
@ -93,10 +100,11 @@ export function renderWorkloadChart(
|
||||||
bounds,
|
bounds,
|
||||||
subgraph_data,
|
subgraph_data,
|
||||||
x,
|
x,
|
||||||
yTickFormat,
|
|
||||||
formatY,
|
formatY,
|
||||||
formatX,
|
formatX,
|
||||||
(_e: MouseEvent, _d: number) => undefined,
|
(_e: MouseEvent, _d: number) => undefined,
|
||||||
|
yTickFormat,
|
||||||
|
xTickFormat,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,10 +177,11 @@ export function renderSimulationChart(
|
||||||
bounds,
|
bounds,
|
||||||
subgraph_data,
|
subgraph_data,
|
||||||
x,
|
x,
|
||||||
yTickFormat,
|
|
||||||
formatY,
|
formatY,
|
||||||
formatX,
|
formatX,
|
||||||
legendMouseMove,
|
legendMouseMove,
|
||||||
|
yTickFormat,
|
||||||
|
undefined,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -181,10 +190,11 @@ function _renderSimulationChart<T extends { x: any; y: any; label: number }>(
|
||||||
bounds: GraphBounds,
|
bounds: GraphBounds,
|
||||||
subgraph_data: T[],
|
subgraph_data: T[],
|
||||||
x: any,
|
x: any,
|
||||||
yTickFormat: (n: number) => string,
|
|
||||||
formatY: (n: T["y"]) => string,
|
formatY: (n: T["y"]) => string,
|
||||||
formatX: (n: T["x"]) => string,
|
formatX: (n: T["x"]) => string,
|
||||||
legendMouseMove: (e: MouseEvent, d: number) => void,
|
legendMouseMove: (e: MouseEvent, d: number) => void,
|
||||||
|
yTickFormat?: (n: number) => string,
|
||||||
|
xTickFormat?: (n: number) => string,
|
||||||
): TableDatum[] {
|
): TableDatum[] {
|
||||||
const svg = select(svgElem);
|
const svg = select(svgElem);
|
||||||
svg.selectAll(".lines").remove();
|
svg.selectAll(".lines").remove();
|
||||||
|
@ -198,7 +208,9 @@ function _renderSimulationChart<T extends { x: any; y: any; label: number }>(
|
||||||
const trans = svg.transition().duration(600) as any;
|
const trans = svg.transition().duration(600) as any;
|
||||||
|
|
||||||
svg.select<SVGGElement>(".x-ticks")
|
svg.select<SVGGElement>(".x-ticks")
|
||||||
.call((selection) => selection.transition(trans).call(axisBottom(x).ticks(7).tickSizeOuter(0)))
|
.call((selection) =>
|
||||||
|
selection.transition(trans).call(axisBottom(x).ticks(7).tickSizeOuter(0).tickFormat(xTickFormat as any))
|
||||||
|
)
|
||||||
.attr("direction", "ltr");
|
.attr("direction", "ltr");
|
||||||
// y scale
|
// y scale
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue