diff --git a/docs/guide/executing_experiment.rst b/docs/guide/executing_experiment.rst index 78ee59c..f56d3b1 100644 --- a/docs/guide/executing_experiment.rst +++ b/docs/guide/executing_experiment.rst @@ -15,6 +15,8 @@ The `` can be one of the following: - `stage`: Prepare the environment and models. - `plot`: Plot forecasts, catalogs, and results. - `reproduce`: (see folllowing\ section) Reproduce the results of a previously run experiment. +- `view`: Export the experiment as a web dashboard and open it in the browser (see :ref:`dashboard`). +- `export`, `serve`: The two steps of `view`, run separately. Each command requires a configuration file (in `YAML` format), which defines the parameters of the experiment. diff --git a/docs/index.rst b/docs/index.rst index 0740c3f..9aee92a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -192,6 +192,7 @@ Collaborators guide/evaluation_config.rst guide/postprocess_config.rst guide/executing_experiment.rst + guide/dashboard.rst .. sidebar-links:: diff --git a/environment.yml b/environment.yml index 5a6305a..45fd00f 100644 --- a/environment.yml +++ b/environment.yml @@ -11,7 +11,6 @@ dependencies: - gitpython - h5py - matplotlib - - panel - pip - pyshp - pyyaml diff --git a/floatcsep/commands/main.py b/floatcsep/commands/main.py index 9d29009..ab466c7 100644 --- a/floatcsep/commands/main.py +++ b/floatcsep/commands/main.py @@ -1,5 +1,6 @@ import argparse import logging +from pathlib import Path from floatcsep import __version__ from floatcsep.experiment import Experiment, ExperimentComparison @@ -11,7 +12,7 @@ plot_custom, ) from floatcsep.postprocess.reporting import generate_report, reproducibility_report -from floatcsep.postprocess.panel import run_app +from floatcsep.postprocess.web import export_experiment, serve as serve_dashboard setup_logger() log = logging.getLogger("floatLogger") @@ -130,36 +131,85 @@ def plot(config: str, **kwargs) -> None: log.debug("") -def view(config: str, **kwargs) -> None: +def view(config: str, out: str = None, port: int = 8765, no_browser: bool = False, **kwargs) -> None: """ - Launch an interactive Panel-based data viewer for an existing experiment. + Exports an existing experiment as a static web dashboard and opens it in the browser. - This function loads the experiment configuration, reconstructs the model and - evaluation file tree, and starts a Panel server so that the user can explore the - catalogs, forecasts, and test results in a web browser. + It always re-exports, so the dashboard reflects the current results. Use + :func:`export` and :func:`serve` to do the two steps separately. Example usage from a terminal: :: floatcsep view + floatcsep view --port 8080 - Args - ---- - config : str - Path to the experiment configuration file (YAML format). - **kwargs : - Additional configuration parameters forwarded to `Experiment.from_yml`. - - Returns - ------- - None + Args: + config (str): Path to the experiment configuration file (YAML format). + out (str): Dashboard folder. Defaults to ``/dashboard``. + port (int): TCP port to serve on. + no_browser (bool): Do not open the browser automatically. + **kwargs: Additional configuration parameters forwarded to `Experiment.from_yml`. """ log.info(f"floatCSEP v{__version__} | View") exp = Experiment.from_yml(config_yml=config, **kwargs) exp.stage_models() exp.set_tree() - log.info(f"Creating Panel App") - run_app(experiment=exp, **kwargs) + folder = export_experiment(exp, out_dir=out) + serve_dashboard(folder, port=port, open_browser=not no_browser) + + +def export(config: str, out: str = None, **kwargs) -> None: + """ + Exports an existing experiment as a static web dashboard (``/dashboard``). + + The folder holds the experiment manifest, catalog, forecasts and results as JSON, plus + the front-end files, and can be served by any static web server or published as is. + + Example usage from a terminal: + :: + + floatcsep export + + Args: + config (str): Path to the experiment configuration file (YAML format). + out (str): Output folder. Defaults to ``/dashboard``. + **kwargs: Additional configuration parameters forwarded to `Experiment.from_yml`. + """ + log.info(f"floatCSEP v{__version__} | Export") + kwargs.pop("port", None) + kwargs.pop("no_browser", None) + exp = Experiment.from_yml(config_yml=config, **kwargs) + exp.stage_models() + exp.set_tree() + export_experiment(exp, out_dir=out) + log.info("Finalized") + + +def serve(config: str, out: str = None, port: int = 8765, no_browser: bool = False, **kwargs) -> None: + """ + Serves the static dashboard of an experiment, exporting it first if it does not exist. + + Example usage from a terminal: + :: + + floatcsep serve + floatcsep serve --port 8080 + + Args: + config (str): Path to the experiment configuration file (YAML format). + out (str): Dashboard folder. Defaults to ``/dashboard``. + port (int): TCP port to serve on. + no_browser (bool): Do not open the browser automatically. + """ + log.info(f"floatCSEP v{__version__} | Serve") + exp = Experiment.from_yml(config_yml=config, **kwargs) + folder = Path(out) if out else exp.registry.run_dir / "dashboard" + if not (folder / "manifest.json").exists(): + exp.stage_models() + exp.set_tree() + folder = export_experiment(exp, out_dir=out) + serve_dashboard(folder, port=port, open_browser=not no_browser) def reproduce(config: str, **kwargs) -> None: @@ -225,7 +275,7 @@ def floatcsep() -> None: parser.add_argument( "func", type=str, - choices=["run", "stage", "plot", "view", "reproduce"], + choices=["run", "stage", "plot", "view", "export", "serve", "reproduce"], help="Run a calculation", ) parser.add_argument("config", type=str, help="Experiment Configuration file") @@ -236,6 +286,11 @@ def floatcsep() -> None: "-t", "--timestamp", action="store_true", default=False, help="Timestamp results" ) + parser.add_argument("-o", "--out", type=str, help="Dashboard output folder (export/serve)") + parser.add_argument("-p", "--port", type=int, help="Port for `serve` (default 8765)") + parser.add_argument( + "--no-browser", action="store_true", help="Do not open the browser on `serve`" + ) parser.add_argument( "-d", "--debug", diff --git a/floatcsep/infrastructure/repositories.py b/floatcsep/infrastructure/repositories.py index 21e021d..26cfe97 100644 --- a/floatcsep/infrastructure/repositories.py +++ b/floatcsep/infrastructure/repositories.py @@ -10,7 +10,7 @@ from csep.core.catalogs import CSEPCatalog from csep.core.forecasts import GriddedForecast, CatalogForecast from csep.models import EvaluationResult -from csep.utils.time_utils import decimal_year +from csep.utils.time_utils import decimal_year, datetime_to_utc_epoch from floatcsep.infrastructure.registries import ( ExperimentRegistry, @@ -233,9 +233,9 @@ def get_input_cat(self, tstring: str) -> CSEPCatalog: """ start, end = str2timewindow(tstring) cfg = self.input_cat_config - filters = [f"origin_time < {start.timestamp() * 1000}"] + filters = [f"origin_time < {datetime_to_utc_epoch(start)}"] if cfg["start_date"]: - filters.append(f"origin_time >= {cfg['start_date'].timestamp() * 1000}") + filters.append(f"origin_time >= {datetime_to_utc_epoch(cfg['start_date'])}") if cfg["mag_min"] is not None: filters.append(f"magnitude >= {cfg['mag_min']}") if cfg["mag_max"] is not None: @@ -283,8 +283,8 @@ def set_test_cats(self, tstring: str, fmt: str = "json") -> None: ) start, end = str2timewindow(tstring) filters = [ - f"origin_time < {end.timestamp() * 1000}", - f"origin_time >= {start.timestamp() * 1000}", + f"origin_time < {datetime_to_utc_epoch(end)}", + f"origin_time >= {datetime_to_utc_epoch(start)}", f"magnitude >= {self.mag_min}", f"magnitude < {self.mag_max}", ] diff --git a/floatcsep/model.py b/floatcsep/model.py index 4308ffe..6b25ed2 100644 --- a/floatcsep/model.py +++ b/floatcsep/model.py @@ -12,7 +12,7 @@ from floatcsep.infrastructure.environments import EnvironmentFactory from floatcsep.infrastructure.registries import ModelRegistry -from floatcsep.infrastructure.repositories import ForecastRepository +from floatcsep.infrastructure.repositories import ForecastRepository, GriddedForecastRepository from floatcsep.utils.accessors import from_zenodo, from_git from floatcsep.utils.helpers import timewindow2str, str2timewindow, parse_nested_dicts @@ -383,10 +383,12 @@ def get_forecast( If None, will return a forecast for all regions. Note: - The number of synthetic catalogs is taken from ``func_kwargs['n_sims']`` (or a - model-level ``n_sims``). Without it, pyCSEP infers it from the largest + For catalog-based forecasts, the number of synthetic catalogs is taken from + ``func_kwargs['n_sims']`` (or a model-level ``n_sims``). Without it, pyCSEP infers it from the largest ``catalog_id`` in the file, which misses trailing empty catalogs. """ + if isinstance(self.repository, GriddedForecastRepository): + return self.repository.load_forecast(tstring, name=self.name, region=region) n_sims = self.func_kwargs.get("n_sims") or self.__dict__.get("n_sims") return self.repository.load_forecast( tstring, name=self.name, region=region, n_sims=n_sims diff --git a/floatcsep/postprocess/panel/__init__.py b/floatcsep/postprocess/panel/__init__.py deleted file mode 100644 index 226dfd5..0000000 --- a/floatcsep/postprocess/panel/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .app import run_app - -__all__ = ["run_app"] diff --git a/floatcsep/postprocess/panel/app.py b/floatcsep/postprocess/panel/app.py deleted file mode 100644 index 152de56..0000000 --- a/floatcsep/postprocess/panel/app.py +++ /dev/null @@ -1,38 +0,0 @@ -from pathlib import Path -from typing import Any, Optional -import panel as pn - -from .manifest import build_manifest -from .layout import make_template_app - - -def run_app( - experiment: Any, - port: int = 0, - address: str = "localhost", - show: bool = True, - title: Optional[str] = None, - start: bool = True, - **kwargs, -) -> None: - pn.extension() - - manifest = build_manifest(experiment) - app = make_template_app(manifest) - - if title is None: - title = manifest.name - - panel_dir = Path(__file__).resolve().parent - artifacts_dir = panel_dir.parent / "artifacts" - - pn.serve( - app, - address=address, - port=port, - show=show, - title=title or manifest.name, - static_dirs={"artifacts": str(artifacts_dir)}, - start=start, - **kwargs - ) diff --git a/floatcsep/postprocess/panel/layout.py b/floatcsep/postprocess/panel/layout.py deleted file mode 100644 index 3e1a4c3..0000000 --- a/floatcsep/postprocess/panel/layout.py +++ /dev/null @@ -1,311 +0,0 @@ -import panel as pn -from panel.template import MaterialTemplate -from panel.theme.material import MaterialDarkTheme -from panel.widgets import MenuButton -from panel.layout import VSpacer, HSpacer -from panel import indicators - -from .manifest import Manifest -from .views.exp import build_experiment_view -from .views.cats import build_catalogs_view -from .views.forecasts import build_forecasts_view -from .views.results import build_results_view - - -from floatcsep import __version__ as FLOATCSEP_VERSION - -FLOATCSEP_REPO_URL = "https://github.com/cseptesting/floatcsep" - -DASHBOARD_CSS = """ -@font-face { - font-family: "NotoSans"; - src: url("/artifacts/NotoSans-Regular.ttf") format("truetype"); - font-weight: 400; - font-style: normal; - font-display: swap; -} -@font-face { - font-family: "NotoSans"; - src: url("/artifacts/NotoSans-Bold.ttf") format("truetype"); - font-weight: 700; - font-style: normal; - font-display: swap; -} - -:root { - --design-background-color: #020617; /* page background */ - --design-background-text-color: #e5e7eb; - - --design-surface-color: #020617; /* background of cards / surfaces / buttons */ - --design-surface-text-color: #e5e7eb; /* text of cards / surfaces / buttons */ - - --design-primary-color: #14b8a6; - --design-primary-text-color: #020617; - - --design-secondary-color: #f59e0b; - --design-secondary-text-color: #e5e7eb; -} - -/* Base font */ -body { - font-family: "NotoSans", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important; -} - -/* Override Material / Bokeh default fonts */ -.bk, .bk * { - font-family: "NotoSans", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important; -} -.mdc-typography, .mdc-typography * { - font-family: "NotoSans", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important; -} - -/* Headings */ -h1, h2, h3 { - font-family: "NotoSans", system-ui, sans-serif !important; - font-weight: 700; -} - - -""" - - -def _build_tabs(manifest: Manifest) -> pn.Tabs: - tab_experiment = build_experiment_view(manifest) - tab_catalogs = build_catalogs_view(manifest) - tab_forecasts = build_forecasts_view(manifest) - tab_results = build_results_view(manifest) - - tabs = pn.Tabs( - ("Experiment", tab_experiment), - ("Catalogs", tab_catalogs), - ("Forecasts", tab_forecasts), - ("Results", tab_results), - tabs_location="left", - dynamic=True, - sizing_mode="fixed", - ) - return tabs - - -def _build_header_menu() -> MenuButton: - - return MenuButton( - name="☰", - button_type="default", - width=32, - height=32, - margin=(25, 25, 25, 25), - items=[ - ("Citation", "citation"), - ("Imprint", "imprint"), - ("Data Protection", "privacy"), - ], - ) - - -def _build_custom_header(manifest: Manifest) -> pn.Row: - logo = pn.pane.PNG( - "/artifacts/logo.png", - height=56, - align="center", - margin=(0, 12, 0, 0), - link_url=FLOATCSEP_REPO_URL, - ) - - title = pn.pane.Markdown( - f"Experiment Dashboard", - sizing_mode="stretch_width", - margin=(0, 0, 0, 0), - styles={ - "font-size": "24px", - "font-weight": "400", - }, - ) - - header_row = pn.Row( - logo, - title, - HSpacer(), - _build_header_menu(), - sizing_mode="stretch_width", - align="center", - margin=(15, 0, 0, -20), - ) - return header_row - - -def _status_chip(manifest: Manifest) -> pn.pane.Markdown: - # TODO: later, inspect experiment results - label = "Status: 🟢 OK" - return pn.pane.Markdown( - label, - margin=(0, 12, 0, 0), - styles={ - "font-size": "9px", - "opacity": "0.75", - }, - ) - - -def _build_meta_bar(manifest: Manifest, busy_spinner: pn.viewable.Viewable) -> pn.Row: - items = [] - - def _chip(text: str) -> pn.pane.Markdown: - return pn.pane.Markdown( - text, - margin=(0, 12, 0, 0), - styles={"font-size": "9px", "opacity": "0.6"}, - ) - - if getattr(manifest, "name", None): - items.append(_chip(f"**Name**: {manifest.name}")) - - if getattr(manifest, "date_range", None): - items.append(_chip(f"**Time frame**: {manifest.date_range}")) - - if getattr(manifest, "magnitudes", None): - m_min = min(manifest.magnitudes) - m_max = max(manifest.magnitudes) - items.append(_chip(f"**Magnitude range**: {m_min} — {m_max}")) - - if getattr(manifest, "models", None): - items.append(_chip(f"**Models**: {len(manifest.models)}")) - - if getattr(manifest, "tests", None): - items.append(_chip(f"**Tests**: {len(manifest.tests)}")) - - items.append(_status_chip(manifest)) - - if getattr(manifest, "doi", None): - doi = manifest.doi.strip() - doi_badge_html = ( - '
' - f'' - f'' - f"" - ) - items.append( - pn.pane.HTML(doi_badge_html, margin=(6, 0, 0, 0), styles={"opacity": "0.85"}) - ) - - if not items: - return pn.Row() - - bar = pn.Row( - *items, - HSpacer(), - busy_spinner, - sizing_mode="stretch_width", - align="center", - margin=(-10, 10, -10, 0), - ) - return bar - - -def _build_footer(manifest: Manifest) -> pn.Row: - - version = pn.pane.Markdown( - f"**floatCSEP** v{FLOATCSEP_VERSION}", - styles={"font-size": "9px", "opacity": "0.7"}, - margin=(2, 0, 0, 0), - ) - - github_logo = pn.pane.PNG( - object="/artifacts/github_logo.png", - height=18, - margin=(0, 4, 0, 0), - link_url=FLOATCSEP_REPO_URL, - ) - - rtd_logo = pn.pane.PNG( - object="/artifacts/readthedocs_logo.png", - height=18, - margin=(0, 4, 0, 0), - link_url="https://floatcsep.readthedocs.io/en/latest/", - ) - - csep_logo = pn.pane.PNG( - object="/artifacts/csep_logo.png", - height=18, - margin=(0, 0, 0, 0), - link_url="https://cseptesting.org/", - ) - - gi_logo = pn.pane.PNG( - object="/artifacts/geoinquire_logo.png", - height=18, - margin=(0, 0, 0, 0), - link_url="https://www.geo-inquire.eu/", - ) - - footer = pn.Row( - version, - HSpacer(), - gi_logo, - github_logo, - rtd_logo, - csep_logo, - sizing_mode="stretch_width", - margin=(4, 8, 4, 8), - ) - return footer - - -def make_template_app(manifest: Manifest) -> MaterialTemplate: - tabs = _build_tabs(manifest) - - template = MaterialTemplate( - title="", - site="", - theme=MaterialDarkTheme, - header_background="#020617", - header_color="#e5e7eb", - sidebar_width=0, - ) - template.busy_indicator.visible = False - - busy_spinner = indicators.LoadingSpinner( - value=False, - size=14, - height=18, - width=18, - margin=(8, 0, 0, 0), - ) - - def _sync_busy(event): - busy_spinner.value = event.new - - pn.state.param.watch(_sync_busy, "busy") - - meta_bar = _build_meta_bar(manifest, busy_spinner) - template.header[:] = [_build_custom_header(manifest)] - - footer = _build_footer(manifest) - - tabs_surface = pn.Column( - tabs, - sizing_mode="fixed", - styles={ - "background-color": "#0b1120", - "border-radius": "10px", - "padding": "8px 8px 8px 0", - "box-shadow": "0 10px 30px rgba(0, 0, 0, 0.4)", - "min-height": "400px", - "width": "100%", # force full width inside MaterialTemplate - }, - margin=(10, 0, 0, 0), - ) - - template.main[:] = [ - pn.Column( - pn.layout.Divider(), - meta_bar, - tabs_surface, - VSpacer(), - footer, - sizing_mode="stretch_width", - ) - ] - template.config.raw_css.append(DASHBOARD_CSS) - return template diff --git a/floatcsep/postprocess/panel/manifest.py b/floatcsep/postprocess/panel/manifest.py deleted file mode 100644 index ea3f9bf..0000000 --- a/floatcsep/postprocess/panel/manifest.py +++ /dev/null @@ -1,278 +0,0 @@ -import os -from dataclasses import dataclass -from typing import Any, Dict, List, Optional, Tuple, Union - -from floatcsep.utils.helpers import timewindow2str - -import datetime - - -def _rel(path: Union[os.PathLike, str], base: Union[os.PathLike, str]) -> str: - rel = os.path.relpath(str(path), str(base)) - return rel.replace("\\", "/") - - -@dataclass -class Manifest: - # --- Existing fields used by the layout --- - name: str - start_date: str - end_date: str - authors: str - doi: str - journal: str - manuscript_doi: str - exp_time: str - floatcsep_version: str - pycsep_version: str - last_run: str - catalog_doi: str - license: str - date_range: str - magnitudes: List[float] - region: Optional[Any] # Region object (e.g. CartesianGrid2D) - models: List[Dict[str, Any]] - tests: List[Dict[str, Any]] - time_windows: List[str] - - catalog: Dict[str, str] - results_main: Dict[Tuple[str, str], str] - results_model: Dict[Tuple[str, str, str], str] - app_root: str - - # --- New metadata fields for the Experiment view / meta bar --- - exp_class: str # "Time-Independent" / "Time-Dependent" - n_intervals: int # number of time windows / intervals - horizon: Optional[str] # human-readable horizon (e.g. "1 year") - offset: Optional[str] # human-readable offset - growth: Optional[str] # "incremental" / "cumulative" / None - - mag_min: Optional[float] - mag_max: Optional[float] - mag_bin: Optional[float] - depth_min: Optional[float] - depth_max: Optional[float] - - run_mode: Optional[str] # "sequential" / "parallel" - run_dir: Optional[str] # results directory (relative or abs) - config_file: Optional[str] # main config file path - model_config: Optional[str] # models config path - test_config: Optional[str] # tests config path - - -def _timedelta_to_str(value: Any) -> Optional[str]: - """Best-effort pretty-print for horizon/offset.""" - if value is None: - return None - # If it's already a string, just return it - if isinstance(value, str): - return value - # Timedelta-like: try to derive something nice - try: - days = value.days - seconds = value.seconds - except Exception: - return str(value) - - if days and not seconds: - # Use years if divisible by 365 - if days % 365 == 0: - years = days // 365 - return f"{years} year{'s' if years != 1 else ''}" - return f"{days} day{'s' if days != 1 else ''}" - if not days and seconds: - hours = seconds // 3600 - if hours: - return f"{hours} hour{'s' if hours != 1 else ''}" - # Fallback - return str(value) - - -def build_manifest(experiment: Any, app_root: Optional[str] = None) -> Manifest: - reg = experiment.registry - cat_repo = experiment.catalog_repo - if app_root is None: - app_root = reg.abs(reg.run_dir) - - name = getattr(experiment, "name", "Experiment") - start = getattr(experiment, "start_date", None) - end = getattr(experiment, "end_date", None) - authors = getattr(experiment, "authors", None) - doi = getattr(experiment, "doi", None) - catalog_doi = getattr(experiment, "catalog_doi", None) - license_ = getattr(experiment, "LICENSE", None) - if authors: - if isinstance(authors, (list, tuple)): - authors = ", ".join(str(a) for a in authors) - else: - authors = str(authors) - - if isinstance(start, datetime.datetime) and isinstance(end, datetime.datetime): - date_range = f"{start.date()} — {end.date()}" - else: - date_range = "?" - - magnitudes = list(getattr(experiment, "magnitudes", [])) - region = getattr(experiment, "region", None) - - tw_raw: List[Any] = list(getattr(experiment, "time_windows", [])) - tw_all: List[str] = [] - for tw in tw_raw: - tw_all.append(timewindow2str(tw).replace("_", " to ")) - - models: List[Dict[str, Any]] = [] - model_objs = getattr(experiment, "models", []) - model_names = [i.name for i in model_objs] - for model in getattr(experiment, "models", []): - model_registry = model.registry - - model_forecasts: Dict[str, str] = {} - for tw_obj, tw_str in zip(tw_raw, tw_all): - try: - fc_path = model_registry.get_forecast_key(tw_obj) - except Exception: - continue - - rel_fc = _rel(fc_path, app_root) - model_forecasts[tw_str] = rel_fc - - models.append( - { - "name": getattr(model, "name", None), - "forecast_unit": getattr(model, "forecast_unit", None), - "path": model_registry.rel(model_registry.path) or None, - "giturl": getattr(model, "giturl", None), - "git_hash": getattr(model, "repo_hash", None), - "zenodo_id": getattr(model, "zenodo_id", None), - "authors": getattr(model, "authors", None), - "doi": getattr(model, "doi", None), - "func": getattr(model, "func", None), - "func_kwargs": getattr(model, "func_kwargs", None), - "fmt": getattr(model, "fmt", None), - "registry": model_registry, - "forecasts": model_forecasts, - "forecast_class": model.repository.__class__.__name__, - } - ) - - tests: List[Dict] = [] - test_objs = getattr(experiment, "tests", []) - test_names = [i.name for i in getattr(experiment, "tests", [])] - for test, test_name in zip(test_objs, test_names): - func_obj = getattr(test, "func", None) - mod_name = getattr(func_obj, "__module__", None) - func_name = getattr(func_obj, "__name__", None) - - if mod_name is not None and func_name is not None: - func_str = f"{mod_name}.{func_name}" - elif func_name is not None: - func_str = func_name - else: - func_str = None - - tests.append( - { - "name": test_name, - "func": func_str, - "func_kwargs": getattr(test, "func_kwargs", None), - "ref_model": getattr(test, "ref_model", None), - "plot_func": getattr(test, "plot_func", None), - "plot_args": getattr(test, "plot_args", None), - "plot_kwargs": getattr(test, "plot_kwargs", None), - } - ) - - catalog: Dict[str, str] = {} - try: - cat_map = reg.get_figure_key("main_catalog_map") - cat_time = reg.get_figure_key("main_catalog_time") - cat_path = _rel(reg.run_dir / cat_repo.cat_path, app_root) - catalog["path"] = cat_path - catalog["map"] = _rel(cat_map, app_root) - catalog["time"] = _rel(cat_time, app_root) - except Exception: - pass - - results_main: Dict[Tuple[str, str], str] = {} - results_model: Dict[Tuple[str, str, str], str] = {} - - for tw_obj, tw_str in zip(tw_raw, tw_all): - for test_name in test_names: - try: - p = reg.get_figure_key(tw_obj, test_name) - results_main[(tw_str, test_name)] = _rel(p, app_root) - except Exception: - pass - for model_name in model_names: - try: - p = reg.get_figure_key(tw_obj, f"{test_name}_{model_name}") - if reg.file_exists("figures", tw_obj, f"{test_name}_{model_name}"): - results_model[(tw_str, test_name, model_name)] = _rel(p, app_root) - except Exception: - continue - - time_cfg: Dict[str, Any] = getattr(experiment, "time_config", {}) or {} - region_cfg: Dict[str, Any] = getattr(experiment, "region_config", {}) or {} - - exp_class_code = time_cfg.get("exp_class", getattr(experiment, "exp_class", "ti")) - exp_class = ( - "Time-Dependent" if exp_class_code in ("td", "time-dependent") else "Time-Independent" - ) - - n_intervals = time_cfg.get("intervals") or len(time_cfg.get("time_windows", [])) or 0 - horizon_str = _timedelta_to_str(time_cfg.get("horizon")) - offset_str = _timedelta_to_str(time_cfg.get("offset")) - growth = time_cfg.get("growth") - - mag_min = getattr(experiment, "mag_min", None) - mag_max = getattr(experiment, "mag_max", None) - mag_bin = getattr(experiment, "mag_bin", None) - depth_min = getattr(experiment, "depth_min", None) - depth_max = getattr(experiment, "depth_max", None) - - run_mode = getattr(experiment, "run_mode", None) - run_dir = getattr(experiment, "run_dir", None) - config_file = getattr(experiment, "config_file", None) - model_config_path = getattr(experiment, "model_config", None) - test_config_path = getattr(experiment, "test_config", None) - return Manifest( - name=name, - start_date=start.date().isoformat(), - end_date=end.date().isoformat(), - authors=authors, - journal=getattr(experiment, "journal", None), - manuscript_doi=getattr(experiment, "manuscript_doi", None), - floatcsep_version=getattr(experiment, "floatcsep_version", None), - pycsep_version=getattr(experiment, "pycsep_version", None), - last_run=getattr(experiment, "last_run", None), - exp_time=getattr(experiment, "exp_time", None), - doi=doi, - catalog_doi=catalog_doi, - license=license_, - date_range=date_range, - magnitudes=magnitudes, - region=region, - models=models, - tests=tests, - time_windows=tw_all, - catalog=catalog, - results_main=results_main, - results_model=results_model, - app_root=str(app_root), - # new metadata fields - exp_class=exp_class, - n_intervals=n_intervals, - horizon=horizon_str, - offset=offset_str, - growth=growth, - mag_min=mag_min, - mag_max=mag_max, - mag_bin=mag_bin, - depth_min=depth_min, - depth_max=depth_max, - run_mode=run_mode, - run_dir=run_dir, - config_file=config_file, - model_config=model_config_path, - test_config=test_config_path, - ) diff --git a/floatcsep/postprocess/panel/views/cats.py b/floatcsep/postprocess/panel/views/cats.py deleted file mode 100644 index 64693d1..0000000 --- a/floatcsep/postprocess/panel/views/cats.py +++ /dev/null @@ -1,754 +0,0 @@ -import json -from datetime import datetime, date, timezone -from pathlib import Path - -import numpy as np -import panel as pn -from bokeh.models import ( - ColumnDataSource, - HoverTool, - DatetimeTickFormatter, - Range1d, - LabelSet, -) -from bokeh.plotting import figure - -from ..manifest import Manifest -from .utils import ( - build_region_basemap, - lonlat_to_mercator, - parse_time_window_strings, - make_doi_badge, -) -from floatcsep.utils.file_io import CatalogParser - - -def _to_datetime_or_none(value): - """Return value as timezone-aware datetime or None.""" - if value is None: - return None - if isinstance(value, datetime): - return value.replace(tzinfo=timezone.utc) - if isinstance(value, date): - return datetime(value.year, value.month, value.day, tzinfo=timezone.utc) - if isinstance(value, str): - try: - dtime = datetime.fromisoformat(value) - return dtime.replace(tzinfo=timezone.utc) - except ValueError: - return None - return None - - -SUBSCRIPT_DIGITS = str.maketrans("0123456789", "₀₁₂₃₄₅₆₇₈₉") - - -def _make_window_label(i: int) -> str: - """Return a time-window label like for index i.""" - idx = str(i + 1).translate(SUBSCRIPT_DIGITS) - return f"T{idx}" - - -def _compute_marker_sizes( - mags: np.ndarray, - min_size: float = 5.0, - max_size: float = 18.0, - power: float = 2.5, -) -> np.ndarray: - """Map magnitudes to Bokeh marker sizes.""" - mags = np.asarray(mags, dtype=float) - if mags.size == 0 or not np.isfinite(mags).any(): - return np.array([], dtype=float) - - vmin = np.nanmin(mags) - vmax = np.nanmax(mags) - if not np.isfinite(vmin) or not np.isfinite(vmax) or vmax <= vmin: - return np.full(mags.shape, (min_size + max_size) / 2.0, dtype=float) - - norm = ((mags - vmin) / (vmax - vmin)) ** power - return min_size + norm * (max_size - min_size) - - -def _fmt_dt(dt): - """Format datetime to second precision.""" - if dt is None: - return None - return dt.strftime("%Y-%m-%d %H:%M:%S") - - -def _load_csep_catalog_from_manifest(manifest: Manifest): - """Load a CSEPCatalog from manifest.catalog['path'].""" - cat_info = getattr(manifest, "catalog", None) - if not isinstance(cat_info, dict): - return None - - path = cat_info.get("path") - if not path: - return None - - app_root = Path(getattr(manifest, "app_root", ".")) - path_obj = Path(path) - - if not path_obj.is_absolute(): - path_obj = (app_root / path_obj).resolve() - else: - path_obj = path_obj.resolve() - - try: - if path_obj.suffix.lower() == ".json": - try: - return CatalogParser.json(str(path_obj)) - except json.JSONDecodeError: - return CatalogParser.ascii(str(path_obj)) - else: - return CatalogParser.ascii(str(path_obj)) - except FileNotFoundError: - return None - except Exception: - return None - - -def _build_spatial_catalog_legend(catalog) -> pn.pane.Markdown: - """Return a small static legend for the spatial catalog scatter.""" - if catalog is None or catalog.event_count == 0: - text = "_No catalog loaded; legend unavailable._" - return pn.pane.Markdown(text, sizing_mode="stretch_width", styles={"font-size": "9px"}) - - mags = catalog.get_magnitudes() - min_mag = float(np.nanmin(mags)) - max_mag = float(np.nanmax(mags)) - - mags_ticks = np.linspace(min_mag, max_mag, 4) - mags_ticks = np.round(mags_ticks, 1) - - sizes = _compute_marker_sizes(mags_ticks, min_size=5.0, max_size=18.0, power=2.5) - font_min, font_max = 9, 15 - smin, smax = sizes.min(), sizes.max() - if smax > smin: - font_sizes = font_min + (sizes - smin) / (smax - smin) * (font_max - font_min) - else: - font_sizes = np.full_like(sizes, (font_min + font_max) / 2.0) - - bullet_parts = [] - for m, fs in zip(mags_ticks, font_sizes): - bullet_parts.append(f'● M {m:g}') - bullets_html = "    ".join(bullet_parts) - - legend_html = f""" - -Magnitude legend: {bullets_html}
-Colors: ● Input Catalog (t < start)    -● Test Catalog (start < t) -
-""" - - return pn.pane.Markdown( - legend_html, - sizing_mode="stretch_width", - styles={"font-size": "10px"}, - margin=(4, 0, 0, 0), - ) - - -def _build_spatial_catalog_figure(manifest: Manifest, height: int = 350): - """Build spatial catalog figure on a basemap.""" - region = getattr(manifest, "region", None) - catalog = _load_csep_catalog_from_manifest(manifest) - - fig, *_ = build_region_basemap( - region, basemap="WorldTerrain", min_height=height, plot_cells=False - ) - - if catalog is None or catalog.event_count == 0: - source = ColumnDataSource( - data={ - "x": [], - "y": [], - "mag": [], - "size": [], - "time_str": [], - "event_id": [], - "color": [], - "category": [], - } - ) - fig.circle( - x="x", - y="y", - source=source, - size="size", - fill_color="color", - fill_alpha=0.0, - line_alpha=0.0, - ) - return fig, source - - start_date = _to_datetime_or_none(getattr(manifest, "start_date", None)) - end_date = _to_datetime_or_none(getattr(manifest, "end_date", None)) - - lons = catalog.get_longitudes() - lats = catalog.get_latitudes() - mags = catalog.get_magnitudes() - dts = catalog.get_datetimes() - event_ids_raw = catalog.get_event_ids() - - indices = list(range(len(dts))) - if end_date is not None: - indices = [i for i in indices if dts[i] <= end_date] - - if not indices: - source = ColumnDataSource( - data={ - "x": [], - "y": [], - "mag": [], - "size": [], - "time_str": [], - "event_id": [], - "color": [], - "category": [], - } - ) - fig.circle( - x="x", - y="y", - source=source, - size="size", - fill_color="color", - fill_alpha=0.0, - line_alpha=0.0, - ) - return fig, source - - input_idx = [] - test_idx = [] - for i in indices: - dt = dts[i] - if start_date is not None and dt < start_date: - input_idx.append(i) - else: - test_idx.append(i) - - ordered_indices = input_idx + test_idx - - lons = np.asarray(lons)[ordered_indices] - lats = np.asarray(lats)[ordered_indices] - mags = np.asarray(mags)[ordered_indices] - dts_ordered = [dts[i] for i in ordered_indices] - event_ids_ordered = [event_ids_raw[i] for i in ordered_indices] - - x, y = lonlat_to_mercator(lons, lats) - - event_ids = [ - eid.decode("utf-8") if isinstance(eid, (bytes, bytearray)) else str(eid) - for eid in event_ids_ordered - ] - time_str = [dt.strftime("%Y-%m-%d %H:%M:%S") for dt in dts_ordered] - - sizes = _compute_marker_sizes(mags, min_size=3.0, max_size=18.0, power=3) - - INPUT_COLOR = "#38bdf8" - TEST_COLOR = "#ef4444" - - colors = [] - categories = [] - alphas = [] - for dt in dts_ordered: - if start_date is not None and dt < start_date: - colors.append(INPUT_COLOR) - categories.append("input") - alphas.append(0.35) - else: - colors.append(TEST_COLOR) - categories.append("test") - alphas.append(0.6) - - source = ColumnDataSource( - data={ - "x": x, - "y": y, - "mag": mags, - "size": sizes, - "time_str": time_str, - "event_id": event_ids, - "color": colors, - "category": categories, - "alphas": alphas, - } - ) - - fig.circle( - x="x", - y="y", - source=source, - size="size", - fill_color="color", - fill_alpha="alphas", - line_color="#020617", - line_width=0.4, - line_alpha=0.5, - ) - - hover = HoverTool( - tooltips=[ - ("Time", "@time_str"), - ("Magnitude", "@mag{0.00}"), - ("ID", "@event_id"), - ], - mode="mouse", - ) - fig.add_tools(hover) - - return fig, source - - -def _build_spatial_catalog_panel(manifest: Manifest) -> pn.panel: - """Build the spatial catalog panel.""" - catalog = _load_csep_catalog_from_manifest(manifest) - fig, _source = _build_spatial_catalog_figure(manifest, height=350) - legend_md = _build_spatial_catalog_legend(catalog) - - return pn.Column( - pn.pane.Bokeh(fig, sizing_mode="stretch_width"), - legend_md, - sizing_mode="stretch_both", - ) - - -def _build_magtime_catalog_figure(manifest: Manifest, height: int = 220): - """Build magnitude–time scatter with embedded time windows.""" - catalog = _load_csep_catalog_from_manifest(manifest) - - if catalog is None or catalog.event_count == 0: - fig = figure( - x_axis_type="datetime", - height=height, - sizing_mode="stretch_width", - toolbar_location="above", - tools="xwheel_zoom,xpan,box_zoom,reset", - active_scroll="xwheel_zoom", - ) - fig.title.text = "No catalog events" - fig.yaxis.axis_label = "Magnitude" - fig.xaxis.axis_label = "Time" - - fig.background_fill_color = "#0b1120" - fig.border_fill_color = "#0b1120" - fig.outline_line_color = None - fig.grid.grid_line_color = "#1f2933" - fig.axis.major_label_text_color = "#e5e7eb" - fig.axis.axis_line_color = "#6b7280" - fig.axis.major_tick_line_color = "#6b7280" - fig.axis.minor_tick_line_color = None - - return fig, ColumnDataSource({"time": [], "mag": []}) - - start_date = _to_datetime_or_none(getattr(manifest, "start_date", None)) - end_date = _to_datetime_or_none(getattr(manifest, "end_date", None)) - - dts = catalog.get_datetimes() - mags = np.asarray(catalog.get_magnitudes(), dtype=float) - event_ids_raw = catalog.get_event_ids() - - indices = list(range(len(dts))) - if end_date is not None: - indices = [i for i in indices if dts[i] <= end_date] - - if not indices: - fig = figure( - x_axis_type="datetime", - height=height, - sizing_mode="stretch_width", - toolbar_location="above", - tools="xwheel_zoom,xpan,box_zoom,reset", - active_scroll="xwheel_zoom", - ) - fig.title.text = "No events within experiment end time" - fig.yaxis.axis_label = "Magnitude" - fig.xaxis.axis_label = "Time" - fig.background_fill_color = "#0b1120" - fig.border_fill_color = "#0b1120" - fig.outline_line_color = None - fig.grid.grid_line_color = "#1f2933" - fig.axis.major_label_text_color = "#e5e7eb" - fig.axis.axis_line_color = "#6b7280" - fig.axis.major_tick_line_color = "#6b7280" - fig.axis.minor_tick_line_color = None - - return fig, ColumnDataSource({"time": [], "mag": []}) - - input_idx = [] - test_idx = [] - for i in indices: - dt = dts[i] - if start_date is not None and dt < start_date: - input_idx.append(i) - else: - test_idx.append(i) - - ordered_indices = input_idx + test_idx - - dts_ordered = [dts[i] for i in ordered_indices] - mags_ordered = mags[ordered_indices] - event_ids_ordered = [event_ids_raw[i] for i in ordered_indices] - - sizes = _compute_marker_sizes(mags_ordered, min_size=4.0, max_size=16.0, power=3.0) - - INPUT_COLOR = "#38bdf8" - TEST_COLOR = "#ef4444" - - colors = [] - alphas = [] - categories = [] - for dt in dts_ordered: - if start_date is not None and dt < start_date: - colors.append(INPUT_COLOR) - categories.append("input") - alphas.append(0.35) - else: - colors.append(TEST_COLOR) - categories.append("test") - alphas.append(0.65) - - time_str = [dt.strftime("%Y-%m-%d %H:%M:%S") for dt in dts_ordered] - event_ids = [ - eid.decode("utf-8") if isinstance(eid, (bytes, bytearray)) else str(eid) - for eid in event_ids_ordered - ] - - source = ColumnDataSource( - data={ - "time": dts_ordered, - "mag": mags_ordered, - "size": sizes, - "color": colors, - "alphas": alphas, - "category": categories, - "time_str": time_str, - "event_id": event_ids, - } - ) - - fig = figure( - x_axis_type="datetime", - height=height, - sizing_mode="stretch_width", - toolbar_location="above", - tools="xwheel_zoom,xpan,box_zoom,reset", - active_scroll="xwheel_zoom", - ) - - y_min = float(np.nanmin(mags_ordered)) - y_max = float(np.nanmax(mags_ordered)) - y_max_pad = max(0.4, 0.2 * (y_max - y_min) if y_max > y_min else 0.0) - y_min_pad = 0.15 - fig.y_range = Range1d(y_min - y_min_pad, y_max + y_max_pad) - - t_min = min(dts_ordered) - t_max = max(dts_ordered) - if t_max > t_min: - pad = (t_max - t_min) * 0.05 - fig.x_range = Range1d(t_min - pad, t_max + pad) - - tw_strings = getattr(manifest, "time_windows", None) or [] - parsed_raw = parse_time_window_strings(tw_strings) - - if parsed_raw: - windows_sorted = sorted(parsed_raw, key=lambda tw: tw["start"]) - - lane_last_end = [] - lanes = [] - - for tw in windows_sorted: - start = tw["start"] - end = tw["end"] - assigned = False - for i, last_end in enumerate(lane_last_end): - if start >= last_end: - lane_last_end[i] = end - lanes.append(i) - assigned = True - break - if not assigned: - lane_last_end.append(end) - lanes.append(len(lane_last_end) - 1) - - n_lanes = max(lanes) + 1 if lanes else 1 - - y_top_min = y_max - y_top_max = y_max + y_max_pad - lane_step = (y_top_max - y_top_min) / max(n_lanes, 1) - bar_height = lane_step * 0.7 - - left = [] - right = [] - bottom = [] - top = [] - labels = [] - start_strs = [] - end_strs = [] - length_days = [] - y_label = [] - - for i, tw in enumerate(windows_sorted): - lane = lanes[i] - - lane_center = y_top_min + (lane + 0.5) * lane_step - b = lane_center - bar_height / 2.0 - t = lane_center + bar_height / 2.0 - - left.append(tw["start"]) - right.append(tw["end"]) - bottom.append(b) - top.append(t) - labels.append(_make_window_label(i)) - start_strs.append(tw["start_str"]) - end_strs.append(tw["end_str"]) - length_days.append(tw["length_days"]) - y_label.append(lane_center) - - tw_source = ColumnDataSource( - data={ - "start": left, - "end": right, - "bottom": bottom, - "top": top, - "label": labels, - "start_str": start_strs, - "end_str": end_strs, - "length_days": length_days, - "y_label": y_label, - } - ) - - window_renderer = fig.quad( - left="start", - right="end", - bottom="bottom", - top="top", - source=tw_source, - fill_color="#38bdf8", - fill_alpha=0.16, - line_color=None, - ) - - labels_glyph = LabelSet( - x="start", - y="y_label", - text="label", - source=tw_source, - text_font_size="7pt", - text_color="#e5e7eb", - text_align="left", - text_baseline="middle", - background_fill_color="#020617", - background_fill_alpha=0.0, - border_line_color=None, - ) - fig.add_layout(labels_glyph) - - window_hover = HoverTool( - renderers=[window_renderer], - tooltips=[ - ("Start", "@start_str"), - ("End", "@end_str"), - ("Length (days)", "@length_days"), - ], - mode="mouse", - ) - fig.add_tools(window_hover) - - scatter_renderer = fig.circle( - x="time", - y="mag", - source=source, - size="size", - fill_color="color", - fill_alpha="alphas", - line_color="#020617", - line_width=0.4, - line_alpha=0.6, - ) - - fig.yaxis.axis_label = "Magnitude" - fig.xaxis.axis_label = "Time" - - fig.background_fill_color = "#0b1120" - fig.border_fill_color = "#0b1120" - fig.outline_line_color = None - fig.grid.grid_line_color = "#1f2933" - fig.axis.major_label_text_color = "#e5e7eb" - fig.axis.axis_line_color = "#6b7280" - fig.axis.major_tick_line_color = "#6b7280" - fig.axis.minor_tick_line_color = None - - fig.xaxis.formatter = DatetimeTickFormatter( - years="%Y", - months="%b %Y", - days="%d %b %Y", - hours="%d %b %Y", - ) - fig.xaxis.major_label_orientation = np.pi / 2 - fig.xaxis.major_label_text_font_size = "7pt" - fig.yaxis.major_label_text_font_size = "8pt" - - event_hover = HoverTool( - renderers=[scatter_renderer], - tooltips=[ - ("Time", "@time_str"), - ("Magnitude", "@mag{0.00}"), - ("ID", "@event_id"), - ], - mode="mouse", - ) - fig.add_tools(event_hover) - - return fig, source - - -def _build_magtime_catalog_panel(manifest: Manifest) -> pn.panel: - """Build the magnitude–time catalog panel.""" - magtime_fig, _source = _build_magtime_catalog_figure(manifest, height=280) - magtime_pane = pn.pane.Bokeh(magtime_fig, sizing_mode="stretch_width") - - return pn.Column( - magtime_pane, - sizing_mode="stretch_width", - ) - - -def _build_plots_panel(manifest: Manifest) -> pn.Tabs: - """Build tabs with spatial and magnitude–time plots.""" - spatial_panel = _build_spatial_catalog_panel(manifest) - magtime_panel = _build_magtime_catalog_panel(manifest) - - return pn.Tabs( - ("Spatial", spatial_panel), - ("Magnitude–Time", magtime_panel), - sizing_mode="stretch_both", - ) - - -def _catalog_overview_block(manifest: Manifest) -> pn.panel: - """Build the title block for the Catalogs tab.""" - text = "## Catalogs" - return pn.pane.Markdown(text, sizing_mode="stretch_width") - - -def _catalog_metadata_section(manifest: Manifest) -> pn.panel: - """Build catalog metadata section from CSEPCatalog attributes.""" - cat_info = getattr(manifest, "catalog", None) - cat_path = None - if isinstance(cat_info, dict): - cat_path = cat_info.get("path") - - csep_cat = _load_csep_catalog_from_manifest(manifest) - - lines = ["### Metadata"] - - if cat_path: - lines.append(f"- **Path:** `{cat_path}`") - - if csep_cat is None: - lines.append("") - lines.append("_Catalog could not be loaded from this path._") - return pn.pane.Markdown( - "\n".join(lines), - sizing_mode="stretch_width", - styles={"font-size": "11px"}, - ) - - name = getattr(csep_cat, "name", None) - if not name and cat_path: - name = Path(cat_path).name - - if name != cat_path: - lines.append(f"- **Name:** {name}") - - provider = getattr(manifest, "catalog_provided", None) - if provider: - lines.append(f"- **Provider:** `{provider}`") - - lines.append(f"- **Event count:** {csep_cat.event_count}") - - start_time = getattr(csep_cat, "start_time", None) - end_time = getattr(csep_cat, "end_time", None) - - start_str = _fmt_dt(start_time) - end_str = _fmt_dt(end_time) - if start_time and end_time: - lines.append(f"- **Time span:** {start_str} → {end_str}") - - min_mag = getattr(csep_cat, "min_magnitude", None) - max_mag = getattr(csep_cat, "max_magnitude", None) - if min_mag is not None and max_mag is not None: - lines.append(f"- **Magnitude range:** [{min_mag:.2f}, {max_mag:.2f}]") - - try: - depths = csep_cat.get_depths() - if depths is not None and len(depths) > 0: - min_depth = float(np.nanmin(depths)) - max_depth = float(np.nanmax(depths)) - lines.append(f"- **Depth range:** [{min_depth:.1f}, {max_depth:.1f}] km") - except Exception: - pass - - try: - lon_min, lon_max, lat_min, lat_max = csep_cat.get_bbox() - lines.append( - "- **Catalog extent:** " - f"lon [{lon_min:.2f}, {lon_max:.2f}], " - f"lat [{lat_min:.2f}, {lat_max:.2f}]" - ) - except Exception: - pass - - region = getattr(csep_cat, "region", None) - region_name = getattr(region, "name", None) if region is not None else None - if region_name: - lines.append(f"- **Region (catalog):** {region_name}") - - filters = getattr(csep_cat, "filters", None) - if filters: - lines.append(f"- **Filters:** `{filters}`") - # Experiment DOI (e.g. Zenodo for the experiment bundle) - doi = getattr(manifest, "catalog_doi", None) - if doi: - badge = make_doi_badge(doi) - lines.append(f"- **DOI:** {badge}") - - date_accessed = getattr(csep_cat, "date_accessed", None) - if date_accessed: - lines.append(f"- **Date accessed:** {_fmt_dt(date_accessed)}") - - return pn.pane.Markdown( - "\n".join(lines), - sizing_mode="stretch_width", - styles={"font-size": "11px"}, - ) - - -def _build_metadata_panel(manifest: Manifest) -> pn.Column: - """Build right-side catalog metadata panel.""" - overview = _catalog_overview_block(manifest) - metadata = _catalog_metadata_section(manifest) - - return pn.Column( - overview, - pn.layout.Divider(), - metadata, - width=380, - ) - - -def build_catalogs_view(manifest: Manifest) -> pn.layout.Panel: - """Build the Catalogs tab view.""" - left = _build_metadata_panel(manifest) - right = _build_plots_panel(manifest) - - return pn.Row( - left, - pn.Spacer(width=25), - right, - sizing_mode="stretch_both", - ) diff --git a/floatcsep/postprocess/panel/views/exp.py b/floatcsep/postprocess/panel/views/exp.py deleted file mode 100644 index cb018df..0000000 --- a/floatcsep/postprocess/panel/views/exp.py +++ /dev/null @@ -1,389 +0,0 @@ -import panel as pn -from ..manifest import Manifest - -from .utils import ( - build_region_basemap, - parse_time_window_strings, - build_time_windows_figure, - fmt_coord, - make_doi_badge, -) - - -def _experiment_overview_block(manifest: Manifest) -> pn.panel: - """Title block at the top of the Experiment tab.""" - name = manifest.name or "Experiment" - text = f"## {name}" - return pn.pane.Markdown(text, sizing_mode="stretch_width") - - -def _metadata_section(manifest: Manifest) -> pn.Column: - """High-level experiment metadata: authors, DOIs, journal, versions, etc.""" - lines = [] - - # EXP CLASS - exp_time = getattr(manifest, "exp_time", None) - if exp_time: - lines.append(f"**Experiment Class:** `{exp_time}`") - - # EXP CLASS - model_type = getattr(manifest, "exp_class", None) - if model_type: - lines.append(f"**Model Type:** `{model_type}`") - - # Authors - authors = getattr(manifest, "authors", None) - if authors: - if isinstance(authors, (list, tuple)): - authors_str = ", ".join(str(a) for a in authors) - else: - authors_str = str(authors) - lines.append(f"**Authors:** {authors_str}") - - # Experiment DOI (e.g. Zenodo for the experiment bundle) - doi = getattr(manifest, "doi", None) - if doi: - badge = make_doi_badge(doi) - lines.append(f"**DOI:** {badge}") - - # Manuscript / paper DOI - manuscript_doi = getattr(manifest, "manuscript_doi", None) - if manuscript_doi: - lines.append(f"**Manuscript DOI:** `{manuscript_doi}`") - - # Journal name, if present - journal = getattr(manifest, "journal", None) - if journal: - lines.append(f"**Journal:** {journal}") - - # Last run timestamp - last_run = getattr(manifest, "last_run", None) - if last_run: - lines.append(f"**Last run:** {last_run}") - - # floatCSEP version: prefer manifest override, else package - fc_ver = getattr(manifest, "floatcsep_version", None) - if fc_ver: - lines.append(f"**floatCSEP version:** `{fc_ver}`") - - # pyCSEP version: prefer manifest override, else package - pycsep_ver = getattr(manifest, "pycsep_version", None) - if pycsep_ver: - lines.append(f"**pyCSEP version:** `{pycsep_ver}`") - - license_ = getattr(manifest, "license", None) - if license: - lines.append(f"**LICENSE:** `{license_}`") - - if len(lines) == 1: - lines.append("_No experiment metadata available._") - - section = pn.pane.Markdown( - "\n\n".join(lines), - sizing_mode="stretch_width", - styles={ - "font-size": "11px", - "line-height": "1", - }, - ) - return pn.Column(section, margin=(4, 0, 4, 4)) - - -def _temporal_section(manifest: Manifest) -> pn.Column: - """Markdown summary for the temporal configuration.""" - start_date = manifest.start_date - end_date = manifest.end_date - n_intervals = getattr(manifest, "n_intervals", None) - exp_class = getattr(manifest, "exp_class", None) - horizon = getattr(manifest, "horizon", None) - offset = getattr(manifest, "offset", None) - growth = getattr(manifest, "growth", None) - time_windows = getattr(manifest, "time_windows", None) or [] - - lines = [] - - if exp_class: - exp_str = ( - "Time-Independent" - if exp_class in ("ti", "time-independent", "Time-Independent") - else "Time-Dependent" - ) - lines.append(f"**Class:** {exp_str}") - lines.append(f"**Start Date:** {start_date}") - lines.append(f"**End Date:** {end_date}") - - if horizon: - lines.append(f"**Forecast Horizon:** {horizon}") - if offset: - lines.append(f"**Window Offset:** {offset}") - if growth: - lines.append(f"**Window Growth:** {growth}") - - tw_str = f"**Time Windows:** {n_intervals}\n" - for tw in time_windows: - tw_str += f" - {tw}\n\n" - lines.append(tw_str) - - section = pn.pane.Markdown( - "\n\n".join(lines), - sizing_mode="stretch_width", - styles={"font-size": "11px", "line-height": "0.6"}, - ) - return pn.Column(section, margin=(0, 0, 0, 8)) - - -def _spatial_section(manifest: Manifest) -> pn.Column: - - region = getattr(manifest, "region", None) - region_name = getattr(region, "name", None) if region is not None else None - - mag_min = getattr(manifest, "mag_min", None) - mag_max = getattr(manifest, "mag_max", None) - mag_bin = getattr(manifest, "mag_bin", None) - depth_min = getattr(manifest, "depth_min", None) - depth_max = getattr(manifest, "depth_max", None) - - lines = [] - - if region_name: - lines.append(f"**Region:** {region_name}") - elif isinstance(region, str): - lines.append(f"**Region:** {region}") - else: - lines.append("**Region:** \n") - - lines.append(f"**Magnitude range:** [{mag_min}, {mag_max}]") - lines.append(f"**Magnitude bin:** ΔM = {mag_bin}") - - if depth_min is not None and depth_max is not None: - lines.append(f"**Depth range:** [{depth_min}, {depth_max}] km") - - section = pn.pane.Markdown( - "\n\n".join(lines), - sizing_mode="stretch_width", - styles={ - "font-size": "11px", - "line-height": "0.6", - }, - ) - return pn.Column(section, margin=(0, 0, 0, 8)) - - -def _models_section(manifest: Manifest) -> pn.Column: - models = manifest.models or [] - - lines = [] - for model in models: - lines.append(f"### {model['name']}") - if model.get("forecast_unit", False): - lines.append(f" - **Forecast Unit:** {model['forecast_unit']} years") - if model.get("path", False): - lines.append(f" - **Path:** `{model['path']}`") - if model.get("giturl", False): - lines.append(f" - **Git URL:** `{model['giturl']}`") - if model.get("git_hash", False): - lines.append(f" - **Git Hash:** `{model['git_hash']}`") - if model.get("zenodo_id", False): - lines.append(f" - **Zenodo ID:** {model['zenodo_id']}") - if model.get("authors", False): - lines.append(f" - **Authors:** {model['authors']}") - if model.get("doi"): - badge = make_doi_badge(model["doi"]) - lines.append(f"- **DOI:** {badge}") - if model.get("func", False): - lines.append(f" - **Call Function:** {model['func']}") - if model.get("func_kwargs", False): - lines.append(f" - **Function Arguments:** {model['func_kwargs']}") - if model.get("fmt", False): - lines.append(f" - **Forecast Format:** {model['fmt']}") - - section = pn.pane.Markdown( - "\n".join(lines), - sizing_mode="stretch_width", - styles={ - "font-size": "11px", - "line-height": "1", - }, - ) - - return pn.Column(section, margin=(0, 0, 0, 8)) - - -def _tests_section(manifest: Manifest) -> pn.Column: - tests = manifest.tests or [] - - lines = [] - for test in tests: - lines.append(f"### {test['name']}") - if test.get("func", False): - lines.append(f" - **Function:** {test['func']}") - if test.get("func_kwargs", False): - lines.append(f" - **Function Arguments:** {test['func_kwargs']}") - if test.get("ref_model", False): - lines.append(f" - **Reference Model:** {test['ref_model']}") - - section = pn.pane.Markdown( - "\n\n".join(lines), - sizing_mode="stretch_width", - styles={ - "font-size": "11px", - "line-height": "0.6", - }, - ) - - return pn.Column(section, margin=(0, 0, 0, 8)) - - -def _run_config_section(manifest: Manifest) -> pn.pane.Markdown: - run_mode = getattr(manifest, "run_mode", None) - run_dir = getattr(manifest, "run_dir", None) - config_file = getattr(manifest, "config_file", None) - model_config = getattr(manifest, "model_config", None) - test_config = getattr(manifest, "test_config", None) - - lines = ["#### Run & configuration"] - - if run_mode: - lines.append(f"- **Run mode:** {run_mode.capitalize()}") - if run_dir: - lines.append(f"- **Results directory:** `{run_dir}`") - if config_file: - lines.append(f"- **Experiment config:** `{config_file}`") - if model_config: - lines.append(f"- **Models config:** `{model_config}`") - if test_config: - lines.append(f"- **Tests config:** `{test_config}`") - - lines.append(f"- **Host:** `local`") - - if len(lines) == 1: - lines.append("_No run/config information available._") - - return pn.pane.Markdown("\n".join(lines), sizing_mode="stretch_width") - - -def _build_region_panel(manifest: Manifest) -> pn.Column: - """Region tab: basemap with experiment region overlay + compact metadata.""" - region = getattr(manifest, "region", None) - fig, n_cells, dh, (lon_min, lon_max), (lat_min, lat_max) = build_region_basemap(region) - fig_pane = pn.pane.Bokeh(fig, sizing_mode="stretch_width") - - line1_parts = [] - if n_cells is not None: - line1_parts.append(f"**Cells:** {n_cells}") - if dh is not None: - line1_parts.append(f"**Δh:** {dh}") - - line2_parts = [] - if lon_min is not None and lon_max is not None: - line2_parts.append(f"**Longitude range:** [{fmt_coord(lon_min)}, {fmt_coord(lon_max)}]") - if lat_min is not None and lat_max is not None: - line2_parts.append(f"**Latitude range:** [{fmt_coord(lat_min)}, {fmt_coord(lat_max)}]") - - if not line1_parts and not line2_parts: - meta_text = "_No region metadata available._" - else: - meta_lines = [] - meta_lines.append(" ".join(line1_parts) if line1_parts else "") - meta_lines.append(" ".join(line2_parts) if line2_parts else "") - meta_text = "\n\n".join(l for l in meta_lines if l) - - meta_pane = pn.pane.Markdown( - meta_text, - sizing_mode="stretch_width", - styles={ - "font-size": "09px", - "line-height": "0.8", - }, - ) - - return pn.Column( - fig_pane, - meta_pane, - sizing_mode="stretch_both", - ) - - -def _build_time_windows_panel(manifest: Manifest) -> pn.Column: - """Time windows tab: interactive timeline of forecast intervals.""" - tw_strings = getattr(manifest, "time_windows", None) or [] - parsed = parse_time_window_strings(tw_strings) - n_intervals = getattr(manifest, "n_intervals", None) - - header_lines = [] - if n_intervals is not None: - header_lines.append(f"Number of windows: **{n_intervals}**") - - header_md = pn.pane.Markdown( - "\n\n".join(header_lines), - sizing_mode="stretch_width", - styles={"font-size": "11px"}, - ) - - fig = build_time_windows_figure(parsed, height=180) - fig_pane = pn.pane.Bokeh(fig, sizing_mode="stretch_width") - - return pn.Column( - header_md, - pn.Spacer(height=4), - fig_pane, - sizing_mode="stretch_width", - ) - - -def _build_right_tabs(manifest: Manifest) -> pn.Tabs: - """Right-hand panel: Region | Time Windows tabs.""" - region_panel = _build_region_panel(manifest) - time_panel = _build_time_windows_panel(manifest) - - return pn.Tabs( - ("Region", region_panel), - ("Time Windows", time_panel), - sizing_mode="stretch_width", - ) - - -def build_experiment_view(manifest: Manifest) -> pn.layout.Panel: - """Build the Experiment tab view. - - Left: metadata (overview + accordion sections). - Right: region map and time-window timeline. - """ - overview = _experiment_overview_block(manifest) - - meta_panel = pn.Column(_metadata_section(manifest), margin=(4, 0, 4, 4)) - temporal_panel = pn.Column(_temporal_section(manifest), margin=(4, 0, 4, 4)) - spatial_panel = pn.Column(_spatial_section(manifest), margin=(4, 0, 4, 4)) - models_panel = pn.Column(_models_section(manifest), margin=(4, 0, 4, 4)) - tests_panel = pn.Column(_tests_section(manifest), margin=(4, 0, 4, 4)) - run_cfg = _run_config_section(manifest) - - sections = pn.Accordion( - ("Metadata", meta_panel), - ("Temporal Configuration", temporal_panel), - ("Region Definition", spatial_panel), - ("Models", models_panel), - ("Evaluations", tests_panel), - ("Run Configuration", run_cfg), - sizing_mode="stretch_width", - active_header_background="#0b1120", - header_background="#0b1120", - header_color="#e5e7eb", - styles={"stroke": "#e5e7eb"}, - ) - - left = pn.Column( - overview, - pn.layout.Divider(), - sections, - width=380, - ) - - right = _build_right_tabs(manifest) - - return pn.Row( - left, - pn.Spacer(width=25), - right, - sizing_mode="stretch_both", - ) diff --git a/floatcsep/postprocess/panel/views/forecasts.py b/floatcsep/postprocess/panel/views/forecasts.py deleted file mode 100644 index 08bcdea..0000000 --- a/floatcsep/postprocess/panel/views/forecasts.py +++ /dev/null @@ -1,637 +0,0 @@ -from typing import Dict, Any, Optional, List - -from pathlib import Path - -import numpy as np -import panel as pn -from bokeh.models import ( - ColumnDataSource, - HoverTool, - LinearColorMapper, - ColorBar, -) -from bokeh.palettes import Magma256 - -from ..manifest import Manifest -from .utils import build_region_basemap, lonlat_to_mercator, make_doi_badge -from floatcsep.utils.file_io import GriddedForecastParsers, CatalogForecastParsers -import logging - -logger = logging.getLogger(__name__) - -pn.extension() - -_FORECAST_CACHE: Dict[Any, Any] = {} -_GLOBAL_FC_RANGE: Dict[str, Optional[float]] = { - "low": None, - "high": None, - "initialized": None, -} - - -def make_magma_alpha_palette( - alpha_exp: float = 0.0, - alpha_0: Optional[float] = None, -) -> List[str]: - base = list(Magma256) - n = len(base) - - if alpha_0 is not None: - a_arr = np.full(n, int(np.clip(alpha_0, 0.0, 1.0) * 255), dtype=int) - elif alpha_exp != 0.0: - a_arr = (np.linspace(0.05, 1.0, n) ** alpha_exp * 255).astype(int) - else: - a_arr = np.full(n, 255, dtype=int) - - palette: List[str] = [] - for color, a in zip(base, a_arr): - r = color[1:3] - g = color[3:5] - b = color[5:7] - aa = f"{a:02x}" - palette.append(f"#{r}{g}{b}{aa}") - return palette - - -def load_catalog_forecast_as_grid( - path: Path, - region: Any, - nsims: Optional[int] = None, -) -> tuple[np.ndarray, Any, np.ndarray]: - """ - Load a catalog-based forecast file and return a gridded representation: - - rates : (n_cells, n_mags) float32 array of expected rates - region : the region associated with the forecast (CartesianGrid2D) - mags : 1D array of magnitude bin edges - - This uses pyCSEP's CatalogForecast + get_expected_rates under the hood, - but exposes only raw arrays to the dashboard. - """ - if region is None: - raise ValueError("Region is required to load a catalog-based forecast.") - - cf = CatalogForecastParsers.csv( - path.as_posix(), - region=region, - filter_spatial=True, - apply_filters=True, - store=False, - ) - - if nsims is not None: - cf.n_cat = nsims - - gf = cf.get_expected_rates(verbose=False) - - rates = np.asarray(gf.data, dtype="float32") - region_out = getattr(gf, "region", region) - mags = np.asarray(getattr(gf, "magnitudes", [])) - - return rates, region_out, mags - - -def load_gridded_forecast( - manifest: Manifest, - model_index: int, - timewindow_str: str, -) -> Dict[str, Any]: - """ - Load and preprocess a gridded *or catalog-based* forecast for the dashboard. - - Returns a dict with: - x, y: cell centers (Web Mercator) - width, height: cell sizes (Web Mercator) - log10_rate: log10(total rate) per cell (NaN where rate <= 0) - mapper_meta: dict with vmin, vmax in log10 space, or None - """ - cache_key = (model_index, timewindow_str, "total") - if cache_key in _FORECAST_CACHE: - return _FORECAST_CACHE[cache_key] - - models: List[Dict[str, Any]] = getattr(manifest, "models", []) or [] - if model_index < 0 or model_index >= len(models): - data = dict(x=[], y=[], width=[], height=[], log10_rate=[], mapper_meta=None) - _FORECAST_CACHE[cache_key] = data - return data - - model_cfg = models[model_index] - fc_map = model_cfg.get("forecasts") or {} - fc_rel = fc_map.get(timewindow_str) - - if not fc_rel: - logger.warning( - "No forecast file found for model '%s' (index %d), time window '%s'.", - model_cfg.get("name", f"model_{model_index}"), - model_index, - timewindow_str, - ) - data = dict(x=[], y=[], width=[], height=[], log10_rate=[], mapper_meta=None) - _FORECAST_CACHE[cache_key] = data - return data - - app_root = Path(getattr(manifest, "app_root", ".")) - fc_path = (app_root / fc_rel).resolve() - suffix = fc_path.suffix.lower() - - func_kwargs = model_cfg.get("func_kwargs") or {} - # Heuristic / convention: catalog-based forecasts - is_catalog_fc = ( - model_cfg.get("forecast_class", "GriddedForecastRepository") - == "CatalogForecastRepository" - ) - try: - if is_catalog_fc: - # --- Catalog forecast path: use CatalogForecast + expected rates --- - region = getattr(manifest, "region", None) - if region is None: - raise ValueError( - f"Cannot load catalog forecast '{fc_path}': manifest.region is None." - ) - - nsims = func_kwargs.get("n_sims") - rates, region, mags = load_catalog_forecast_as_grid( - fc_path, - region=region, - nsims=nsims, - ) - - else: - # --- Classic gridded forecast path --- - if suffix == ".dat": - rates, region, mags = GriddedForecastParsers.dat(fc_path.as_posix()) - elif suffix in (".xml", ".gml"): - rates, region, mags = GriddedForecastParsers.xml(fc_path.as_posix()) - elif suffix in (".csv", ".txt"): - rates, region, mags = GriddedForecastParsers.csv(fc_path.as_posix()) - elif suffix in (".h5", ".hdf5"): - rates, region, mags = GriddedForecastParsers.hdf5(fc_path.as_posix()) - else: - logger.warning( - "Unsupported forecast file extension '%s' for '%s'. Skipping this forecast.", - suffix, - fc_path, - ) - data = dict(x=[], y=[], width=[], height=[], log10_rate=[], mapper_meta=None) - _FORECAST_CACHE[cache_key] = data - return data - - except Exception as exc: - logger.warning( - "Failed to load forecast from '%s' (model '%s', window '%s'): %s", - fc_path, - model_cfg.get("name", f"model_{model_index}"), - timewindow_str, - exc, - ) - data = dict(x=[], y=[], width=[], height=[], log10_rate=[], mapper_meta=None) - _FORECAST_CACHE[cache_key] = data - return data - - # From here on, treat both catalog-based and classic gridded forecasts identically - total_rates = rates.sum(axis=1).astype("float32") - - origins = region.origins() - dh = float(region.dh) - - lon_min = origins[:, 0] - lat_min = origins[:, 1] - lon_max = lon_min + dh - lat_max = lat_min + dh - - lon_c = lon_min + 0.5 * dh - lat_c = lat_min + 0.5 * dh - - x_c, y_c = lonlat_to_mercator(lon_c, lat_c) - - x_left, _ = lonlat_to_mercator(lon_min, lat_c) - x_right, _ = lonlat_to_mercator(lon_max, lat_c) - width = x_right - x_left - - _, y_bottom = lonlat_to_mercator(lon_c, lat_min) - _, y_top = lonlat_to_mercator(lon_c, lat_max) - height = y_top - y_bottom - - with np.errstate(divide="ignore", invalid="ignore"): - log10_rate = np.where(total_rates > 0.0, np.log10(total_rates), np.nan).astype( - "float32" - ) - - finite = np.isfinite(log10_rate) - if np.any(finite): - vmin = float(np.nanmin(log10_rate[finite])) - vmax = float(np.nanmax(log10_rate[finite])) - if vmax <= vmin: - vmax = vmin + 1.0 - mapper_meta = {"vmin": vmin, "vmax": vmax} - else: - mapper_meta = None - - data = dict( - x=x_c, - y=y_c, - width=width, - height=height, - log10_rate=log10_rate, - mapper_meta=mapper_meta, - ) - - _FORECAST_CACHE[cache_key] = data - return data - - -def build_model_options(manifest: Manifest) -> Dict[str, int]: - """Build a label -> model_index mapping for the model select widget.""" - options: Dict[str, int] = {} - models = getattr(manifest, "models", []) or [] - for i, model in enumerate(models): - name = model.get("name") or f"Model {i+1}" - options[name] = i - return options - - -def build_timewindow_options(manifest: Manifest) -> Dict[str, str]: - """Build a label -> timewindow_str mapping for the time-window select widget.""" - tw_strings = getattr(manifest, "time_windows", []) or [] - options: Dict[str, str] = {} - for tw in tw_strings: - label = tw - options[label] = tw - return options - - -def load_forecast_for_selection( - manifest: Manifest, - model_index: Optional[int], - timewindow_str: Optional[str], -) -> Dict[str, Any]: - """Return preprocessed forecast data for a model and time window.""" - empty = dict( - x=np.array([]), - y=np.array([]), - width=np.array([]), - height=np.array([]), - log10_rate=np.array([]), - mapper_meta=None, - ) - - if model_index is None or timewindow_str is None: - return empty - - models = getattr(manifest, "models", []) or [] - if model_index < 0 or model_index >= len(models): - return empty - - return load_gridded_forecast(manifest, model_index, timewindow_str) - - -def build_spatial_figure(manifest: Manifest, height: int = 350): - """Create a basemap figure and an empty forecast overlay with colorbar.""" - region = getattr(manifest, "region", None) - - fig, *_ = build_region_basemap( - region, - basemap="WorldTerrain", - min_height=height, - plot_cells=False, - ) - - fig.output_backend = "webgl" - - source = ColumnDataSource( - data=dict( - x=[], - y=[], - width=[], - height=[], - log10_rate=[], - ) - ) - - palette = make_magma_alpha_palette(alpha_exp=0.7, alpha_0=None) - color_mapper = LinearColorMapper( - palette=palette, - low=0.0, - high=1.0, - nan_color=(0, 0, 0, 0), - ) - - renderer = fig.rect( - x="x", - y="y", - width="width", - height="height", - source=source, - fill_color={"field": "log10_rate", "transform": color_mapper}, - fill_alpha=1.0, - line_color=None, - line_alpha=0.0, - ) - - hover = HoverTool( - renderers=[renderer], - tooltips=[ - ("log10 λ", "@log10_rate{0.00}"), - ], - mode="mouse", - ) - fig.add_tools(hover) - - color_bar = ColorBar( - color_mapper=color_mapper, - label_standoff=8, - location="bottom", - orientation="horizontal", - title="log10 λ", - title_text_color="#e5e7eb", - title_text_font_size="9pt", - major_label_text_color="#e5e7eb", - major_label_text_font_size="7pt", - background_fill_color=None, - background_fill_alpha=0.0, - border_line_color=None, - ) - fig.add_layout(color_bar, "below") - - fig._forecast_color_mapper = color_mapper - - return fig, source - - -def build_spatial_panel( - manifest: Manifest, - model_select: pn.widgets.Select, - timewindow_select: pn.widgets.Select, -) -> pn.Column: - """ - Build the spatial forecast panel with map and interactive color range. - - The model/timewindow selectors are provided by the caller and are typically - displayed in the left metadata panel. - """ - color_range = pn.widgets.RangeSlider( - name="", - start=-5.0, - end=5.0, - value=(-2.0, 2.0), - step=0.1, - show_value=False, - sizing_mode="stretch_width", - ) - - fig, source = build_spatial_figure(manifest, height=350) - fig_pane = pn.pane.Bokeh(fig, sizing_mode="stretch_both") - - def apply_color_range(event=None): - color_mapper = getattr(fig, "_forecast_color_mapper", None) - if color_mapper is None: - return - - val = color_range.value - if not val or len(val) != 2: - return - - low, high = val - if low is None or high is None or high <= low: - return - - color_mapper.low = low - color_mapper.high = high - - def update_forecast(event=None): - model_idx = model_select.value - tw_str = timewindow_select.value - - data = load_forecast_for_selection(manifest, model_idx, tw_str) - default = dict(x=[], y=[], width=[], height=[], log10_rate=[], mapper_meta=None) - default.update(data or {}) - - source.data = {k: v for k, v in default.items() if k != "mapper_meta"} - - color_mapper = getattr(fig, "_forecast_color_mapper", None) - mapper_meta = default.get("mapper_meta") - - if color_mapper is not None and mapper_meta is not None: - vmin = mapper_meta["vmin"] - vmax = mapper_meta["vmax"] - - global_low = _GLOBAL_FC_RANGE["low"] - global_high = _GLOBAL_FC_RANGE["high"] - - if global_low is None or vmin < global_low: - global_low = vmin - if global_high is None or vmax > global_high: - global_high = vmax - - _GLOBAL_FC_RANGE["low"] = global_low - _GLOBAL_FC_RANGE["high"] = global_high - - color_range.start = global_low - color_range.end = global_high - - initialized = _GLOBAL_FC_RANGE["initialized"] - - if not initialized: - new_low, new_high = global_low, global_high - _GLOBAL_FC_RANGE["initialized"] = True - else: - val_low, val_high = color_range.value - - val_low = max(global_low, min(val_low, global_high)) - val_high = max(global_low, min(val_high, global_high)) - - if val_high <= val_low: - new_low, new_high = global_low, global_high - else: - new_low, new_high = val_low, val_high - - color_range.value = (new_low, new_high) - - model_select.param.watch(update_forecast, "value") - timewindow_select.param.watch(update_forecast, "value") - color_range.param.watch(apply_color_range, "value") - - update_forecast() - - return pn.Column( - fig_pane, - color_range, - sizing_mode="stretch_both", - ) - - -def forecast_overview_block(manifest: Manifest) -> pn.panel: - """Return the title block for the Forecasts tab.""" - text = "## Forecasts" - return pn.pane.Markdown(text, sizing_mode="stretch_width") - - -def forecast_metadata_section(manifest: Manifest) -> pn.panel: - """ - Display forecast availability summary: - - Total time windows - - Per-model forecast count with a colored badge. - """ - - models = getattr(manifest, "models", []) or [] - time_windows = getattr(manifest, "time_windows", []) or [] - n_tw = len(time_windows) - - lines: List[str] = [] - lines.append("### Forecast Summary\n") - lines.append(f"**Total Time Windows:** {n_tw}\n") - - if not models: - lines.append("- _No models configured in manifest._") - return pn.pane.Markdown("\n".join(lines), sizing_mode="stretch_width") - - for m in models: - name = m.get("name", "Unnamed Model") - fc_map = m.get("forecasts", {}) or {} - - n_available = sum(1 for tw in time_windows if fc_map.get(tw) is not None) - - if n_available == 0: - color = "#ef4444" - elif n_available < n_tw: - color = "#f59e0b" - else: - color = "#22c55e" - - badge = f"●" - lines.append(f"- {name}: {n_available}/{n_tw} {badge}") - - return pn.pane.Markdown( - "\n".join(lines), - sizing_mode="stretch_width", - styles={"font-size": "11px"}, - ) - - -def build_model_metadata_pane( - manifest: Manifest, - model_select: pn.widgets.Select, -) -> pn.pane.Markdown: - """ - Build a small metadata block describing the currently selected model. - - This is updated whenever the model_select widget changes. - """ - models = getattr(manifest, "models", []) or [] - time_windows = getattr(manifest, "time_windows", []) or [] - - pane = pn.pane.Markdown( - "", - sizing_mode="stretch_width", - styles={"font-size": "11px"}, - ) - - def _update(event=None): - idx = model_select.value - if idx is None or not models or idx < 0 or idx >= len(models): - pane.object = "_No model selected._" - return - - m = models[idx] - name = m.get("name", f"Model {idx+1}") - - model_class = ( - "Gridded Forecast" - if m.get("forecast_class") == "GriddedForecastRepository" - else "Catalog Forecast" - ) - - unit = m.get("forecast_unit", "—") - giturl = m.get("giturl") or None - doi = m.get("doi") or None - fc_map = m.get("forecasts", {}) or {} - fmt = m.get("fmt", None) - n_tw_total = len(time_windows) - n_avail = sum(1 for tw in time_windows if fc_map.get(tw) is not None) - - lines: List[str] = [] - lines.append("### Selected Model\n") - lines.append(f"- **Name:** {name}") - lines.append(f"- **Forecast Type:** {model_class}") - lines.append(f"- **Forecast unit:** {unit}") - if giturl: - lines.append(f"- **Source repo:** {giturl}") - if doi: - badge = make_doi_badge(doi) - lines.append(f"- **DOI:** {badge}") - if fmt: - lines.append(f"- **Format:** {fmt}") - - badge = f"●" - lines.append(f"- **Forecast coverage:** {n_avail}/{n_tw_total} time windows {badge}") - - pane.object = "\n".join(lines) - - # Initial fill + watcher - _update() - model_select.param.watch(_update, "value") - - return pane - - -def build_metadata_panel( - manifest: Manifest, - model_select: pn.widgets.Select, - timewindow_select: pn.widgets.Select, -) -> pn.Column: - """Build the left-side metadata panel for the Forecasts tab.""" - overview = forecast_overview_block(manifest) - - model_metadata = build_model_metadata_pane(manifest, model_select) - - summary_metadata = forecast_metadata_section(manifest) - - summary = pn.Accordion( - ("Summary", summary_metadata), - sizing_mode="stretch_width", - active_header_background="#0b1120", - header_background="#0b1120", - header_color="#e5e7eb", - styles={"stroke": "#e5e7eb"}, - ) - - return pn.Column( - overview, - pn.layout.Divider(), - summary, - pn.layout.Divider(), - model_select, - timewindow_select, - model_metadata, - width=380, - ) - - -def build_forecasts_view(manifest: Manifest) -> pn.layout.Panel: - """Build the Forecasts tab view.""" - - model_options = build_model_options(manifest) - tw_options = build_timewindow_options(manifest) - - model_select = pn.widgets.Select( - name="", - options=model_options, - sizing_mode="stretch_width", - ) - timewindow_select = pn.widgets.Select( - name="", - options=tw_options, - sizing_mode="stretch_width", - ) - - left = build_metadata_panel(manifest, model_select, timewindow_select) - - spatial_panel = build_spatial_panel(manifest, model_select, timewindow_select) - spatial_panel.sizing_mode = "stretch_both" - - return pn.Row( - left, - pn.Spacer(width=25), - spatial_panel, - sizing_mode="stretch_both", - ) diff --git a/floatcsep/postprocess/panel/views/results.py b/floatcsep/postprocess/panel/views/results.py deleted file mode 100644 index 850455b..0000000 --- a/floatcsep/postprocess/panel/views/results.py +++ /dev/null @@ -1,244 +0,0 @@ -from typing import Dict, Any, Optional, List, Tuple -from pathlib import Path - -import panel as pn - -from ..manifest import Manifest - -pn.extension() - - -def build_timewindow_options(manifest: Manifest) -> Dict[str, str]: - """ - Build a label -> timewindow_str mapping for the time-window select widget. - Same pattern as in the Forecasts tab. - """ - tw_strings = getattr(manifest, "time_windows", []) or [] - options: Dict[str, str] = {} - for tw in tw_strings: - label = tw - options[label] = tw - return options - - -def build_test_options(manifest: Manifest) -> Dict[str, str]: - """ - Build a label -> test_name mapping for the test select widget. - """ - tests: List[Dict[str, Any]] = getattr(manifest, "tests", []) or [] - options: Dict[str, str] = {} - for t in tests: - name = t.get("name") or "Unnamed Test" - options[name] = name - return options - - -def index_tests_by_name(manifest: Manifest) -> Dict[str, Dict[str, Any]]: - """Convenience mapping: test_name -> test_dict.""" - tests: List[Dict[str, Any]] = getattr(manifest, "tests", []) or [] - return {t.get("name"): t for t in tests if t.get("name") is not None} - - -def build_model_options_for_test( - manifest: Manifest, - test_name: Optional[str], -) -> Dict[str, Optional[str]]: - """ - Build model options for a given test. - - - Always include "All models" (None value) which maps to results_main. - - If there are per-model figures for this test, add each model by name. - """ - options: Dict[str, Optional[str]] = {"All models": None} - - if not test_name: - return options - - res_model: Dict[Tuple[str, str, str], str] = getattr(manifest, "results_model", {}) or {} - - model_names = { - model_name for (tw_str, t_name, model_name) in res_model.keys() if t_name == test_name - } - - for m in sorted(model_names): - options[m] = m - - return options - - -def resolve_result_figure_path( - manifest: Manifest, - timewindow_str: Optional[str], - test_name: Optional[str], - model_name: Optional[str], -) -> Optional[Path]: - """ - Given the current selection, return the absolute Path to the result figure, - or None if not available. - """ - if not timewindow_str or not test_name: - return None - - results_main: Dict[Tuple[str, str], str] = getattr(manifest, "results_main", {}) or {} - results_model: Dict[Tuple[str, str, str], str] = ( - getattr(manifest, "results_model", {}) or {} - ) - - rel: Optional[str] = None - - if model_name is None: - rel = results_main.get((timewindow_str, test_name)) - else: - rel = results_model.get((timewindow_str, test_name, model_name)) - if rel is None: - rel = results_main.get((timewindow_str, test_name)) - - if not rel: - return None - - app_root = Path(getattr(manifest, "app_root", ".")) - return (app_root / rel).resolve() - - -def results_overview_block(manifest: Manifest) -> pn.panel: - """Title block for the Results tab.""" - text = "## Evaluation Results" - return pn.pane.Markdown(text, sizing_mode="stretch_width") - - -def build_results_view(manifest: Manifest) -> pn.layout.Panel: - """ - Build the Evaluation Results tab view. - - """ - - test_by_name = index_tests_by_name(manifest) - - tw_options = build_timewindow_options(manifest) - test_options = build_test_options(manifest) - - initial_tw = next(iter(tw_options.values()), None) - initial_test = next(iter(test_options.values()), None) - initial_model_options = build_model_options_for_test(manifest, initial_test) - - timewindow_select = pn.widgets.Select( - name="Time window", - options=tw_options, - value=initial_tw, - sizing_mode="stretch_width", - ) - - test_select = pn.widgets.Select( - name="Test", - options=test_options, - value=initial_test, - sizing_mode="stretch_width", - ) - - model_select = pn.widgets.Select( - name="Model", - options=initial_model_options, - value=next(iter(initial_model_options.values()), None), - sizing_mode="stretch_width", - ) - - test_metadata_pane = pn.pane.Markdown( - "", - sizing_mode="stretch_width", - styles={"font-size": "11px"}, - ) - - figure_pane = pn.pane.PNG( - None, - sizing_mode="stretch_both", - align="start", - ) - - def update_test_metadata(test_name: Optional[str]) -> None: - """Update the descriptive metadata block for the selected test.""" - if not test_name or test_name not in test_by_name: - test_metadata_pane.object = "_No metadata available for this test._" - return - - t = test_by_name[test_name] - lines: List[str] = [] - lines.append("### Test details\n") - lines.append(f"- **Name:** {t.get('name', '—')}") - lines.append(f"- **Function:** `{t.get('func', '—')}`") - ref_model = t.get("ref_model", None) - if ref_model: - lines.append(f"- **Reference model:** {ref_model}") - func_kwargs = t.get("func_kwargs") or {} - if func_kwargs: - lines.append("- **Parameters:**") - for k, v in func_kwargs.items(): - lines.append(f" - `{k}` = `{v}`") - - test_metadata_pane.object = "\n".join(lines) - - def refresh_model_options(event=None) -> None: - """ - When the test changes, rebuild the model options list - (always including 'All models'). - """ - test_name = test_select.value - model_opts = build_model_options_for_test(manifest, test_name) - - current = model_select.value - if current not in model_opts.values(): - current = next(iter(model_opts.values()), None) - - model_select.options = model_opts - model_select.value = current - - def update_figure(event=None) -> None: - """Update the figure pane based on current selections.""" - tw_str = timewindow_select.value - test_name = test_select.value - model_name = model_select.value - - path = resolve_result_figure_path(manifest, tw_str, test_name, model_name) - if path is None or not path.exists(): - figure_pane.object = None - figure_pane.alt_text = "No result figure available for this selection." - return - - figure_pane.object = str(path) - figure_pane.alt_text = f"Results for {test_name} ({tw_str})" - - def on_test_change(event): - update_test_metadata(event.new) - refresh_model_options() - update_figure() - - test_select.param.watch(on_test_change, "value") - timewindow_select.param.watch(update_figure, "value") - model_select.param.watch(update_figure, "value") - - update_test_metadata(initial_test) - update_figure() - - left_col = pn.Column( - results_overview_block(manifest), - pn.layout.Divider(), - timewindow_select, - test_select, - model_select, - pn.layout.Divider(), - test_metadata_pane, - width=380, - ) - - right_col = pn.Column( - pn.Spacer(height=25), - figure_pane, - pn.Spacer(height=25), - sizing_mode="stretch_both", - ) - - return pn.Row( - left_col, - pn.Spacer(width=30), - right_col, - sizing_mode="stretch_both", - ) diff --git a/floatcsep/postprocess/panel/views/utils.py b/floatcsep/postprocess/panel/views/utils.py deleted file mode 100644 index 062a80e..0000000 --- a/floatcsep/postprocess/panel/views/utils.py +++ /dev/null @@ -1,346 +0,0 @@ -from typing import Optional - -import numpy as np -from datetime import datetime, timedelta - -import xyzservices.providers as xyz -from bokeh.models import ( - ColumnDataSource, - HoverTool, - Range1d, - Span, - DatetimeTickFormatter, -) -from bokeh.plotting import figure -from shapely.geometry import Polygon, LineString, LinearRing, MultiLineString -from shapely.ops import unary_union - - -def make_doi_badge(doi: str, height: int = 14) -> str: - """Return an inline HTML snippet for a Zenodo-style DOI badge.""" - doi = doi.strip() - return ( - f'' - f'' - f"" - ) - - -def fmt_coord(x: Optional[float], ndigits: int = 3) -> str: - """Format a coordinate with sensible precision and no trailing zeros.""" - if x is None: - return "?" - try: - s = f"{round(float(x), ndigits):.{ndigits}f}" - s = s.rstrip("0").rstrip(".") - return s - except Exception: - return str(x) - - -def lonlat_to_mercator(lon, lat): - """Convert lon/lat in degrees to Web Mercator x/y in meters.""" - k = 6378137.0 - lon_rad = np.radians(lon) - lat_rad = np.radians(lat) - x = k * lon_rad - y = k * np.log(np.tan(np.pi / 4.0 + lat_rad / 2.0)) - return x, y - - -def add_region_cells(fig, region, to_mercator=True, alpha=0.2): - """Draw grid cells as semi-transparent patches.""" - xs_all = [] - ys_all = [] - - for cell in region.polygons: - pts = np.asarray(cell.points) - xs, ys = pts[:, 0], pts[:, 1] - if to_mercator: - xs, ys = lonlat_to_mercator(xs, ys) - xs_all.append(xs) - ys_all.append(ys) - - fig.patches( - xs=xs_all, - ys=ys_all, - fill_alpha=alpha, - fill_color="#0077b6", - line_color="#0077b6", - line_alpha=0.24, - line_width=0.2, - ) - - -def add_region_outline( - fig, - region, - to_mercator=True, - line_color="#0077b6", - line_width=1.0, - precision=4, -): - """Draw outline of a CartesianGrid2D region, including holes.""" - cell_polys = [Polygon(np.round(cell.points, precision)) for cell in region.polygons] - merged = unary_union(cell_polys) - boundary = merged.boundary - - if isinstance(boundary, (LineString, LinearRing)): - lines = [boundary] - elif isinstance(boundary, MultiLineString): - lines = list(boundary.geoms) - else: - return - - xs_list = [] - ys_list = [] - - for line in lines: - coords = np.asarray(line.coords) - xs = coords[:, 0] - ys = coords[:, 1] - if to_mercator: - xs, ys = lonlat_to_mercator(xs, ys) - xs_list.append(xs) - ys_list.append(ys) - - fig.multi_line(xs=xs_list, ys=ys_list, line_color=line_color, line_width=line_width) - - -def build_region_basemap(region, basemap="WorldTerrain", min_height=300, plot_cells=True): - """Create a Bokeh figure with a dark basemap and optional region overlay.""" - if region is not None: - xmin, xmax, ymin, ymax = region.get_bbox() - pad_x = pad_y = 10 * region.dh - xmin_p, xmax_p = xmin - pad_x, xmax + pad_x - ymin_p, ymax_p = ymin - pad_y, ymax + pad_y - - x0, y0 = lonlat_to_mercator(xmin_p, ymin_p) - x1, y1 = lonlat_to_mercator(xmax_p, ymax_p) - x_range = (x0, x1) - y_range = (y0, y1) - else: - x_range = (-18_000_000, 18_000_000) - y_range = (-7_000_000, 7_000_000) - - fig = figure( - x_range=x_range, - y_range=y_range, - x_axis_type="mercator", - y_axis_type="mercator", - tools="pan,wheel_zoom,box_zoom,reset", - active_scroll="wheel_zoom", - active_drag="pan", - toolbar_location="right", - match_aspect=True, - sizing_mode="scale_width", - min_width=300, - min_height=min_height, - ) - - DARK_BASEMAPS = { - "AlidadeSmoothDark": xyz.Stadia.AlidadeSmoothDark, - "DarkMatter": xyz.CartoDB.DarkMatter, - "WorldImagery": xyz.Esri.WorldImagery, - "WorldTerrain": xyz.Esri.WorldTerrain, - "WorldShadedRelief": xyz.Esri.WorldShadedRelief, - "USImagery": xyz.USGS.USImagery, - "BlueMarble": xyz.NASAGIBS.BlueMarble, - "GDEM": xyz.NASAGIBS.ASTER_GDEM_Greyscale_Shaded_Relief, - } - - # tiles = (tiles.build_url(scale_factor="@2x"),) - provider = DARK_BASEMAPS[basemap].copy() - # fig.add_tile(provider, retina=True) - - fig.add_tile(provider, retina=True) - - fig.toolbar.logo = None - fig.background_fill_color = "#0b1120" - fig.border_fill_color = "#0b1120" - fig.outline_line_color = None - fig.axis.visible = False - fig.grid.visible = False - - if region is not None: - add_region_outline(fig, region, to_mercator=True) - try: - n_cells = len(region.polygons) - except Exception: - n_cells = None - - if plot_cells: - if n_cells is not None and n_cells <= 50_000: - add_region_cells(fig, region, to_mercator=True) - if region is not None: - return fig, n_cells, region.dh, [xmin, xmax], [ymin, ymax] - else: - return fig, None, None, (None, None), (None, None) - - -def parse_time_window_strings(tw_strings): - """Parse 'YYYY-MM-DD to YYYY-MM-DD' strings into time window dicts.""" - parsed = [] - - for idx, s in enumerate(tw_strings or []): - if " to " not in s: - continue - start_str, end_str = s.split(" to ", 1) - try: - start = datetime.fromisoformat(start_str.strip()) - end = datetime.fromisoformat(end_str.strip()) - except ValueError: - continue - - length_days = (end - start).days - parsed.append( - { - "label": f"Window {idx + 1}", - "start": start, - "end": end, - "start_str": start_str.strip(), - "end_str": end_str.strip(), - "length_days": length_days, - } - ) - - return parsed - - -def build_time_windows_figure(parsed_windows, height=180): - """Build an interactive timeline of time windows.""" - if not parsed_windows: - fig = figure( - x_axis_type="datetime", - height=height, - sizing_mode="stretch_width", - toolbar_location="above", - tools="xwheel_zoom,xpan,box_zoom,reset", - active_scroll="xwheel_zoom", - ) - fig.title.text = "No time windows defined" - fig.yaxis.visible = False - fig.grid.visible = False - fig.background_fill_color = "#020617" - fig.border_fill_color = "#020617" - fig.outline_line_color = None - return fig - - windows_sorted = sorted(parsed_windows, key=lambda tw: tw["start"]) - lane_last_end = [] - lane_index = [] - - for tw in windows_sorted: - start = tw["start"] - end = tw["end"] - assigned = False - for i, last_end in enumerate(lane_last_end): - if start >= last_end: - lane_last_end[i] = end - lane_index.append(i) - assigned = True - break - if not assigned: - lane_last_end.append(end) - lane_index.append(len(lane_last_end) - 1) - - n_lanes = len(lane_last_end) - y = [li + 0.5 for li in lane_index] - bar_height = 0.6 - - starts = [tw["start"] for tw in windows_sorted] - ends = [tw["end"] for tw in windows_sorted] - - top = [yy + bar_height / 2 for yy in y] - bottom = [yy - bar_height / 2 for yy in y] - - source = ColumnDataSource( - { - "start": starts, - "end": ends, - "y": y, - "top": top, - "bottom": bottom, - "label": [tw["label"] for tw in windows_sorted], - "start_str": [tw["start_str"] for tw in windows_sorted], - "end_str": [tw["end_str"] for tw in windows_sorted], - "length_days": [tw["length_days"] for tw in windows_sorted], - } - ) - - x_min = min(starts) - x_max = max(ends) - pad = (x_max - x_min) * 0.05 if x_max > x_min else None - - fig = figure( - x_axis_type="datetime", - height=height, - sizing_mode="stretch_width", - toolbar_location="above", - tools="xwheel_zoom,xpan,reset", - active_scroll="xwheel_zoom", - ) - - if pad is not None: - fig.x_range = Range1d(x_min - pad, x_max + pad) - - fig.y_range = Range1d(-0.2, n_lanes + 0.8) - - fig.quad( - left="start", - right="end", - top="top", - bottom="bottom", - source=source, - fill_color="#38bdf8", - fill_alpha=0.6, - line_color="#0ea5e9", - line_width=1.0, - ) - - hover = HoverTool( - tooltips=[ - ("Window", "@label"), - ("Start", "@start_str"), - ("End", "@end_str"), - ("Length (days)", "@length_days"), - ], - mode="mouse", - ) - fig.add_tools(hover) - - today = datetime.today() - if today <= x_max and (x_max - today) <= timedelta(days=5 * 365): - today_span = Span( - location=today, - dimension="height", - line_color="#f97316", - line_width=2, - line_dash="dashed", - ) - fig.add_layout(today_span) - - fig.yaxis.visible = False - fig.ygrid.visible = False - fig.xgrid.visible = False - fig.background_fill_color = "#0b1120" - fig.border_fill_color = "#0b1120" - fig.outline_line_color = None - fig.xaxis.formatter = DatetimeTickFormatter( - years="%Y", - months="%b %Y", - days="%d %b %Y", - hours="%d %b %Y", - ) - fig.xaxis.major_label_orientation = np.pi / 2 - fig.xaxis.major_label_text_font_size = "6pt" - fig.axis.major_label_text_color = "#e5e7eb" - fig.axis.major_tick_line_color = "#6b7280" - fig.axis.minor_tick_line_color = None - fig.axis.axis_line_color = "#6b7280" - fig.title.text = "" - - fig.min_border_top = 10 - - return fig diff --git a/floatcsep/postprocess/web/README.md b/floatcsep/postprocess/web/README.md new file mode 100644 index 0000000..7c3f547 --- /dev/null +++ b/floatcsep/postprocess/web/README.md @@ -0,0 +1,51 @@ +# floatCSEP static dashboard + +A static web front end for an experiment. floatCSEP writes the experiment once as plain +files (`floatcsep export`), and the pages read those files in the browser. No server-side +code is needed to view it: any static web server works, including `floatcsep serve`, +`python -m http.server`, GitHub Pages or a Zenodo record. + +## Commands + +```bash +floatcsep export # writes /dashboard/ +floatcsep export -o DIR # custom output folder +floatcsep serve # exports if needed, serves on http://localhost:8765 and opens the browser +floatcsep serve -p 8080 --no-browser +``` + +Re-run `export` after a new `floatcsep run` to refresh the data. + +## Folder layout + +``` +dashboard/ + index.html, css/, js/, vendor/, fonts/, logos/ front end (copied from floatcsep/postprocess/web/static) + manifest.json experiment, region, magnitudes, time_windows, models, tests + file references + grid.json region cell origins, cell size, outline (GeoJSON) + catalog.json main catalog as column arrays (id, t [ms], lat, lon, depth, mag) + forecasts/m_w.json one file per model and window (see below) + results/index.json one record per (window, test, model): observed statistic, quantile, status, + distribution percentiles or Poisson parameters or confidence interval + results/w*_t*_m*.json full test distributions, loaded on demand + figures/ pyCSEP figures copied from the results folder +``` + +### Forecast files + +`rates` (cells x magnitude bins) are turned into cumulative rates per threshold +(M >= m_k), then log10 and quantized to uint16: `0` means no rate, `1..65535` map linearly +onto `[vmin, vmax]`. `data` is the base64 of that array (row-major, cells x thresholds); +`totals` is the expected number of events per threshold; `grid` is `"region"` when the +forecast shares the experiment grid, otherwise its own `{dh, origins}`. + +## Front end + +Plain ES modules, no build step. `js/app.js` loads the manifest, routes `#/experiment`, +`#/catalogs`, `#/forecasts`, `#/results` to `js/pages/*.js`, and handles the theme. +Maps are Leaflet (`vendor/leaflet`), charts are Apache ECharts (`vendor/echarts`), the +forecast raster is a canvas layer (`js/gridlayer.js`). Colours and spacing are CSS custom +properties in `css/app.css` (light and dark). + +Basemap tiles come from CARTO, Esri and OpenStreetMap, so maps need internet access; +everything else works offline. diff --git a/floatcsep/postprocess/web/__init__.py b/floatcsep/postprocess/web/__init__.py new file mode 100644 index 0000000..3fae0f3 --- /dev/null +++ b/floatcsep/postprocess/web/__init__.py @@ -0,0 +1,4 @@ +from .export import export_experiment +from .serve import serve + +__all__ = ["export_experiment", "serve"] diff --git a/floatcsep/postprocess/web/export.py b/floatcsep/postprocess/web/export.py new file mode 100644 index 0000000..2e5df1c --- /dev/null +++ b/floatcsep/postprocess/web/export.py @@ -0,0 +1,429 @@ +""" +Writes an experiment as a static dashboard folder: the manifest, the catalog, the forecasts, +the evaluation results and the front-end files. The folder can be served by any static web +server (``floatcsep serve``, ``python -m http.server``, GitHub Pages, ...). +""" + +import base64 +import json +import logging +import shutil +from pathlib import Path +from typing import Any, Dict, List, Optional + +import numpy as np + +from floatcsep.utils.helpers import timewindow2str +from .manifest import build_manifest +from .meta import citation, fair_scores, find_cache + +log = logging.getLogger("floatLogger") + +STATIC = Path(__file__).resolve().parent / "static" +ARTIFACTS = Path(__file__).resolve().parents[1] / "artifacts" + + +def _dump(obj: Any, path: Path) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + with open(path, "w") as f: + json.dump(obj, f, separators=(",", ":"), allow_nan=False) + + +def _round(arr: np.ndarray, nd: int) -> List[float]: + return np.round(np.asarray(arr, dtype=float), nd).tolist() + + +def _finite(value: Any) -> Any: + """Replaces non-finite numbers by None so the JSON stays standard.""" + if isinstance(value, dict): + return {k: _finite(v) for k, v in value.items()} + if isinstance(value, (list, tuple)): + return [_finite(v) for v in value] + if isinstance(value, float) and not np.isfinite(value): + return None + return value + + +def _outline(origins: np.ndarray, dh: float) -> Optional[Dict[str, Any]]: + """Union of the grid cells as a GeoJSON geometry (needs shapely, a pyCSEP dependency).""" + try: + from shapely.geometry import box, mapping + from shapely.ops import unary_union + except ImportError: + return None + eps = dh * 0.02 + cells = [box(x - eps, y - eps, x + dh + eps, y + dh + eps) for x, y in origins] + geom = unary_union(cells).buffer(-eps, join_style=2).simplify(dh * 0.01) + return mapping(geom) + + +def export_grid(region: Any, out: Path) -> Optional[Dict[str, Any]]: + if region is None: + return None + origins = np.asarray(region.origins(), dtype=float) + dh = float(region.dh) + grid = {"dh": dh, "origins": _round(origins, 5), "outline": _outline(origins, dh)} + _dump(grid, out / "grid.json") + return {"file": "grid.json", "n_cells": int(len(origins))} + + +def _columns(cat: Any) -> Dict[str, Any]: + d = cat.data + return { + "id": [i.decode() if isinstance(i, bytes) else str(i) for i in d["id"]], + "t": np.asarray(d["origin_time"], dtype=np.int64).tolist(), + "lat": _round(d["latitude"], 4), + "lon": _round(d["longitude"], 4), + "depth": _round(d["depth"], 2), + "mag": _round(d["magnitude"], 2), + } + + +def _iso(v: Any) -> Any: + from .manifest import _iso as iso + return iso(v) if hasattr(v, "isoformat") else v + + +def export_catalog(experiment: Any, manifest: Dict[str, Any], out: Path) -> Optional[Dict[str, Any]]: + """ + Writes the testing and input catalogs as floatCSEP produced them. + + The testing catalog is read from the files stored in ``results//catalog/``; each + event keeps the list of windows whose testing catalog contains it. The input catalog is + the one handed to the models (``input_config.catalog``), produced with the same + function floatCSEP uses to write it into each model's input folder, up to the start of + the last window. Events of the input catalog for a given window are those before its + start. + """ + repo = experiment.catalog_repo + rcfg = experiment.region_config or {} + windows = manifest["time_windows"] + + events: Dict[Any, int] = {} + test = {k: [] for k in ("id", "t", "lat", "lon", "depth", "mag")} + test["w"] = [] + missing = [] + for wi, win in enumerate(windows): + try: + cat = repo.get_test_cat(win["key"]) + except Exception: + missing.append(win["label"]) + continue + cols = _columns(cat) + for j in range(len(cols["id"])): + key = (cols["id"][j], cols["t"][j]) + if key not in events: + events[key] = len(test["id"]) + for c in ("id", "t", "lat", "lon", "depth", "mag"): + test[c].append(cols[c][j]) + test["w"].append([]) + test["w"][events[key]].append(wi) + if missing: + log.warning(f"No stored testing catalog for {len(missing)} window(s), e.g. {missing[0]}") + test["n"] = len(test["id"]) + test["filters"] = { + "region": manifest["region"].get("name"), + "mag_min": rcfg.get("mag_min"), + "mag_max": rcfg.get("mag_max"), + "depth_min": rcfg.get("depth_min"), + "depth_max": rcfg.get("depth_max"), + "time": "Within each window", + } + test["stored"] = "results//catalog/" + + inp = None + td = manifest["experiment"]["exp_class"] == "Time-Dependent" + if td or experiment.input_config: + try: + cat = repo.get_input_cat(windows[-1]["key"]) + inp = _columns(cat) + inp["n"] = len(inp["id"]) + cfg = repo.input_cat_config + reg = cfg.get("region") + inp["filters"] = { + "region": getattr(reg, "name", None) if reg is not None else None, + "mag_min": cfg.get("mag_min"), + "mag_max": cfg.get("mag_max"), + "depth_min": cfg.get("depth_min"), + "depth_max": cfg.get("depth_max"), + "start_date": _iso(cfg.get("start_date")), + "time": "Before each window start", + } + inp["stored"] = "Model input folders" + except Exception as exc: + log.warning(f"Could not build the input catalog: {exc}") + inp = None + + data = {"testing": test, "input": inp} + _dump(data, out / "catalog.json") + return { + "file": "catalog.json", + "n_testing": test["n"], + "n_input": inp["n"] if inp else None, + "source": str(repo.cat_path) if repo.cat_path else None, + } + + +def _encode_rates(rates: np.ndarray) -> Dict[str, Any]: + """ + Cumulative rates per cell and magnitude threshold, as quantized log10 values. + + Parameters + ---------- + rates : ndarray, shape (n_cells, n_mags) + Expected number of events per cell and magnitude bin. + + Returns + ------- + dict + ``vmin``/``vmax`` in log10 units, ``totals`` per threshold, and ``data`` as a + base64 little-endian uint16 array (row-major, cells x thresholds). 0 means no rate, + 1..65535 map linearly onto [vmin, vmax]. + """ + cum = np.cumsum(rates[:, ::-1], axis=1)[:, ::-1] + pos = cum > 0 + with np.errstate(divide="ignore"): + lg = np.where(pos, np.log10(np.where(pos, cum, 1.0)), np.nan) + if not pos.any(): + return {"vmin": 0.0, "vmax": 1.0, "totals": _round(cum.sum(axis=0), 4), "data": ""} + vmin, vmax = float(np.nanmin(lg)), float(np.nanmax(lg)) + if vmax <= vmin: + vmax = vmin + 1.0 + q = np.zeros(lg.shape, dtype=np.uint16) + q[pos] = np.round((lg[pos] - vmin) / (vmax - vmin) * 65534).astype(np.uint16) + 1 + return { + "vmin": vmin, + "vmax": vmax, + "totals": _round(cum.sum(axis=0), 4), + "data": base64.b64encode(q.astype(" None: + region = getattr(experiment, "region", None) + ref = np.asarray(region.origins(), dtype=float) if region is not None else None + windows = manifest["time_windows"] + + for mi, (model, mrec) in enumerate(zip(experiment.models, manifest["models"])): + for win in windows: + tstr = win["key"] + try: + rates, fregion, mags = _read_rates(model.get_forecast(tstr, region=region)) + except ValueError as exc: + if "more catalogs than" not in str(exc): + log.warning(f"Could not read forecast {model.name} / {tstr}: {exc}") + continue + log.warning( + f"{model.name} / {tstr}: {exc}. Reading it again with the number of " + f"catalogs found in the file (catalog_id may start at 1)." + ) + try: + fc = model.repository.load_forecast(tstr, name=model.name, region=region) + rates, fregion, mags = _read_rates(fc) + mrec.setdefault("notes", []).append( + f"Window {int(win['id'][1:]) + 1}: more catalogs in the file than n_sims" + ) + except Exception as exc2: + log.warning(f"Could not read forecast {model.name} / {tstr}: {exc2}") + continue + except Exception as exc: + log.warning(f"Could not read forecast {model.name} / {tstr}: {exc}") + continue + if rates is None: + continue + + rec = { + "model": mrec["id"], + "window": win["id"], + "mags": _round(mags, 3), + "n_cells": int(rates.shape[0]), + **_encode_rates(rates), + } + origins = np.asarray(fregion.origins(), dtype=float) + if ref is not None and origins.shape == ref.shape and np.allclose(origins, ref): + rec["grid"] = "region" + else: + rec["grid"] = {"dh": float(fregion.dh), "origins": _round(origins, 5)} + rel = f"forecasts/{mrec['id']}_{win['id']}.json" + _dump(rec, out / rel) + mrec["forecasts"][win["id"]] = rel + log.info(f"\tForecast {model.name} / {win['label']}") + + +def _summary(rec: Dict[str, Any], test_type: Optional[str]) -> Dict[str, Any]: + dist = rec.get("test_distribution") + obs = rec.get("observed_statistic") + out = { + "name": rec.get("name"), + "observed_statistic": obs, + "quantile": rec.get("quantile"), + "status": rec.get("status"), + "min_mw": rec.get("min_mw"), + } + if isinstance(dist, list) and dist and isinstance(dist[0], str): + out["dist"] = {"type": dist[0], "params": dist[1:]} + elif test_type == "comparative" and isinstance(dist, list) and len(dist) == 2: + out["ci"] = dist + elif isinstance(dist, list) and dist and isinstance(obs, (int, float)): + arr = np.asarray(dist, dtype=float) + arr = arr[np.isfinite(arr)] + if arr.size: + out["n_sim"] = int(arr.size) + out["dist_q"] = _round(np.percentile(arr, [2.5, 5, 25, 50, 75, 95, 97.5]), 5) + return out + + +def export_results(experiment: Any, manifest: Dict[str, Any], out: Path) -> Dict[str, Any]: + reg = experiment.registry + wid = {w["key"]: w["id"] for w in manifest["time_windows"]} + tid = {t["name"]: t for t in manifest["tests"]} + mid = {m["name"]: m["id"] for m in manifest["models"]} + index: List[Dict[str, Any]] = [] + + for wkey, tests in (reg.results or {}).items(): + for tname, models in tests.items(): + for mname, rel in models.items(): + path = reg.abs(reg.run_dir, rel) + if not path.exists() or tname not in tid or mname not in mid: + continue + try: + with open(path) as f: + rec = json.load(f) + except Exception as exc: + log.warning(f"Could not read result {path}: {exc}") + continue + t = tid[tname] + entry = {"window": wid.get(wkey, wkey), "test": t["id"], "model": mid[mname]} + entry.update(_summary(rec, t.get("type"))) + dist = rec.get("test_distribution") + if "dist_q" in entry: + frel = f"results/{entry['window']}_{t['id']}_{entry['model']}.json" + _dump({"test_distribution": _finite(dist)}, out / frel) + entry["dist_file"] = frel + elif isinstance(dist, list) and "ci" not in entry and "dist" not in entry: + entry["test_distribution"] = dist + index.append(_finite(entry)) + + _dump(index, out / "results" / "index.json") + return {"index": "results/index.json", "n": len(index)} + + +def export_figures(experiment: Any, manifest: Dict[str, Any], out: Path) -> Dict[str, Any]: + reg = experiment.registry + figs = reg.figures or {} + wid = {w["key"]: w["id"] for w in manifest["time_windows"]} + mid = {m["name"]: m["id"] for m in manifest["models"]} + tid = {t["name"]: t["id"] for t in manifest["tests"]} + result: Dict[str, Any] = {"windows": {}} + + def copy(rel: Any, dest: str) -> Optional[str]: + src = reg.abs(reg.run_dir, rel) + if not src.exists(): + return None + (out / dest).parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(src, out / dest) + return dest + + for key in ("main_catalog_map", "main_catalog_time"): + if key in figs: + d = copy(figs[key], f"figures/{Path(str(figs[key])).name}") + if d: + result[key] = d + + for wkey, w in wid.items(): + wf = figs.get(wkey) or {} + entry: Dict[str, Any] = {"tests": {}, "forecasts": {}} + for k in ("catalog_map", "catalog_time"): + if k in wf: + d = copy(wf[k], f"figures/{w}/{Path(str(wf[k])).name}") + if d: + entry[k] = d + for tname, t in tid.items(): + if tname in wf: + d = copy(wf[tname], f"figures/{w}/{Path(str(wf[tname])).name}") + if d: + entry["tests"][t] = d + for mname, m in mid.items(): + k = f"{tname}_{mname}" + if k in wf: + d = copy(wf[k], f"figures/{w}/{Path(str(wf[k])).name}") + if d: + entry["tests"][f"{t}:{m}"] = d + for mname, m in mid.items(): + fk = (wf.get("forecasts") or {}).get(mname) + if fk: + d = copy(fk, f"figures/{w}/{Path(str(fk)).name}") + if d: + entry["forecasts"][m] = d + result["windows"][w] = entry + return result + + +def export_static(out: Path) -> None: + for src in STATIC.rglob("*"): + if src.is_file(): + dest = out / src.relative_to(STATIC) + dest.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(src, dest) + logos = out / "logos" + logos.mkdir(exist_ok=True) + if ARTIFACTS.exists(): + for src in ARTIFACTS.glob("*.png"): + shutil.copy2(src, logos / src.name) + + +def export_experiment( + experiment: Any, + out_dir: Optional[str] = None, + forecasts: bool = True, + results: bool = True, + figures: bool = True, +) -> Path: + """ + Exports an experiment as a self-contained static dashboard. + + Parameters + ---------- + experiment : floatcsep.experiment.Experiment + A staged experiment whose results exist on disk. + out_dir : str, optional + Output folder. Defaults to ``/dashboard``. + forecasts, results, figures : bool + Which parts to export besides the manifest and the catalog. + + Returns + ------- + pathlib.Path + The output folder. + """ + reg = experiment.registry + out = Path(out_dir) if out_dir else Path(reg.run_dir) / "dashboard" + out.mkdir(parents=True, exist_ok=True) + log.info(f"Exporting dashboard to {out}") + + manifest = build_manifest(experiment) + roots = [Path.cwd(), Path(reg.workdir).resolve(), Path(__file__).resolve().parents[3]] + exp = manifest["experiment"] + exp["citation"] = citation(exp, find_cache("citation_cache.json", roots)) + exp["fair"] = fair_scores(exp.get("doi"), find_cache("fuji_cache.json", roots)) + manifest["grid"] = export_grid(getattr(experiment, "region", None), out) + manifest["catalog"] = export_catalog(experiment, manifest, out) + if forecasts: + export_forecasts(experiment, manifest, out) + manifest["results"] = export_results(experiment, manifest, out) if results else None + manifest["figures"] = export_figures(experiment, manifest, out) if figures else None + export_static(out) + _dump(manifest, out / "manifest.json") + log.info("Dashboard exported") + return out diff --git a/floatcsep/postprocess/web/manifest.py b/floatcsep/postprocess/web/manifest.py new file mode 100644 index 0000000..a79e8a9 --- /dev/null +++ b/floatcsep/postprocess/web/manifest.py @@ -0,0 +1,201 @@ +""" +JSON manifest of an experiment: the single contract between floatCSEP and the static +dashboard. Everything the pages show is either in this file or in a file it points to. +""" + +import datetime +import re +from typing import Any, Dict, List, Optional + +from floatcsep import __version__ as fc_version +from floatcsep.utils.helpers import timewindow2str + + +def _str(value: Any) -> Optional[str]: + if value is None: + return None + if isinstance(value, (list, tuple)): + return ", ".join(str(v) for v in value) + return str(value) + + +def _iso(value: Any) -> Optional[str]: + """ISO 8601 string in UTC. Naive datetimes are UTC in floatCSEP.""" + if isinstance(value, datetime.datetime): + if value.tzinfo is None: + value = value.replace(tzinfo=datetime.timezone.utc) + return value.astimezone(datetime.timezone.utc).isoformat().replace("+00:00", "Z") + return _str(value) + + +def _duration(value: Any) -> Optional[str]: + if value is None: + return None + if isinstance(value, str): + m = re.fullmatch(r"\s*(\d+(?:\.\d+)?)\s*-?\s*([a-zA-Z]+?)s?\s*", value) + if not m: + return value + n, unit = m.groups() + return f"{n} {unit}{'' if n in ('1', '1.0') else 's'}" + days = getattr(value, "days", None) + secs = getattr(value, "seconds", 0) + if days is None: + return str(value) + if days and not secs: + if days % 365 == 0: + n = days // 365 + return f"{n} year{'s' if n != 1 else ''}" + return f"{days} day{'s' if days != 1 else ''}" + if not days and secs: + h = secs // 3600 + return f"{h} hour{'s' if h != 1 else ''}" if h else f"{secs} s" + return str(value) + + +def _jsonable(value: Any) -> Any: + if isinstance(value, dict): + return {str(k): _jsonable(v) for k, v in value.items()} + if isinstance(value, (list, tuple)): + return [_jsonable(v) for v in value] + if isinstance(value, (int, float, str, bool)) or value is None: + return value + return str(value) + + +def _refs(value: Any) -> Optional[List[str]]: + if value is None: + return None + if isinstance(value, (list, tuple)): + return [str(v) for v in value] + return [str(value)] + + +def window_entries(experiment: Any) -> List[Dict[str, Any]]: + out = [] + for i, tw in enumerate(experiment.time_windows): + out.append( + { + "id": f"w{i}", + "key": timewindow2str(tw), + "label": timewindow2str(tw).replace("_", " – "), + "start": _iso(tw[0]), + "end": _iso(tw[1]), + } + ) + return out + + +def build_manifest(experiment: Any) -> Dict[str, Any]: + """ + Serializable description of an experiment for the dashboard. + + Parameters + ---------- + experiment : floatcsep.experiment.Experiment + A staged experiment (``stage_models`` and ``set_tree`` already called). + + Returns + ------- + dict + Keys ``experiment``, ``region``, ``magnitudes``, ``time_windows``, ``models``, + ``tests``. File references (``catalog``, ``grid``, ``results``, ``figures``) are + added by the exporter. + """ + tcfg = experiment.time_config or {} + rcfg = experiment.region_config or {} + region = getattr(experiment, "region", None) + exp_class = tcfg.get("exp_class", "ti") + + info = { + "name": experiment.name, + "authors": _str(experiment.authors), + "doi": experiment.doi, + "catalog_doi": experiment.catalog_doi, + "license": experiment.LICENSE, + "journal": experiment.journal, + "manuscript_doi": experiment.manuscript_doi, + "floatcsep_version": experiment.floatcsep_version or fc_version, + "pycsep_version": experiment.pycsep_version, + "last_run": _str(experiment.last_run), + "exp_time": _str(experiment.exp_time), + "exp_class": "Time-Dependent" if exp_class in ("td", "time-dependent") else "Time-Independent", + "start_date": _iso(experiment.start_date), + "end_date": _iso(experiment.end_date), + "horizon": _duration(tcfg.get("horizon")), + "offset": _duration(tcfg.get("offset")), + "growth": tcfg.get("growth"), + "n_intervals": len(experiment.time_windows), + "run_mode": experiment.run_mode, + "run_dir": _str(experiment.run_dir), + "config_file": _str(experiment.config_file), + "model_config": _str(experiment.model_config), + "test_config": _str(experiment.test_config), + } + + reg = None + if region is not None: + x0, x1, y0, y1 = region.get_bbox() + reg = { + "name": getattr(region, "name", None) or rcfg.get("region"), + "dh": float(region.dh), + "n_cells": int(len(region.origins())), + "bbox": [float(x0), float(y0), float(x1), float(y1)], + } + reg = reg or {} + reg.update( + { + "mag_min": rcfg.get("mag_min"), + "mag_max": rcfg.get("mag_max"), + "mag_bin": rcfg.get("mag_bin"), + "depth_min": rcfg.get("depth_min"), + "depth_max": rcfg.get("depth_max"), + } + ) + + models = [] + for i, m in enumerate(experiment.models): + models.append( + { + "id": f"m{i}", + "name": m.name, + "authors": _str(getattr(m, "authors", None)), + "doi": getattr(m, "doi", None), + "giturl": getattr(m, "giturl", None), + "git_hash": getattr(m, "repo_hash", None), + "zenodo_id": getattr(m, "zenodo_id", None), + "path": _str(m.registry.rel(m.registry.path)), + "func": _str(getattr(m, "func", None)), + "func_kwargs": _jsonable(getattr(m, "func_kwargs", None)), + "fmt": getattr(m, "fmt", None), + "forecast_unit": getattr(m, "forecast_unit", None), + "forecast_class": m.repository.__class__.__name__, + "forecasts": {}, + } + ) + + tests = [] + for i, t in enumerate(experiment.tests): + func = getattr(t, "func", None) + tests.append( + { + "id": f"t{i}", + "name": t.name, + "func": f"{func.__module__}.{func.__name__}" if func else None, + "type": getattr(t, "type", None), + "func_kwargs": _jsonable(getattr(t, "func_kwargs", None)), + "ref_model": _str(getattr(t, "ref_model", None)), + "ref_models": _refs(getattr(t, "ref_model", None)), + "plot_func": [f"{p.__module__}.{p.__name__}" for p in (t.plot_func or [])], + } + ) + + return { + "schema": 1, + "generated": datetime.datetime.now(datetime.timezone.utc).isoformat(timespec="seconds"), + "experiment": info, + "region": reg, + "magnitudes": [float(m) for m in experiment.magnitudes], + "time_windows": window_entries(experiment), + "models": models, + "tests": tests, + } diff --git a/floatcsep/postprocess/web/meta.py b/floatcsep/postprocess/web/meta.py new file mode 100644 index 0000000..962e504 --- /dev/null +++ b/floatcsep/postprocess/web/meta.py @@ -0,0 +1,74 @@ +""" +Citation and FAIR metadata for the dashboard. + +Reads the caches written by ``fetch_citations.py`` (``citation_cache.json``) and +``fetch_fuji.py`` (``fuji_cache.json``) when they exist, and falls back to a citation built +from the experiment fields otherwise. Both caches are keyed by ``https://doi.org/``. +""" + +import datetime +import json +import re +from pathlib import Path +from typing import Any, Dict, List, Optional + +PUBLISHER = "Collaboratory for the Study of Earthquake Predictability (CSEP)" + + +def _doi_url(doi: Optional[str]) -> str: + doi = (doi or "").strip() + if not doi: + return "" + return doi if doi.startswith("http") else f"https://doi.org/{doi}" + + +def find_cache(name: str, roots: List[Path]) -> Dict[str, Any]: + for root in roots: + for d in [root, *root.parents][:4]: + p = d / name + if p.exists(): + try: + return json.loads(p.read_text()) + except Exception: + return {} + return {} + + +def citation(exp: Dict[str, Any], cache: Dict[str, Any]) -> Dict[str, str]: + """APA, BibTeX and RIS strings for the experiment.""" + url = _doi_url(exp.get("doi")) + hit = cache.get(url) if url else None + if hit and any(hit.get(k) for k in ("apa", "bibtex", "ris")): + return {k: hit.get(k, "") for k in ("apa", "bibtex", "ris")} | {"source": "DataCite"} + + name = exp.get("name") or "Experiment" + authors = exp.get("authors") or "CSEP Working Group" + m = re.search(r"(\d{4})", str(exp.get("last_run") or "")) + year = m.group(1) if m else str(datetime.date.today().year) + doi = (exp.get("doi") or "").strip() + + apa = f"{authors} ({year}). {name}. CSEP." + (f" {url}" if url else "") + slug = (re.sub(r"[^A-Za-z0-9]+", "", name)[:20] or "experiment") + year + bib = [f" author = {{{authors}}}", f" title = {{{name}}}", f" year = {{{year}}}", f" publisher = {{{PUBLISHER}}}"] + if doi: + bib += [f" doi = {{{doi}}}", f" url = {{{url}}}"] + bibtex = f"@misc{{{slug},\n" + ",\n".join(bib) + "\n}" + ris = ["TY - DATA", f"TI - {name}", f"PY - {year}", f"PB - {PUBLISHER}"] + ris += [f"AU - {a.strip()}" for a in authors.split(",") if a.strip()] + if doi: + ris += [f"DO - {doi}", f"UR - {url}"] + ris.append("ER - ") + return {"apa": apa, "bibtex": bibtex, "ris": "\n".join(ris), "source": "experiment fields"} + + +def fair_scores(doi: Optional[str], cache: Dict[str, Any]) -> Optional[Dict[str, float]]: + """F, A, I, R and FAIR percentages from an F-UJI assessment, if cached.""" + url = _doi_url(doi) + res = cache.get(url) if url else None + if not isinstance(res, dict): + return None + pct = (res.get("summary") or {}).get("score_percent") + if not isinstance(pct, dict): + return None + out = {k: float(pct[k]) for k in ("F", "A", "I", "R", "FAIR") if pct.get(k) is not None} + return out or None diff --git a/floatcsep/postprocess/web/serve.py b/floatcsep/postprocess/web/serve.py new file mode 100644 index 0000000..e2d1d00 --- /dev/null +++ b/floatcsep/postprocess/web/serve.py @@ -0,0 +1,56 @@ +import functools +import logging +import threading +import webbrowser +from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer +from pathlib import Path +from typing import Union + +log = logging.getLogger("floatLogger") + + +class _Handler(SimpleHTTPRequestHandler): + extensions_map = { + **SimpleHTTPRequestHandler.extensions_map, + ".js": "text/javascript", + ".mjs": "text/javascript", + ".json": "application/json", + } + + def end_headers(self): + self.send_header("Cache-Control", "no-store") + super().end_headers() + + def log_message(self, fmt, *args): + log.debug("%s " + fmt, self.address_string(), *args) + + +def serve(directory: Union[str, Path], port: int = 8765, open_browser: bool = True) -> None: + """ + Serves an exported dashboard folder over HTTP and blocks until Ctrl-C. + + Parameters + ---------- + directory : str or Path + Folder written by :func:`export_experiment`. + port : int + TCP port; 0 picks a free one. + open_browser : bool + Open the default browser on the dashboard. + """ + directory = Path(directory).resolve() + if not (directory / "manifest.json").exists(): + raise FileNotFoundError(f"No manifest.json in {directory}; run `floatcsep export` first") + + handler = functools.partial(_Handler, directory=str(directory)) + httpd = ThreadingHTTPServer(("localhost", port), handler) + url = f"http://localhost:{httpd.server_address[1]}/" + log.info(f"Serving {directory} at {url} (Ctrl-C to stop)") + if open_browser: + threading.Timer(0.5, webbrowser.open, args=(url,)).start() + try: + httpd.serve_forever() + except KeyboardInterrupt: + pass + finally: + httpd.server_close() diff --git a/floatcsep/postprocess/web/static/css/app.css b/floatcsep/postprocess/web/static/css/app.css new file mode 100644 index 0000000..fa0fb70 --- /dev/null +++ b/floatcsep/postprocess/web/static/css/app.css @@ -0,0 +1,454 @@ +@font-face { + font-family: "Noto Sans"; + src: url("../fonts/NotoSans-Regular.ttf") format("truetype"); + font-weight: 400; + font-display: swap; +} +@font-face { + font-family: "Noto Sans"; + src: url("../fonts/NotoSans-Bold.ttf") format("truetype"); + font-weight: 700; + font-display: swap; +} + +:root { + --bg: #f4f6f9; + --surface: #ffffff; + --surface-2: #eaeef4; + --line: #d6dce6; + --line-2: #c0c9d6; + --ink: #0f172a; + --ink-2: #4b5768; + --ink-3: #5f6a7b; + --accent: #0f9b8e; + --accent-ink: #0b6f66; + --accent-soft: rgba(15, 155, 142, 0.12); + --good: #0a7a35; + --bad: #d03b3b; + --warn: #c98500; + --grid: #e3e8ef; + --focus: #2a78d6; + --shadow: 0 1px 2px rgba(15, 23, 42, 0.06); + --radius: 6px; + --s1: var(--series-1); + --series-1: #2a78d6; + --series-2: #eb6834; + --series-3: #1baf7a; + --series-4: #eda100; + --series-5: #e87ba4; + --series-6: #008300; + --series-7: #4a3aa7; + --series-8: #e34948; + --series-9: #0e7490; + --series-10: #8d5a2b; + color-scheme: light; +} + +@media (prefers-color-scheme: dark) { + :root:not([data-theme="light"]) { + --bg: #020617; + --surface: #0b1120; + --surface-2: #131c30; + --line: #1e2a44; + --line-2: #2b3a58; + --ink: #e5e7eb; + --ink-2: #a3adbd; + --ink-3: #8a95a8; + --accent: #14b8a6; + --accent-ink: #2dd4bf; + --accent-soft: rgba(20, 184, 166, 0.14); + --good: #22c55e; + --bad: #f05d5d; + --warn: #f0b429; + --grid: #182238; + --focus: #3987e5; + --shadow: none; + --series-1: #3987e5; + --series-2: #d95926; + --series-3: #199e70; + --series-4: #c98500; + --series-5: #d55181; + --series-6: #008300; + --series-7: #9085e9; + --series-8: #e66767; + --series-9: #22a7c7; + --series-10: #b4793c; + color-scheme: dark; + } +} +:root[data-theme="dark"] { + --bg: #020617; + --surface: #0b1120; + --surface-2: #131c30; + --line: #1e2a44; + --line-2: #2b3a58; + --ink: #e5e7eb; + --ink-2: #a3adbd; + --ink-3: #8a95a8; + --accent: #14b8a6; + --accent-ink: #2dd4bf; + --accent-soft: rgba(20, 184, 166, 0.14); + --good: #22c55e; + --bad: #f05d5d; + --warn: #f0b429; + --grid: #182238; + --focus: #3987e5; + --shadow: none; + --series-1: #3987e5; + --series-2: #d95926; + --series-3: #199e70; + --series-4: #c98500; + --series-5: #d55181; + --series-6: #008300; + --series-7: #9085e9; + --series-8: #e66767; + --series-9: #22a7c7; + --series-10: #b4793c; + color-scheme: dark; +} + +* { box-sizing: border-box; } +html, body { margin: 0; padding: 0; } +body { + background: var(--bg); + color: var(--ink); + font-family: "Noto Sans", "Segoe UI", system-ui, sans-serif; + font-size: 14px; + line-height: 1.5; + font-variant-numeric: tabular-nums; + -webkit-font-smoothing: antialiased; +} +a { color: var(--accent-ink); text-decoration: none; } +a:hover { text-decoration: underline; } +button, select, input { font: inherit; color: inherit; } +:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; } +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { transition: none !important; animation: none !important; } +} + +/* top bar */ +.topbar { + position: relative; z-index: 50; + background: var(--surface); + border-bottom: 1px solid var(--line); +} +.topbar-inner { + max-width: 1440px; margin: 0 auto; padding: 0 20px; + height: 56px; display: flex; align-items: center; gap: 20px; +} +.brand { display: flex; align-items: center; gap: 10px; min-width: 0; } +.brand img { height: 26px; width: auto; } +.brand .exp-name { + font-weight: 700; font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; +} +.brand .sep { color: var(--ink-3); } +.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 10px; } +.icon-link { color: var(--ink-2); display: inline-flex; padding: 6px; border-radius: var(--radius); } +.icon-link:hover { background: var(--surface-2); } +.icon-link svg { width: 18px; height: 18px; }/* meta strip */ + +.chip { + display: inline-flex; align-items: center; gap: 6px; + padding: 2px 9px; border-radius: 999px; font-size: 12px; + background: var(--surface); border: 1px solid var(--line); color: var(--ink-2); +} +.chip b { color: var(--ink); font-weight: 700; } +.chip.accent { border-color: var(--accent); color: var(--accent-ink); } + +/* page grid */ +.page { + max-width: 1440px; margin: 0 auto; padding: 14px 20px 32px; + display: grid; grid-template-columns: repeat(12, 1fr); gap: 14px; +} +.span-4 { grid-column: span 4; } +.span-5 { grid-column: span 5; } +.span-7 { grid-column: span 7; } +.span-8 { grid-column: span 8; } +.span-12 { grid-column: span 12; } +@media (max-width: 1100px) { + .span-4, .span-5 { grid-column: span 12; } + .span-7, .span-8 { grid-column: span 12; } +} +.stack { display: flex; flex-direction: column; gap: 14px; } + +/* panels */ +.panel { + background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); + box-shadow: var(--shadow); min-width: 0; +} +.panel-head { + display: flex; align-items: center; gap: 10px; padding: 10px 14px; + border-bottom: 1px solid var(--line); +} +.panel-head h2 { margin: 0; font-size: 14px; font-weight: 700; } +.panel-head .sub { color: var(--ink-3); font-size: 12px; } +.panel-head .right { margin-left: auto; display: flex; align-items: center; gap: 8px; } +.panel-body { padding: 12px 14px; } +.panel-body.flush { padding: 0; } +.panel-body.tight { padding: 6px 8px; }/* controls */ + +.field { display: flex; flex-direction: column; gap: 4px; min-width: 0; } +.field > span { font-size: 12px; color: var(--ink-2); } +select, .input { + background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); + padding: 5px 8px; min-height: 30px; max-width: 100%; +} +select:hover { border-color: var(--line-2); } +.seg { display: inline-flex; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); padding: 2px; } +.seg button { + background: transparent; border: 0; padding: 3px 10px; border-radius: 4px; color: var(--ink-2); cursor: pointer; +} +.seg button[aria-pressed="true"] { background: var(--surface); color: var(--ink); font-weight: 700; box-shadow: var(--shadow); } +.seg.small button { padding: 2px 8px; font-size: 12px; } +.btn { + background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); + padding: 5px 10px; cursor: pointer; color: var(--ink); +} +.btn:hover { border-color: var(--line-2); } +.btn.small { padding: 2px 8px; font-size: 12px; } +.checkbox { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; } +.checkbox input { accent-color: var(--accent); } + +/* sliders */ +.range { display: flex; align-items: center; gap: 10px; } +.range input[type="range"] { flex: 1; accent-color: var(--accent); min-width: 120px; } +.range .val { min-width: 3.5em; text-align: right; font-weight: 700; } +.drange { position: relative; height: 30px; flex: 1; min-width: 160px; } +.drange input[type="range"] { + position: absolute; left: 0; right: 0; top: 0; width: 100%; margin: 0; height: 30px; + background: transparent; pointer-events: none; -webkit-appearance: none; appearance: none; +} +.drange input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; pointer-events: auto; width: 14px; height: 14px; border-radius: 50%; + background: var(--accent); border: 2px solid var(--surface); cursor: pointer; +} +.drange input[type="range"]::-moz-range-thumb { + pointer-events: auto; width: 12px; height: 12px; border-radius: 50%; + background: var(--accent); border: 2px solid var(--surface); cursor: pointer; +} +.drange .track { + position: absolute; left: 0; right: 0; top: 13px; height: 4px; border-radius: 2px; background: var(--line); +} +.drange .fill { position: absolute; top: 13px; height: 4px; background: var(--accent); border-radius: 2px; } + +/* maps */ +.map { width: 100%; height: 520px; border-radius: 0 0 var(--radius) var(--radius); background: var(--surface-2); } +.map.short { height: 380px; } +.map-wrap { position: relative; } +.leaflet-container { font: inherit; } +.leaflet-container a { color: var(--accent-ink); } +.leaflet-popup-content-wrapper, .leaflet-popup-tip { + background: var(--surface); color: var(--ink); box-shadow: 0 2px 10px rgba(0,0,0,0.3); +} +.leaflet-popup-content { margin: 10px 12px; font-size: 12px; line-height: 1.45; } +.leaflet-bar a { background: var(--surface); color: var(--ink); border-bottom-color: var(--line); } +.leaflet-bar a:hover { background: var(--surface-2); } +.leaflet-control-attribution { background: color-mix(in srgb, var(--surface) 85%, transparent); color: var(--ink-3); font-size: 10px; } +.leaflet-control-attribution a { color: var(--ink-2); } +.cell-tip { + position: absolute; z-index: 900; pointer-events: none; padding: 4px 8px; font-size: 12px; + background: var(--surface); border: 1px solid var(--line); border-radius: 4px; color: var(--ink); + white-space: nowrap; box-shadow: 0 2px 8px rgba(0,0,0,0.25); display: none; +} +.colorbar { display: flex; align-items: center; gap: 10px; padding: 8px 14px; font-size: 12px; color: var(--ink-2); } +.colorbar canvas { height: 10px; width: 220px; border-radius: 3px; border: 1px solid var(--line); } +.colorbar .cb-label { color: var(--ink); } + +/* charts */ +.chart { width: 100%; height: 280px; } +.chart.tall { height: 420px; } +.chart.short { height: 200px; } + +/* tables */ +table.data { width: 100%; border-collapse: collapse; font-size: 13px; } +table.data th, table.data td { padding: 6px 10px; text-align: left; border-bottom: 1px solid var(--line); white-space: nowrap; } +table.data th { color: var(--ink-2); font-weight: 400; font-size: 12px; } +table.data td.num, table.data th.num { text-align: right; } +table.data tbody tr:hover { background: var(--surface-2); } +table.data tbody tr.clickable { cursor: pointer; } +table.data tbody tr.selected { background: var(--accent-soft); } +.table-scroll { overflow: auto; max-height: 360px; } + +/* definition lists */ +.props { margin: 0; display: grid; grid-template-columns: max-content 1fr; gap: 4px 14px; font-size: 13px; } +.props dt { color: var(--ink-2); } +.props dd { margin: 0; min-width: 0; overflow-wrap: anywhere; } +.props dd code { font-size: 12px; background: var(--surface-2); padding: 1px 5px; border-radius: 3px; } +details.section { border-bottom: 1px solid var(--line); } +details.section:last-child { border-bottom: 0; } +details.section > summary { + cursor: pointer; padding: 10px 14px; font-weight: 700; list-style: none; display: flex; align-items: center; gap: 8px; +} +details.section > summary::-webkit-details-marker { display: none; } +details.section > summary::before { + content: ""; width: 6px; height: 6px; border-right: 1.5px solid var(--ink-3); border-bottom: 1.5px solid var(--ink-3); + transform: rotate(-45deg); transition: transform 0.15s; +} +details.section[open] > summary::before { transform: rotate(45deg); } +details.section > summary .count { margin-left: auto; color: var(--ink-3); font-weight: 400; font-size: 12px; } +details.section > .body { padding: 0 14px 12px; } +.model-card { padding: 8px 0; border-top: 1px dashed var(--line); } +.model-card:first-child { border-top: 0; padding-top: 0; } +.model-card h4 { margin: 0 0 4px; font-size: 13px; display: flex; align-items: center; gap: 8px; } +.swatch { width: 10px; height: 10px; border-radius: 2px; display: inline-block; flex: none; } +.status { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; } +.status::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: currentColor; } +.status.pass { color: var(--good); } +.status.fail { color: var(--bad); } +.status.na { color: var(--ink-3); } +.legend { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: 12px; color: var(--ink-2); } +.legend span { display: inline-flex; align-items: center; gap: 6px; } +.note { color: var(--ink-3); font-size: 12px; } +.empty { padding: 30px; text-align: center; color: var(--ink-3); } +.doi { display: inline-block; font-size: 11px; padding: 1px 6px; border-radius: 3px; background: var(--accent-soft); color: var(--accent-ink); } +.figure { max-width: 100%; height: auto; display: block; margin: 0 auto; border-radius: 4px; } + +/* footer */ +.footer { background: #0b1120; border-top: 1px solid #1e2a44; color: #a3adbd; margin-top: 20px; } +.footer-inner { + max-width: 1440px; margin: 0 auto; padding: 16px 20px; display: flex; flex-wrap: wrap; align-items: center; gap: 18px; font-size: 12px; +} +.footer-inner .logos { margin-left: auto; display: flex; align-items: center; gap: 18px; flex-wrap: wrap; } +.footer-inner .logos img { height: 18px; width: auto; opacity: 0.85; } +.footer-inner .logos img.tall { height: 24px; } +.footer-inner a { color: #cbd5e1; } + +@media (max-width: 720px) { + .topbar-inner { gap: 8px; padding: 0 16px; } + .brand .exp-name { display: none; } + .page { padding-left: 16px; padding-right: 16px; } + .map { height: 380px; } +} + +/* sub grids */ +.two { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; } +@media (max-width: 900px) { .two { grid-template-columns: 1fr; } } + +/* section bar */ +.sections { + position: sticky; top: 0; z-index: 60; + background: var(--surface); border-bottom: 1px solid var(--line); +} +.sections-inner { max-width: 1440px; margin: 0 auto; padding: 0 12px; display: flex; gap: 2px; overflow-x: auto; } +.sections a { + display: inline-flex; align-items: center; gap: 9px; padding: 13px 18px 11px; + color: var(--ink-2); font-size: 16px; font-weight: 700; letter-spacing: 0.005em; + border-bottom: 3px solid transparent; text-decoration: none; white-space: nowrap; +} +.sections a svg { width: 20px; height: 20px; opacity: 0.8; } +.sections a:hover { color: var(--ink); background: var(--surface-2); text-decoration: none; } +.sections a.active { color: var(--accent-ink); border-bottom-color: var(--accent); } +.sections a.active svg { opacity: 1; } +.sections .count { + font-style: normal; font-size: 11px; font-weight: 700; min-width: 20px; text-align: center; + padding: 1px 6px; border-radius: 999px; background: var(--surface-2); color: var(--ink-2); +} +.sections a.active .count { background: var(--accent-soft); color: var(--accent-ink); } +.sections .count:empty { display: none; } +.topbar-inner { height: 50px; }/* basemap switch (leaflet control) */ +.basemap-switch a { width: auto !important; padding: 0 9px; font-size: 12px; font-weight: 700; line-height: 28px !important; height: 28px !important; } +.basemap-switch a.on { background: var(--accent) !important; color: #04221f !important; }/* config blocks */ + +.filters { margin: 0; padding: 0; list-style: none; font-size: 13px; } +.filters li { display: flex; gap: 10px; padding: 4px 0; border-bottom: 1px dashed var(--line); } +.filters li:last-child { border-bottom: 0; } +.filters li span:first-child { color: var(--ink-2); min-width: 9em; } + +/* experiment header */ +.exp-head { grid-column: span 12; display: grid; grid-template-columns: 1fr auto; gap: 18px; align-items: start; + padding: 18px 20px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); } +.exp-head h1 { margin: 0 0 4px; font-size: 24px; line-height: 1.25; } +.exp-head .authors { color: var(--ink-2); margin: 0 0 10px; } +.badges { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; } +.badges img { height: 20px; display: block; } +.badge-label { font-size: 12px; color: var(--ink-3); margin-right: -2px; } +.fair { display: flex; gap: 6px; align-items: center; } +.fair .pill { display: inline-flex; flex-direction: column; align-items: center; min-width: 42px; padding: 4px 6px; border-radius: 6px; border: 1px solid var(--line); } +.fair .pill b { font-size: 15px; } +.fair .pill span { font-size: 11px; color: var(--ink-2); } +.cite-box { width: 100%; min-height: 120px; font: 12px/1.45 ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--ink); + background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--radius); padding: 8px; resize: vertical; } +.flow { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; } +.flow .n { font-size: 26px; font-weight: 700; line-height: 1.1; } +.flow .t { color: var(--ink-2); font-size: 13px; } +.flow a { color: inherit; } +@media (max-width: 900px) { .flow { grid-template-columns: 1fr 1fr; } .exp-head { grid-template-columns: 1fr; } } + +/* v4: layout and readability */ +:root { --gap: 16px; } +body { font-size: 14.5px; } +.page { gap: var(--gap); padding-top: 18px; } +.stack { gap: var(--gap); } +.panel { border-radius: 8px; } +.panel-head { padding: 12px 16px; min-height: 48px; } +.panel-head h2 { font-size: 15px; } +.panel-head .sub { font-size: 12.5px; } +.panel-body { padding: 14px 16px; } +.panel-body.tight { padding: 8px 10px 6px; } +.field > span { font-size: 12.5px; font-weight: 700; color: var(--ink-2); } +.field .hint { font-size: 12px; font-weight: 400; color: var(--ink-3); } +select, .input, .btn { min-height: 34px; } +.btn.small { min-height: 28px; } +.seg button { min-height: 30px; } +.seg { width: 100%; } +.seg button { flex: 1; } +.seg.small { width: auto; } +.seg.small button { flex: none; } + +/* left control rail */ +.rail { position: sticky; top: 68px; z-index: 5; } +.rail .panel-body { display: flex; flex-direction: column; gap: 16px; } +.rail .group { display: flex; flex-direction: column; gap: 12px; padding-top: 14px; border-top: 1px solid var(--line); } +.rail .group:first-child { padding-top: 0; border-top: 0; } +.rail select { width: 100%; } +.rail .row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } +.stepper { display: grid; grid-template-columns: 34px 1fr 34px; gap: 4px; } +.stepper .btn { padding: 0; font-size: 18px; line-height: 1; } +.readout { margin: 0; font-size: 13.5px; color: var(--ink-2); line-height: 1.5; } +.readout b { color: var(--ink); } +@media (max-width: 1100px) { .rail { position: static; } } + +/* skip link */ +.skip { position: absolute; left: 12px; top: -40px; z-index: 100; background: var(--accent); color: #04221f; padding: 8px 12px; border-radius: 6px; font-weight: 700; } +.skip:focus { top: 8px; } + +/* legend chips under charts */ +.legend { padding: 4px 6px 8px; } +.visually-hidden { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; } +.map { height: 560px; } +.map.short { height: 420px; } +@media (max-width: 720px) { .map, .map.short { height: 360px; } } + +/* map legend */ +.map-legend { + position: absolute; z-index: 800; right: 10px; bottom: 26px; display: flex; flex-direction: column; gap: 6px; + padding: 8px 10px; background: color-mix(in srgb, var(--surface) 92%, transparent); border: 1px solid var(--line); border-radius: 6px; + font-size: 12px; color: var(--ink-2); box-shadow: 0 1px 4px rgba(0,0,0,0.2); +} +.map-legend .legend-kinds { display: flex; gap: 12px; flex-wrap: wrap; } +.map-legend .legend-kinds span { display: inline-flex; align-items: center; gap: 6px; color: var(--ink); } +.map-legend .legend-sizes { display: flex; flex-direction: column; gap: 2px; } +.map-legend svg { display: block; } +table.data tbody tr.clickable:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; } + +/* v6: summary strip and rail */ +.rail { position: static; } +.flow-cell { display: block; padding: 14px 18px; border-right: 1px solid var(--line); color: inherit; text-decoration: none; } +.flow-cell:last-child { border-right: 0; } +.flow-cell:hover { background: var(--surface-2); text-decoration: none; } +.flow-cell h3 { margin: 0 0 6px; font-size: 13px; font-weight: 700; color: var(--ink-2); } +.flow-cell .n { font-size: 28px; font-weight: 700; line-height: 1.1; color: var(--ink); } +.flow-cell .unit { font-size: 14px; font-weight: 400; color: var(--ink-2); margin-left: 6px; } +.flow-cell .lines { list-style: none; margin: 8px 0 0; padding: 0; font-size: 13px; color: var(--ink-2); line-height: 1.55; } +.flow > .flow-cell { padding: 14px 18px; } +@media (max-width: 900px) { .flow-cell:nth-child(2) { border-right: 0; } .flow-cell { border-bottom: 1px solid var(--line); } } +.mini { width: 100%; border-collapse: collapse; font-size: 13.5px; } +.mini th { text-align: right; font-weight: 400; font-size: 12px; color: var(--ink-2); padding: 0 0 4px 8px; } +.mini th:first-child { text-align: left; padding-left: 0; } +.mini td { padding: 3px 0 3px 8px; text-align: right; font-weight: 700; color: var(--ink); } +.mini td:first-child { text-align: left; padding-left: 0; font-weight: 400; color: var(--ink-2); } +.mini td .swatch { margin-right: 6px; border-radius: 50%; vertical-align: -1px; } +.flow-cell .lines li { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } +.flow-cell .lines li.more { color: var(--accent-ink); font-weight: 700; } +.flow-cell { min-width: 0; } +.scroll-list { max-height: 460px; overflow-y: auto; padding-right: 4px; } diff --git a/floatcsep/postprocess/web/static/fonts/NotoSans-Bold.ttf b/floatcsep/postprocess/web/static/fonts/NotoSans-Bold.ttf new file mode 100644 index 0000000..07f0d25 Binary files /dev/null and b/floatcsep/postprocess/web/static/fonts/NotoSans-Bold.ttf differ diff --git a/floatcsep/postprocess/web/static/fonts/NotoSans-Regular.ttf b/floatcsep/postprocess/web/static/fonts/NotoSans-Regular.ttf new file mode 100644 index 0000000..4bac02f Binary files /dev/null and b/floatcsep/postprocess/web/static/fonts/NotoSans-Regular.ttf differ diff --git a/floatcsep/postprocess/web/static/index.html b/floatcsep/postprocess/web/static/index.html new file mode 100644 index 0000000..4e4d695 --- /dev/null +++ b/floatcsep/postprocess/web/static/index.html @@ -0,0 +1,68 @@ + + + + + + floatCSEP + + + + + + + +
+
+ + floatCSEP + / + Loading… + +
+
+ + + +
+ + + + + + +
+
+
+ +
+ + + + + + diff --git a/floatcsep/postprocess/web/static/js/app.js b/floatcsep/postprocess/web/static/js/app.js new file mode 100644 index 0000000..babaf30 --- /dev/null +++ b/floatcsep/postprocess/web/static/js/app.js @@ -0,0 +1,76 @@ +import { getJSON, el, isDark } from "./util.js"; + +const pages = { + experiment: () => import("./pages/experiment.js"), + catalogs: () => import("./pages/catalogs.js"), + forecasts: () => import("./pages/forecasts.js"), + results: () => import("./pages/results.js"), +}; + +const ctx = { manifest: null, grid: null, catalog: null, page: null, current: null }; +const root = document.getElementById("page"); + +// theme +const themeSeg = document.getElementById("theme-seg"); +function applyTheme(mode) { + const html = document.documentElement; + if (mode === "system") html.removeAttribute("data-theme"); + else html.setAttribute("data-theme", mode); + for (const b of themeSeg.children) b.setAttribute("aria-pressed", String(b.dataset.theme === mode)); + try { localStorage.setItem("fc-theme", mode); } catch (e) {} + window.dispatchEvent(new CustomEvent("fc-theme", { detail: { dark: isDark() } })); +} +themeSeg.addEventListener("click", (e) => { + const b = e.target.closest("button"); + if (b) applyTheme(b.dataset.theme); +}); +window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => { + if (!document.documentElement.getAttribute("data-theme")) window.dispatchEvent(new CustomEvent("fc-theme", { detail: { dark: isDark() } })); +}); +(() => { + let t = "system"; + try { t = localStorage.getItem("fc-theme") || "system"; } catch (e) {} + for (const b of themeSeg.children) b.setAttribute("aria-pressed", String(b.dataset.theme === t)); +})(); + +async function route() { + const hash = location.hash.replace(/^#\/?/, "") || "experiment"; + const [name, query] = hash.split("?"); + const loader = pages[name] || pages.experiment; + for (const a of document.querySelectorAll("#nav a")) a.classList.toggle("active", a.dataset.page === (pages[name] ? name : "experiment")); + if (ctx.page && ctx.page.destroy) ctx.page.destroy(); + root.replaceChildren(el("div", { class: "empty span-12" }, "Loading…")); + const mod = await loader(); + ctx.params = Object.fromEntries(new URLSearchParams(query || "")); + ctx.page = mod; + root.replaceChildren(); + try { + await mod.render(root, ctx); + } catch (err) { + console.error(err); + root.replaceChildren(el("div", { class: "empty span-12" }, `This page could not be built: ${err.message}`)); + } +} + +async function main() { + try { + ctx.manifest = await getJSON("manifest.json"); + } catch (err) { + root.replaceChildren(el("div", { class: "empty span-12" }, "manifest.json was not found. Run `floatcsep export ` and serve the dashboard folder over HTTP.")); + return; + } + const m = ctx.manifest; + document.title = `floatCSEP: ${m.experiment.name}`; + document.getElementById("exp-name").textContent = m.experiment.name; + document.getElementById("footer-version").textContent = `floatCSEP ${m.experiment.floatcsep_version || ""}`.trim() + (m.experiment.pycsep_version ? ` · pyCSEP ${m.experiment.pycsep_version}` : ""); + const counts = { forecasts: m.models.length, results: m.tests.length }; + for (const [k, v] of Object.entries(counts)) { + const c = document.querySelector(`[data-count="${k}"]`); + if (c) c.textContent = String(v); + } + if (m.grid && m.grid.file) ctx.gridPromise = getJSON(m.grid.file); + window.addEventListener("hashchange", route); + route(); +} + +main(); diff --git a/floatcsep/postprocess/web/static/js/charts.js b/floatcsep/postprocess/web/static/js/charts.js new file mode 100644 index 0000000..dd7442d --- /dev/null +++ b/floatcsep/postprocess/web/static/js/charts.js @@ -0,0 +1,46 @@ +import { css, el } from "./util.js"; + +export function chrome() { + const ink = css("--ink"), ink2 = css("--ink-2"), grid = css("--grid"), line = css("--line-2"); + return { + textStyle: { fontFamily: "Noto Sans, Segoe UI, system-ui, sans-serif", color: ink2, fontSize: 12 }, + animationDuration: 250, + useUTC: true, + grid: { left: 52, right: 18, top: 28, bottom: 36, containLabel: false }, + tooltip: { + backgroundColor: css("--surface"), borderColor: css("--line"), textStyle: { color: ink, fontSize: 12 }, + extraCssText: "box-shadow: 0 2px 10px rgba(0,0,0,0.25); border-radius: 4px;", + }, + axis: { + axisLine: { lineStyle: { color: line } }, + axisTick: { show: false }, + axisLabel: { color: ink2 }, + splitLine: { lineStyle: { color: grid } }, + nameTextStyle: { color: ink2, fontSize: 12 }, + }, + legend: { type: "scroll", textStyle: { color: ink2 }, icon: "roundRect", itemWidth: 12, itemHeight: 8, top: 0, left: "center", width: "72%", pageIconColor: ink2, pageTextStyle: { color: ink2 } }, + }; +} + +export function axis(extra = {}) { + return { ...chrome().axis, ...extra }; +} + +/** Creates an ECharts instance on a node and keeps it sized to its container. */ +export function makeChart(node) { + const inst = echarts.init(node, null, { renderer: "canvas" }); + const ro = new ResizeObserver(() => inst.resize()); + ro.observe(node); + inst._ro = ro; + return inst; +} + +export function disposeChart(inst) { + if (!inst) return; + inst._ro && inst._ro.disconnect(); + inst.dispose(); +} + +export function chartNode(cls = "") { + return el("div", { class: "chart " + cls }); +} diff --git a/floatcsep/postprocess/web/static/js/gridlayer.js b/floatcsep/postprocess/web/static/js/gridlayer.js new file mode 100644 index 0000000..8cee936 --- /dev/null +++ b/floatcsep/postprocess/web/static/js/gridlayer.js @@ -0,0 +1,134 @@ +import { MAGMA } from "./magma.js"; + +/** + * Leaflet layer that paints gridded cell values on a canvas. + * + * `setData({origins, dh, values})` sets the cells (values aligned with origins, NaN = empty); + * `setRange(lo, hi)` sets the colour scale; `valueAt(latlng)` looks a cell up for tooltips. + */ +export const GridLayer = L.Layer.extend({ + initialize(options) { + L.setOptions(this, { alphaMin: 0.15, alphaMax: 0.9, pane: "overlayPane", ...options }); + this._cells = null; + this._lo = 0; + this._hi = 1; + this._alphaRamp = this._makeAlpha(); + }, + + onAdd(map) { + this._map = map; + if (!map.getPane("gridPane")) map.createPane("gridPane").style.zIndex = 350; + this.options.pane = "gridPane"; + this._canvas = L.DomUtil.create("canvas", "leaflet-zoom-animated leaflet-grid-layer"); + this._canvas.style.pointerEvents = "none"; + this.getPane().appendChild(this._canvas); + map.on("moveend zoomend resize viewreset", this._reset, this); + if (map.options.zoomAnimation) map.on("zoomanim", this._animateZoom, this); + this._reset(); + }, + + onRemove(map) { + L.DomUtil.remove(this._canvas); + map.off("moveend zoomend resize viewreset", this._reset, this); + map.off("zoomanim", this._animateZoom, this); + }, + + setData(cells) { + this._cells = cells; + this._index = null; + if (cells) { + const dh = cells.dh; + const idx = new Map(); + cells.origins.forEach(([x, y], i) => idx.set(`${Math.round(x / dh)}|${Math.round(y / dh)}`, i)); + this._index = (lon, lat) => { + const k = `${Math.round(Math.floor(lon / dh + 1e-9))}|${Math.round(Math.floor(lat / dh + 1e-9))}`; + const i = idx.get(k); + return i === undefined ? -1 : i; + }; + } + this._draw(); + }, + + setRange(lo, hi) { + this._lo = lo; + this._hi = hi > lo ? hi : lo + 1e-9; + this._draw(); + }, + + valueAt(latlng) { + if (!this._cells || !this._index) return null; + const i = this._index(latlng.lng, latlng.lat); + if (i < 0) return null; + const v = this._cells.values[i]; + return Number.isFinite(v) ? { index: i, value: v, origin: this._cells.origins[i] } : null; + }, + + _makeAlpha() { + const { alphaMin, alphaMax } = this.options; + const out = new Float32Array(256); + for (let i = 0; i < 256; i++) out[i] = alphaMin + (alphaMax - alphaMin) * Math.pow(i / 255, 0.8); + return out; + }, + + _animateZoom(e) { + const scale = this._map.getZoomScale(e.zoom); + const offset = this._map._latLngBoundsToNewLayerBounds(this._map.getBounds(), e.zoom, e.center).min; + L.DomUtil.setTransform(this._canvas, offset, scale); + }, + + _reset() { + const size = this._map.getSize(); + const topLeft = this._map.containerPointToLayerPoint([0, 0]); + L.DomUtil.setPosition(this._canvas, topLeft); + const dpr = window.devicePixelRatio || 1; + this._canvas.width = size.x * dpr; + this._canvas.height = size.y * dpr; + this._canvas.style.width = size.x + "px"; + this._canvas.style.height = size.y + "px"; + this._dpr = dpr; + this._draw(); + }, + + _draw() { + if (!this._map || !this._canvas) return; + const ctx = this._canvas.getContext("2d"); + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(0, 0, this._canvas.width, this._canvas.height); + if (!this._cells) return; + ctx.scale(this._dpr, this._dpr); + const { origins, dh, values } = this._cells; + const map = this._map; + const b = map.getBounds().pad(0.05); + const span = this._hi - this._lo; + const n = origins.length; + const rgb = this._rgb || (this._rgb = MAGMA.map((h) => [parseInt(h.slice(1, 3), 16), parseInt(h.slice(3, 5), 16), parseInt(h.slice(5, 7), 16)])); + for (let i = 0; i < n; i++) { + const v = values[i]; + if (!Number.isFinite(v)) continue; + const [x, y] = origins[i]; + if (x + dh < b.getWest() || x > b.getEast() || y + dh < b.getSouth() || y > b.getNorth()) continue; + const p0 = map.latLngToContainerPoint([y + dh, x]); + const p1 = map.latLngToContainerPoint([y, x + dh]); + if (this.options.fill) { + ctx.fillStyle = this.options.fill; + } else { + let t = (v - this._lo) / span; + t = t < 0 ? 0 : t > 1 ? 1 : t; + const ci = Math.round(t * 255); + const c = rgb[ci]; + ctx.fillStyle = `rgba(${c[0]},${c[1]},${c[2]},${this._alphaRamp[ci]})`; + } + ctx.fillRect(p0.x, p0.y, Math.max(p1.x - p0.x, 1), Math.max(p1.y - p0.y, 1)); + } + }, +}); + +export function drawColorbar(canvas, lo, hi) { + const ctx = canvas.getContext("2d"); + const w = (canvas.width = 220), h = (canvas.height = 10); + const g = ctx.createLinearGradient(0, 0, w, 0); + MAGMA.forEach((c, i) => g.addColorStop(i / 255, c)); + ctx.fillStyle = g; + ctx.fillRect(0, 0, w, h); + return [lo, hi]; +} diff --git a/floatcsep/postprocess/web/static/js/magma.js b/floatcsep/postprocess/web/static/js/magma.js new file mode 100644 index 0000000..1ef7446 --- /dev/null +++ b/floatcsep/postprocess/web/static/js/magma.js @@ -0,0 +1 @@ +export const MAGMA = ["#000003","#000004","#000006","#010007","#010109","#01010b","#02020d","#02020f","#030311","#040313","#040415","#050417","#060519","#07051b","#08061d","#09071f","#0a0722","#0b0824","#0c0926","#0d0a28","#0e0a2a","#0f0b2c","#100c2f","#110c31","#120d33","#140d35","#150e38","#160e3a","#170f3c","#180f3f","#1a1041","#1b1044","#1c1046","#1e1049","#1f114b","#20114d","#221150","#231152","#251155","#261157","#281159","#2a115c","#2b115e","#2d1060","#2f1062","#301065","#321067","#341068","#350f6a","#370f6c","#390f6e","#3b0f6f","#3c0f71","#3e0f72","#400f73","#420f74","#430f75","#450f76","#470f77","#481078","#4a1079","#4b1079","#4d117a","#4f117b","#50127b","#52127c","#53137c","#55137d","#57147d","#58157e","#5a157e","#5b167e","#5d177e","#5e177f","#60187f","#61187f","#63197f","#651a80","#661a80","#681b80","#691c80","#6b1c80","#6c1d80","#6e1e81","#6f1e81","#711f81","#731f81","#742081","#762181","#772181","#792281","#7a2281","#7c2381","#7e2481","#7f2481","#812581","#822581","#842681","#852681","#872781","#892881","#8a2881","#8c2980","#8d2980","#8f2a80","#912a80","#922b80","#942b80","#952c80","#972c7f","#992d7f","#9a2d7f","#9c2e7f","#9e2e7e","#9f2f7e","#a12f7e","#a3307e","#a4307d","#a6317d","#a7317d","#a9327c","#ab337c","#ac337b","#ae347b","#b0347b","#b1357a","#b3357a","#b53679","#b63679","#b83778","#b93778","#bb3877","#bd3977","#be3976","#c03a75","#c23a75","#c33b74","#c53c74","#c63c73","#c83d72","#ca3e72","#cb3e71","#cd3f70","#ce4070","#d0416f","#d1426e","#d3426d","#d4436d","#d6446c","#d7456b","#d9466a","#da4769","#dc4869","#dd4968","#de4a67","#e04b66","#e14c66","#e24d65","#e44e64","#e55063","#e65162","#e75262","#e85461","#ea5560","#eb5660","#ec585f","#ed595f","#ee5b5e","#ee5d5d","#ef5e5d","#f0605d","#f1615c","#f2635c","#f3655c","#f3675b","#f4685b","#f56a5b","#f56c5b","#f66e5b","#f6705b","#f7715b","#f7735c","#f8755c","#f8775c","#f9795c","#f97b5d","#f97d5d","#fa7f5e","#fa805e","#fa825f","#fb8460","#fb8660","#fb8861","#fb8a62","#fc8c63","#fc8e63","#fc9064","#fc9265","#fc9366","#fd9567","#fd9768","#fd9969","#fd9b6a","#fd9d6b","#fd9f6c","#fda16e","#fda26f","#fda470","#fea671","#fea873","#feaa74","#feac75","#feae76","#feaf78","#feb179","#feb37b","#feb57c","#feb77d","#feb97f","#febb80","#febc82","#febe83","#fec085","#fec286","#fec488","#fec689","#fec78b","#fec98d","#fecb8e","#fdcd90","#fdcf92","#fdd193","#fdd295","#fdd497","#fdd698","#fdd89a","#fdda9c","#fddc9d","#fddd9f","#fddfa1","#fde1a3","#fce3a5","#fce5a6","#fce6a8","#fce8aa","#fceaac","#fcecae","#fceeb0","#fcf0b1","#fcf1b3","#fcf3b5","#fcf5b7","#fbf7b9","#fbf9bb","#fbfabd","#fbfcbf"]; diff --git a/floatcsep/postprocess/web/static/js/pages/catalogs.js b/floatcsep/postprocess/web/static/js/pages/catalogs.js new file mode 100644 index 0000000..a42ea36 --- /dev/null +++ b/floatcsep/postprocess/web/static/js/pages/catalogs.js @@ -0,0 +1,395 @@ +import { el, panel, seg, select, field, fmt, getJSON, makeMap, outlineStyle, css, downloadCSV, debounce } from "../util.js"; +import { makeChart, disposeChart, chartNode, chrome, axis } from "../charts.js"; + +let map = null, charts = [], onTheme = null, markers = null; + +function dualRange(lo, hi, step, value, onChange) { + const wrap = el("div", { class: "range" }); + const box = el("div", { class: "drange" }); + const fill = el("div", { class: "fill" }); + const a = el("input", { type: "range", min: lo, max: hi, step, value: value[0], "aria-label": "Minimum magnitude" }); + const b = el("input", { type: "range", min: lo, max: hi, step, value: value[1], "aria-label": "Maximum magnitude" }); + const lab = el("span", { class: "val", style: { minWidth: "6.5em" } }); + const update = (emit) => { + let v0 = +a.value, v1 = +b.value; + if (v0 > v1) { if (document.activeElement === a) { v1 = v0; b.value = v0; } else { v0 = v1; a.value = v1; } } + const p0 = ((v0 - lo) / (hi - lo || 1)) * 100, p1 = ((v1 - lo) / (hi - lo || 1)) * 100; + fill.style.left = p0 + "%"; + fill.style.width = p1 - p0 + "%"; + lab.textContent = `M ${v0.toFixed(1)} – ${v1.toFixed(1)}`; + if (emit) onChange([v0, v1]); + }; + a.addEventListener("input", () => update(true)); + b.addEventListener("input", () => update(true)); + box.append(el("div", { class: "track" }), fill, a, b); + wrap.append(box, lab); + wrap.reset = (v) => { a.min = b.min = lo = v[0]; a.max = b.max = hi = v[1]; a.value = v[0]; b.value = v[1]; update(false); }; + update(false); + return wrap; +} + +function gr(mags, bin) { + if (!mags.length) return { x: [], inc: [], cum: [] }; + const lo = Math.floor(Math.min(...mags) / bin + 1e-6) * bin; + const n = Math.round((Math.max(...mags) - lo) / bin) + 1; + const inc = new Array(n).fill(0); + for (const m of mags) inc[Math.min(n - 1, Math.max(0, Math.round((m - lo) / bin - 1e-6)))]++; + const cum = []; + let c = 0; + for (let i = n - 1; i >= 0; i--) { c += inc[i]; cum[i] = c; } + return { x: inc.map((_, i) => +(lo + i * bin).toFixed(2)), inc, cum }; +} + +function filterList(f, stored) { + if (!f) return null; + const row = (k, v) => (v === null || v === undefined ? null : el("li", {}, el("span", {}, k), el("span", {}, String(v)))); + const num = (v) => (v === null || v === undefined ? null : Number(v)); + const range = (a, b, u = "", d = 1) => { + a = num(a); b = num(b); + if (a === null && b === null) return "None"; + const f = (v) => (v === null ? "–" : d ? v.toFixed(d) : String(v)); + return `${f(a)} – ${f(b)}${u}`; + }; + return el("ul", { class: "filters" }, + row("Region", f.region || "None"), + row("Magnitude", range(f.mag_min, f.mag_max)), + row("Depth", range(f.depth_min, f.depth_max, " km", 0)), + f.start_date !== undefined ? row("Start", f.start_date ? fmt.iso(f.start_date) : "None") : null, + row("Time", f.time), + row("Stored in", stored)); +} + +export async function render(root, ctx) { + const m = ctx.manifest, r = m.region || {}; + if (!m.catalog || !m.catalog.file) { + root.append(el("div", { class: "empty span-12" }, "No catalog was exported for this experiment.")); + return; + } + const [data, grid] = await Promise.all([getJSON(m.catalog.file), ctx.gridPromise || Promise.resolve(null)]); + const windows = m.time_windows.map((w, i) => ({ ...w, i, s: new Date(w.start).getTime(), e: new Date(w.end).getTime() })); + const cats = { input: data.input, testing: data.testing }; + const hasInput = !!(cats.input && cats.input.n); + const bin = r.mag_bin || 0.1; + const LABEL = { input: "Input", testing: "Testing" }; + const colorOf = (k) => (k === "input" ? css("--series-1") : css("--accent")); + + // one magnitude scale for every view + const allMags = [...(cats.testing ? cats.testing.mag : []), ...(hasInput ? cats.input.mag : [])]; + const magLo = allMags.length ? Math.floor(Math.min(...allMags) * 10) / 10 : 0; + const magHi = allMags.length ? Math.ceil(Math.max(...allMags) * 10) / 10 : 1; + const radius = (mag) => 3 + Math.max(0, mag - magLo) * 3; + + const state = { kind: hasInput ? "both" : "testing", win: "all", mag: [magLo, magHi] }; + const kindsShown = () => (state.kind === "both" ? ["input", "testing"] : [state.kind]); + + /** Events in view as {k, i} pairs, input first so testing is drawn on top. */ + function selection() { + const [m0, m1] = state.mag; + const w = state.win === "all" ? null : +state.win; + const out = []; + for (const k of kindsShown()) { + const cat = cats[k]; + if (!cat) continue; + for (let i = 0; i < cat.n; i++) { + if (cat.mag[i] < m0 - 1e-9 || cat.mag[i] > m1 + 1e-9) continue; + if (k === "testing") { + if (w !== null && !cat.w[i].includes(w)) continue; + } else { + const end = windows[w === null ? 0 : w].s; + if (cat.t[i] >= end) continue; + } + out.push({ k, i }); + } + } + return out; + } + + // controls + const kinds = hasInput ? [["both", "Both"], ["input", "Input"], ["testing", "Testing"]] : [["testing", "Testing"]]; + const winSel = el("select", { onchange: () => { state.win = winSel.value; update(); } }); + const winLabel = el("span", {}, "Time window"); + function fillWindows() { + winSel.replaceChildren(); + const inputOnly = state.kind === "input"; + if (!inputOnly) winSel.append(el("option", { value: "all" }, "All windows")); + for (const w of windows) { + const lab = inputOnly ? `Window ${w.i + 1}: before ${fmt.iso(w.start)}` : `Window ${w.i + 1}: ${w.label.replace(" to ", " – ")}`; + winSel.append(el("option", { value: String(w.i) }, lab)); + } + if (inputOnly && state.win === "all") { + const first = windows.find((w) => cats.input.t.some((t) => t < w.s)); + state.win = String(first ? first.i : windows.length - 1); + } + winSel.value = state.win; + winLabel.textContent = "Time window"; + } + const magCtl = dualRange(magLo, magHi, 0.1, state.mag, debounce((v) => { state.mag = v; update(); }, 60)); + const hint = el("span", { class: "hint" }); + const HINTS = { + both: "Input events are drawn below testing events. Both use the same magnitude scale.", + input: "Events available to the models before the window starts.", + testing: "Events used to evaluate the forecasts.", + }; + const kindSeg = seg(kinds, state.kind, (v) => { + state.kind = v; + fillWindows(); + update(); + }, false); + fillWindows(); + const readout = el("div", { class: "readout", "aria-live": "polite" }); + const dl = el("button", { class: "btn", onclick: () => { + const sel = selection(); + downloadCSV(`${m.experiment.name.replace(/\s+/g, "_")}_${state.kind}_catalog.csv`, ["catalog", "id", "origin_time", "latitude", "longitude", "depth", "magnitude"], + sel.map(({ k, i }) => { const c = cats[k]; return [k, c.id[i], new Date(c.t[i]).toISOString(), c.lat[i], c.lon[i], c.depth[i], c.mag[i]]; })); + } }, "Download CSV"); + + const left = el("div", { class: "span-4 stack" }); + const right = el("div", { class: "span-8 stack" }); + root.append(left, right); + left.append(panel("Catalogs", el("div", { class: "stack", style: { gap: "16px" } }, + el("div", { class: "group" }, field("Show", kindSeg), hint), + el("div", { class: "group" }, el("label", { class: "field" }, winLabel, winSel), el("div", { class: "field" }, el("span", {}, "Magnitude"), magCtl)), + el("div", { class: "group" }, readout, el("div", { class: "row" }, dl)), + ), { class: "rail" })); + left.lastChild.querySelector(".panel-body").style.display = "block"; + const filtersBox = el("div", { class: "stack", style: { gap: "12px" } }); + left.append(panel("Catalog Properties", filtersBox)); + const tableHead = el("tr"); + const tableBody = el("tbody"); + left.append(panel("Largest Events", el("div", { class: "table-scroll" }, el("table", { class: "data" }, + el("caption", { class: "visually-hidden" }, "Largest events in view. Select a row to show it on the map."), + el("thead", {}, tableHead), tableBody)), { flush: true })); + + const mapNode = el("div", { class: "map", role: "region", "aria-label": "Map of catalog events" }); + const legend = el("div", { class: "map-legend", "aria-label": "Map legend" }); + const mapWrap = el("div", { class: "map-wrap" }, mapNode, legend); + right.append(panel("Event Map", mapWrap, { flush: true })); + const mtNode = chartNode(), grNode = chartNode(); + const mtPanel = panel("Magnitude–Time", mtNode, { tight: true }); + const grPanel = panel("Frequency–Magnitude", grNode, { tight: true }); + right.append(el("div", { class: "two" }, mtPanel, grPanel)); + const perNode = chartNode("short"); + const perPanel = panel("Events per Time Window", perNode, { tight: true }); + right.append(perPanel); + + // map + map = makeMap(mapNode); + if (r.bbox) map.fitBounds([[r.bbox[1], r.bbox[0]], [r.bbox[3], r.bbox[2]]], { padding: [10, 10] }); + else map.setView([0, 0], 2); + let outline = null; + const drawOutline = () => { + if (outline) outline.remove(); + if (grid && grid.outline) outline = L.geoJSON(grid.outline, { style: { ...outlineStyle(), weight: 1.2, opacity: 0.8 } }).addTo(map); + }; + drawOutline(); + const layerOf = new Map(); + + function drawMarkers(sel) { + if (markers) markers.remove(); + markers = L.layerGroup(); + layerOf.clear(); + for (const k of kindsShown()) { + const cat = cats[k]; + const canvas = L.canvas({ padding: 0.3 }); + const items = sel.filter((x) => x.k === k).sort((a, b) => cat.mag[a.i] - cat.mag[b.i]); + for (const { i } of items) { + const mk = L.circleMarker([cat.lat[i], cat.lon[i]], { + renderer: canvas, radius: radius(cat.mag[i]), color: k === "testing" ? "#ffffff" : css("--surface"), weight: k === "testing" ? 1 : 0.6, + fillColor: colorOf(k), fillOpacity: k === "testing" ? 0.92 : 0.7, + }); + const wins = k === "testing" ? `
Window ${cat.w[i].map((x) => x + 1).join(" ")}` : ""; + mk.bindPopup(`M ${fmt.num(cat.mag[i], 1)} ${LABEL[k]} catalog
${fmt.datetime(cat.t[i])} UTC
${fmt.lat(cat.lat[i])} ${fmt.lon(cat.lon[i])}
Depth ${fmt.num(cat.depth[i], 1)} km${wins}
ID ${cat.id[i]}`); + mk.addTo(markers); + layerOf.set(`${k}:${i}`, mk); + } + } + markers.addTo(map); + drawLegend(); + } + + function drawLegend() { + const span = magHi - magLo; + const step = span > 2.5 ? 1 : 0.5; + let ticks = []; + for (let v = Math.ceil(magLo / step - 1e-9) * step; v <= magHi + 1e-9; v += step) ticks.push(+v.toFixed(1)); + if (!ticks.length || ticks[0] - magLo > step / 2) ticks.unshift(magLo); + while (ticks.length > 4) ticks = ticks.filter((_, j) => j % 2 === 0 || j === ticks.length - 1); + const rmax = radius(ticks[ticks.length - 1]); + const h = 2 * rmax + 4; + const ns = "http://www.w3.org/2000/svg"; + const svg = document.createElementNS(ns, "svg"); + let x = 0; + const parts = []; + for (const t of ticks) { + const rr = radius(t), wd = Math.max(2 * rr + 8, 46); + parts.push({ t, cx: x + wd / 2, rr }); + x += wd; + } + svg.setAttribute("width", String(x)); + svg.setAttribute("height", String(h + 16)); + svg.setAttribute("aria-hidden", "true"); + for (const { t, cx, rr } of parts) { + const c = document.createElementNS(ns, "circle"); + c.setAttribute("cx", cx); c.setAttribute("cy", h - rr); c.setAttribute("r", rr); + c.setAttribute("fill", css("--accent")); c.setAttribute("fill-opacity", "0.25"); c.setAttribute("stroke", css("--ink-2")); c.setAttribute("stroke-width", "1"); + const tx = document.createElementNS(ns, "text"); + tx.setAttribute("x", cx); tx.setAttribute("y", h + 13); tx.setAttribute("text-anchor", "middle"); + tx.setAttribute("font-size", "11"); tx.setAttribute("fill", css("--ink-2")); + tx.textContent = `M ${t.toFixed(1)}`; + svg.append(c, tx); + } + const sw = (k) => el("span", {}, el("i", { class: "swatch", style: { background: colorOf(k), borderRadius: "50%", opacity: k === "input" ? 0.75 : 1 } }), `${LABEL[k]} catalog`); + legend.replaceChildren( + el("div", { class: "legend-kinds" }, ...kindsShown().slice().reverse().map(sw)), + el("div", { class: "legend-sizes" }, el("span", { class: "note" }, "Magnitude"), svg), + el("span", { class: "visually-hidden" }, `Marker size shows magnitude from M ${magLo.toFixed(1)} to M ${magHi.toFixed(1)}.`), + ); + } + + const grc = makeChart(grNode), mt = makeChart(mtNode), per = makeChart(perNode); + charts = [grc, mt, per]; + + function drawCharts(sel) { + const c = chrome(); + const ks = kindsShown(); + const nz = (v) => (v > 0 ? v : null); + const grSeries = []; + let x0 = magLo, x1 = magHi; + for (const k of ks) { + const d = gr(sel.filter((x) => x.k === k).map((x) => cats[k].mag[x.i]), bin); + if (!d.x.length) continue; + grSeries.push({ name: `${LABEL[k]} N(≥M)`, type: "line", step: "end", data: d.x.map((x, i) => [x, nz(d.cum[i])]), symbol: "none", lineStyle: { width: 2, color: colorOf(k) }, itemStyle: { color: colorOf(k) }, z: k === "testing" ? 3 : 2 }); + grSeries.push({ name: `${LABEL[k]} N(M)`, type: "scatter", data: d.x.map((x, i) => [x, nz(d.inc[i])]), symbolSize: 6, itemStyle: { color: colorOf(k), opacity: 0.55 }, z: k === "testing" ? 3 : 2 }); + } + grc.setOption({ + ...c, + legend: { ...c.legend, data: grSeries.filter((s) => s.type === "line").map((s) => s.name), left: 10, right: "auto" }, + tooltip: { ...c.tooltip, trigger: "axis", valueFormatter: (v) => (v === null ? "0" : v) }, + grid: { ...c.grid, left: 44, top: 34 }, + xAxis: { type: "value", name: "Magnitude", nameLocation: "middle", nameGap: 24, min: x0, max: x1, ...axis() }, + yAxis: { type: "log", logBase: 10, min: 0.8, ...axis(), minorSplitLine: { show: false } }, + series: grSeries, + }, true); + + const w = state.win === "all" ? null : +state.win; + const band = []; + if (state.kind !== "input") { + for (const win of w === null ? windows : [windows[w]]) band.push([{ xAxis: win.s }, { xAxis: win.e }]); + } else { + band.push([{ xAxis: windows[w === null ? 0 : w].s }, { xAxis: windows[windows.length - 1].e }]); + } + mt.setOption({ + ...c, + legend: { show: false }, + grid: { ...c.grid, left: 40 }, + tooltip: { ...c.tooltip, trigger: "item", formatter: (p) => `${p.seriesName}
M ${fmt.num(p.value[1], 1)}
${fmt.datetime(p.value[0])}` }, + xAxis: { type: "time", ...axis() }, + yAxis: { type: "value", name: "M", min: Math.floor(magLo * 2) / 2, max: Math.ceil(magHi * 2) / 2, ...axis() }, + series: ks.map((k) => ({ + name: LABEL[k], type: "scatter", z: k === "testing" ? 3 : 2, + data: sel.filter((x) => x.k === k).map(({ i }) => [cats[k].t[i], cats[k].mag[i]]), + symbolSize: (v) => 2 * radius(v[1]) * 0.7, + itemStyle: { color: colorOf(k), opacity: k === "testing" ? 0.9 : 0.55, borderColor: css("--surface"), borderWidth: 0.5 }, + markArea: k === ks[ks.length - 1] && !(state.kind !== "input" && w === null && windows.length > 1) ? { silent: true, itemStyle: { color: css("--accent-soft") }, data: band } : undefined, + })), + }, true); + + const many = windows.length > 30; + const series = []; + if (ks.includes("input")) { + const ci = cats.input; + series.push({ name: LABEL.input, counts: windows.map((win) => { let n = 0; for (let i = 0; i < ci.n; i++) if (ci.t[i] < win.s) n++; return n; }) }); + } + if (ks.includes("testing")) { + const ct = cats.testing; + series.push({ name: LABEL.testing, counts: windows.map((win) => { let n = 0; for (let i = 0; i < ct.n; i++) if (ct.w[i].includes(win.i)) n++; return n; }) }); + } + per.setOption({ + ...c, + legend: { ...c.legend, data: series.map((s) => s.name), left: 10, right: "auto" }, + grid: { ...c.grid, left: 20, right: 30, top: 34, bottom: 10, containLabel: true }, + tooltip: { ...c.tooltip, trigger: "axis", formatter: (ps) => `${windows[ps[0].dataIndex].label}
` + ps.map((p) => `${p.seriesName}: ${p.value}`).join("
") }, + xAxis: many + ? { type: "category", data: windows.map((x) => x.end.slice(0, 10)), ...axis(), axisLabel: { ...axis().axisLabel, interval: Math.ceil(windows.length / 12) } } + : { type: "category", data: windows.map((x) => x.label), ...axis(), axisLabel: { ...axis().axisLabel, rotate: windows.length > 6 ? 30 : 0, fontSize: 11 } }, + yAxis: { type: ks.length > 1 ? "log" : "value", minInterval: 1, min: ks.length > 1 ? 1 : 0, ...axis(), minorSplitLine: { show: false } }, + series: series.map((s) => { + const k = s.name === LABEL.input ? "input" : "testing"; + return { + name: s.name, type: many ? "line" : "bar", barMaxWidth: 26, symbol: "none", lineStyle: { width: 2, color: colorOf(k) }, itemStyle: { color: colorOf(k) }, + data: s.counts.map((v, i) => ({ value: ks.length > 1 && v === 0 ? null : v, itemStyle: { color: colorOf(k), opacity: w === null || w === i ? 1 : 0.35, borderRadius: [2, 2, 0, 0] } })), + }; + }), + }, true); + per.off("click"); + per.on("click", (p) => { + if (state.kind === "input") state.win = String(p.dataIndex); + else state.win = state.win === String(p.dataIndex) ? "all" : String(p.dataIndex); + winSel.value = state.win; + update(); + }); + } + + function drawTable(sel) { + const both = state.kind === "both"; + tableHead.replaceChildren(...[ + el("th", { scope: "col" }, "Origin time UTC"), el("th", { scope: "col", class: "num" }, "M"), el("th", { scope: "col", class: "num" }, "Depth km"), + both ? el("th", { scope: "col" }, "Catalog") : null].filter(Boolean)); + const top = [...sel].sort((a, b) => cats[b.k].mag[b.i] - cats[a.k].mag[a.i]).slice(0, 12); + tableBody.replaceChildren(...top.map(({ k, i }) => { + const cat = cats[k]; + return el("tr", { class: "clickable", tabindex: "0", title: "Show on the map", onclick: () => focusEvent(k, i), onkeydown: (e) => { if (e.key === "Enter") focusEvent(k, i); } }, + el("td", {}, fmt.datetime(cat.t[i])), el("td", { class: "num" }, fmt.num(cat.mag[i], 1)), el("td", { class: "num" }, fmt.num(cat.depth[i], 0)), + both ? el("td", {}, el("span", { class: "swatch", style: { background: colorOf(k), borderRadius: "50%", marginRight: "6px" } }), LABEL[k]) : null); + })); + if (!top.length) tableBody.append(el("tr", {}, el("td", { colspan: both ? 4 : 3, class: "empty" }, "No events match these filters."))); + } + + function focusEvent(k, i) { + const cat = cats[k]; + map.setView([cat.lat[i], cat.lon[i]], Math.max(map.getZoom(), 8)); + const mk = layerOf.get(`${k}:${i}`); + if (mk) mk.openPopup(); + } + + function drawReadout(sel) { + const rows = kindsShown().slice().reverse().map((k) => { + const ms = sel.filter((x) => x.k === k).map((x) => cats[k].mag[x.i]); + return el("tr", {}, + el("td", {}, el("span", { class: "swatch", style: { background: colorOf(k) } }), LABEL[k]), + el("td", {}, fmt.int(ms.length)), + el("td", {}, ms.length ? fmt.num(Math.max(...ms), 1) : "–")); + }); + readout.replaceChildren(el("table", { class: "mini" }, + el("thead", {}, el("tr", {}, el("th", { scope: "col" }, "Catalog"), el("th", { scope: "col" }, "Events"), el("th", { scope: "col" }, "M max"))), + el("tbody", {}, rows))); + } + + function drawFilters() { + filtersBox.replaceChildren(...kindsShown().slice().reverse().map((k) => el("div", {}, + el("h4", { style: { margin: "0 0 4px", fontSize: "13px", display: "flex", alignItems: "center", gap: "6px" } }, el("span", { class: "swatch", style: { background: colorOf(k), borderRadius: "50%" } }), `${LABEL[k]} catalog`), + filterList(cats[k].filters, cats[k].stored) || el("p", { class: "note" }, "No filter information.")))); + } + + function update() { + hint.textContent = HINTS[state.kind]; + const sel = selection(); + drawFilters(); + drawMarkers(sel); + drawCharts(sel); + drawTable(sel); + drawReadout(sel); + } + update(); + + onTheme = () => { drawOutline(); update(); }; + window.addEventListener("fc-theme", onTheme); +} + +export function destroy() { + window.removeEventListener("fc-theme", onTheme); + if (map) { map.remove(); map = null; } + charts.forEach(disposeChart); + charts = []; + markers = null; +} diff --git a/floatcsep/postprocess/web/static/js/pages/experiment.js b/floatcsep/postprocess/web/static/js/pages/experiment.js new file mode 100644 index 0000000..c801c99 --- /dev/null +++ b/floatcsep/postprocess/web/static/js/pages/experiment.js @@ -0,0 +1,216 @@ +import { el, panel, seg, fmt, doiBadge, makeMap, outlineStyle, seriesColor, css } from "../util.js"; +import { makeChart, disposeChart, chartNode, chrome, axis } from "../charts.js"; +import { GridLayer } from "../gridlayer.js"; + +let map = null, chart = null, onTheme = null; + +const TEST_TYPES = { consistency: "Consistency", comparative: "Comparative", sequential: "Sequential", sequential_comparative: "Sequential comparative", batch: "Batch" }; + +function props(pairs) { + const dl = el("dl", { class: "props" }); + for (const [k, v] of pairs) { + if (v === null || v === undefined || v === "" || v === "None") continue; + dl.append(el("dt", {}, k), el("dd", {}, v)); + } + return dl; +} + +function code(v) { + return v === null || v === undefined ? null : el("code", {}, typeof v === "object" ? JSON.stringify(v) : String(v)); +} + +function header(m) { + const e = m.experiment; + const badges = el("div", { class: "badges" }); + const add = (label, node) => { if (node) badges.append(el("span", { class: "badge-label" }, label), node); }; + add("Experiment", doiBadge(e.doi)); + add("Manuscript", doiBadge(e.manuscript_doi)); + add("Catalog", doiBadge(e.catalog_doi)); + if (e.license) badges.append(el("span", { class: "chip" }, el("b", {}, e.license))); + badges.append(el("span", { class: "chip accent" }, el("b", {}, e.exp_class))); + + const right = el("div", { class: "stack", style: { gap: "8px", alignItems: "flex-end" } }); + if (e.fair) { + const tone = (v) => (v >= 75 ? css("--good") : v >= 40 ? css("--warn") : css("--bad")); + right.append(el("span", { class: "note" }, "FAIR score, F-UJI"), + el("div", { class: "fair" }, ["F", "A", "I", "R", "FAIR"].filter((k) => e.fair[k] !== undefined).map((k) => + el("span", { class: "pill", style: { borderColor: tone(e.fair[k]) } }, el("b", { style: { color: tone(e.fair[k]) } }, `${Math.round(e.fair[k])}`), el("span", {}, k))))); + } + return el("section", { class: "exp-head" }, + el("div", {}, + el("h1", {}, e.name), + e.authors ? el("p", { class: "authors" }, e.authors) : null, + e.journal ? el("p", { class: "note", style: { margin: "-6px 0 10px" } }, e.journal) : null, + badges), + right); +} + +function flow(m) { + const e = m.experiment, r = m.region || {}; + const lines = (...xs) => { + xs = xs.filter(Boolean); + const shown = xs.length > 4 ? xs.slice(0, 3) : xs; + const items = shown.map((x) => el("li", { title: x }, x)); + if (xs.length > shown.length) items.push(el("li", { class: "more" }, `+ ${xs.length - shown.length} more`)); + return el("ul", { class: "lines" }, items); + }; + const cell = (title, n, unit, href, body) => el("a", { class: "flow-cell", href }, + el("h3", {}, title), el("div", { class: "n" }, n, unit ? el("span", { class: "unit" }, unit) : null), body); + const nw = m.time_windows.length; + const mag = (v) => (v === null || v === undefined ? "?" : Number(v).toFixed(1)); + return el("section", { class: "panel span-12" }, el("div", { class: "flow" }, + cell("Time Configuration", String(nw), nw === 1 ? "window" : "windows", "#/catalogs", lines( + `${fmt.iso(e.start_date)} – ${fmt.iso(e.end_date)}`, + e.horizon ? `Horizon ${e.horizon}` : null, + e.growth ? `${e.growth[0].toUpperCase()}${e.growth.slice(1)} windows` : null)), + cell("Region", fmt.int(r.n_cells), "cells", "#/catalogs", lines( + r.name, r.dh ? `${r.dh}° grid` : null, `M ${mag(r.mag_min)} – ${mag(r.mag_max)}`)), + cell("Models", String(m.models.length), "", "#/forecasts", lines(...m.models.map((x) => x.name))), + cell("Tests", String(m.tests.length), "", "#/results", lines(...m.tests.map((x) => x.name))), + )); +} + +function modelsList(m) { + return m.models.map((mod, i) => + el("div", { class: "model-card" }, + el("h4", {}, el("span", { class: "swatch", style: { background: seriesColor(i) } }), mod.name, doiBadge(mod.doi)), + props([ + ["Authors", mod.authors], + ["Type", mod.forecast_class === "CatalogForecastRepository" ? "Catalog-based" : "Gridded"], + ["Forecasts", `${Object.keys(mod.forecasts || {}).length} / ${m.time_windows.length} windows`], + ["Forecast unit", mod.forecast_unit ? `${mod.forecast_unit} years` : null], + ["Source", mod.giturl ? el("a", { href: mod.giturl, target: "_blank", rel: "noopener" }, mod.giturl.replace(/^https?:\/\//, "")) : null], + ["Commit", code(mod.git_hash)], + ["Zenodo", mod.zenodo_id ? el("a", { href: `https://zenodo.org/records/${mod.zenodo_id}`, target: "_blank", rel: "noopener" }, String(mod.zenodo_id)) : null], + ["Path", code(mod.path)], + ["Function", code(mod.func)], + ["Arguments", mod.func_kwargs && Object.keys(mod.func_kwargs).length ? code(mod.func_kwargs) : null], + ["Format", mod.fmt], + ["Note", mod.notes && mod.notes.length ? mod.notes.join("; ") : null], + ]))); +} + +function testsList(m) { + return m.tests.map((t) => + el("div", { class: "model-card" }, + el("h4", {}, t.name, el("span", { class: "note" }, TEST_TYPES[t.type] || t.type || "")), + props([ + ["Function", code(t.func)], + ["Arguments", t.func_kwargs && Object.keys(t.func_kwargs).length ? code(t.func_kwargs) : null], + ["Reference", t.ref_model], + ["Plot", t.plot_func && t.plot_func.length ? code(t.plot_func.join(", ")) : null], + ]))); +} + +function citeBlock(e) { + const c = e.citation; + if (!c) return null; + const box = el("textarea", { class: "cite-box", readonly: true, "aria-label": "Citation" }); + box.value = c.apa; + const copy = el("button", { class: "btn small", onclick: async () => { + try { await navigator.clipboard.writeText(box.value); copy.textContent = "Copied"; } catch (err) { box.select(); copy.textContent = "Press Ctrl+C"; } + setTimeout(() => { copy.textContent = "Copy"; }, 1500); + } }, "Copy"); + const fmtSeg = seg([["apa", "APA"], ["bibtex", "BibTeX"], ["ris", "RIS"]], "apa", (v) => { box.value = c[v] || ""; }); + return panel("Citation", el("div", { class: "stack", style: { gap: "8px" } }, + el("div", { style: { display: "flex", gap: "8px", alignItems: "center" } }, fmtSeg, copy, el("span", { class: "note", style: { marginLeft: "auto" } }, `Source: ${c.source === "DataCite" ? "DataCite" : "experiment metadata"}`)), + box)); +} + +function windowsChart(node, m) { + chart = makeChart(node); + const c = chrome(); + const wins = m.time_windows; + const data = wins.map((w, i) => [new Date(w.start).getTime(), new Date(w.end).getTime(), i, w.label]); + const accent = css("--accent"); + chart.setOption({ + ...c, + grid: { left: 10, right: 18, top: 10, bottom: 30, containLabel: true }, + tooltip: { ...c.tooltip, trigger: "item", formatter: (p) => `Window ${p.data[2] + 1}
${p.data[3].replace(" to ", " – ")}` }, + xAxis: { type: "time", ...axis() }, + yAxis: { type: "category", data: wins.map((_, i) => `${i + 1}`), inverse: true, ...axis(), axisLine: { show: false }, splitLine: { show: false }, axisLabel: { show: wins.length <= 30, color: css("--ink-3") } }, + series: [{ + type: "custom", + renderItem: (params, api) => { + const a = api.coord([api.value(0), api.value(2)]), b = api.coord([api.value(1), api.value(2)]); + const h = Math.max(2, Math.min(14, api.size([0, 1])[1] * 0.6)); + return { type: "rect", shape: { x: a[0], y: a[1] - h / 2, width: Math.max(2, b[0] - a[0]), height: h, r: 2 }, style: { fill: accent, opacity: 0.85 } }; + }, + encode: { x: [0, 1], y: 2 }, + data, + }], + }); +} + +export async function render(root, ctx) { + const m = ctx.manifest, e = m.experiment, r = m.region || {}; + root.append(header(m), flow(m)); + const left = el("div", { class: "span-7 stack" }); + const right = el("div", { class: "span-5 stack" }); + root.append(right, left); + + const mapNode = el("div", { class: "map short" }); + left.append(panel("Testing Region", el("div", {}, mapNode, el("div", { style: { padding: "12px 16px" } }, props([ + ["Name", r.name], + ["Cell size", r.dh ? `${r.dh}°` : null], + ["Magnitudes", `${Number(r.mag_min).toFixed(1)} – ${Number(r.mag_max).toFixed(1)}`], + ["Bin width", r.mag_bin ? `ΔM ${r.mag_bin}` : null], + ["Depth", r.depth_min !== null && r.depth_min !== undefined ? `${r.depth_min} – ${r.depth_max} km` : null], + ]))), { flush: true })); + + const winNode = chartNode("short"); + left.append(panel("Time Windows", el("div", {}, + winNode, + el("div", { style: { padding: "4px 8px 8px" } }, props([ + ["Class", e.exp_class], + ["Start", fmt.iso(e.start_date)], + ["End", fmt.iso(e.end_date)], + ["Horizon", e.horizon], + ["Offset", e.offset], + ["Growth", e.growth ? `${e.growth[0].toUpperCase()}${e.growth.slice(1)}` : null], + ]))), { tight: true })); + + right.append(panel("Models", el("div", { class: "scroll-list" }, modelsList(m)), { sub: m.models.length > 4 ? `${m.models.length} models` : "" })); + right.append(panel("Tests", el("div", { class: "scroll-list" }, testsList(m)), { sub: m.tests.length > 4 ? `${m.tests.length} tests` : "" })); + const cite = citeBlock(e); + if (cite) right.append(cite); + right.append(panel("Run", props([ + ["floatCSEP", e.floatcsep_version], + ["pyCSEP", e.pycsep_version], + ["Last run", e.last_run], + ["Run mode", e.run_mode ? `${e.run_mode[0].toUpperCase()}${e.run_mode.slice(1)}` : null], + ["Results", code(e.run_dir)], + ["Configuration", code(e.config_file)], + ["Models file", code(e.model_config)], + ["Tests file", code(e.test_config)], + ["Catalog file", code(m.catalog && m.catalog.source)], + ["Exported", fmt.iso(m.generated)], + ]))); + + windowsChart(winNode, m); + + map = makeMap(mapNode); + if (r.bbox) map.fitBounds([[r.bbox[1], r.bbox[0]], [r.bbox[3], r.bbox[2]]], { padding: [10, 10] }); + else map.setView([0, 0], 2); + let outline = null, cells = null; + const draw = async () => { + if (!ctx.gridPromise) return; + const g = await ctx.gridPromise; + if (cells) cells.remove(); + if (outline) outline.remove(); + cells = new GridLayer({ fill: css("--accent-soft") }).addTo(map); + cells.setData({ origins: g.origins, dh: g.dh, values: new Float32Array(g.origins.length).fill(1) }); + if (g.outline) outline = L.geoJSON(g.outline, { style: outlineStyle() }).addTo(map); + }; + await draw(); + + onTheme = () => { draw(); disposeChart(chart); windowsChart(winNode, m); }; + window.addEventListener("fc-theme", onTheme); +} + +export function destroy() { + window.removeEventListener("fc-theme", onTheme); + if (map) { map.remove(); map = null; } + disposeChart(chart); + chart = null; +} diff --git a/floatcsep/postprocess/web/static/js/pages/forecasts.js b/floatcsep/postprocess/web/static/js/pages/forecasts.js new file mode 100644 index 0000000..14ec727 --- /dev/null +++ b/floatcsep/postprocess/web/static/js/pages/forecasts.js @@ -0,0 +1,289 @@ +import { el, panel, select, field, fmt, getJSON, makeMap, outlineStyle, css, decodeU16, cellValue, doiBadge, seriesColor, debounce } from "../util.js"; +import { makeChart, disposeChart, chartNode, chrome, axis } from "../charts.js"; +import { GridLayer, drawColorbar } from "../gridlayer.js"; + +let map = null, chart = null, onTheme = null, layer = null, events = null, outline = null; + +async function loadForecast(m, modelId, winId) { + const mod = m.models.find((x) => x.id === modelId); + const rel = mod && mod.forecasts[winId]; + if (!rel) return null; + const raw = await getJSON(rel); + if (!raw._q) { + raw._q = decodeU16(raw.data || ""); + raw.data = ""; + } + return { q: raw._q, nm: raw.mags.length, vmin: raw.vmin, vmax: raw.vmax, mags: raw.mags, totals: raw.totals, n: raw.n_cells, grid: raw.grid }; +} + +/** log10 rate per cell for magnitude bins k0..k1, from the cumulative N(>=M) values. */ +function valuesAt(fc, k0, k1) { + const out = new Float32Array(fc.n); + const finite = []; + const last = k1 >= fc.nm - 1; + for (let i = 0; i < fc.n; i++) { + const a = cellValue(fc, i, k0); + let v = a; + if (!last && Number.isFinite(a)) { + const b = cellValue(fc, i, k1 + 1); + if (Number.isFinite(b)) { + const d = Math.pow(10, a) - Math.pow(10, b); + v = d > 0 ? Math.log10(d) : NaN; + } + } + out[i] = v; + if (Number.isFinite(v)) finite.push(v); + } + finite.sort((a, b) => a - b); + const count = finite.length; + return { values: out, lo: count ? finite[Math.floor(count * 0.01)] : NaN, hi: count ? finite[count - 1] : NaN, count }; +} + +export async function render(root, ctx) { + const m = ctx.manifest, r = m.region || {}; + const models = m.models.filter((x) => Object.keys(x.forecasts || {}).length); + if (!models.length) { + root.append(el("div", { class: "empty span-12" }, "No forecasts were exported for this experiment.")); + return; + } + const grid = ctx.gridPromise ? await ctx.gridPromise : null; + const mags = m.magnitudes || []; + const state = { model: models[0].id, win: Object.keys(models[0].forecasts)[0], k: 0, k1: Math.max(0, mags.length - 1), range: null, lock: false, showCat: true }; + let fc = null, cur = null, catalog = null; + const thr = () => (fc ? fc.mags : mags)[state.k]; + const dm = mags.length > 1 ? +(mags[1] - mags[0]).toFixed(4) : (r.mag_bin || 0.1); + const mtop = () => { + const ms = fc ? fc.mags : mags; + return state.k1 >= ms.length - 1 ? (r.mag_max ?? ms[ms.length - 1] + dm) : ms[state.k1] + dm; + }; + const isTop = () => state.k1 >= (fc ? fc.mags : mags).length - 1; + const magLabel = () => `M ${fmt.num(thr(), 1)} – ${fmt.num(mtop(), 1)}`; + const inRange = (mg) => mg >= thr() - 1e-9 && (isTop() || mg < mtop() - 1e-9); + const windows = m.time_windows; + + // controls + const modelSel = select(models.map((x) => [x.id, x.name]), state.model, (v) => { state.model = v; refresh(); }); + const winSel = select(windows.map((w) => [w.id, w.label]), state.win, (v) => { state.win = v; refresh(); }); + const step = (d) => { + const i = windows.findIndex((w) => w.id === state.win) + d; + if (i >= 0 && i < windows.length) { state.win = windows[i].id; winSel.value = state.win; refresh(); } + }; + const winRow = el("div", { class: "stepper" }, + el("button", { class: "btn", title: "Previous window", "aria-label": "Previous window", onclick: () => step(-1) }, "‹"), winSel, + el("button", { class: "btn", title: "Next window", "aria-label": "Next window", onclick: () => step(1) }, "›")); + const magVal = el("span", { class: "val", style: { minWidth: "7em" } }); + const nmax = Math.max(0, mags.length - 1); + const magLo = el("input", { type: "range", min: 0, max: nmax, step: 1, value: 0, "aria-label": "Minimum magnitude" }); + const magHi = el("input", { type: "range", min: 0, max: nmax, step: 1, value: nmax, "aria-label": "Maximum magnitude" }); + const magFill = el("div", { class: "fill" }); + const magBox = el("div", { class: "drange" }, el("div", { class: "track" }), magFill, magLo, magHi); + const syncMag = () => { + const n = +magLo.max || 1; + magFill.style.left = (state.k / n) * 100 + "%"; + magFill.style.width = ((state.k1 - state.k) / n) * 100 + "%"; + magVal.textContent = magLabel(); + }; + const onMag = (e) => { + let a = +magLo.value, b = +magHi.value; + if (a > b) { if (e.target === magLo) { b = a; magHi.value = b; } else { a = b; magLo.value = a; } } + state.k = a; state.k1 = b; + syncMag(); + draw(); + drawComparison(); + }; + magLo.addEventListener("input", onMag); + magHi.addEventListener("input", onMag); + const magSlider = magBox; + const rangeLo = el("input", { type: "range", min: -10, max: 3, step: 0.05, "aria-label": "Colour scale minimum" }); + const rangeHi = el("input", { type: "range", min: -10, max: 3, step: 0.05, "aria-label": "Colour scale maximum" }); + const rangeLab = el("span", { class: "val", style: { minWidth: "7em" } }); + const onRange = debounce(() => { + let a = +rangeLo.value, b = +rangeHi.value; + if (a >= b) { if (document.activeElement === rangeLo) { b = a + 0.05; rangeHi.value = b; } else { a = b - 0.05; rangeLo.value = a; } } + state.range = [a, b]; + applyRange(); + }, 30); + rangeLo.addEventListener("input", onRange); + rangeHi.addEventListener("input", onRange); + const rangeBox = el("div", { class: "drange" }, el("div", { class: "track" }), el("div", { class: "fill" }), rangeLo, rangeHi); + const fitBtn = el("button", { class: "btn small", onclick: () => { state.range = null; draw(); } }, "Reset scale"); + const lockCb = el("label", { class: "checkbox" }, el("input", { type: "checkbox", onchange: (e) => { state.lock = e.target.checked; } }), "Lock scale"); + const catCb = el("label", { class: "checkbox" }, el("input", { type: "checkbox", checked: true, onchange: (e) => { state.showCat = e.target.checked; drawEvents(); } }), "Show observed events"); + const left = el("div", { class: "span-4 stack" }); + const right = el("div", { class: "span-8 stack" }); + root.append(left, right); + const summary = el("div", { class: "readout", "aria-live": "polite" }); + left.append(panel("Forecast", el("div", { class: "stack", style: { gap: "16px" } }, + el("div", { class: "group" }, field("Model", modelSel), field("Time window", winRow)), + el("div", { class: "group" }, + el("div", { class: "field" }, el("span", {}, "Magnitude range"), el("div", { class: "range" }, magSlider, magVal)), + el("div", { class: "field" }, el("span", {}, "Colour scale, log₁₀ rate per cell"), el("div", { class: "range" }, rangeBox, rangeLab)), + el("div", { class: "row" }, fitBtn, lockCb)), + m.catalog ? el("div", { class: "group" }, catCb) : null, + el("div", { class: "group" }, summary), + ), { class: "rail" })); + const kpis = el("dl", { class: "props" }); + const modelMeta = el("dl", { class: "props" }); + left.append(panel("Forecast Details", el("div", { class: "stack", style: { gap: "12px" } }, modelMeta, kpis))); + + // map + const mapNode = el("div", { class: "map", role: "region", "aria-label": "Forecast map" }); + const tip = el("div", { class: "cell-tip", role: "status" }); + const mapWrap = el("div", { class: "map-wrap" }, mapNode, tip); + const cb = el("canvas", { "aria-hidden": "true" }); + const cbLo = el("span", {}), cbHi = el("span", {}); + const cbBar = el("div", { class: "colorbar" }, el("span", { class: "cb-label" }, "log₁₀ rate per cell"), cbLo, cb, cbHi, el("span", { class: "note", id: "cb-note" })); + right.append(panel("Forecast Map", el("div", {}, mapWrap, cbBar), { flush: true })); + const cmpNode = chartNode(); + right.append(panel("Expected N(≥M) per Model", cmpNode, { tight: true })); + + map = makeMap(mapNode); + if (r.bbox) map.fitBounds([[r.bbox[1], r.bbox[0]], [r.bbox[3], r.bbox[2]]], { padding: [10, 10] }); + layer = new GridLayer().addTo(map); + const drawOutline = () => { + if (outline) outline.remove(); + if (grid && grid.outline) outline = L.geoJSON(grid.outline, { style: { ...outlineStyle(), weight: 1, opacity: 0.6 } }).addTo(map); + }; + drawOutline(); + map.on("mousemove", (e) => { + const hit = layer.valueAt(e.latlng); + if (!hit) { tip.style.display = "none"; return; } + const p = map.latLngToContainerPoint(e.latlng); + tip.style.display = "block"; + tip.style.left = p.x + 14 + "px"; + tip.style.top = p.y + 14 + "px"; + tip.innerHTML = `Rate ${fmt.sci(Math.pow(10, hit.value))}
log₁₀ ${fmt.num(hit.value, 2)}
Cell ${fmt.lon(hit.origin[0])} ${fmt.lat(hit.origin[1])}`; + }); + map.on("mouseout", () => { tip.style.display = "none"; }); + + chart = makeChart(cmpNode); + + function setRangeUI(lo, hi) { + const min = Math.floor(Math.min(lo, fc ? fc.vmin : lo) - 0.5), max = Math.ceil(Math.max(hi, fc ? fc.vmax : hi) + 0.5); + rangeLo.min = rangeHi.min = min; + rangeLo.max = rangeHi.max = max; + rangeLo.value = lo; + rangeHi.value = hi; + const fill = rangeBox.querySelector(".fill"); + fill.style.left = ((lo - min) / (max - min)) * 100 + "%"; + fill.style.width = ((hi - lo) / (max - min)) * 100 + "%"; + rangeLab.textContent = `${fmt.num(lo, 2)} – ${fmt.num(hi, 2)}`; + cbLo.textContent = fmt.num(lo, 1); + cbHi.textContent = fmt.num(hi, 1); + drawColorbar(cb, lo, hi); + } + + function applyRange() { + if (!state.range) return; + layer.setRange(state.range[0], state.range[1]); + setRangeUI(state.range[0], state.range[1]); + } + + function draw() { + if (!fc) return; + cur = valuesAt(fc, state.k, state.k1); + const g = fc.grid === "region" ? grid : fc.grid; + layer.setData({ origins: g.origins, dh: g.dh, values: cur.values }); + if (!state.range || !state.lock) state.range = cur.count ? (cur.hi - cur.lo < 0.05 ? [cur.lo - 0.5, cur.hi + 0.5] : [cur.lo, cur.hi]) : [0, 1]; + if (state.range && state.lock) { /* keep */ } + applyRange(); + const total = fc.totals[state.k] - (isTop() ? 0 : fc.totals[state.k1 + 1] || 0); + const mod = m.models.find((x) => x.id === state.model); + const w = windows.find((x) => x.id === state.win); + const obs = catalog ? countObserved() : null; + summary.replaceChildren(el("table", { class: "mini" }, + el("thead", {}, el("tr", {}, el("th", { scope: "col" }, magLabel()), el("th", { scope: "col" }, "Events"))), + el("tbody", {}, + el("tr", {}, el("td", {}, "Expected"), el("td", {}, fmt.num(total, total >= 100 ? 0 : 2))), + obs !== null ? el("tr", {}, el("td", {}, "Observed"), el("td", {}, String(obs))) : null))); + kpis.replaceChildren(); + for (const [k, v] of [ + ["Active cells", `${fmt.int(cur.count)} / ${fmt.int(fc.n)}`], + ["Max cell rate", cur.count ? fmt.sci(Math.pow(10, cur.hi)) : "–"], + ["Magnitude bins", `${fc.mags.length}`], + ["Forecast unit", mod.forecast_unit ? `${mod.forecast_unit} years` : null], + ]) if (v) kpis.append(el("dt", {}, k), el("dd", {}, v)); + drawEvents(); + } + + function countObserved() { + const wi = windows.findIndex((x) => x.id === state.win), th = thr(); + let n = 0; + for (let i = 0; i < catalog.n; i++) if (catalog.w[i].includes(wi) && inRange(catalog.mag[i])) n++; + return n; + } + + function drawEvents() { + if (events) { events.remove(); events = null; } + if (!state.showCat || !catalog) return; + const wi = windows.findIndex((x) => x.id === state.win), th = thr(); + const canvas = L.canvas({ padding: 0.3 }); + events = L.layerGroup(); + for (let i = 0; i < catalog.n; i++) { + if (!catalog.w[i].includes(wi) || !inRange(catalog.mag[i])) continue; + L.circleMarker([catalog.lat[i], catalog.lon[i]], { renderer: canvas, radius: 3 + Math.max(0, catalog.mag[i] - th) * 1.8, color: "#ffffff", weight: 1.2, fillColor: css("--accent"), fillOpacity: 0.95 }) + .bindPopup(`M ${fmt.num(catalog.mag[i], 1)}
${fmt.datetime(catalog.t[i])} UTC`).addTo(events); + } + events.addTo(map); + } + + async function drawComparison() { + const c = chrome(); + const series = []; + for (const [i, mod] of m.models.entries()) { + const f = await loadForecast(m, mod.id, state.win).catch(() => null); + if (!f) continue; + series.push({ name: mod.name, type: "line", data: f.mags.map((mg, k) => [mg, f.totals[k] > 0 ? f.totals[k] : null]), symbol: "circle", symbolSize: 5, lineStyle: { width: 2, color: seriesColor(i) }, itemStyle: { color: seriesColor(i) }, emphasis: { focus: "series" } }); + } + chart.setOption({ + ...c, + legend: { ...c.legend, data: series.map((s) => s.name) }, + tooltip: { ...c.tooltip, trigger: "axis", valueFormatter: (v) => (v === null ? "0" : fmt.sci(v)) }, + xAxis: { type: "value", name: "Magnitude", nameLocation: "middle", nameGap: 24, min: mags[0], max: mags[mags.length - 1], ...axis() }, + yAxis: { type: "log", logBase: 10, name: "Expected events", ...axis(), minorSplitLine: { show: false } }, + series: [...series, { type: "line", data: [], silent: true, markArea: { silent: true, itemStyle: { color: css("--accent-soft") }, data: [[{ xAxis: thr() }, { xAxis: Math.min(mtop(), mags[mags.length - 1]) }]] } }], + }, true); + } + + function drawModelMeta() { + const mod = m.models.find((x) => x.id === state.model); + modelMeta.replaceChildren(); + const rows = [["Name", mod.name], ["Authors", mod.authors], ["DOI", doiBadge(mod.doi)], ["Type", mod.forecast_class === "CatalogForecastRepository" ? "Catalog-based" : "Gridded"], ["Path", mod.path ? el("code", {}, mod.path) : null], ["Source", mod.giturl ? el("a", { href: mod.giturl, target: "_blank", rel: "noopener" }, mod.giturl.replace(/^https?:\/\//, "")) : null], ["Commit", mod.git_hash ? el("code", {}, mod.git_hash) : null]]; + for (const [k, v] of rows) if (v) modelMeta.append(el("dt", {}, k), el("dd", {}, v)); + } + + async function refresh() { + drawModelMeta(); + document.getElementById("cb-note").textContent = "loading…"; + fc = await loadForecast(m, state.model, state.win).catch((e) => { console.error(e); return null; }); + document.getElementById("cb-note").textContent = ""; + if (!fc) { + layer.setData(null); + summary.replaceChildren("No forecast for this model and window."); kpis.replaceChildren(); + return; + } + if (+magLo.max !== fc.mags.length - 1) { + magLo.max = magHi.max = fc.mags.length - 1; + state.k = Math.min(state.k, fc.mags.length - 1); + state.k1 = fc.mags.length - 1; + magLo.value = state.k; magHi.value = state.k1; + } + syncMag(); + draw(); + drawComparison(); + } + + if (m.catalog && m.catalog.file) getJSON(m.catalog.file).then((c) => { catalog = c.testing; draw(); }); + await refresh(); + + onTheme = () => { map.retheme(); drawOutline(); drawEvents(); drawComparison(); }; + window.addEventListener("fc-theme", onTheme); +} + +export function destroy() { + window.removeEventListener("fc-theme", onTheme); + if (map) { map.remove(); map = null; } + disposeChart(chart); + chart = null; + layer = events = outline = null; +} diff --git a/floatcsep/postprocess/web/static/js/pages/results.js b/floatcsep/postprocess/web/static/js/pages/results.js new file mode 100644 index 0000000..10f79e4 --- /dev/null +++ b/floatcsep/postprocess/web/static/js/pages/results.js @@ -0,0 +1,423 @@ +import { el, panel, seg, select, field, fmt, getJSON, css, seriesColor, poissonPmf, poissonQuantiles, percentile } from "../util.js"; +import { makeChart, disposeChart, chartNode, chrome, axis } from "../charts.js"; + +let charts = [], onTheme = null; + +const TYPE_LABEL = { consistency: "Consistency", comparative: "Comparative", sequential: "Sequential", sequential_comparative: "Sequential comparative", batch: "Batch" }; + +/** Pass/fail of a consistency result at level alpha; null when it cannot be decided. */ +function verdict(rec, alpha) { + const q = rec.quantile; + if (Array.isArray(q)) { + const v = q.filter((x) => typeof x === "number" && Number.isFinite(x)); + if (!v.length) return null; + return Math.min(...v) >= alpha / 2; + } + if (typeof q === "number" && Number.isFinite(q)) return q >= alpha; + return null; +} + +/** [low, q25, median, q75, high] of the test distribution, for the range bars. */ +function rangeOf(rec, alpha) { + if (rec.dist && rec.dist.type === "poisson") { + const lam = rec.dist.params[0]; + const [lo, q25, med, q75, hi] = poissonQuantiles(lam, [alpha / 2, 0.25, 0.5, 0.75, 1 - alpha / 2]); + return { lo, q25, med, q75, hi, twoSided: true, lambda: lam }; + } + if (rec.dist_q) { + const [p2, p5, q25, med, q75, p95, p97] = rec.dist_q; + const twoSided = Array.isArray(rec.quantile); + return twoSided ? { lo: p2, q25, med, q75, hi: p97, twoSided } : { lo: p5, q25, med, q75, hi: Math.max(p97, med), twoSided, oneSided: true }; + } + return null; +} + +export async function render(root, ctx) { + const m = ctx.manifest; + if (!m.results || !m.results.index) { + root.append(el("div", { class: "empty span-12" }, "No results were exported for this experiment.")); + return; + } + const index = await getJSON(m.results.index); + const windows = m.time_windows, models = m.models; + const mName = Object.fromEntries(models.map((x) => [x.id, x.name])); + const mIdx = Object.fromEntries(models.map((x, i) => [x.id, i])); + const wIdx = Object.fromEntries(windows.map((w, i) => [w.id, i])); + const tests = m.tests.filter((t) => index.some((r) => r.test === t.id)); + if (!tests.length) { + root.append(el("div", { class: "empty span-12" }, "The results folder has no evaluation files yet.")); + return; + } + const state = { test: tests[0].id, win: windows[windows.length - 1].id, alpha: 0.05, view: "window", figure: false, pick: null }; + const testOf = () => tests.find((t) => t.id === state.test); + const recs = () => index.filter((r) => r.test === state.test); + const winRecs = () => recs().filter((r) => r.window === state.win); + + // controls + const testSel = select(tests.map((t) => [t.id, t.name]), state.test, (v) => { state.test = v; state.pick = null; update(); }); + const winSel = select(windows.map((w) => [w.id, w.label]), state.win, (v) => { state.win = v; update(); }); + const step = (d) => { const i = wIdx[state.win] + d; if (i >= 0 && i < windows.length) { state.win = windows[i].id; winSel.value = state.win; update(); } }; + const winRow = el("div", { class: "stepper" }, el("button", { class: "btn", onclick: () => step(-1), title: "Previous window", "aria-label": "Previous window" }, "‹"), winSel, el("button", { class: "btn", onclick: () => step(1), title: "Next window", "aria-label": "Next window" }, "›")); + const viewSeg = seg([["window", "Single window"], ["time", "All windows"]], state.view, (v) => { state.view = v; update(); }, false); + const alphaSel = select([["0.01", "0.01"], ["0.05", "0.05"], ["0.1", "0.10"]], "0.05", (v) => { state.alpha = +v; update(); }); + const figCb = el("label", { class: "checkbox" }, el("input", { type: "checkbox", onchange: (e) => { state.figure = e.target.checked; update(); } }), "Show pyCSEP figure"); + const winField = field("Time window", winRow); + const left = el("div", { class: "span-4 stack" }); + const right = el("div", { class: "span-8 stack" }); + root.append(left, right); + left.append(panel("Tests", el("div", { class: "stack", style: { gap: "16px" } }, + el("div", { class: "group" }, field("Test", testSel), windows.length > 1 ? field("Show", viewSeg) : null, winField), + el("div", { class: "group" }, field("Significance level α", alphaSel), m.figures ? figCb : null), + ), { class: "rail" })); + const tableWrap = el("div", { class: "table-scroll" }); + left.append(panel("Scores", tableWrap, { flush: true })); + const testInfo = el("dl", { class: "props" }); + left.append(panel("Test Definition", testInfo)); + + const mainNode = chartNode("tall"); + const mainPanel = panel("", mainNode, { tight: true }); + const mainTitle = mainPanel.querySelector("h2"); + const mainSub = el("span", { class: "sub" }); + mainPanel.querySelector(".panel-head").append(mainSub); + right.append(mainPanel); + const detailNode = chartNode(); + const detailPanel = panel("Test Distribution", detailNode, { tight: true }); + const detailSub = el("span", { class: "sub" }); + detailPanel.querySelector(".panel-head").append(detailSub); + right.append(detailPanel); + const figPanel = panel("pyCSEP Figure", el("div", { class: "fig-body" }), {}); + right.append(figPanel); + const legend = el("div", { class: "legend", style: { padding: "0 14px 10px" } }); + mainPanel.append(legend); + + const main = makeChart(mainNode), detail = makeChart(detailNode); + charts = [main, detail]; + + function testInfoDraw() { + const t = testOf(); + testInfo.replaceChildren(); + for (const [k, v] of [["Type", TYPE_LABEL[t.type] || t.type], ["Function", t.func ? el("code", {}, t.func) : null], ["Reference", t.ref_model], ["Arguments", t.func_kwargs && Object.keys(t.func_kwargs).length ? el("code", {}, JSON.stringify(t.func_kwargs)) : null]]) { + if (v) testInfo.append(el("dt", {}, k), el("dd", {}, v)); + } + } + + function statusEl(ok) { + return el("span", { class: "status " + (ok === null ? "na" : ok ? "pass" : "fail") }, ok === null ? "–" : ok ? "Pass" : "Fail"); + } + + function consistencyWindow(t) { + const rows = winRecs().sort((a, b) => mIdx[a.model] - mIdx[b.model]); + const c = chrome(); + const cats = rows.map((r) => mName[r.model]); + const ranges = rows.map((r) => rangeOf(r, state.alpha)); + const ok = rows.map((r) => verdict(r, state.alpha)); + const good = css("--good"), bad = css("--bad"), ink2 = css("--ink-2"), ink3 = css("--ink-3"); + const whisker = rows.map((r, i) => ranges[i] ? [ranges[i].lo, ranges[i].hi, i] : null).filter(Boolean); + const box = rows.map((r, i) => ranges[i] ? [ranges[i].q25, ranges[i].q75, i] : null).filter(Boolean); + const obs = rows.map((r, i) => ({ value: [r.observed_statistic, i], itemStyle: { color: ok[i] === null ? ink3 : ok[i] ? good : bad } })); + const oneSided = ranges.some((x) => x && x.oneSided); + mainTitle.textContent = t.name; + mainSub.textContent = `Window ${wIdx[state.win] + 1}: ${windows[wIdx[state.win]].label.replace(" to ", " – ")}`; + main.setOption({ + ...c, + legend: { show: false }, + grid: { left: 10, right: 24, top: 16, bottom: 40, containLabel: true }, + tooltip: { ...c.tooltip, trigger: "item", formatter: (p) => { + const i = p.data.value ? p.data.value[1] : p.data[2]; + const r = rows[i], g = ranges[i]; + const q = Array.isArray(r.quantile) ? r.quantile.map((x) => fmt.num(x, 3)).join(" / ") : fmt.num(r.quantile, 3); + return `${mName[r.model]}
Observed ${fmt.num(r.observed_statistic, 2)}
Quantile ${q}` + (g ? `
${Math.round(100 * (1 - state.alpha))}% interval ${fmt.num(g.lo, 2)} – ${fmt.num(g.hi, 2)}` : ""); + } }, + xAxis: { type: "value", ...axis(), scale: true }, + yAxis: { type: "category", data: cats, inverse: true, ...axis(), axisLine: { show: false }, splitLine: { show: false }, axisLabel: { ...axis().axisLabel, color: css("--ink") } }, + series: [ + { type: "custom", name: "range", data: whisker, encode: { x: [0, 1], y: 2 }, renderItem: (p, api) => { + const a = api.coord([api.value(0), api.value(2)]), b = api.coord([api.value(1), api.value(2)]); + return { type: "group", children: [ + { type: "line", shape: { x1: a[0], y1: a[1], x2: b[0], y2: b[1] }, style: { stroke: ink2, lineWidth: 1.5 } }, + { type: "line", shape: { x1: a[0], y1: a[1] - 6, x2: a[0], y2: a[1] + 6 }, style: { stroke: ink2, lineWidth: 1.5 } }, + { type: "line", shape: { x1: b[0], y1: b[1] - 6, x2: b[0], y2: b[1] + 6 }, style: { stroke: ink2, lineWidth: 1.5 } }, + ] }; + } }, + { type: "custom", name: "iqr", data: box, encode: { x: [0, 1], y: 2 }, renderItem: (p, api) => { + const a = api.coord([api.value(0), api.value(2)]), b = api.coord([api.value(1), api.value(2)]); + return { type: "rect", shape: { x: a[0], y: a[1] - 4, width: Math.max(1, b[0] - a[0]), height: 8, r: 2 }, style: { fill: ink2, opacity: 0.45 } }; + } }, + { type: "scatter", name: "observed", data: obs, symbolSize: 12, itemStyle: { borderColor: css("--surface"), borderWidth: 1.5 }, z: 10 }, + ], + }, true); + legend.replaceChildren( + el("span", {}, el("i", { class: "swatch", style: { background: good, borderRadius: "50%" } }), "Pass"), + el("span", {}, el("i", { class: "swatch", style: { background: bad, borderRadius: "50%" } }), "Fail"), + el("span", {}, el("i", { class: "swatch", style: { background: ink2, opacity: 0.45, width: "16px" } }), "50% interval"), + el("span", {}, el("i", { class: "swatch", style: { background: ink2, height: "2px", width: "16px" } }), oneSided ? `${Math.round(100 * (1 - state.alpha))}% interval, one-sided` : `${Math.round(100 * (1 - state.alpha))}% interval`), + ); + main.off("click"); + main.on("click", (p) => { const i = p.data.value ? p.data.value[1] : p.data[2]; state.pick = rows[i] && rows[i].model; detailDraw(); }); + table(rows.map((r, i) => [mName[r.model], fmt.num(r.observed_statistic, 2), Array.isArray(r.quantile) ? r.quantile.map((x) => fmt.num(x, 3)).join(" / ") : fmt.num(r.quantile, 3), statusEl(ok[i])]), ["Model", "Statistic", "Quantile", "Result"], rows.map((r) => r.model)); + if (!state.pick || !rows.some((r) => r.model === state.pick)) state.pick = rows.length ? rows[0].model : null; + } + + async function detailDraw() { + const t = testOf(); + const rec = winRecs().find((r) => r.model === state.pick); + if (!rec || t.type !== "consistency" || state.view !== "window") { detailPanel.style.display = "none"; return; } + detailPanel.style.display = ""; + const c = chrome(); + const ok = verdict(rec, state.alpha); + const obsColor = ok === null ? css("--ink-3") : ok ? css("--good") : css("--bad"); + detailSub.textContent = mName[rec.model]; + let xs = [], ys = [], xType = "category", yName = ""; + if (rec.dist && rec.dist.type === "poisson") { + const lam = rec.dist.params[0]; + const kmax = Math.ceil(Math.max(lam + 4 * Math.sqrt(lam) + 5, rec.observed_statistic + 2)); + const pmf = poissonPmf(lam, kmax); + xs = pmf.map((_, k) => k); + ys = pmf; + yName = "Probability"; + } else if (rec.dist_file) { + const d = await getJSON(rec.dist_file); + const vals = d.test_distribution.filter((v) => typeof v === "number" && Number.isFinite(v)).sort((a, b) => a - b); + const lo = Math.min(vals[0], rec.observed_statistic), hi = Math.max(vals[vals.length - 1], rec.observed_statistic); + const nb = Math.min(60, Math.max(15, Math.round(Math.sqrt(vals.length)))); + const w = (hi - lo) / nb || 1; + const counts = new Array(nb).fill(0); + for (const v of vals) counts[Math.min(nb - 1, Math.floor((v - lo) / w))]++; + xs = counts.map((_, i) => +(lo + (i + 0.5) * w).toFixed(4)); + ys = counts; + yName = "Simulations"; + } else { detailPanel.style.display = "none"; return; } + const obsIdx = xs.reduce((best, x, i) => (Math.abs(x - rec.observed_statistic) < Math.abs(xs[best] - rec.observed_statistic) ? i : best), 0); + detail.setOption({ + ...c, + legend: { show: false }, + grid: { ...c.grid, left: 56 }, + tooltip: { ...c.tooltip, trigger: "axis", valueFormatter: (v) => fmt.num(v, yName === "Probability" ? 4 : 0) }, + xAxis: { type: "category", data: xs.map((x) => (typeof x === "number" ? fmt.num(x, yName === "Probability" ? 0 : 1) : x)), name: "Statistic", nameLocation: "middle", nameGap: 24, ...axis(), axisLabel: { ...axis().axisLabel, interval: Math.max(0, Math.ceil(xs.length / 12) - 1) } }, + yAxis: { type: "value", name: yName, ...axis() }, + series: [{ + type: "bar", data: ys, barCategoryGap: "10%", itemStyle: { color: css("--series-1"), borderRadius: [2, 2, 0, 0] }, + markLine: { silent: true, symbol: "none", lineStyle: { color: obsColor, width: 2 }, label: { color: obsColor, formatter: `Observed ${fmt.num(rec.observed_statistic, 2)}`, position: "insideEndTop", rotate: 0, distance: [0, 4] }, data: [{ xAxis: obsIdx }] }, + }], + }, true); + } + + function consistencyTime(t) { + const c = chrome(); + const rows = recs(); + const series = models.map((mod, i) => { + const data = windows.map((w) => { + const r = rows.find((x) => x.model === mod.id && x.window === w.id); + if (!r) return null; + const q = Array.isArray(r.quantile) ? Math.min(...r.quantile.filter((x) => Number.isFinite(x))) : r.quantile; + return Number.isFinite(q) ? q : null; + }); + return data.some((v) => v !== null) ? { name: mod.name, type: "line", data, symbol: "circle", symbolSize: 7, lineStyle: { width: 2, color: seriesColor(i) }, itemStyle: { color: seriesColor(i) }, connectNulls: false, emphasis: { focus: "series" } } : null; + }).filter(Boolean); + mainTitle.textContent = `${t.name} Quantile Score`; + const twoSided = rows.some((r) => Array.isArray(r.quantile)); + const thr = twoSided ? state.alpha / 2 : state.alpha; + mainSub.textContent = twoSided ? "Lower of the two quantiles. Dashed line at α/2" : "Dashed line at α"; + main.setOption({ + ...c, + legend: { ...c.legend, data: series.map((s) => s.name) }, + grid: { ...c.grid, top: 36, bottom: windows.length > 6 ? 70 : 40 }, + tooltip: { ...c.tooltip, trigger: "axis", valueFormatter: (v) => (v === null ? "–" : fmt.num(v, 3)) }, + xAxis: { type: "category", data: windows.map((w) => (windows.length > 12 ? w.end.slice(0, 10) : w.label)), ...axis(), axisLabel: { ...axis().axisLabel, rotate: windows.length > 6 ? 30 : 0, interval: windows.length > 30 ? Math.ceil(windows.length / 15) : 0 } }, + yAxis: { type: "value", name: "Quantile", min: 0, max: 1, ...axis() }, + series: [...series, { type: "line", name: "α", data: [], markLine: { silent: true, symbol: "none", lineStyle: { color: css("--bad"), type: "dashed" }, label: { color: css("--bad"), formatter: twoSided ? `α/2 = ${thr}` : `α = ${thr}` }, data: [{ yAxis: thr }] } }], + }, true); + legend.replaceChildren(); + main.off("click"); + table(windows.map((w, j) => [`${j + 1}`, ...models.map((mod) => { const r = rows.find((x) => x.model === mod.id && x.window === w.id); return r ? statusEl(verdict(r, state.alpha)) : "–"; })]), ["Window", ...models.map((x) => x.name)]); + } + + function comparativeWindow(t) { + const rows = winRecs().sort((a, b) => mIdx[a.model] - mIdx[b.model]); + const c = chrome(); + const good = css("--good"), bad = css("--bad"), ink2 = css("--ink-2"), ink3 = css("--ink-3"); + const sig = (r) => (r.ci && Number.isFinite(r.ci[0]) && Number.isFinite(r.ci[1]) ? (r.ci[0] > 0 ? 1 : r.ci[1] < 0 ? -1 : 0) : null); + mainTitle.textContent = t.name; + mainSub.textContent = `Window ${wIdx[state.win] + 1}. Reference ${t.ref_model || "–"}`; + main.setOption({ + ...c, + legend: { show: false }, + grid: { left: 10, right: 24, top: 16, bottom: 40, containLabel: true }, + tooltip: { ...c.tooltip, trigger: "item", formatter: (p) => { const r = rows[p.data.value ? p.data.value[1] : p.data[2]]; return `${mName[r.model]}
IG ${fmt.num(r.observed_statistic, 3)}` + (r.ci ? `
${Math.round(100 * (1 - state.alpha))}% CI ${fmt.num(r.ci[0], 3)} – ${fmt.num(r.ci[1], 3)}` : ""); } }, + xAxis: { type: "value", name: "Information gain per event", nameLocation: "middle", nameGap: 26, ...axis(), scale: true }, + yAxis: { type: "category", data: rows.map((r) => mName[r.model] + (mName[r.model] === t.ref_model ? " (ref)" : "")), inverse: true, ...axis(), axisLine: { show: false }, splitLine: { show: false }, axisLabel: { ...axis().axisLabel, color: css("--ink") } }, + series: [ + { type: "custom", data: rows.map((r, i) => (r.ci && Number.isFinite(r.ci[0]) && Number.isFinite(r.ci[1]) ? [r.ci[0], r.ci[1], i] : null)).filter(Boolean), encode: { x: [0, 1], y: 2 }, renderItem: (p, api) => { + const a = api.coord([api.value(0), api.value(2)]), b = api.coord([api.value(1), api.value(2)]); + return { type: "group", children: [ + { type: "line", shape: { x1: a[0], y1: a[1], x2: b[0], y2: b[1] }, style: { stroke: ink2, lineWidth: 1.5 } }, + { type: "line", shape: { x1: a[0], y1: a[1] - 6, x2: a[0], y2: a[1] + 6 }, style: { stroke: ink2, lineWidth: 1.5 } }, + { type: "line", shape: { x1: b[0], y1: b[1] - 6, x2: b[0], y2: b[1] + 6 }, style: { stroke: ink2, lineWidth: 1.5 } }, + ] }; + } }, + { type: "scatter", data: rows.map((r, i) => ({ value: [Number.isFinite(r.observed_statistic) ? r.observed_statistic : null, i], itemStyle: { color: sig(r) === 1 ? good : sig(r) === -1 ? bad : sig(r) === 0 ? ink2 : ink3 } })), symbolSize: 12, itemStyle: { borderColor: css("--surface"), borderWidth: 1.5 }, z: 10, + markLine: { silent: true, symbol: "none", lineStyle: { color: ink3, type: "dashed" }, data: [{ xAxis: 0 }] } }, + ], + }, true); + legend.replaceChildren( + el("span", {}, el("i", { class: "swatch", style: { background: good, borderRadius: "50%" } }), "Better than reference"), + el("span", {}, el("i", { class: "swatch", style: { background: bad, borderRadius: "50%" } }), "Worse than reference"), + el("span", {}, el("i", { class: "swatch", style: { background: ink2, borderRadius: "50%" } }), "No significant difference"), + el("span", {}, el("i", { class: "swatch", style: { background: ink2, height: "2px", width: "16px" } }), `${Math.round(100 * (1 - state.alpha))}% confidence interval`), + ); + main.off("click"); + table(rows.map((r) => [mName[r.model], fmt.num(r.observed_statistic, 3), r.ci ? `${fmt.num(r.ci[0], 3)} – ${fmt.num(r.ci[1], 3)}` : "–", sig(r) === 1 ? el("span", { class: "status pass" }, "Better") : sig(r) === -1 ? el("span", { class: "status fail" }, "Worse") : el("span", { class: "status na" }, sig(r) === 0 ? "Equal" : "–")]), ["Model", "IG", "CI", "Result"]); + } + + function linesOverWindows(t, title, sub, valueOf, yName) { + const c = chrome(); + const series = models.map((mod, i) => { + const data = windows.map((w) => valueOf(mod.id, w.id)); + return data.some((v) => v !== null && v !== undefined) ? { name: mod.name, type: "line", data, symbol: "circle", symbolSize: 6, lineStyle: { width: 2, color: seriesColor(i) }, itemStyle: { color: seriesColor(i) }, emphasis: { focus: "series" } } : null; + }).filter(Boolean); + mainTitle.textContent = title; + mainSub.textContent = sub; + main.setOption({ + ...c, + legend: { ...c.legend, data: series.map((s) => s.name) }, + grid: { ...c.grid, top: 36, bottom: windows.length > 6 ? 70 : 40, left: 64 }, + tooltip: { ...c.tooltip, trigger: "axis", valueFormatter: (v) => (v === null || v === undefined ? "–" : fmt.num(v, 3)) }, + xAxis: { type: "category", data: windows.map((w) => (windows.length > 12 ? w.end.slice(0, 10) : w.label)), ...axis(), axisLabel: { ...axis().axisLabel, rotate: windows.length > 6 ? 30 : 0, interval: windows.length > 30 ? Math.ceil(windows.length / 15) : 0 } }, + yAxis: { type: "value", name: yName, scale: true, ...axis() }, + series: [...series, { type: "line", data: [], markLine: { silent: true, symbol: "none", lineStyle: { color: css("--ink-3"), type: "dashed" }, data: [{ yAxis: 0 }] } }], + }, true); + legend.replaceChildren(); + main.off("click"); + table(windows.map((w, j) => [`${j + 1}`, ...models.map((mod) => fmt.num(valueOf(mod.id, w.id), 2))]), ["Window", ...models.map((x) => x.name)]); + } + + function sequential(t) { + const rows = recs(); + const best = {}; + for (const r of rows) { + const n = Array.isArray(r.observed_statistic) ? r.observed_statistic.length : 0; + if (!best[r.model] || n > best[r.model].n) best[r.model] = { n, r }; + } + const valueOf = (mid, wid) => { const b = best[mid]; const i = wIdx[wid]; const v = b && b.r.observed_statistic[i]; return Number.isFinite(v) ? v : null; }; + linesOverWindows(t, t.type === "sequential_comparative" ? "Cumulative Information Gain" : "Cumulative Log-Likelihood", t.ref_model ? `Reference ${t.ref_model}` : t.name, valueOf, t.type === "sequential_comparative" ? "Information gain" : "Log-likelihood"); + } + + function batch(t) { + const rows = winRecs().filter((r) => Array.isArray(r.observed_statistic)); + const refs = t.ref_models && t.ref_models.length ? t.ref_models : models.map((x) => x.name); + if (!rows.length) { generic(t); return; } + const score = (r) => r.observed_statistic.filter(Number.isFinite).reduce((a, b) => a + b, 0) / r.observed_statistic.length; + rows.sort((a, b) => score(b) - score(a)); + const yNames = rows.map((r) => mName[r.model]); + const cells = []; + let amax = 0; + rows.forEach((r, yi) => { + const tq = Array.isArray(r.quantile) ? r.quantile[0] || [] : []; + const wq = Array.isArray(r.quantile) ? r.quantile[1] || [] : []; + r.observed_statistic.forEach((v, xi) => { + if (!Number.isFinite(v) || mName[r.model] === refs[xi]) return; + amax = Math.max(amax, Math.abs(v)); + cells.push({ xi, yi, v, t: Number.isFinite(tq[xi]) && tq[xi] > 0, w: Number.isFinite(wq[xi]) && wq[xi] < state.alpha }); + }); + }); + amax = amax || 1; + const pos = css("--series-1"), neg = css("--series-8"), mid = css("--surface-2"), ink = css("--ink"); + const mix = (v) => { + const f = Math.min(1, Math.abs(v) / amax); + return { color: v >= 0 ? pos : neg, opacity: 0.15 + 0.85 * f }; + }; + mainTitle.textContent = t.name; + mainSub.textContent = `Window ${wIdx[state.win] + 1}. Information gain of each model (row) over each reference (column)`; + const c = chrome(); + main.setOption({ + ...c, + legend: { show: false }, + grid: { left: 10, right: 20, top: 10, bottom: 60, containLabel: true }, + tooltip: { ...c.tooltip, trigger: "item", formatter: (p) => { + const d = cells[p.dataIndex]; + return `${yNames[d.yi]} over ${refs[d.xi]}
IG ${fmt.num(d.v, 3)}
T-test ${d.t ? "significant" : "not significant"}
W-test ${d.w ? "significant" : "not significant"}`; + } }, + xAxis: { type: "category", data: refs, ...axis(), splitLine: { show: false }, axisLabel: { ...axis().axisLabel, rotate: refs.length > 5 ? 30 : 0, interval: 0 } }, + yAxis: { type: "category", data: yNames, inverse: true, ...axis(), splitLine: { show: false }, axisLabel: { ...axis().axisLabel, color: ink } }, + series: [{ + type: "custom", + data: cells.map((d) => [d.xi, d.yi, d.v]), + renderItem: (params, api) => { + const d = cells[params.dataIndex]; + const p = api.coord([d.xi, d.yi]); + const sz = api.size([1, 1]); + const w = sz[0] - 3, h = sz[1] - 3; + const st = mix(d.v); + const kids = [{ type: "rect", shape: { x: p[0] - w / 2, y: p[1] - h / 2, width: w, height: h, r: 3 }, style: { fill: st.color, opacity: st.opacity } }]; + if (d.t) kids.push({ type: "rect", shape: { x: p[0] - w / 2 + 1, y: p[1] - h / 2 + 1, width: w - 2, height: h - 2, r: 3 }, style: { fill: "none", stroke: ink, lineWidth: 2 } }); + kids.push({ type: "text", style: { x: p[0], y: p[1], text: fmt.num(d.v, 2) + (d.w ? "" : "*"), fill: ink, align: "center", verticalAlign: "middle", fontSize: 12, fontWeight: d.t ? 700 : 400 } }); + return { type: "group", children: kids }; + }, + }], + }, true); + legend.replaceChildren( + el("span", {}, el("i", { class: "swatch", style: { background: pos } }), "Row model better"), + el("span", {}, el("i", { class: "swatch", style: { background: neg } }), "Reference better"), + el("span", {}, el("i", { class: "swatch", style: { background: "transparent", border: `2px solid ${ink}` } }), "T-test significant"), + el("span", {}, "* W-test not significant"), + ); + main.off("click"); + table(rows.map((r) => [mName[r.model], fmt.num(score(r), 3)]), ["Model", "Mean IG"]); + } + + function generic(t) { + const rows = winRecs(); + mainTitle.textContent = t.name; + mainSub.textContent = "No interactive plot for this test type"; + main.clear(); + legend.replaceChildren(); + table(rows.map((r) => [mName[r.model], Array.isArray(r.observed_statistic) ? r.observed_statistic.map((v) => fmt.num(v, 2)).join(", ") : fmt.num(r.observed_statistic, 3), Array.isArray(r.quantile) ? r.quantile.map((v) => fmt.num(v, 3)).join(", ") : fmt.num(r.quantile, 3), r.status || ""]), ["Model", "Statistic", "Quantile", "Status"]); + } + + function table(rows, header, keys) { + const body = el("tbody", {}, rows.map((r, i) => el("tr", { class: keys ? "clickable" + (keys[i] === state.pick ? " selected" : "") : "", onclick: keys ? () => { state.pick = keys[i]; detailDraw(); table(rows, header, keys); } : null }, + r.map((v, j) => el("td", { class: j > 0 && typeof v === "string" && /^[-–\d]/.test(v) ? "num" : "" }, v))))); + tableWrap.replaceChildren(el("table", { class: "data" }, el("thead", {}, el("tr", {}, header.map((h, j) => el("th", { class: j > 0 ? "num" : "" }, h)))), body)); + } + + function figureDraw() { + const body = figPanel.querySelector(".fig-body"); + body.replaceChildren(); + if (!state.figure || !m.figures) { figPanel.style.display = "none"; return; } + const wf = (m.figures.windows || {})[state.win] || {}; + const srcs = []; + if (wf.tests && wf.tests[state.test]) srcs.push([`${testOf().name}`, wf.tests[state.test]]); + for (const mod of models) if (wf.tests && wf.tests[`${state.test}:${mod.id}`]) srcs.push([mod.name, wf.tests[`${state.test}:${mod.id}`]]); + if (!srcs.length) { body.append(el("div", { class: "empty" }, "No figure for this test and window.")); figPanel.style.display = ""; return; } + body.append(...srcs.map(([label, src]) => el("figure", { style: { margin: "0 0 10px" } }, el("img", { class: "figure", src, alt: label }), el("figcaption", { class: "note", style: { textAlign: "center" } }, label)))); + figPanel.style.display = ""; + } + + function update() { + const t = testOf(); + testInfoDraw(); + const seqLike = t.type === "sequential" || t.type === "sequential_comparative"; + const single = seqLike || t.type === "batch"; + winField.style.display = seqLike || (state.view === "time" && t.type !== "batch") ? "none" : ""; + if (viewSeg.parentElement) viewSeg.parentElement.style.display = single ? "none" : ""; + if (seqLike) sequential(t); + else if (t.type === "consistency") (state.view === "time" && windows.length > 1 ? consistencyTime : consistencyWindow)(t); + else if (t.type === "comparative") { + if (state.view === "time" && windows.length > 1) linesOverWindows(t, "Information Gain per Window", `Reference ${t.ref_model || "–"}`, (mid, wid) => { const r = recs().find((x) => x.model === mid && x.window === wid); return r && Number.isFinite(r.observed_statistic) ? r.observed_statistic : null; }, "Information gain"); + else comparativeWindow(t); + } else if (t.type === "batch") batch(t); + else generic(t); + detailDraw(); + figureDraw(); + } + update(); + + onTheme = () => update(); + window.addEventListener("fc-theme", onTheme); +} + +export function destroy() { + window.removeEventListener("fc-theme", onTheme); + charts.forEach(disposeChart); + charts = []; +} diff --git a/floatcsep/postprocess/web/static/js/util.js b/floatcsep/postprocess/web/static/js/util.js new file mode 100644 index 0000000..4b303cc --- /dev/null +++ b/floatcsep/postprocess/web/static/js/util.js @@ -0,0 +1,230 @@ +const cache = new Map(); + +export async function getJSON(url) { + if (cache.has(url)) return cache.get(url); + const p = fetch(url).then((r) => { + if (!r.ok) throw new Error(`${r.status} ${url}`); + return r.json(); + }); + cache.set(url, p); + try { + return await p; + } catch (e) { + cache.delete(url); + throw e; + } +} + +// DOM +export function el(tag, attrs = {}, ...children) { + const n = document.createElement(tag); + for (const [k, v] of Object.entries(attrs)) { + if (v === null || v === undefined || v === false) continue; + if (k === "class") n.className = v; + else if (k === "html") n.innerHTML = v; + else if (k.startsWith("on")) n.addEventListener(k.slice(2), v); + else if (k === "style" && typeof v === "object") Object.assign(n.style, v); + else n.setAttribute(k, v === true ? "" : v); + } + for (const c of children.flat()) { + if (c === null || c === undefined || c === false) continue; + n.append(c.nodeType ? c : document.createTextNode(String(c))); + } + return n; +} + +export function panel(title, body, opts = {}) { + const head = el("div", { class: "panel-head" }, el("h2", {}, title)); + if (opts.sub) head.append(el("span", { class: "sub" }, opts.sub)); + if (opts.right) head.append(el("div", { class: "right" }, opts.right)); + const bodyEl = el("div", { class: "panel-body" + (opts.flush ? " flush" : "") + (opts.tight ? " tight" : "") }, body); + return el("section", { class: "panel " + (opts.class || "") }, head, bodyEl); +} + +export function seg(options, value, onChange, small = true) { + const box = el("div", { class: "seg" + (small ? " small" : ""), role: "group" }); + const set = (v) => { + for (const b of box.children) b.setAttribute("aria-pressed", String(b.dataset.v === String(v))); + }; + for (const o of options) { + const [v, label] = Array.isArray(o) ? o : [o, o]; + box.append( + el("button", { "data-v": String(v), type: "button", "aria-pressed": String(v === value), onclick: () => { set(v); onChange(v); } }, label) + ); + } + box.set = set; + return box; +} + +export function select(options, value, onChange) { + const s = el("select", { onchange: () => onChange(s.value) }); + for (const o of options) { + const [v, label] = Array.isArray(o) ? o : [o, o]; + s.append(el("option", { value: v, selected: String(v) === String(value) }, label)); + } + return s; +} + +export function field(label, control) { + return el("label", { class: "field" }, el("span", {}, label), control); +} + +// theme +export function css(name) { + return getComputedStyle(document.documentElement).getPropertyValue(name).trim(); +} +export function isDark() { + const t = document.documentElement.getAttribute("data-theme"); + if (t) return t === "dark"; + return window.matchMedia("(prefers-color-scheme: dark)").matches; +} +export function seriesColor(i) { + return css(`--series-${(i % 10) + 1}`); +} + +// formatting +export const fmt = { + int: (v) => (v === null || v === undefined || Number.isNaN(v) ? "–" : Math.round(v).toLocaleString("en")), + num: (v, d = 2) => (v === null || v === undefined || !Number.isFinite(v) ? "–" : Number(v).toFixed(d)), + sci: (v) => { + if (v === null || v === undefined || !Number.isFinite(v)) return "–"; + const a = Math.abs(v); + if (a === 0) return "0"; + if (a >= 1000 || a < 0.01) return v.toExponential(2); + return v.toFixed(a < 1 ? 3 : 2); + }, + date: (ms) => new Date(ms).toISOString().slice(0, 10), + lat: (v) => `${Math.abs(v).toFixed(3)}°${v >= 0 ? "N" : "S"}`, + lon: (v) => `${Math.abs(v).toFixed(3)}°${v >= 0 ? "E" : "W"}`, + datetime: (ms) => new Date(ms).toISOString().slice(0, 16).replace("T", " "), + iso: (s) => (s ? String(s).slice(0, 10) : "–"), +}; + +export function doiBadge(doi, text = false) { + if (!doi) return null; + doi = String(doi).replace(/^https?:\/\/(dx\.)?doi\.org\//, "").trim(); + const a = el("a", { class: text ? "doi" : "", href: `https://doi.org/${doi}`, target: "_blank", rel: "noopener", title: `doi:${doi}` }); + if (text) { a.textContent = doi; return a; } + const img = el("img", { src: `https://zenodo.org/badge/DOI/${doi}.svg`, alt: `DOI ${doi}`, style: { height: "20px", verticalAlign: "middle" } }); + img.addEventListener("error", () => { a.className = "doi"; a.replaceChildren(doi); }); + a.append(img); + return a; +} + +// stats +export function percentile(sorted, p) { + if (!sorted.length) return NaN; + const i = (sorted.length - 1) * p; + const lo = Math.floor(i), hi = Math.ceil(i); + return sorted[lo] + (sorted[hi] - sorted[lo]) * (i - lo); +} +export function poissonPmf(lambda, kmax) { + const out = new Array(kmax + 1); + let p = Math.exp(-lambda); + out[0] = p; + for (let k = 1; k <= kmax; k++) { + p *= lambda / k; + out[k] = p; + } + return out; +} +export function poissonQuantiles(lambda, probs) { + const kmax = Math.ceil(lambda + 10 * Math.sqrt(lambda) + 20); + const pmf = poissonPmf(lambda, kmax); + const out = probs.map(() => kmax); + let c = 0; + for (let k = 0; k <= kmax; k++) { + c += pmf[k]; + probs.forEach((p, i) => { if (out[i] === kmax && c >= p) out[i] = k; }); + } + return out; +} + +// forecast decoding +export function decodeU16(b64) { + const bin = atob(b64); + const buf = new ArrayBuffer(bin.length); + const u8 = new Uint8Array(buf); + for (let i = 0; i < bin.length; i++) u8[i] = bin.charCodeAt(i); + return new Uint16Array(buf); +} +export function cellValue(fc, i, k) { + const q = fc.q[i * fc.nm + k]; + return q ? fc.vmin + ((q - 1) / 65534) * (fc.vmax - fc.vmin) : NaN; +} + +// grid index: lon/lat -> cell index +export function gridIndex(origins, dh) { + const map = new Map(); + const key = (x, y) => `${Math.round(x / dh)}|${Math.round(y / dh)}`; + origins.forEach(([x, y], i) => map.set(key(x, y), i)); + return (lon, lat) => { + const i = map.get(key(Math.floor(lon / dh + 1e-9) * dh, Math.floor(lat / dh + 1e-9) * dh)); + return i === undefined ? -1 : i; + }; +} + +export function downloadCSV(name, header, rows) { + const esc = (v) => (/[",\n]/.test(String(v)) ? `"${String(v).replace(/"/g, '""')}"` : v); + const text = [header.join(","), ...rows.map((r) => r.map(esc).join(","))].join("\n"); + const a = el("a", { href: URL.createObjectURL(new Blob([text], { type: "text/csv" })), download: name }); + document.body.append(a); + a.click(); + a.remove(); +} + +export function debounce(fn, ms = 80) { + let t; + return (...a) => { clearTimeout(t); t = setTimeout(() => fn(...a), ms); }; +} + +// basemaps +export const BASEMAPS = { + terrain: ["Terrain", "https://server.arcgisonline.com/ArcGIS/rest/services/World_Terrain_Base/MapServer/tile/{z}/{y}/{x}", "Tiles © Esri, USGS, NOAA", 13], + satellite: ["Satellite", "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}", "Tiles © Esri, Maxar, Earthstar Geographics", 18], +}; + +let lastBase = "terrain"; +try { lastBase = localStorage.getItem("fc-basemap") || "terrain"; } catch (e) {} + +/** Leaflet map with a Terrain/Satellite switch stacked under the zoom buttons. */ +export function makeMap(node, opts = {}) { + const map = L.map(node, { zoomControl: true, attributionControl: true, preferCanvas: true, ...opts }); + let layer = null; + const buttons = {}; + const setBase = (name) => { + if (!BASEMAPS[name]) name = "terrain"; + const [, url, attr, maxZoom] = BASEMAPS[name]; + if (layer) layer.remove(); + layer = L.tileLayer(url, { attribution: attr, maxNativeZoom: maxZoom, maxZoom: 18 }).addTo(map); + for (const [k, b] of Object.entries(buttons)) b.classList.toggle("on", k === name); + lastBase = name; + try { localStorage.setItem("fc-basemap", name); } catch (e) {} + }; + const Switch = L.Control.extend({ + options: { position: "topleft" }, + onAdd() { + const box = L.DomUtil.create("div", "leaflet-bar basemap-switch"); + for (const [k, [label]] of Object.entries(BASEMAPS)) { + const a = L.DomUtil.create("a", "", box); + a.href = "#"; + a.textContent = label; + a.title = `${label} basemap`; + a.setAttribute("role", "button"); + L.DomEvent.on(a, "click", (e) => { L.DomEvent.preventDefault(e); setBase(k); }); + buttons[k] = a; + } + L.DomEvent.disableClickPropagation(box); + return box; + }, + }); + new Switch().addTo(map); + setBase(lastBase); + map.setBase = setBase; + map.retheme = () => {}; + return map; +} + +export function outlineStyle() { + return { color: css("--accent"), weight: 1.5, fill: false, opacity: 0.9, interactive: false }; +} diff --git a/floatcsep/postprocess/web/static/logos/csep_logo.png b/floatcsep/postprocess/web/static/logos/csep_logo.png new file mode 100644 index 0000000..ce20bd4 Binary files /dev/null and b/floatcsep/postprocess/web/static/logos/csep_logo.png differ diff --git a/floatcsep/postprocess/web/static/logos/efehr_logo.png b/floatcsep/postprocess/web/static/logos/efehr_logo.png new file mode 100644 index 0000000..463cb4d Binary files /dev/null and b/floatcsep/postprocess/web/static/logos/efehr_logo.png differ diff --git a/floatcsep/postprocess/web/static/logos/ethz_logo.png b/floatcsep/postprocess/web/static/logos/ethz_logo.png new file mode 100644 index 0000000..826766d Binary files /dev/null and b/floatcsep/postprocess/web/static/logos/ethz_logo.png differ diff --git a/floatcsep/postprocess/web/static/logos/eu_logo.png b/floatcsep/postprocess/web/static/logos/eu_logo.png new file mode 100644 index 0000000..a509d1f Binary files /dev/null and b/floatcsep/postprocess/web/static/logos/eu_logo.png differ diff --git a/floatcsep/postprocess/web/static/logos/geoinquire_logo.png b/floatcsep/postprocess/web/static/logos/geoinquire_logo.png new file mode 100644 index 0000000..81f33af Binary files /dev/null and b/floatcsep/postprocess/web/static/logos/geoinquire_logo.png differ diff --git a/floatcsep/postprocess/web/static/logos/gfz_logo.png b/floatcsep/postprocess/web/static/logos/gfz_logo.png new file mode 100644 index 0000000..e89413a Binary files /dev/null and b/floatcsep/postprocess/web/static/logos/gfz_logo.png differ diff --git a/floatcsep/postprocess/web/static/logos/github_logo.png b/floatcsep/postprocess/web/static/logos/github_logo.png new file mode 100644 index 0000000..50b8175 Binary files /dev/null and b/floatcsep/postprocess/web/static/logos/github_logo.png differ diff --git a/floatcsep/postprocess/web/static/logos/logo.png b/floatcsep/postprocess/web/static/logos/logo.png new file mode 100644 index 0000000..268e1f6 Binary files /dev/null and b/floatcsep/postprocess/web/static/logos/logo.png differ diff --git a/floatcsep/postprocess/web/static/logos/readthedocs_logo.png b/floatcsep/postprocess/web/static/logos/readthedocs_logo.png new file mode 100644 index 0000000..8681e29 Binary files /dev/null and b/floatcsep/postprocess/web/static/logos/readthedocs_logo.png differ diff --git a/floatcsep/postprocess/web/static/vendor/echarts/echarts.min.js b/floatcsep/postprocess/web/static/vendor/echarts/echarts.min.js new file mode 100644 index 0000000..5423598 --- /dev/null +++ b/floatcsep/postprocess/web/static/vendor/echarts/echarts.min.js @@ -0,0 +1,48 @@ +(()=>{var P1=Object.defineProperty;var Me=(r,t)=>{for(var e in t)P1(r,e,{get:t[e],enumerable:!0})};var Hv={};Me(Hv,{Axis:()=>mf,ChartView:()=>It,ComponentModel:()=>ht,ComponentView:()=>Rt,List:()=>dr,Model:()=>gt,PRIORITY:()=>rv,SeriesModel:()=>Ut,color:()=>po,connect:()=>BE,dataTool:()=>XE,dependencies:()=>SE,disConnect:()=>UE,disconnect:()=>Xx,dispose:()=>VE,env:()=>Y,extendChartView:()=>aP,extendComponentModel:()=>rP,extendComponentView:()=>iP,extendSeriesModel:()=>nP,format:()=>Uv,getCoordinateSystemDimensions:()=>GE,getInstanceByDom:()=>av,getInstanceById:()=>HE,getMap:()=>YE,graphic:()=>Bv,helper:()=>Pv,init:()=>FE,innerDrawElementOnCanvas:()=>Ha,matrix:()=>Ur,number:()=>zv,parseGeoJSON:()=>df,parseGeoJson:()=>df,registerAction:()=>Ci,registerCoordinateSystem:()=>uv,registerLayout:()=>fv,registerLoading:()=>Qu,registerLocale:()=>lu,registerMap:()=>cv,registerPostInit:()=>sv,registerPostUpdate:()=>lv,registerPreprocessor:()=>Ku,registerProcessor:()=>ju,registerTheme:()=>ov,registerTransform:()=>pv,registerUpdateLifecycle:()=>bs,registerVisual:()=>Jr,setCanvasCreator:()=>WE,setPlatformAPI:()=>Ws,throttle:()=>Bn,time:()=>Fv,use:()=>Ce,util:()=>Vv,vector:()=>Ue,version:()=>xE,zrUtil:()=>$,zrender:()=>Tl});var Qf=function(r,t){return Qf=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,i){e.__proto__=i}||function(e,i){for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(e[n]=i[n])},Qf(r,t)};function O(r,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");Qf(r,t);function e(){this.constructor=r}r.prototype=t===null?Object.create(t):(e.prototype=t.prototype,new e)}var Tl={};Me(Tl,{dispose:()=>cC,disposeAll:()=>pC,getElementSSRData:()=>dC,getInstance:()=>vC,init:()=>wl,registerPainter:()=>Xh,registerSSRDataGetter:()=>qh,version:()=>mC});var O1=function(){function r(){this.firefox=!1,this.ie=!1,this.edge=!1,this.newEdge=!1,this.weChat=!1}return r}(),R1=function(){function r(){this.browser=new O1,this.node=!1,this.wxa=!1,this.worker=!1,this.svgSupported=!1,this.touchEventsSupported=!1,this.pointerEventsSupported=!1,this.domSupported=!1,this.transformSupported=!1,this.transform3dSupported=!1,this.hasGlobalWindow=typeof window<"u"}return r}(),Fi=new R1;typeof wx=="object"&&typeof wx.getSystemInfoSync=="function"?(Fi.wxa=!0,Fi.touchEventsSupported=!0):typeof document>"u"&&typeof self<"u"?Fi.worker=!0:typeof navigator>"u"||navigator.userAgent.indexOf("Node.js")===0?(Fi.node=!0,Fi.svgSupported=!0):I1(navigator.userAgent,Fi);function I1(r,t){var e=t.browser,i=r.match(/Firefox\/([\d.]+)/),n=r.match(/MSIE\s([\d.]+)/)||r.match(/Trident\/.+?rv:(([\d.]+))/),a=r.match(/Edge?\/([\d.]+)/),o=/micromessenger/i.test(r);i&&(e.firefox=!0,e.version=i[1]),n&&(e.ie=!0,e.version=n[1]),a&&(e.edge=!0,e.version=a[1],e.newEdge=+a[1].split(".")[0]>18),o&&(e.weChat=!0),t.svgSupported=typeof SVGRect<"u",t.touchEventsSupported="ontouchstart"in window&&!e.ie&&!e.edge,t.pointerEventsSupported="onpointerdown"in window&&(e.edge||e.ie&&+e.version>=11),t.domSupported=typeof document<"u";var s=document.documentElement.style;t.transform3dSupported=(e.ie&&"transition"in s||e.edge||"WebKitCSSMatrix"in window&&"m11"in new WebKitCSSMatrix||"MozPerspective"in s)&&!("OTransition"in s),t.transformSupported=t.transform3dSupported||e.ie&&+e.version>=9}var Y=Fi;var $={};Me($,{HashMap:()=>gm,RADIAN_TO_DEGREE:()=>qs,assert:()=>Ht,bind:()=>at,clone:()=>j,concatArray:()=>ih,createCanvas:()=>Y1,createHashMap:()=>W,createObject:()=>kr,curry:()=>st,defaults:()=>X,disableUserSelect:()=>io,each:()=>w,eqNaN:()=>Vi,extend:()=>I,filter:()=>dt,find:()=>X1,guid:()=>Ja,hasOwn:()=>U,indexOf:()=>K,inherits:()=>to,isArray:()=>N,isArrayLike:()=>Mt,isBuiltInObject:()=>$f,isDom:()=>Bi,isFunction:()=>G,isGradientObject:()=>Nr,isImagePatternObject:()=>rh,isNumber:()=>ot,isObject:()=>H,isPrimitive:()=>Jn,isRegExp:()=>Z1,isString:()=>F,isStringSafe:()=>ea,isTypedArray:()=>Et,keys:()=>rt,logError:()=>Ui,map:()=>z,merge:()=>nt,mergeAll:()=>eh,mixin:()=>Nt,noop:()=>kt,normalizeCssArray:()=>ro,reduce:()=>Vt,retrieve:()=>le,retrieve2:()=>Q,retrieve3:()=>yr,setAsPrimitive:()=>Hi,slice:()=>eo,trim:()=>Gt});var Gs=12,N1="sans-serif",sr=Gs+"px "+N1,k1=20,z1=100,F1="007LLmW'55;N0500LLLLLLLLLL00NNNLzWW\\\\WQb\\0FWLg\\bWb\\WQ\\WrWWQ000CL5LLFLL0LL**F*gLLLL5F0LF\\FFF5.5N";function B1(r){var t={};if(typeof JSON>"u")return t;for(var e=0;e=0)s=o*e.length;else for(var l=0;lZs,applyTransform:()=>Pt,clone:()=>nh,copy:()=>Q1,create:()=>zr,dist:()=>sh,distSquare:()=>ni,distance:()=>oo,distanceSquare:()=>ym,div:()=>iT,dot:()=>nT,len:()=>ah,lenSquare:()=>oh,length:()=>tT,lengthSquare:()=>eT,lerp:()=>oT,max:()=>Be,min:()=>Fe,mul:()=>rT,negate:()=>aT,normalize:()=>Gi,scale:()=>ao,scaleAndAdd:()=>J1,set:()=>$1,sub:()=>no});function zr(r,t){return r==null&&(r=0),t==null&&(t=0),[r,t]}function Q1(r,t){return r[0]=t[0],r[1]=t[1],r}function nh(r){return[r[0],r[1]]}function $1(r,t,e){return r[0]=t,r[1]=e,r}function Zs(r,t,e){return r[0]=t[0]+e[0],r[1]=t[1]+e[1],r}function J1(r,t,e,i){return r[0]=t[0]+e[0]*i,r[1]=t[1]+e[1]*i,r}function no(r,t,e){return r[0]=t[0]-e[0],r[1]=t[1]-e[1],r}function ah(r){return Math.sqrt(oh(r))}var tT=ah;function oh(r){return r[0]*r[0]+r[1]*r[1]}var eT=oh;function rT(r,t,e){return r[0]=t[0]*e[0],r[1]=t[1]*e[1],r}function iT(r,t,e){return r[0]=t[0]/e[0],r[1]=t[1]/e[1],r}function nT(r,t){return r[0]*t[0]+r[1]*t[1]}function ao(r,t,e){return r[0]=t[0]*e,r[1]=t[1]*e,r}function Gi(r,t){var e=ah(t);return e===0?(r[0]=0,r[1]=0):(r[0]=t[0]/e,r[1]=t[1]/e),r}function oo(r,t){return Math.sqrt((r[0]-t[0])*(r[0]-t[0])+(r[1]-t[1])*(r[1]-t[1]))}var sh=oo;function ym(r,t){return(r[0]-t[0])*(r[0]-t[0])+(r[1]-t[1])*(r[1]-t[1])}var ni=ym;function aT(r,t){return r[0]=-t[0],r[1]=-t[1],r}function oT(r,t,e,i){return r[0]=t[0]+i*(e[0]-t[0]),r[1]=t[1]+i*(e[1]-t[1]),r}function Pt(r,t,e){var i=t[0],n=t[1];return r[0]=e[0]*i+e[2]*n+e[4],r[1]=e[1]*i+e[3]*n+e[5],r}function Fe(r,t,e){return r[0]=Math.min(t[0],e[0]),r[1]=Math.min(t[1],e[1]),r}function Be(r,t,e){return r[0]=Math.max(t[0],e[0]),r[1]=Math.max(t[1],e[1]),r}var ra=function(){function r(t,e){this.target=t,this.topTarget=e&&e.topTarget}return r}(),sT=function(){function r(t){this.handler=t,t.on("mousedown",this._dragStart,this),t.on("mousemove",this._drag,this),t.on("mouseup",this._dragEnd,this)}return r.prototype._dragStart=function(t){for(var e=t.target;e&&!e.draggable;)e=e.parent||e.__hostTarget;e&&(this._draggingTarget=e,e.dragging=!0,this._x=t.offsetX,this._y=t.offsetY,this.handler.dispatchToElement(new ra(e,t),"dragstart",t.event))},r.prototype._drag=function(t){var e=this._draggingTarget;if(e){var i=t.offsetX,n=t.offsetY,a=i-this._x,o=n-this._y;this._x=i,this._y=n,e.drift(a,o,t),this.handler.dispatchToElement(new ra(e,t),"drag",t.event);var s=this.handler.findHover(i,n,e).target,l=this._dropTarget;this._dropTarget=s,e!==s&&(l&&s!==l&&this.handler.dispatchToElement(new ra(l,t),"dragleave",t.event),s&&s!==l&&this.handler.dispatchToElement(new ra(s,t),"dragenter",t.event))}},r.prototype._dragEnd=function(t){var e=this._draggingTarget;e&&(e.dragging=!1),this.handler.dispatchToElement(new ra(e,t),"dragend",t.event),this._dropTarget&&this.handler.dispatchToElement(new ra(this._dropTarget,t),"drop",t.event),this._draggingTarget=null,this._dropTarget=null},r}(),_m=sT;var lT=function(){function r(t){t&&(this._$eventProcessor=t)}return r.prototype.on=function(t,e,i,n){this._$handlers||(this._$handlers={});var a=this._$handlers;if(typeof e=="function"&&(n=i,i=e,e=null),!i||!t)return this;var o=this._$eventProcessor;e!=null&&o&&o.normalizeQuery&&(e=o.normalizeQuery(e)),a[t]||(a[t]=[]);for(var s=0;s>1)%2;s.cssText=["position: absolute","visibility: hidden","padding: 0","margin: 0","border-width: 0","user-select: none","width:0","height:0",i[l]+":0",n[u]+":0",i[1-l]+":auto",n[1-u]+":auto",""].join("!important;"),r.appendChild(o),e.push(o)}return e}function hT(r,t,e){for(var i=e?"invTrans":"trans",n=t[i],a=t.srcCoords,o=[],s=[],l=!0,u=0;u<4;u++){var f=r[u].getBoundingClientRect(),h=2*u,c=f.left,p=f.top;o.push(c,p),l=l&&a&&c===a[h]&&p===a[h+1],s.push(r[u].offsetLeft,r[u].offsetTop)}return l&&n?n:(t.srcCoords=o,t[i]=e?uh(s,o):uh(o,s))}function hh(r){return r.nodeName.toUpperCase()==="CANVAS"}var cT=/([&<>"'])/g,pT={"&":"&","<":"<",">":">",'"':""","'":"'"};function Wt(r){return r==null?"":(r+"").replace(cT,function(t,e){return pT[e]})}var vT=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ch=[],dT=Y.browser.firefox&&+Y.browser.version.split(".")[0]<39;function js(r,t,e,i){return e=e||{},i?bm(r,t,e):dT&&t.layerX!=null&&t.layerX!==t.offsetX?(e.zrX=t.layerX,e.zrY=t.layerY):t.offsetX!=null?(e.zrX=t.offsetX,e.zrY=t.offsetY):bm(r,t,e),e}function bm(r,t,e){if(Y.domSupported&&r.getBoundingClientRect){var i=t.clientX,n=t.clientY;if(hh(r)){var a=r.getBoundingClientRect();e.zrX=i-a.left,e.zrY=n-a.top;return}else if(Ks(ch,r,i,n)){e.zrX=ch[0],e.zrY=ch[1];return}}e.zrX=e.zrY=0}function Qs(r){return r||window.event}function ve(r,t,e){if(t=Qs(t),t.zrX!=null)return t;var i=t.type,n=i&&i.indexOf("touch")>=0;if(n){var o=i!=="touchend"?t.targetTouches[0]:t.changedTouches[0];o&&js(r,o,t,e)}else{js(r,t,t,e);var a=mT(t);t.zrDelta=a?a/120:-(t.detail||0)/3}var s=t.button;return t.which==null&&s!==void 0&&vT.test(t.type)&&(t.which=s&1?1:s&2?3:s&4?2:0),t}function mT(r){var t=r.wheelDelta;if(t)return t;var e=r.deltaX,i=r.deltaY;if(e==null||i==null)return t;var n=Math.abs(i!==0?i:e),a=i>0?-1:i<0?1:e>0?-1:1;return 3*n*a}function wm(r,t,e,i){r.addEventListener(t,e,i)}function Tm(r,t,e,i){r.removeEventListener(t,e,i)}var $s=function(r){r.preventDefault(),r.stopPropagation(),r.cancelBubble=!0};var Dm=function(){function r(){this._track=[]}return r.prototype.recognize=function(t,e,i){return this._doTrack(t,e,i),this._recognize(t)},r.prototype.clear=function(){return this._track.length=0,this},r.prototype._doTrack=function(t,e,i){var n=t.touches;if(n){for(var a={points:[],touches:[],target:e,event:t},o=0,s=n.length;o1&&i&&i.length>1){var a=Cm(i)/Cm(n);!isFinite(a)&&(a=1),t.pinchScale=a;var o=gT(i);return t.pinchX=o[0],t.pinchY=o[1],{type:"pinch",target:r[0].target,event:t}}}}};var Ur={};Me(Ur,{clone:()=>yT,copy:()=>Js,create:()=>lr,identity:()=>Fr,invert:()=>Br,mul:()=>Ve,rotate:()=>Wi,scale:()=>dh,translate:()=>ia});function lr(){return[1,0,0,1,0,0]}function Fr(r){return r[0]=1,r[1]=0,r[2]=0,r[3]=1,r[4]=0,r[5]=0,r}function Js(r,t){return r[0]=t[0],r[1]=t[1],r[2]=t[2],r[3]=t[3],r[4]=t[4],r[5]=t[5],r}function Ve(r,t,e){var i=t[0]*e[0]+t[2]*e[1],n=t[1]*e[0]+t[3]*e[1],a=t[0]*e[2]+t[2]*e[3],o=t[1]*e[2]+t[3]*e[3],s=t[0]*e[4]+t[2]*e[5]+t[4],l=t[1]*e[4]+t[3]*e[5]+t[5];return r[0]=i,r[1]=n,r[2]=a,r[3]=o,r[4]=s,r[5]=l,r}function ia(r,t,e){return r[0]=t[0],r[1]=t[1],r[2]=t[2],r[3]=t[3],r[4]=t[4]+e[0],r[5]=t[5]+e[1],r}function Wi(r,t,e,i){i===void 0&&(i=[0,0]);var n=t[0],a=t[2],o=t[4],s=t[1],l=t[3],u=t[5],f=Math.sin(e),h=Math.cos(e);return r[0]=n*h+s*f,r[1]=-n*f+s*h,r[2]=a*h+l*f,r[3]=-a*f+h*l,r[4]=h*(o-i[0])+f*(u-i[1])+i[0],r[5]=h*(u-i[1])-f*(o-i[0])+i[1],r}function dh(r,t,e){var i=e[0],n=e[1];return r[0]=t[0]*i,r[1]=t[1]*n,r[2]=t[2]*i,r[3]=t[3]*n,r[4]=t[4]*i,r[5]=t[5]*n,r}function Br(r,t){var e=t[0],i=t[2],n=t[4],a=t[1],o=t[3],s=t[5],l=e*o-a*i;return l?(l=1/l,r[0]=o*l,r[1]=-a*l,r[2]=-i*l,r[3]=e*l,r[4]=(i*s-o*n)*l,r[5]=(a*n-e*s)*l,r):null}function yT(r){var t=lr();return Js(t,r),t}var _T=function(){function r(t,e){this.x=t||0,this.y=e||0}return r.prototype.copy=function(t){return this.x=t.x,this.y=t.y,this},r.prototype.clone=function(){return new r(this.x,this.y)},r.prototype.set=function(t,e){return this.x=t,this.y=e,this},r.prototype.equal=function(t){return t.x===this.x&&t.y===this.y},r.prototype.add=function(t){return this.x+=t.x,this.y+=t.y,this},r.prototype.scale=function(t){this.x*=t,this.y*=t},r.prototype.scaleAndAdd=function(t,e){this.x+=t.x*e,this.y+=t.y*e},r.prototype.sub=function(t){return this.x-=t.x,this.y-=t.y,this},r.prototype.dot=function(t){return this.x*t.x+this.y*t.y},r.prototype.len=function(){return Math.sqrt(this.x*this.x+this.y*this.y)},r.prototype.lenSquare=function(){return this.x*this.x+this.y*this.y},r.prototype.normalize=function(){var t=this.len();return this.x/=t,this.y/=t,this},r.prototype.distance=function(t){var e=this.x-t.x,i=this.y-t.y;return Math.sqrt(e*e+i*i)},r.prototype.distanceSquare=function(t){var e=this.x-t.x,i=this.y-t.y;return e*e+i*i},r.prototype.negate=function(){return this.x=-this.x,this.y=-this.y,this},r.prototype.transform=function(t){if(t){var e=this.x,i=this.y;return this.x=t[0]*e+t[2]*i+t[4],this.y=t[1]*e+t[3]*i+t[5],this}},r.prototype.toArray=function(t){return t[0]=this.x,t[1]=this.y,t},r.prototype.fromArray=function(t){this.x=t[0],this.y=t[1]},r.set=function(t,e,i){t.x=e,t.y=i},r.copy=function(t,e){t.x=e.x,t.y=e.y},r.len=function(t){return Math.sqrt(t.x*t.x+t.y*t.y)},r.lenSquare=function(t){return t.x*t.x+t.y*t.y},r.dot=function(t,e){return t.x*e.x+t.y*e.y},r.add=function(t,e,i){t.x=e.x+i.x,t.y=e.y+i.y},r.sub=function(t,e,i){t.x=e.x-i.x,t.y=e.y-i.y},r.scale=function(t,e,i){t.x=e.x*i,t.y=e.y*i},r.scaleAndAdd=function(t,e,i,n){t.x=e.x+i.x*n,t.y=e.y+i.y*n},r.lerp=function(t,e,i,n){var a=1-n;t.x=a*e.x+n*i.x,t.y=a*e.y+n*i.y},r}(),_t=_T;var tl=Math.min,el=Math.max,Yi=new _t,Xi=new _t,qi=new _t,Zi=new _t,so=new _t,lo=new _t,xT=function(){function r(t,e,i,n){i<0&&(t=t+i,i=-i),n<0&&(e=e+n,n=-n),this.x=t,this.y=e,this.width=i,this.height=n}return r.prototype.union=function(t){var e=tl(t.x,this.x),i=tl(t.y,this.y);isFinite(this.x)&&isFinite(this.width)?this.width=el(t.x+t.width,this.x+this.width)-e:this.width=t.width,isFinite(this.y)&&isFinite(this.height)?this.height=el(t.y+t.height,this.y+this.height)-i:this.height=t.height,this.x=e,this.y=i},r.prototype.applyTransform=function(t){r.applyTransform(this,this,t)},r.prototype.calculateTransform=function(t){var e=this,i=t.width/e.width,n=t.height/e.height,a=lr();return ia(a,a,[-e.x,-e.y]),dh(a,a,[i,n]),ia(a,a,[t.x,t.y]),a},r.prototype.intersect=function(t,e){if(!t)return!1;t instanceof r||(t=r.create(t));var i=this,n=i.x,a=i.x+i.width,o=i.y,s=i.y+i.height,l=t.x,u=t.x+t.width,f=t.y,h=t.y+t.height,c=!(av&&(v=_,mv&&(v=x,g=i.x&&t<=i.x+i.width&&e>=i.y&&e<=i.y+i.height},r.prototype.clone=function(){return new r(this.x,this.y,this.width,this.height)},r.prototype.copy=function(t){r.copy(this,t)},r.prototype.plain=function(){return{x:this.x,y:this.y,width:this.width,height:this.height}},r.prototype.isFinite=function(){return isFinite(this.x)&&isFinite(this.y)&&isFinite(this.width)&&isFinite(this.height)},r.prototype.isZero=function(){return this.width===0||this.height===0},r.create=function(t){return new r(t.x,t.y,t.width,t.height)},r.copy=function(t,e){t.x=e.x,t.y=e.y,t.width=e.width,t.height=e.height},r.applyTransform=function(t,e,i){if(!i){t!==e&&r.copy(t,e);return}if(i[1]<1e-5&&i[1]>-1e-5&&i[2]<1e-5&&i[2]>-1e-5){var n=i[0],a=i[3],o=i[4],s=i[5];t.x=e.x*n+o,t.y=e.y*a+s,t.width=e.width*n,t.height=e.height*a,t.width<0&&(t.x+=t.width,t.width=-t.width),t.height<0&&(t.y+=t.height,t.height=-t.height);return}Yi.x=qi.x=e.x,Yi.y=Zi.y=e.y,Xi.x=Zi.x=e.x+e.width,Xi.y=qi.y=e.y+e.height,Yi.transform(i),Zi.transform(i),Xi.transform(i),qi.transform(i),t.x=tl(Yi.x,Xi.x,qi.x,Zi.x),t.y=tl(Yi.y,Xi.y,qi.y,Zi.y);var l=el(Yi.x,Xi.x,qi.x,Zi.x),u=el(Yi.y,Xi.y,qi.y,Zi.y);t.width=l-t.x,t.height=u-t.y},r}(),J=xT;var Mm="silent";function ST(r,t,e){return{type:r,event:e,target:t.target,topTarget:t.topTarget,cancelBubble:!1,offsetX:e.zrX,offsetY:e.zrY,gestureEvent:e.gestureEvent,pinchX:e.pinchX,pinchY:e.pinchY,pinchScale:e.pinchScale,wheelDelta:e.zrDelta,zrByTouch:e.zrByTouch,which:e.which,stop:bT}}function bT(){$s(this.event)}var wT=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.handler=null,e}return t.prototype.dispose=function(){},t.prototype.setCursor=function(){},t}(jt),uo=function(){function r(t,e){this.x=t,this.y=e}return r}(),TT=["click","dblclick","mousewheel","mouseout","mouseup","mousedown","mousemove","contextmenu"],mh=new J(0,0,0,0),Em=function(r){O(t,r);function t(e,i,n,a,o){var s=r.call(this)||this;return s._hovered=new uo(0,0),s.storage=e,s.painter=i,s.painterRoot=a,s._pointerSize=o,n=n||new wT,s.proxy=null,s.setHandlerProxy(n),s._draggingMgr=new _m(s),s}return t.prototype.setHandlerProxy=function(e){this.proxy&&this.proxy.dispose(),e&&(w(TT,function(i){e.on&&e.on(i,this[i],this)},this),e.handler=this),this.proxy=e},t.prototype.mousemove=function(e){var i=e.zrX,n=e.zrY,a=Lm(this,i,n),o=this._hovered,s=o.target;s&&!s.__zr&&(o=this.findHover(o.x,o.y),s=o.target);var l=this._hovered=a?new uo(i,n):this.findHover(i,n),u=l.target,f=this.proxy;f.setCursor&&f.setCursor(u?u.cursor:"default"),s&&u!==s&&this.dispatchToElement(o,"mouseout",e),this.dispatchToElement(l,"mousemove",e),u&&u!==s&&this.dispatchToElement(l,"mouseover",e)},t.prototype.mouseout=function(e){var i=e.zrEventControl;i!=="only_globalout"&&this.dispatchToElement(this._hovered,"mouseout",e),i!=="no_globalout"&&this.trigger("globalout",{type:"globalout",event:e})},t.prototype.resize=function(){this._hovered=new uo(0,0)},t.prototype.dispatch=function(e,i){var n=this[e];n&&n.call(this,i)},t.prototype.dispose=function(){this.proxy.dispose(),this.storage=null,this.proxy=null,this.painter=null},t.prototype.setCursorStyle=function(e){var i=this.proxy;i.setCursor&&i.setCursor(e)},t.prototype.dispatchToElement=function(e,i,n){e=e||{};var a=e.target;if(!(a&&a.silent)){for(var o="on"+i,s=ST(i,e,n);a&&(a[o]&&(s.cancelBubble=!!a[o].call(a,s)),a.trigger(i,s),a=a.__hostTarget?a.__hostTarget:a.parent,!s.cancelBubble););s.cancelBubble||(this.trigger(i,s),this.painter&&this.painter.eachOtherLayer&&this.painter.eachOtherLayer(function(l){typeof l[o]=="function"&&l[o].call(l,s),l.trigger&&l.trigger(i,s)}))}},t.prototype.findHover=function(e,i,n){var a=this.storage.getDisplayList(),o=new uo(e,i);if(Am(a,o,e,i,n),this._pointerSize&&!o.target){for(var s=[],l=this._pointerSize,u=l/2,f=new J(e-u,i-u,l,l),h=a.length-1;h>=0;h--){var c=a[h];c!==n&&!c.ignore&&!c.ignoreCoarsePointer&&(!c.parent||!c.parent.ignoreCoarsePointer)&&(mh.copy(c.getBoundingRect()),c.transform&&mh.applyTransform(c.transform),mh.intersect(f)&&s.push(c))}if(s.length)for(var p=4,v=Math.PI/12,m=Math.PI*2,d=0;d4)return;this._downPoint=null}this.dispatchToElement(a,r,t)}});function CT(r,t,e){if(r[r.rectHover?"rectContain":"contain"](t,e)){for(var i=r,n=void 0,a=!1;i;){if(i.ignoreClip&&(a=!0),!a){var o=i.getClipPath();if(o&&!o.contain(t,e))return!1}i.silent&&(n=!0);var s=i.__hostTarget;i=s||i.parent}return n?Mm:!0}return!1}function Am(r,t,e,i,n){for(var a=r.length-1;a>=0;a--){var o=r[a],s=void 0;if(o!==n&&!o.ignore&&(s=CT(o,e,i))&&(!t.topTarget&&(t.topTarget=o),s!==Mm)){t.target=o;break}}}function Lm(r,t,e){var i=r.painter;return t<0||t>i.getWidth()||e<0||e>i.getHeight()}var Pm=Em;var Im=32,fo=7;function DT(r){for(var t=0;r>=Im;)t|=r&1,r>>=1;return r+t}function Om(r,t,e,i){var n=t+1;if(n===e)return 1;if(i(r[n++],r[t])<0){for(;n=0;)n++;return n-t}function AT(r,t,e){for(e--;t>>1,n(a,r[l])<0?s=l:o=l+1;var u=i-o;switch(u){case 3:r[o+3]=r[o+2];case 2:r[o+2]=r[o+1];case 1:r[o+1]=r[o];break;default:for(;u>0;)r[o+u]=r[o+u-1],u--}r[o]=a}}function gh(r,t,e,i,n,a){var o=0,s=0,l=1;if(a(r,t[e+n])>0){for(s=i-n;l0;)o=l,l=(l<<1)+1,l<=0&&(l=s);l>s&&(l=s),o+=n,l+=n}else{for(s=n+1;ls&&(l=s);var u=o;o=n-l,l=n-u}for(o++;o>>1);a(r,t[e+f])>0?o=f+1:l=f}return l}function yh(r,t,e,i,n,a){var o=0,s=0,l=1;if(a(r,t[e+n])<0){for(s=n+1;ls&&(l=s);var u=o;o=n-l,l=n-u}else{for(s=i-n;l=0;)o=l,l=(l<<1)+1,l<=0&&(l=s);l>s&&(l=s),o+=n,l+=n}for(o++;o>>1);a(r,t[e+f])<0?l=f:o=f+1}return l}function MT(r,t){var e=fo,i,n,a=0,o=[];i=[],n=[];function s(p,v){i[a]=p,n[a]=v,a+=1}function l(){for(;a>1;){var p=a-2;if(p>=1&&n[p-1]<=n[p]+n[p+1]||p>=2&&n[p-2]<=n[p]+n[p-1])n[p-1]n[p+1])break;f(p)}}function u(){for(;a>1;){var p=a-2;p>0&&n[p-1]=fo||T>=fo);if(C)break;b<0&&(b=0),b+=2}if(e=b,e<1&&(e=1),v===1){for(g=0;g=0;g--)r[S+g]=r[b+g];r[x]=o[_];return}for(var T=e;;){var C=0,A=0,M=!1;do if(t(o[_],r[y])<0){if(r[x--]=r[y--],C++,A=0,--v===0){M=!0;break}}else if(r[x--]=o[_--],A++,C=0,--d===1){M=!0;break}while((C|A)=0;g--)r[S+g]=r[b+g];if(v===0){M=!0;break}}if(r[x--]=o[_--],--d===1){M=!0;break}if(A=d-gh(r[y],o,0,d,d-1,t),A!==0){for(x-=A,_-=A,d-=A,S=x+1,b=_+1,g=0;g=fo||A>=fo);if(M)break;T<0&&(T=0),T+=2}if(e=T,e<1&&(e=1),d===1){for(x-=v,y-=v,S=x+1,b=y+1,g=v-1;g>=0;g--)r[S+g]=r[b+g];r[x]=o[_]}else{if(d===0)throw new Error;for(b=x-(d-1),g=0;gs&&(l=s),Rm(r,e,e+l,e+a,t),a=l}o.pushRun(e,a),o.mergeRuns(),n-=a,e+=a}while(n!==0);o.forceMergeRuns()}}var zt=1,ji=2,ai=4;var Nm=!1;function _h(){Nm||(Nm=!0,console.warn("z / z2 / zlevel of displayable is invalid, which may cause unexpected errors"))}function km(r,t){return r.zlevel===t.zlevel?r.z===t.z?r.z2-t.z2:r.z-t.z:r.zlevel-t.zlevel}var ET=function(){function r(){this._roots=[],this._displayList=[],this._displayListLen=0,this.displayableSortFunc=km}return r.prototype.traverse=function(t,e){for(var i=0;i0&&(f.__clipPaths=[]),isNaN(f.z)&&(_h(),f.z=0),isNaN(f.z2)&&(_h(),f.z2=0),isNaN(f.zlevel)&&(_h(),f.zlevel=0),this._displayList[this._displayListLen++]=f}var h=t.getDecalElement&&t.getDecalElement();h&&this._updateAndAddDisplayable(h,e,i);var c=t.getTextGuideLine();c&&this._updateAndAddDisplayable(c,e,i);var p=t.getTextContent();p&&this._updateAndAddDisplayable(p,e,i)}},r.prototype.addRoot=function(t){t.__zr&&t.__zr.storage===this||this._roots.push(t)},r.prototype.delRoot=function(t){if(t instanceof Array){for(var e=0,i=t.length;e=0&&this._roots.splice(n,1)},r.prototype.delAllRoots=function(){this._roots=[],this._displayList=[],this._displayListLen=0},r.prototype.getRoots=function(){return this._roots},r.prototype.dispose=function(){this._displayList=null,this._roots=null},r}(),zm=ET;var Fm;Fm=Y.hasGlobalWindow&&(window.requestAnimationFrame&&window.requestAnimationFrame.bind(window)||window.msRequestAnimationFrame&&window.msRequestAnimationFrame.bind(window)||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame)||function(r){return setTimeout(r,16)};var ho=Fm;var rl={linear:function(r){return r},quadraticIn:function(r){return r*r},quadraticOut:function(r){return r*(2-r)},quadraticInOut:function(r){return(r*=2)<1?.5*r*r:-.5*(--r*(r-2)-1)},cubicIn:function(r){return r*r*r},cubicOut:function(r){return--r*r*r+1},cubicInOut:function(r){return(r*=2)<1?.5*r*r*r:.5*((r-=2)*r*r+2)},quarticIn:function(r){return r*r*r*r},quarticOut:function(r){return 1- --r*r*r*r},quarticInOut:function(r){return(r*=2)<1?.5*r*r*r*r:-.5*((r-=2)*r*r*r-2)},quinticIn:function(r){return r*r*r*r*r},quinticOut:function(r){return--r*r*r*r*r+1},quinticInOut:function(r){return(r*=2)<1?.5*r*r*r*r*r:.5*((r-=2)*r*r*r*r+2)},sinusoidalIn:function(r){return 1-Math.cos(r*Math.PI/2)},sinusoidalOut:function(r){return Math.sin(r*Math.PI/2)},sinusoidalInOut:function(r){return .5*(1-Math.cos(Math.PI*r))},exponentialIn:function(r){return r===0?0:Math.pow(1024,r-1)},exponentialOut:function(r){return r===1?1:1-Math.pow(2,-10*r)},exponentialInOut:function(r){return r===0?0:r===1?1:(r*=2)<1?.5*Math.pow(1024,r-1):.5*(-Math.pow(2,-10*(r-1))+2)},circularIn:function(r){return 1-Math.sqrt(1-r*r)},circularOut:function(r){return Math.sqrt(1- --r*r)},circularInOut:function(r){return(r*=2)<1?-.5*(Math.sqrt(1-r*r)-1):.5*(Math.sqrt(1-(r-=2)*r)+1)},elasticIn:function(r){var t,e=.1,i=.4;return r===0?0:r===1?1:(!e||e<1?(e=1,t=i/4):t=i*Math.asin(1/e)/(2*Math.PI),-(e*Math.pow(2,10*(r-=1))*Math.sin((r-t)*(2*Math.PI)/i)))},elasticOut:function(r){var t,e=.1,i=.4;return r===0?0:r===1?1:(!e||e<1?(e=1,t=i/4):t=i*Math.asin(1/e)/(2*Math.PI),e*Math.pow(2,-10*r)*Math.sin((r-t)*(2*Math.PI)/i)+1)},elasticInOut:function(r){var t,e=.1,i=.4;return r===0?0:r===1?1:(!e||e<1?(e=1,t=i/4):t=i*Math.asin(1/e)/(2*Math.PI),(r*=2)<1?-.5*(e*Math.pow(2,10*(r-=1))*Math.sin((r-t)*(2*Math.PI)/i)):e*Math.pow(2,-10*(r-=1))*Math.sin((r-t)*(2*Math.PI)/i)*.5+1)},backIn:function(r){var t=1.70158;return r*r*((t+1)*r-t)},backOut:function(r){var t=1.70158;return--r*r*((t+1)*r+t)+1},backInOut:function(r){var t=2.5949095;return(r*=2)<1?.5*(r*r*((t+1)*r-t)):.5*((r-=2)*r*((t+1)*r+t)+2)},bounceIn:function(r){return 1-rl.bounceOut(1-r)},bounceOut:function(r){return r<.36363636363636365?7.5625*r*r:r<.7272727272727273?7.5625*(r-=.5454545454545454)*r+.75:r<.9090909090909091?7.5625*(r-=.8181818181818182)*r+.9375:7.5625*(r-=.9545454545454546)*r+.984375},bounceInOut:function(r){return r<.5?rl.bounceIn(r*2)*.5:rl.bounceOut(r*2-1)*.5+.5}},il=rl;var nl=Math.pow,si=Math.sqrt,ol=1e-8,Um=1e-4,Bm=si(3),al=1/3,_r=zr(),He=zr(),na=zr();function oi(r){return r>-ol&&rol||r<-ol}function Dt(r,t,e,i,n){var a=1-n;return a*a*(a*r+3*n*t)+n*n*(n*i+3*a*e)}function xh(r,t,e,i,n){var a=1-n;return 3*(((t-r)*a+2*(e-t)*n)*a+(i-e)*n*n)}function Qi(r,t,e,i,n,a){var o=i+3*(t-e)-r,s=3*(e-t*2+r),l=3*(t-r),u=r-n,f=s*s-3*o*l,h=s*l-9*o*u,c=l*l-3*s*u,p=0;if(oi(f)&&oi(h))if(oi(s))a[0]=0;else{var v=-l/s;v>=0&&v<=1&&(a[p++]=v)}else{var m=h*h-4*f*c;if(oi(m)){var d=h/f,v=-s/o+d,g=-d/2;v>=0&&v<=1&&(a[p++]=v),g>=0&&g<=1&&(a[p++]=g)}else if(m>0){var y=si(m),_=f*s+1.5*o*(-h+y),x=f*s+1.5*o*(-h-y);_<0?_=-nl(-_,al):_=nl(_,al),x<0?x=-nl(-x,al):x=nl(x,al);var v=(-s-(_+x))/(3*o);v>=0&&v<=1&&(a[p++]=v)}else{var b=(2*f*s-3*o*h)/(2*si(f*f*f)),S=Math.acos(b)/3,T=si(f),C=Math.cos(S),v=(-s-2*T*C)/(3*o),g=(-s+T*(C+Bm*Math.sin(S)))/(3*o),A=(-s+T*(C-Bm*Math.sin(S)))/(3*o);v>=0&&v<=1&&(a[p++]=v),g>=0&&g<=1&&(a[p++]=g),A>=0&&A<=1&&(a[p++]=A)}}return p}function sl(r,t,e,i,n){var a=6*e-12*t+6*r,o=9*t+3*i-3*r-9*e,s=3*t-3*r,l=0;if(oi(o)){if(Vm(a)){var u=-s/a;u>=0&&u<=1&&(n[l++]=u)}}else{var f=a*a-4*o*s;if(oi(f))n[0]=-a/(2*o);else if(f>0){var h=si(f),u=(-a+h)/(2*o),c=(-a-h)/(2*o);u>=0&&u<=1&&(n[l++]=u),c>=0&&c<=1&&(n[l++]=c)}}return l}function aa(r,t,e,i,n,a){var o=(t-r)*n+r,s=(e-t)*n+t,l=(i-e)*n+e,u=(s-o)*n+o,f=(l-s)*n+s,h=(f-u)*n+u;a[0]=r,a[1]=o,a[2]=u,a[3]=h,a[4]=h,a[5]=f,a[6]=l,a[7]=i}function Hm(r,t,e,i,n,a,o,s,l,u,f){var h,c=.005,p=1/0,v,m,d,g;_r[0]=l,_r[1]=u;for(var y=0;y<1;y+=.05)He[0]=Dt(r,e,n,o,y),He[1]=Dt(t,i,a,s,y),d=ni(_r,He),d=0&&d=0&&u<=1&&(n[l++]=u)}}else{var f=o*o-4*a*s;if(oi(f)){var u=-o/(2*a);u>=0&&u<=1&&(n[l++]=u)}else if(f>0){var h=si(f),u=(-o+h)/(2*a),c=(-o-h)/(2*a);u>=0&&u<=1&&(n[l++]=u),c>=0&&c<=1&&(n[l++]=c)}}return l}function ll(r,t,e){var i=r+e-2*t;return i===0?.5:(r-t)/i}function oa(r,t,e,i,n){var a=(t-r)*i+r,o=(e-t)*i+t,s=(o-a)*i+a;n[0]=r,n[1]=a,n[2]=s,n[3]=s,n[4]=o,n[5]=e}function Ym(r,t,e,i,n,a,o,s,l){var u,f=.005,h=1/0;_r[0]=o,_r[1]=s;for(var c=0;c<1;c+=.05){He[0]=Bt(r,e,n,c),He[1]=Bt(t,i,a,c);var p=ni(_r,He);p=0&&p=1?1:Qi(0,i,a,1,l,s)&&Dt(0,n,o,1,s[0])}}}var PT=function(){function r(t){this._inited=!1,this._startTime=0,this._pausedTime=0,this._paused=!1,this._life=t.life||1e3,this._delay=t.delay||0,this.loop=t.loop||!1,this.onframe=t.onframe||kt,this.ondestroy=t.ondestroy||kt,this.onrestart=t.onrestart||kt,t.easing&&this.setEasing(t.easing)}return r.prototype.step=function(t,e){if(this._inited||(this._startTime=t+this._delay,this._inited=!0),this._paused){this._pausedTime+=e;return}var i=this._life,n=t-this._startTime-this._pausedTime,a=n/i;a<0&&(a=0),a=Math.min(a,1);var o=this.easingFunc,s=o?o(a):a;if(this.onframe(s),a===1)if(this.loop){var l=n%i;this._startTime=t-l,this._pausedTime=0,this.onrestart()}else return!0;return!1},r.prototype.pause=function(){this._paused=!0},r.prototype.resume=function(){this._paused=!1},r.prototype.setEasing=function(t){this.easing=t,this.easingFunc=G(t)?t:il[t]||ul(t)},r}(),qm=PT;var po={};Me(po,{fastLerp:()=>$m,fastMapToColor:()=>zT,lerp:()=>hl,lift:()=>Ah,liftColor:()=>pl,lum:()=>Ji,mapToColor:()=>FT,modifyAlpha:()=>cl,modifyHSL:()=>BT,parse:()=>Jt,random:()=>UT,stringify:()=>xr,toHex:()=>kT});var Zm=function(){function r(t){this.value=t}return r}();var OT=function(){function r(){this._len=0}return r.prototype.insert=function(t){var e=new Zm(t);return this.insertEntry(e),e},r.prototype.insertEntry=function(t){this.head?(this.tail.next=t,t.prev=this.tail,t.next=null,this.tail=t):this.head=this.tail=t,this._len++},r.prototype.remove=function(t){var e=t.prev,i=t.next;e?e.next=i:this.head=i,i?i.prev=e:this.tail=e,t.next=t.prev=null,this._len--},r.prototype.len=function(){return this._len},r.prototype.clear=function(){this.head=this.tail=null,this._len=0},r}();var RT=function(){function r(t){this._list=new OT,this._maxSize=10,this._map={},this._maxSize=t}return r.prototype.put=function(t,e){var i=this._list,n=this._map,a=null;if(n[t]==null){var o=i.len(),s=this._lastRemovedEntry;if(o>=this._maxSize&&o>0){var l=i.head;i.remove(l),delete n[l.key],a=l.value,this._lastRemovedEntry=l}s?s.value=e:s=new Zm(e),s.key=t,i.insertEntry(s),n[t]=s}return a},r.prototype.get=function(t){var e=this._map[t],i=this._list;if(e!=null)return e!==i.tail&&(i.remove(e),i.insertEntry(e)),e.value},r.prototype.clear=function(){this._list.clear(),this._map={}},r.prototype.len=function(){return this._list.len()},r}(),Vr=RT;var Km={transparent:[0,0,0,0],aliceblue:[240,248,255,1],antiquewhite:[250,235,215,1],aqua:[0,255,255,1],aquamarine:[127,255,212,1],azure:[240,255,255,1],beige:[245,245,220,1],bisque:[255,228,196,1],black:[0,0,0,1],blanchedalmond:[255,235,205,1],blue:[0,0,255,1],blueviolet:[138,43,226,1],brown:[165,42,42,1],burlywood:[222,184,135,1],cadetblue:[95,158,160,1],chartreuse:[127,255,0,1],chocolate:[210,105,30,1],coral:[255,127,80,1],cornflowerblue:[100,149,237,1],cornsilk:[255,248,220,1],crimson:[220,20,60,1],cyan:[0,255,255,1],darkblue:[0,0,139,1],darkcyan:[0,139,139,1],darkgoldenrod:[184,134,11,1],darkgray:[169,169,169,1],darkgreen:[0,100,0,1],darkgrey:[169,169,169,1],darkkhaki:[189,183,107,1],darkmagenta:[139,0,139,1],darkolivegreen:[85,107,47,1],darkorange:[255,140,0,1],darkorchid:[153,50,204,1],darkred:[139,0,0,1],darksalmon:[233,150,122,1],darkseagreen:[143,188,143,1],darkslateblue:[72,61,139,1],darkslategray:[47,79,79,1],darkslategrey:[47,79,79,1],darkturquoise:[0,206,209,1],darkviolet:[148,0,211,1],deeppink:[255,20,147,1],deepskyblue:[0,191,255,1],dimgray:[105,105,105,1],dimgrey:[105,105,105,1],dodgerblue:[30,144,255,1],firebrick:[178,34,34,1],floralwhite:[255,250,240,1],forestgreen:[34,139,34,1],fuchsia:[255,0,255,1],gainsboro:[220,220,220,1],ghostwhite:[248,248,255,1],gold:[255,215,0,1],goldenrod:[218,165,32,1],gray:[128,128,128,1],green:[0,128,0,1],greenyellow:[173,255,47,1],grey:[128,128,128,1],honeydew:[240,255,240,1],hotpink:[255,105,180,1],indianred:[205,92,92,1],indigo:[75,0,130,1],ivory:[255,255,240,1],khaki:[240,230,140,1],lavender:[230,230,250,1],lavenderblush:[255,240,245,1],lawngreen:[124,252,0,1],lemonchiffon:[255,250,205,1],lightblue:[173,216,230,1],lightcoral:[240,128,128,1],lightcyan:[224,255,255,1],lightgoldenrodyellow:[250,250,210,1],lightgray:[211,211,211,1],lightgreen:[144,238,144,1],lightgrey:[211,211,211,1],lightpink:[255,182,193,1],lightsalmon:[255,160,122,1],lightseagreen:[32,178,170,1],lightskyblue:[135,206,250,1],lightslategray:[119,136,153,1],lightslategrey:[119,136,153,1],lightsteelblue:[176,196,222,1],lightyellow:[255,255,224,1],lime:[0,255,0,1],limegreen:[50,205,50,1],linen:[250,240,230,1],magenta:[255,0,255,1],maroon:[128,0,0,1],mediumaquamarine:[102,205,170,1],mediumblue:[0,0,205,1],mediumorchid:[186,85,211,1],mediumpurple:[147,112,219,1],mediumseagreen:[60,179,113,1],mediumslateblue:[123,104,238,1],mediumspringgreen:[0,250,154,1],mediumturquoise:[72,209,204,1],mediumvioletred:[199,21,133,1],midnightblue:[25,25,112,1],mintcream:[245,255,250,1],mistyrose:[255,228,225,1],moccasin:[255,228,181,1],navajowhite:[255,222,173,1],navy:[0,0,128,1],oldlace:[253,245,230,1],olive:[128,128,0,1],olivedrab:[107,142,35,1],orange:[255,165,0,1],orangered:[255,69,0,1],orchid:[218,112,214,1],palegoldenrod:[238,232,170,1],palegreen:[152,251,152,1],paleturquoise:[175,238,238,1],palevioletred:[219,112,147,1],papayawhip:[255,239,213,1],peachpuff:[255,218,185,1],peru:[205,133,63,1],pink:[255,192,203,1],plum:[221,160,221,1],powderblue:[176,224,230,1],purple:[128,0,128,1],red:[255,0,0,1],rosybrown:[188,143,143,1],royalblue:[65,105,225,1],saddlebrown:[139,69,19,1],salmon:[250,128,114,1],sandybrown:[244,164,96,1],seagreen:[46,139,87,1],seashell:[255,245,238,1],sienna:[160,82,45,1],silver:[192,192,192,1],skyblue:[135,206,235,1],slateblue:[106,90,205,1],slategray:[112,128,144,1],slategrey:[112,128,144,1],snow:[255,250,250,1],springgreen:[0,255,127,1],steelblue:[70,130,180,1],tan:[210,180,140,1],teal:[0,128,128,1],thistle:[216,191,216,1],tomato:[255,99,71,1],turquoise:[64,224,208,1],violet:[238,130,238,1],wheat:[245,222,179,1],white:[255,255,255,1],whitesmoke:[245,245,245,1],yellow:[255,255,0,1],yellowgreen:[154,205,50,1]};function ur(r){return r=Math.round(r),r<0?0:r>255?255:r}function IT(r){return r=Math.round(r),r<0?0:r>360?360:r}function co(r){return r<0?0:r>1?1:r}function wh(r){var t=r;return t.length&&t.charAt(t.length-1)==="%"?ur(parseFloat(t)/100*255):ur(parseInt(t,10))}function $i(r){var t=r;return t.length&&t.charAt(t.length-1)==="%"?co(parseFloat(t)/100):co(parseFloat(t))}function Th(r,t,e){return e<0?e+=1:e>1&&(e-=1),e*6<1?r+(t-r)*e*6:e*2<1?t:e*3<2?r+(t-r)*(2/3-e)*6:r}function li(r,t,e){return r+(t-r)*e}function Ge(r,t,e,i,n){return r[0]=t,r[1]=e,r[2]=i,r[3]=n,r}function Ch(r,t){return r[0]=t[0],r[1]=t[1],r[2]=t[2],r[3]=t[3],r}var Qm=new Vr(20),fl=null;function sa(r,t){fl&&Ch(fl,t),fl=Qm.put(r,fl||t.slice())}function Jt(r,t){if(r){t=t||[];var e=Qm.get(r);if(e)return Ch(t,e);r=r+"";var i=r.replace(/ /g,"").toLowerCase();if(i in Km)return Ch(t,Km[i]),sa(r,t),t;var n=i.length;if(i.charAt(0)==="#"){if(n===4||n===5){var a=parseInt(i.slice(1,4),16);if(!(a>=0&&a<=4095)){Ge(t,0,0,0,1);return}return Ge(t,(a&3840)>>4|(a&3840)>>8,a&240|(a&240)>>4,a&15|(a&15)<<4,n===5?parseInt(i.slice(4),16)/15:1),sa(r,t),t}else if(n===7||n===9){var a=parseInt(i.slice(1,7),16);if(!(a>=0&&a<=16777215)){Ge(t,0,0,0,1);return}return Ge(t,(a&16711680)>>16,(a&65280)>>8,a&255,n===9?parseInt(i.slice(7),16)/255:1),sa(r,t),t}return}var o=i.indexOf("("),s=i.indexOf(")");if(o!==-1&&s+1===n){var l=i.substr(0,o),u=i.substr(o+1,s-(o+1)).split(","),f=1;switch(l){case"rgba":if(u.length!==4)return u.length===3?Ge(t,+u[0],+u[1],+u[2],1):Ge(t,0,0,0,1);f=$i(u.pop());case"rgb":if(u.length>=3)return Ge(t,wh(u[0]),wh(u[1]),wh(u[2]),u.length===3?f:$i(u[3])),sa(r,t),t;Ge(t,0,0,0,1);return;case"hsla":if(u.length!==4){Ge(t,0,0,0,1);return}return u[3]=$i(u[3]),Dh(u,t),sa(r,t),t;case"hsl":if(u.length!==3){Ge(t,0,0,0,1);return}return Dh(u,t),sa(r,t),t;default:return}}Ge(t,0,0,0,1)}}function Dh(r,t){var e=(parseFloat(r[0])%360+360)%360/360,i=$i(r[1]),n=$i(r[2]),a=n<=.5?n*(i+1):n+i-n*i,o=n*2-a;return t=t||[],Ge(t,ur(Th(o,a,e+1/3)*255),ur(Th(o,a,e)*255),ur(Th(o,a,e-1/3)*255),1),r.length===4&&(t[3]=r[3]),t}function NT(r){if(r){var t=r[0]/255,e=r[1]/255,i=r[2]/255,n=Math.min(t,e,i),a=Math.max(t,e,i),o=a-n,s=(a+n)/2,l,u;if(o===0)l=0,u=0;else{s<.5?u=o/(a+n):u=o/(2-a-n);var f=((a-t)/6+o/2)/o,h=((a-e)/6+o/2)/o,c=((a-i)/6+o/2)/o;t===a?l=c-h:e===a?l=1/3+f-c:i===a&&(l=2/3+h-f),l<0&&(l+=1),l>1&&(l-=1)}var p=[l*360,u,s];return r[3]!=null&&p.push(r[3]),p}}function Ah(r,t){var e=Jt(r);if(e){for(var i=0;i<3;i++)t<0?e[i]=e[i]*(1-t)|0:e[i]=(255-e[i])*t+e[i]|0,e[i]>255?e[i]=255:e[i]<0&&(e[i]=0);return xr(e,e.length===4?"rgba":"rgb")}}function kT(r){var t=Jt(r);if(t)return((1<<24)+(t[0]<<16)+(t[1]<<8)+ +t[2]).toString(16).slice(1)}function $m(r,t,e){if(!(!(t&&t.length)||!(r>=0&&r<=1))){e=e||[];var i=r*(t.length-1),n=Math.floor(i),a=Math.ceil(i),o=t[n],s=t[a],l=i-n;return e[0]=ur(li(o[0],s[0],l)),e[1]=ur(li(o[1],s[1],l)),e[2]=ur(li(o[2],s[2],l)),e[3]=co(li(o[3],s[3],l)),e}}var zT=$m;function hl(r,t,e){if(!(!(t&&t.length)||!(r>=0&&r<=1))){var i=r*(t.length-1),n=Math.floor(i),a=Math.ceil(i),o=Jt(t[n]),s=Jt(t[a]),l=i-n,u=xr([ur(li(o[0],s[0],l)),ur(li(o[1],s[1],l)),ur(li(o[2],s[2],l)),co(li(o[3],s[3],l))],"rgba");return e?{color:u,leftIndex:n,rightIndex:a,value:i}:u}}var FT=hl;function BT(r,t,e,i){var n=Jt(r);if(r)return n=NT(n),t!=null&&(n[0]=IT(t)),e!=null&&(n[1]=$i(e)),i!=null&&(n[2]=$i(i)),xr(Dh(n),"rgba")}function cl(r,t){var e=Jt(r);if(e&&t!=null)return e[3]=co(t),xr(e,"rgba")}function xr(r,t){if(!(!r||!r.length)){var e=r[0]+","+r[1]+","+r[2];return(t==="rgba"||t==="hsva"||t==="hsla")&&(e+=","+r[3]),t+"("+e+")"}}function Ji(r,t){var e=Jt(r);return e?(.299*e[0]+.587*e[1]+.114*e[2])*e[3]/255+(1-e[3])*t:0}function UT(){return xr([Math.round(Math.random()*255),Math.round(Math.random()*255),Math.round(Math.random()*255)],"rgb")}var jm=new Vr(100);function pl(r){if(F(r)){var t=jm.get(r);return t||(t=Ah(r,-.1),jm.put(r,t)),t}else if(Nr(r)){var e=I({},r);return e.colorStops=z(r.colorStops,function(i){return{offset:i.offset,color:Ah(i.color,-.1)}}),e}return r}function Jm(r){return r.type==="linear"}function tg(r){return r.type==="radial"}var YI=function(){return Y.hasGlobalWindow&&G(window.btoa)?function(r){return window.btoa(unescape(encodeURIComponent(r)))}:typeof Buffer<"u"?function(r){return Buffer.from(r).toString("base64")}:function(r){return null}}();var Eh=Array.prototype.slice;function Hr(r,t,e){return(t-r)*e+r}function Mh(r,t,e,i){for(var n=t.length,a=0;ai?t:r,a=Math.min(e,i),o=n[a-1]||{color:[0,0,0,0],offset:0},s=a;so;if(s)i.length=o;else for(var l=a;l=1},r.prototype.getAdditiveTrack=function(){return this._additiveTrack},r.prototype.addKeyframe=function(t,e,i){this._needsSort=!0;var n=this.keyframes,a=n.length,o=!1,s=rg,l=e;if(Mt(e)){var u=WT(e);s=u,(u===1&&!ot(e[0])||u===2&&!ot(e[0][0]))&&(o=!0)}else if(ot(e)&&!Vi(e))s=dl;else if(F(e))if(!isNaN(+e))s=dl;else{var f=Jt(e);f&&(l=f,s=mo)}else if(Nr(e)){var h=I({},l);h.colorStops=z(e.colorStops,function(p){return{offset:p.offset,color:Jt(p.color)}}),Jm(e)?s=Lh:tg(e)&&(s=Ph),l=h}a===0?this.valType=s:(s!==this.valType||s===rg)&&(o=!0),this.discrete=this.discrete||o;var c={time:t,value:l,rawValue:e,percent:0};return i&&(c.easing=i,c.easingFunc=G(i)?i:il[i]||ul(i)),n.push(c),c},r.prototype.prepare=function(t,e){var i=this.keyframes;this._needsSort&&i.sort(function(m,d){return m.time-d.time});for(var n=this.valType,a=i.length,o=i[a-1],s=this.discrete,l=ml(n),u=ig(n),f=0;f=0&&!(o[f].percent<=e);f--);f=c(f,s-2)}else{for(f=h;fe);f++);f=c(f-1,s-2)}v=o[f+1],p=o[f]}if(p&&v){this._lastFr=f,this._lastFrP=e;var d=v.percent-p.percent,g=d===0?1:c((e-p.percent)/d,1);v.easingFunc&&(g=v.easingFunc(g));var y=i?this._additiveValue:u?vo:t[l];if((ml(a)||u)&&!y&&(y=this._additiveValue=[]),this.discrete)t[l]=g<1?p.rawValue:v.rawValue;else if(ml(a))a===yl?Mh(y,p[n],v[n],g):VT(y,p[n],v[n],g);else if(ig(a)){var _=p[n],x=v[n],b=a===Lh;t[l]={type:b?"linear":"radial",x:Hr(_.x,x.x,g),y:Hr(_.y,x.y,g),colorStops:z(_.colorStops,function(T,C){var A=x.colorStops[C];return{offset:Hr(T.offset,A.offset,g),color:gl(Mh([],T.color,A.color,g))}}),global:x.global},b?(t[l].x2=Hr(_.x2,x.x2,g),t[l].y2=Hr(_.y2,x.y2,g)):t[l].r=Hr(_.r,x.r,g)}else if(u)Mh(y,p[n],v[n],g),i||(t[l]=gl(y));else{var S=Hr(p[n],v[n],g);i?this._additiveValue=S:t[l]=S}i&&this._addToTarget(t)}}},r.prototype._addToTarget=function(t){var e=this.valType,i=this.propName,n=this._additiveValue;e===dl?t[i]=t[i]+n:e===mo?(Jt(t[i],vo),vl(vo,vo,n,1),t[i]=gl(vo)):e===yl?vl(t[i],t[i],n,1):e===ng&&eg(t[i],t[i],n,1)},r}(),XT=function(){function r(t,e,i,n){if(this._tracks={},this._trackKeys=[],this._maxTime=0,this._started=0,this._clip=null,this._target=t,this._loop=e,e&&n){Ui("Can' use additive animation on looped animation.");return}this._additiveAnimators=n,this._allowDiscrete=i}return r.prototype.getMaxTime=function(){return this._maxTime},r.prototype.getDelay=function(){return this._delay},r.prototype.getLoop=function(){return this._loop},r.prototype.getTarget=function(){return this._target},r.prototype.changeTarget=function(t){this._target=t},r.prototype.when=function(t,e,i){return this.whenWithKeys(t,e,rt(e),i)},r.prototype.whenWithKeys=function(t,e,i,n){for(var a=this._tracks,o=0;o0&&l.addKeyframe(0,tn(u),n),this._trackKeys.push(s)}l.addKeyframe(t,tn(e[s]),n)}return this._maxTime=Math.max(this._maxTime,t),this},r.prototype.pause=function(){this._clip.pause(),this._paused=!0},r.prototype.resume=function(){this._clip.resume(),this._paused=!1},r.prototype.isPaused=function(){return!!this._paused},r.prototype.duration=function(t){return this._maxTime=t,this._force=!0,this},r.prototype._doneCallback=function(){this._setTracksFinished(),this._clip=null;var t=this._doneCbs;if(t)for(var e=t.length,i=0;i0)){this._started=1;for(var e=this,i=[],n=this._maxTime||0,a=0;a1){var s=o.pop();a.addKeyframe(s.time,t[n]),a.prepare(this._maxTime,a.getAdditiveTrack())}}}},r}(),go=XT;function en(){return new Date().getTime()}var qT=function(r){O(t,r);function t(e){var i=r.call(this)||this;return i._running=!1,i._time=0,i._pausedTime=0,i._pauseStart=0,i._paused=!1,e=e||{},i.stage=e.stage||{},i}return t.prototype.addClip=function(e){e.animation&&this.removeClip(e),this._head?(this._tail.next=e,e.prev=this._tail,e.next=null,this._tail=e):this._head=this._tail=e,e.animation=this},t.prototype.addAnimator=function(e){e.animation=this;var i=e.getClip();i&&this.addClip(i)},t.prototype.removeClip=function(e){if(e.animation){var i=e.prev,n=e.next;i?i.next=n:this._head=n,n?n.prev=i:this._tail=i,e.next=e.prev=e.animation=null}},t.prototype.removeAnimator=function(e){var i=e.getClip();i&&this.removeClip(i),e.animation=null},t.prototype.update=function(e){for(var i=en()-this._pausedTime,n=i-this._time,a=this._head;a;){var o=a.next,s=a.step(i,n);s&&(a.ondestroy(),this.removeClip(a)),a=o}this._time=i,e||(this.trigger("frame",n),this.stage.update&&this.stage.update())},t.prototype._startLoop=function(){var e=this;this._running=!0;function i(){e._running&&(ho(i),!e._paused&&e.update())}ho(i)},t.prototype.start=function(){this._running||(this._time=en(),this._pausedTime=0,this._startLoop())},t.prototype.stop=function(){this._running=!1},t.prototype.pause=function(){this._paused||(this._pauseStart=en(),this._paused=!0)},t.prototype.resume=function(){this._paused&&(this._pausedTime+=en()-this._pauseStart,this._paused=!1)},t.prototype.clear=function(){for(var e=this._head;e;){var i=e.next;e.prev=e.next=e.animation=null,e=i}this._head=this._tail=null},t.prototype.isFinished=function(){return this._head==null},t.prototype.animate=function(e,i){i=i||{},this.start();var n=new go(e,i.loop);return this.addAnimator(n),n},t}(jt),ag=qT;var ZT=300,Oh=Y.domSupported,Rh=function(){var r=["click","dblclick","mousewheel","wheel","mouseout","mouseup","mousedown","mousemove","contextmenu"],t=["touchstart","touchend","touchmove"],e={pointerdown:1,pointerup:1,pointermove:1,pointerout:1},i=z(r,function(n){var a=n.replace("mouse","pointer");return e.hasOwnProperty(a)?a:n});return{mouse:r,touch:t,pointer:i}}(),og={mouse:["mousemove","mouseup"],pointer:["pointermove","pointerup"]},sg=!1;function kh(r){var t=r.pointerType;return t==="pen"||t==="touch"}function KT(r){r.touching=!0,r.touchTimer!=null&&(clearTimeout(r.touchTimer),r.touchTimer=null),r.touchTimer=setTimeout(function(){r.touching=!1,r.touchTimer=null},700)}function Ih(r){r&&(r.zrByTouch=!0)}function jT(r,t){return ve(r.dom,new QT(r,t),!0)}function ug(r,t){for(var e=t,i=!1;e&&e.nodeType!==9&&!(i=e.domBelongToZr||e!==t&&e===r.painterRoot);)e=e.parentNode;return i}var QT=function(){function r(t,e){this.stopPropagation=kt,this.stopImmediatePropagation=kt,this.preventDefault=kt,this.type=e.type,this.target=this.currentTarget=t.dom,this.pointerType=e.pointerType,this.clientX=e.clientX,this.clientY=e.clientY}return r}(),fr={mousedown:function(r){r=ve(this.dom,r),this.__mayPointerCapture=[r.zrX,r.zrY],this.trigger("mousedown",r)},mousemove:function(r){r=ve(this.dom,r);var t=this.__mayPointerCapture;t&&(r.zrX!==t[0]||r.zrY!==t[1])&&this.__togglePointerCapture(!0),this.trigger("mousemove",r)},mouseup:function(r){r=ve(this.dom,r),this.__togglePointerCapture(!1),this.trigger("mouseup",r)},mouseout:function(r){r=ve(this.dom,r);var t=r.toElement||r.relatedTarget;ug(this,t)||(this.__pointerCapturing&&(r.zrEventControl="no_globalout"),this.trigger("mouseout",r))},wheel:function(r){sg=!0,r=ve(this.dom,r),this.trigger("mousewheel",r)},mousewheel:function(r){sg||(r=ve(this.dom,r),this.trigger("mousewheel",r))},touchstart:function(r){r=ve(this.dom,r),Ih(r),this.__lastTouchMoment=new Date,this.handler.processGesture(r,"start"),fr.mousemove.call(this,r),fr.mousedown.call(this,r)},touchmove:function(r){r=ve(this.dom,r),Ih(r),this.handler.processGesture(r,"change"),fr.mousemove.call(this,r)},touchend:function(r){r=ve(this.dom,r),Ih(r),this.handler.processGesture(r,"end"),fr.mouseup.call(this,r),+new Date-+this.__lastTouchMomentvg||r<-vg}var an=[],la=[],Fh=lr(),Bh=Math.abs,eC=function(){function r(){}return r.prototype.getLocalTransform=function(t){return r.getLocalTransform(this,t)},r.prototype.setPosition=function(t){this.x=t[0],this.y=t[1]},r.prototype.setScale=function(t){this.scaleX=t[0],this.scaleY=t[1]},r.prototype.setSkew=function(t){this.skewX=t[0],this.skewY=t[1]},r.prototype.setOrigin=function(t){this.originX=t[0],this.originY=t[1]},r.prototype.needLocalTransform=function(){return nn(this.rotation)||nn(this.x)||nn(this.y)||nn(this.scaleX-1)||nn(this.scaleY-1)||nn(this.skewX)||nn(this.skewY)},r.prototype.updateTransform=function(){var t=this.parent&&this.parent.transform,e=this.needLocalTransform(),i=this.transform;if(!(e||t)){i&&(pg(i),this.invTransform=null);return}i=i||lr(),e?this.getLocalTransform(i):pg(i),t&&(e?Ve(i,t,i):Js(i,t)),this.transform=i,this._resolveGlobalScaleRatio(i)},r.prototype._resolveGlobalScaleRatio=function(t){var e=this.globalScaleRatio;if(e!=null&&e!==1){this.getGlobalScale(an);var i=an[0]<0?-1:1,n=an[1]<0?-1:1,a=((an[0]-i)*e+i)/an[0]||0,o=((an[1]-n)*e+n)/an[1]||0;t[0]*=a,t[1]*=a,t[2]*=o,t[3]*=o}this.invTransform=this.invTransform||lr(),Br(this.invTransform,t)},r.prototype.getComputedTransform=function(){for(var t=this,e=[];t;)e.push(t),t=t.parent;for(;t=e.pop();)t.updateTransform();return this.transform},r.prototype.setLocalTransform=function(t){if(t){var e=t[0]*t[0]+t[1]*t[1],i=t[2]*t[2]+t[3]*t[3],n=Math.atan2(t[1],t[0]),a=Math.PI/2+n-Math.atan2(t[3],t[2]);i=Math.sqrt(i)*Math.cos(a),e=Math.sqrt(e),this.skewX=a,this.skewY=0,this.rotation=-n,this.x=+t[4],this.y=+t[5],this.scaleX=e,this.scaleY=i,this.originX=0,this.originY=0}},r.prototype.decomposeTransform=function(){if(this.transform){var t=this.parent,e=this.transform;t&&t.transform&&(t.invTransform=t.invTransform||lr(),Ve(la,t.invTransform,e),e=la);var i=this.originX,n=this.originY;(i||n)&&(Fh[4]=i,Fh[5]=n,Ve(la,e,Fh),la[4]-=i,la[5]-=n,e=la),this.setLocalTransform(e)}},r.prototype.getGlobalScale=function(t){var e=this.transform;return t=t||[],e?(t[0]=Math.sqrt(e[0]*e[0]+e[1]*e[1]),t[1]=Math.sqrt(e[2]*e[2]+e[3]*e[3]),e[0]<0&&(t[0]=-t[0]),e[3]<0&&(t[1]=-t[1]),t):(t[0]=1,t[1]=1,t)},r.prototype.transformCoordToLocal=function(t,e){var i=[t,e],n=this.invTransform;return n&&Pt(i,i,n),i},r.prototype.transformCoordToGlobal=function(t,e){var i=[t,e],n=this.transform;return n&&Pt(i,i,n),i},r.prototype.getLineScale=function(){var t=this.transform;return t&&Bh(t[0]-1)>1e-10&&Bh(t[3]-1)>1e-10?Math.sqrt(Bh(t[0]*t[3]-t[2]*t[1])):1},r.prototype.copyTransform=function(t){rC(this,t)},r.getLocalTransform=function(t,e){e=e||[];var i=t.originX||0,n=t.originY||0,a=t.scaleX,o=t.scaleY,s=t.anchorX,l=t.anchorY,u=t.rotation||0,f=t.x,h=t.y,c=t.skewX?Math.tan(t.skewX):0,p=t.skewY?Math.tan(-t.skewY):0;if(i||n||s||l){var v=i+s,m=n+l;e[4]=-v*a-c*m*o,e[5]=-m*o-p*v*a}else e[4]=e[5]=0;return e[0]=a,e[3]=o,e[1]=p*a,e[2]=c*o,u&&Wi(e,e,u),e[4]+=i+f,e[5]+=n+h,e},r.initDefaultProps=function(){var t=r.prototype;t.scaleX=t.scaleY=t.globalScaleRatio=1,t.x=t.y=t.originX=t.originY=t.skewX=t.skewY=t.rotation=t.anchorX=t.anchorY=0}(),r}(),Ee=["x","y","originX","originY","anchorX","anchorY","rotation","scaleX","scaleY","skewX","skewY"];function rC(r,t){for(var e=0;e=0?parseFloat(r)/100*t:parseFloat(r):r}function sn(r,t,e){var i=t.position||"inside",n=t.distance!=null?t.distance:5,a=e.height,o=e.width,s=a/2,l=e.x,u=e.y,f="left",h="top";if(i instanceof Array)l+=We(i[0],e.width),u+=We(i[1],e.height),f=null,h=null;else switch(i){case"left":l-=n,u+=s,f="right",h="middle";break;case"right":l+=n+o,u+=s,h="middle";break;case"top":l+=o/2,u-=n,f="center",h="bottom";break;case"bottom":l+=o/2,u+=a+n,f="center";break;case"inside":l+=o/2,u+=s,f="center",h="middle";break;case"insideLeft":l+=n,u+=s,h="middle";break;case"insideRight":l+=o-n,u+=s,f="right",h="middle";break;case"insideTop":l+=o/2,u+=n,f="center";break;case"insideBottom":l+=o/2,u+=a-n,f="center",h="bottom";break;case"insideTopLeft":l+=n,u+=n;break;case"insideTopRight":l+=o-n,u+=n,f="right";break;case"insideBottomLeft":l+=n,u+=a-n,h="bottom";break;case"insideBottomRight":l+=o-n,u+=a-n,f="right",h="bottom";break}return r=r||{},r.x=l,r.y=u,r.align=f,r.verticalAlign=h,r}var Uh="__zr_normal__",Vh=Ee.concat(["ignore"]),iC=Vt(Ee,function(r,t){return r[t]=!0,r},{ignore:!1}),ha={},nC=new J(0,0,0,0),Wh=function(){function r(t){this.id=Ja(),this.animators=[],this.currentStates=[],this.states={},this._init(t)}return r.prototype._init=function(t){this.attr(t)},r.prototype.drift=function(t,e,i){switch(this.draggable){case"horizontal":e=0;break;case"vertical":t=0;break}var n=this.transform;n||(n=this.transform=[1,0,0,1,0,0]),n[4]+=t,n[5]+=e,this.decomposeTransform(),this.markRedraw()},r.prototype.beforeUpdate=function(){},r.prototype.afterUpdate=function(){},r.prototype.update=function(){this.updateTransform(),this.__dirty&&this.updateInnerText()},r.prototype.updateInnerText=function(t){var e=this._textContent;if(e&&(!e.ignore||t)){this.textConfig||(this.textConfig={});var i=this.textConfig,n=i.local,a=e.innerTransformable,o=void 0,s=void 0,l=!1;a.parent=n?this:null;var u=!1;if(a.copyTransform(e),i.position!=null){var f=nC;i.layoutRect?f.copy(i.layoutRect):f.copy(this.getBoundingRect()),n||f.applyTransform(this.transform),this.calculateTextPosition?this.calculateTextPosition(ha,i,f):sn(ha,i,f),a.x=ha.x,a.y=ha.y,o=ha.align,s=ha.verticalAlign;var h=i.origin;if(h&&i.rotation!=null){var c=void 0,p=void 0;h==="center"?(c=f.width*.5,p=f.height*.5):(c=We(h[0],f.width),p=We(h[1],f.height)),u=!0,a.originX=-a.x+c+(n?0:f.x),a.originY=-a.y+p+(n?0:f.y)}}i.rotation!=null&&(a.rotation=i.rotation);var v=i.offset;v&&(a.x+=v[0],a.y+=v[1],u||(a.originX=-v[0],a.originY=-v[1]));var m=i.inside==null?typeof i.position=="string"&&i.position.indexOf("inside")>=0:i.inside,d=this._innerTextDefaultStyle||(this._innerTextDefaultStyle={}),g=void 0,y=void 0,_=void 0;m&&this.canBeInsideText()?(g=i.insideFill,y=i.insideStroke,(g==null||g==="auto")&&(g=this.getInsideTextFill()),(y==null||y==="auto")&&(y=this.getInsideTextStroke(g),_=!0)):(g=i.outsideFill,y=i.outsideStroke,(g==null||g==="auto")&&(g=this.getOutsideFill()),(y==null||y==="auto")&&(y=this.getOutsideStroke(g),_=!0)),g=g||"#000",(g!==d.fill||y!==d.stroke||_!==d.autoStroke||o!==d.align||s!==d.verticalAlign)&&(l=!0,d.fill=g,d.stroke=y,d.autoStroke=_,d.align=o,d.verticalAlign=s,e.setDefaultTextStyle(d)),e.__dirty|=zt,l&&e.dirtyStyle(!0)}},r.prototype.canBeInsideText=function(){return!0},r.prototype.getInsideTextFill=function(){return"#fff"},r.prototype.getInsideTextStroke=function(t){return"#000"},r.prototype.getOutsideFill=function(){return this.__zr&&this.__zr.isDarkMode()?xo:_o},r.prototype.getOutsideStroke=function(t){var e=this.__zr&&this.__zr.getBackgroundColor(),i=typeof e=="string"&&Jt(e);i||(i=[255,255,255,1]);for(var n=i[3],a=this.__zr.isDarkMode(),o=0;o<3;o++)i[o]=i[o]*n+(a?0:255)*(1-n);return i[3]=1,xr(i,"rgba")},r.prototype.traverse=function(t,e){},r.prototype.attrKV=function(t,e){t==="textConfig"?this.setTextConfig(e):t==="textContent"?this.setTextContent(e):t==="clipPath"?this.setClipPath(e):t==="extra"?(this.extra=this.extra||{},I(this.extra,e)):this[t]=e},r.prototype.hide=function(){this.ignore=!0,this.markRedraw()},r.prototype.show=function(){this.ignore=!1,this.markRedraw()},r.prototype.attr=function(t,e){if(typeof t=="string")this.attrKV(t,e);else if(H(t))for(var i=t,n=rt(i),a=0;a0},r.prototype.getState=function(t){return this.states[t]},r.prototype.ensureState=function(t){var e=this.states;return e[t]||(e[t]={}),e[t]},r.prototype.clearStates=function(t){this.useState(Uh,!1,t)},r.prototype.useState=function(t,e,i,n){var a=t===Uh,o=this.hasState();if(!(!o&&a)){var s=this.currentStates,l=this.stateTransition;if(!(K(s,t)>=0&&(e||s.length===1))){var u;if(this.stateProxy&&!a&&(u=this.stateProxy(t)),u||(u=this.states&&this.states[t]),!u&&!a){Ui("State "+t+" not exists.");return}a||this.saveCurrentToNormalState(u);var f=!!(u&&u.hoverLayer||n);f&&this._toggleHoverLayerFlag(!0),this._applyStateObj(t,u,this._normalState,e,!i&&!this.__inHover&&l&&l.duration>0,l);var h=this._textContent,c=this._textGuide;return h&&h.useState(t,e,i,f),c&&c.useState(t,e,i,f),a?(this.currentStates=[],this._normalState={}):e?this.currentStates.push(t):this.currentStates=[t],this._updateAnimationTargets(),this.markRedraw(),!f&&this.__inHover&&(this._toggleHoverLayerFlag(!1),this.__dirty&=~zt),u}}},r.prototype.useStates=function(t,e,i){if(!t.length)this.clearStates();else{var n=[],a=this.currentStates,o=t.length,s=o===a.length;if(s){for(var l=0;l0,v);var m=this._textContent,d=this._textGuide;m&&m.useStates(t,e,c),d&&d.useStates(t,e,c),this._updateAnimationTargets(),this.currentStates=t.slice(),this.markRedraw(),!c&&this.__inHover&&(this._toggleHoverLayerFlag(!1),this.__dirty&=~zt)}},r.prototype.isSilent=function(){for(var t=this.silent,e=this.parent;!t&&e;){if(e.silent){t=!0;break}e=e.parent}return t},r.prototype._updateAnimationTargets=function(){for(var t=0;t=0){var i=this.currentStates.slice();i.splice(e,1),this.useStates(i)}},r.prototype.replaceState=function(t,e,i){var n=this.currentStates.slice(),a=K(n,t),o=K(n,e)>=0;a>=0?o?n.splice(a,1):n[a]=e:i&&!o&&n.push(e),this.useStates(n)},r.prototype.toggleState=function(t,e){e?this.useState(t,!0):this.removeState(t)},r.prototype._mergeStates=function(t){for(var e={},i,n=0;n=0&&a.splice(o,1)}),this.animators.push(t),i&&i.animation.addAnimator(t),i&&i.wakeUp()},r.prototype.updateDuringAnimation=function(t){this.markRedraw()},r.prototype.stopAnimation=function(t,e){for(var i=this.animators,n=i.length,a=[],o=0;o0&&e.during&&a[0].during(function(v,m){e.during(m)});for(var c=0;c0||n.force&&!o.length){var C=void 0,A=void 0,M=void 0;if(s){A={},c&&(C={});for(var x=0;x<_;x++){var g=m[x];A[g]=e[g],c?C[g]=i[g]:e[g]=i[g]}}else if(c){M={};for(var x=0;x<_;x++){var g=m[x];M[g]=tn(e[g]),oC(e,i,g)}}var b=new go(e,!1,!1,h?dt(v,function(L){return L.targetName===t}):null);b.targetName=t,n.scope&&(b.scope=n.scope),c&&C&&b.whenWithKeys(0,C,m),M&&b.whenWithKeys(0,M,m),b.whenWithKeys(u??500,s?A:i,m).delay(f||0),r.addAnimator(b,t),o.push(b)}}var Sl=Wh;var _g=function(r){O(t,r);function t(e){var i=r.call(this)||this;return i.isGroup=!0,i._children=[],i.attr(e),i}return t.prototype.childrenRef=function(){return this._children},t.prototype.children=function(){return this._children.slice()},t.prototype.childAt=function(e){return this._children[e]},t.prototype.childOfName=function(e){for(var i=this._children,n=0;n=0&&(n.splice(a,0,e),this._doAdd(e))}return this},t.prototype.replace=function(e,i){var n=K(this._children,e);return n>=0&&this.replaceAt(i,n),this},t.prototype.replaceAt=function(e,i){var n=this._children,a=n[i];if(e&&e!==this&&e.parent!==this&&e!==a){n[i]=e,a.parent=null;var o=this.__zr;o&&a.removeSelfFromZr(o),this._doAdd(e)}return this},t.prototype._doAdd=function(e){e.parent&&e.parent.remove(e),e.parent=this;var i=this.__zr;i&&i!==e.__zr&&e.addSelfToZr(i),i&&i.refresh()},t.prototype.remove=function(e){var i=this.__zr,n=this._children,a=K(n,e);return a<0?this:(n.splice(a,1),e.parent=null,i&&e.removeSelfFromZr(i),i&&i.refresh(),this)},t.prototype.removeAll=function(){for(var e=this._children,i=this.__zr,n=0;n0&&(this._stillFrameAccum++,this._stillFrameAccum>this._sleepAfterStill&&this.animation.stop())},r.prototype.setSleepAfterStill=function(t){this._sleepAfterStill=t},r.prototype.wakeUp=function(){this._disposed||(this.animation.start(),this._stillFrameAccum=0)},r.prototype.refreshHover=function(){this._needsRefreshHover=!0},r.prototype.refreshHoverImmediately=function(){this._disposed||(this._needsRefreshHover=!1,this.painter.refreshHover&&this.painter.getType()==="canvas"&&this.painter.refreshHover())},r.prototype.resize=function(t){this._disposed||(t=t||{},this.painter.resize(t.width,t.height),this.handler.resize())},r.prototype.clearAnimation=function(){this._disposed||this.animation.clear()},r.prototype.getWidth=function(){if(!this._disposed)return this.painter.getWidth()},r.prototype.getHeight=function(){if(!this._disposed)return this.painter.getHeight()},r.prototype.setCursorStyle=function(t){this._disposed||this.handler.setCursorStyle(t)},r.prototype.findHover=function(t,e){if(!this._disposed)return this.handler.findHover(t,e)},r.prototype.on=function(t,e,i){return this._disposed||this.handler.on(t,e,i),this},r.prototype.off=function(t,e){this._disposed||this.handler.off(t,e)},r.prototype.trigger=function(t,e){this._disposed||this.handler.trigger(t,e)},r.prototype.clear=function(){if(!this._disposed){for(var t=this.storage.getRoots(),e=0;e0){if(r<=n)return o;if(r>=a)return s}else{if(r>=n)return o;if(r<=a)return s}else{if(r===n)return o;if(r===a)return s}return(r-n)/l*u+o}function Tt(r,t){switch(r){case"center":case"middle":r="50%";break;case"left":case"top":r="0%";break;case"right":case"bottom":r="100%";break}return F(r)?gC(r).match(/%$/)?parseFloat(r)/100*t:parseFloat(r):r==null?NaN:+r}function mt(r,t,e){return t==null&&(t=10),t=Math.min(Math.max(0,t),Sg),r=(+r).toFixed(t),e?r:+r}function wo(r){return r.sort(function(t,e){return t-e}),r}function Qt(r){if(r=+r,isNaN(r))return 0;if(r>1e-14){for(var t=1,e=0;e<15;e++,t*=10)if(Math.round(r*t)/t===r)return e}return Zh(r)}function Zh(r){var t=r.toString().toLowerCase(),e=t.indexOf("e"),i=e>0?+t.slice(e+1):0,n=e>0?e:t.length,a=t.indexOf("."),o=a<0?0:n-1-a;return Math.max(0,o-i)}function Cl(r,t){var e=Math.log,i=Math.LN10,n=Math.floor(e(r[1]-r[0])/i),a=Math.round(e(Math.abs(t[1]-t[0]))/i),o=Math.min(Math.max(-n+a,0),20);return isFinite(o)?o:20}function bg(r,t,e){if(!r[t])return 0;var i=yC(r,e);return i[t]||0}function yC(r,t){var e=Vt(r,function(p,v){return p+(isNaN(v)?0:v)},0);if(e===0)return[];for(var i=Math.pow(10,t),n=z(r,function(p){return(isNaN(p)?0:p)/e*i*100}),a=i*100,o=z(n,function(p){return Math.floor(p)}),s=Vt(o,function(p,v){return p+v},0),l=z(n,function(p,v){return p-o[v]});su&&(u=l[h],f=h);++o[f],l[f]=0,++s}return z(o,function(p){return p/i})}function wg(r,t){var e=Math.max(Qt(r),Qt(t)),i=r+t;return e>Sg?i:mt(i,e)}var Tg=9007199254740991;function To(r){var t=Math.PI*2;return(r%t+t)%t}function un(r){return r>-xg&&r=10&&t++,t}function pa(r,t){var e=ca(r),i=Math.pow(10,e),n=r/i,a;return t?n<1.5?a=1:n<2.5?a=2:n<4?a=3:n<7?a=5:a=10:n<1?a=1:n<2?a=2:n<3?a=3:n<5?a=5:a=10,r=a*i,e>=-20?+r.toFixed(e<0?-e:0):r}function Cg(r,t){var e=(r.length-1)*t+1,i=Math.floor(e),n=+r[i-1],a=e-i;return a?n+a*(r[i]-n):n}function Dg(r){r.sort(function(l,u){return s(l,u,0)?-1:1});for(var t=-1/0,e=1,i=0;i=0||a&&K(a,l)<0)){var u=i.getShallow(l,t);u!=null&&(o[r[s][0]]=u)}}return o}}var NC=[["fill","color"],["shadowBlur"],["shadowOffsetX"],["shadowOffsetY"],["opacity"],["shadowColor"]],kC=Sr(NC),Bg=function(){function r(){}return r.prototype.getAreaStyle=function(t,e){return kC(this,t,e)},r}();var tc=new Vr(50);function Vg(r){if(typeof r=="string"){var t=tc.get(r);return t&&t.image}else return r}function ec(r,t,e,i,n){if(r)if(typeof r=="string"){if(t&&t.__zrImageSrc===r||!e)return t;var a=tc.get(r),o={hostEl:e,cb:i,cbPayload:n};return a?(t=a.image,!ga(t)&&a.pending.push(o)):(t=se.loadImage(r,Ug,Ug),t.__zrImageSrc=r,tc.put(r,t.__cachedImgObj={image:t,pending:[o]})),t}else return r;else return t}function Ug(){var r=this.__cachedImgObj;this.onload=this.onerror=this.__cachedImgObj=null;for(var t=0;t=o;l++)s-=o;var u=de(e,t);return u>s&&(e="",u=0),s=r-u,n.ellipsis=e,n.ellipsisWidth=u,n.contentWidth=s,n.containerWidth=r,n}function Wg(r,t){var e=t.containerWidth,i=t.font,n=t.contentWidth;if(!e)return"";var a=de(r,i);if(a<=e)return r;for(var o=0;;o++){if(a<=n||o>=t.maxIterations){r+=t.ellipsis;break}var s=o===0?FC(r,n,t.ascCharWidth,t.cnCharWidth):a>0?Math.floor(r.length*n/a):0;r=r.substr(0,s),a=de(r,i)}return r===""&&(r=t.placeholder),r}function FC(r,t,e,i){for(var n=0,a=0,o=r.length;ap&&u){var v=Math.floor(p/s);h=h.slice(0,v)}if(r&&a&&f!=null)for(var m=Gg(f,n,t.ellipsis,{minChar:t.truncateMinChar,placeholder:t.placeholder}),d=0;ds&&ic(e,r.substring(s,u),t,o),ic(e,l[2],t,o,l[1]),s=rc.lastIndex}sn){b>0?(y.tokens=y.tokens.slice(0,b),d(y,x,_),e.lines=e.lines.slice(0,g+1)):e.lines=e.lines.slice(0,g);break t}var L=T.width,R=L==null||L==="auto";if(typeof L=="string"&&L.charAt(L.length-1)==="%")S.percentWidth=L,f.push(S),S.contentWidth=de(S.text,M);else{if(R){var E=T.backgroundColor,P=E&&E.image;P&&(P=Vg(P),ga(P)&&(S.width=Math.max(S.width,P.width*D/P.height)))}var k=v&&i!=null?i-x:null;k!=null&&k0&&v+i.accumWidth>i.width&&(f=t.split(` +`),u=!0),i.accumWidth=v}else{var m=qg(t,l,i.width,i.breakAll,i.accumWidth);i.accumWidth=m.accumWidth+p,h=m.linesWidths,f=m.lines}}else f=t.split(` +`);for(var d=0;d=32&&t<=591||t>=880&&t<=4351||t>=4608&&t<=5119||t>=7680&&t<=8303}var HC=Vt(",&?/;] ".split(""),function(r,t){return r[t]=!0,r},{});function GC(r){return VC(r)?!!HC[r]:!0}function qg(r,t,e,i,n){for(var a=[],o=[],s="",l="",u=0,f=0,h=0;he:n+f+p>e){f?(s||l)&&(v?(s||(s=l,l="",u=0,f=u),a.push(s),o.push(f-u),l+=c,u+=p,s="",f=u):(l&&(s+=l,l="",u=0),a.push(s),o.push(f),s=c,f=p)):v?(a.push(l),o.push(u),l=c,u=p):(a.push(c),o.push(p));continue}f+=p,v?(l+=c,u+=p):(l&&(s+=l,l="",u=0),s+=c)}return!a.length&&!s&&(s=r,l="",u=0),l&&(s+=l),s&&(a.push(s),o.push(f)),a.length===1&&(f+=n),{accumWidth:f,lines:a,linesWidths:o}}var oc="__zr_style_"+Math.round(Math.random()*10),br={shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,shadowColor:"#000",opacity:1,blend:"source-over"},pn={style:{shadowBlur:!0,shadowOffsetX:!0,shadowOffsetY:!0,shadowColor:!0,opacity:!0}};br[oc]=!0;var Zg=["z","z2","invisible"],WC=["invisible"],YC=function(r){O(t,r);function t(e){return r.call(this,e)||this}return t.prototype._init=function(e){for(var i=rt(e),n=0;n1e-4){s[0]=r-e,s[1]=t-i,l[0]=r+e,l[1]=t+i;return}if(Pl[0]=lc(n)*e+r,Pl[1]=sc(n)*i+t,Ol[0]=lc(a)*e+r,Ol[1]=sc(a)*i+t,u(s,Pl,Ol),f(l,Pl,Ol),n=n%vn,n<0&&(n=n+vn),a=a%vn,a<0&&(a=a+vn),n>a&&!o?a+=vn:nn&&(Rl[0]=lc(p)*e+r,Rl[1]=sc(p)*i+t,u(s,Rl,s),f(l,Rl,l))}var xt={M:1,L:2,C:3,Q:4,A:5,Z:6,R:7},dn=[],mn=[],wr=[],hi=[],Tr=[],Cr=[],fc=Math.min,hc=Math.max,gn=Math.cos,yn=Math.sin,Wr=Math.abs,vc=Math.PI,ci=vc*2,cc=typeof Float32Array<"u",Eo=[];function pc(r){var t=Math.round(r/vc*1e8)/1e8;return t%2*vc}function qC(r,t){var e=pc(r[0]);e<0&&(e+=ci);var i=e-r[0],n=r[1];n+=i,!t&&n-e>=ci?n=e+ci:t&&e-n>=ci?n=e-ci:!t&&e>n?n=e+(ci-pc(e-n)):t&&e0&&(this._ux=Wr(i/rn/t)||0,this._uy=Wr(i/rn/e)||0)},r.prototype.setDPR=function(t){this.dpr=t},r.prototype.setContext=function(t){this._ctx=t},r.prototype.getContext=function(){return this._ctx},r.prototype.beginPath=function(){return this._ctx&&this._ctx.beginPath(),this.reset(),this},r.prototype.reset=function(){this._saveData&&(this._len=0),this._pathSegLen&&(this._pathSegLen=null,this._pathLen=0),this._version++},r.prototype.moveTo=function(t,e){return this._drawPendingPt(),this.addData(xt.M,t,e),this._ctx&&this._ctx.moveTo(t,e),this._x0=t,this._y0=e,this._xi=t,this._yi=e,this},r.prototype.lineTo=function(t,e){var i=Wr(t-this._xi),n=Wr(e-this._yi),a=i>this._ux||n>this._uy;if(this.addData(xt.L,t,e),this._ctx&&a&&this._ctx.lineTo(t,e),a)this._xi=t,this._yi=e,this._pendingPtDist=0;else{var o=i*i+n*n;o>this._pendingPtDist&&(this._pendingPtX=t,this._pendingPtY=e,this._pendingPtDist=o)}return this},r.prototype.bezierCurveTo=function(t,e,i,n,a,o){return this._drawPendingPt(),this.addData(xt.C,t,e,i,n,a,o),this._ctx&&this._ctx.bezierCurveTo(t,e,i,n,a,o),this._xi=a,this._yi=o,this},r.prototype.quadraticCurveTo=function(t,e,i,n){return this._drawPendingPt(),this.addData(xt.Q,t,e,i,n),this._ctx&&this._ctx.quadraticCurveTo(t,e,i,n),this._xi=i,this._yi=n,this},r.prototype.arc=function(t,e,i,n,a,o){this._drawPendingPt(),Eo[0]=n,Eo[1]=a,qC(Eo,o),n=Eo[0],a=Eo[1];var s=a-n;return this.addData(xt.A,t,e,i,i,n,s,0,o?0:1),this._ctx&&this._ctx.arc(t,e,i,n,a,o),this._xi=gn(a)*i+t,this._yi=yn(a)*i+e,this},r.prototype.arcTo=function(t,e,i,n,a){return this._drawPendingPt(),this._ctx&&this._ctx.arcTo(t,e,i,n,a),this},r.prototype.rect=function(t,e,i,n){return this._drawPendingPt(),this._ctx&&this._ctx.rect(t,e,i,n),this.addData(xt.R,t,e,i,n),this},r.prototype.closePath=function(){this._drawPendingPt(),this.addData(xt.Z);var t=this._ctx,e=this._x0,i=this._y0;return t&&t.closePath(),this._xi=e,this._yi=i,this},r.prototype.fill=function(t){t&&t.fill(),this.toStatic()},r.prototype.stroke=function(t){t&&t.stroke(),this.toStatic()},r.prototype.len=function(){return this._len},r.prototype.setData=function(t){var e=t.length;!(this.data&&this.data.length===e)&&cc&&(this.data=new Float32Array(e));for(var i=0;if.length&&(this._expandData(),f=this.data);for(var h=0;h0&&(this._ctx&&this._ctx.lineTo(this._pendingPtX,this._pendingPtY),this._pendingPtDist=0)},r.prototype._expandData=function(){if(!(this.data instanceof Array)){for(var t=[],e=0;e11&&(this.data=new Float32Array(t)))}},r.prototype.getBoundingRect=function(){wr[0]=wr[1]=Tr[0]=Tr[1]=Number.MAX_VALUE,hi[0]=hi[1]=Cr[0]=Cr[1]=-Number.MAX_VALUE;var t=this.data,e=0,i=0,n=0,a=0,o;for(o=0;oi||Wr(_)>n||c===e-1)&&(m=Math.sqrt(y*y+_*_),a=d,o=g);break}case xt.C:{var x=t[c++],b=t[c++],d=t[c++],g=t[c++],S=t[c++],T=t[c++];m=Gm(a,o,x,b,d,g,S,T,10),a=S,o=T;break}case xt.Q:{var x=t[c++],b=t[c++],d=t[c++],g=t[c++];m=Xm(a,o,x,b,d,g,10),a=d,o=g;break}case xt.A:var C=t[c++],A=t[c++],M=t[c++],D=t[c++],L=t[c++],R=t[c++],E=R+L;c+=1,v&&(s=gn(L)*M+C,l=yn(L)*D+A),m=hc(M,D)*fc(ci,Math.abs(R)),a=gn(E)*M+C,o=yn(E)*D+A;break;case xt.R:{s=a=t[c++],l=o=t[c++];var P=t[c++],k=t[c++];m=P*2+k*2;break}case xt.Z:{var y=s-a,_=l-o;m=Math.sqrt(y*y+_*_),a=s,o=l;break}}m>=0&&(u[h++]=m,f+=m)}return this._pathLen=f,f},r.prototype.rebuildPath=function(t,e){var i=this.data,n=this._ux,a=this._uy,o=this._len,s,l,u,f,h,c,p=e<1,v,m,d=0,g=0,y,_=0,x,b;if(!(p&&(this._pathSegLen||this._calculateLength(),v=this._pathSegLen,m=this._pathLen,y=e*m,!y)))t:for(var S=0;S0&&(t.lineTo(x,b),_=0),T){case xt.M:s=u=i[S++],l=f=i[S++],t.moveTo(u,f);break;case xt.L:{h=i[S++],c=i[S++];var A=Wr(h-u),M=Wr(c-f);if(A>n||M>a){if(p){var D=v[g++];if(d+D>y){var L=(y-d)/D;t.lineTo(u*(1-L)+h*L,f*(1-L)+c*L);break t}d+=D}t.lineTo(h,c),u=h,f=c,_=0}else{var R=A*A+M*M;R>_&&(x=h,b=c,_=R)}break}case xt.C:{var E=i[S++],P=i[S++],k=i[S++],q=i[S++],B=i[S++],V=i[S++];if(p){var D=v[g++];if(d+D>y){var L=(y-d)/D;aa(u,E,k,B,L,dn),aa(f,P,q,V,L,mn),t.bezierCurveTo(dn[1],mn[1],dn[2],mn[2],dn[3],mn[3]);break t}d+=D}t.bezierCurveTo(E,P,k,q,B,V),u=B,f=V;break}case xt.Q:{var E=i[S++],P=i[S++],k=i[S++],q=i[S++];if(p){var D=v[g++];if(d+D>y){var L=(y-d)/D;oa(u,E,k,L,dn),oa(f,P,q,L,mn),t.quadraticCurveTo(dn[1],mn[1],dn[2],mn[2]);break t}d+=D}t.quadraticCurveTo(E,P,k,q),u=k,f=q;break}case xt.A:var tt=i[S++],ft=i[S++],ct=i[S++],yt=i[S++],Ct=i[S++],De=i[S++],At=i[S++],Ir=!i[S++],$n=ct>yt?ct:yt,Ae=Wr(ct-yt)>.001,Kt=Ct+De,ut=!1;if(p){var D=v[g++];d+D>y&&(Kt=Ct+De*(y-d)/D,ut=!0),d+=D}if(Ae&&t.ellipse?t.ellipse(tt,ft,ct,yt,At,Ct,Kt,Ir):t.arc(tt,ft,$n,Ct,Kt,Ir),ut)break t;C&&(s=gn(Ct)*ct+tt,l=yn(Ct)*yt+ft),u=gn(Kt)*ct+tt,f=yn(Kt)*yt+ft;break;case xt.R:s=u=i[S],l=f=i[S+1],h=i[S++],c=i[S++];var pt=i[S++],zi=i[S++];if(p){var D=v[g++];if(d+D>y){var oe=y-d;t.moveTo(h,c),t.lineTo(h+fc(oe,pt),c),oe-=pt,oe>0&&t.lineTo(h+pt,c+fc(oe,zi)),oe-=zi,oe>0&&t.lineTo(h+hc(pt-oe,0),c+zi),oe-=pt,oe>0&&t.lineTo(h,c+hc(zi-oe,0));break t}d+=D}t.rect(h,c,pt,zi);break;case xt.Z:if(p){var D=v[g++];if(d+D>y){var L=(y-d)/D;t.lineTo(u*(1-L)+s*L,f*(1-L)+l*L);break t}d+=D}t.closePath(),u=s,f=l}}},r.prototype.clone=function(){var t=new r,e=this.data;return t.data=e.slice?e.slice():Array.prototype.slice.call(e),t._len=this._len,t},r.CMD=xt,r.initDefaultProps=function(){var t=r.prototype;t._saveData=!0,t._ux=0,t._uy=0,t._pendingPtDist=0,t._version=0}(),r}(),Pe=ZC;function _n(r,t,e,i,n,a,o){if(n===0)return!1;var s=n,l=0,u=r;if(o>t+s&&o>i+s||or+s&&a>e+s||at+h&&f>i+h&&f>a+h&&f>s+h||fr+h&&u>e+h&&u>n+h&&u>o+h||ut+u&&l>i+u&&l>a+u||lr+u&&s>e+u&&s>n+u||se||f+un&&(n+=Po);var c=Math.atan2(l,s);return c<0&&(c+=Po),c>=i&&c<=n||c+Po>=i&&c+Po<=n}function Ke(r,t,e,i,n,a){if(a>t&&a>i||an?s:0}var pi=Pe.CMD,xn=Math.PI*2,JC=1e-4;function tD(r,t){return Math.abs(r-t)t&&u>i&&u>a&&u>s||u1&&eD(),p=Dt(t,i,a,s,je[0]),c>1&&(v=Dt(t,i,a,s,je[1]))),c===2?dt&&s>i&&s>a||s=0&&u<=1){for(var f=0,h=Bt(t,i,a,u),c=0;ce||s<-e)return 0;var l=Math.sqrt(e*e-s*s);ue[0]=-l,ue[1]=l;var u=Math.abs(i-n);if(u<1e-4)return 0;if(u>=xn-1e-4){i=0,n=xn;var f=a?1:-1;return o>=ue[0]+r&&o<=ue[1]+r?f:0}if(i>n){var h=i;i=n,n=h}i<0&&(i+=xn,n+=xn);for(var c=0,p=0;p<2;p++){var v=ue[p];if(v+r>o){var m=Math.atan2(s,v),f=a?1:-1;m<0&&(m=xn+m),(m>=i&&m<=n||m+xn>=i&&m+xn<=n)&&(m>Math.PI/2&&m1&&(e||(s+=Ke(l,u,f,h,i,n))),d&&(l=a[v],u=a[v+1],f=l,h=u),m){case pi.M:f=a[v++],h=a[v++],l=f,u=h;break;case pi.L:if(e){if(_n(l,u,a[v],a[v+1],t,i,n))return!0}else s+=Ke(l,u,a[v],a[v+1],i,n)||0;l=a[v++],u=a[v++];break;case pi.C:if(e){if(ty(l,u,a[v++],a[v++],a[v++],a[v++],a[v],a[v+1],t,i,n))return!0}else s+=rD(l,u,a[v++],a[v++],a[v++],a[v++],a[v],a[v+1],i,n)||0;l=a[v++],u=a[v++];break;case pi.Q:if(e){if(ey(l,u,a[v++],a[v++],a[v],a[v+1],t,i,n))return!0}else s+=iD(l,u,a[v++],a[v++],a[v],a[v+1],i,n)||0;l=a[v++],u=a[v++];break;case pi.A:var g=a[v++],y=a[v++],_=a[v++],x=a[v++],b=a[v++],S=a[v++];v+=1;var T=!!(1-a[v++]);c=Math.cos(b)*_+g,p=Math.sin(b)*x+y,d?(f=c,h=p):s+=Ke(l,u,c,p,i,n);var C=(i-g)*x/_+g;if(e){if(iy(g,y,x,b,b+S,T,t,C,n))return!0}else s+=nD(g,y,x,b,b+S,T,C,n);l=Math.cos(b+S)*_+g,u=Math.sin(b+S)*x+y;break;case pi.R:f=l=a[v++],h=u=a[v++];var A=a[v++],M=a[v++];if(c=f+A,p=h+M,e){if(_n(f,h,c,h,t,i,n)||_n(c,h,c,p,t,i,n)||_n(c,p,f,p,t,i,n)||_n(f,p,f,h,t,i,n))return!0}else s+=Ke(c,h,c,p,i,n),s+=Ke(f,p,f,h,i,n);break;case pi.Z:if(e){if(_n(l,u,f,h,t,i,n))return!0}else s+=Ke(l,u,f,h,i,n);l=f,u=h;break}}return!e&&!tD(u,h)&&(s+=Ke(l,u,f,h,i,n)||0),s!==0}function ay(r,t,e){return ny(r,0,!1,t,e)}function oy(r,t,e,i){return ny(r,t,!0,e,i)}var mc=X({fill:"#000",stroke:null,strokePercent:1,fillOpacity:1,strokeOpacity:1,lineDashOffset:0,lineWidth:1,lineCap:"butt",miterLimit:10,strokeNoScale:!1,strokeFirst:!1},br),oD={style:X({fill:!0,stroke:!0,strokePercent:!0,fillOpacity:!0,strokeOpacity:!0,lineDashOffset:!0,lineWidth:!0,miterLimit:!0},pn.style)},dc=Ee.concat(["invisible","culling","z","z2","zlevel","parent"]),sD=function(r){O(t,r);function t(e){return r.call(this,e)||this}return t.prototype.update=function(){var e=this;r.prototype.update.call(this);var i=this.style;if(i.decal){var n=this._decalEl=this._decalEl||new t;n.buildPath===t.prototype.buildPath&&(n.buildPath=function(l){e.buildPath(l,e.shape)}),n.silent=!0;var a=n.style;for(var o in i)a[o]!==i[o]&&(a[o]=i[o]);a.fill=i.fill?i.decal:null,a.decal=null,a.shadowColor=null,i.strokeFirst&&(a.stroke=null);for(var s=0;s.5?_o:i>.2?cg:xo}else if(e)return xo}return _o},t.prototype.getInsideTextStroke=function(e){var i=this.style.fill;if(F(i)){var n=this.__zr,a=!!(n&&n.isDarkMode()),o=Ji(e,0)0))},t.prototype.hasFill=function(){var e=this.style,i=e.fill;return i!=null&&i!=="none"},t.prototype.getBoundingRect=function(){var e=this._rect,i=this.style,n=!e;if(n){var a=!1;this.path||(a=!0,this.createPathProxy());var o=this.path;(a||this.__dirty&ai)&&(o.beginPath(),this.buildPath(o,this.shape,!1),this.pathUpdated()),e=o.getBoundingRect()}if(this._rect=e,this.hasStroke()&&this.path&&this.path.len()>0){var s=this._rectStroke||(this._rectStroke=e.clone());if(this.__dirty||n){s.copy(e);var l=i.strokeNoScale?this.getLineScale():1,u=i.lineWidth;if(!this.hasFill()){var f=this.strokeContainThreshold;u=Math.max(u,f??4)}l>1e-10&&(s.width+=u/l,s.height+=u/l,s.x-=u/l/2,s.y-=u/l/2)}return s}return e},t.prototype.contain=function(e,i){var n=this.transformCoordToLocal(e,i),a=this.getBoundingRect(),o=this.style;if(e=n[0],i=n[1],a.contain(e,i)){var s=this.path;if(this.hasStroke()){var l=o.lineWidth,u=o.strokeNoScale?this.getLineScale():1;if(u>1e-10&&(this.hasFill()||(l=Math.max(l,this.strokeContainThreshold)),oy(s,l/u,e,i)))return!0}if(this.hasFill())return ay(s,e,i)}return!1},t.prototype.dirtyShape=function(){this.__dirty|=ai,this._rect&&(this._rect=null),this._decalEl&&this._decalEl.dirtyShape(),this.markRedraw()},t.prototype.dirty=function(){this.dirtyStyle(),this.dirtyShape()},t.prototype.animateShape=function(e){return this.animate("shape",e)},t.prototype.updateDuringAnimation=function(e){e==="style"?this.dirtyStyle():e==="shape"?this.dirtyShape():this.markRedraw()},t.prototype.attrKV=function(e,i){e==="shape"?this.setShape(i):r.prototype.attrKV.call(this,e,i)},t.prototype.setShape=function(e,i){var n=this.shape;return n||(n=this.shape={}),typeof e=="string"?n[e]=i:I(n,e),this.dirtyShape(),this},t.prototype.shapeChanged=function(){return!!(this.__dirty&ai)},t.prototype.createStyle=function(e){return kr(mc,e)},t.prototype._innerSaveToNormal=function(e){r.prototype._innerSaveToNormal.call(this,e);var i=this._normalState;e.shape&&!i.shape&&(i.shape=I({},this.shape))},t.prototype._applyStateObj=function(e,i,n,a,o,s){r.prototype._applyStateObj.call(this,e,i,n,a,o,s);var l=!(i&&a),u;if(i&&i.shape?o?a?u=i.shape:(u=I({},n.shape),I(u,i.shape)):(u=I({},a?this.shape:n.shape),I(u,i.shape)):l&&(u=n.shape),u)if(o){this.shape=I({},this.shape);for(var f={},h=rt(u),c=0;c0},t.prototype.hasFill=function(){var e=this.style,i=e.fill;return i!=null&&i!=="none"},t.prototype.createStyle=function(e){return kr(lD,e)},t.prototype.setBoundingRect=function(e){this._rect=e},t.prototype.getBoundingRect=function(){var e=this.style;if(!this._rect){var i=e.text;i!=null?i+="":i="";var n=ua(i,e.font,e.textAlign,e.textBaseline);if(n.x+=e.x||0,n.y+=e.y||0,this.hasStroke()){var a=e.lineWidth;n.x-=a/2,n.y-=a/2,n.width+=a,n.height+=a}this._rect=n}return this._rect},t.initDefaultProps=function(){var e=t.prototype;e.dirtyRectTolerance=10}(),t}(ge);sy.prototype.type="tspan";var Oo=sy;var uD=X({x:0,y:0},br),fD={style:X({x:!0,y:!0,width:!0,height:!0,sx:!0,sy:!0,sWidth:!0,sHeight:!0},pn.style)};function hD(r){return!!(r&&typeof r!="string"&&r.width&&r.height)}var ly=function(r){O(t,r);function t(){return r!==null&&r.apply(this,arguments)||this}return t.prototype.createStyle=function(e){return kr(uD,e)},t.prototype._getSize=function(e){var i=this.style,n=i[e];if(n!=null)return n;var a=hD(i.image)?i.image:this.__image;if(!a)return 0;var o=e==="width"?"height":"width",s=i[o];return s==null?a[e]:a[e]/a[o]*s},t.prototype.getWidth=function(){return this._getSize("width")},t.prototype.getHeight=function(){return this._getSize("height")},t.prototype.getAnimationStyleProps=function(){return fD},t.prototype.getBoundingRect=function(){var e=this.style;return this._rect||(this._rect=new J(e.x||0,e.y||0,this.getWidth(),this.getHeight())),this._rect},t}(ge);ly.prototype.type="image";var ee=ly;function uy(r,t){var e=t.x,i=t.y,n=t.width,a=t.height,o=t.r,s,l,u,f;n<0&&(e=e+n,n=-n),a<0&&(i=i+a,a=-a),typeof o=="number"?s=l=u=f=o:o instanceof Array?o.length===1?s=l=u=f=o[0]:o.length===2?(s=u=o[0],l=f=o[1]):o.length===3?(s=o[0],l=f=o[1],u=o[2]):(s=o[0],l=o[1],u=o[2],f=o[3]):s=l=u=f=0;var h;s+l>n&&(h=s+l,s*=n/h,l*=n/h),u+f>n&&(h=u+f,u*=n/h,f*=n/h),l+u>a&&(h=l+u,l*=a/h,u*=a/h),s+f>a&&(h=s+f,s*=a/h,f*=a/h),r.moveTo(e+s,i),r.lineTo(e+n-l,i),l!==0&&r.arc(e+n-l,i+l,l,-Math.PI/2,0),r.lineTo(e+n,i+a-u),u!==0&&r.arc(e+n-u,i+a-u,u,0,Math.PI/2),r.lineTo(e+f,i+a),f!==0&&r.arc(e+f,i+a-f,f,Math.PI/2,Math.PI),r.lineTo(e,i+s),s!==0&&r.arc(e+s,i+s,s,Math.PI,Math.PI*1.5)}var ya=Math.round;function Il(r,t,e){if(t){var i=t.x1,n=t.x2,a=t.y1,o=t.y2;r.x1=i,r.x2=n,r.y1=a,r.y2=o;var s=e&&e.lineWidth;return s&&(ya(i*2)===ya(n*2)&&(r.x1=r.x2=vi(i,s,!0)),ya(a*2)===ya(o*2)&&(r.y1=r.y2=vi(a,s,!0))),r}}function Nl(r,t,e){if(t){var i=t.x,n=t.y,a=t.width,o=t.height;r.x=i,r.y=n,r.width=a,r.height=o;var s=e&&e.lineWidth;return s&&(r.x=vi(i,s,!0),r.y=vi(n,s,!0),r.width=Math.max(vi(i+a,s,!1)-r.x,a===0?0:1),r.height=Math.max(vi(n+o,s,!1)-r.y,o===0?0:1)),r}}function vi(r,t,e){if(!t)return r;var i=ya(r*2);return(i+ya(t))%2===0?i/2:(i+(e?1:-1))/2}var vD=function(){function r(){this.x=0,this.y=0,this.width=0,this.height=0}return r}();var dD={},fy=function(r){O(t,r);function t(e){return r.call(this,e)||this}return t.prototype.getDefaultShape=function(){return new vD},t.prototype.buildPath=function(e,i){var n,a,o,s;if(this.subPixelOptimize){var l=Nl(dD,i,this.style);n=l.x,a=l.y,o=l.width,s=l.height,l.r=i.r,i=l}else n=i.x,a=i.y,o=i.width,s=i.height;i.r?uy(e,i):e.rect(n,a,o,s)},t.prototype.isZeroArea=function(){return!this.shape.width||!this.shape.height},t}(Z);fy.prototype.type="rect";var vt=fy;var hy={fill:"#000"},cy=2,mD={style:X({fill:!0,stroke:!0,fillOpacity:!0,strokeOpacity:!0,lineWidth:!0,fontSize:!0,lineHeight:!0,width:!0,height:!0,textShadowColor:!0,textShadowBlur:!0,textShadowOffsetX:!0,textShadowOffsetY:!0,backgroundColor:!0,padding:!0,borderColor:!0,borderWidth:!0,borderRadius:!0},pn.style)},xy=function(r){O(t,r);function t(e){var i=r.call(this)||this;return i.type="text",i._children=[],i._defaultStyle=hy,i.attr(e),i}return t.prototype.childrenRef=function(){return this._children},t.prototype.update=function(){r.prototype.update.call(this),this.styleChanged()&&this._updateSubTexts();for(var e=0;e0,L=e.width!=null&&(e.overflow==="truncate"||e.overflow==="break"||e.overflow==="breakAll"),R=o.calculatedLineHeight,E=0;E=0&&(E=S[R],E.align==="right");)this._placeToken(E,e,C,g,L,"right",_),A-=E.width,L-=E.width,R--;for(D+=(a-(D-d)-(y-L)-A)/2;M<=R;)E=S[M],this._placeToken(E,e,C,g,D+E.width/2,"center",_),D+=E.width,M++;g+=C}},t.prototype._placeToken=function(e,i,n,a,o,s,l){var u=i.rich[e.styleName]||{};u.text=e.text;var f=e.verticalAlign,h=a+n/2;f==="top"?h=a+e.height/2:f==="bottom"&&(h=a+n-e.height/2);var c=!e.isLineHolder&&gc(u);c&&this._renderBackground(u,i,s==="right"?o-e.width:s==="center"?o-e.width/2:o,h-e.height/2,e.width,e.height);var p=!!u.backgroundColor,v=e.textPadding;v&&(o=yy(o,s,v),h-=e.height/2-v[0]-e.innerHeight/2);var m=this._getOrCreateChild(Oo),d=m.createStyle();m.useStyle(d);var g=this._defaultStyle,y=!1,_=0,x=gy("fill"in u?u.fill:"fill"in i?i.fill:(y=!0,g.fill)),b=my("stroke"in u?u.stroke:"stroke"in i?i.stroke:!p&&!l&&(!g.autoStroke||y)?(_=cy,g.stroke):null),S=u.textShadowBlur>0||i.textShadowBlur>0;d.text=e.text,d.x=o,d.y=h,S&&(d.shadowBlur=u.textShadowBlur||i.textShadowBlur||0,d.shadowColor=u.textShadowColor||i.textShadowColor||"transparent",d.shadowOffsetX=u.textShadowOffsetX||i.textShadowOffsetX||0,d.shadowOffsetY=u.textShadowOffsetY||i.textShadowOffsetY||0),d.textAlign=s,d.textBaseline="middle",d.font=e.font||sr,d.opacity=yr(u.opacity,i.opacity,1),vy(d,u),b&&(d.lineWidth=yr(u.lineWidth,i.lineWidth,_),d.lineDash=Q(u.lineDash,i.lineDash),d.lineDashOffset=i.lineDashOffset||0,d.stroke=b),x&&(d.fill=x);var T=e.contentWidth,C=e.contentHeight;m.setBoundingRect(new J(fa(d.x,T,d.textAlign),on(d.y,C,d.textBaseline),T,C))},t.prototype._renderBackground=function(e,i,n,a,o,s){var l=e.backgroundColor,u=e.borderWidth,f=e.borderColor,h=l&&l.image,c=l&&!h,p=e.borderRadius,v=this,m,d;if(c||e.lineHeight||u&&f){m=this._getOrCreateChild(vt),m.useStyle(m.createStyle()),m.style.fill=null;var g=m.shape;g.x=n,g.y=a,g.width=o,g.height=s,g.r=p,m.dirtyShape()}if(c){var y=m.style;y.fill=l||null,y.fillOpacity=Q(e.fillOpacity,1)}else if(h){d=this._getOrCreateChild(ee),d.onload=function(){v.dirtyStyle()};var _=d.style;_.image=l.image,_.x=n,_.y=a,_.width=o,_.height=s}if(u&&f){var y=m.style;y.lineWidth=u,y.stroke=f,y.strokeOpacity=Q(e.strokeOpacity,1),y.lineDash=e.borderDash,y.lineDashOffset=e.borderDashOffset||0,m.strokeContainThreshold=0,m.hasFill()&&m.hasStroke()&&(y.strokeFirst=!0,y.lineWidth*=2)}var x=(m||d).style;x.shadowBlur=e.shadowBlur||0,x.shadowColor=e.shadowColor||"transparent",x.shadowOffsetX=e.shadowOffsetX||0,x.shadowOffsetY=e.shadowOffsetY||0,x.opacity=yr(e.opacity,i.opacity,1)},t.makeFont=function(e){var i="";return xD(e)&&(i=[e.fontStyle,e.fontWeight,_D(e.fontSize),e.fontFamily||"sans-serif"].join(" ")),i&&Gt(i)||e.textFont||e.font},t}(ge),gD={left:!0,right:1,center:1},yD={top:1,bottom:1,middle:1},py=["fontStyle","fontWeight","fontSize","fontFamily"];function _D(r){return typeof r=="string"&&(r.indexOf("px")!==-1||r.indexOf("rem")!==-1||r.indexOf("em")!==-1)?r:isNaN(+r)?Gs+"px":r+"px"}function vy(r,t){for(var e=0;e=0,a=!1;if(r instanceof Z){var o=My(r),s=n&&o.selectFill||o.normalFill,l=n&&o.selectStroke||o.normalStroke;if(_a(s)||_a(l)){i=i||{};var u=i.style||{};u.fill==="inherit"?(a=!0,i=I({},i),u=I({},u),u.fill=s):!_a(u.fill)&&_a(s)?(a=!0,i=I({},i),u=I({},u),u.fill=pl(s)):!_a(u.stroke)&&_a(l)&&(a||(i=I({},i),u=I({},u)),u.stroke=pl(l)),i.style=u}}if(i&&i.z2==null){a||(i=I({},i));var f=r.z2EmphasisLift;i.z2=r.z2+(f??bD)}return i}function MD(r,t,e){if(e&&e.z2==null){e=I({},e);var i=r.z2SelectLift;e.z2=r.z2+(i??wD)}return e}function ED(r,t,e){var i=K(r.currentStates,t)>=0,n=r.style.opacity,a=i?null:DD(r,["opacity"],t,{opacity:1});e=e||{};var o=e.style||{};return o.opacity==null&&(e=I({},e),o=I({opacity:i?n:a.opacity*.1},o),e.style=o),e}function yc(r,t){var e=this.states[r];if(this.style){if(r==="emphasis")return AD(this,r,t,e);if(r==="blur")return ED(this,r,e);if(r==="select")return MD(this,r,e)}return e}function Cc(r){r.stateProxy=yc;var t=r.getTextContent(),e=r.getTextGuideLine();t&&(t.stateProxy=yc),e&&(e.stateProxy=yc)}function Cy(r,t){!Oy(r,t)&&!r.__highByOuter&&Yr(r,Ey)}function Dy(r,t){!Oy(r,t)&&!r.__highByOuter&&Yr(r,Ly)}function Xr(r,t){r.__highByOuter|=1<<(t||0),Yr(r,Ey)}function qr(r,t){!(r.__highByOuter&=~(1<<(t||0)))&&Yr(r,Ly)}function Fl(r){Yr(r,wc)}function zo(r){Yr(r,Py)}function Dc(r){Yr(r,TD)}function Ac(r){Yr(r,CD)}function Oy(r,t){return r.__highDownSilentOnTouch&&t.zrByTouch}function Mc(r){var t=r.getModel(),e=[],i=[];t.eachComponent(function(n,a){var o=xc(a),s=n==="series",l=s?r.getViewOfSeriesModel(a):r.getViewOfComponentModel(a);!s&&i.push(l),o.isBlured&&(l.group.traverse(function(u){Py(u)}),s&&e.push(a)),o.isBlured=!1}),w(i,function(n){n&&n.toggleBlurSeries&&n.toggleBlurSeries(e,!1,t)})}function _c(r,t,e,i){var n=i.getModel();e=e||"coordinateSystem";function a(u,f){for(var h=0;h0){var l={dataIndex:s,seriesIndex:e.seriesIndex};o!=null&&(l.dataType=o),t.push(l)}})}),t}function ba(r,t,e){Fy(r,!0),Yr(r,Cc),PD(r,t,e)}function LD(r){Fy(r,!1)}function Oe(r,t,e,i){i?LD(r):ba(r,t,e)}function PD(r,t,e){var i=it(r);t!=null?(i.focus=t,i.blurScope=e):i.focus&&(i.focus=null)}var Ay=["emphasis","blur","select"],OD={itemStyle:"getItemStyle",lineStyle:"getLineStyle",areaStyle:"getAreaStyle"};function Sn(r,t,e,i){e=e||"itemStyle";for(var n=0;nCn,BezierCurve:()=>Tn,BoundingRect:()=>J,Circle:()=>bn,CompoundPath:()=>Yl,Ellipse:()=>Uo,Group:()=>lt,Image:()=>ee,IncrementalDisplayable:()=>jl,Line:()=>he,LinearGradient:()=>Ca,OrientedBoundingRect:()=>Da,Path:()=>Z,Point:()=>_t,Polygon:()=>mi,Polyline:()=>Wo,RadialGradient:()=>ql,Rect:()=>vt,Ring:()=>Go,Sector:()=>Ar,Text:()=>St,applyTransform:()=>eu,clipPointsByRect:()=>Wc,clipRectByRect:()=>Yc,createIcon:()=>Ln,extendPath:()=>Uc,extendShape:()=>Bc,getShapeClass:()=>qo,getTransform:()=>Hc,groupTransition:()=>Gc,initProps:()=>Xt,isElementRemoved:()=>Mn,lineLineIntersect:()=>d_,linePolygonIntersect:()=>cA,makeImage:()=>Zo,makePath:()=>gi,mergePath:()=>Vc,registerShape:()=>Re,removeElement:()=>Aa,removeElementWithFadeOut:()=>Xo,resizePath:()=>tu,setTooltipConfig:()=>Ko,subPixelOptimize:()=>uA,subPixelOptimizeLine:()=>En,subPixelOptimizeRect:()=>lA,transformDirection:()=>fA,traverseElements:()=>cr,updateProps:()=>wt});var wa=Pe.CMD,RD=[[],[],[]],Vy=Math.sqrt,ID=Math.atan2;function Pc(r,t){if(t){var e=r.data,i=r.len(),n,a,o,s,l,u,f=wa.M,h=wa.C,c=wa.L,p=wa.R,v=wa.A,m=wa.Q;for(o=0,s=0;o1&&(o*=Oc(v),s*=Oc(v));var m=(n===a?-1:1)*Oc((o*o*(s*s)-o*o*(p*p)-s*s*(c*c))/(o*o*(p*p)+s*s*(c*c)))||0,d=m*o*p/s,g=m*-s*c/o,y=(r+e)/2+Hl(h)*d-Vl(h)*g,_=(t+i)/2+Vl(h)*d+Hl(h)*g,x=Gy([1,0],[(c-d)/o,(p-g)/s]),b=[(c-d)/o,(p-g)/s],S=[(-1*c-d)/o,(-1*p-g)/s],T=Gy(b,S);if(Rc(b,S)<=-1&&(T=Bo),Rc(b,S)>=1&&(T=0),T<0){var C=Math.round(T/Bo*1e6)/1e6;T=Bo*2+C%2*Bo}f.addData(u,y,_,o,s,x,T,h,a)}var ND=/([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig,kD=/-?([0-9]*\.)?[0-9]+([eE]-?[0-9]+)?/g;function zD(r){var t=new Pe;if(!r)return t;var e=0,i=0,n=e,a=i,o,s=Pe.CMD,l=r.match(ND);if(!l)return t;for(var u=0;uE*E+P*P&&(C=M,A=D),{cx:C,cy:A,x0:-f,y0:-h,x1:C*(n/b-1),y1:A*(n/b-1)}}function GD(r){var t;if(N(r)){var e=r.length;if(!e)return r;e===1?t=[r[0],r[0],0,0]:e===2?t=[r[0],r[0],r[1],r[1]]:e===3?t=r.concat(r[2]):t=r}else t=[r,r,r,r];return t}function e_(r,t){var e,i=Vo(t.r,0),n=Vo(t.r0||0,0),a=i>0,o=n>0;if(!(!a&&!o)){if(a||(i=n,n=0),n>i){var s=i;i=n,n=s}var l=t.startAngle,u=t.endAngle;if(!(isNaN(l)||isNaN(u))){var f=t.cx,h=t.cy,c=!!t.clockwise,p=Jy(u-l),v=p>Ic&&p%Ic;if(v>hr&&(p=v),!(i>hr))r.moveTo(f,h);else if(p>Ic-hr)r.moveTo(f+i*Ta(l),h+i*wn(l)),r.arc(f,h,i,l,u,!c),n>hr&&(r.moveTo(f+n*Ta(u),h+n*wn(u)),r.arc(f,h,n,u,l,c));else{var m=void 0,d=void 0,g=void 0,y=void 0,_=void 0,x=void 0,b=void 0,S=void 0,T=void 0,C=void 0,A=void 0,M=void 0,D=void 0,L=void 0,R=void 0,E=void 0,P=i*Ta(l),k=i*wn(l),q=n*Ta(u),B=n*wn(u),V=p>hr;if(V){var tt=t.cornerRadius;tt&&(e=GD(tt),m=e[0],d=e[1],g=e[2],y=e[3]);var ft=Jy(i-n)/2;if(_=Dr(ft,g),x=Dr(ft,y),b=Dr(ft,m),S=Dr(ft,d),A=T=Vo(_,x),M=C=Vo(b,S),(T>hr||C>hr)&&(D=i*Ta(u),L=i*wn(u),R=n*Ta(l),E=n*wn(l),phr){var Ae=Dr(g,A),Kt=Dr(y,A),ut=Gl(R,E,P,k,i,Ae,c),pt=Gl(D,L,q,B,i,Kt,c);r.moveTo(f+ut.cx+ut.x0,h+ut.cy+ut.y0),A0&&r.arc(f+ut.cx,h+ut.cy,Ae,re(ut.y0,ut.x0),re(ut.y1,ut.x1),!c),r.arc(f,h,i,re(ut.cy+ut.y1,ut.cx+ut.x1),re(pt.cy+pt.y1,pt.cx+pt.x1),!c),Kt>0&&r.arc(f+pt.cx,h+pt.cy,Kt,re(pt.y1,pt.x1),re(pt.y0,pt.x0),!c))}else r.moveTo(f+P,h+k),r.arc(f,h,i,l,u,!c);if(!(n>hr)||!V)r.lineTo(f+q,h+B);else if(M>hr){var Ae=Dr(m,M),Kt=Dr(d,M),ut=Gl(q,B,D,L,n,-Kt,c),pt=Gl(P,k,R,E,n,-Ae,c);r.lineTo(f+ut.cx+ut.x0,h+ut.cy+ut.y0),M0&&r.arc(f+ut.cx,h+ut.cy,Kt,re(ut.y0,ut.x0),re(ut.y1,ut.x1),!c),r.arc(f,h,n,re(ut.cy+ut.y1,ut.cx+ut.x1),re(pt.cy+pt.y1,pt.cx+pt.x1),c),Ae>0&&r.arc(f+pt.cx,h+pt.cy,Ae,re(pt.y1,pt.x1),re(pt.y0,pt.x0),!c))}else r.lineTo(f+q,h+B),r.arc(f,h,n,u,l,c)}r.closePath()}}}var YD=function(){function r(){this.cx=0,this.cy=0,this.r0=0,this.r=0,this.startAngle=0,this.endAngle=Math.PI*2,this.clockwise=!0,this.cornerRadius=0}return r}();var r_=function(r){O(t,r);function t(e){return r.call(this,e)||this}return t.prototype.getDefaultShape=function(){return new YD},t.prototype.buildPath=function(e,i){e_(e,i)},t.prototype.isZeroArea=function(){return this.shape.startAngle===this.shape.endAngle||this.shape.r===this.shape.r0},t}(Z);r_.prototype.type="sector";var Ar=r_;var XD=function(){function r(){this.cx=0,this.cy=0,this.r=0,this.r0=0}return r}();var i_=function(r){O(t,r);function t(e){return r.call(this,e)||this}return t.prototype.getDefaultShape=function(){return new XD},t.prototype.buildPath=function(e,i){var n=i.cx,a=i.cy,o=Math.PI*2;e.moveTo(n+i.r,a),e.arc(n,a,i.r,0,o,!1),e.moveTo(n+i.r0,a),e.arc(n,a,i.r0,0,o,!0)},t}(Z);i_.prototype.type="ring";var Go=i_;function Nc(r,t,e,i){var n=[],a=[],o=[],s=[],l,u,f,h;if(i){f=[1/0,1/0],h=[-1/0,-1/0];for(var c=0,p=r.length;c=2){if(i){var a=Nc(n,i,e,t.smoothConstraint);r.moveTo(n[0][0],n[0][1]);for(var o=n.length,s=0;s<(e?o:o-1);s++){var l=a[s*2],u=a[s*2+1],f=n[(s+1)%o];r.bezierCurveTo(l[0],l[1],u[0],u[1],f[0],f[1])}}else{r.moveTo(n[0][0],n[0][1]);for(var s=1,h=n.length;sAn[1]){if(s=!1,a)return s;var f=Math.abs(An[0]-Dn[1]),h=Math.abs(Dn[0]-An[1]);Math.min(f,h)>n.len()&&(f0){var h=f.duration,c=f.delay,p=f.easing,v={duration:h,delay:c||0,easing:p,done:a,force:!!a||!!o,setToFinal:!u,scope:r,during:o};s?t.animateFrom(e,v):t.animateTo(e,v)}else t.stopAnimation(),!s&&t.attr(e),o&&o(1),a&&a()}function wt(r,t,e,i,n,a){kc("update",r,t,e,i,n,a)}function Xt(r,t,e,i,n,a){kc("enter",r,t,e,i,n,a)}function Mn(r){if(!r.__zr)return!0;for(var t=0;tMath.abs(a[1])?a[0]>0?"right":"left":a[1]>0?"bottom":"top"}function c_(r){return!r.isGroup}function hA(r){return r.shape!=null}function Gc(r,t,e){if(!r||!t)return;function i(o){var s={};return o.traverse(function(l){c_(l)&&l.anid&&(s[l.anid]=l)}),s}function n(o){var s={x:o.x,y:o.y,rotation:o.rotation};return hA(o)&&(s.shape=I({},o.shape)),s}var a=i(r);t.traverse(function(o){if(c_(o)&&o.anid){var s=a[o.anid];if(s){var l=n(o);o.attr(n(s)),wt(o,l,e,it(o).dataIndex)}}})}function Wc(r,t){return z(r,function(e){var i=e[0];i=$l(i,t.x),i=Jl(i,t.x+t.width);var n=e[1];return n=$l(n,t.y),n=Jl(n,t.y+t.height),[i,n]})}function Yc(r,t){var e=$l(r.x,t.x),i=Jl(r.x+r.width,t.x+t.width),n=$l(r.y,t.y),a=Jl(r.y+r.height,t.y+t.height);if(i>=e&&a>=n)return{x:e,y:n,width:i-e,height:a-n}}function Ln(r,t,e){var i=I({rectHover:!0},t),n=i.style={strokeNoScale:!0};if(e=e||{x:-1,y:-1,width:2,height:2},r)return r.indexOf("image://")===0?(n.image=r.slice(8),X(n,e),new ee(i)):gi(r.replace("path://",""),i,e,"center")}function cA(r,t,e,i,n){for(var a=0,o=n[n.length-1];a1)return!1;var d=zc(p,v,f,h)/c;return!(d<0||d>1)}function zc(r,t,e,i){return r*i-e*t}function pA(r){return r<=1e-6&&r>=-1e-6}function Ko(r){var t=r.itemTooltipOption,e=r.componentModel,i=r.itemName,n=F(t)?{formatter:t}:t,a=e.mainType,o=e.componentIndex,s={componentType:a,name:i,$vars:["name"]};s[a+"Index"]=o;var l=r.formatterParamsExtra;l&&w(rt(l),function(f){U(s,f)||(s[f]=l[f],s.$vars.push(f))});var u=it(r.el);u.componentMainType=a,u.componentIndex=o,u.tooltipConfig={name:i,option:X({content:i,encodeHTMLContent:!0,formatterParams:s},n)}}function p_(r,t){var e;r.isGroup&&(e=t(r)),e||r.traverse(t)}function cr(r,t){if(r)if(N(r))for(var e=0;e=0&&s.push(l)}),s}}function nu(r,t){return nt(nt({},r,!0),t,!0)}var A_={time:{month:["January","February","March","April","May","June","July","August","September","October","November","December"],monthAbbr:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayOfWeek:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayOfWeekAbbr:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]},legend:{selector:{all:"All",inverse:"Inv"}},toolbox:{brush:{title:{rect:"Box Select",polygon:"Lasso Select",lineX:"Horizontally Select",lineY:"Vertically Select",keep:"Keep Selections",clear:"Clear Selections"}},dataView:{title:"Data View",lang:["Data View","Close","Refresh"]},dataZoom:{title:{zoom:"Zoom",back:"Zoom Reset"}},magicType:{title:{line:"Switch to Line Chart",bar:"Switch to Bar Chart",stack:"Stack",tiled:"Tile"}},restore:{title:"Restore"},saveAsImage:{title:"Save as Image",lang:["Right Click to Save Image"]}},series:{typeNames:{pie:"Pie chart",bar:"Bar chart",line:"Line chart",scatter:"Scatter plot",effectScatter:"Ripple scatter plot",radar:"Radar chart",tree:"Tree",treemap:"Treemap",boxplot:"Boxplot",candlestick:"Candlestick",k:"K line chart",heatmap:"Heat map",map:"Map",parallel:"Parallel coordinate map",lines:"Line graph",graph:"Relationship graph",sankey:"Sankey diagram",funnel:"Funnel chart",gauge:"Gauge",pictorialBar:"Pictorial bar",themeRiver:"Theme River Map",sunburst:"Sunburst",custom:"Custom chart",chart:"Chart"}},aria:{general:{withTitle:'This is a chart about "{title}"',withoutTitle:"This is a chart"},series:{single:{prefix:"",withName:" with type {seriesType} named {seriesName}.",withoutName:" with type {seriesType}."},multiple:{prefix:". It consists of {seriesCount} series count.",withName:" The {seriesId} series is a {seriesType} representing {seriesName}.",withoutName:" The {seriesId} series is a {seriesType}.",separator:{middle:"",end:""}}},data:{allData:"The data is as follows: ",partialData:"The first {displayCnt} items are: ",withName:"the data for {name} is {value}",withoutName:"{value}",separator:{middle:", ",end:". "}}}};var M_={time:{month:["\u4E00\u6708","\u4E8C\u6708","\u4E09\u6708","\u56DB\u6708","\u4E94\u6708","\u516D\u6708","\u4E03\u6708","\u516B\u6708","\u4E5D\u6708","\u5341\u6708","\u5341\u4E00\u6708","\u5341\u4E8C\u6708"],monthAbbr:["1\u6708","2\u6708","3\u6708","4\u6708","5\u6708","6\u6708","7\u6708","8\u6708","9\u6708","10\u6708","11\u6708","12\u6708"],dayOfWeek:["\u661F\u671F\u65E5","\u661F\u671F\u4E00","\u661F\u671F\u4E8C","\u661F\u671F\u4E09","\u661F\u671F\u56DB","\u661F\u671F\u4E94","\u661F\u671F\u516D"],dayOfWeekAbbr:["\u65E5","\u4E00","\u4E8C","\u4E09","\u56DB","\u4E94","\u516D"]},legend:{selector:{all:"\u5168\u9009",inverse:"\u53CD\u9009"}},toolbox:{brush:{title:{rect:"\u77E9\u5F62\u9009\u62E9",polygon:"\u5708\u9009",lineX:"\u6A2A\u5411\u9009\u62E9",lineY:"\u7EB5\u5411\u9009\u62E9",keep:"\u4FDD\u6301\u9009\u62E9",clear:"\u6E05\u9664\u9009\u62E9"}},dataView:{title:"\u6570\u636E\u89C6\u56FE",lang:["\u6570\u636E\u89C6\u56FE","\u5173\u95ED","\u5237\u65B0"]},dataZoom:{title:{zoom:"\u533A\u57DF\u7F29\u653E",back:"\u533A\u57DF\u7F29\u653E\u8FD8\u539F"}},magicType:{title:{line:"\u5207\u6362\u4E3A\u6298\u7EBF\u56FE",bar:"\u5207\u6362\u4E3A\u67F1\u72B6\u56FE",stack:"\u5207\u6362\u4E3A\u5806\u53E0",tiled:"\u5207\u6362\u4E3A\u5E73\u94FA"}},restore:{title:"\u8FD8\u539F"},saveAsImage:{title:"\u4FDD\u5B58\u4E3A\u56FE\u7247",lang:["\u53F3\u952E\u53E6\u5B58\u4E3A\u56FE\u7247"]}},series:{typeNames:{pie:"\u997C\u56FE",bar:"\u67F1\u72B6\u56FE",line:"\u6298\u7EBF\u56FE",scatter:"\u6563\u70B9\u56FE",effectScatter:"\u6D9F\u6F2A\u6563\u70B9\u56FE",radar:"\u96F7\u8FBE\u56FE",tree:"\u6811\u56FE",treemap:"\u77E9\u5F62\u6811\u56FE",boxplot:"\u7BB1\u578B\u56FE",candlestick:"K\u7EBF\u56FE",k:"K\u7EBF\u56FE",heatmap:"\u70ED\u529B\u56FE",map:"\u5730\u56FE",parallel:"\u5E73\u884C\u5750\u6807\u56FE",lines:"\u7EBF\u56FE",graph:"\u5173\u7CFB\u56FE",sankey:"\u6851\u57FA\u56FE",funnel:"\u6F0F\u6597\u56FE",gauge:"\u4EEA\u8868\u76D8\u56FE",pictorialBar:"\u8C61\u5F62\u67F1\u56FE",themeRiver:"\u4E3B\u9898\u6CB3\u6D41\u56FE",sunburst:"\u65ED\u65E5\u56FE",custom:"\u81EA\u5B9A\u4E49\u56FE\u8868",chart:"\u56FE\u8868"}},aria:{general:{withTitle:"\u8FD9\u662F\u4E00\u4E2A\u5173\u4E8E\u201C{title}\u201D\u7684\u56FE\u8868\u3002",withoutTitle:"\u8FD9\u662F\u4E00\u4E2A\u56FE\u8868\uFF0C"},series:{single:{prefix:"",withName:"\u56FE\u8868\u7C7B\u578B\u662F{seriesType}\uFF0C\u8868\u793A{seriesName}\u3002",withoutName:"\u56FE\u8868\u7C7B\u578B\u662F{seriesType}\u3002"},multiple:{prefix:"\u5B83\u7531{seriesCount}\u4E2A\u56FE\u8868\u7CFB\u5217\u7EC4\u6210\u3002",withName:"\u7B2C{seriesId}\u4E2A\u7CFB\u5217\u662F\u4E00\u4E2A\u8868\u793A{seriesName}\u7684{seriesType}\uFF0C",withoutName:"\u7B2C{seriesId}\u4E2A\u7CFB\u5217\u662F\u4E00\u4E2A{seriesType}\uFF0C",separator:{middle:"\uFF1B",end:"\u3002"}}},data:{allData:"\u5176\u6570\u636E\u662F\u2014\u2014",partialData:"\u5176\u4E2D\uFF0C\u524D{displayCnt}\u9879\u662F\u2014\u2014",withName:"{name}\u7684\u6570\u636E\u662F{value}",withoutName:"{value}",separator:{middle:"\uFF0C",end:""}}}};var ou="ZH",Qc="EN",Ea=Qc,au={},$c={},su=Y.domSupported?function(){var r=(document.documentElement.lang||navigator.language||navigator.browserLanguage||Ea).toUpperCase();return r.indexOf(ou)>-1?ou:Ea}():Ea;function lu(r,t){r=r.toUpperCase(),$c[r]=new gt(t),au[r]=t}function E_(r){if(F(r)){var t=au[r.toUpperCase()]||{};return r===ou||r===Qc?j(t):nt(j(t),j(au[Ea]),!1)}else return nt(j(r),j(au[Ea]),!1)}function L_(r){return $c[r]}function P_(){return $c[Ea]}lu(Qc,A_);lu(ou,M_);var fu=1e3,hu=fu*60,Pa=hu*60,Ie=Pa*24,tp=Ie*365,Qo={year:"{yyyy}",month:"{MMM}",day:"{d}",hour:"{HH}:{mm}",minute:"{HH}:{mm}",second:"{HH}:{mm}:{ss}",millisecond:"{HH}:{mm}:{ss} {SSS}",none:"{yyyy}-{MM}-{dd} {HH}:{mm}:{ss} {SSS}"},uu="{yyyy}-{MM}-{dd}",ep={year:"{yyyy}",month:"{yyyy}-{MM}",day:uu,hour:uu+" "+Qo.hour,minute:uu+" "+Qo.minute,second:uu+" "+Qo.second,millisecond:Qo.none},Jc=["year","month","day","hour","minute","second","millisecond"],rp=["year","half-year","quarter","month","week","half-week","day","half-day","quarter-day","hour","minute","second","millisecond"];function ie(r,t){return r+="","0000".substr(0,t-r.length)+r}function Rn(r){switch(r){case"half-year":case"quarter":return"month";case"week":case"half-week":return"day";case"half-day":case"quarter-day":return"hour";default:return r}}function O_(r){return r===Rn(r)}function R_(r){switch(r){case"year":case"month":return"day";case"millisecond":return"millisecond";default:return"second"}}function Zr(r,t,e,i){var n=Yt(r),a=n[cu(e)](),o=n[On(e)]()+1,s=Math.floor((o-1)/3)+1,l=n[$o(e)](),u=n["get"+(e?"UTC":"")+"Day"](),f=n[La(e)](),h=(f-1)%12+1,c=n[Jo(e)](),p=n[ts(e)](),v=n[es(e)](),m=f>=12?"pm":"am",d=m.toUpperCase(),g=i instanceof gt?i:L_(i||su)||P_(),y=g.getModel("time"),_=y.get("month"),x=y.get("monthAbbr"),b=y.get("dayOfWeek"),S=y.get("dayOfWeekAbbr");return(t||"").replace(/{a}/g,m+"").replace(/{A}/g,d+"").replace(/{yyyy}/g,a+"").replace(/{yy}/g,ie(a%100+"",2)).replace(/{Q}/g,s+"").replace(/{MMMM}/g,_[o-1]).replace(/{MMM}/g,x[o-1]).replace(/{MM}/g,ie(o,2)).replace(/{M}/g,o+"").replace(/{dd}/g,ie(l,2)).replace(/{d}/g,l+"").replace(/{eeee}/g,b[u]).replace(/{ee}/g,S[u]).replace(/{e}/g,u+"").replace(/{HH}/g,ie(f,2)).replace(/{H}/g,f+"").replace(/{hh}/g,ie(h+"",2)).replace(/{h}/g,h+"").replace(/{mm}/g,ie(c,2)).replace(/{m}/g,c+"").replace(/{ss}/g,ie(p,2)).replace(/{s}/g,p+"").replace(/{SSS}/g,ie(v,3)).replace(/{S}/g,v+"")}function I_(r,t,e,i,n){var a=null;if(F(e))a=e;else if(G(e))a=e(r.value,t,{level:r.level});else{var o=I({},Qo);if(r.level>0)for(var s=0;s=0;--s)if(l[u]){a=l[u];break}a=a||o.none}if(N(a)){var h=r.level==null?0:r.level>=0?r.level:a.length+r.level;h=Math.min(h,a.length-1),a=a[h]}}return Zr(new Date(r.value),a,n,i)}function N_(r,t){var e=Yt(r),i=e[On(t)]()+1,n=e[$o(t)](),a=e[La(t)](),o=e[Jo(t)](),s=e[ts(t)](),l=e[es(t)](),u=l===0,f=u&&s===0,h=f&&o===0,c=h&&a===0,p=c&&n===1,v=p&&i===1;return v?"year":p?"month":c?"day":h?"hour":f?"minute":u?"second":"millisecond"}function ip(r,t,e){var i=ot(r)?Yt(r):r;switch(t=t||N_(r,e),t){case"year":return i[cu(e)]();case"half-year":return i[On(e)]()>=6?1:0;case"quarter":return Math.floor((i[On(e)]()+1)/4);case"month":return i[On(e)]();case"day":return i[$o(e)]();case"half-day":return i[La(e)]()/24;case"hour":return i[La(e)]();case"minute":return i[Jo(e)]();case"second":return i[ts(e)]();case"millisecond":return i[es(e)]()}}function cu(r){return r?"getUTCFullYear":"getFullYear"}function On(r){return r?"getUTCMonth":"getMonth"}function $o(r){return r?"getUTCDate":"getDate"}function La(r){return r?"getUTCHours":"getHours"}function Jo(r){return r?"getUTCMinutes":"getMinutes"}function ts(r){return r?"getUTCSeconds":"getSeconds"}function es(r){return r?"getUTCMilliseconds":"getMilliseconds"}function k_(r){return r?"setUTCFullYear":"setFullYear"}function np(r){return r?"setUTCMonth":"setMonth"}function ap(r){return r?"setUTCDate":"setDate"}function op(r){return r?"setUTCHours":"setHours"}function sp(r){return r?"setUTCMinutes":"setMinutes"}function lp(r){return r?"setUTCSeconds":"setSeconds"}function up(r){return r?"setUTCMilliseconds":"setMilliseconds"}function fp(r,t,e,i,n,a,o,s){var l=new St({style:{text:r,font:t,align:e,verticalAlign:i,padding:n,rich:a,overflow:o?"truncate":null,lineHeight:s}});return l.getBoundingRect()}function rs(r){if(!Co(r))return F(r)?r:"-";var t=(r+"").split(".");return t[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g,"$1,")+(t.length>1?"."+t[1]:"")}function Oa(r,t){return r=(r||"").toLowerCase().replace(/-(.)/g,function(e,i){return i.toUpperCase()}),t&&r&&(r=r.charAt(0).toUpperCase()+r.slice(1)),r}var Mr=ro;function pu(r,t,e){var i="{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}";function n(f){return f&&Gt(f)?f:"-"}function a(f){return!!(f!=null&&!isNaN(f)&&isFinite(f))}var o=t==="time",s=r instanceof Date;if(o||s){var l=o?Yt(r):r;if(isNaN(+l)){if(s)return"-"}else return Zr(l,i,e)}if(t==="ordinal")return ea(r)?n(r):ot(r)&&a(r)?r+"":"-";var u=Ye(r);return a(u)?rs(u):ea(r)?n(r):typeof r=="boolean"?r+"":"-"}var z_=["a","b","c","d","e","f","g"],hp=function(r,t){return"{"+r+(t??"")+"}"};function Ra(r,t,e){N(t)||(t=[t]);var i=t.length;if(!i)return"";for(var n=t[0].$vars||[],a=0;a':'';var o=e.markerId||"markerX";return{renderMode:a,content:"{"+o+"|} ",style:n==="subItem"?{width:4,height:4,borderRadius:2,backgroundColor:i}:{width:10,height:10,borderRadius:5,backgroundColor:i}}}function F_(r,t,e){(r==="week"||r==="month"||r==="quarter"||r==="half-year"||r==="year")&&(r=`MM-dd +yyyy`);var i=Yt(t),n=e?"getUTC":"get",a=i[n+"FullYear"](),o=i[n+"Month"]()+1,s=i[n+"Date"](),l=i[n+"Hours"](),u=i[n+"Minutes"](),f=i[n+"Seconds"](),h=i[n+"Milliseconds"]();return r=r.replace("MM",ie(o,2)).replace("M",o).replace("yyyy",a).replace("yy",ie(a%100+"",2)).replace("dd",ie(s,2)).replace("d",s).replace("hh",ie(l,2)).replace("h",l).replace("mm",ie(u,2)).replace("m",u).replace("ss",ie(f,2)).replace("s",f).replace("SSS",ie(h,3)),r}function B_(r){return r&&r.charAt(0).toUpperCase()+r.substr(1)}function pr(r,t){return t=t||"transparent",F(r)?r:H(r)&&r.colorStops&&(r.colorStops[0]||{}).color||t}var gu=w,wA=["left","right","top","bottom","width","height"],mu=[["width","left","right"],["height","top","bottom"]];function cp(r,t,e,i,n){var a=0,o=0;i==null&&(i=1/0),n==null&&(n=1/0);var s=0;t.eachChild(function(l,u){var f=l.getBoundingRect(),h=t.childAt(u+1),c=h&&h.getBoundingRect(),p,v;if(r==="horizontal"){var m=f.width+(c?-c.x+f.x:0);p=a+m,p>i||l.newline?(a=0,p=m,o+=s+e,s=f.height):s=Math.max(s,f.height)}else{var d=f.height+(c?-c.y+f.y:0);v=o+d,v>n||l.newline?(a+=s+e,o=0,v=d,s=f.width):s=Math.max(s,f.width)}l.newline||(l.x=a,l.y=o,l.markRedraw(),r==="horizontal"?a=p+e:o=v+e)})}var In=cp,SF=st(cp,"vertical"),bF=st(cp,"horizontal");function Kr(r,t,e){e=Mr(e||0);var i=t.width,n=t.height,a=Tt(r.left,i),o=Tt(r.top,n),s=Tt(r.right,i),l=Tt(r.bottom,n),u=Tt(r.width,i),f=Tt(r.height,n),h=e[2]+e[0],c=e[1]+e[3],p=r.aspect;switch(isNaN(u)&&(u=i-s-c-a),isNaN(f)&&(f=n-l-h-o),p!=null&&(isNaN(u)&&isNaN(f)&&(p>i/n?u=i*.8:f=n*.8),isNaN(u)&&(u=p*f),isNaN(f)&&(f=u/p)),isNaN(a)&&(a=i-s-u-c),isNaN(o)&&(o=n-l-f-h),r.left||r.right){case"center":a=i/2-u/2-e[3];break;case"right":a=i-u-c;break}switch(r.top||r.bottom){case"middle":case"center":o=n/2-f/2-e[0];break;case"bottom":o=n-f-h;break}a=a||0,o=o||0,isNaN(u)&&(u=i-c-a-(s||0)),isNaN(f)&&(f=n-h-o-(l||0));var v=new J(a+e[3],o+e[0],u,f);return v.margin=e,v}function _i(r){var t=r.layoutMode||r.constructor.layoutMode;return H(t)?t:t?{type:t}:null}function Er(r,t,e){var i=e&&e.ignoreSize;!N(i)&&(i=[i,i]);var n=o(mu[0],0),a=o(mu[1],1);u(mu[0],r,n),u(mu[1],r,a);function o(f,h){var c={},p=0,v={},m=0,d=2;if(gu(f,function(_){v[_]=r[_]}),gu(f,function(_){s(t,_)&&(c[_]=v[_]=t[_]),l(c,_)&&p++,l(v,_)&&m++}),i[h])return l(t,f[1])?v[f[2]]=null:l(t,f[2])&&(v[f[1]]=null),v;if(m===d||!p)return v;if(p>=d)return c;for(var g=0;g=0;l--)s=nt(s,n[l],!0);i.defaultOption=s}return i.defaultOption},t.prototype.getReferringComponents=function(e,i){var n=e+"Index",a=e+"Id";return ui(this.ecModel,e,{index:this.get(n,!0),id:this.get(a,!0)},i)},t.prototype.getBoxLayoutParams=function(){var e=this;return{left:e.get("left"),top:e.get("top"),right:e.get("right"),bottom:e.get("bottom"),width:e.get("width"),height:e.get("height")}},t.prototype.getZLevelKey=function(){return""},t.prototype.setZLevel=function(e){this.option.zlevel=e},t.protoInitialize=function(){var e=t.prototype;e.type="component",e.id="",e.name="",e.mainType="",e.subType="",e.componentIndex=0}(),t}(gt);El(Ia,gt);fi(Ia);C_(Ia);D_(Ia,DA);function DA(r){var t=[];return w(Ia.getClassesByMainType(r),function(e){t=t.concat(e.dependencies||e.prototype.dependencies||[])}),t=z(t,function(e){return me(e).main}),r!=="dataset"&&K(t,"dataset")<=0&&t.unshift("dataset"),t}var ht=Ia;var U_="";typeof navigator<"u"&&(U_=navigator.platform||"");var Na="rgba(0, 0, 0, 0.2)",V_={darkMode:"auto",colorBy:"series",color:["#5470c6","#91cc75","#fac858","#ee6666","#73c0de","#3ba272","#fc8452","#9a60b4","#ea7ccc"],gradientColor:["#f6efa6","#d88273","#bf444c"],aria:{decal:{decals:[{color:Na,dashArrayX:[1,0],dashArrayY:[2,5],symbolSize:1,rotation:Math.PI/6},{color:Na,symbol:"circle",dashArrayX:[[8,8],[0,8,8,0]],dashArrayY:[6,0],symbolSize:.8},{color:Na,dashArrayX:[1,0],dashArrayY:[4,3],rotation:-Math.PI/4},{color:Na,dashArrayX:[[6,6],[0,6,6,0]],dashArrayY:[6,0]},{color:Na,dashArrayX:[[1,0],[1,6]],dashArrayY:[1,0,6,0],rotation:Math.PI/4},{color:Na,symbol:"triangle",dashArrayX:[[9,9],[0,9,9,0]],dashArrayY:[7,2],symbolSize:.75}]}},textStyle:{fontFamily:U_.match(/^Win/)?"Microsoft YaHei":"sans-serif",fontSize:12,fontStyle:"normal",fontWeight:"normal"},blendMode:null,stateAnimation:{duration:300,easing:"cubicOut"},animation:"auto",animationDuration:1e3,animationDurationUpdate:500,animationEasing:"cubicInOut",animationEasingUpdate:"cubicInOut",animationThreshold:2e3,progressiveThreshold:3e3,progressive:400,hoverLayerThreshold:3e3,useUTC:!1};var yu=W(["tooltip","label","itemName","itemId","itemGroupId","itemChildGroupId","seriesName"]),qt="original",Zt="arrayRows",Se="objectRows",$e="keyedColumns",Ne="typedArray",vp="unknown",Je="column",jr="row";var ce={Must:1,Might:2,Not:3},H_=et();function G_(r){H_(r).datasetMap=W()}function W_(r,t,e){var i={},n=dp(t);if(!n||!r)return i;var a=[],o=[],s=t.ecModel,l=H_(s).datasetMap,u=n.uid+"_"+e.seriesLayoutBy,f,h;r=r.slice(),w(r,function(m,d){var g=H(m)?m:r[d]={name:m};g.type==="ordinal"&&f==null&&(f=d,h=v(g)),i[g.name]=[]});var c=l.get(u)||l.set(u,{categoryWayDim:h,valueWayDim:0});w(r,function(m,d){var g=m.name,y=v(m);if(f==null){var _=c.valueWayDim;p(i[g],_,y),p(o,_,y),c.valueWayDim+=y}else if(f===d)p(i[g],0,y),p(a,0,y);else{var _=c.categoryWayDim;p(i[g],_,y),p(o,_,y),c.categoryWayDim+=y}});function p(m,d,g){for(var y=0;yt)return r[i];return r[e-1]}function LA(r,t,e,i,n,a,o){a=a||r;var s=t(a),l=s.paletteIdx||0,u=s.paletteNameMap=s.paletteNameMap||{};if(u.hasOwnProperty(n))return u[n];var f=o==null||!i?e:EA(i,o);if(f=f||e,!(!f||!f.length)){var h=f[l];return n&&(u[n]=h),s.paletteIdx=(l+1)%f.length,h}}function PA(r,t){t(r).paletteIdx=0,t(r).paletteNameMap={}}var xu,ns,Z_,K_="\0_ec_inner",OA=1;var J_=function(r){O(t,r);function t(){return r!==null&&r.apply(this,arguments)||this}return t.prototype.init=function(e,i,n,a,o,s){a=a||{},this.option=null,this._theme=new gt(a),this._locale=new gt(o),this._optionManager=s},t.prototype.setOption=function(e,i,n){var a=$_(i);this._optionManager.setOption(e,n,a),this._resetOption(null,a)},t.prototype.resetOption=function(e,i){return this._resetOption(e,$_(i))},t.prototype._resetOption=function(e,i){var n=!1,a=this._optionManager;if(!e||e==="recreate"){var o=a.mountOption(e==="recreate");!this.option||e==="recreate"?Z_(this,o):(this.restoreData(),this._mergeOption(o,i)),n=!0}if((e==="timeline"||e==="media")&&this.restoreData(),!e||e==="recreate"||e==="timeline"){var s=a.getTimelineOption(this);s&&(n=!0,this._mergeOption(s,i))}if(!e||e==="recreate"||e==="media"){var l=a.getMediaOption(this);l.length&&w(l,function(u){n=!0,this._mergeOption(u,i)},this)}return n},t.prototype.mergeOption=function(e){this._mergeOption(e,null)},t.prototype._mergeOption=function(e,i){var n=this.option,a=this._componentsMap,o=this._componentsCount,s=[],l=W(),u=i&&i.replaceMergeMainTypeMap;G_(this),w(e,function(h,c){h!=null&&(ht.hasClass(c)?c&&(s.push(c),l.set(c,!0)):n[c]=n[c]==null?j(h):nt(n[c],h,!0))}),u&&u.each(function(h,c){ht.hasClass(c)&&!l.get(c)&&(s.push(c),l.set(c,!0))}),ht.topologicalTravel(s,ht.getAllClassMainTypes(),f,this);function f(h){var c=X_(this,h,bt(e[h])),p=a.get(h),v=p?u&&u.get(h)?"replaceMerge":"normalMerge":"replaceAll",m=Pg(p,c,v);Rg(m,h,ht),n[h]=null,a.set(h,null),o.set(h,0);var d=[],g=[],y=0,_,x;w(m,function(b,S){var T=b.existing,C=b.newOption;if(!C)T&&(T.mergeOption({},this),T.optionUpdated({},!1));else{var A=h==="series",M=ht.getClass(h,b.keyInfo.subType,!A);if(!M){if(0)var D,L;return}if(h==="tooltip"){if(_)return;_=!0}if(T&&T.constructor===M)T.name=b.keyInfo.name,T.mergeOption(C,this),T.optionUpdated(C,!1);else{var R=I({componentIndex:S},b.keyInfo);T=new M(C,this,this,R),I(T,R),b.brandNew&&(T.__requireNewView=!0),T.init(C,this,this),T.optionUpdated(null,!0)}}T?(d.push(T.option),g.push(T),y++):(d.push(void 0),g.push(void 0))},this),n[h]=d,a.set(h,g),o.set(h,y),h==="series"&&xu(this)}this._seriesIndices||xu(this)},t.prototype.getOption=function(){var e=j(this.option);return w(e,function(i,n){if(ht.hasClass(n)){for(var a=bt(i),o=a.length,s=!1,l=o-1;l>=0;l--)a[l]&&!va(a[l])?s=!0:(a[l]=null,!s&&o--);a.length=o,e[n]=a}}),delete e[K_],e},t.prototype.getTheme=function(){return this._theme},t.prototype.getLocaleModel=function(){return this._locale},t.prototype.setUpdatePayload=function(e){this._payload=e},t.prototype.getUpdatePayload=function(){return this._payload},t.prototype.getComponent=function(e,i){var n=this._componentsMap.get(e);if(n){var a=n[i||0];if(a)return a;if(i==null){for(var o=0;o=t:e==="max"?r<=t:r===t}function GA(r,t){return r.join(",")===t.join(",")}var t0=BA;var vr=w,os=H,e0=["areaStyle","lineStyle","nodeStyle","linkStyle","chordStyle","label","labelLine"];function gp(r){var t=r&&r.itemStyle;if(t)for(var e=0,i=e0.length;e=0;d--){var g=r[d];if(s||(v=g.data.rawIndexOf(g.stackedByDimension,p)),v>=0){var y=g.data.getByRawIndex(g.stackResultDimension,v);if(l==="all"||l==="positive"&&y>0||l==="negative"&&y<0||l==="samesign"&&c>=0&&y>0||l==="samesign"&&c<=0&&y<0){c=wg(c,y),m=y;break}}}return i[0]=c,i[1]=m,i})})}var Tu=function(){function r(t){this.data=t.data||(t.sourceFormat===$e?{}:[]),this.sourceFormat=t.sourceFormat||vp,this.seriesLayoutBy=t.seriesLayoutBy||Je,this.startIndex=t.startIndex||0,this.dimensionsDetectedCount=t.dimensionsDetectedCount,this.metaRawOption=t.metaRawOption;var e=this.dimensionsDefine=t.dimensionsDefine;if(e)for(var i=0;im&&(m=_)}p[0]=v,p[1]=m}},n=function(){return this._data?this._data.length/this._dimSize:0};f0=(t={},t[Zt+"_"+Je]={pure:!0,appendData:a},t[Zt+"_"+jr]={pure:!0,appendData:function(){throw new Error('Do not support appendData when set seriesLayoutBy: "row".')}},t[Se]={pure:!0,appendData:a},t[$e]={pure:!0,appendData:function(o){var s=this._data;w(o,function(l,u){for(var f=s[u]||(s[u]=[]),h=0;h<(l||[]).length;h++)f.push(l[h])})}},t[qt]={appendData:a},t[Ne]={persistent:!1,pure:!0,appendData:function(o){this._data=o},clean:function(){this._offset+=this.count(),this._data=null}},t);function a(o){for(var s=0;s=0&&(m=o.interpolatedValue[d])}return m!=null?m+"":""})}},r.prototype.getRawValue=function(t,e){return $r(this.getData(e),t)},r.prototype.formatTooltip=function(t,e,i){},r}();function Ap(r){var t,e;return H(r)?r.type&&(e=r):t=r,{text:t,frag:e}}function Si(r){return new iM(r)}var iM=function(){function r(t){t=t||{},this._reset=t.reset,this._plan=t.plan,this._count=t.count,this._onDirty=t.onDirty,this._dirty=!0}return r.prototype.perform=function(t){var e=this._upstream,i=t&&t.skip;if(this._dirty&&e){var n=this.context;n.data=n.outputData=e.context.outputData}this.__pipeline&&(this.__pipeline.currentTask=this);var a;this._plan&&!i&&(a=this._plan(this.context));var o=f(this._modBy),s=this._modDataCount||0,l=f(t&&t.modBy),u=t&&t.modDataCount||0;(o!==l||s!==u)&&(a="reset");function f(y){return!(y>=1)&&(y=1),y}var h;(this._dirty||a==="reset")&&(this._dirty=!1,h=this._doReset(i)),this._modBy=l,this._modDataCount=u;var c=t&&t.step;if(e?this._dueEnd=e._outputDueEnd:this._dueEnd=this._count?this._count(this.context):1/0,this._progress){var p=this._dueIndex,v=Math.min(c!=null?this._dueIndex+c:1/0,this._dueEnd);if(!i&&(h||p1&&i>0?s:o}};return a;function o(){return t=r?null:lt},gte:function(r,t){return r>=t}},RB=function(){function r(t,e){if(!ot(e)){var i="";Ft(i)}this._opFn=nM[t],this._rvalFloat=Ye(e)}return r.prototype.evaluate=function(t){return ot(t)?this._opFn(t,this._rvalFloat):this._opFn(Ye(t),this._rvalFloat)},r}(),d0=function(){function r(t,e){var i=t==="desc";this._resultLT=i?1:-1,e==null&&(e=i?"min":"max"),this._incomparable=e==="min"?-1/0:1/0}return r.prototype.evaluate=function(t,e){var i=ot(t)?t:Ye(t),n=ot(e)?e:Ye(e),a=isNaN(i),o=isNaN(n);if(a&&(i=this._incomparable),o&&(n=this._incomparable),a&&o){var s=F(t),l=F(e);s&&(i=l?t:0),l&&(n=s?e:0)}return in?-this._resultLT:0},r}();var IB=function(){function r(t,e){this._rval=e,this._isEQ=t,this._rvalTypeof=typeof e,this._rvalFloat=Ye(e)}return r.prototype.evaluate=function(t){var e=t===this._rval;if(!e){var i=typeof t;i!==this._rvalTypeof&&(i==="number"||this._rvalTypeof==="number")&&(e=Ye(t)===this._rvalFloat)}return this._isEQ?e:!e},r}();var aM=function(){function r(){}return r.prototype.getRawData=function(){throw new Error("not supported")},r.prototype.getRawDataItem=function(t){throw new Error("not supported")},r.prototype.cloneRawData=function(){},r.prototype.getDimensionInfo=function(t){},r.prototype.cloneAllDimensionInfo=function(){},r.prototype.count=function(){},r.prototype.retrieveValue=function(t,e){},r.prototype.retrieveValueFromItem=function(t,e){},r.prototype.convertValue=function(t,e){return er(t,e)},r}();function oM(r,t){var e=new aM,i=r.data,n=e.sourceFormat=r.sourceFormat,a=r.startIndex,o="";r.seriesLayoutBy!==Je&&Ft(o);var s=[],l={},u=r.dimensionsDefine;if(u)w(u,function(m,d){var g=m.name,y={index:d,name:g,displayName:m.displayName};if(s.push(y),g!=null){var _="";U(l,g)&&Ft(_),l[g]=y}});else for(var f=0;f65535?cM:pM}function Ba(){return[1/0,-1/0]}function vM(r){var t=r.constructor;return t===Array?r.slice():new t(r)}function x0(r,t,e,i,n){var a=S0[e||"float"];if(n){var o=r[t],s=o&&o.length;if(s!==i){for(var l=new a(i),u=0;ud[1]&&(d[1]=m)}return this._rawCount=this._count=l,{start:s,end:l}},r.prototype._initDataFromProvider=function(t,e,i){for(var n=this._provider,a=this._chunks,o=this._dimensions,s=o.length,l=this._rawExtent,u=z(o,function(y){return y.property}),f=0;fg[1]&&(g[1]=d)}}!n.persistent&&n.clean&&n.clean(),this._rawCount=this._count=e,this._extent=[]},r.prototype.count=function(){return this._count},r.prototype.get=function(t,e){if(!(e>=0&&e=0&&e=this._rawCount||t<0)return-1;if(!this._indices)return t;var e=this._indices,i=e[t];if(i!=null&&it)a=o-1;else return o}return-1},r.prototype.indicesOfNearest=function(t,e,i){var n=this._chunks,a=n[t],o=[];if(!a)return o;i==null&&(i=1/0);for(var s=1/0,l=-1,u=0,f=0,h=this.count();f=0&&l<0)&&(s=v,l=p,u=0),p===l&&(o[u++]=f))}return o.length=u,o},r.prototype.getIndices=function(){var t,e=this._indices;if(e){var i=e.constructor,n=this._count;if(i===Array){t=new i(n);for(var a=0;a=h&&y<=c||isNaN(y))&&(l[u++]=m),m++}v=!0}else if(a===2){for(var d=p[n[0]],_=p[n[1]],x=t[n[1]][0],b=t[n[1]][1],g=0;g=h&&y<=c||isNaN(y))&&(S>=x&&S<=b||isNaN(S))&&(l[u++]=m),m++}v=!0}}if(!v)if(a===1)for(var g=0;g=h&&y<=c||isNaN(y))&&(l[u++]=T)}else for(var g=0;gt[M][1])&&(C=!1)}C&&(l[u++]=e.getRawIndex(g))}return ug[1]&&(g[1]=d)}}}},r.prototype.lttbDownSample=function(t,e){var i=this.clone([t],!0),n=i._chunks,a=n[t],o=this.count(),s=0,l=Math.floor(1/e),u=this.getRawIndex(0),f,h,c,p=new(fs(this._rawCount))(Math.min((Math.ceil(o/l)+2)*2,o));p[s++]=u;for(var v=1;vf&&(f=h,c=x)}D>0&&Df-v&&(l=f-v,s.length=l);for(var m=0;mh[1]&&(h[1]=g),c[p++]=y}return a._count=p,a._indices=c,a._updateGetRawIdx(),a},r.prototype.each=function(t,e){if(this._count)for(var i=t.length,n=this._chunks,a=0,o=this.count();al&&(l=h)}return o=[s,l],this._extent[t]=o,o},r.prototype.getRawDataItem=function(t){var e=this.getRawIndex(t);if(this._provider.persistent)return this._provider.getItem(e);for(var i=[],n=this._chunks,a=0;a=0?this._indices[t]:-1},r.prototype._updateGetRawIdx=function(){this.getRawIndex=this._indices?this._getRawIdx:this._getRawIdxIdentity},r.internalField=function(){function t(e,i,n,a){return er(e[a],this._dimensions[a])}Ep={arrayRows:t,objectRows:function(e,i,n,a){return er(e[i],this._dimensions[a])},keyedColumns:t,original:function(e,i,n,a){var o=e&&(e.value==null?e:e.value);return er(o instanceof Array?o[a]:o,this._dimensions[a])},typedArray:function(e,i,n,a){return e[a]}}}(),r}(),hs=dM;var w0=function(){function r(t){this._sourceList=[],this._storeList=[],this._upstreamSignList=[],this._versionSignBase=0,this._dirty=!0,this._sourceHost=t}return r.prototype.dirty=function(){this._setLocalSource([],[]),this._storeList=[],this._dirty=!0},r.prototype._setLocalSource=function(t,e){this._sourceList=t,this._upstreamSignList=e,this._versionSignBase++,this._versionSignBase>9e10&&(this._versionSignBase=0)},r.prototype._getVersionSign=function(){return this._sourceHost.uid+"_"+this._versionSignBase},r.prototype.prepareSource=function(){this._isDirty()&&(this._createSource(),this._dirty=!1)},r.prototype._createSource=function(){this._setLocalSource([],[]);var t=this._sourceHost,e=this._getUpstreamSourceManagers(),i=!!e.length,n,a;if(Mu(t)){var o=t,s=void 0,l=void 0,u=void 0;if(i){var f=e[0];f.prepareSource(),u=f.getSource(),s=u.data,l=u.sourceFormat,a=[f._getVersionSign()]}else s=o.get("data",!0),l=Et(s)?Ne:qt,a=[];var h=this._getSourceMetaRawOption()||{},c=u&&u.metaRawOption||{},p=Q(h.seriesLayoutBy,c.seriesLayoutBy)||null,v=Q(h.sourceHeader,c.sourceHeader),m=Q(h.dimensions,c.dimensions),d=p!==c.seriesLayoutBy||!!v!=!!c.sourceHeader||m;n=d?[ls(s,{seriesLayoutBy:p,sourceHeader:v,dimensions:m},l)]:[]}else{var g=t;if(i){var y=this._applyTransform(e);n=y.sourceList,a=y.upstreamSignList}else{var _=g.get("source",!0);n=[ls(_,this._getSourceMetaRawOption(),null)],a=[]}}this._setLocalSource(n,a)},r.prototype._applyTransform=function(t){var e=this._sourceHost,i=e.get("transform",!0),n=e.get("fromTransformResult",!0);if(n!=null){var a="";t.length!==1&&b0(a)}var o,s=[],l=[];return w(t,function(u){u.prepareSource();var f=u.getSource(n||0),h="";n!=null&&!f&&b0(h),s.push(f),l.push(u._getVersionSign())}),i?o=y0(i,s,{datasetIndex:e.componentIndex}):n!=null&&(o=[u0(s[0])]),{sourceList:o,upstreamSignList:l}},r.prototype._isDirty=function(){if(this._dirty)return!0;for(var t=this._getUpstreamSourceManagers(),e=0;e1||e>0&&!r.noHeader;return w(r.blocks,function(n){var a=A0(n);a>=t&&(t=a+ +(i&&(!a||Pp(n)&&!n.noHeader)))}),t}return 0}function yM(r,t,e,i){var n=t.noHeader,a=xM(A0(t)),o=[],s=t.blocks||[];Ht(!s||N(s)),s=s||[];var l=r.orderMode;if(t.sortBlocks&&l){s=s.slice();var u={valueAsc:"asc",valueDesc:"desc"};if(U(u,l)){var f=new d0(u[l],null);s.sort(function(v,m){return f.evaluate(v.sortParam,m.sortParam)})}else l==="seriesDesc"&&s.reverse()}w(s,function(v,m){var d=t.valueFormatter,g=D0(v)(d?I(I({},r),{valueFormatter:d}):r,v,m>0?a.html:0,i);g!=null&&o.push(g)});var h=r.renderMode==="richText"?o.join(a.richText):Op(o.join(""),n?e:a.html);if(n)return h;var c=pu(t.header,"ordinal",r.useUTC),p=C0(i,r.renderMode).nameStyle;return r.renderMode==="richText"?M0(r,c,p)+a.richText+h:Op('
'+Wt(c)+"
"+h,e)}function _M(r,t,e,i){var n=r.renderMode,a=t.noName,o=t.noValue,s=!t.markerType,l=t.name,u=r.useUTC,f=t.valueFormatter||r.valueFormatter||function(x){return x=N(x)?x:[x],z(x,function(b,S){return pu(b,N(p)?p[S]:p,u)})};if(!(a&&o)){var h=s?"":r.markupStyleCreator.makeTooltipMarker(t.markerType,t.markerColor||"#333",n),c=a?"":pu(l,"ordinal",u),p=t.valueType,v=o?[]:f(t.value,t.dataIndex),m=!s||!a,d=!s&&a,g=C0(i,n),y=g.nameStyle,_=g.valueStyle;return n==="richText"?(s?"":h)+(a?"":M0(r,c,y))+(o?"":wM(r,v,m,d,_)):Op((s?"":h)+(a?"":SM(c,!s,y))+(o?"":bM(v,m,d,_)),e)}}function Rp(r,t,e,i,n,a){if(r){var o=D0(r),s={useUTC:n,renderMode:e,orderMode:i,markupStyleCreator:t,valueFormatter:r.valueFormatter};return o(s,r,0,a)}}function xM(r){return{html:mM[r],richText:gM[r]}}function Op(r,t){var e='
',i="margin: "+t+"px 0 0";return'
'+r+e+"
"}function SM(r,t,e){var i=t?"margin-left:2px":"";return''+Wt(r)+""}function bM(r,t,e,i){var n=e?"10px":"20px",a=t?"float:right;margin-left:"+n:"";return r=N(r)?r:[r],''+z(r,function(o){return Wt(o)}).join("  ")+""}function M0(r,t,e){return r.markupStyleCreator.wrapRichTextStyle(t,e)}function wM(r,t,e,i,n){var a=[n],o=i?10:20;return e&&a.push({padding:[0,0,0,o],align:"right"}),r.markupStyleCreator.wrapRichTextStyle(N(t)?t.join(" "):t,a)}function E0(r,t){var e=r.getData().getItemVisual(t,"style"),i=e[r.visualDrawType];return pr(i)}function Eu(r,t){var e=r.get("padding");return e??(t==="richText"?[8,10]:10)}var Lu=function(){function r(){this.richTextStyles={},this._nextStyleNameId=Al()}return r.prototype._generateStyleName=function(){return"__EC_aUTo_"+this._nextStyleNameId++},r.prototype.makeTooltipMarker=function(t,e,i){var n=i==="richText"?this._generateStyleName():null,a=vu({color:e,type:t,renderMode:i,markerId:n});return F(a)?a:(this.richTextStyles[n]=a.style,a.content)},r.prototype.wrapRichTextStyle=function(t,e){var i={};N(e)?w(e,function(a){return I(i,a)}):I(i,e);var n=this._generateStyleName();return this.richTextStyles[n]=i,"{"+n+"|"+t+"}"},r}();function L0(r){var t=r.series,e=r.dataIndex,i=r.multipleSeries,n=t.getData(),a=n.mapDimensionsAll("defaultedTooltip"),o=a.length,s=t.getRawValue(e),l=N(s),u=E0(t,e),f,h,c,p;if(o>1||l&&!o){var v=TM(s,t,e,a,u);f=v.inlineValues,h=v.inlineValueTypes,c=v.blocks,p=v.inlineValues[0]}else if(o){var m=n.getDimensionInfo(a[0]);p=f=$r(n,e,a[0]),h=m.type}else p=f=l?s[0]:s;var d=da(t),g=d&&t.name||"",y=n.getName(e),_=i?g:y;return Lr("section",{header:g,noHeader:i||!d,sortParam:p,blocks:[Lr("nameValue",{markerType:"item",markerColor:u,name:_,noName:!Gt(_),value:f,valueType:h,dataIndex:e})].concat(c||[])})}function TM(r,t,e,i,n){var a=t.getData(),o=Vt(r,function(h,c,p){var v=a.getDimensionInfo(p);return h=h||v&&v.tooltip!==!1&&v.displayName!=null},!1),s=[],l=[],u=[];i.length?w(i,function(h){f($r(a,e,h),h)}):w(r,f);function f(h,c){var p=a.getDimensionInfo(c);!p||p.otherDims.tooltip===!1||(o?u.push(Lr("nameValue",{markerType:"subItem",markerColor:n,name:p.displayName,value:h,valueType:p.type})):(s.push(h),l.push(p.type)))}return{inlineValues:s,inlineValueTypes:l,blocks:u}}var bi=et();function Pu(r,t){return r.getName(t)||r.getId(t)}var CM="__universalTransitionEnabled",Ou=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e._selectedDataIndicesMap={},e}return t.prototype.init=function(e,i,n){this.seriesIndex=this.componentIndex,this.dataTask=Si({count:AM,reset:MM}),this.dataTask.context={model:this},this.mergeDefaultAndTheme(e,n);var a=bi(this).sourceManager=new w0(this);a.prepareSource();var o=this.getInitialData(e,n);O0(o,this),this.dataTask.context.data=o,bi(this).dataBeforeProcessed=o,P0(this),this._initSelectedMapFromData(o)},t.prototype.mergeDefaultAndTheme=function(e,i){var n=_i(this),a=n?xi(e):{},o=this.subType;ht.hasClass(o)&&(o+="Series"),nt(e,i.getTheme().get(this.subType)),nt(e,this.getDefaultOption()),Ao(e,"label",["show"]),this.fillDataTextStyle(e.data),n&&Er(e,a,n)},t.prototype.mergeOption=function(e,i){e=nt(this.option,e,!0),this.fillDataTextStyle(e.data);var n=_i(this);n&&Er(this.option,e,n);var a=bi(this).sourceManager;a.dirty(),a.prepareSource();var o=this.getInitialData(e,i);O0(o,this),this.dataTask.dirty(),this.dataTask.context.data=o,bi(this).dataBeforeProcessed=o,P0(this),this._initSelectedMapFromData(o)},t.prototype.fillDataTextStyle=function(e){if(e&&!Et(e))for(var i=["show"],n=0;nthis.getShallow("animationThreshold")&&(i=!1),!!i},t.prototype.restoreData=function(){this.dataTask.dirty()},t.prototype.getColorFromPalette=function(e,i,n){var a=this.ecModel,o=is.prototype.getColorFromPalette.call(this,e,i,n);return o||(o=a.getColorFromPalette(e,i,n)),o},t.prototype.coordDimToDataDim=function(e){return this.getRawData().mapDimensionsAll(e)},t.prototype.getProgressive=function(){return this.get("progressive")},t.prototype.getProgressiveThreshold=function(){return this.get("progressiveThreshold")},t.prototype.select=function(e,i){this._innerSelect(this.getData(i),e)},t.prototype.unselect=function(e,i){var n=this.option.selectedMap;if(n){var a=this.option.selectedMode,o=this.getData(i);if(a==="series"||n==="all"){this.option.selectedMap={},this._selectedDataIndicesMap={};return}for(var s=0;s=0&&n.push(o)}return n},t.prototype.isSelected=function(e,i){var n=this.option.selectedMap;if(!n)return!1;var a=this.getData(i);return(n==="all"||n[Pu(a,e)])&&!a.getItemModel(e).get(["select","disabled"])},t.prototype.isUniversalTransitionEnabled=function(){if(this[CM])return!0;var e=this.option.universalTransition;return e?e===!0?!0:e&&e.enabled:!1},t.prototype._innerSelect=function(e,i){var n,a,o=this.option,s=o.selectedMode,l=i.length;if(!(!s||!l)){if(s==="series")o.selectedMap="all";else if(s==="multiple"){H(o.selectedMap)||(o.selectedMap={});for(var u=o.selectedMap,f=0;f0&&this._innerSelect(e,i)}},t.registerClass=function(e){return ht.registerClass(e)},t.protoInitialize=function(){var e=t.prototype;e.type="series.__base__",e.seriesIndex=0,e.ignoreStyleOnData=!1,e.hasSymbolVisual=!1,e.defaultSymbol="circle",e.visualStyleAccessPath="itemStyle",e.visualDrawType="fill"}(),t}(ht);Nt(Ou,us);Nt(Ou,is);El(Ou,ht);function P0(r){var t=r.name;da(r)||(r.name=DM(r)||t)}function DM(r){var t=r.getRawData(),e=t.mapDimensionsAll("seriesName"),i=[];return w(e,function(n){var a=t.getDimensionInfo(n);a.displayName&&i.push(a.displayName)}),i.join(" ")}function AM(r){return r.model.getRawData().count()}function MM(r){var t=r.model;return t.setData(t.getRawData().cloneShallow()),EM}function EM(r,t){t.outputData&&r.end>t.outputData.count()&&t.model.getRawData().cloneShallow(t.outputData)}function O0(r,t){w(ih(r.CHANGABLE_METHODS,r.DOWNSAMPLE_METHODS),function(e){r.wrapMethod(e,st(LM,t))})}function LM(r,t){var e=Ip(r);return e&&e.setOutputEnd((t||this).count()),t}function Ip(r){var t=(r.ecModel||{}).scheduler,e=t&&t.getPipeline(r.uid);if(e){var i=e.currentTask;if(i){var n=i.agentStubMap;n&&(i=n.get(r.uid))}return i}}var Ut=Ou;var Np=function(){function r(){this.group=new lt,this.uid=yi("viewComponent")}return r.prototype.init=function(t,e){},r.prototype.render=function(t,e,i,n){},r.prototype.dispose=function(t,e){},r.prototype.updateView=function(t,e,i,n){},r.prototype.updateLayout=function(t,e,i,n){},r.prototype.updateVisual=function(t,e,i,n){},r.prototype.toggleBlurSeries=function(t,e,i){},r.prototype.eachRendered=function(t){var e=this.group;e&&e.traverse(t)},r}();ma(Np);fi(Np);var Rt=Np;function Fn(){var r=et();return function(t){var e=r(t),i=t.pipelineContext,n=!!e.large,a=!!e.progressiveRender,o=e.large=!!(i&&i.large),s=e.progressiveRender=!!(i&&i.progressiveRender);return(n!==o||a!==s)&&"reset"}}var N0=et(),PM=Fn(),kp=function(){function r(){this.group=new lt,this.uid=yi("viewChart"),this.renderTask=Si({plan:OM,reset:RM}),this.renderTask.context={view:this}}return r.prototype.init=function(t,e){},r.prototype.render=function(t,e,i,n){},r.prototype.highlight=function(t,e,i,n){var a=t.getData(n&&n.dataType);a&&I0(a,n,"emphasis")},r.prototype.downplay=function(t,e,i,n){var a=t.getData(n&&n.dataType);a&&I0(a,n,"normal")},r.prototype.remove=function(t,e){this.group.removeAll()},r.prototype.dispose=function(t,e){},r.prototype.updateView=function(t,e,i,n){this.render(t,e,i,n)},r.prototype.updateLayout=function(t,e,i,n){this.render(t,e,i,n)},r.prototype.updateVisual=function(t,e,i,n){this.render(t,e,i,n)},r.prototype.eachRendered=function(t){cr(this.group,t)},r.markUpdateMethod=function(t,e){N0(t).updateMethod=e},r.protoInitialize=function(){var t=r.prototype;t.type="chart"}(),r}();function R0(r,t,e){r&&Fo(r)&&(t==="emphasis"?Xr:qr)(r,e)}function I0(r,t,e){var i=Xe(r,t),n=t&&t.highlightKey!=null?By(t.highlightKey):null;i!=null?w(bt(i),function(a){R0(r.getItemGraphicEl(a),e,n)}):r.eachItemGraphicEl(function(a){R0(a,e,n)})}ma(kp,["dispose"]);fi(kp);function OM(r){return PM(r.model)}function RM(r){var t=r.model,e=r.ecModel,i=r.api,n=r.payload,a=t.pipelineContext.progressiveRender,o=r.view,s=n&&N0(n).updateMethod,l=a?"incrementalPrepareRender":s&&o[s]?s:"render";return l!=="render"&&o[l](t,e,i,n),IM[l]}var IM={incrementalPrepareRender:{progress:function(r,t){t.view.incrementalRender(r,t.model,t.ecModel,t.api,t.payload)}},render:{forceFirstProgress:!0,progress:function(r,t){t.view.render(t.model,t.ecModel,t.api,t.payload)}}},It=kp;var Ru="\0__throttleOriginMethod",k0="\0__throttleRate",z0="\0__throttleType";function Bn(r,t,e){var i,n=0,a=0,o=null,s,l,u,f;t=t||0;function h(){a=new Date().getTime(),o=null,r.apply(l,u||[])}var c=function(){for(var p=[],v=0;v=0?h():o=setTimeout(h,-s),n=i};return c.clear=function(){o&&(clearTimeout(o),o=null)},c.debounceNextCall=function(p){f=p},c}function Iu(r,t,e,i){var n=r[t];if(n){var a=n[Ru]||n,o=n[z0],s=n[k0];if(s!==e||o!==i){if(e==null||!i)return r[t]=a;n=r[t]=Bn(a,e,i==="debounce"),n[Ru]=a,n[z0]=i,n[k0]=e}return n}}function cs(r,t){var e=r[t];e&&e[Ru]&&(e.clear&&e.clear(),r[t]=e[Ru])}var F0=et(),B0={itemStyle:Sr(Kc,!0),lineStyle:Sr(Zc,!0)},kM={lineStyle:"stroke",itemStyle:"fill"};function U0(r,t){var e=r.visualStyleMapper||B0[t];return e||(console.warn("Unknown style type '"+t+"'."),B0.itemStyle)}function V0(r,t){var e=r.visualDrawType||kM[t];return e||(console.warn("Unknown style type '"+t+"'."),"fill")}var H0={createOnAllSeries:!0,performRawSeries:!0,reset:function(r,t){var e=r.getData(),i=r.visualStyleAccessPath||"itemStyle",n=r.getModel(i),a=U0(r,i),o=a(n),s=n.getShallow("decal");s&&(e.setVisual("decal",s),s.dirty=!0);var l=V0(r,i),u=o[l],f=G(u)?u:null,h=o.fill==="auto"||o.stroke==="auto";if(!o[l]||f||h){var c=r.getColorFromPalette(r.name,null,t.getSeriesCount());o[l]||(o[l]=c,e.setVisual("colorFromPalette",!0)),o.fill=o.fill==="auto"||G(o.fill)?c:o.fill,o.stroke=o.stroke==="auto"||G(o.stroke)?c:o.stroke}if(e.setVisual("style",o),e.setVisual("drawType",l),!t.isSeriesFiltered(r)&&f)return e.setVisual("colorFromPalette",!1),{dataEach:function(p,v){var m=r.getDataParams(v),d=I({},o);d[l]=f(m),p.setItemVisual(v,"style",d)}}}},ps=new gt,G0={createOnAllSeries:!0,performRawSeries:!0,reset:function(r,t){if(!(r.ignoreStyleOnData||t.isSeriesFiltered(r))){var e=r.getData(),i=r.visualStyleAccessPath||"itemStyle",n=U0(r,i),a=e.getVisual("drawType");return{dataEach:e.hasItemOption?function(o,s){var l=o.getRawDataItem(s);if(l&&l[i]){ps.option=l[i];var u=n(ps),f=o.ensureUniqueItemVisual(s,"style");I(f,u),ps.option.decal&&(o.setItemVisual(s,"decal",ps.option.decal),ps.option.decal.dirty=!0),a in u&&o.setItemVisual(s,"colorFromPalette",!1)}}:null}}}},W0={performRawSeries:!0,overallReset:function(r){var t=W();r.eachSeries(function(e){var i=e.getColorBy();if(!e.isColorBySeries()){var n=e.type+"-"+i,a=t.get(n);a||(a={},t.set(n,a)),F0(e).scope=a}}),r.eachSeries(function(e){if(!(e.isColorBySeries()||r.isSeriesFiltered(e))){var i=e.getRawData(),n={},a=e.getData(),o=F0(e).scope,s=e.visualStyleAccessPath||"itemStyle",l=V0(e,s);a.each(function(u){var f=a.getRawIndex(u);n[f]=u}),i.each(function(u){var f=n[u],h=a.getItemVisual(f,"colorFromPalette");if(h){var c=a.ensureUniqueItemVisual(f,"style"),p=i.getName(u)||u+"",v=i.count();c[l]=e.getColorFromPalette(p,o,v)}})}})}};var Nu=Math.PI;function zp(r,t){t=t||{},X(t,{text:"loading",textColor:"#000",fontSize:12,fontWeight:"normal",fontStyle:"normal",fontFamily:"sans-serif",maskColor:"rgba(255, 255, 255, 0.8)",showSpinner:!0,color:"#5470c6",spinnerRadius:10,lineWidth:5,zlevel:0});var e=new lt,i=new vt({style:{fill:t.maskColor},zlevel:t.zlevel,z:1e4});e.add(i);var n=new St({style:{text:t.text,fill:t.textColor,fontSize:t.fontSize,fontWeight:t.fontWeight,fontStyle:t.fontStyle,fontFamily:t.fontFamily},zlevel:t.zlevel,z:10001}),a=new vt({style:{fill:"none"},textContent:n,textConfig:{position:"right",distance:10},zlevel:t.zlevel,z:10001});e.add(a);var o;return t.showSpinner&&(o=new Cn({shape:{startAngle:-Nu/2,endAngle:-Nu/2+.1,r:t.spinnerRadius},style:{stroke:t.color,lineCap:"round",lineWidth:t.lineWidth},zlevel:t.zlevel,z:10001}),o.animateShape(!0).when(1e3,{endAngle:Nu*3/2}).start("circularInOut"),o.animateShape(!0).when(1e3,{startAngle:Nu*3/2}).delay(300).start("circularInOut"),e.add(o)),e.resize=function(){var s=n.getBoundingRect().width,l=t.showSpinner?t.spinnerRadius:0,u=(r.getWidth()-l*2-(t.showSpinner&&s?10:0)-s)/2-(t.showSpinner&&s?0:5+s/2)+(t.showSpinner?0:s/2)+(s?0:l),f=r.getHeight()/2;t.showSpinner&&o.setShape({cx:u,cy:f}),a.setShape({x:u-l,y:f-l,width:l*2,height:l*2}),i.setShape({x:0,y:0,width:r.getWidth(),height:r.getHeight()})},e.resize(),e}var zM=function(){function r(t,e,i,n){this._stageTaskMap=W(),this.ecInstance=t,this.api=e,i=this._dataProcessorHandlers=i.slice(),n=this._visualHandlers=n.slice(),this._allHandlers=i.concat(n)}return r.prototype.restoreData=function(t,e){t.restoreData(e),this._stageTaskMap.each(function(i){var n=i.overallTask;n&&n.dirty()})},r.prototype.getPerformArgs=function(t,e){if(t.__pipeline){var i=this._pipelineMap.get(t.__pipeline.id),n=i.context,a=!e&&i.progressiveEnabled&&(!n||n.progressiveRender)&&t.__idxInPipeline>i.blockIndex,o=a?i.step:null,s=n&&n.modDataCount,l=s!=null?Math.ceil(s/o):null;return{step:o,modBy:l,modDataCount:s}}},r.prototype.getPipeline=function(t){return this._pipelineMap.get(t)},r.prototype.updateStreamModes=function(t,e){var i=this._pipelineMap.get(t.uid),n=t.getData(),a=n.count(),o=i.progressiveEnabled&&e.incrementalPrepareRender&&a>=i.threshold,s=t.get("large")&&a>=t.get("largeThreshold"),l=t.get("progressiveChunkMode")==="mod"?a:null;t.pipelineContext=i.context={progressiveRender:o,modDataCount:l,large:s}},r.prototype.restorePipelines=function(t){var e=this,i=e._pipelineMap=W();t.eachSeries(function(n){var a=n.getProgressive(),o=n.uid;i.set(o,{id:o,head:null,tail:null,threshold:n.getProgressiveThreshold(),progressiveEnabled:a&&!(n.preventIncremental&&n.preventIncremental()),blockIndex:-1,step:Math.round(a||700),count:0}),e._pipe(n,n.dataTask)})},r.prototype.prepareStageTasks=function(){var t=this._stageTaskMap,e=this.api.getModel(),i=this.api;w(this._allHandlers,function(n){var a=t.get(n.uid)||t.set(n.uid,{}),o="";Ht(!(n.reset&&n.overallReset),o),n.reset&&this._createSeriesStageTask(n,a,e,i),n.overallReset&&this._createOverallStageTask(n,a,e,i)},this)},r.prototype.prepareView=function(t,e,i,n){var a=t.renderTask,o=a.context;o.model=e,o.ecModel=i,o.api=n,a.__block=!t.incrementalPrepareRender,this._pipe(e,a)},r.prototype.performDataProcessorTasks=function(t,e){this._performStageTasks(this._dataProcessorHandlers,t,e,{block:!0})},r.prototype.performVisualTasks=function(t,e,i){this._performStageTasks(this._visualHandlers,t,e,i)},r.prototype._performStageTasks=function(t,e,i,n){n=n||{};var a=!1,o=this;w(t,function(l,u){if(!(n.visualType&&n.visualType!==l.visualType)){var f=o._stageTaskMap.get(l.uid),h=f.seriesTaskMap,c=f.overallTask;if(c){var p,v=c.agentStubMap;v.each(function(d){s(n,d)&&(d.dirty(),p=!0)}),p&&c.dirty(),o.updatePayload(c,i);var m=o.getPerformArgs(c,n.block);v.each(function(d){d.perform(m)}),c.perform(m)&&(a=!0)}else h&&h.each(function(d,g){s(n,d)&&d.dirty();var y=o.getPerformArgs(d,n.block);y.skip=!l.performRawSeries&&e.isSeriesFiltered(d.context.model),o.updatePayload(d,i),d.perform(y)&&(a=!0)})}});function s(l,u){return l.setDirty&&(!l.dirtyMap||l.dirtyMap.get(u.__pipeline.id))}this.unfinished=a||this.unfinished},r.prototype.performSeriesTasks=function(t){var e;t.eachSeries(function(i){e=i.dataTask.perform()||e}),this.unfinished=e||this.unfinished},r.prototype.plan=function(){this._pipelineMap.each(function(t){var e=t.tail;do{if(e.__block){t.blockIndex=e.__idxInPipeline;break}e=e.getUpstream()}while(e)})},r.prototype.updatePayload=function(t,e){e!=="remain"&&(t.context.payload=e)},r.prototype._createSeriesStageTask=function(t,e,i,n){var a=this,o=e.seriesTaskMap,s=e.seriesTaskMap=W(),l=t.seriesType,u=t.getTargetSeries;t.createOnAllSeries?i.eachRawSeries(f):l?i.eachRawSeriesByType(l,f):u&&u(i,n).each(f);function f(h){var c=h.uid,p=s.set(c,o&&o.get(c)||Si({plan:HM,reset:GM,count:YM}));p.context={model:h,ecModel:i,api:n,useClearVisual:t.isVisual&&!t.isLayout,plan:t.plan,reset:t.reset,scheduler:a},a._pipe(h,p)}},r.prototype._createOverallStageTask=function(t,e,i,n){var a=this,o=e.overallTask=e.overallTask||Si({reset:FM});o.context={ecModel:i,api:n,overallReset:t.overallReset,scheduler:a};var s=o.agentStubMap,l=o.agentStubMap=W(),u=t.seriesType,f=t.getTargetSeries,h=!0,c=!1,p="";Ht(!t.createOnAllSeries,p),u?i.eachRawSeriesByType(u,v):f?f(i,n).each(v):(h=!1,w(i.getSeries(),v));function v(m){var d=m.uid,g=l.set(d,s&&s.get(d)||(c=!0,Si({reset:BM,onDirty:VM})));g.context={model:m,overallProgress:h},g.agent=o,g.__block=h,a._pipe(m,g)}c&&o.dirty()},r.prototype._pipe=function(t,e){var i=t.uid,n=this._pipelineMap.get(i);!n.head&&(n.head=e),n.tail&&n.tail.pipe(e),n.tail=e,e.__idxInPipeline=n.count++,e.__pipeline=n},r.wrapStageHandler=function(t,e){return G(t)&&(t={overallReset:t,seriesType:XM(t)}),t.uid=yi("stageHandler"),e&&(t.visualType=e),t},r}();function FM(r){r.overallReset(r.ecModel,r.api,r.payload)}function BM(r){return r.overallProgress&&UM}function UM(){this.agent.dirty(),this.getDownstream().dirty()}function VM(){this.agent&&this.agent.dirty()}function HM(r){return r.plan?r.plan(r.model,r.ecModel,r.api,r.payload):null}function GM(r){r.useClearVisual&&r.data.clearAllVisual();var t=r.resetDefines=bt(r.reset(r.model,r.ecModel,r.api,r.payload));return t.length>1?z(t,function(e,i){return Y0(i)}):WM}var WM=Y0(0);function Y0(r){return function(t,e){var i=e.data,n=e.resetDefines[r];if(n&&n.dataEach)for(var a=t.start;a0&&p===u.length-c.length){var v=u.slice(0,p);v!=="data"&&(e.mainType=v,e[c.toLowerCase()]=l,f=!0)}}s.hasOwnProperty(u)&&(i[u]=l,f=!0),f||(n[u]=l)})}return{cptQuery:e,dataQuery:i,otherQuery:n}},r.prototype.filter=function(t,e){var i=this.eventInfo;if(!i)return!0;var n=i.targetEl,a=i.packedEvent,o=i.model,s=i.view;if(!o||!s)return!0;var l=e.cptQuery,u=e.dataQuery;return f(l,o,"mainType")&&f(l,o,"subType")&&f(l,o,"index","componentIndex")&&f(l,o,"name")&&f(l,o,"id")&&f(u,a,"name")&&f(u,a,"dataIndex")&&f(u,a,"dataType")&&(!s.filterForExposedEvent||s.filterForExposedEvent(t,e.otherQuery,n,a));function f(h,c,p,v){return h[p]==null||c[v||p]===h[p]}},r.prototype.afterTrigger=function(){this.eventInfo=null},r}();var Bp=["symbol","symbolSize","symbolRotate","symbolOffset"],ex=Bp.concat(["symbolKeepAspect"]),rx={createOnAllSeries:!0,performRawSeries:!0,reset:function(r,t){var e=r.getData();if(r.legendIcon&&e.setVisual("legendIcon",r.legendIcon),!r.hasSymbolVisual)return;for(var i={},n={},a=!1,o=0;o=0&&Hn(l)?l:.5;var u=r.createRadialGradient(o,s,0,o,s,l);return u}function ms(r,t,e){for(var i=t.type==="radial"?oE(r,t,e):aE(r,t,e),n=t.colorStops,a=0;a0)?null:r==="dashed"?[4*t,2*t]:r==="dotted"?[t]:ot(r)?[r]:N(r)?r:null}function Vp(r){var t=r.style,e=t.lineDash&&t.lineWidth>0&&sE(t.lineDash,t.lineWidth),i=t.lineDashOffset;if(e){var n=t.strokeNoScale&&r.getLineScale?r.getLineScale():1;n&&n!==1&&(e=z(e,function(a){return a/n}),i/=n)}return[e,i]}var lE=new Pe(!0);function Bu(r){var t=r.stroke;return!(t==null||t==="none"||!(r.lineWidth>0))}function lx(r){return typeof r=="string"&&r!=="none"}function Uu(r){var t=r.fill;return t!=null&&t!=="none"}function ux(r,t){if(t.fillOpacity!=null&&t.fillOpacity!==1){var e=r.globalAlpha;r.globalAlpha=t.fillOpacity*t.opacity,r.fill(),r.globalAlpha=e}else r.fill()}function fx(r,t){if(t.strokeOpacity!=null&&t.strokeOpacity!==1){var e=r.globalAlpha;r.globalAlpha=t.strokeOpacity*t.opacity,r.stroke(),r.globalAlpha=e}else r.stroke()}function Vu(r,t,e){var i=ec(t.image,t.__image,e);if(ga(i)){var n=r.createPattern(i,t.repeat||"repeat");if(typeof DOMMatrix=="function"&&n&&n.setTransform){var a=new DOMMatrix;a.translateSelf(t.x||0,t.y||0),a.rotateSelf(0,0,(t.rotation||0)*qs),a.scaleSelf(t.scaleX||1,t.scaleY||1),n.setTransform(a)}return n}}function uE(r,t,e,i){var n,a=Bu(e),o=Uu(e),s=e.strokePercent,l=s<1,u=!t.path;(!t.silent||l)&&u&&t.createPathProxy();var f=t.path||lE,h=t.__dirty;if(!i){var c=e.fill,p=e.stroke,v=o&&!!c.colorStops,m=a&&!!p.colorStops,d=o&&!!c.image,g=a&&!!p.image,y=void 0,_=void 0,x=void 0,b=void 0,S=void 0;(v||m)&&(S=t.getBoundingRect()),v&&(y=h?ms(r,c,S):t.__canvasFillGradient,t.__canvasFillGradient=y),m&&(_=h?ms(r,p,S):t.__canvasStrokeGradient,t.__canvasStrokeGradient=_),d&&(x=h||!t.__canvasFillPattern?Vu(r,c,t):t.__canvasFillPattern,t.__canvasFillPattern=x),g&&(b=h||!t.__canvasStrokePattern?Vu(r,p,t):t.__canvasStrokePattern,t.__canvasStrokePattern=x),v?r.fillStyle=y:d&&(x?r.fillStyle=x:o=!1),m?r.strokeStyle=_:g&&(b?r.strokeStyle=b:a=!1)}var T=t.getGlobalScale();f.setScale(T[0],T[1],t.segmentIgnoreThreshold);var C,A;r.setLineDash&&e.lineDash&&(n=Vp(t),C=n[0],A=n[1]);var M=!0;(u||h&ai)&&(f.setDPR(r.dpr),l?f.setContext(null):(f.setContext(r),M=!1),f.reset(),t.buildPath(f,t.shape,i),f.toStatic(),t.pathUpdated()),M&&f.rebuildPath(r,l?s:1),C&&(r.setLineDash(C),r.lineDashOffset=A),i||(e.strokeFirst?(a&&fx(r,e),o&&ux(r,e)):(o&&ux(r,e),a&&fx(r,e))),C&&r.setLineDash([])}function fE(r,t,e){var i=t.__image=ec(e.image,t.__image,t,t.onload);if(!(!i||!ga(i))){var n=e.x||0,a=e.y||0,o=t.getWidth(),s=t.getHeight(),l=i.width/i.height;if(o==null&&s!=null?o=s*l:s==null&&o!=null?s=o/l:o==null&&s==null&&(o=i.width,s=i.height),e.sWidth&&e.sHeight){var u=e.sx||0,f=e.sy||0;r.drawImage(i,u,f,e.sWidth,e.sHeight,n,a,o,s)}else if(e.sx&&e.sy){var u=e.sx,f=e.sy,h=o-u,c=s-f;r.drawImage(i,u,f,h,c,n,a,o,s)}else r.drawImage(i,n,a,o,s)}}function hE(r,t,e){var i,n=e.text;if(n!=null&&(n+=""),n){r.font=e.font||sr,r.textAlign=e.textAlign,r.textBaseline=e.textBaseline;var a=void 0,o=void 0;r.setLineDash&&e.lineDash&&(i=Vp(t),a=i[0],o=i[1]),a&&(r.setLineDash(a),r.lineDashOffset=o),e.strokeFirst?(Bu(e)&&r.strokeText(n,e.x,e.y),Uu(e)&&r.fillText(n,e.x,e.y)):(Uu(e)&&r.fillText(n,e.x,e.y),Bu(e)&&r.strokeText(n,e.x,e.y)),a&&r.setLineDash([])}}var hx=["shadowBlur","shadowOffsetX","shadowOffsetY"],cx=[["lineCap","butt"],["lineJoin","miter"],["miterLimit",10]];function yx(r,t,e,i,n){var a=!1;if(!i&&(e=e||{},t===e))return!1;if(i||t.opacity!==e.opacity){be(r,n),a=!0;var o=Math.max(Math.min(t.opacity,1),0);r.globalAlpha=isNaN(o)?br.opacity:o}(i||t.blend!==e.blend)&&(a||(be(r,n),a=!0),r.globalCompositeOperation=t.blend||br.blend);for(var s=0;s0&&e.unfinished);e.unfinished||this._zr.flush()}}},t.prototype.getDom=function(){return this._dom},t.prototype.getId=function(){return this.id},t.prototype.getZr=function(){return this._zr},t.prototype.isSSR=function(){return this._ssr},t.prototype.setOption=function(e,i,n){if(!this[ae]){if(this._disposed){this.id;return}var a,o,s;if(H(i)&&(n=i.lazyUpdate,a=i.silent,o=i.replaceMerge,s=i.transition,i=i.notMerge),this[ae]=!0,!this._model||i){var l=new t0(this._api),u=this._theme,f=this._model=new Su;f.scheduler=this._scheduler,f.ssr=this._ssr,f.init(null,null,null,u,this._locale,l)}this._model.setOption(e,{replaceMerge:o},Jp);var h={seriesTransition:s,optionChanged:!0};if(n)this[we]={silent:a,updateParams:h},this[ae]=!1,this.getZr().wakeUp();else{try{Ga(this),Ti.update.call(this,null,h)}catch(c){throw this[we]=null,this[ae]=!1,c}this._ssr||this._zr.flush(),this[we]=null,this[ae]=!1,_s.call(this,a),xs.call(this,a)}}},t.prototype.setTheme=function(){},t.prototype.getModel=function(){return this._model},t.prototype.getOption=function(){return this._model&&this._model.getOption()},t.prototype.getWidth=function(){return this._zr.getWidth()},t.prototype.getHeight=function(){return this._zr.getHeight()},t.prototype.getDevicePixelRatio=function(){return this._zr.painter.dpr||Y.hasGlobalWindow&&window.devicePixelRatio||1},t.prototype.getRenderedCanvas=function(e){return this.renderToCanvas(e)},t.prototype.renderToCanvas=function(e){e=e||{};var i=this._zr.painter;return i.getRenderedCanvas({backgroundColor:e.backgroundColor||this._model.get("backgroundColor"),pixelRatio:e.pixelRatio||this.getDevicePixelRatio()})},t.prototype.renderToSVGString=function(e){e=e||{};var i=this._zr.painter;return i.renderToString({useViewBox:e.useViewBox})},t.prototype.getSvgDataURL=function(){if(Y.svgSupported){var e=this._zr,i=e.storage.getDisplayList();return w(i,function(n){n.stopAnimation(null,!0)}),e.painter.toDataURL()}},t.prototype.getDataURL=function(e){if(this._disposed){this.id;return}e=e||{};var i=e.excludeComponents,n=this._model,a=[],o=this;w(i,function(l){n.eachComponent({mainType:l},function(u){var f=o._componentsMap[u.__viewId];f.group.ignore||(a.push(f),f.group.ignore=!0)})});var s=this._zr.painter.getType()==="svg"?this.getSvgDataURL():this.renderToCanvas(e).toDataURL("image/"+(e&&e.type||"png"));return w(a,function(l){l.group.ignore=!1}),s},t.prototype.getConnectedDataURL=function(e){if(this._disposed){this.id;return}var i=e.type==="svg",n=this.group,a=Math.min,o=Math.max,s=1/0;if(qu[n]){var l=s,u=s,f=-s,h=-s,c=[],p=e&&e.pixelRatio||this.getDevicePixelRatio();w(Wn,function(_,x){if(_.group===n){var b=i?_.getZr().painter.getSvgDom().innerHTML:_.renderToCanvas(j(e)),S=_.getDom().getBoundingClientRect();l=a(S.left,l),u=a(S.top,u),f=o(S.right,f),h=o(S.bottom,h),c.push({dom:b,left:S.left,top:S.top})}}),l*=p,u*=p,f*=p,h*=p;var v=f-l,m=h-u,d=se.createCanvas(),g=wl(d,{renderer:i?"svg":"canvas"});if(g.resize({width:v,height:m}),i){var y="";return w(c,function(_){var x=_.left-l,b=_.top-u;y+=''+_.dom+""}),g.painter.getSvgRoot().innerHTML=y,e.connectedBackgroundColor&&g.painter.setBackgroundColor(e.connectedBackgroundColor),g.refreshImmediately(),g.painter.toDataURL()}else return e.connectedBackgroundColor&&g.add(new vt({shape:{x:0,y:0,width:v,height:m},style:{fill:e.connectedBackgroundColor}})),w(c,function(_){var x=new ee({style:{x:_.left*p-l,y:_.top*p-u,image:_.dom}});g.add(x)}),g.refreshImmediately(),d.toDataURL("image/"+(e&&e.type||"png"))}else return this.getDataURL(e)},t.prototype.convertToPixel=function(e,i){return Zp(this,"convertToPixel",e,i)},t.prototype.convertFromPixel=function(e,i){return Zp(this,"convertFromPixel",e,i)},t.prototype.containPixel=function(e,i){if(this._disposed){this.id;return}var n=this._model,a,o=Ml(n,e);return w(o,function(s,l){l.indexOf("Models")>=0&&w(s,function(u){var f=u.coordinateSystem;if(f&&f.containPoint)a=a||!!f.containPoint(i);else if(l==="seriesModels"){var h=this._chartsMap[u.__viewId];h&&h.containPoint&&(a=a||h.containPoint(i,u))}},this)},this),!!a},t.prototype.getVisual=function(e,i){var n=this._model,a=Ml(n,e,{defaultMainType:"series"}),o=a.seriesModel,s=o.getData(),l=a.hasOwnProperty("dataIndexInside")?a.dataIndexInside:a.hasOwnProperty("dataIndex")?s.indexOfRawIndex(a.dataIndex):null;return l!=null?nx(s,l,i):Ua(s,i)},t.prototype.getViewOfComponentModel=function(e){return this._componentsMap[e.__viewId]},t.prototype.getViewOfSeriesModel=function(e){return this._chartsMap[e.__viewId]},t.prototype._initEvents=function(){var e=this;w(NE,function(i){var n=function(a){var o=e.getModel(),s=a.target,l,u=i==="globalout";if(u?l={}:s&&Un(s,function(v){var m=it(v);if(m&&m.dataIndex!=null){var d=m.dataModel||o.getSeriesByIndex(m.seriesIndex);return l=d&&d.getDataParams(m.dataIndex,m.dataType,s)||{},!0}else if(m.eventData)return l=I({},m.eventData),!0},!0),l){var f=l.componentType,h=l.componentIndex;(f==="markLine"||f==="markPoint"||f==="markArea")&&(f="series",h=l.seriesIndex);var c=f&&h!=null&&o.getComponent(f,h),p=c&&e[c.mainType==="series"?"_chartsMap":"_componentsMap"][c.__viewId];l.event=a,l.type=i,e._$eventProcessor.eventInfo={targetEl:s,packedEvent:l,model:c,view:p},e.trigger(i,l)}};n.zrEventfulCallAtLast=!0,e._zr.on(i,n,e)}),w(Ss,function(i,n){e._messageCenter.on(n,function(a){this.trigger(n,a)},e)}),w(["selectchanged"],function(i){e._messageCenter.on(i,function(n){this.trigger(i,n)},e)}),ax(this._messageCenter,this,this._api)},t.prototype.isDisposed=function(){return this._disposed},t.prototype.clear=function(){if(this._disposed){this.id;return}this.setOption({series:[]},!0)},t.prototype.dispose=function(){if(this._disposed){this.id;return}this._disposed=!0;var e=this.getDom();e&&Qh(this.getDom(),nv,"");var i=this,n=i._api,a=i._model;w(i._componentsViews,function(o){o.dispose(a,n)}),w(i._chartsViews,function(o){o.dispose(a,n)}),i._zr.dispose(),i._dom=i._model=i._chartsMap=i._componentsMap=i._chartsViews=i._componentsViews=i._scheduler=i._api=i._zr=i._throttledZrFlush=i._theme=i._coordSysMgr=i._messageCenter=null,delete Wn[i.id]},t.prototype.resize=function(e){if(!this[ae]){if(this._disposed){this.id;return}this._zr.resize(e);var i=this._model;if(this._loadingFX&&this._loadingFX.resize(),!!i){var n=i.resetOption("media"),a=e&&e.silent;this[we]&&(a==null&&(a=this[we].silent),n=!0,this[we]=null),this[ae]=!0;try{n&&Ga(this),Ti.update.call(this,{type:"resize",animation:I({duration:0},e&&e.animation)})}catch(o){throw this[ae]=!1,o}this[ae]=!1,_s.call(this,a),xs.call(this,a)}}},t.prototype.showLoading=function(e,i){if(this._disposed){this.id;return}if(H(e)&&(i=e,e=""),e=e||"default",this.hideLoading(),!!tv[e]){var n=tv[e](this._api,i),a=this._zr;this._loadingFX=n,a.add(n)}},t.prototype.hideLoading=function(){if(this._disposed){this.id;return}this._loadingFX&&this._zr.remove(this._loadingFX),this._loadingFX=null},t.prototype.makeActionFromEvent=function(e){var i=I({},e);return i.type=Ss[e.type],i},t.prototype.dispatchAction=function(e,i){if(this._disposed){this.id;return}if(H(i)||(i={silent:!!i}),!!Yu[e.type]&&this._model){if(this[ae]){this._pendingActions.push(e);return}var n=i.silent;jp.call(this,e,n);var a=i.flush;a?this._zr.flush():a!==!1&&Y.browser.weChat&&this._throttledZrFlush(),_s.call(this,n),xs.call(this,n)}},t.prototype.updateLabelLayout=function(){rr.trigger("series:layoutlabels",this._model,this._api,{updatedSeries:[]})},t.prototype.appendData=function(e){if(this._disposed){this.id;return}var i=e.seriesIndex,n=this.getModel(),a=n.getSeriesByIndex(i);a.appendData(e),this._scheduler.unfinished=!0,this.getZr().wakeUp()},t.internalField=function(){Ga=function(h){var c=h._scheduler;c.restorePipelines(h._model),c.prepareStageTasks(),qp(h,!0),qp(h,!1),c.plan()},qp=function(h,c){for(var p=h._model,v=h._scheduler,m=c?h._componentsViews:h._chartsViews,d=c?h._componentsMap:h._chartsMap,g=h._zr,y=h._api,_=0;_c.get("hoverLayerThreshold")&&!Y.node&&!Y.worker&&c.eachSeries(function(d){if(!d.preventUsingHoverLayer){var g=h._chartsMap[d.__viewId];g.__alive&&g.eachRendered(function(y){y.states.emphasis&&(y.states.emphasis.hoverLayer=!0)})}})}function o(h,c){var p=h.get("blendMode")||null;c.eachRendered(function(v){v.isGroup||(v.style.blend=p)})}function s(h,c){if(!h.preventAutoZ){var p=h.get("z")||0,v=h.get("zlevel")||0;c.eachRendered(function(m){return l(m,p,v,-1/0),!0})}}function l(h,c,p,v){var m=h.getTextContent(),d=h.getTextGuideLine(),g=h.isGroup;if(g)for(var y=h.childrenRef(),_=0;_0?{duration:m,delay:p.get("delay"),easing:p.get("easing")}:null;c.eachRendered(function(g){if(g.states&&g.states.emphasis){if(Mn(g))return;if(g instanceof Z&&Uy(g),g.__dirty){var y=g.prevStates;y&&g.useStates(y)}if(v){g.stateTransition=d;var _=g.getTextContent(),x=g.getTextGuideLine();_&&(_.stateTransition=d),x&&(x.stateTransition=d)}g.__dirty&&n(g)}})}Rx=function(h){return new(function(c){O(p,c);function p(){return c!==null&&c.apply(this,arguments)||this}return p.prototype.getCoordinateSystems=function(){return h._coordSysMgr.getCoordinateSystems()},p.prototype.getComponentByElement=function(v){for(;v;){var m=v.__ecComponentInfo;if(m!=null)return h._model.getComponent(m.mainType,m.index);v=v.parent}},p.prototype.enterEmphasis=function(v,m){Xr(v,m),ir(h)},p.prototype.leaveEmphasis=function(v,m){qr(v,m),ir(h)},p.prototype.enterBlur=function(v){Fl(v),ir(h)},p.prototype.leaveBlur=function(v){zo(v),ir(h)},p.prototype.enterSelect=function(v){Dc(v),ir(h)},p.prototype.leaveSelect=function(v){Ac(v),ir(h)},p.prototype.getModel=function(){return h.getModel()},p.prototype.getViewOfComponentModel=function(v){return h.getViewOfComponentModel(v)},p.prototype.getViewOfSeriesModel=function(v){return h.getViewOfSeriesModel(v)},p}(bu))(h)},Wx=function(h){function c(p,v){for(var m=0;m=0)){Nx.push(e);var a=Fp.wrapStageHandler(e,n);a.__prio=t,a.__raw=e,r.push(a)}}function Qu(r,t){tv[r]=t}function WE(r){Ws({createCanvas:r})}function cv(r,t,e){var i=Wp("registerMap");i&&i(r,t,e)}function YE(r){var t=Wp("getMap");return t&&t(r)}var pv=g0;Jr(ev,H0);Jr(Zu,G0);Jr(Zu,W0);Jr(ev,rx);Jr(Zu,ix);Jr(Fx,Gp);Ku(wu);ju(TE,xp);Qu("default",zp);Ci({type:di,event:di,update:di},kt);Ci({type:No,event:No,update:No},kt);Ci({type:xa,event:xa,update:xa},kt);Ci({type:ko,event:ko,update:ko},kt);Ci({type:Sa,event:Sa,update:Sa},kt);ov("light",K0);ov("dark",J0);var XE={};function ws(r){return r==null?0:r.length||1}function qx(r){return r}var qE=function(){function r(t,e,i,n,a,o){this._old=t,this._new=e,this._oldKeyGetter=i||qx,this._newKeyGetter=n||qx,this.context=a,this._diffModeMultiple=o==="multiple"}return r.prototype.add=function(t){return this._add=t,this},r.prototype.update=function(t){return this._update=t,this},r.prototype.updateManyToOne=function(t){return this._updateManyToOne=t,this},r.prototype.updateOneToMany=function(t){return this._updateOneToMany=t,this},r.prototype.updateManyToMany=function(t){return this._updateManyToMany=t,this},r.prototype.remove=function(t){return this._remove=t,this},r.prototype.execute=function(){this[this._diffModeMultiple?"_executeMultiple":"_executeOneToOne"]()},r.prototype._executeOneToOne=function(){var t=this._old,e=this._new,i={},n=new Array(t.length),a=new Array(e.length);this._initIndexMap(t,null,n,"_oldKeyGetter"),this._initIndexMap(e,i,a,"_newKeyGetter");for(var o=0;o1){var f=l.shift();l.length===1&&(i[s]=l[0]),this._update&&this._update(f,o)}else u===1?(i[s]=null,this._update&&this._update(l,o)):this._remove&&this._remove(o)}this._performRestAdd(a,i)},r.prototype._executeMultiple=function(){var t=this._old,e=this._new,i={},n={},a=[],o=[];this._initIndexMap(t,i,a,"_oldKeyGetter"),this._initIndexMap(e,n,o,"_newKeyGetter");for(var s=0;s1&&c===1)this._updateManyToOne&&this._updateManyToOne(f,u),n[l]=null;else if(h===1&&c>1)this._updateOneToMany&&this._updateOneToMany(f,u),n[l]=null;else if(h===1&&c===1)this._update&&this._update(f,u),n[l]=null;else if(h>1&&c>1)this._updateManyToMany&&this._updateManyToMany(f,u),n[l]=null;else if(h>1)for(var p=0;p1)for(var s=0;s30}var Ts=H,Di=z,JE=typeof Int32Array>"u"?Array:Int32Array,tL="e\0\0",jx=-1,eL=["hasItemOption","_nameList","_idList","_invertedIndicesMap","_dimSummary","userOutput","_rawData","_dimValueGetter","_nameDimIdx","_idDimIdx","_nameRepeatCount"],rL=["_approximateExtent"],Qx,tf,Cs,Ds,_v,ef,xv,iL=function(){function r(t,e){this.type="list",this._dimOmitted=!1,this._nameList=[],this._idList=[],this._visual={},this._layout={},this._itemVisuals=[],this._itemLayouts=[],this._graphicEls=[],this._approximateExtent={},this._calculationInfo={},this.hasItemOption=!1,this.TRANSFERABLE_METHODS=["cloneShallow","downSample","lttbDownSample","map"],this.CHANGABLE_METHODS=["filterSelf","selectRange"],this.DOWNSAMPLE_METHODS=["downSample","lttbDownSample"];var i,n=!1;Ju(t)?(i=t.dimensions,this._dimOmitted=t.isDimensionOmitted(),this._schema=t):(n=!0,i=t),i=i||["x","y"];for(var a={},o=[],s={},l=!1,u={},f=0;f=e)){var i=this._store,n=i.getProvider();this._updateOrdinalMeta();var a=this._nameList,o=this._idList,s=n.getSource().sourceFormat,l=s===qt;if(l&&!n.pure)for(var u=[],f=t;f0},r.prototype.ensureUniqueItemVisual=function(t,e){var i=this._itemVisuals,n=i[t];n||(n=i[t]={});var a=n[e];return a==null&&(a=this.getVisual(e),N(a)?a=a.slice():Ts(a)&&(a=I({},a)),n[e]=a),a},r.prototype.setItemVisual=function(t,e,i){var n=this._itemVisuals[t]||{};this._itemVisuals[t]=n,Ts(e)?I(n,e):n[e]=i},r.prototype.clearAllVisual=function(){this._visual={},this._itemVisuals=[]},r.prototype.setLayout=function(t,e){Ts(t)?I(this._layout,t):this._layout[t]=e},r.prototype.getLayout=function(t){return this._layout[t]},r.prototype.getItemLayout=function(t){return this._itemLayouts[t]},r.prototype.setItemLayout=function(t,e,i){this._itemLayouts[t]=i?I(this._itemLayouts[t]||{},e):e},r.prototype.clearItemLayouts=function(){this._itemLayouts.length=0},r.prototype.setItemGraphicEl=function(t,e){var i=this.hostModel&&this.hostModel.seriesIndex;Sy(i,this.dataType,t,e),this._graphicEls[t]=e},r.prototype.getItemGraphicEl=function(t){return this._graphicEls[t]},r.prototype.eachItemGraphicEl=function(t,e){w(this._graphicEls,function(i,n){i&&t&&t.call(e,i,n)})},r.prototype.cloneShallow=function(t){return t||(t=new r(this._schema?this._schema:Di(this.dimensions,this._getDimInfo,this),this.hostModel)),_v(t,this),t._store=this._store,t},r.prototype.wrapMethod=function(t,e){var i=this[t];G(i)&&(this.__wrappedMethods=this.__wrappedMethods||[],this.__wrappedMethods.push(t),this[t]=function(){var n=i.apply(this,arguments);return e.apply(this,[n].concat(eo(arguments)))})},r.internalField=function(){Qx=function(t){var e=t._invertedIndicesMap;w(e,function(i,n){var a=t._dimInfos[n],o=a.ordinalMeta,s=t._store;if(o){i=e[n]=new JE(o.categories.length);for(var l=0;l1&&(l+="__ec__"+f),n[e]=l}}}(),r}(),dr=iL;var Pv={};Me(Pv,{createDimensions:()=>$x,createList:()=>FL,createScale:()=>UL,createSymbol:()=>$t,createTextStyle:()=>HL,dataStack:()=>BL,enableHoverEmphasis:()=>ba,getECData:()=>it,getLayoutRect:()=>Kr,mixinAxisModelCommonMethods:()=>VL});function $x(r,t){return rf(r,t).dimensions}function rf(r,t){za(r)||(r=Fa(r)),t=t||{};var e=t.coordDimensions||[],i=t.dimensionsDefine||r.dimensionsDefine||[],n=W(),a=[],o=aL(r,e,i,t.dimensionsCount),s=t.canOmitUnusedDimensions&&yv(o),l=i===r.dimensionsDefine,u=l?gv(r):mv(i),f=t.encodeDefine;!f&&t.encodeDefaulter&&(f=t.encodeDefaulter(r,o));for(var h=W(f),c=new Lp(o),p=0;p0&&(i.name=n+(a-1)),a++,t.set(n,a)}}function aL(r,t,e,i){var n=Math.max(r.dimensionsDetectedCount||1,t.length,e.length,i||0);return w(t,function(a){var o;H(a)&&(o=a.dimsDef)&&(n=Math.max(n,o.length))}),n}function oL(r,t,e){if(e||t.hasKey(r)){for(var i=0;t.hasKey(r+i);)i++;r+=i}return t.set(r,!0),r}var sL=function(){function r(t){this.coordSysDims=[],this.axisMap=W(),this.categoryAxisMap=W(),this.coordSysName=t}return r}();function Jx(r){var t=r.get("coordinateSystem"),e=new sL(t),i=lL[t];if(i)return i(r,e,e.axisMap,e.categoryAxisMap),e}var lL={cartesian2d:function(r,t,e,i){var n=r.getReferringComponents("xAxis",te).models[0],a=r.getReferringComponents("yAxis",te).models[0];t.coordSysDims=["x","y"],e.set("x",n),e.set("y",a),Ya(n)&&(i.set("x",n),t.firstCategoryDimIndex=0),Ya(a)&&(i.set("y",a),t.firstCategoryDimIndex==null&&(t.firstCategoryDimIndex=1))},singleAxis:function(r,t,e,i){var n=r.getReferringComponents("singleAxis",te).models[0];t.coordSysDims=["single"],e.set("single",n),Ya(n)&&(i.set("single",n),t.firstCategoryDimIndex=0)},polar:function(r,t,e,i){var n=r.getReferringComponents("polar",te).models[0],a=n.findAxisModel("radiusAxis"),o=n.findAxisModel("angleAxis");t.coordSysDims=["radius","angle"],e.set("radius",a),e.set("angle",o),Ya(a)&&(i.set("radius",a),t.firstCategoryDimIndex=0),Ya(o)&&(i.set("angle",o),t.firstCategoryDimIndex==null&&(t.firstCategoryDimIndex=1))},geo:function(r,t,e,i){t.coordSysDims=["lng","lat"]},parallel:function(r,t,e,i){var n=r.ecModel,a=n.getComponent("parallel",r.get("parallelIndex")),o=t.coordSysDims=a.dimensions.slice();w(a.parallelAxisIndex,function(s,l){var u=n.getComponent("parallelAxis",s),f=o[l];e.set(f,u),Ya(u)&&(i.set(f,u),t.firstCategoryDimIndex==null&&(t.firstCategoryDimIndex=l))})}};function Ya(r){return r.get("type")==="category"}function nf(r,t,e){e=e||{};var i=e.byIndex,n=e.stackedCoordDimension,a,o,s;uL(t)?a=t:(o=t.schema,a=o.dimensions,s=t.store);var l=!!(r&&r.get("stack")),u,f,h,c;if(w(a,function(y,_){F(y)&&(a[_]=y={name:y}),l&&!y.isExtraCoord&&(!i&&!u&&y.ordinalMeta&&(u=y),!f&&y.type!=="ordinal"&&y.type!=="time"&&(!n||n===y.coordDim)&&(f=y))}),f&&!i&&!u&&(i=!0),f){h="__\0ecstackresult_"+r.id,c="__\0ecstackedover_"+r.id,u&&(u.createInvertedIndices=!0);var p=f.coordDim,v=f.type,m=0;w(a,function(y){y.coordDim===p&&m++});var d={name:h,coordDim:p,coordDimIndex:m,type:v,isExtraCoord:!0,isCalculationCoord:!0,storeDimIndex:a.length},g={name:c,coordDim:c,coordDimIndex:m+1,type:v,isExtraCoord:!0,isCalculationCoord:!0,storeDimIndex:a.length+1};o?(s&&(d.storeDimIndex=s.ensureCalculationDimension(c,v),g.storeDimIndex=s.ensureCalculationDimension(h,v)),o.appendCalculationDimension(d),o.appendCalculationDimension(g)):(a.push(d),a.push(g))}return{stackedDimension:f&&f.name,stackedByDimension:u&&u.name,isStackedByIndex:i,stackedOverDimension:c,stackResultDimension:h}}function uL(r){return!Ju(r.schema)}function ke(r,t){return!!t&&t===r.getCalculationInfo("stackedDimension")}function Xa(r,t){return ke(r,t)?r.getCalculationInfo("stackResultDimension"):t}function fL(r,t){var e=r.get("coordinateSystem"),i=ka.get(e),n;return t&&t.coordSysDims&&(n=z(t.coordSysDims,function(a){var o={name:a},s=t.axisMap.get(a);if(s){var l=s.get("type");o.type=Kx(l)}return o})),n||(n=i&&(i.getDimensionsInfo?i.getDimensionsInfo():i.dimensions.slice())||["x","y"]),n}function hL(r,t,e){var i,n;return e&&w(r,function(a,o){var s=a.coordDim,l=e.categoryAxisMap.get(s);l&&(i==null&&(i=o),a.ordinalMeta=l.getOrdinalMeta(),t&&(a.createInvertedIndices=!0)),a.otherDims.itemName!=null&&(n=!0)}),!n&&i!=null&&(r[i].otherDims.itemName=0),i}function cL(r,t,e){e=e||{};var i=t.getSourceManager(),n,a=!1;r?(a=!0,n=Fa(r)):(n=i.getSource(),a=n.sourceFormat===qt);var o=Jx(t),s=fL(t,o),l=e.useEncodeDefaulter,u=G(l)?l:l?st(W_,s,t):null,f={coordDimensions:s,generateCoord:e.generateCoord,encodeDefine:t.getEncode(),encodeDefaulter:u,canOmitUnusedDimensions:!a},h=rf(n,f),c=hL(h.dimensions,e.createInvertedIndices,o),p=a?null:i.getSharedDataStore(h),v=nf(t,{schema:h,store:p}),m=new dr(h,t);m.setCalculationInfo(v);var d=c!=null&&pL(n)?function(g,y,_,x){return x===c?_:this.defaultDimValueGetter(g,y,_,x)}:null;return m.hasItemOption=!1,m.initData(a?n:p,null,d),m}function pL(r){if(r.sourceFormat===qt){var t=vL(r.data||[]);return!N(Gr(t))}}function vL(r){for(var t=0;te[1]&&(e[1]=t[1])},r.prototype.unionExtentFromData=function(t,e){this.unionExtent(t.getApproximateExtent(e))},r.prototype.getExtent=function(){return this._extent.slice()},r.prototype.setExtent=function(t,e){var i=this._extent;isNaN(t)||(i[0]=t),isNaN(e)||(i[1]=e)},r.prototype.isInExtentRange=function(t){return this._extent[0]<=t&&this._extent[1]>=t},r.prototype.isBlank=function(){return this._isBlank},r.prototype.setBlank=function(t){this._isBlank=t},r}();fi(tS);var Te=tS;var dL=0,mL=function(){function r(t){this.categories=t.categories||[],this._needCollect=t.needCollect,this._deduplication=t.deduplication,this.uid=++dL}return r.createByAxisModel=function(t){var e=t.option,i=e.data,n=i&&z(i,gL);return new r({categories:n,needCollect:!n,deduplication:e.dedplication!==!1})},r.prototype.getOrdinal=function(t){return this._getOrCreateMap().get(t)},r.prototype.parseAndCollect=function(t){var e,i=this._needCollect;if(!F(t)&&!i)return t;if(i&&!this._deduplication)return e=this.categories.length,this.categories[e]=t,e;var n=this._getOrCreateMap();return e=n.get(t),e==null&&(i?(e=this.categories.length,this.categories[e]=t,n.set(t,e)):e=NaN),e},r.prototype._getOrCreateMap=function(){return this._map||(this._map=W(this.categories))},r}();function gL(r){return H(r)&&r.value!=null?r.value:r+""}var As=mL;function Ms(r){return r.type==="interval"||r.type==="log"}function rS(r,t,e,i){var n={},a=r[1]-r[0],o=n.interval=pa(a/t,!0);e!=null&&oi&&(o=n.interval=i);var s=n.intervalPrecision=Sv(o),l=n.niceTickExtent=[mt(Math.ceil(r[0]/o)*o,s),mt(Math.floor(r[1]/o)*o,s)];return yL(l,r),n}function af(r){var t=Math.pow(10,ca(r)),e=r/t;return e?e===2?e=3:e===3?e=5:e*=2:e=1,mt(e*t)}function Sv(r){return Qt(r)+2}function eS(r,t,e){r[t]=Math.max(Math.min(r[t],e[1]),e[0])}function yL(r,t){!isFinite(r[0])&&(r[0]=t[0]),!isFinite(r[1])&&(r[1]=t[1]),eS(r,0,t),eS(r,1,t),r[0]>r[1]&&(r[0]=r[1])}function Ai(r,t){return r>=t[0]&&r<=t[1]}function Mi(r,t){return t[1]===t[0]?.5:(r-t[0])/(t[1]-t[0])}function Ei(r,t){return r*(t[1]-t[0])+t[0]}var iS=function(r){O(t,r);function t(e){var i=r.call(this,e)||this;i.type="ordinal";var n=i.getSetting("ordinalMeta");return n||(n=new As({})),N(n)&&(n=new As({categories:z(n,function(a){return H(a)?a.value:a})})),i._ordinalMeta=n,i._extent=i.getSetting("extent")||[0,n.categories.length-1],i}return t.prototype.parse=function(e){return e==null?NaN:F(e)?this._ordinalMeta.getOrdinal(e):Math.round(e)},t.prototype.contain=function(e){return e=this.parse(e),Ai(e,this._extent)&&this._ordinalMeta.categories[e]!=null},t.prototype.normalize=function(e){return e=this._getTickNumber(this.parse(e)),Mi(e,this._extent)},t.prototype.scale=function(e){return e=Math.round(Ei(e,this._extent)),this.getRawOrdinalNumber(e)},t.prototype.getTicks=function(){for(var e=[],i=this._extent,n=i[0];n<=i[1];)e.push({value:n}),n++;return e},t.prototype.getMinorTicks=function(e){},t.prototype.setSortInfo=function(e){if(e==null){this._ordinalNumbersByTick=this._ticksByOrdinalNumber=null;return}for(var i=e.ordinalNumbers,n=this._ordinalNumbersByTick=[],a=this._ticksByOrdinalNumber=[],o=0,s=this._ordinalMeta.categories.length,l=Math.min(s,i.length);o=0&&e=0&&e=e},t.prototype.getOrdinalMeta=function(){return this._ordinalMeta},t.prototype.calcNiceTicks=function(){},t.prototype.calcNiceExtent=function(){},t.type="ordinal",t}(Te);Te.registerClass(iS);var bv=iS;var Yn=mt,nS=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type="interval",e._interval=0,e._intervalPrecision=2,e}return t.prototype.parse=function(e){return e},t.prototype.contain=function(e){return Ai(e,this._extent)},t.prototype.normalize=function(e){return Mi(e,this._extent)},t.prototype.scale=function(e){return Ei(e,this._extent)},t.prototype.setExtent=function(e,i){var n=this._extent;isNaN(e)||(n[0]=parseFloat(e)),isNaN(i)||(n[1]=parseFloat(i))},t.prototype.unionExtent=function(e){var i=this._extent;e[0]i[1]&&(i[1]=e[1]),this.setExtent(i[0],i[1])},t.prototype.getInterval=function(){return this._interval},t.prototype.setInterval=function(e){this._interval=e,this._niceExtent=this._extent.slice(),this._intervalPrecision=Sv(e)},t.prototype.getTicks=function(e){var i=this._interval,n=this._extent,a=this._niceExtent,o=this._intervalPrecision,s=[];if(!i)return s;var l=1e4;n[0]l)return[];var f=s.length?s[s.length-1].value:a[1];return n[1]>f&&(e?s.push({value:Yn(f+i,o)}):s.push({value:n[1]})),s},t.prototype.getMinorTicks=function(e){for(var i=this.getTicks(!0),n=[],a=this.getExtent(),o=1;oa[0]&&p0&&(a=a===null?s:Math.min(a,s))}e[i]=a}}return e}function Av(r){var t=xL(r),e=[];return w(r,function(i){var n=i.coordinateSystem,a=n.getBaseAxis(),o=a.getExtent(),s;if(a.type==="category")s=a.getBandWidth();else if(a.type==="value"||a.type==="time"){var l=a.dim+"_"+a.index,u=t[l],f=Math.abs(o[1]-o[0]),h=a.scale.getExtent(),c=Math.abs(h[1]-h[0]);s=u?f/c*u:f}else{var p=i.getData();s=Math.abs(o[1]-o[0])/p.count()}var v=Tt(i.get("barWidth"),s),m=Tt(i.get("barMaxWidth"),s),d=Tt(i.get("barMinWidth")||(cS(i)?.5:1),s),g=i.get("barGap"),y=i.get("barCategoryGap");e.push({bandWidth:s,barWidth:v,barMaxWidth:m,barMinWidth:d,barGap:g,barCategoryGap:y,axisKey:Cv(a),stackId:Tv(i)})}),sS(e)}function sS(r){var t={};w(r,function(i,n){var a=i.axisKey,o=i.bandWidth,s=t[a]||{bandWidth:o,remainedWidth:o,autoWidthCount:0,categoryGap:null,gap:"20%",stacks:{}},l=s.stacks;t[a]=s;var u=i.stackId;l[u]||s.autoWidthCount++,l[u]=l[u]||{width:0,maxWidth:0};var f=i.barWidth;f&&!l[u].width&&(l[u].width=f,f=Math.min(s.remainedWidth,f),s.remainedWidth-=f);var h=i.barMaxWidth;h&&(l[u].maxWidth=h);var c=i.barMinWidth;c&&(l[u].minWidth=c);var p=i.barGap;p!=null&&(s.gap=p);var v=i.barCategoryGap;v!=null&&(s.categoryGap=v)});var e={};return w(t,function(i,n){e[n]={};var a=i.stacks,o=i.bandWidth,s=i.categoryGap;if(s==null){var l=rt(a).length;s=Math.max(35-l*4,15)+"%"}var u=Tt(s,o),f=Tt(i.gap,1),h=i.remainedWidth,c=i.autoWidthCount,p=(h-u)/(c+(c-1)*f);p=Math.max(p,0),w(a,function(g){var y=g.maxWidth,_=g.minWidth;if(g.width){var x=g.width;y&&(x=Math.min(x,y)),_&&(x=Math.max(x,_)),g.width=x,h-=x+f*x,c--}else{var x=p;y&&yx&&(x=_),x!==p&&(g.width=x,h-=x+f*x,c--)}}),p=(h-u)/(c+(c-1)*f),p=Math.max(p,0);var v=0,m;w(a,function(g,y){g.width||(g.width=p),m=g,v+=g.width*(1+f)}),m&&(v-=m.width*f);var d=-v/2;w(a,function(g,y){e[n][y]=e[n][y]||{bandWidth:o,offset:d,width:g.width},d+=g.width*(1+f)})}),e}function lS(r,t,e){if(r&&t){var i=r[Cv(t)];return i!=null&&e!=null?i[Tv(e)]:i}}function uS(r,t){var e=Dv(r,t),i=Av(e);w(e,function(n){var a=n.getData(),o=n.coordinateSystem,s=o.getBaseAxis(),l=Tv(n),u=i[Cv(s)][l],f=u.offset,h=u.width;a.setLayout({bandWidth:u.bandWidth,offset:f,size:h})})}function fS(r){return{seriesType:r,plan:Fn(),reset:function(t){if(hS(t)){var e=t.getData(),i=t.coordinateSystem,n=i.getBaseAxis(),a=i.getOtherAxis(n),o=e.getDimensionIndex(e.mapDimension(a.dim)),s=e.getDimensionIndex(e.mapDimension(n.dim)),l=t.get("showBackground",!0),u=e.mapDimension(a.dim),f=e.getCalculationInfo("stackResultDimension"),h=ke(e,u)&&!!e.getCalculationInfo("stackedOnSeries"),c=a.isHorizontal(),p=SL(n,a),v=cS(t),m=t.get("barMinHeight")||0,d=f&&e.getDimensionIndex(f),g=e.getLayout("size"),y=e.getLayout("offset");return{progress:function(_,x){for(var b=_.count,S=v&&ze(b*3),T=v&&l&&ze(b*3),C=v&&ze(b),A=i.master.getRect(),M=c?A.width:A.height,D,L=x.getStore(),R=0;(D=_.next())!=null;){var E=L.get(h?d:o,D),P=L.get(s,D),k=p,q=void 0;h&&(q=+E-L.get(o,D));var B=void 0,V=void 0,tt=void 0,ft=void 0;if(c){var ct=i.dataToPoint([E,P]);if(h){var yt=i.dataToPoint([q,P]);k=yt[0]}B=k,V=ct[1]+y,tt=ct[0]-k,ft=g,Math.abs(tt)0?e:1:e))}var bL=function(r,t,e,i){for(;e>>1;r[n][1]n&&(this._approxInterval=n);var s=sf.length,l=Math.min(bL(sf,this._approxInterval,0,s),s-1);this._interval=sf[l][1],this._minLevelUnit=sf[Math.max(l-1,0)][0]},t.prototype.parse=function(e){return ot(e)?e:+Yt(e)},t.prototype.contain=function(e){return Ai(this.parse(e),this._extent)},t.prototype.normalize=function(e){return Mi(this.parse(e),this._extent)},t.prototype.scale=function(e){return Ei(e,this._extent)},t.type="time",t}(ti),sf=[["second",fu],["minute",hu],["hour",Pa],["quarter-day",Pa*6],["half-day",Pa*12],["day",Ie*1.2],["half-week",Ie*3.5],["week",Ie*7],["month",Ie*31],["quarter",Ie*95],["half-year",tp/2],["year",tp]];function wL(r,t,e,i){var n=Yt(t),a=Yt(e),o=function(v){return ip(n,v,i)===ip(a,v,i)},s=function(){return o("year")},l=function(){return s()&&o("month")},u=function(){return l()&&o("day")},f=function(){return u()&&o("hour")},h=function(){return f()&&o("minute")},c=function(){return h()&&o("second")},p=function(){return c()&&o("millisecond")};switch(r){case"year":return s();case"month":return l();case"day":return u();case"hour":return f();case"minute":return h();case"second":return c();case"millisecond":return p()}}function TL(r,t){return r/=Ie,r>16?16:r>7.5?7:r>3.5?4:r>1.5?2:1}function CL(r){var t=30*Ie;return r/=t,r>6?6:r>3?3:r>2?2:1}function DL(r){return r/=Pa,r>12?12:r>6?6:r>3.5?4:r>2?2:1}function pS(r,t){return r/=t?hu:fu,r>30?30:r>20?20:r>15?15:r>10?10:r>5?5:r>2?2:1}function AL(r){return pa(r,!0)}function ML(r,t,e){var i=new Date(r);switch(Rn(t)){case"year":case"month":i[np(e)](0);case"day":i[ap(e)](1);case"hour":i[op(e)](0);case"minute":i[sp(e)](0);case"second":i[lp(e)](0),i[up(e)](0)}return i.getTime()}function EL(r,t,e,i){var n=1e4,a=rp,o=0;function s(M,D,L,R,E,P,k){for(var q=new Date(D),B=D,V=q[R]();B1&&P===0&&L.unshift({value:L[0].value-B})}}for(var P=0;P=i[0]&&y<=i[1]&&h++)}var _=(i[1]-i[0])/t;if(h>_*1.5&&c>_/1.5||(u.push(d),h>_||r===a[p]))break}f=[]}}}for(var x=dt(z(u,function(M){return dt(M,function(D){return D.value>=i[0]&&D.value<=i[1]&&!D.notAdd})}),function(M){return M.length>0}),b=[],S=x.length-1,p=0;p0;)a*=10;var s=[mt(OL(i[0]/a)*a),mt(PL(i[1]/a)*a)];this._interval=a,this._niceExtent=s}},t.prototype.calcNiceExtent=function(e){Es.calcNiceExtent.call(this,e),this._fixMin=e.fixMin,this._fixMax=e.fixMax},t.prototype.parse=function(e){return e},t.prototype.contain=function(e){return e=mr(e)/mr(this.base),Ai(e,this._extent)},t.prototype.normalize=function(e){return e=mr(e)/mr(this.base),Mi(e,this._extent)},t.prototype.scale=function(e){return e=Ei(e,this._extent),lf(this.base,e)},t.type="log",t}(Te),gS=Mv.prototype;gS.getMinorTicks=Es.getMinorTicks;gS.getLabel=Es.getLabel;function uf(r,t){return LL(r,Qt(t))}Te.registerClass(Mv);var yS=Mv;var RL=function(){function r(t,e,i){this._prepareParams(t,e,i)}return r.prototype._prepareParams=function(t,e,i){i[1]0&&l>0&&!u&&(s=0),s<0&&l<0&&!f&&(l=0));var c=this._determinedMin,p=this._determinedMax;return c!=null&&(s=c,u=!0),p!=null&&(l=p,f=!0),{min:s,max:l,minFixed:u,maxFixed:f,isBlank:h}},r.prototype.modifyDataMinMax=function(t,e){this[NL[t]]=e},r.prototype.setDeterminedMinMax=function(t,e){var i=IL[t];this[i]=e},r.prototype.freeze=function(){this.frozen=!0},r}();var IL={min:"_determinedMin",max:"_determinedMax"},NL={min:"_dataMin",max:"_dataMax"};function _S(r,t,e){var i=r.rawExtentInfo;return i||(i=new RL(r,t,e),r.rawExtentInfo=i,i)}function ff(r,t){return t==null?null:Vi(t)?NaN:r.parse(t)}function Ev(r,t){var e=r.type,i=_S(r,t,r.getExtent()).calculate();r.setBlank(i.isBlank);var n=i.min,a=i.max,o=t.ecModel;if(o&&e==="time"){var s=Dv("bar",o),l=!1;if(w(s,function(h){l=l||h.getBaseAxis()===t.axis}),l){var u=Av(s),f=kL(n,a,t,u);n=f.min,a=f.max}}return{extent:[n,a],fixMin:i.minFixed,fixMax:i.maxFixed}}function kL(r,t,e,i){var n=e.axis.getExtent(),a=n[1]-n[0],o=lS(i,e.axis);if(o===void 0)return{min:r,max:t};var s=1/0;w(o,function(p){s=Math.min(p.offset,s)});var l=-1/0;w(o,function(p){l=Math.max(p.offset+p.width,l)}),s=Math.abs(s),l=Math.abs(l);var u=s+l,f=t-r,h=1-(s+l)/a,c=f/h-f;return t+=c*(l/u),r-=c*(s/u),{min:r,max:t}}function Ls(r,t){var e=t,i=Ev(r,e),n=i.extent,a=e.get("splitNumber");r instanceof yS&&(r.base=e.get("logBase"));var o=r.type,s=e.get("interval"),l=o==="interval"||o==="time";r.setExtent(n[0],n[1]),r.calcNiceExtent({splitNumber:a,fixMin:i.fixMin,fixMax:i.fixMax,minInterval:l?e.get("minInterval"):null,maxInterval:l?e.get("maxInterval"):null}),s!=null&&r.setInterval&&r.setInterval(s)}function hf(r,t){if(t=t||r.get("type"),t)switch(t){case"category":return new bv({ordinalMeta:r.getOrdinalMeta?r.getOrdinalMeta():r.getCategories(),extent:[1/0,-1/0]});case"time":return new dS({locale:r.ecModel.getLocaleModel(),useUTC:r.ecModel.get("useUTC")});default:return new(Te.getClass(t)||ti)}}function xS(r){var t=r.scale.getExtent(),e=t[0],i=t[1];return!(e>0&&i>0||e<0&&i<0)}function Xn(r){var t=r.getLabelModel().get("formatter"),e=r.type==="category"?r.scale.getExtent()[0]:null;return r.scale.type==="time"?function(i){return function(n,a){return r.scale.getFormattedLabel(n,a,i)}}(t):F(t)?function(i){return function(n){var a=r.scale.getLabel(n),o=i.replace("{value}",a??"");return o}}(t):G(t)?function(i){return function(n,a){return e!=null&&(a=n.value-e),i(Ps(r,n),a,n.level!=null?{level:n.level}:null)}}(t):function(i){return r.scale.getLabel(i)}}function Ps(r,t){return r.type==="category"?r.scale.getLabel(t):t.value}function SS(r){var t=r.model,e=r.scale;if(!(!t.get(["axisLabel","show"])||e.isBlank())){var i,n,a=e.getExtent();e instanceof bv?n=e.count():(i=e.getTicks(),n=i.length);var o=r.getLabelModel(),s=Xn(r),l,u=1;n>40&&(u=Math.ceil(n/40));for(var f=0;f=0||(wS.push(r),G(r)&&(r={install:r}),r.install(GL))}var WL=1e-8;function TS(r,t){return Math.abs(r-t)n&&(i=o,n=l)}if(i)return qL(i.exterior);var u=this.getBoundingRect();return[u.x+u.width/2,u.y+u.height/2]},t.prototype.getBoundingRect=function(e){var i=this._rect;if(i&&!e)return i;var n=[1/0,1/0],a=[-1/0,-1/0],o=this.geometries;return w(o,function(s){s.type==="polygon"?CS(s.exterior,n,a,e):w(s.points,function(l){CS(l,n,a,e)})}),isFinite(n[0])&&isFinite(n[1])&&isFinite(a[0])&&isFinite(a[1])||(n[0]=n[1]=a[0]=a[1]=0),i=new J(n[0],n[1],a[0]-n[0],a[1]-n[1]),e||(this._rect=i),i},t.prototype.contain=function(e){var i=this.getBoundingRect(),n=this.geometries;if(!i.contain(e[0],e[1]))return!1;t:for(var a=0,o=n.length;a>1^-(s&1),l=l>>1^-(l&1),s+=n,l+=a,n=s,a=l,i.push([s/e,l/e])}return i}function df(r,t){return r=ZL(r),z(dt(r.features,function(e){return e.geometry&&e.properties&&e.geometry.coordinates.length>0}),function(e){var i=e.properties,n=e.geometry,a=[];switch(n.type){case"Polygon":var o=n.coordinates;a.push(new Iv(o[0],o.slice(1)));break;case"MultiPolygon":w(n.coordinates,function(l){l[0]&&a.push(new Iv(l[0],l.slice(1)))});break;case"LineString":a.push(new Nv([n.coordinates]));break;case"MultiLineString":a.push(new Nv(n.coordinates))}var s=new AS(i[t||"name"],a,i.cp);return s.properties=i,s})}var zv={};Me(zv,{MAX_SAFE_INTEGER:()=>Tg,asc:()=>wo,getPercentWithPrecision:()=>bg,getPixelPrecision:()=>Cl,getPrecision:()=>Qt,getPrecisionSafe:()=>Zh,isNumeric:()=>Co,isRadianAroundZero:()=>un,linearMap:()=>bo,nice:()=>pa,numericToNumber:()=>Ye,parseDate:()=>Yt,quantile:()=>Cg,quantity:()=>Dl,quantityExponent:()=>ca,reformIntervals:()=>Dg,remRadian:()=>To,round:()=>mt});var Fv={};Me(Fv,{format:()=>Zr,parse:()=>Yt});var Bv={};Me(Bv,{Arc:()=>Cn,BezierCurve:()=>Tn,BoundingRect:()=>J,Circle:()=>bn,CompoundPath:()=>Yl,Ellipse:()=>Uo,Group:()=>lt,Image:()=>ee,IncrementalDisplayable:()=>jl,Line:()=>he,LinearGradient:()=>Ca,Polygon:()=>mi,Polyline:()=>Wo,RadialGradient:()=>ql,Rect:()=>vt,Ring:()=>Go,Sector:()=>Ar,Text:()=>St,clipPointsByRect:()=>Wc,clipRectByRect:()=>Yc,createIcon:()=>Ln,extendPath:()=>Uc,extendShape:()=>Bc,getShapeClass:()=>qo,getTransform:()=>Hc,initProps:()=>Xt,makeImage:()=>Zo,makePath:()=>gi,mergePath:()=>Vc,registerShape:()=>Re,resizePath:()=>tu,updateProps:()=>wt});var Uv={};Me(Uv,{addCommas:()=>rs,capitalFirst:()=>B_,encodeHTML:()=>Wt,formatTime:()=>F_,formatTpl:()=>Ra,getTextRect:()=>fp,getTooltipMarker:()=>vu,normalizeCssArray:()=>Mr,toCamelCase:()=>Oa,truncateText:()=>Ll});var Vv={};Me(Vv,{bind:()=>at,clone:()=>j,curry:()=>st,defaults:()=>X,each:()=>w,extend:()=>I,filter:()=>dt,indexOf:()=>K,inherits:()=>to,isArray:()=>N,isFunction:()=>G,isObject:()=>H,isString:()=>F,map:()=>z,merge:()=>nt,reduce:()=>Vt});var Os=et();function ES(r,t){var e=z(t,function(i){return r.scale.parse(i)});return r.type==="time"&&e.length>0&&(e.sort(),e.unshift(e[0]),e.push(e[e.length-1])),e}function LS(r){var t=r.getLabelModel().get("customValues");if(t){var e=Xn(r);return{labels:ES(r,t).map(function(i){var n={value:i};return{formattedLabel:e(n),rawLabel:r.scale.getLabel(n),tickValue:i}})}}return r.type==="category"?KL(r):QL(r)}function PS(r,t){var e=r.getTickModel().get("customValues");return e?{ticks:ES(r,e)}:r.type==="category"?jL(r,t):{ticks:z(r.scale.getTicks(),function(i){return i.value})}}function KL(r){var t=r.getLabelModel(),e=OS(r,t);return!t.get("show")||r.scale.isBlank()?{labels:[],labelCategoryInterval:e.labelCategoryInterval}:e}function OS(r,t){var e=RS(r,"labels"),i=cf(t),n=IS(e,i);if(n)return n;var a,o;return G(i)?a=FS(r,i):(o=i==="auto"?$L(r):i,a=zS(r,o)),NS(e,i,{labels:a,labelCategoryInterval:o})}function jL(r,t){var e=RS(r,"ticks"),i=cf(t),n=IS(e,i);if(n)return n;var a,o;if((!t.get("show")||r.scale.isBlank())&&(a=[]),G(i))a=FS(r,i,!0);else if(i==="auto"){var s=OS(r,r.getLabelModel());o=s.labelCategoryInterval,a=z(s.labels,function(l){return l.tickValue})}else o=i,a=zS(r,o,!0);return NS(e,i,{ticks:a,tickCategoryInterval:o})}function QL(r){var t=r.scale.getTicks(),e=Xn(r);return{labels:z(t,function(i,n){return{level:i.level,formattedLabel:e(i,n),rawLabel:r.scale.getLabel(i),tickValue:i.value}})}}function RS(r,t){return Os(r)[t]||(Os(r)[t]=[])}function IS(r,t){for(var e=0;e40&&(s=Math.max(1,Math.floor(o/40)));for(var l=a[0],u=r.dataToCoord(l+1)-r.dataToCoord(l),f=Math.abs(u*Math.cos(i)),h=Math.abs(u*Math.sin(i)),c=0,p=0;l<=a[1];l+=s){var v=0,m=0,d=ua(e({value:l}),t.font,"center","top");v=d.width*1.3,m=d.height*1.3,c=Math.max(c,v,7),p=Math.max(p,m,7)}var g=c/f,y=p/h;isNaN(g)&&(g=1/0),isNaN(y)&&(y=1/0);var _=Math.max(0,Math.floor(Math.min(g,y))),x=Os(r.model),b=r.getExtent(),S=x.lastAutoInterval,T=x.lastTickCount;return S!=null&&T!=null&&Math.abs(S-_)<=1&&Math.abs(T-o)<=1&&S>_&&x.axisExtent0===b[0]&&x.axisExtent1===b[1]?_=S:(x.lastTickCount=o,x.lastAutoInterval=_,x.axisExtent0=b[0],x.axisExtent1=b[1]),_}function JL(r){var t=r.getLabelModel();return{axisRotate:r.getRotate?r.getRotate():r.isHorizontal&&!r.isHorizontal()?90:0,labelRotate:t.get("rotate")||0,font:t.getFont()}}function zS(r,t,e){var i=Xn(r),n=r.scale,a=n.getExtent(),o=r.getLabelModel(),s=[],l=Math.max((t||0)+1,1),u=a[0],f=n.count();u!==0&&l>1&&f/l>2&&(u=Math.round(Math.ceil(u/l)*l));var h=pf(r),c=o.get("showMinLabel")||h,p=o.get("showMaxLabel")||h;c&&u!==a[0]&&m(a[0]);for(var v=u;v<=a[1];v+=l)m(v);p&&v-l!==a[1]&&m(a[1]);function m(d){var g={value:d};s.push(e?d:{formattedLabel:i(g),rawLabel:n.getLabel(g),tickValue:d})}return s}function FS(r,t,e){var i=r.scale,n=Xn(r),a=[];return w(i.getTicks(),function(o){var s=i.getLabel(o),l=o.value;t(o.value,s)&&a.push(e?l:{formattedLabel:n(o),rawLabel:s,tickValue:l})}),a}var BS=[0,1],tP=function(){function r(t,e,i){this.onBand=!1,this.inverse=!1,this.dim=t,this.scale=e,this._extent=i||[0,0]}return r.prototype.contain=function(t){var e=this._extent,i=Math.min(e[0],e[1]),n=Math.max(e[0],e[1]);return t>=i&&t<=n},r.prototype.containData=function(t){return this.scale.contain(t)},r.prototype.getExtent=function(){return this._extent.slice()},r.prototype.getPixelPrecision=function(t){return Cl(t||this.scale.getExtent(),this._extent)},r.prototype.setExtent=function(t,e){var i=this._extent;i[0]=t,i[1]=e},r.prototype.dataToCoord=function(t,e){var i=this._extent,n=this.scale;return t=n.normalize(t),this.onBand&&n.type==="ordinal"&&(i=i.slice(),US(i,n.count())),bo(t,BS,i,e)},r.prototype.coordToData=function(t,e){var i=this._extent,n=this.scale;this.onBand&&n.type==="ordinal"&&(i=i.slice(),US(i,n.count()));var a=bo(t,i,BS,e);return this.scale.scale(a)},r.prototype.pointToData=function(t,e){},r.prototype.getTicksCoords=function(t){t=t||{};var e=t.tickModel||this.getTickModel(),i=PS(this,e),n=i.ticks,a=z(n,function(s){return{coord:this.dataToCoord(this.scale.type==="ordinal"?this.scale.getRawOrdinalNumber(s):s),tickValue:s}},this),o=e.get("alignWithLabel");return eP(this,a,o,t.clamp),a},r.prototype.getMinorTicksCoords=function(){if(this.scale.type==="ordinal")return[];var t=this.model.getModel("minorTick"),e=t.get("splitNumber");e>0&&e<100||(e=5);var i=this.scale.getMinorTicks(e),n=z(i,function(a){return z(a,function(o){return{coord:this.dataToCoord(o),tickValue:o}},this)},this);return n},r.prototype.getViewLabels=function(){return LS(this).labels},r.prototype.getLabelModel=function(){return this.model.getModel("axisLabel")},r.prototype.getTickModel=function(){return this.model.getModel("axisTick")},r.prototype.getBandWidth=function(){var t=this._extent,e=this.scale.getExtent(),i=e[1]-e[0]+(this.onBand?1:0);i===0&&(i=1);var n=Math.abs(t[1]-t[0]);return Math.abs(n)/i},r.prototype.calculateCategoryInterval=function(){return kS(this)},r}();function US(r,t){var e=r[1]-r[0],i=t,n=e/i/2;r[0]+=n,r[1]-=n}function eP(r,t,e,i){var n=t.length;if(!r.onBand||e||!n)return;var a=r.getExtent(),o,s;if(n===1)t[0].coord=a[0],o=t[1]={coord:a[1]};else{var l=t[n-1].tickValue-t[0].tickValue,u=(t[n-1].coord-t[0].coord)/l;w(t,function(p){p.coord-=u/2});var f=r.scale.getExtent();s=1+f[1]-t[n-1].tickValue,o={coord:t[n-1].coord+u*s},t.push(o)}var h=a[0]>a[1];c(t[0].coord,a[0])&&(i?t[0].coord=a[0]:t.shift()),i&&c(a[0],t[0].coord)&&t.unshift({coord:a[0]}),c(a[1],o.coord)&&(i?o.coord=a[1]:t.pop()),i&&c(o.coord,a[1])&&t.push({coord:a[1]});function c(p,v){return p=mt(p),v=mt(v),h?p>v:p-1&&(u.style.stroke=u.style.fill,u.style.fill="#fff",u.style.lineWidth=2),i},t.type="series.line",t.dependencies=["grid","polar"],t.defaultOption={z:3,coordinateSystem:"cartesian2d",legendHoverLink:!0,clip:!0,label:{position:"top"},endLabel:{show:!1,valueAnimation:!0,distance:8},lineStyle:{width:2,type:"solid"},emphasis:{scale:!0},step:!1,smooth:!1,smoothMonotone:null,symbol:"emptyCircle",symbolSize:4,symbolRotate:null,showSymbol:!0,showAllSymbol:"auto",connectNulls:!1,sampling:"none",animationEasing:"linear",progressive:0,hoverLayerThreshold:1/0,universalTransition:{divideShape:"clone"},triggerLineEvent:!1},t}(Ut),GS=oP;function ei(r,t){var e=r.mapDimensionsAll("defaultedLabel"),i=e.length;if(i===1){var n=$r(r,t,e[0]);return n!=null?n+"":null}else if(i){for(var a=[],o=0;o=0&&i.push(t[a])}return i.join(" ")}var sP=function(r){O(t,r);function t(e,i,n,a){var o=r.call(this)||this;return o.updateData(e,i,n,a),o}return t.prototype._createSymbol=function(e,i,n,a,o){this.removeAll();var s=$t(e,-1,-1,2,2,null,o);s.attr({z2:100,culling:!0,scaleX:a[0]/2,scaleY:a[1]/2}),s.drift=lP,this._symbolType=e,this.add(s)},t.prototype.stopSymbolAnimation=function(e){this.childAt(0).stopAnimation(null,e)},t.prototype.getSymbolType=function(){return this._symbolType},t.prototype.getSymbolPath=function(){return this.childAt(0)},t.prototype.highlight=function(){Xr(this.childAt(0))},t.prototype.downplay=function(){qr(this.childAt(0))},t.prototype.setZ=function(e,i){var n=this.childAt(0);n.zlevel=e,n.z=i},t.prototype.setDraggable=function(e,i){var n=this.childAt(0);n.draggable=e,n.cursor=!i&&e?"move":n.cursor},t.prototype.updateData=function(e,i,n,a){this.silent=!1;var o=e.getItemVisual(i,"symbol")||"circle",s=e.hostModel,l=t.getSymbolSize(e,i),u=o!==this._symbolType,f=a&&a.disableAnimation;if(u){var h=e.getItemVisual(i,"symbolKeepAspect");this._createSymbol(o,e,i,l,h)}else{var c=this.childAt(0);c.silent=!1;var p={scaleX:l[0]/2,scaleY:l[1]/2};f?c.attr(p):wt(c,p,s,i),Ql(c)}if(this._updateCommon(e,i,l,n,a),u){var c=this.childAt(0);if(!f){var p={scaleX:this._sizeX,scaleY:this._sizeY,style:{opacity:c.style.opacity}};c.scaleX=c.scaleY=0,c.style.opacity=0,Xt(c,p,s,i)}}f&&this.childAt(0).stopAnimation("leave")},t.prototype._updateCommon=function(e,i,n,a,o){var s=this.childAt(0),l=e.hostModel,u,f,h,c,p,v,m,d,g;if(a&&(u=a.emphasisItemStyle,f=a.blurItemStyle,h=a.selectItemStyle,c=a.focus,p=a.blurScope,m=a.labelStatesModels,d=a.hoverScale,g=a.cursorStyle,v=a.emphasisDisabled),!a||e.hasItemOption){var y=a&&a.itemModel?a.itemModel:e.getItemModel(i),_=y.getModel("emphasis");u=_.getModel("itemStyle").getItemStyle(),h=y.getModel(["select","itemStyle"]).getItemStyle(),f=y.getModel(["blur","itemStyle"]).getItemStyle(),c=_.get("focus"),p=_.get("blurScope"),v=_.get("disabled"),m=xe(y),d=_.getShallow("scale"),g=y.getShallow("cursor")}var x=e.getItemVisual(i,"symbolRotate");s.attr("rotation",(x||0)*Math.PI/180||0);var b=Vn(e.getItemVisual(i,"symbolOffset"),n);b&&(s.x=b[0],s.y=b[1]),g&&s.attr("cursor",g);var S=e.getItemVisual(i,"style"),T=S.fill;if(s instanceof ee){var C=s.style;s.useStyle(I({image:C.image,x:C.x,y:C.y,width:C.width,height:C.height},S))}else s.__isEmptyBrush?s.useStyle(I({},S)):s.useStyle(S),s.style.decal=null,s.setColor(T,o&&o.symbolInnerColor),s.style.strokeNoScale=!0;var A=e.getItemVisual(i,"liftZ"),M=this._z2;A!=null?M==null&&(this._z2=s.z2,s.z2+=A):M!=null&&(s.z2=M,this._z2=null);var D=o&&o.useNameLabel;Qe(s,m,{labelFetcher:l,labelDataIndex:i,defaultText:L,inheritColor:T,defaultOpacity:S.opacity});function L(P){return D?e.getName(P):ei(e,P)}this._sizeX=n[0]/2,this._sizeY=n[1]/2;var R=s.ensureState("emphasis");R.style=u,s.ensureState("select").style=h,s.ensureState("blur").style=f;var E=d==null||d===!0?Math.max(1.1,3/this._sizeY):isFinite(d)&&d>0?+d:1;R.scaleX=this._sizeX*E,R.scaleY=this._sizeY*E,this.setSymbolScale(1),Oe(this,c,p,v)},t.prototype.setSymbolScale=function(e){this.scaleX=this.scaleY=e},t.prototype.fadeOut=function(e,i,n){var a=this.childAt(0),o=it(this).dataIndex,s=n&&n.animation;if(this.silent=a.silent=!0,n&&n.fadeLabel){var l=a.getTextContent();l&&Aa(l,{style:{opacity:0}},i,{dataIndex:o,removeOpt:s,cb:function(){a.removeTextContent()}})}else a.removeTextContent();Aa(a,{style:{opacity:0},scaleX:0,scaleY:0},i,{dataIndex:o,cb:e,removeOpt:s})},t.getSymbolSize=function(e,i){return ds(e.getItemVisual(i,"symbolSize"))},t}(lt);function lP(r,t){this.parent.drift(r,t)}var Rs=sP;function Gv(r,t,e,i){return t&&!isNaN(t[0])&&!isNaN(t[1])&&!(i.isIgnore&&i.isIgnore(e))&&!(i.clipShape&&!i.clipShape.contain(t[0],t[1]))&&r.getItemVisual(e,"symbol")!=="none"}function WS(r){return r!=null&&!H(r)&&(r={isIgnore:r}),r||{}}function YS(r){var t=r.hostModel,e=t.getModel("emphasis");return{emphasisItemStyle:e.getModel("itemStyle").getItemStyle(),blurItemStyle:t.getModel(["blur","itemStyle"]).getItemStyle(),selectItemStyle:t.getModel(["select","itemStyle"]).getItemStyle(),focus:e.get("focus"),blurScope:e.get("blurScope"),emphasisDisabled:e.get("disabled"),hoverScale:e.get("scale"),labelStatesModels:xe(t),cursorStyle:t.get("cursor")}}var uP=function(){function r(t){this.group=new lt,this._SymbolCtor=t||Rs}return r.prototype.updateData=function(t,e){this._progressiveEls=null,e=WS(e);var i=this.group,n=t.hostModel,a=this._data,o=this._SymbolCtor,s=e.disableAnimation,l=YS(t),u={disableAnimation:s},f=e.getSymbolPoint||function(h){return t.getItemLayout(h)};a||i.removeAll(),t.diff(a).add(function(h){var c=f(h);if(Gv(t,c,h,e)){var p=new o(t,h,l,u);p.setPosition(c),t.setItemGraphicEl(h,p),i.add(p)}}).update(function(h,c){var p=a.getItemGraphicEl(c),v=f(h);if(!Gv(t,v,h,e)){i.remove(p);return}var m=t.getItemVisual(h,"symbol")||"circle",d=p&&p.getSymbolType&&p.getSymbolType();if(!p||d&&d!==m)i.remove(p),p=new o(t,h,l,u),p.setPosition(v);else{p.updateData(t,h,l,u);var g={x:v[0],y:v[1]};s?p.attr(g):wt(p,g,n)}i.add(p),t.setItemGraphicEl(h,p)}).remove(function(h){var c=a.getItemGraphicEl(h);c&&c.fadeOut(function(){i.remove(c)},n)}).execute(),this._getSymbolPoint=f,this._data=t},r.prototype.updateLayout=function(){var t=this,e=this._data;e&&e.eachItemGraphicEl(function(i,n){var a=t._getSymbolPoint(n);i.setPosition(a),i.markRedraw()})},r.prototype.incrementalPrepareUpdate=function(t){this._seriesScope=YS(t),this._data=null,this.group.removeAll()},r.prototype.incrementalUpdate=function(t,e,i){this._progressiveEls=[],i=WS(i);function n(l){l.isGroup||(l.incremental=!0,l.ensureState("emphasis").hoverLayer=!0)}for(var a=t.start;a0?e=i[0]:i[1]<0&&(e=i[1]),e}function xf(r,t,e,i){var n=NaN;r.stacked&&(n=e.get(e.getCalculationInfo("stackedOverDimension"),i)),isNaN(n)&&(n=r.valueStart);var a=r.baseDataOffset,o=[];return o[a]=e.get(r.baseDim,i),o[1-a]=n,t.dataToPoint(o)}function hP(r,t){var e=[];return t.diff(r).add(function(i){e.push({cmd:"+",idx:i})}).update(function(i,n){e.push({cmd:"=",idx:n,idx1:i})}).remove(function(i){e.push({cmd:"-",idx:i})}).execute(),e}function Wv(r,t,e,i,n,a,o,s){for(var l=hP(r,t),u=[],f=[],h=[],c=[],p=[],v=[],m=[],d=_f(n,t,o),g=r.getLayout("points")||[],y=t.getLayout("points")||[],_=0;_=n||m<0)break;if(qn(g,y)){if(l){m+=a;continue}break}if(m===e)r[a>0?"moveTo":"lineTo"](g,y),h=g,c=y;else{var _=g-u,x=y-f;if(_*_+x*x<.5){m+=a;continue}if(o>0){for(var b=m+a,S=t[b*2],T=t[b*2+1];S===g&&T===y&&d=i||qn(S,T))p=g,v=y;else{M=S-u,D=T-f;var E=g-u,P=S-g,k=y-f,q=T-y,B=void 0,V=void 0;if(s==="x"){B=Math.abs(E),V=Math.abs(P);var tt=M>0?1:-1;p=g-tt*B*o,v=y,L=g+tt*V*o,R=y}else if(s==="y"){B=Math.abs(k),V=Math.abs(q);var ft=D>0?1:-1;p=g,v=y-ft*B*o,L=g,R=y+ft*V*o}else B=Math.sqrt(E*E+k*k),V=Math.sqrt(P*P+q*q),A=V/(V+B),p=g-M*o*(1-A),v=y-D*o*(1-A),L=g+M*o*A,R=y+D*o*A,L=Li(L,Pi(S,g)),R=Li(R,Pi(T,y)),L=Pi(L,Li(S,g)),R=Pi(R,Li(T,y)),M=L-g,D=R-y,p=g-M*B/V,v=y-D*B/V,p=Li(p,Pi(u,g)),v=Li(v,Pi(f,y)),p=Pi(p,Li(u,g)),v=Pi(v,Li(f,y)),M=g-p,D=y-v,L=g+M*V/B,R=y+D*V/B}r.bezierCurveTo(h,c,p,v,g,y),h=L,c=R}else r.lineTo(g,y)}u=g,f=y,m+=a}return d}var XS=function(){function r(){this.smooth=0,this.smoothConstraint=!0}return r}(),qS=function(r){O(t,r);function t(e){var i=r.call(this,e)||this;return i.type="ec-polyline",i}return t.prototype.getDefaultStyle=function(){return{stroke:"#000",fill:null}},t.prototype.getDefaultShape=function(){return new XS},t.prototype.buildPath=function(e,i){var n=i.points,a=0,o=n.length/2;if(i.connectNulls){for(;o>0&&qn(n[o*2-2],n[o*2-1]);o--);for(;a=0){var x=u?(v-l)*_+l:(p-s)*_+s;return u?[e,x]:[x,e]}s=p,l=v;break;case o.C:p=a[h++],v=a[h++],m=a[h++],d=a[h++],g=a[h++],y=a[h++];var b=u?Qi(s,p,m,g,e,f):Qi(l,v,d,y,e,f);if(b>0)for(var S=0;S=0){var x=u?Dt(l,v,d,y,T):Dt(s,p,m,g,T);return u?[e,x]:[x,e]}}s=g,l=y;break}}},t}(Z);var cP=function(r){O(t,r);function t(){return r!==null&&r.apply(this,arguments)||this}return t}(XS),ZS=function(r){O(t,r);function t(e){var i=r.call(this,e)||this;return i.type="ec-polygon",i}return t.prototype.getDefaultShape=function(){return new cP},t.prototype.buildPath=function(e,i){var n=i.points,a=i.stackedOnPoints,o=0,s=n.length/2,l=i.smoothMonotone;if(i.connectNulls){for(;s>0&&qn(n[s*2-2],n[s*2-1]);s--);for(;ot){a?e.push(o(a,l,t)):n&&e.push(o(n,l,0),o(n,l,t));break}else n&&(e.push(o(n,l,0)),n=null),e.push(l),a=l}return e}function dP(r,t,e){var i=r.getVisual("visualMeta");if(!(!i||!i.length||!r.count())&&t.type==="cartesian2d"){for(var n,a,o=i.length-1;o>=0;o--){var s=r.getDimensionInfo(i[o].dimension);if(n=s&&s.coordDim,n==="x"||n==="y"){a=i[o];break}}if(a){var l=t.getAxis(n),u=z(a.stops,function(_){return{coord:l.toGlobalCoord(l.dataToCoord(_.value)),color:_.color}}),f=u.length,h=a.outerColors.slice();f&&u[0].coord>u[f-1].coord&&(u.reverse(),h.reverse());var c=vP(u,n==="x"?e.getWidth():e.getHeight()),p=c.length;if(!p&&f)return u[0].coord<0?h[1]?h[1]:u[f-1].color:h[0]?h[0]:u[0].color;var v=10,m=c[0].coord-v,d=c[p-1].coord+v,g=d-m;if(g<.001)return"transparent";w(c,function(_){_.offset=(_.coord-m)/g}),c.push({offset:p?c[p-1].offset:.5,color:h[1]||"transparent"}),c.unshift({offset:p?c[0].offset:.5,color:h[0]||"transparent"});var y=new Ca(0,0,0,0,c,!0);return y[n]=m,y[n+"2"]=d,y}}}function mP(r,t,e){var i=r.get("showAllSymbol"),n=i==="auto";if(!(i&&!n)){var a=e.getAxesByScale("ordinal")[0];if(a&&!(n&&gP(a,t))){var o=t.mapDimension(a.dim),s={};return w(a.getViewLabels(),function(l){var u=a.scale.getRawOrdinalNumber(l.tickValue);s[u]=1}),function(l){return!s.hasOwnProperty(t.get(o,l))}}}}function gP(r,t){var e=r.getExtent(),i=Math.abs(e[1]-e[0])/r.scale.count();isNaN(i)&&(i=0);for(var n=t.count(),a=Math.max(1,Math.round(n/5)),o=0;oi)return!1;return!0}function yP(r,t){return isNaN(r)||isNaN(t)}function _P(r){for(var t=r.length/2;t>0&&yP(r[t*2-2],r[t*2-1]);t--);return t-1}function JS(r,t){return[r[t*2],r[t*2+1]]}function xP(r,t,e){for(var i=r.length/2,n=e==="x"?0:1,a,o,s=0,l=-1,u=0;u=t||a>=t&&o<=t){l=u;break}s=u,a=o}return{range:[s,l],t:(t-a)/(o-a)}}function tb(r){if(r.get(["endLabel","show"]))return!0;for(var t=0;t0&&e.get(["emphasis","lineStyle","width"])==="bolder"){var tt=m.getState("emphasis").style;tt.lineWidth=+m.style.lineWidth+1}it(m).seriesIndex=e.seriesIndex,Oe(m,q,B,V);var ft=$S(e.get("smooth")),ct=e.get("smoothMonotone");if(m.setShape({smooth:ft,smoothMonotone:ct,connectNulls:C}),d){var yt=l.getCalculationInfo("stackedOnSeries"),Ct=0;d.useStyle(X(f.getAreaStyle(),{fill:R,opacity:.7,lineJoin:"bevel",decal:l.getVisual("style").decal})),yt&&(Ct=$S(yt.get("smooth"))),d.setShape({smooth:ft,stackedOnSmooth:Ct,smoothMonotone:ct,connectNulls:C}),Sn(d,e,"areaStyle"),it(d).seriesIndex=e.seriesIndex,Oe(d,q,B,V)}var De=function(At){a._changePolyState(At)};l.eachItemGraphicEl(function(At){At&&(At.onHoverStateChange=De)}),this._polyline.onHoverStateChange=De,this._data=l,this._coordSys=o,this._stackedOnPoints=S,this._points=h,this._step=D,this._valueOrigin=x,e.get("triggerLineEvent")&&(this.packEventData(e,m),d&&this.packEventData(e,d))},t.prototype.packEventData=function(e,i){it(i).eventData={componentType:"series",componentSubType:"line",componentIndex:e.componentIndex,seriesIndex:e.seriesIndex,seriesName:e.name,seriesType:"line"}},t.prototype.highlight=function(e,i,n,a){var o=e.getData(),s=Xe(o,a);if(this._changePolyState("emphasis"),!(s instanceof Array)&&s!=null&&s>=0){var l=o.getLayout("points"),u=o.getItemGraphicEl(s);if(!u){var f=l[s*2],h=l[s*2+1];if(isNaN(f)||isNaN(h)||this._clipShapeForSymbol&&!this._clipShapeForSymbol.contain(f,h))return;var c=e.get("zlevel")||0,p=e.get("z")||0;u=new Rs(o,s),u.x=f,u.y=h,u.setZ(c,p);var v=u.getSymbolPath().getTextContent();v&&(v.zlevel=c,v.z=p,v.z2=this._polyline.z2+1),u.__temp=!0,o.setItemGraphicEl(s,u),u.stopSymbolAnimation(!0),this.group.add(u)}u.highlight()}else It.prototype.highlight.call(this,e,i,n,a)},t.prototype.downplay=function(e,i,n,a){var o=e.getData(),s=Xe(o,a);if(this._changePolyState("normal"),s!=null&&s>=0){var l=o.getItemGraphicEl(s);l&&(l.__temp?(o.setItemGraphicEl(s,null),this.group.remove(l)):l.downplay())}else It.prototype.downplay.call(this,e,i,n,a)},t.prototype._changePolyState=function(e){var i=this._polygon;Tc(this._polyline,e),i&&Tc(i,e)},t.prototype._newPolyline=function(e){var i=this._polyline;return i&&this._lineGroup.remove(i),i=new qS({shape:{points:e},segmentIgnoreThreshold:2,z2:10}),this._lineGroup.add(i),this._polyline=i,i},t.prototype._newPolygon=function(e,i){var n=this._polygon;return n&&this._lineGroup.remove(n),n=new ZS({shape:{points:e,stackedOnPoints:i},segmentIgnoreThreshold:2}),this._lineGroup.add(n),this._polygon=n,n},t.prototype._initSymbolLabelAnimation=function(e,i,n){var a,o,s=i.getBaseAxis(),l=s.inverse;i.type==="cartesian2d"?(a=s.isHorizontal(),o=!1):i.type==="polar"&&(a=s.dim==="angle",o=!0);var u=e.hostModel,f=u.get("animationDuration");G(f)&&(f=f(null));var h=u.get("animationDelay")||0,c=G(h)?h(null):h;e.eachItemGraphicEl(function(p,v){var m=p;if(m){var d=[p.x,p.y],g=void 0,y=void 0,_=void 0;if(n)if(o){var x=n,b=i.pointToCoord(d);a?(g=x.startAngle,y=x.endAngle,_=-b[1]/180*Math.PI):(g=x.r0,y=x.r,_=b[0])}else{var S=n;a?(g=S.x,y=S.x+S.width,_=p.x):(g=S.y+S.height,y=S.y,_=p.y)}var T=y===g?0:(_-g)/(y-g);l&&(T=1-T);var C=G(h)?h(v):f*T+c,A=m.getSymbolPath(),M=A.getTextContent();m.attr({scaleX:0,scaleY:0}),m.animateTo({scaleX:1,scaleY:1},{duration:200,setToFinal:!0,delay:C}),M&&M.animateFrom({style:{opacity:0}},{duration:300,delay:C}),A.disableLabelAnimation=!0}})},t.prototype._initOrUpdateEndLabel=function(e,i,n){var a=e.getModel("endLabel");if(tb(e)){var o=e.getData(),s=this._polyline,l=o.getLayout("points");if(!l){s.removeTextContent(),this._endLabel=null;return}var u=this._endLabel;u||(u=this._endLabel=new St({z2:200}),u.ignoreClip=!0,s.setTextContent(this._endLabel),s.disableLabelAnimation=!0);var f=_P(l);f>=0&&(Qe(s,xe(e,"endLabel"),{inheritColor:n,labelFetcher:e,labelDataIndex:f,defaultText:function(h,c,p){return p!=null?gf(o,p):ei(o,h)},enableTextSetter:!0},SP(a,i)),s.textConfig.position=null)}else this._endLabel&&(this._polyline.removeTextContent(),this._endLabel=null)},t.prototype._endLabelOnDuring=function(e,i,n,a,o,s,l){var u=this._endLabel,f=this._polyline;if(u){e<1&&a.originalX==null&&(a.originalX=u.x,a.originalY=u.y);var h=n.getLayout("points"),c=n.hostModel,p=c.get("connectNulls"),v=s.get("precision"),m=s.get("distance")||0,d=l.getBaseAxis(),g=d.isHorizontal(),y=d.inverse,_=i.shape,x=y?g?_.x:_.y+_.height:g?_.x+_.width:_.y,b=(g?m:0)*(y?-1:1),S=(g?0:-m)*(y?-1:1),T=g?"x":"y",C=xP(h,x,T),A=C.range,M=A[1]-A[0],D=void 0;if(M>=1){if(M>1&&!p){var L=JS(h,A[0]);u.attr({x:L[0]+b,y:L[1]+S}),o&&(D=c.getRawValue(A[0]))}else{var L=f.getPointOn(x,T);L&&u.attr({x:L[0]+b,y:L[1]+S});var R=c.getRawValue(A[0]),E=c.getRawValue(A[1]);o&&(D=$h(n,v,R,E,C.t))}a.lastFrameIndex=A[0]}else{var P=e===1||a.lastFrameIndex>0?A[0]:0,L=JS(h,P);o&&(D=c.getRawValue(P)),u.attr({x:L[0]+b,y:L[1]+S})}if(o){var k=Ma(u);typeof k.setLabelText=="function"&&k.setLabelText(D)}}},t.prototype._doUpdateAnimation=function(e,i,n,a,o,s,l){var u=this._polyline,f=this._polygon,h=e.hostModel,c=Wv(this._data,e,this._stackedOnPoints,i,this._coordSys,n,this._valueOrigin,s),p=c.current,v=c.stackedOnCurrent,m=c.next,d=c.stackedOnNext;if(o&&(p=Oi(c.current,n,o,l),v=Oi(c.stackedOnCurrent,n,o,l),m=Oi(c.next,n,o,l),d=Oi(c.stackedOnNext,n,o,l)),QS(p,m)>3e3||f&&QS(v,d)>3e3){u.stopAnimation(),u.setShape({points:m}),f&&(f.stopAnimation(),f.setShape({points:m,stackedOnPoints:d}));return}u.shape.__points=c.current,u.shape.points=p;var g={shape:{points:m}};c.current!==p&&(g.shape.__points=c.next),u.stopAnimation(),wt(u,g,h),f&&(f.setShape({points:p,stackedOnPoints:v}),f.stopAnimation(),wt(f,{shape:{stackedOnPoints:d}},h),u.shape.points!==f.shape.points&&(f.shape.points=u.shape.points));for(var y=[],_=c.status,x=0;x<_.length;x++){var b=_[x].cmd;if(b==="="){var S=e.getItemGraphicEl(_[x].idx1);S&&y.push({el:S,ptIdx:x})}}u.animators&&u.animators.length&&u.animators[0].during(function(){f&&f.dirtyShape();for(var T=u.shape.__points,C=0;Ct&&(t=r[e]);return isFinite(t)?t:NaN},min:function(r){for(var t=1/0,e=0;et&&(t=a,e=n)}return isFinite(e)?e:NaN},nearest:function(r){return r[0]}},TP=function(r){return Math.round(r.length/2)};function Is(r){return{seriesType:r,reset:function(t,e,i){var n=t.getData(),a=t.get("sampling"),o=t.coordinateSystem,s=n.count();if(s>10&&o.type==="cartesian2d"&&a){var l=o.getBaseAxis(),u=o.getOtherAxis(l),f=l.getExtent(),h=i.getDevicePixelRatio(),c=Math.abs(f[1]-f[0])*(h||1),p=Math.round(s/c);if(isFinite(p)&&p>1){a==="lttb"&&t.setData(n.lttbDownSample(n.mapDimension(u.dim),1/p));var v=void 0;F(a)?v=wP[a]:G(a)&&(v=a),v&&t.setData(n.downSample(n.mapDimension(u.dim),1/p,v,TP))}}}}}function Kv(r){r.registerChartView(eb),r.registerSeriesModel(GS),r.registerLayout(Zn("line",!0)),r.registerVisual({seriesType:"line",reset:function(t){var e=t.getData(),i=t.getModel("lineStyle").getLineStyle();i&&!i.stroke&&(i.stroke=e.getVisual("style").fill),e.setVisual("legendLineStyle",i)}}),r.registerProcessor(r.PRIORITY.PROCESSOR.STATISTIC,Is("line"))}var rb=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e}return t.prototype.getInitialData=function(e,i){return nr(null,this,{useEncodeDefaulter:!0})},t.prototype.getMarkerPosition=function(e,i,n){var a=this.coordinateSystem;if(a&&a.clampData){var o=a.clampData(e),s=a.dataToPoint(o);if(n)w(a.getAxes(),function(c,p){if(c.type==="category"&&i!=null){var v=c.getTicksCoords(),m=c.getTickModel().get("alignWithLabel"),d=o[p],g=i[p]==="x1"||i[p]==="y1";if(g&&!m&&(d+=1),v.length<2)return;if(v.length===2){s[p]=c.toGlobalCoord(c.getExtent()[g?1:0]);return}for(var y=void 0,_=void 0,x=1,b=0;bd){_=(S+y)/2;break}b===1&&(x=T-v[0].tickValue)}_==null&&(y?y&&(_=v[v.length-1].coord):_=v[0].coord),s[p]=c.toGlobalCoord(_)}});else{var l=this.getData(),u=l.getLayout("offset"),f=l.getLayout("size"),h=a.getBaseAxis().isHorizontal()?0:1;s[h]+=u+f/2}return s}return[NaN,NaN]},t.type="series.__base_bar__",t.defaultOption={z:2,coordinateSystem:"cartesian2d",legendHoverLink:!0,barMinHeight:0,barMinAngle:0,large:!1,largeThreshold:400,progressive:3e3,progressiveChunkMode:"mod"},t}(Ut);Ut.registerClass(rb);var jv=rb;var CP=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e}return t.prototype.getInitialData=function(){return nr(null,this,{useEncodeDefaulter:!0,createInvertedIndices:!!this.get("realtimeSort",!0)||null})},t.prototype.getProgressive=function(){return this.get("large")?this.get("progressive"):!1},t.prototype.getProgressiveThreshold=function(){var e=this.get("progressiveThreshold"),i=this.get("largeThreshold");return i>e&&(e=i),e},t.prototype.brushSelector=function(e,i,n){return n.rect(i.getItemLayout(e))},t.type="series.bar",t.dependencies=["grid","polar"],t.defaultOption=nu(jv.defaultOption,{clip:!0,roundCap:!1,showBackground:!1,backgroundStyle:{color:"rgba(180, 180, 180, 0.2)",borderColor:null,borderWidth:0,borderType:"solid",borderRadius:0,shadowBlur:0,shadowColor:null,shadowOffsetX:0,shadowOffsetY:0,opacity:1},select:{itemStyle:{borderColor:"#212121"}},realtimeSort:!1}),t}(jv),ib=CP;var DP=function(){function r(){this.cx=0,this.cy=0,this.r0=0,this.r=0,this.startAngle=0,this.endAngle=Math.PI*2,this.clockwise=!0}return r}(),AP=function(r){O(t,r);function t(e){var i=r.call(this,e)||this;return i.type="sausage",i}return t.prototype.getDefaultShape=function(){return new DP},t.prototype.buildPath=function(e,i){var n=i.cx,a=i.cy,o=Math.max(i.r0||0,0),s=Math.max(i.r,0),l=(s-o)*.5,u=o+l,f=i.startAngle,h=i.endAngle,c=i.clockwise,p=Math.PI*2,v=c?h-fMath.PI/2&&fs)return!0;s=h}return!1},t.prototype._isOrderDifferentInView=function(e,i){for(var n=i.scale,a=n.getExtent(),o=Math.max(0,a[0]),s=Math.min(a[1],n.getOrdinalMeta().categories.length-1);o<=s;++o)if(e.ordinalNumbers[o]!==n.getRawOrdinalNumber(o))return!0},t.prototype._updateSortWithinSameData=function(e,i,n,a){if(this._isOrderChangedWithinSameData(e,i,n)){var o=this._dataSort(e,n,i);this._isOrderDifferentInView(o,n)&&(this._removeOnRenderedListener(a),a.dispatchAction({type:"changeAxisOrder",componentType:n.dim+"Axis",axisId:n.index,sortInfo:o}))}},t.prototype._dispatchInitSort=function(e,i,n){var a=i.baseAxis,o=this._dataSort(e,a,function(s){return e.get(e.mapDimension(i.otherAxis.dim),s)});n.dispatchAction({type:"changeAxisOrder",componentType:a.dim+"Axis",isInitSort:!0,axisId:a.index,sortInfo:o})},t.prototype.remove=function(e,i){this._clear(this._model),this._removeOnRenderedListener(i)},t.prototype.dispose=function(e,i){this._removeOnRenderedListener(i)},t.prototype._removeOnRenderedListener=function(e){this._onRendered&&(e.getZr().off("rendered",this._onRendered),this._onRendered=null)},t.prototype._clear=function(e){var i=this.group,n=this._data;e&&e.isAnimationEnabled()&&n&&!this._isLargeDraw?(this._removeBackground(),this._backgroundEls=[],n.eachItemGraphicEl(function(a){Xo(a,e,it(a).dataIndex)})):i.removeAll(),this._data=null,this._isFirstFrame=!0},t.prototype._removeBackground=function(){this.group.remove(this._backgroundGroup),this._backgroundGroup=null},t.type="bar",t}(It),sb={cartesian2d:function(r,t){var e=t.width<0?-1:1,i=t.height<0?-1:1;e<0&&(t.x+=t.width,t.width=-t.width),i<0&&(t.y+=t.height,t.height=-t.height);var n=r.x+r.width,a=r.y+r.height,o=$v(t.x,r.x),s=Jv(t.x+t.width,n),l=$v(t.y,r.y),u=Jv(t.y+t.height,a),f=sn?s:o,t.y=h&&l>a?u:l,t.width=f?0:s-o,t.height=h?0:u-l,e<0&&(t.x+=t.width,t.width=-t.width),i<0&&(t.y+=t.height,t.height=-t.height),f||h},polar:function(r,t){var e=t.r0<=t.r?1:-1;if(e<0){var i=t.r;t.r=t.r0,t.r0=i}var n=Jv(t.r,r.r),a=$v(t.r0,r.r0);t.r=n,t.r0=a;var o=n-a<0;if(e<0){var i=t.r;t.r=t.r0,t.r0=i}return o}},lb={cartesian2d:function(r,t,e,i,n,a,o,s,l){var u=new vt({shape:I({},i),z2:1});if(u.__dataIndex=e,u.name="item",a){var f=u.shape,h=n?"height":"width";f[h]=0}return u},polar:function(r,t,e,i,n,a,o,s,l){var u=!n&&l?Qv:Ar,f=new u({shape:i,z2:1});f.name="item";var h=mb(n);if(f.calculateTextPosition=nb(h,{isRoundCap:u===Qv}),a){var c=f.shape,p=n?"r":"endAngle",v={};c[p]=n?i.r0:i.startAngle,v[p]=i[p],(s?wt:Xt)(f,{shape:v},a)}return f}};function LP(r,t){var e=r.get("realtimeSort",!0),i=t.getBaseAxis();if(e&&i.type==="category"&&t.type==="cartesian2d")return{baseAxis:i,otherAxis:t.getOtherAxis(i)}}function ub(r,t,e,i,n,a,o,s){var l,u;a?(u={x:i.x,width:i.width},l={y:i.y,height:i.height}):(u={y:i.y,height:i.height},l={x:i.x,width:i.width}),s||(o?wt:Xt)(e,{shape:l},t,n,null);var f=t?r.baseAxis.model:null;(o?wt:Xt)(e,{shape:u},f,n)}function fb(r,t){for(var e=0;e0?1:-1,o=i.height>0?1:-1;return{x:i.x+a*n/2,y:i.y+o*n/2,width:i.width-a*n,height:i.height-o*n}},polar:function(r,t,e){var i=r.getItemLayout(t);return{cx:i.cx,cy:i.cy,r0:i.r0,r:i.r,startAngle:i.startAngle,endAngle:i.endAngle,clockwise:i.clockwise}}};function RP(r){return r.startAngle!=null&&r.endAngle!=null&&r.startAngle===r.endAngle}function mb(r){return function(t){var e=t?"Arc":"Angle";return function(i){switch(i){case"start":case"insideStart":case"end":case"insideEnd":return i+e;default:return i}}}(r)}function cb(r,t,e,i,n,a,o,s){var l=t.getItemVisual(e,"style");if(s){if(!a.get("roundCap")){var f=r.shape,h=ob(i.getModel("itemStyle"),f,!0);I(f,h),r.setShape(f)}}else{var u=i.get(["itemStyle","borderRadius"])||0;r.setShape("r",u)}r.useStyle(l);var c=i.getShallow("cursor");c&&r.attr("cursor",c);var p=s?o?n.r>=n.r0?"endArc":"startArc":n.endAngle>=n.startAngle?"endAngle":"startAngle":o?n.height>=0?"bottom":"top":n.width>=0?"right":"left",v=xe(i);Qe(r,v,{labelFetcher:a,labelDataIndex:e,defaultText:ei(a.getData(),e),inheritColor:l.fill,defaultOpacity:l.opacity,defaultOutsidePosition:p});var m=r.getTextContent();if(s&&m){var d=i.get(["label","position"]);r.textConfig.inside=d==="middle"?!0:null,ab(r,d==="outside"?p:d,mb(o),i.get(["label","rotate"]))}S_(m,v,a.getRawValue(e),function(y){return gf(t,y)});var g=i.getModel(["emphasis"]);Oe(r,g.get("focus"),g.get("blurScope"),g.get("disabled")),Sn(r,i),RP(n)&&(r.style.fill="none",r.style.stroke="none",w(r.states,function(y){y.style&&(y.style.fill=y.style.stroke="none")}))}function IP(r,t){var e=r.get(["itemStyle","borderColor"]);if(!e||e==="none")return 0;var i=r.get(["itemStyle","borderWidth"])||0,n=isNaN(t.width)?Number.MAX_VALUE:Math.abs(t.width),a=isNaN(t.height)?Number.MAX_VALUE:Math.abs(t.height);return Math.min(i,n,a)}var NP=function(){function r(){}return r}(),pb=function(r){O(t,r);function t(e){var i=r.call(this,e)||this;return i.type="largeBar",i}return t.prototype.getDefaultShape=function(){return new NP},t.prototype.buildPath=function(e,i){for(var n=i.points,a=this.baseDimIdx,o=1-this.baseDimIdx,s=[],l=[],u=this.barWidth,f=0;f=0?e:null},30,!1);function kP(r,t,e){for(var i=r.baseDimIdx,n=1-i,a=r.shape.points,o=r.largeDataIndices,s=[],l=[],u=r.barWidth,f=0,h=a.length/3;f=s[0]&&t<=s[0]+l[0]&&e>=s[1]&&e<=s[1]+l[1])return o[f]}return-1}function gb(r,t,e){if(Pr(e,"cartesian2d")){var i=t,n=e.getArea();return{x:r?i.x:n.x,y:r?n.y:i.y,width:r?i.width:n.width,height:r?n.height:i.height}}else{var n=e.getArea(),a=t;return{cx:n.cx,cy:n.cy,r0:r?n.r0:a.r0,r:r?n.r:a.r,startAngle:r?a.startAngle:0,endAngle:r?a.endAngle:Math.PI*2}}}function zP(r,t,e){var i=r.type==="polar"?Ar:vt;return new i({shape:gb(t,e,r),silent:!0,z2:0})}var yb=EP;function td(r){r.registerChartView(yb),r.registerSeriesModel(ib),r.registerLayout(r.PRIORITY.VISUAL.LAYOUT,st(uS,"bar")),r.registerLayout(r.PRIORITY.VISUAL.PROGRESSIVE_LAYOUT,fS("bar")),r.registerProcessor(r.PRIORITY.PROCESSOR.STATISTIC,Is("bar")),r.registerAction({type:"changeAxisOrder",event:"changeAxisOrder",update:"update"},function(t,e){var i=t.componentType||"series";e.eachComponent({mainType:i,query:t},function(n){t.sortInfo&&n.axis.setCategorySortInfo(t.sortInfo)})})}var FP=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e.hasSymbolVisual=!0,e}return t.prototype.getInitialData=function(e,i){return nr(null,this,{useEncodeDefaulter:!0})},t.prototype.getProgressive=function(){var e=this.option.progressive;return e??(this.option.large?5e3:this.get("progressive"))},t.prototype.getProgressiveThreshold=function(){var e=this.option.progressiveThreshold;return e??(this.option.large?1e4:this.get("progressiveThreshold"))},t.prototype.brushSelector=function(e,i,n){return n.point(i.getItemLayout(e))},t.prototype.getZLevelKey=function(){return this.getData().count()>this.getProgressiveThreshold()?this.id:""},t.type="series.scatter",t.dependencies=["grid","polar","geo","singleAxis","calendar"],t.defaultOption={coordinateSystem:"cartesian2d",z:2,legendHoverLink:!0,symbolSize:10,large:!1,largeThreshold:2e3,itemStyle:{opacity:.8},emphasis:{scale:!0},clip:!0,select:{itemStyle:{borderColor:"#212121"}},universalTransition:{divideShape:"clone"}},t}(Ut),_b=FP;var xb=4,BP=function(){function r(){}return r}(),UP=function(r){O(t,r);function t(e){var i=r.call(this,e)||this;return i._off=0,i.hoverDataIdx=-1,i}return t.prototype.getDefaultShape=function(){return new BP},t.prototype.reset=function(){this.notClear=!1,this._off=0},t.prototype.buildPath=function(e,i){var n=i.points,a=i.size,o=this.symbolProxy,s=o.shape,l=e.getContext?e.getContext():e,u=l&&a[0]=0;u--){var f=u*2,h=a[f]-s/2,c=a[f+1]-l/2;if(e>=h&&i>=c&&e<=h+s&&i<=c+l)return u}return-1},t.prototype.contain=function(e,i){var n=this.transformCoordToLocal(e,i),a=this.getBoundingRect();if(e=n[0],i=n[1],a.contain(e,i)){var o=this.hoverDataIdx=this.findDataIndex(e,i);return o>=0}return this.hoverDataIdx=-1,!1},t.prototype.getBoundingRect=function(){var e=this._rect;if(!e){for(var i=this.shape,n=i.points,a=i.size,o=a[0],s=a[1],l=1/0,u=1/0,f=-1/0,h=-1/0,c=0;c=0&&(u.dataIndex=h+(t.startIndex||0))})},r.prototype.remove=function(){this._clear()},r.prototype._clear=function(){this._newAdded=[],this.group.removeAll()},r}(),Sb=VP;var HP=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e}return t.prototype.render=function(e,i,n){var a=e.getData(),o=this._updateSymbolDraw(a,e);o.updateData(a,{clipShape:this._getClipShape(e)}),this._finished=!0},t.prototype.incrementalPrepareRender=function(e,i,n){var a=e.getData(),o=this._updateSymbolDraw(a,e);o.incrementalPrepareUpdate(a),this._finished=!1},t.prototype.incrementalRender=function(e,i,n){this._symbolDraw.incrementalUpdate(e,i.getData(),{clipShape:this._getClipShape(i)}),this._finished=e.end===i.getData().count()},t.prototype.updateTransform=function(e,i,n){var a=e.getData();if(this.group.dirty(),!this._finished||a.count()>1e4)return{update:!0};var o=Zn("").reset(e,i,n);o.progress&&o.progress({start:0,end:a.count(),count:a.count()},a),this._symbolDraw.updateLayout(a)},t.prototype.eachRendered=function(e){this._symbolDraw&&this._symbolDraw.eachRendered(e)},t.prototype._getClipShape=function(e){if(e.get("clip",!0)){var i=e.coordinateSystem;return i&&i.getArea&&i.getArea(.1)}},t.prototype._updateSymbolDraw=function(e,i){var n=this._symbolDraw,a=i.pipelineContext,o=a.large;return(!n||o!==this._isLargeDraw)&&(n&&n.remove(),n=this._symbolDraw=o?new Sb:new yf,this._isLargeDraw=o,this.group.removeAll()),this.group.add(n.group),n},t.prototype.remove=function(e,i){this._symbolDraw&&this._symbolDraw.remove(!0),this._symbolDraw=null},t.prototype.dispose=function(){},t.type="scatter",t}(It),bb=HP;var GP=function(r){O(t,r);function t(){return r!==null&&r.apply(this,arguments)||this}return t.type="grid",t.dependencies=["xAxis","yAxis"],t.layoutMode="box",t.defaultOption={show:!1,z:0,left:"10%",top:60,right:"10%",bottom:70,containLabel:!1,backgroundColor:"rgba(0,0,0,0)",borderWidth:1,borderColor:"#ccc"},t}(ht),wb=GP;var Cf=function(r){O(t,r);function t(){return r!==null&&r.apply(this,arguments)||this}return t.prototype.getCoordSysModel=function(){return this.getReferringComponents("grid",te).models[0]},t.type="cartesian2dAxis",t}(ht);Nt(Cf,vf);var Tb={show:!0,z:0,inverse:!1,name:"",nameLocation:"end",nameRotate:null,nameTruncate:{maxWidth:null,ellipsis:"...",placeholder:"."},nameTextStyle:{},nameGap:15,silent:!1,triggerEvent:!1,tooltip:{show:!1},axisPointer:{},axisLine:{show:!0,onZero:!0,onZeroAxisIndex:null,lineStyle:{color:"#6E7079",width:1,type:"solid"},symbol:["none","none"],symbolSize:[10,15]},axisTick:{show:!0,inside:!1,length:5,lineStyle:{width:1}},axisLabel:{show:!0,inside:!1,rotate:0,showMinLabel:null,showMaxLabel:null,margin:8,fontSize:12},splitLine:{show:!0,lineStyle:{color:["#E0E6F1"],width:1,type:"solid"}},splitArea:{show:!1,areaStyle:{color:["rgba(250,250,250,0.2)","rgba(210,219,238,0.2)"]}}},WP=nt({boundaryGap:!0,deduplication:null,splitLine:{show:!1},axisTick:{alignWithLabel:!1,interval:"auto"},axisLabel:{interval:"auto"}},Tb),ed=nt({boundaryGap:[0,0],axisLine:{show:"auto"},axisTick:{show:"auto"},splitNumber:5,minorTick:{show:!1,splitNumber:5,length:3,lineStyle:{}},minorSplitLine:{show:!1,lineStyle:{color:"#F4F7FD",width:1}}},Tb),YP=nt({splitNumber:6,axisLabel:{showMinLabel:!1,showMaxLabel:!1,rich:{primary:{fontWeight:"bold"}}},splitLine:{show:!1}},ed),XP=X({logBase:10},ed),Cb={category:WP,value:ed,time:YP,log:XP};var Db={value:1,category:1,time:1,log:1};function Df(r,t,e,i){w(Db,function(n,a){var o=nt(nt({},Cb[a],!0),i,!0),s=function(l){O(u,l);function u(){var f=l!==null&&l.apply(this,arguments)||this;return f.type=t+"Axis."+a,f}return u.prototype.mergeDefaultAndTheme=function(f,h){var c=_i(this),p=c?xi(f):{},v=h.getTheme();nt(f,v.get(a+"Axis")),nt(f,this.getDefaultOption()),f.type=Ab(f),c&&Er(f,p,c)},u.prototype.optionUpdated=function(){var f=this.option;f.type==="category"&&(this.__ordinalMeta=As.createByAxisModel(this))},u.prototype.getCategories=function(f){var h=this.option;if(h.type==="category")return f?h.data:this.__ordinalMeta.categories},u.prototype.getOrdinalMeta=function(){return this.__ordinalMeta},u.type=t+"Axis."+a,u.defaultOption=o,u}(e);r.registerComponentModel(s)}),r.registerSubTypeDefaulter(t+"Axis",Ab)}function Ab(r){return r.type||(r.data?"category":"value")}var qP=function(){function r(t){this.type="cartesian",this._dimList=[],this._axes={},this.name=t||""}return r.prototype.getAxis=function(t){return this._axes[t]},r.prototype.getAxes=function(){return z(this._dimList,function(t){return this._axes[t]},this)},r.prototype.getAxesByScale=function(t){return t=t.toLowerCase(),dt(this.getAxes(),function(e){return e.scale.type===t})},r.prototype.addAxis=function(t){var e=t.dim;this._axes[e]=t,this._dimList.push(e)},r}(),Mb=qP;var Af=["x","y"];function Eb(r){return r.type==="interval"||r.type==="time"}var ZP=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type="cartesian2d",e.dimensions=Af,e}return t.prototype.calcAffineTransform=function(){this._transform=this._invTransform=null;var e=this.getAxis("x").scale,i=this.getAxis("y").scale;if(!(!Eb(e)||!Eb(i))){var n=e.getExtent(),a=i.getExtent(),o=this.dataToPoint([n[0],a[0]]),s=this.dataToPoint([n[1],a[1]]),l=n[1]-n[0],u=a[1]-a[0];if(!(!l||!u)){var f=(s[0]-o[0])/l,h=(s[1]-o[1])/u,c=o[0]-n[0]*f,p=o[1]-a[0]*h,v=this._transform=[f,0,0,h,c,p];this._invTransform=Br([],v)}}},t.prototype.getBaseAxis=function(){return this.getAxesByScale("ordinal")[0]||this.getAxesByScale("time")[0]||this.getAxis("x")},t.prototype.containPoint=function(e){var i=this.getAxis("x"),n=this.getAxis("y");return i.contain(i.toLocalCoord(e[0]))&&n.contain(n.toLocalCoord(e[1]))},t.prototype.containData=function(e){return this.getAxis("x").containData(e[0])&&this.getAxis("y").containData(e[1])},t.prototype.containZone=function(e,i){var n=this.dataToPoint(e),a=this.dataToPoint(i),o=this.getArea(),s=new J(n[0],n[1],a[0]-n[0],a[1]-n[1]);return o.intersect(s)},t.prototype.dataToPoint=function(e,i,n){n=n||[];var a=e[0],o=e[1];if(this._transform&&a!=null&&isFinite(a)&&o!=null&&isFinite(o))return Pt(n,e,this._transform);var s=this.getAxis("x"),l=this.getAxis("y");return n[0]=s.toGlobalCoord(s.dataToCoord(a,i)),n[1]=l.toGlobalCoord(l.dataToCoord(o,i)),n},t.prototype.clampData=function(e,i){var n=this.getAxis("x").scale,a=this.getAxis("y").scale,o=n.getExtent(),s=a.getExtent(),l=n.parse(e[0]),u=a.parse(e[1]);return i=i||[],i[0]=Math.min(Math.max(Math.min(o[0],o[1]),l),Math.max(o[0],o[1])),i[1]=Math.min(Math.max(Math.min(s[0],s[1]),u),Math.max(s[0],s[1])),i},t.prototype.pointToData=function(e,i){var n=[];if(this._invTransform)return Pt(n,e,this._invTransform);var a=this.getAxis("x"),o=this.getAxis("y");return n[0]=a.coordToData(a.toLocalCoord(e[0]),i),n[1]=o.coordToData(o.toLocalCoord(e[1]),i),n},t.prototype.getOtherAxis=function(e){return this.getAxis(e.dim==="x"?"y":"x")},t.prototype.getArea=function(e){e=e||0;var i=this.getAxis("x").getGlobalExtent(),n=this.getAxis("y").getGlobalExtent(),a=Math.min(i[0],i[1])-e,o=Math.min(n[0],n[1])-e,s=Math.max(i[0],i[1])-a+e,l=Math.max(n[0],n[1])-o+e;return new J(a,o,s,l)},t}(Mb),Lb=ZP;var KP=function(r){O(t,r);function t(e,i,n,a,o){var s=r.call(this,e,i,n)||this;return s.index=0,s.type=a||"value",s.position=o||"bottom",s}return t.prototype.isHorizontal=function(){var e=this.position;return e==="top"||e==="bottom"},t.prototype.getGlobalExtent=function(e){var i=this.getExtent();return i[0]=this.toGlobalCoord(i[0]),i[1]=this.toGlobalCoord(i[1]),e&&i[0]>i[1]&&i.reverse(),i},t.prototype.pointToData=function(e,i){return this.coordToData(this.toLocalCoord(e[this.dim==="x"?0:1]),i)},t.prototype.setCategorySortInfo=function(e){if(this.type!=="category")return!1;this.model.option.categorySortInfo=e,this.scale.setSortInfo(e)},t}(mf),Pb=KP;function Ns(r,t,e){e=e||{};var i=r.coordinateSystem,n=t.axis,a={},o=n.getAxesOnZeroOf()[0],s=n.position,l=o?"onZero":s,u=n.dim,f=i.getRect(),h=[f.x,f.x+f.width,f.y,f.y+f.height],c={left:0,right:1,top:0,bottom:1,onZero:2},p=t.get("offset")||0,v=u==="x"?[h[2]-p,h[3]+p]:[h[0]-p,h[1]+p];if(o){var m=o.toGlobalCoord(o.dataToCoord(0));v[c.onZero]=Math.max(Math.min(m,v[1]),v[0])}a.position=[u==="y"?v[c[l]]:h[0],u==="x"?v[c[l]]:h[3]],a.rotation=Math.PI/2*(u==="x"?0:1);var d={top:-1,bottom:1,left:-1,right:1};a.labelDirection=a.tickDirection=a.nameDirection=d[s],a.labelOffset=o?v[c[s]]-v[c.onZero]:0,t.get(["axisTick","inside"])&&(a.tickDirection=-a.tickDirection),le(e.labelInside,t.get(["axisLabel","inside"]))&&(a.labelDirection=-a.labelDirection);var g=t.get(["axisLabel","rotate"]);return a.labelRotate=l==="top"?-g:g,a.z2=1,a}function rd(r){return r.get("coordinateSystem")==="cartesian2d"}function id(r){var t={xAxisModel:null,yAxisModel:null};return w(t,function(e,i){var n=i.replace(/Model$/,""),a=r.getReferringComponents(n,te).models[0];t[i]=a}),t}var nd=Math.log;function Rb(r,t,e){var i=ti.prototype,n=i.getTicks.call(e),a=i.getTicks.call(e,!0),o=n.length-1,s=i.getInterval.call(e),l=Ev(r,t),u=l.extent,f=l.fixMin,h=l.fixMax;if(r.type==="log"){var c=nd(r.base);u=[nd(u[0])/c,nd(u[1])/c]}r.setExtent(u[0],u[1]),r.calcNiceExtent({splitNumber:o,fixMin:f,fixMax:h});var p=i.getExtent.call(r);f&&(u[0]=p[0]),h&&(u[1]=p[1]);var v=i.getInterval.call(r),m=u[0],d=u[1];if(f&&h)v=(d-m)/o;else if(f)for(d=u[0]+v*o;du[0]&&isFinite(m)&&isFinite(u[0]);)v=af(v),m=u[1]-v*o;else{var g=r.getTicks().length-1;g>o&&(v=af(v));var y=v*o;d=Math.ceil(u[1]/v)*v,m=mt(d-y),m<0&&u[0]>=0?(m=0,d=mt(y)):d>0&&u[1]<=0&&(d=0,m=-mt(y))}var _=(n[0].value-a[0].value)/s,x=(n[o].value-a[o].value)/s;if(i.setExtent.call(r,m+v*_,d+v*x),i.setInterval.call(r,v),(_||x)&&i.setNiceExtent.call(r,m+v,d-v),0)var b}var jP=function(){function r(t,e,i){this.type="grid",this._coordsMap={},this._coordsList=[],this._axesMap={},this._axesList=[],this.axisPointerEnabled=!0,this.dimensions=Af,this._initCartesian(t,e,i),this.model=t}return r.prototype.getRect=function(){return this._rect},r.prototype.update=function(t,e){var i=this._axesMap;this._updateScale(t,this.model);function n(o){var s,l=rt(o),u=l.length;if(u){for(var f=[],h=u-1;h>=0;h--){var c=+l[h],p=o[c],v=p.model,m=p.scale;Ms(m)&&v.get("alignTicks")&&v.get("interval")==null?f.push(p):(Ls(m,v),Ms(m)&&(s=p))}f.length&&(s||(s=f.pop(),Ls(s.scale,s.model)),w(f,function(d){Rb(d.scale,d.model,s.scale)}))}}n(i.x),n(i.y);var a={};w(i.x,function(o){Ib(i,"y",o,a)}),w(i.y,function(o){Ib(i,"x",o,a)}),this.resize(this.model,e)},r.prototype.resize=function(t,e,i){var n=t.getBoxLayoutParams(),a=!i&&t.get("containLabel"),o=Kr(n,{width:e.getWidth(),height:e.getHeight()});this._rect=o;var s=this._axesList;l(),a&&(w(s,function(u){if(!u.model.get(["axisLabel","inside"])){var f=SS(u);if(f){var h=u.isHorizontal()?"height":"width",c=u.model.get(["axisLabel","margin"]);o[h]-=f[h]+c,u.position==="top"?o.y+=f.height+c:u.position==="left"&&(o.x+=f.width+c)}}}),l()),w(this._coordsList,function(u){u.calcAffineTransform()});function l(){w(s,function(u){var f=u.isHorizontal(),h=f?[0,o.width]:[0,o.height],c=u.inverse?1:0;u.setExtent(h[c],h[1-c]),QP(u,f?o.x:o.y)})}},r.prototype.getAxis=function(t,e){var i=this._axesMap[t];if(i!=null)return i[e||0]},r.prototype.getAxes=function(){return this._axesList.slice()},r.prototype.getCartesian=function(t,e){if(t!=null&&e!=null){var i="x"+t+"y"+e;return this._coordsMap[i]}H(t)&&(e=t.yAxisIndex,t=t.xAxisIndex);for(var n=0,a=this._coordsList;n0?"top":"bottom",a="center"):un(n-Ri)?(o=i>0?"bottom":"top",a="center"):(o="middle",n>0&&n0?"right":"left":a=i>0?"left":"right"),{rotation:n,textAlign:a,textVerticalAlign:o}},r.makeAxisEventDataBase=function(t){var e={componentType:t.mainType,componentIndex:t.componentIndex};return e[t.mainType+"Index"]=t.componentIndex,e},r.isLabelSilent=function(t){var e=t.get("tooltip");return t.get("silent")||!(t.get("triggerEvent")||e&&e.show)},r}(),zb={axisLine:function(r,t,e,i){var n=t.get(["axisLine","show"]);if(n==="auto"&&r.handleAutoShown&&(n=r.handleAutoShown("axisLine")),!!n){var a=t.axis.getExtent(),o=i.transform,s=[a[0],0],l=[a[1],0],u=s[0]>l[0];o&&(Pt(s,s,o),Pt(l,l,o));var f=I({lineCap:"round"},t.getModel(["axisLine","lineStyle"]).getLineStyle()),h=new he({shape:{x1:s[0],y1:s[1],x2:l[0],y2:l[1]},style:f,strokeContainThreshold:r.strokeContainThreshold||5,silent:!0,z2:1});En(h.shape,h.style.lineWidth),h.anid="line",e.add(h);var c=t.get(["axisLine","symbol"]);if(c!=null){var p=t.get(["axisLine","symbolSize"]);F(c)&&(c=[c,c]),(F(p)||ot(p))&&(p=[p,p]);var v=Vn(t.get(["axisLine","symbolOffset"])||0,p),m=p[0],d=p[1];w([{rotate:r.rotation+Math.PI/2,offset:v[0],r:0},{rotate:r.rotation-Math.PI/2,offset:v[1],r:Math.sqrt((s[0]-l[0])*(s[0]-l[0])+(s[1]-l[1])*(s[1]-l[1]))}],function(g,y){if(c[y]!=="none"&&c[y]!=null){var _=$t(c[y],-m/2,-d/2,m,d,f.stroke,!0),x=g.r+g.offset,b=u?l:s;_.attr({rotation:g.rotate,x:b[0]+x*Math.cos(r.rotation),y:b[1]-x*Math.sin(r.rotation),silent:!0,z2:11}),e.add(_)}})}}},axisTickLabel:function(r,t,e,i){var n=tO(e,i,t,r),a=rO(e,i,t,r);if(JP(t,a,n),eO(e,i,t,r.tickDirection),t.get(["axisLabel","hideOverlap"])){var o=VS(z(a,function(s){return{label:s,priority:s.z2,defaultAttr:{ignore:s.ignore}}}));HS(o)}},axisName:function(r,t,e,i){var n=le(r.axisName,t.get("name"));if(n){var a=t.get("nameLocation"),o=r.nameDirection,s=t.getModel("nameTextStyle"),l=t.get("nameGap")||0,u=t.axis.getExtent(),f=u[0]>u[1]?-1:1,h=[a==="start"?u[0]-f*l:a==="end"?u[1]+f*l:(u[0]+u[1])/2,Bb(a)?r.labelOffset+o*l:0],c,p=t.get("nameRotate");p!=null&&(p=p*Ri/180);var v;Bb(a)?c=Kn.innerTextLayout(r.rotation,p??r.rotation,o):(c=$P(r.rotation,a,p||0,u),v=r.axisNameAvailableWidth,v!=null&&(v=Math.abs(v/Math.sin(c.rotation)),!isFinite(v)&&(v=null)));var m=s.getFont(),d=t.get("nameTruncate",!0)||{},g=d.ellipsis,y=le(r.nameTruncateMaxWidth,d.maxWidth,v),_=new St({x:h[0],y:h[1],rotation:c.rotation,silent:Kn.isLabelSilent(t),style:_e(s,{text:n,font:m,overflow:"truncate",width:y,ellipsis:g,fill:s.getTextColor()||t.get(["axisLine","lineStyle","color"]),align:s.get("align")||c.textAlign,verticalAlign:s.get("verticalAlign")||c.textVerticalAlign}),z2:1});if(Ko({el:_,componentModel:t,itemName:n}),_.__fullText=n,_.anid="name",t.get("triggerEvent")){var x=Kn.makeAxisEventDataBase(t);x.targetType="axisName",x.name=n,it(_).eventData=x}i.add(_),_.updateTransform(),e.add(_),_.decomposeTransform()}}};function $P(r,t,e,i){var n=To(e-r),a,o,s=i[0]>i[1],l=t==="start"&&!s||t!=="start"&&s;return un(n-Ri/2)?(o=l?"bottom":"top",a="center"):un(n-Ri*1.5)?(o=l?"top":"bottom",a="center"):(o="middle",nRi/2?a=l?"left":"right":a=l?"right":"left"),{rotation:n,textAlign:a,textVerticalAlign:o}}function JP(r,t,e){if(!pf(r.axis)){var i=r.get(["axisLabel","showMinLabel"]),n=r.get(["axisLabel","showMaxLabel"]);t=t||[],e=e||[];var a=t[0],o=t[1],s=t[t.length-1],l=t[t.length-2],u=e[0],f=e[1],h=e[e.length-1],c=e[e.length-2];i===!1?(ar(a),ar(u)):Fb(a,o)&&(i?(ar(o),ar(f)):(ar(a),ar(u))),n===!1?(ar(s),ar(h)):Fb(l,s)&&(n?(ar(l),ar(c)):(ar(s),ar(h)))}}function ar(r){r&&(r.ignore=!0)}function Fb(r,t){var e=r&&r.getBoundingRect().clone(),i=t&&t.getBoundingRect().clone();if(!(!e||!i)){var n=Fr([]);return Wi(n,n,-r.rotation),e.applyTransform(Ve([],n,r.getLocalTransform())),i.applyTransform(Ve([],n,t.getLocalTransform())),e.intersect(i)}}function Bb(r){return r==="middle"||r==="center"}function Ub(r,t,e,i,n){for(var a=[],o=[],s=[],l=0;l=0||r===t}function Hb(r){var t=Ef(r);if(t){var e=t.axisPointerModel,i=t.axis.scale,n=e.option,a=e.get("status"),o=e.get("value");o!=null&&(o=i.parse(o));var s=sd(e);a==null&&(n.status=s?"show":"hide");var l=i.getExtent().slice();l[0]>l[1]&&l.reverse(),(o==null||o>l[1])&&(o=l[1]),o0&&(b[0]=-b[0],b[1]=-b[1]);var T=x[0]<0?-1:1;if(a.__position!=="start"&&a.__position!=="end"){var C=-Math.atan2(x[1],x[0]);h[0].8?"left":c[0]<-.8?"right":"center",m=c[1]>.8?"top":c[1]<-.8?"bottom":"middle";break;case"start":a.x=-c[0]*g+f[0],a.y=-c[1]*y+f[1],v=c[0]>.8?"right":c[0]<-.8?"left":"center",m=c[1]>.8?"bottom":c[1]<-.8?"top":"middle";break;case"insideStartTop":case"insideStart":case"insideStartBottom":a.x=g*T+f[0],a.y=f[1]+A,v=x[0]<0?"right":"left",a.originX=-g*T,a.originY=-A;break;case"insideMiddleTop":case"insideMiddle":case"insideMiddleBottom":case"middle":a.x=S[0],a.y=S[1]+A,v="center",a.originY=-A;break;case"insideEndTop":case"insideEnd":case"insideEndBottom":a.x=-g*T+h[0],a.y=h[1]+A,v=x[0]>=0?"right":"left",a.originX=g*T,a.originY=-A;break}a.scaleX=a.scaleY=o,a.setStyle({verticalAlign:a.__verticalAlign||m,align:a.__align||v})}},t}(lt),rw=vO;var dO=function(){function r(t){this.group=new lt,this._LineCtor=t||rw}return r.prototype.updateData=function(t){var e=this;this._progressiveEls=null;var i=this,n=i.group,a=i._lineData;i._lineData=t,a||n.removeAll();var o=iw(t);t.diff(a).add(function(s){e._doAdd(t,s,o)}).update(function(s,l){e._doUpdate(a,t,l,s,o)}).remove(function(s){n.remove(a.getItemGraphicEl(s))}).execute()},r.prototype.updateLayout=function(){var t=this._lineData;t&&t.eachItemGraphicEl(function(e,i){e.updateLayout(t,i)},this)},r.prototype.incrementalPrepareUpdate=function(t){this._seriesScope=iw(t),this._lineData=null,this.group.removeAll()},r.prototype.incrementalUpdate=function(t,e){this._progressiveEls=[];function i(s){!s.isGroup&&!mO(s)&&(s.incremental=!0,s.ensureState("emphasis").hoverLayer=!0)}for(var n=t.start;n0}function iw(r){var t=r.hostModel,e=t.getModel("emphasis");return{lineStyle:t.getModel("lineStyle").getLineStyle(),emphasisLineStyle:e.getModel(["lineStyle"]).getLineStyle(),blurLineStyle:t.getModel(["blur","lineStyle"]).getLineStyle(),selectLineStyle:t.getModel(["select","lineStyle"]).getLineStyle(),emphasisDisabled:e.get("disabled"),blurScope:e.get("blurScope"),focus:e.get("focus"),labelStatesModels:xe(t)}}function nw(r){return isNaN(r[0])||isNaN(r[1])}function md(r){return r&&!nw(r[0])&&!nw(r[1])}var aw=dO;var gd={color:"fill",borderColor:"stroke"},ow={symbol:1,symbolSize:1,symbolKeepAspect:1,legendIcon:1,visualMeta:1,liftZ:1,decal:1},Or=et(),gO=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e}return t.prototype.optionUpdated=function(){this.currentZLevel=this.get("zlevel",!0),this.currentZ=this.get("z",!0)},t.prototype.getInitialData=function(e,i){return nr(null,this)},t.prototype.getDataParams=function(e,i,n){var a=r.prototype.getDataParams.call(this,e,i);return n&&(a.info=Or(n).info),a},t.type="series.custom",t.dependencies=["grid","polar","geo","singleAxis","calendar"],t.defaultOption={coordinateSystem:"cartesian2d",z:2,legendHoverLink:!0,clip:!1},t}(Ut),sw=gO;function yO(r,t){return t=t||[0,0],z(["x","y"],function(e,i){var n=this.getAxis(e),a=t[i],o=r[i]/2;return n.type==="category"?n.getBandWidth():Math.abs(n.dataToCoord(a-o)-n.dataToCoord(a+o))},this)}function yd(r){var t=r.master.getRect();return{coordSys:{type:"cartesian2d",x:t.x,y:t.y,width:t.width,height:t.height},api:{coord:function(e){return r.dataToPoint(e)},size:at(yO,r)}}}function _O(r,t){return t=t||[0,0],z([0,1],function(e){var i=t[e],n=r[e]/2,a=[],o=[];return a[e]=i-n,o[e]=i+n,a[1-e]=o[1-e]=t[1-e],Math.abs(this.dataToPoint(a)[e]-this.dataToPoint(o)[e])},this)}function _d(r){var t=r.getBoundingRect();return{coordSys:{type:"geo",x:t.x,y:t.y,width:t.width,height:t.height,zoom:r.getZoom()},api:{coord:function(e){return r.dataToPoint(e)},size:at(_O,r)}}}function xO(r,t){var e=this.getAxis(),i=t instanceof Array?t[0]:t,n=(r instanceof Array?r[0]:r)/2;return e.type==="category"?e.getBandWidth():Math.abs(e.dataToCoord(i-n)-e.dataToCoord(i+n))}function xd(r){var t=r.getRect();return{coordSys:{type:"singleAxis",x:t.x,y:t.y,width:t.width,height:t.height},api:{coord:function(e){return r.dataToPoint(e)},size:at(xO,r)}}}function SO(r,t){return t=t||[0,0],z(["Radius","Angle"],function(e,i){var n="get"+e+"Axis",a=this[n](),o=t[i],s=r[i]/2,l=a.type==="category"?a.getBandWidth():Math.abs(a.dataToCoord(o-s)-a.dataToCoord(o+s));return e==="Angle"&&(l=l*Math.PI/180),l},this)}function Sd(r){var t=r.getRadiusAxis(),e=r.getAngleAxis(),i=t.getExtent();return i[0]>i[1]&&i.reverse(),{coordSys:{type:"polar",cx:r.cx,cy:r.cy,r:i[1],r0:i[0]},api:{coord:function(n){var a=t.dataToRadius(n[0]),o=e.dataToAngle(n[1]),s=r.coordToPoint([a,o]);return s.push(a,o*Math.PI/180),s},size:at(SO,r)}}}function bd(r){var t=r.getRect(),e=r.getRangeInfo();return{coordSys:{type:"calendar",x:t.x,y:t.y,width:t.width,height:t.height,cellWidth:r.getCellWidth(),cellHeight:r.getCellHeight(),rangeInfo:{start:e.start,end:e.end,weeks:e.weeks,dayCount:e.allDay}},api:{coord:function(i,n){return r.dataToPoint(i,n)}}}}function fw(r,t,e,i){return r&&(r.legacy||r.legacy!==!1&&!e&&!i&&t!=="tspan"&&(t==="text"||U(r,"text")))}function hw(r,t,e){var i=r,n,a,o;if(t==="text")o=i;else{o={},U(i,"text")&&(o.text=i.text),U(i,"rich")&&(o.rich=i.rich),U(i,"textFill")&&(o.fill=i.textFill),U(i,"textStroke")&&(o.stroke=i.textStroke),U(i,"fontFamily")&&(o.fontFamily=i.fontFamily),U(i,"fontSize")&&(o.fontSize=i.fontSize),U(i,"fontStyle")&&(o.fontStyle=i.fontStyle),U(i,"fontWeight")&&(o.fontWeight=i.fontWeight),a={type:"text",style:o,silent:!0},n={};var s=U(i,"textPosition");e?n.position=s?i.textPosition:"inside":s&&(n.position=i.textPosition),U(i,"textPosition")&&(n.position=i.textPosition),U(i,"textOffset")&&(n.offset=i.textOffset),U(i,"textRotation")&&(n.rotation=i.textRotation),U(i,"textDistance")&&(n.distance=i.textDistance)}return lw(o,r),w(o.rich,function(l){lw(l,l)}),{textConfig:n,textContent:a}}function lw(r,t){t&&(t.font=t.textFont||t.font,U(t,"textStrokeWidth")&&(r.lineWidth=t.textStrokeWidth),U(t,"textAlign")&&(r.align=t.textAlign),U(t,"textVerticalAlign")&&(r.verticalAlign=t.textVerticalAlign),U(t,"textLineHeight")&&(r.lineHeight=t.textLineHeight),U(t,"textWidth")&&(r.width=t.textWidth),U(t,"textHeight")&&(r.height=t.textHeight),U(t,"textBackgroundColor")&&(r.backgroundColor=t.textBackgroundColor),U(t,"textPadding")&&(r.padding=t.textPadding),U(t,"textBorderColor")&&(r.borderColor=t.textBorderColor),U(t,"textBorderWidth")&&(r.borderWidth=t.textBorderWidth),U(t,"textBorderRadius")&&(r.borderRadius=t.textBorderRadius),U(t,"textBoxShadowColor")&&(r.shadowColor=t.textBoxShadowColor),U(t,"textBoxShadowBlur")&&(r.shadowBlur=t.textBoxShadowBlur),U(t,"textBoxShadowOffsetX")&&(r.shadowOffsetX=t.textBoxShadowOffsetX),U(t,"textBoxShadowOffsetY")&&(r.shadowOffsetY=t.textBoxShadowOffsetY))}function wd(r,t,e){var i=r;i.textPosition=i.textPosition||e.position||"inside",e.offset!=null&&(i.textOffset=e.offset),e.rotation!=null&&(i.textRotation=e.rotation),e.distance!=null&&(i.textDistance=e.distance);var n=i.textPosition.indexOf("inside")>=0,a=r.fill||"#000";uw(i,t);var o=i.textFill==null;return n?o&&(i.textFill=e.insideFill||"#fff",!i.textStroke&&e.insideStroke&&(i.textStroke=e.insideStroke),!i.textStroke&&(i.textStroke=a),i.textStrokeWidth==null&&(i.textStrokeWidth=2)):(o&&(i.textFill=r.fill||e.outsideFill||"#000"),!i.textStroke&&e.outsideStroke&&(i.textStroke=e.outsideStroke)),i.text=t.text,i.rich=t.rich,w(t.rich,function(s){uw(s,s)}),i}function uw(r,t){t&&(U(t,"fill")&&(r.textFill=t.fill),U(t,"stroke")&&(r.textStroke=t.fill),U(t,"lineWidth")&&(r.textStrokeWidth=t.lineWidth),U(t,"font")&&(r.font=t.font),U(t,"fontStyle")&&(r.fontStyle=t.fontStyle),U(t,"fontWeight")&&(r.fontWeight=t.fontWeight),U(t,"fontSize")&&(r.fontSize=t.fontSize),U(t,"fontFamily")&&(r.fontFamily=t.fontFamily),U(t,"align")&&(r.textAlign=t.align),U(t,"verticalAlign")&&(r.textVerticalAlign=t.verticalAlign),U(t,"lineHeight")&&(r.textLineHeight=t.lineHeight),U(t,"width")&&(r.textWidth=t.width),U(t,"height")&&(r.textHeight=t.height),U(t,"backgroundColor")&&(r.textBackgroundColor=t.backgroundColor),U(t,"padding")&&(r.textPadding=t.padding),U(t,"borderColor")&&(r.textBorderColor=t.borderColor),U(t,"borderWidth")&&(r.textBorderWidth=t.borderWidth),U(t,"borderRadius")&&(r.textBorderRadius=t.borderRadius),U(t,"shadowColor")&&(r.textBoxShadowColor=t.shadowColor),U(t,"shadowBlur")&&(r.textBoxShadowBlur=t.shadowBlur),U(t,"shadowOffsetX")&&(r.textBoxShadowOffsetX=t.shadowOffsetX),U(t,"shadowOffsetY")&&(r.textBoxShadowOffsetY=t.shadowOffsetY),U(t,"textShadowColor")&&(r.textShadowColor=t.textShadowColor),U(t,"textShadowBlur")&&(r.textShadowBlur=t.textShadowBlur),U(t,"textShadowOffsetX")&&(r.textShadowOffsetX=t.textShadowOffsetX),U(t,"textShadowOffsetY")&&(r.textShadowOffsetY=t.textShadowOffsetY))}var dw={position:["x","y"],scale:["scaleX","scaleY"],origin:["originX","originY"]},cw=rt(dw),GX=Vt(Ee,function(r,t){return r[t]=1,r},{}),WX=Ee.join(", "),ks=["","style","shape","extra"],Ka=et();function Td(r,t,e,i,n){var a=r+"Animation",o=Yo(r,i,n)||{},s=Ka(t).userDuring;return o.duration>0&&(o.during=s?at(AO,{el:t,userDuring:s}):null,o.setToFinal=!0,o.scope=r),I(o,e[a]),o}function mw(r,t,e,i){i=i||{};var n=i.dataIndex,a=i.isInit,o=i.clearStyle,s=e.isAnimationEnabled(),l=Ka(r),u=t.style;l.userDuring=t.during;var f={},h={};if(EO(r,t,h),vw("shape",t,h),vw("extra",t,h),!a&&s&&(MO(r,t,f),pw("shape",r,t,f),pw("extra",r,t,f),LO(r,t,u,f)),h.style=u,wO(r,h,o),CO(r,t),s)if(a){var c={};w(ks,function(v){var m=v?t[v]:t;m&&m.enterFrom&&(v&&(c[v]=c[v]||{}),I(v?c[v]:c,m.enterFrom))});var p=Td("enter",r,t,e,n);p.duration>0&&r.animateFrom(c,p)}else TO(r,t,n||0,e,f);bO(r,t),u?r.dirty():r.markRedraw()}function bO(r,t){for(var e=Ka(r).leaveToProps,i=0;i0&&r.animateFrom(n,a)}}function CO(r,t){U(t,"silent")&&(r.silent=t.silent),U(t,"ignore")&&(r.ignore=t.ignore),r instanceof ge&&U(t,"invisible")&&(r.invisible=t.invisible),r instanceof Z&&U(t,"autoBatch")&&(r.autoBatch=t.autoBatch)}var Rr={},DO={setTransform:function(r,t){return Rr.el[r]=t,this},getTransform:function(r){return Rr.el[r]},setShape:function(r,t){var e=Rr.el,i=e.shape||(e.shape={});return i[r]=t,e.dirtyShape&&e.dirtyShape(),this},getShape:function(r){var t=Rr.el.shape;if(t)return t[r]},setStyle:function(r,t){var e=Rr.el,i=e.style;return i&&(i[r]=t,e.dirtyStyle&&e.dirtyStyle()),this},getStyle:function(r){var t=Rr.el.style;if(t)return t[r]},setExtra:function(r,t){var e=Rr.el.extra||(Rr.el.extra={});return e[r]=t,this},getExtra:function(r){var t=Rr.el.extra;if(t)return t[r]}};function AO(){var r=this,t=r.el;if(t){var e=Ka(t).userDuring,i=r.userDuring;if(e!==i){r.el=r.userDuring=null;return}Rr.el=t,i(DO)}}function pw(r,t,e,i){var n=e[r];if(n){var a=t[r],o;if(a){var s=e.transition,l=n.transition;if(l)if(!o&&(o=i[r]={}),Za(l))I(o,a);else for(var u=bt(l),f=0;f=0){!o&&(o=i[r]={});for(var p=rt(a),f=0;f=0)){var c=r.getAnimationStyleProps(),p=c?c.style:null;if(p){!a&&(a=i.style={});for(var v=rt(e),u=0;u=0?t.getStore().get(q,P):void 0}var B=t.get(k.name,P),V=k&&k.ordinalMeta;return V?V.categories[B]:B}function S(E,P){P==null&&(P=u);var k=t.getItemVisual(P,"style"),q=k&&k.fill,B=k&&k.opacity,V=y(P,Ii).getItemStyle();q!=null&&(V.fill=q),B!=null&&(V.opacity=B);var tt={inheritColor:F(q)?q:"#000"},ft=_(P,Ii),ct=_e(ft,null,tt,!1,!0);ct.text=ft.getShallow("show")?Q(r.getFormattedLabel(P,Ii),ei(t,P)):null;var yt=jo(ft,tt,!1);return A(E,V),V=wd(V,ct,yt),E&&C(V,E),V.legacy=!0,V}function T(E,P){P==null&&(P=u);var k=y(P,ri).getItemStyle(),q=_(P,ri),B=_e(q,null,null,!0,!0);B.text=q.getShallow("show")?yr(r.getFormattedLabel(P,ri),r.getFormattedLabel(P,Ii),ei(t,P)):null;var V=jo(q,null,!0);return A(E,k),k=wd(k,B,V),E&&C(k,E),k.legacy=!0,k}function C(E,P){for(var k in P)U(P,k)&&(E[k]=P[k])}function A(E,P){E&&(E.textFill&&(P.textFill=E.textFill),E.textPosition&&(P.textPosition=E.textPosition))}function M(E,P){if(P==null&&(P=u),U(gd,E)){var k=t.getItemVisual(P,"style");return k?k[gd[E]]:null}if(U(ow,E))return t.getItemVisual(P,E)}function D(E){if(a.type==="cartesian2d"){var P=a.getBaseAxis();return oS(X({axis:P},E))}}function L(){return e.getCurrentSeriesIndices()}function R(E){return iu(E,e)}}function UO(r){var t={};return w(r.dimensions,function(e){var i=r.getDimensionInfo(e);if(!i.isExtraCoord){var n=i.coordDim,a=t[n]=t[n]||[];a[i.coordDimIndex]=r.getDimensionIndex(e)}}),t}function Md(r,t,e,i,n,a,o){if(!i){a.remove(t);return}var s=Nd(r,t,e,i,n,a);return s&&o.setItemGraphicEl(e,s),s&&Oe(s,i.focus,i.blurScope,i.emphasisDisabled),s}function Nd(r,t,e,i,n,a){var o=-1,s=t;t&&Cw(t,i,n)&&(o=K(a.childrenRef(),t),t=null);var l=!t,u=t;u?u.clearStates():(u=Rd(i),s&&kO(s,u)),i.morph===!1?u.disableMorphing=!0:u.disableMorphing&&(u.disableMorphing=!1),or.normal.cfg=or.normal.conOpt=or.emphasis.cfg=or.emphasis.conOpt=or.blur.cfg=or.blur.conOpt=or.select.cfg=or.select.conOpt=null,or.isLegacy=!1,HO(u,e,i,n,l,or),VO(u,e,i,n,l),Id(r,u,e,i,or,n,l),U(i,"info")&&(Or(u).info=i.info);for(var f=0;f=0?a.replaceAt(u,o):a.add(u),u}function Cw(r,t,e){var i=Or(r),n=t.type,a=t.shape,o=t.style;return e.isUniversalTransitionEnabled()||n!=null&&n!==i.customGraphicType||n==="path"&&qO(a)&&Dw(a)!==i.customPathData||n==="image"&&U(o,"image")&&o.image!==i.customImagePath}function VO(r,t,e,i,n){var a=e.clipPath;if(a===!1)r&&r.getClipPath()&&r.removeClipPath();else if(a){var o=r.getClipPath();o&&Cw(o,a,i)&&(o=null),o||(o=Rd(a),r.setClipPath(o)),Id(null,o,t,a,null,i,n)}}function HO(r,t,e,i,n,a){if(!r.isGroup){xw(e,null,a),xw(e,ri,a);var o=a.normal.conOpt,s=a.emphasis.conOpt,l=a.blur.conOpt,u=a.select.conOpt;if(o!=null||s!=null||u!=null||l!=null){var f=r.getTextContent();if(o===!1)f&&r.removeTextContent();else{o=a.normal.conOpt=o||{type:"text"},f?f.clearStates():(f=Rd(o),r.setTextContent(f)),Id(null,f,t,o,null,i,n);for(var h=o&&o.style,c=0;c=f;p--){var v=t.childAt(p);WO(t,v,n)}}}function WO(r,t,e){t&&Of(t,Or(r).option,e)}function YO(r){new $u(r.oldChildren,r.newChildren,Sw,Sw,r).add(bw).update(bw).remove(XO).execute()}function Sw(r,t){var e=r&&r.name;return e??IO+t}function bw(r,t){var e=this.context,i=r!=null?e.newChildren[r]:null,n=t!=null?e.oldChildren[t]:null;Nd(e.api,n,e.dataIndex,i,e.seriesModel,e.group)}function XO(r){var t=this.context,e=t.oldChildren[r];e&&Of(e,Or(e).option,t.seriesModel)}function Dw(r){return r&&(r.pathData||r.d)}function qO(r){return r&&(U(r,"pathData")||U(r,"d"))}function zd(r){r.registerChartView(ww),r.registerSeriesModel(sw)}var jn=et(),Aw=j,Fd=at,ZO=function(){function r(){this._dragging=!1,this.animationThreshold=15}return r.prototype.render=function(t,e,i,n){var a=e.get("value"),o=e.get("status");if(this._axisModel=t,this._axisPointerModel=e,this._api=i,!(!n&&this._lastValue===a&&this._lastStatus===o)){this._lastValue=a,this._lastStatus=o;var s=this._group,l=this._handle;if(!o||o==="hide"){s&&s.hide(),l&&l.hide();return}s&&s.show(),l&&l.show();var u={};this.makeElOption(u,a,t,e,i);var f=u.graphicKey;f!==this._lastGraphicKey&&this.clear(i),this._lastGraphicKey=f;var h=this._moveAnimation=this.determineAnimation(t,e);if(!s)s=this._group=new lt,this.createPointerEl(s,u,t,e),this.createLabelEl(s,u,t,e),i.getZr().add(s);else{var c=st(Mw,e,h);this.updatePointerEl(s,u,c),this.updateLabelEl(s,u,c,e)}Lw(s,e,!0),this._renderHandle(a)}},r.prototype.remove=function(t){this.clear(t)},r.prototype.dispose=function(t){this.clear(t)},r.prototype.determineAnimation=function(t,e){var i=e.get("animation"),n=t.axis,a=n.type==="category",o=e.get("snap");if(!o&&!a)return!1;if(i==="auto"||i==null){var s=this.animationThreshold;if(a&&n.getBandWidth()>s)return!0;if(o){var l=Ef(t).seriesDataCount,u=n.getExtent();return Math.abs(u[0]-u[1])/l>s}return!1}return i===!0},r.prototype.makeElOption=function(t,e,i,n,a){},r.prototype.createPointerEl=function(t,e,i,n){var a=e.pointer;if(a){var o=jn(t).pointerEl=new Lt[a.type](Aw(e.pointer));t.add(o)}},r.prototype.createLabelEl=function(t,e,i,n){if(e.label){var a=jn(t).labelEl=new St(Aw(e.label));t.add(a),Ew(a,n)}},r.prototype.updatePointerEl=function(t,e,i){var n=jn(t).pointerEl;n&&e.pointer&&(n.setStyle(e.pointer.style),i(n,{shape:e.pointer.shape}))},r.prototype.updateLabelEl=function(t,e,i,n){var a=jn(t).labelEl;a&&(a.setStyle(e.label.style),i(a,{x:e.label.x,y:e.label.y}),Ew(a,n))},r.prototype._renderHandle=function(t){if(!(this._dragging||!this.updateHandleTransform)){var e=this._axisPointerModel,i=this._api.getZr(),n=this._handle,a=e.getModel("handle"),o=e.get("status");if(!a.get("show")||!o||o==="hide"){n&&i.remove(n),this._handle=null;return}var s;this._handle||(s=!0,n=this._handle=Ln(a.get("icon"),{cursor:"move",draggable:!0,onmousemove:function(u){$s(u.event)},onmousedown:Fd(this._onHandleDragMove,this,0,0),drift:Fd(this._onHandleDragMove,this),ondragend:Fd(this._onHandleDragEnd,this)}),i.add(n)),Lw(n,e,!1),n.setStyle(a.getItemStyle(null,["color","borderColor","borderWidth","opacity","shadowColor","shadowBlur","shadowOffsetX","shadowOffsetY"]));var l=a.get("size");N(l)||(l=[l,l]),n.scaleX=l[0]/2,n.scaleY=l[1]/2,Iu(this,"_doDispatchAxisPointer",a.get("throttle")||0,"fixRate"),this._moveHandleToValue(t,s)}},r.prototype._moveHandleToValue=function(t,e){Mw(this._axisPointerModel,!e&&this._moveAnimation,this._handle,Bd(this.getHandleTransform(t,this._axisModel,this._axisPointerModel)))},r.prototype._onHandleDragMove=function(t,e){var i=this._handle;if(i){this._dragging=!0;var n=this.updateHandleTransform(Bd(i),[t,e],this._axisModel,this._axisPointerModel);this._payloadInfo=n,i.stopAnimation(),i.attr(Bd(n)),jn(i).lastProp=null,this._doDispatchAxisPointer()}},r.prototype._doDispatchAxisPointer=function(){var t=this._handle;if(t){var e=this._payloadInfo,i=this._axisModel;this._api.dispatchAction({type:"updateAxisPointer",x:e.cursorPoint[0],y:e.cursorPoint[1],tooltipOption:e.tooltipOption,axesInfo:[{axisDim:i.axis.dim,axisIndex:i.componentIndex}]})}},r.prototype._onHandleDragEnd=function(){this._dragging=!1;var t=this._handle;if(t){var e=this._axisPointerModel.get("value");this._moveHandleToValue(e),this._api.dispatchAction({type:"hideTip"})}},r.prototype.clear=function(t){this._lastValue=null,this._lastStatus=null;var e=t.getZr(),i=this._group,n=this._handle;e&&i&&(this._lastGraphicKey=null,i&&e.remove(i),n&&e.remove(n),this._group=null,this._handle=null,this._payloadInfo=null),cs(this,"_doDispatchAxisPointer")},r.prototype.doClear=function(){},r.prototype.buildLabel=function(t,e,i){return i=i||0,{x:t[i],y:t[1-i],width:e[i],height:e[1-i]}},r}();function Mw(r,t,e,i){Pw(jn(e).lastProp,i)||(jn(e).lastProp=i,t?wt(e,i,r):(e.stopAnimation(),e.attr(i)))}function Pw(r,t){if(H(r)&&H(t)){var e=!0;return w(t,function(i,n){e=e&&Pw(r[n],i)}),!!e}else return r===t}function Ew(r,t){r[t.get(["label","show"])?"show":"hide"]()}function Bd(r){return{x:r.x||0,y:r.y||0,rotation:r.rotation||0}}function Lw(r,t,e){var i=t.get("z"),n=t.get("zlevel");r&&r.traverse(function(a){a.type!=="group"&&(i!=null&&(a.z=i),n!=null&&(a.zlevel=n),a.silent=e)})}var Ow=ZO;function Rw(r){var t=r.get("type"),e=r.getModel(t+"Style"),i;return t==="line"?(i=e.getLineStyle(),i.fill=null):t==="shadow"&&(i=e.getAreaStyle(),i.stroke=null),i}function KO(r,t,e,i,n){var a=e.get("value"),o=Ud(a,t.axis,t.ecModel,e.get("seriesDataIndices"),{precision:e.get(["label","precision"]),formatter:e.get(["label","formatter"])}),s=e.getModel("label"),l=Mr(s.get("padding")||0),u=s.getFont(),f=ua(o,u),h=n.position,c=f.width+l[1]+l[3],p=f.height+l[0]+l[2],v=n.align;v==="right"&&(h[0]-=c),v==="center"&&(h[0]-=c/2);var m=n.verticalAlign;m==="bottom"&&(h[1]-=p),m==="middle"&&(h[1]-=p/2),jO(h,c,p,i);var d=s.get("backgroundColor");(!d||d==="auto")&&(d=t.get(["axisLine","lineStyle","color"])),r.label={x:h[0],y:h[1],style:_e(s,{text:o,font:u,fill:s.getTextColor(),padding:l,backgroundColor:d}),z2:10}}function jO(r,t,e,i){var n=i.getWidth(),a=i.getHeight();r[0]=Math.min(r[0]+t,n)-t,r[1]=Math.min(r[1]+e,a)-e,r[0]=Math.max(r[0],0),r[1]=Math.max(r[1],0)}function Ud(r,t,e,i,n){r=t.scale.parse(r);var a=t.scale.getLabel({value:r},{precision:n.precision}),o=n.formatter;if(o){var s={value:Ps(t,{value:r}),axisDimension:t.dim,axisIndex:t.index,seriesData:[]};w(i,function(l){var u=e.getSeriesByIndex(l.seriesIndex),f=l.dataIndexInside,h=u&&u.getDataParams(f);h&&s.seriesData.push(h)}),F(o)?a=o.replace("{value}",a):G(o)&&(a=o(s))}return a}function Vd(r,t,e){var i=lr();return Wi(i,i,e.rotation),ia(i,i,e.position),eu([r.dataToCoord(t),(e.labelOffset||0)+(e.labelDirection||1)*(e.labelMargin||0)],i)}function Iw(r,t,e,i,n,a){var o=Mf.innerTextLayout(e.rotation,0,e.labelDirection);e.labelMargin=n.get(["label","margin"]),KO(t,i,n,a,{position:Vd(i.axis,r,e),align:o.textAlign,verticalAlign:o.textVerticalAlign})}function Nw(r,t,e){return e=e||0,{x1:r[e],y1:r[1-e],x2:t[e],y2:t[1-e]}}function kw(r,t,e){return e=e||0,{x:r[e],y:r[1-e],width:t[e],height:t[1-e]}}var QO=function(r){O(t,r);function t(){return r!==null&&r.apply(this,arguments)||this}return t.prototype.makeElOption=function(e,i,n,a,o){var s=n.axis,l=s.grid,u=a.get("type"),f=Fw(l,s).getOtherAxis(s).getGlobalExtent(),h=s.toGlobalCoord(s.dataToCoord(i,!0));if(u&&u!=="none"){var c=Rw(a),p=$O[u](s,h,f);p.style=c,e.graphicKey=p.type,e.pointer=p}var v=Ns(l.model,n);Iw(i,e,v,n,a,o)},t.prototype.getHandleTransform=function(e,i,n){var a=Ns(i.axis.grid.model,i,{labelInside:!1});a.labelMargin=n.get(["handle","margin"]);var o=Vd(i.axis,e,a);return{x:o[0],y:o[1],rotation:a.rotation+(a.labelDirection<0?Math.PI:0)}},t.prototype.updateHandleTransform=function(e,i,n,a){var o=n.axis,s=o.grid,l=o.getGlobalExtent(!0),u=Fw(s,o).getOtherAxis(o).getGlobalExtent(),f=o.dim==="x"?0:1,h=[e.x,e.y];h[f]+=i[f],h[f]=Math.min(l[1],h[f]),h[f]=Math.max(l[0],h[f]);var c=(u[1]+u[0])/2,p=[c,c];p[f]=h[f];var v=[{verticalAlign:"middle"},{align:"center"}];return{x:h[0],y:h[1],rotation:e.rotation,cursorPoint:p,tooltipOption:v[f]}},t}(Ow);function Fw(r,t){var e={};return e[t.dim+"AxisIndex"]=t.index,r.getCartesian(e)}var $O={line:function(r,t,e){var i=Nw([t,e[0]],[t,e[1]],Bw(r));return{type:"Line",subPixelOptimize:!0,shape:i}},shadow:function(r,t,e){var i=Math.max(1,r.getBandWidth()),n=e[1]-e[0];return{type:"Rect",shape:kw([t-i/2,e[0]],[i,n],Bw(r))}}};function Bw(r){return r.dim==="x"?0:1}var Uw=QO;var JO=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e}return t.type="axisPointer",t.defaultOption={show:"auto",z:50,type:"line",snap:!1,triggerTooltip:!0,triggerEmphasis:!0,value:null,status:null,link:[],animation:null,animationDurationUpdate:200,lineStyle:{color:"#B9BEC9",width:1,type:"dashed"},shadowStyle:{color:"rgba(210,219,238,0.2)"},label:{show:!0,formatter:null,precision:"auto",margin:3,color:"#fff",padding:[5,7,5,7],backgroundColor:"auto",borderColor:null,borderWidth:0,borderRadius:3},handle:{show:!1,icon:"M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z",size:45,margin:50,color:"#333",shadowBlur:3,shadowColor:"#aaa",shadowOffsetX:0,shadowOffsetY:2,throttle:40}},t}(ht),Vw=JO;var ii=et(),tR=w;function If(r,t,e){if(!Y.node){var i=t.getZr();ii(i).records||(ii(i).records={}),eR(i,t);var n=ii(i).records[r]||(ii(i).records[r]={});n.handler=e}}function eR(r,t){if(ii(r).initialized)return;ii(r).initialized=!0,e("click",st(Hw,"click")),e("mousemove",st(Hw,"mousemove")),e("globalout",iR);function e(i,n){r.on(i,function(a){var o=nR(t);tR(ii(r).records,function(s){s&&n(s,a,o.dispatchAction)}),rR(o.pendings,t)})}}function rR(r,t){var e=r.showTip.length,i=r.hideTip.length,n;e?n=r.showTip[e-1]:i&&(n=r.hideTip[i-1]),n&&(n.dispatchAction=null,t.dispatchAction(n))}function iR(r,t,e){r.handler("leave",null,e)}function Hw(r,t,e,i){t.handler(r,e,i)}function nR(r){var t={showTip:[],hideTip:[]},e=function(i){var n=t[i.type];n?n.push(i):(i.dispatchAction=e,r.dispatchAction(i))};return{dispatchAction:e,pendings:t}}function zs(r,t){if(!Y.node){var e=t.getZr(),i=(ii(e).records||{})[r];i&&(ii(e).records[r]=null)}}var aR=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e}return t.prototype.render=function(e,i,n){var a=i.getComponent("tooltip"),o=e.get("triggerOn")||a&&a.get("triggerOn")||"mousemove|click";If("axisPointer",n,function(s,l,u){o!=="none"&&(s==="leave"||o.indexOf(s)>=0)&&u({type:"updateAxisPointer",currTrigger:s,x:l&&l.offsetX,y:l&&l.offsetY})})},t.prototype.remove=function(e,i){zs("axisPointer",i)},t.prototype.dispose=function(e,i){zs("axisPointer",i)},t.type="axisPointer",t}(Rt),Ww=aR;function Fs(r,t){var e=[],i=r.seriesIndex,n;if(i==null||!(n=t.getSeriesByIndex(i)))return{point:[]};var a=n.getData(),o=Xe(a,r);if(o==null||o<0||N(o))return{point:[]};var s=a.getItemGraphicEl(o),l=n.coordinateSystem;if(n.getTooltipPosition)e=n.getTooltipPosition(o)||[];else if(l&&l.dataToPoint)if(r.isStacked){var u=l.getBaseAxis(),f=l.getOtherAxis(u),h=f.dim,c=u.dim,p=h==="x"||h==="radius"?1:0,v=a.mapDimension(c),m=[];m[p]=a.get(v,o),m[1-p]=a.get(a.getCalculationInfo("stackResultDimension"),o),e=l.dataToPoint(m)||[]}else e=l.dataToPoint(a.getValues(z(l.dimensions,function(g){return a.mapDimension(g)}),o))||[];else if(s){var d=s.getBoundingRect().clone();d.applyTransform(s.transform),e=[d.x+d.width/2,d.y+d.height/2]}return{point:e,el:s}}var Yw=et();function Hd(r,t,e){var i=r.currTrigger,n=[r.x,r.y],a=r,o=r.dispatchAction||at(e.dispatchAction,e),s=t.getComponent("axisPointer").coordSysAxesInfo;if(s){Nf(n)&&(n=Fs({seriesIndex:a.seriesIndex,dataIndex:a.dataIndex},t).point);var l=Nf(n),u=a.axesInfo,f=s.axesInfo,h=i==="leave"||Nf(n),c={},p={},v={list:[],map:{}},m={showPointer:st(sR,p),showTooltip:st(lR,v)};w(s.coordSysMap,function(g,y){var _=l||g.containPoint(n);w(s.coordSysAxesInfo[y],function(x,b){var S=x.axis,T=cR(u,x);if(!h&&_&&(!u||T)){var C=T&&T.value;C==null&&!l&&(C=S.pointToData(n)),C!=null&&Xw(x,C,m,!1,c)}})});var d={};return w(f,function(g,y){var _=g.linkGroup;_&&!p[y]&&w(_.axesInfo,function(x,b){var S=p[b];if(x!==g&&S){var T=S.value;_.mapper&&(T=g.axis.scale.parse(_.mapper(T,qw(x),qw(g)))),d[g.key]=T}})}),w(d,function(g,y){Xw(f[y],g,m,!0,c)}),uR(p,f,c),fR(v,n,r,o),hR(f,o,e),c}}function Xw(r,t,e,i,n){var a=r.axis;if(!(a.scale.isBlank()||!a.containData(t))){if(!r.involveSeries){e.showPointer(r,t);return}var o=oR(t,r),s=o.payloadBatch,l=o.snapToValue;s[0]&&n.seriesIndex==null&&I(n,s[0]),!i&&r.snap&&a.containData(l)&&l!=null&&(t=l),e.showPointer(r,t,s),e.showTooltip(r,o,l)}}function oR(r,t){var e=t.axis,i=e.dim,n=r,a=[],o=Number.MAX_VALUE,s=-1;return w(t.seriesModels,function(l,u){var f=l.getData().mapDimensionsAll(i),h,c;if(l.getAxisTooltipData){var p=l.getAxisTooltipData(f,r,e);c=p.dataIndices,h=p.nestestValue}else{if(c=l.getData().indicesOfNearest(f[0],r,e.type==="category"?.5:null),!c.length)return;h=l.getData().get(f[0],c[0])}if(!(h==null||!isFinite(h))){var v=r-h,m=Math.abs(v);m<=o&&((m=0&&s<0)&&(o=m,s=v,n=h,a.length=0),w(c,function(d){a.push({seriesIndex:l.seriesIndex,dataIndexInside:d,dataIndex:l.getData().getRawIndex(d)})}))}}),{payloadBatch:a,snapToValue:n}}function sR(r,t,e,i){r[t.key]={value:e,payloadBatch:i}}function lR(r,t,e,i){var n=e.payloadBatch,a=t.axis,o=a.model,s=t.axisPointerModel;if(!(!t.triggerTooltip||!n.length)){var l=t.coordSys.model,u=qa(l),f=r.map[u];f||(f=r.map[u]={coordSysId:l.id,coordSysIndex:l.componentIndex,coordSysType:l.type,coordSysMainType:l.mainType,dataByAxis:[]},r.list.push(f)),f.dataByAxis.push({axisDim:a.dim,axisIndex:o.componentIndex,axisType:o.type,axisId:o.id,value:i,valueLabelOpt:{precision:s.get(["label","precision"]),formatter:s.get(["label","formatter"])},seriesDataIndices:n.slice()})}}function uR(r,t,e){var i=e.axesInfo=[];w(t,function(n,a){var o=n.axisPointerModel.option,s=r[a];s?(!n.useHandle&&(o.status="show"),o.value=s.value,o.seriesDataIndices=(s.payloadBatch||[]).slice()):!n.useHandle&&(o.status="hide"),o.status==="show"&&i.push({axisDim:n.axis.dim,axisIndex:n.axis.model.componentIndex,value:o.value})})}function fR(r,t,e,i){if(Nf(t)||!r.list.length){i({type:"hideTip"});return}var n=((r.list[0].dataByAxis[0]||{}).seriesDataIndices||[])[0]||{};i({type:"showTip",escapeConnect:!0,x:t[0],y:t[1],tooltipOption:e.tooltipOption,position:e.position,dataIndexInside:n.dataIndexInside,dataIndex:n.dataIndex,seriesIndex:n.seriesIndex,dataByCoordSys:r.list})}function hR(r,t,e){var i=e.getZr(),n="axisPointerLastHighlights",a=Yw(i)[n]||{},o=Yw(i)[n]={};w(r,function(u,f){var h=u.axisPointerModel.option;h.status==="show"&&u.triggerEmphasis&&w(h.seriesDataIndices,function(c){var p=c.seriesIndex+" | "+c.dataIndex;o[p]=c})});var s=[],l=[];w(a,function(u,f){!o[f]&&l.push(u)}),w(o,function(u,f){!a[f]&&s.push(u)}),l.length&&e.dispatchAction({type:"downplay",escapeConnect:!0,notBlur:!0,batch:l}),s.length&&e.dispatchAction({type:"highlight",escapeConnect:!0,notBlur:!0,batch:s})}function cR(r,t){for(var e=0;e<(r||[]).length;e++){var i=r[e];if(t.axis.dim===i.axisDim&&t.axis.model.componentIndex===i.axisIndex)return i}}function qw(r){var t=r.axis.model,e={},i=e.axisDim=r.axis.dim;return e.axisIndex=e[i+"AxisIndex"]=t.componentIndex,e.axisName=e[i+"AxisName"]=t.name,e.axisId=e[i+"AxisId"]=t.id,e}function Nf(r){return!r||r[0]==null||isNaN(r[0])||r[1]==null||isNaN(r[1])}function kf(r){Lf.registerAxisPointerClass("CartesianAxisPointer",Uw),r.registerComponentModel(Vw),r.registerComponentView(Ww),r.registerPreprocessor(function(t){if(t){(!t.axisPointer||t.axisPointer.length===0)&&(t.axisPointer={});var e=t.axisPointer.link;e&&!N(e)&&(t.axisPointer.link=[e])}}),r.registerProcessor(r.PRIORITY.PROCESSOR.STATISTIC,function(t,e){t.getComponent("axisPointer").coordSysAxesInfo=Vb(t,e)}),r.registerAction({type:"updateAxisPointer",event:"updateAxisPointer",update:":updateAxisPointer"},Hd)}function Gd(r){Ce(Pf),Ce(kf)}function Zw(r,t){var e=Mr(t.get("padding")),i=t.getItemStyle(["color","opacity"]);return i.fill=t.get("backgroundColor"),r=new vt({shape:{x:r.x-e[3],y:r.y-e[0],width:r.width+e[1]+e[3],height:r.height+e[0]+e[2],r:t.get("borderRadius")},style:i,silent:!0,z2:-1}),r}var pR=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e}return t.type="tooltip",t.dependencies=["axisPointer"],t.defaultOption={z:60,show:!0,showContent:!0,trigger:"item",triggerOn:"mousemove|click",alwaysShowContent:!1,displayMode:"single",renderMode:"auto",confine:null,showDelay:0,hideDelay:100,transitionDuration:.4,enterable:!1,backgroundColor:"#fff",shadowBlur:10,shadowColor:"rgba(0, 0, 0, .2)",shadowOffsetX:1,shadowOffsetY:2,borderRadius:4,borderWidth:1,padding:null,extraCssText:"",axisPointer:{type:"line",axis:"auto",animation:"auto",animationDurationUpdate:200,animationEasingUpdate:"exponentialOut",crossStyle:{color:"#999",width:1,type:"dashed",textStyle:{}}},textStyle:{color:"#666",fontSize:14}},t}(ht),Kw=pR;function zf(r){var t=r.get("confine");return t!=null?!!t:r.get("renderMode")==="richText"}function jw(r){if(Y.domSupported){for(var t=document.documentElement.style,e=0,i=r.length;e-1?(s+="top:50%",l+="translateY(-50%) rotate("+(u=a==="left"?-225:-45)+"deg)"):(s+="left:50%",l+="translateX(-50%) rotate("+(u=a==="top"?225:45)+"deg)");var f=u*Math.PI/180,h=o+n,c=h*Math.abs(Math.cos(f))+h*Math.abs(Math.sin(f)),p=Math.round(((c-Math.SQRT2*n)/2+Math.SQRT2*n-(c-h)/2)*100)/100;s+=";"+a+":-"+p+"px";var v=t+" solid "+n+"px;",m=["position:absolute;width:"+o+"px;height:"+o+"px;z-index:-1;",s+";"+l+";","border-bottom:"+v,"border-right:"+v,"background-color:"+i+";"];return'
'}function yR(r,t){var e="cubic-bezier(0.23,1,0.32,1)",i=" "+r/2+"s "+e,n="opacity"+i+",visibility"+i;return t||(i=" "+r+"s "+e,n+=Y.transformSupported?","+Xd+i:",left"+i+",top"+i),vR+":"+n}function Jw(r,t,e){var i=r.toFixed(0)+"px",n=t.toFixed(0)+"px";if(!Y.transformSupported)return e?"top:"+n+";left:"+i+";":[["top",n],["left",i]];var a=Y.transform3dSupported,o="translate"+(a?"3d":"")+"("+i+","+n+(a?",0":"")+")";return e?"top:0;left:0;"+Xd+":"+o+";":[["top",0],["left",0],[Wd,o]]}function _R(r){var t=[],e=r.get("fontSize"),i=r.getTextColor();i&&t.push("color:"+i),t.push("font:"+r.getFont()),e&&t.push("line-height:"+Math.round(e*3/2)+"px");var n=r.get("textShadowColor"),a=r.get("textShadowBlur")||0,o=r.get("textShadowOffsetX")||0,s=r.get("textShadowOffsetY")||0;return n&&a&&t.push("text-shadow:"+o+"px "+s+"px "+a+"px "+n),w(["decoration","align"],function(l){var u=r.get(l);u&&t.push("text-"+l+":"+u)}),t.join(";")}function xR(r,t,e){var i=[],n=r.get("transitionDuration"),a=r.get("backgroundColor"),o=r.get("shadowBlur"),s=r.get("shadowColor"),l=r.get("shadowOffsetX"),u=r.get("shadowOffsetY"),f=r.getModel("textStyle"),h=Eu(r,"html"),c=l+"px "+u+"px "+o+"px "+s;return i.push("box-shadow:"+c),t&&n&&i.push(yR(n,e)),a&&i.push("background-color:"+a),w(["width","color","radius"],function(p){var v="border-"+p,m=Oa(v),d=r.get(m);d!=null&&i.push(v+":"+d+(p==="color"?"":"px"))}),i.push(_R(f)),h!=null&&i.push("padding:"+Mr(h).join("px ")+"px"),i.join(";")+";"}function t1(r,t,e,i,n){var a=t&&t.painter;if(e){var o=a&&a.getViewportRoot();o&&Sm(r,o,e,i,n)}else{r[0]=i,r[1]=n;var s=a&&a.getViewportRootOffset();s&&(r[0]+=s.offsetLeft,r[1]+=s.offsetTop)}r[2]=r[0]/t.getWidth(),r[3]=r[1]/t.getHeight()}var SR=function(){function r(t,e){if(this._show=!1,this._styleCoord=[0,0,0,0],this._enterable=!0,this._alwaysShowContent=!1,this._firstShow=!0,this._longHide=!0,Y.wxa)return null;var i=document.createElement("div");i.domBelongToZr=!0,this.el=i;var n=this._zr=t.getZr(),a=e.appendTo,o=a&&(F(a)?document.querySelector(a):Bi(a)?a:G(a)&&a(t.getDom()));t1(this._styleCoord,n,o,t.getWidth()/2,t.getHeight()/2),(o||t.getDom()).appendChild(i),this._api=t,this._container=o;var s=this;i.onmouseenter=function(){s._enterable&&(clearTimeout(s._hideTimeout),s._show=!0),s._inContent=!0},i.onmousemove=function(l){if(l=l||window.event,!s._enterable){var u=n.handler,f=n.painter.getViewportRoot();ve(f,l,!0),u.dispatch("mousemove",l)}},i.onmouseleave=function(){s._inContent=!1,s._enterable&&s._show&&s.hideLater(s._hideDelay)}}return r.prototype.update=function(t){if(!this._container){var e=this._api.getDom(),i=$w(e,"position"),n=e.style;n.position!=="absolute"&&i!=="absolute"&&(n.position="relative")}var a=t.get("alwaysShowContent");a&&this._moveIfResized(),this._alwaysShowContent=a,this.el.className=t.get("className")||""},r.prototype.show=function(t,e){clearTimeout(this._hideTimeout),clearTimeout(this._longHideTimeout);var i=this.el,n=i.style,a=this._styleCoord;i.innerHTML?n.cssText=dR+xR(t,!this._firstShow,this._longHide)+Jw(a[0],a[1],!0)+("border-color:"+pr(e)+";")+(t.get("extraCssText")||"")+(";pointer-events:"+(this._enterable?"auto":"none")):n.display="none",this._show=!0,this._firstShow=!1,this._longHide=!1},r.prototype.setContent=function(t,e,i,n,a){var o=this.el;if(t==null){o.innerHTML="";return}var s="";if(F(a)&&i.get("trigger")==="item"&&!zf(i)&&(s=gR(i,n,a)),F(t))o.innerHTML=t+s;else if(t){o.innerHTML="",N(t)||(t=[t]);for(var l=0;l=0?this._tryShow(a,o):n==="leave"&&this._hide(o))},this))},t.prototype._keepShow=function(){var e=this._tooltipModel,i=this._ecModel,n=this._api,a=e.get("triggerOn");if(this._lastX!=null&&this._lastY!=null&&a!=="none"&&a!=="click"){var o=this;clearTimeout(this._refreshUpdateTimeout),this._refreshUpdateTimeout=setTimeout(function(){!n.isDisposed()&&o.manuallyShowTip(e,i,n,{x:o._lastX,y:o._lastY,dataByCoordSys:o._lastDataByCoordSys})})}},t.prototype.manuallyShowTip=function(e,i,n,a){if(!(a.from===this.uid||Y.node||!n.getDom())){var o=a1(a,n);this._ticket="";var s=a.dataByCoordSys,l=MR(a,i,n);if(l){var u=l.el.getBoundingRect().clone();u.applyTransform(l.el.transform),this._tryShow({offsetX:u.x+u.width/2,offsetY:u.y+u.height/2,target:l.el,position:a.position,positionDefault:"bottom"},o)}else if(a.tooltip&&a.x!=null&&a.y!=null){var f=wR;f.x=a.x,f.y=a.y,f.update(),it(f).tooltipConfig={name:null,option:a.tooltip},this._tryShow({offsetX:a.x,offsetY:a.y,target:f},o)}else if(s)this._tryShow({offsetX:a.x,offsetY:a.y,position:a.position,dataByCoordSys:s,tooltipOption:a.tooltipOption},o);else if(a.seriesIndex!=null){if(this._manuallyAxisShowTip(e,i,n,a))return;var h=Fs(a,i),c=h.point[0],p=h.point[1];c!=null&&p!=null&&this._tryShow({offsetX:c,offsetY:p,target:h.el,position:a.position,positionDefault:"bottom"},o)}else a.x!=null&&a.y!=null&&(n.dispatchAction({type:"updateAxisPointer",x:a.x,y:a.y}),this._tryShow({offsetX:a.x,offsetY:a.y,position:a.position,target:n.getZr().findHover(a.x,a.y).target},o))}},t.prototype.manuallyHideTip=function(e,i,n,a){var o=this._tooltipContent;this._tooltipModel&&o.hideLater(this._tooltipModel.get("hideDelay")),this._lastX=this._lastY=this._lastDataByCoordSys=null,a.from!==this.uid&&this._hide(a1(a,n))},t.prototype._manuallyAxisShowTip=function(e,i,n,a){var o=a.seriesIndex,s=a.dataIndex,l=i.getComponent("axisPointer").coordSysAxesInfo;if(!(o==null||s==null||l==null)){var u=i.getSeriesByIndex(o);if(u){var f=u.getData(),h=Bs([f.getItemModel(s),u,(u.coordinateSystem||{}).model],this._tooltipModel);if(h.get("trigger")==="axis")return n.dispatchAction({type:"updateAxisPointer",seriesIndex:o,dataIndex:s,position:a.position}),!0}}},t.prototype._tryShow=function(e,i){var n=e.target,a=this._tooltipModel;if(a){this._lastX=e.offsetX,this._lastY=e.offsetY;var o=e.dataByCoordSys;if(o&&o.length)this._showAxisTooltip(o,e);else if(n){var s=it(n);if(s.ssrType==="legend")return;this._lastDataByCoordSys=null;var l,u;Un(n,function(f){if(it(f).dataIndex!=null)return l=f,!0;if(it(f).tooltipConfig!=null)return u=f,!0},!0),l?this._showSeriesItemTooltip(e,l,i):u?this._showComponentItemTooltip(e,u,i):this._hide(i)}else this._lastDataByCoordSys=null,this._hide(i)}},t.prototype._showOrMove=function(e,i){var n=e.get("showDelay");i=at(i,this),clearTimeout(this._showTimout),n>0?this._showTimout=setTimeout(i,n):i()},t.prototype._showAxisTooltip=function(e,i){var n=this._ecModel,a=this._tooltipModel,o=[i.offsetX,i.offsetY],s=Bs([i.tooltipOption],a),l=this._renderMode,u=[],f=Lr("section",{blocks:[],noHeader:!0}),h=[],c=new Lu;w(e,function(y){w(y.dataByAxis,function(_){var x=n.getComponent(_.axisDim+"Axis",_.axisIndex),b=_.value;if(!(!x||b==null)){var S=Ud(b,x.axis,n,_.seriesDataIndices,_.valueLabelOpt),T=Lr("section",{header:S,noHeader:!Gt(S),sortBlocks:!0,blocks:[]});f.blocks.push(T),w(_.seriesDataIndices,function(C){var A=n.getSeriesByIndex(C.seriesIndex),M=C.dataIndexInside,D=A.getDataParams(M);if(!(D.dataIndex<0)){D.axisDim=_.axisDim,D.axisIndex=_.axisIndex,D.axisType=_.axisType,D.axisId=_.axisId,D.axisValue=Ps(x.axis,{value:b}),D.axisValueLabel=S,D.marker=c.makeTooltipMarker("item",pr(D.color),l);var L=Ap(A.formatTooltip(M,!0,null)),R=L.frag;if(R){var E=Bs([A],a).get("valueFormatter");T.blocks.push(E?I({valueFormatter:E},R):R)}L.text&&h.push(L.text),u.push(D)}})}})}),f.blocks.reverse(),h.reverse();var p=i.position,v=s.get("order"),m=Rp(f,c,l,v,n.get("useUTC"),s.get("textStyle"));m&&h.unshift(m);var d=l==="richText"?` + +`:"
",g=h.join(d);this._showOrMove(s,function(){this._updateContentNotChangedOnAxis(e,u)?this._updatePosition(s,p,o[0],o[1],this._tooltipContent,u):this._showTooltipContent(s,g,u,Math.random()+"",o[0],o[1],p,null,c)})},t.prototype._showSeriesItemTooltip=function(e,i,n){var a=this._ecModel,o=it(i),s=o.seriesIndex,l=a.getSeriesByIndex(s),u=o.dataModel||l,f=o.dataIndex,h=o.dataType,c=u.getData(h),p=this._renderMode,v=e.positionDefault,m=Bs([c.getItemModel(f),u,l&&(l.coordinateSystem||{}).model],this._tooltipModel,v?{position:v}:null),d=m.get("trigger");if(!(d!=null&&d!=="item")){var g=u.getDataParams(f,h),y=new Lu;g.marker=y.makeTooltipMarker("item",pr(g.color),p);var _=Ap(u.formatTooltip(f,!1,h)),x=m.get("order"),b=m.get("valueFormatter"),S=_.frag,T=S?Rp(b?I({valueFormatter:b},S):S,y,p,x,a.get("useUTC"),m.get("textStyle")):_.text,C="item_"+u.name+"_"+f;this._showOrMove(m,function(){this._showTooltipContent(m,T,g,C,e.offsetX,e.offsetY,e.position,e.target,y)}),n({type:"showTip",dataIndexInside:f,dataIndex:c.getRawIndex(f),seriesIndex:s,from:this.uid})}},t.prototype._showComponentItemTooltip=function(e,i,n){var a=this._renderMode==="html",o=it(i),s=o.tooltipConfig,l=s.option||{},u=l.encodeHTMLContent;if(F(l)){var f=l;l={content:f,formatter:f},u=!0}u&&a&&l.content&&(l=j(l),l.content=Wt(l.content));var h=[l],c=this._ecModel.getComponent(o.componentMainType,o.componentIndex);c&&h.push(c),h.push({formatter:l.content});var p=e.positionDefault,v=Bs(h,this._tooltipModel,p?{position:p}:null),m=v.get("content"),d=Math.random()+"",g=new Lu;this._showOrMove(v,function(){var y=j(v.get("formatterParams")||{});this._showTooltipContent(v,m,y,d,e.offsetX,e.offsetY,e.position,i,g)}),n({type:"showTip",from:this.uid})},t.prototype._showTooltipContent=function(e,i,n,a,o,s,l,u,f){if(this._ticket="",!(!e.get("showContent")||!e.get("show"))){var h=this._tooltipContent;h.setEnterable(e.get("enterable"));var c=e.get("formatter");l=l||e.get("position");var p=i,v=this._getNearestPoint([o,s],n,e.get("trigger"),e.get("borderColor")),m=v.color;if(c)if(F(c)){var d=e.ecModel.get("useUTC"),g=N(n)?n[0]:n,y=g&&g.axisType&&g.axisType.indexOf("time")>=0;p=c,y&&(p=Zr(g.axisValue,p,d)),p=Ra(p,n,!0)}else if(G(c)){var _=at(function(x,b){x===this._ticket&&(h.setContent(b,f,e,m,l),this._updatePosition(e,l,o,s,h,n,u))},this);this._ticket=a,p=c(n,a,_)}else p=c;h.setContent(p,f,e,m,l),h.show(e,m),this._updatePosition(e,l,o,s,h,n,u)}},t.prototype._getNearestPoint=function(e,i,n,a){if(n==="axis"||N(i))return{color:a||(this._renderMode==="html"?"#fff":"none")};if(!N(i))return{color:a||i.color||i.borderColor}},t.prototype._updatePosition=function(e,i,n,a,o,s,l){var u=this._api.getWidth(),f=this._api.getHeight();i=i||e.get("position");var h=o.getSize(),c=e.get("align"),p=e.get("verticalAlign"),v=l&&l.getBoundingRect().clone();if(l&&v.applyTransform(l.transform),G(i)&&(i=i([n,a],s,o.el,v,{viewSize:[u,f],contentSize:h.slice()})),N(i))n=Tt(i[0],u),a=Tt(i[1],f);else if(H(i)){var m=i;m.width=h[0],m.height=h[1];var d=Kr(m,{width:u,height:f});n=d.x,a=d.y,c=null,p=null}else if(F(i)&&l){var g=AR(i,v,h,e.get("borderWidth"));n=g[0],a=g[1]}else{var g=CR(n,a,o,u,f,c?null:20,p?null:20);n=g[0],a=g[1]}if(c&&(n-=o1(c)?h[0]/2:c==="right"?h[0]:0),p&&(a-=o1(p)?h[1]/2:p==="bottom"?h[1]:0),zf(e)){var g=DR(n,a,o,u,f);n=g[0],a=g[1]}o.moveTo(n,a)},t.prototype._updateContentNotChangedOnAxis=function(e,i){var n=this._lastDataByCoordSys,a=this._cbParamsList,o=!!n&&n.length===e.length;return o&&w(n,function(s,l){var u=s.dataByAxis||[],f=e[l]||{},h=f.dataByAxis||[];o=o&&u.length===h.length,o&&w(u,function(c,p){var v=h[p]||{},m=c.seriesDataIndices||[],d=v.seriesDataIndices||[];o=o&&c.value===v.value&&c.axisType===v.axisType&&c.axisId===v.axisId&&m.length===d.length,o&&w(m,function(g,y){var _=d[y];o=o&&g.seriesIndex===_.seriesIndex&&g.dataIndex===_.dataIndex}),a&&w(c.seriesDataIndices,function(g){var y=g.seriesIndex,_=i[y],x=a[y];_&&x&&x.data!==_.data&&(o=!1)})})}),this._lastDataByCoordSys=e,this._cbParamsList=i,!!o},t.prototype._hide=function(e){this._lastDataByCoordSys=null,e({type:"hideTip",from:this.uid})},t.prototype.dispose=function(e,i){Y.node||!i.getDom()||(cs(this,"_updatePosition"),this._tooltipContent.dispose(),zs("itemTooltip",i))},t.type="tooltip",t}(Rt);function Bs(r,t,e){var i=t.ecModel,n;e?(n=new gt(e,i,i),n=new gt(t.option,n,i)):n=t;for(var a=r.length-1;a>=0;a--){var o=r[a];o&&(o instanceof gt&&(o=o.get("tooltip",!0)),F(o)&&(o={formatter:o}),o&&(n=new gt(o,n,i)))}return n}function a1(r,t){return r.dispatchAction||at(t.dispatchAction,t)}function CR(r,t,e,i,n,a,o){var s=e.getSize(),l=s[0],u=s[1];return a!=null&&(r+l+a+2>i?r-=l+a:r+=a),o!=null&&(t+u+o>n?t-=u+o:t+=o),[r,t]}function DR(r,t,e,i,n){var a=e.getSize(),o=a[0],s=a[1];return r=Math.min(r+o,i)-o,t=Math.min(t+s,n)-s,r=Math.max(r,0),t=Math.max(t,0),[r,t]}function AR(r,t,e,i){var n=e[0],a=e[1],o=Math.ceil(Math.SQRT2*i)+8,s=0,l=0,u=t.width,f=t.height;switch(r){case"inside":s=t.x+u/2-n/2,l=t.y+f/2-a/2;break;case"top":s=t.x+u/2-n/2,l=t.y-a-o;break;case"bottom":s=t.x+u/2-n/2,l=t.y+f+o;break;case"left":s=t.x-n-o,l=t.y+f/2-a/2;break;case"right":s=t.x+u+o,l=t.y+f/2-a/2}return[s,l]}function o1(r){return r==="center"||r==="middle"}function MR(r,t,e){var i=Mo(r).queryOptionMap,n=i.keys()[0];if(!(!n||n==="series")){var a=ui(t,n,i.get(n),{useDefault:!1,enableAll:!1,enableNone:!1}),o=a.models[0];if(o){var s=e.getViewOfComponentModel(o),l;if(s.group.traverse(function(u){var f=it(u).tooltipConfig;if(f&&f.name===r.name)return l=u,!0}),l)return{componentMainType:n,componentIndex:o.componentIndex,el:l}}}}var s1=TR;function qd(r){Ce(kf),r.registerComponentModel(Kw),r.registerComponentView(s1),r.registerAction({type:"showTip",event:"showTip",update:"tooltip:manuallyShowTip"},kt),r.registerAction({type:"hideTip",event:"hideTip",update:"tooltip:manuallyHideTip"},kt)}function Us(r,t){if(!r)return!1;for(var e=N(r)?r:[r],i=0;i=0&&(o[a]=+o[a].toFixed(c)),[o,h]}var Zd={min:st(Uf,"min"),max:st(Uf,"max"),average:st(Uf,"average"),median:st(Uf,"median")};function ja(r,t){if(t){var e=r.getData(),i=r.coordinateSystem,n=i&&i.dimensions;if(!ER(t)&&!N(t.coord)&&N(n)){var a=jd(t,e,i,r);if(t=j(t),t.type&&Zd[t.type]&&a.baseAxis&&a.valueAxis){var o=K(n,a.baseAxis.dim),s=K(n,a.valueAxis.dim),l=Zd[t.type](e,a.baseDataDim,a.valueDataDim,o,s);t.coord=l[0],t.value=l[1]}else t.coord=[t.xAxis!=null?t.xAxis:t.radiusAxis,t.yAxis!=null?t.yAxis:t.angleAxis]}if(t.coord==null||!N(n))t.coord=[];else for(var u=t.coord,f=0;f<2;f++)Zd[u[f]]&&(u[f]=Vf(e,e.mapDimension(n[f]),u[f]));return t}}function jd(r,t,e,i){var n={};return r.valueIndex!=null||r.valueDim!=null?(n.valueDataDim=r.valueIndex!=null?t.getDimension(r.valueIndex):r.valueDim,n.valueAxis=e.getAxis(LR(i,n.valueDataDim)),n.baseAxis=e.getOtherAxis(n.valueAxis),n.baseDataDim=t.mapDimension(n.baseAxis.dim)):(n.baseAxis=i.getBaseAxis(),n.valueAxis=e.getOtherAxis(n.baseAxis),n.baseDataDim=t.mapDimension(n.baseAxis.dim),n.valueDataDim=t.mapDimension(n.valueAxis.dim)),n}function LR(r,t){var e=r.getData().getDimensionInfo(t);return e&&e.coordDim}function Qa(r,t){return r&&r.containData&&t.coord&&!Kd(t)?r.containData(t.coord):!0}function u1(r,t,e){return r&&r.containZone&&t.coord&&e.coord&&!Kd(t)&&!Kd(e)?r.containZone(t.coord,e.coord):!0}function f1(r,t){return r?function(e,i,n,a){var o=a<2?e.coord&&e.coord[a]:e.value;return er(o,t[a])}:function(e,i,n,a){return er(e.value,t[a])}}function Vf(r,t,e){if(e==="average"){var i=0,n=0;return r.each(t,function(a,o){isNaN(a)||(i+=a,n++)}),i/n}else return e==="median"?r.getMedian(t):r.getDataExtent(t)[e==="max"?1:0]}var Qd=et(),PR=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e}return t.prototype.init=function(){this.markerGroupMap=W()},t.prototype.render=function(e,i,n){var a=this,o=this.markerGroupMap;o.each(function(s){Qd(s).keep=!1}),i.eachSeries(function(s){var l=gr.getMarkerModelFromSeries(s,a.type);l&&a.renderSeries(s,l,i,n)}),o.each(function(s){!Qd(s).keep&&a.group.remove(s.group)})},t.prototype.markKeep=function(e){Qd(e).keep=!0},t.prototype.toggleBlurSeries=function(e,i){var n=this;w(e,function(a){var o=gr.getMarkerModelFromSeries(a,n.type);if(o){var s=o.getData();s.eachItemGraphicEl(function(l){l&&(i?Fl(l):zo(l))})}})},t.type="marker",t}(Rt),Hf=PR;var OR=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e}return t.prototype.createMarkerModelFromSeries=function(e,i,n){return new t(e,i,n)},t.type="markLine",t.defaultOption={z:5,symbol:["circle","arrow"],symbolSize:[8,16],symbolOffset:0,precision:2,tooltip:{trigger:"item"},label:{show:!0,position:"end",distance:5},lineStyle:{type:"dashed"},emphasis:{label:{show:!0},lineStyle:{width:3}},animationEasing:"linear"},t}(gr),c1=OR;var Gf=et(),RR=function(r,t,e,i){var n=r.getData(),a;if(N(i))a=i;else{var o=i.type;if(o==="min"||o==="max"||o==="average"||o==="median"||i.xAxis!=null||i.yAxis!=null){var s=void 0,l=void 0;if(i.yAxis!=null||i.xAxis!=null)s=t.getAxis(i.yAxis!=null?"y":"x"),l=le(i.yAxis,i.xAxis);else{var u=jd(i,n,t,r);s=u.valueAxis;var f=Xa(n,u.valueDataDim);l=Vf(n,f,o)}var h=s.dim==="x"?0:1,c=1-h,p=j(i),v={coord:[]};p.type=null,p.coord=[],p.coord[c]=-1/0,v.coord[c]=1/0;var m=e.get("precision");m>=0&&ot(l)&&(l=+l.toFixed(Math.min(m,20))),p.coord[h]=v.coord[h]=l,a=[p,v,{type:o,valueIndex:i.valueIndex,value:l}]}else a=[]}var d=[ja(r,a[0]),ja(r,a[1]),I({},a[2])];return d[2].type=d[2].type||null,nt(d[2],d[0]),nt(d[2],d[1]),d};function Wf(r){return!isNaN(r)&&!isFinite(r)}function p1(r,t,e,i){var n=1-r,a=i.dimensions[r];return Wf(t[n])&&Wf(e[n])&&t[r]===e[r]&&i.getAxis(a).containData(t[r])}function IR(r,t){if(r.type==="cartesian2d"){var e=t[0].coord,i=t[1].coord;if(e&&i&&(p1(1,e,i,r)||p1(0,e,i,r)))return!0}return Qa(r,t[0])&&Qa(r,t[1])}function $d(r,t,e,i,n){var a=i.coordinateSystem,o=r.getItemModel(t),s,l=Tt(o.get("x"),n.getWidth()),u=Tt(o.get("y"),n.getHeight());if(!isNaN(l)&&!isNaN(u))s=[l,u];else{if(i.getMarkerPosition)s=i.getMarkerPosition(r.getValues(r.dimensions,t));else{var f=a.dimensions,h=r.get(f[0],t),c=r.get(f[1],t);s=a.dataToPoint([h,c])}if(Pr(a,"cartesian2d")){var p=a.getAxis("x"),v=a.getAxis("y"),f=a.dimensions;Wf(r.get(f[0],t))?s[0]=p.toGlobalCoord(p.getExtent()[e?0:1]):Wf(r.get(f[1],t))&&(s[1]=v.toGlobalCoord(v.getExtent()[e?0:1]))}isNaN(l)||(s[0]=l),isNaN(u)||(s[1]=u)}r.setItemLayout(t,s)}var NR=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e}return t.prototype.updateTransform=function(e,i,n){i.eachSeries(function(a){var o=gr.getMarkerModelFromSeries(a,"markLine");if(o){var s=o.getData(),l=Gf(o).from,u=Gf(o).to;l.each(function(f){$d(l,f,!0,a,n),$d(u,f,!1,a,n)}),s.each(function(f){s.setItemLayout(f,[l.getItemLayout(f),u.getItemLayout(f)])}),this.markerGroupMap.get(a.id).updateLayout()}},this)},t.prototype.renderSeries=function(e,i,n,a){var o=e.coordinateSystem,s=e.id,l=e.getData(),u=this.markerGroupMap,f=u.get(s)||u.set(s,new aw);this.group.add(f.group);var h=kR(o,e,i),c=h.from,p=h.to,v=h.line;Gf(i).from=c,Gf(i).to=p,i.setData(v);var m=i.get("symbol"),d=i.get("symbolSize"),g=i.get("symbolRotate"),y=i.get("symbolOffset");N(m)||(m=[m,m]),N(d)||(d=[d,d]),N(g)||(g=[g,g]),N(y)||(y=[y,y]),h.from.each(function(x){_(c,x,!0),_(p,x,!1)}),v.each(function(x){var b=v.getItemModel(x).getModel("lineStyle").getLineStyle();v.setItemLayout(x,[c.getItemLayout(x),p.getItemLayout(x)]),b.stroke==null&&(b.stroke=c.getItemVisual(x,"style").fill),v.setItemVisual(x,{fromSymbolKeepAspect:c.getItemVisual(x,"symbolKeepAspect"),fromSymbolOffset:c.getItemVisual(x,"symbolOffset"),fromSymbolRotate:c.getItemVisual(x,"symbolRotate"),fromSymbolSize:c.getItemVisual(x,"symbolSize"),fromSymbol:c.getItemVisual(x,"symbol"),toSymbolKeepAspect:p.getItemVisual(x,"symbolKeepAspect"),toSymbolOffset:p.getItemVisual(x,"symbolOffset"),toSymbolRotate:p.getItemVisual(x,"symbolRotate"),toSymbolSize:p.getItemVisual(x,"symbolSize"),toSymbol:p.getItemVisual(x,"symbol"),style:b})}),f.updateData(v),h.line.eachItemGraphicEl(function(x){it(x).dataModel=i,x.traverse(function(b){it(b).dataModel=i})});function _(x,b,S){var T=x.getItemModel(b);$d(x,b,S,e,a);var C=T.getModel("itemStyle").getItemStyle();C.fill==null&&(C.fill=Ua(l,"color")),x.setItemVisual(b,{symbolKeepAspect:T.get("symbolKeepAspect"),symbolOffset:Q(T.get("symbolOffset",!0),y[S?0:1]),symbolRotate:Q(T.get("symbolRotate",!0),g[S?0:1]),symbolSize:Q(T.get("symbolSize"),d[S?0:1]),symbol:Q(T.get("symbol",!0),m[S?0:1]),style:C})}this.markKeep(f),f.group.silent=i.get("silent")||e.get("silent")},t.type="markLine",t}(Hf);function kR(r,t,e){var i;r?i=z(r&&r.dimensions,function(u){var f=t.getData().getDimensionInfo(t.getData().mapDimension(u))||{};return I(I({},f),{name:u,ordinalMeta:null})}):i=[{name:"value",type:"float"}];var n=new dr(i,e),a=new dr(i,e),o=new dr([],e),s=z(e.get("data"),st(RR,t,r,e));r&&(s=dt(s,st(IR,r)));var l=f1(!!r,i);return n.initData(z(s,function(u){return u[0]}),null,l),a.initData(z(s,function(u){return u[1]}),null,l),o.initData(z(s,function(u){return u[2]})),o.hasItemOption=!0,{from:n,to:a,line:o}}var v1=NR;function Jd(r){r.registerComponentModel(c1),r.registerComponentView(v1),r.registerPreprocessor(function(t){Us(t.series,"markLine")&&(t.markLine=t.markLine||{})})}var zR=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e}return t.prototype.createMarkerModelFromSeries=function(e,i,n){return new t(e,i,n)},t.type="markArea",t.defaultOption={z:1,tooltip:{trigger:"item"},animation:!1,label:{show:!0,position:"top"},itemStyle:{borderWidth:0},emphasis:{label:{show:!0,position:"top"}}},t}(gr),d1=zR;var Yf=et(),FR=function(r,t,e,i){var n=i[0],a=i[1];if(!(!n||!a)){var o=ja(r,n),s=ja(r,a),l=o.coord,u=s.coord;l[0]=le(l[0],-1/0),l[1]=le(l[1],-1/0),u[0]=le(u[0],1/0),u[1]=le(u[1],1/0);var f=eh([{},o,s]);return f.coord=[o.coord,s.coord],f.x0=o.x,f.y0=o.y,f.x1=s.x,f.y1=s.y,f}};function Xf(r){return!isNaN(r)&&!isFinite(r)}function m1(r,t,e,i){var n=1-r;return Xf(t[n])&&Xf(e[n])}function BR(r,t){var e=t.coord[0],i=t.coord[1],n={coord:e,x:t.x0,y:t.y0},a={coord:i,x:t.x1,y:t.y1};return Pr(r,"cartesian2d")?e&&i&&(m1(1,e,i,r)||m1(0,e,i,r))?!0:u1(r,n,a):Qa(r,n)||Qa(r,a)}function g1(r,t,e,i,n){var a=i.coordinateSystem,o=r.getItemModel(t),s,l=Tt(o.get(e[0]),n.getWidth()),u=Tt(o.get(e[1]),n.getHeight());if(!isNaN(l)&&!isNaN(u))s=[l,u];else{if(i.getMarkerPosition){var f=r.getValues(["x0","y0"],t),h=r.getValues(["x1","y1"],t),c=a.clampData(f),p=a.clampData(h),v=[];e[0]==="x0"?v[0]=c[0]>p[0]?h[0]:f[0]:v[0]=c[0]>p[0]?f[0]:h[0],e[1]==="y0"?v[1]=c[1]>p[1]?h[1]:f[1]:v[1]=c[1]>p[1]?f[1]:h[1],s=i.getMarkerPosition(v,e,!0)}else{var m=r.get(e[0],t),d=r.get(e[1],t),g=[m,d];a.clampData&&a.clampData(g,g),s=a.dataToPoint(g,!0)}if(Pr(a,"cartesian2d")){var y=a.getAxis("x"),_=a.getAxis("y"),m=r.get(e[0],t),d=r.get(e[1],t);Xf(m)?s[0]=y.toGlobalCoord(y.getExtent()[e[0]==="x0"?0:1]):Xf(d)&&(s[1]=_.toGlobalCoord(_.getExtent()[e[1]==="y0"?0:1]))}isNaN(l)||(s[0]=l),isNaN(u)||(s[1]=u)}return s}var y1=[["x0","y0"],["x1","y0"],["x1","y1"],["x0","y1"]],UR=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e}return t.prototype.updateTransform=function(e,i,n){i.eachSeries(function(a){var o=gr.getMarkerModelFromSeries(a,"markArea");if(o){var s=o.getData();s.each(function(l){var u=z(y1,function(h){return g1(s,l,h,a,n)});s.setItemLayout(l,u);var f=s.getItemGraphicEl(l);f.setShape("points",u)})}},this)},t.prototype.renderSeries=function(e,i,n,a){var o=e.coordinateSystem,s=e.id,l=e.getData(),u=this.markerGroupMap,f=u.get(s)||u.set(s,{group:new lt});this.group.add(f.group),this.markKeep(f);var h=VR(o,e,i);i.setData(h),h.each(function(c){var p=z(y1,function(C){return g1(h,c,C,e,a)}),v=o.getAxis("x").scale,m=o.getAxis("y").scale,d=v.getExtent(),g=m.getExtent(),y=[v.parse(h.get("x0",c)),v.parse(h.get("x1",c))],_=[m.parse(h.get("y0",c)),m.parse(h.get("y1",c))];wo(y),wo(_);var x=!(d[0]>y[1]||d[1]_[1]||g[1]<_[0]),b=!x;h.setItemLayout(c,{points:p,allClipped:b});var S=h.getItemModel(c).getModel("itemStyle").getItemStyle(),T=Ua(l,"color");S.fill||(S.fill=T,F(S.fill)&&(S.fill=cl(S.fill,.4))),S.stroke||(S.stroke=T),h.setItemVisual(c,"style",S)}),h.diff(Yf(f).data).add(function(c){var p=h.getItemLayout(c);if(!p.allClipped){var v=new mi({shape:{points:p.points}});h.setItemGraphicEl(c,v),f.group.add(v)}}).update(function(c,p){var v=Yf(f).data.getItemGraphicEl(p),m=h.getItemLayout(c);m.allClipped?v&&f.group.remove(v):(v?wt(v,{shape:{points:m.points}},i,c):v=new mi({shape:{points:m.points}}),h.setItemGraphicEl(c,v),f.group.add(v))}).remove(function(c){var p=Yf(f).data.getItemGraphicEl(c);f.group.remove(p)}).execute(),h.eachItemGraphicEl(function(c,p){var v=h.getItemModel(p),m=h.getItemVisual(p,"style");c.useStyle(h.getItemVisual(p,"style")),Qe(c,xe(v),{labelFetcher:i,labelDataIndex:p,defaultText:h.getName(p)||"",inheritColor:F(m.fill)?cl(m.fill,1):"#000"}),Sn(c,v),Oe(c,null,null,v.get(["emphasis","disabled"])),it(c).dataModel=i}),Yf(f).data=h,f.group.silent=i.get("silent")||e.get("silent")},t.type="markArea",t}(Hf);function VR(r,t,e){var i,n,a=["x0","y0","x1","y1"];if(r){var o=z(r&&r.dimensions,function(u){var f=t.getData(),h=f.getDimensionInfo(f.mapDimension(u))||{};return I(I({},h),{name:u,ordinalMeta:null})});n=z(a,function(u,f){return{name:u,type:o[f%2].type}}),i=new dr(n,e)}else n=[{name:"value",type:"float"}],i=new dr(n,e);var s=z(e.get("data"),st(FR,t,r,e));r&&(s=dt(s,st(BR,r)));var l=r?function(u,f,h,c){var p=u.coord[Math.floor(c/2)][c%2];return er(p,n[c])}:function(u,f,h,c){return er(u.value,n[c])};return i.initData(s,null,l),i.hasItemOption=!0,i}var _1=UR;function tm(r){r.registerComponentModel(d1),r.registerComponentView(_1),r.registerPreprocessor(function(t){Us(t.series,"markArea")&&(t.markArea=t.markArea||{})})}var HR=function(r,t){if(t==="all")return{type:"all",title:r.getLocaleModel().get(["legend","selector","all"])};if(t==="inverse")return{type:"inverse",title:r.getLocaleModel().get(["legend","selector","inverse"])}},GR=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e.layoutMode={type:"box",ignoreSize:!0},e}return t.prototype.init=function(e,i,n){this.mergeDefaultAndTheme(e,n),e.selected=e.selected||{},this._updateSelector(e)},t.prototype.mergeOption=function(e,i){r.prototype.mergeOption.call(this,e,i),this._updateSelector(e)},t.prototype._updateSelector=function(e){var i=e.selector,n=this.ecModel;i===!0&&(i=e.selector=["all","inverse"]),N(i)&&w(i,function(a,o){F(a)&&(a={type:a}),i[o]=nt(a,HR(n,a.type))})},t.prototype.optionUpdated=function(){this._updateData(this.ecModel);var e=this._data;if(e[0]&&this.get("selectedMode")==="single"){for(var i=!1,n=0;n=0},t.prototype.getOrient=function(){return this.get("orient")==="vertical"?{index:1,name:"vertical"}:{index:0,name:"horizontal"}},t.type="legend.plain",t.dependencies=["series"],t.defaultOption={z:4,show:!0,orient:"horizontal",left:"center",top:0,align:"auto",backgroundColor:"rgba(0,0,0,0)",borderColor:"#ccc",borderRadius:0,borderWidth:0,padding:5,itemGap:10,itemWidth:25,itemHeight:14,symbolRotate:"inherit",symbolKeepAspect:!0,inactiveColor:"#ccc",inactiveBorderColor:"#ccc",inactiveBorderWidth:"auto",itemStyle:{color:"inherit",opacity:"inherit",borderColor:"inherit",borderWidth:"auto",borderCap:"inherit",borderJoin:"inherit",borderDashOffset:"inherit",borderMiterLimit:"inherit"},lineStyle:{width:"auto",color:"inherit",inactiveColor:"#ccc",inactiveWidth:2,opacity:"inherit",type:"inherit",cap:"inherit",join:"inherit",dashOffset:"inherit",miterLimit:"inherit"},textStyle:{color:"#333"},selectedMode:!0,selector:!1,selectorLabel:{show:!0,borderRadius:10,padding:[3,5,3,5],fontSize:12,fontFamily:"sans-serif",color:"#666",borderWidth:1,borderColor:"#666"},emphasis:{selectorLabel:{show:!0,color:"#eee",backgroundColor:"#666"}},selectorPosition:"auto",selectorItemGap:7,selectorButtonGap:10,tooltip:{show:!1}},t}(ht),Vs=GR;var $a=st,em=w,qf=lt,WR=function(r){O(t,r);function t(){var e=r!==null&&r.apply(this,arguments)||this;return e.type=t.type,e.newlineDisabled=!1,e}return t.prototype.init=function(){this.group.add(this._contentGroup=new qf),this.group.add(this._selectorGroup=new qf),this._isFirstRender=!0},t.prototype.getContentGroup=function(){return this._contentGroup},t.prototype.getSelectorGroup=function(){return this._selectorGroup},t.prototype.render=function(e,i,n){var a=this._isFirstRender;if(this._isFirstRender=!1,this.resetInner(),!!e.get("show",!0)){var o=e.get("align"),s=e.get("orient");(!o||o==="auto")&&(o=e.get("left")==="right"&&s==="vertical"?"right":"left");var l=e.get("selector",!0),u=e.get("selectorPosition",!0);l&&(!u||u==="auto")&&(u=s==="horizontal"?"end":"start"),this.renderInner(o,e,i,n,l,s,u);var f=e.getBoxLayoutParams(),h={width:n.getWidth(),height:n.getHeight()},c=e.get("padding"),p=Kr(f,h,c),v=this.layoutInner(e,o,p,a,l,u),m=Kr(X({width:v.width,height:v.height},f),h,c);this.group.x=m.x-v.x,this.group.y=m.y-v.y,this.group.markRedraw(),this.group.add(this._backgroundEl=Zw(v,e))}},t.prototype.resetInner=function(){this.getContentGroup().removeAll(),this._backgroundEl&&this.group.remove(this._backgroundEl),this.getSelectorGroup().removeAll()},t.prototype.renderInner=function(e,i,n,a,o,s,l){var u=this.getContentGroup(),f=W(),h=i.get("selectedMode"),c=[];n.eachRawSeries(function(p){!p.get("legendHoverLink")&&c.push(p.id)}),em(i.getData(),function(p,v){var m=p.get("name");if(!this.newlineDisabled&&(m===""||m===` +`)){var d=new qf;d.newline=!0,u.add(d);return}var g=n.getSeriesByName(m)[0];if(!f.get(m))if(g){var y=g.getData(),_=y.getVisual("legendLineStyle")||{},x=y.getVisual("legendIcon"),b=y.getVisual("style"),S=this._createItem(g,m,v,p,i,e,_,b,x,h,a);S.on("click",$a(x1,m,null,a,c)).on("mouseover",$a(rm,g.name,null,a,c)).on("mouseout",$a(im,g.name,null,a,c)),n.ssr&&S.eachChild(function(T){var C=it(T);C.seriesIndex=g.seriesIndex,C.dataIndex=v,C.ssrType="legend"}),f.set(m,!0)}else n.eachRawSeries(function(T){if(!f.get(m)&&T.legendVisualProvider){var C=T.legendVisualProvider;if(!C.containName(m))return;var A=C.indexOfName(m),M=C.getItemVisual(A,"style"),D=C.getItemVisual(A,"legendIcon"),L=Jt(M.fill);L&&L[3]===0&&(L[3]=.2,M=I(I({},M),{fill:xr(L,"rgba")}));var R=this._createItem(T,m,v,p,i,e,{},M,D,h,a);R.on("click",$a(x1,null,m,a,c)).on("mouseover",$a(rm,null,m,a,c)).on("mouseout",$a(im,null,m,a,c)),n.ssr&&R.eachChild(function(E){var P=it(E);P.seriesIndex=T.seriesIndex,P.dataIndex=v,P.ssrType="legend"}),f.set(m,!0)}},this)},this),o&&this._createSelector(o,i,a,s,l)},t.prototype._createSelector=function(e,i,n,a,o){var s=this.getSelectorGroup();em(e,function(u){var f=u.type,h=new St({style:{x:0,y:0,align:"center",verticalAlign:"middle"},onclick:function(){n.dispatchAction({type:f==="all"?"legendAllSelect":"legendInverseSelect"})}});s.add(h);var c=i.getModel("selectorLabel"),p=i.getModel(["emphasis","selectorLabel"]);Qe(h,{normal:c,emphasis:p},{defaultText:u.title}),ba(h)})},t.prototype._createItem=function(e,i,n,a,o,s,l,u,f,h,c){var p=e.visualDrawType,v=o.get("itemWidth"),m=o.get("itemHeight"),d=o.isSelected(i),g=a.get("symbolRotate"),y=a.get("symbolKeepAspect"),_=a.get("icon");f=_||f||"roundRect";var x=YR(f,a,l,u,p,d,c),b=new qf,S=a.getModel("textStyle");if(G(e.getLegendIcon)&&(!_||_==="inherit"))b.add(e.getLegendIcon({itemWidth:v,itemHeight:m,icon:f,iconRotate:g,itemStyle:x.itemStyle,lineStyle:x.lineStyle,symbolKeepAspect:y}));else{var T=_==="inherit"&&e.getData().getVisual("symbol")?g==="inherit"?e.getData().getVisual("symbolRotate"):g:0;b.add(XR({itemWidth:v,itemHeight:m,icon:f,iconRotate:T,itemStyle:x.itemStyle,lineStyle:x.lineStyle,symbolKeepAspect:y}))}var C=s==="left"?v+5:-5,A=s,M=o.get("formatter"),D=i;F(M)&&M?D=M.replace("{name}",i??""):G(M)&&(D=M(i));var L=d?S.getTextColor():a.get("inactiveColor");b.add(new St({style:_e(S,{text:D,x:C,y:m/2,fill:L,align:A,verticalAlign:"middle"},{inheritColor:L})}));var R=new vt({shape:b.getBoundingRect(),style:{fill:"transparent"}}),E=a.getModel("tooltip");return E.get("show")&&Ko({el:R,componentModel:o,itemName:i,itemTooltipOption:E.option}),b.add(R),b.eachChild(function(P){P.silent=!0}),R.silent=!h,this.getContentGroup().add(b),ba(b),b.__legendDataIndex=n,b},t.prototype.layoutInner=function(e,i,n,a,o,s){var l=this.getContentGroup(),u=this.getSelectorGroup();In(e.get("orient"),l,e.get("itemGap"),n.width,n.height);var f=l.getBoundingRect(),h=[-f.x,-f.y];if(u.markRedraw(),l.markRedraw(),o){In("horizontal",u,e.get("selectorItemGap",!0));var c=u.getBoundingRect(),p=[-c.x,-c.y],v=e.get("selectorButtonGap",!0),m=e.getOrient().index,d=m===0?"width":"height",g=m===0?"height":"width",y=m===0?"y":"x";s==="end"?p[m]+=f[d]+v:h[m]+=c[d]+v,p[1-m]+=f[g]/2-c[g]/2,u.x=p[0],u.y=p[1],l.x=h[0],l.y=h[1];var _={x:0,y:0};return _[d]=f[d]+v+c[d],_[g]=Math.max(f[g],c[g]),_[y]=Math.min(0,c[y]+p[1-m]),_}else return l.x=h[0],l.y=h[1],this.group.getBoundingRect()},t.prototype.remove=function(){this.getContentGroup().removeAll(),this._isFirstRender=!0},t.type="legend.plain",t}(Rt);function YR(r,t,e,i,n,a,o){function s(d,g){d.lineWidth==="auto"&&(d.lineWidth=g.lineWidth>0?2:0),em(d,function(y,_){d[_]==="inherit"&&(d[_]=g[_])})}var l=t.getModel("itemStyle"),u=l.getItemStyle(),f=r.lastIndexOf("empty",0)===0?"fill":"stroke",h=l.getShallow("decal");u.decal=!h||h==="inherit"?i.decal:Gn(h,o),u.fill==="inherit"&&(u.fill=i[n]),u.stroke==="inherit"&&(u.stroke=i[f]),u.opacity==="inherit"&&(u.opacity=(n==="fill"?i:e).opacity),s(u,i);var c=t.getModel("lineStyle"),p=c.getLineStyle();if(s(p,e),u.fill==="auto"&&(u.fill=i.fill),u.stroke==="auto"&&(u.stroke=i.fill),p.stroke==="auto"&&(p.stroke=i.fill),!a){var v=t.get("inactiveBorderWidth"),m=u[f];u.lineWidth=v==="auto"?i.lineWidth>0&&m?2:0:u.lineWidth,u.fill=t.get("inactiveColor"),u.stroke=t.get("inactiveBorderColor"),p.stroke=c.get("inactiveColor"),p.lineWidth=c.get("inactiveWidth")}return{itemStyle:u,lineStyle:p}}function XR(r){var t=r.icon||"roundRect",e=$t(t,0,0,r.itemWidth,r.itemHeight,r.itemStyle.fill,r.symbolKeepAspect);return e.setStyle(r.itemStyle),e.rotation=(r.iconRotate||0)*Math.PI/180,e.setOrigin([r.itemWidth/2,r.itemHeight/2]),t.indexOf("empty")>-1&&(e.style.stroke=e.style.fill,e.style.fill="#fff",e.style.lineWidth=2),e}function x1(r,t,e,i){im(r,t,e,i),e.dispatchAction({type:"legendToggleSelect",name:r??t}),rm(r,t,e,i)}function S1(r){for(var t=r.getZr().storage.getDisplayList(),e,i=0,n=t.length;in[o],d=[-p.x,-p.y];i||(d[a]=f[u]);var g=[0,0],y=[-v.x,-v.y],_=Q(e.get("pageButtonGap",!0),e.get("itemGap",!0));if(m){var x=e.get("pageButtonPosition",!0);x==="end"?y[a]+=n[o]-v[o]:g[a]+=v[o]+_}y[1-a]+=p[s]/2-v[s]/2,f.setPosition(d),h.setPosition(g),c.setPosition(y);var b={x:0,y:0};if(b[o]=m?n[o]:p[o],b[s]=Math.max(p[s],v[s]),b[l]=Math.min(0,v[l]+y[1-a]),h.__rectSize=n[o],m){var S={x:0,y:0};S[o]=Math.max(n[o]-v[o]-_,0),S[s]=b[s],h.setClipPath(new vt({shape:S})),h.__rectSize=S[o]}else c.eachChild(function(C){C.attr({invisible:!0,silent:!0})});var T=this._getPageInfo(e);return T.pageIndex!=null&&wt(f,{x:T.contentPosition[0],y:T.contentPosition[1]},m?e:null),this._updatePageInfoView(e,T),b},t.prototype._pageGo=function(e,i,n){var a=this._getPageInfo(i)[e];a!=null&&n.dispatchAction({type:"legendScroll",scrollDataIndex:a,legendId:i.id})},t.prototype._updatePageInfoView=function(e,i){var n=this._controllerGroup;w(["pagePrev","pageNext"],function(f){var h=f+"DataIndex",c=i[h]!=null,p=n.childOfName(f);p&&(p.setStyle("fill",c?e.get("pageIconColor",!0):e.get("pageIconInactiveColor",!0)),p.cursor=c?"pointer":"default")});var a=n.childOfName("pageText"),o=e.get("pageFormatter"),s=i.pageIndex,l=s!=null?s+1:0,u=i.pageCount;a&&o&&a.setStyle("text",F(o)?o.replace("{current}",l==null?"":l+"").replace("{total}",u==null?"":u+""):o({current:l,total:u}))},t.prototype._getPageInfo=function(e){var i=e.get("scrollDataIndex",!0),n=this.getContentGroup(),a=this._containerGroup.__rectSize,o=e.getOrient().index,s=am[o],l=om[o],u=this._findTargetItemIndex(i),f=n.children(),h=f[u],c=f.length,p=c?1:0,v={contentPosition:[n.x,n.y],pageCount:p,pageIndex:p-1,pagePrevDataIndex:null,pageNextDataIndex:null};if(!h)return v;var m=x(h);v.contentPosition[o]=-m.s;for(var d=u+1,g=m,y=m,_=null;d<=c;++d)_=x(f[d]),(!_&&y.e>g.s+a||_&&!b(_,g.s))&&(y.i>g.i?g=y:g=_,g&&(v.pageNextDataIndex==null&&(v.pageNextDataIndex=g.i),++v.pageCount)),y=_;for(var d=u-1,g=m,y=m,_=null;d>=-1;--d)_=x(f[d]),(!_||!b(y,_.s))&&g.i=T&&S.s<=T+a}},t.prototype._findTargetItemIndex=function(e){if(!this._showController)return 0;var i,n=this.getContentGroup(),a;return n.eachChild(function(o,s){var l=o.__legendDataIndex;a==null&&l!=null&&(a=s),l===e&&(i=s)}),i??a},t.type="legend.scroll",t}(Zf),A1=ZR;function sm(r){r.registerAction("legendScroll","legendscroll",function(t,e){var i=t.scrollDataIndex;i!=null&&e.eachComponent({mainType:"legend",subType:"scroll",query:t},function(n){n.setScrollDataIndex(i)})})}function lm(r){Ce(w1),r.registerComponentModel(C1),r.registerComponentView(A1),sm(r)}function M1(r,t,e){var i=se.createCanvas(),n=t.getWidth(),a=t.getHeight(),o=i.style;return o&&(o.position="absolute",o.left="0",o.top="0",o.width=n+"px",o.height=a+"px",i.setAttribute("data-zr-dom-id",r)),i.width=n*e,i.height=a*e,i}var KR=function(r){O(t,r);function t(e,i,n){var a=r.call(this)||this;a.motionBlur=!1,a.lastFrameAlpha=.7,a.dpr=1,a.virtual=!1,a.config={},a.incremental=!1,a.zlevel=0,a.maxRepaintRectCount=5,a.__dirty=!0,a.__firstTimePaint=!0,a.__used=!1,a.__drawIndex=0,a.__startIndex=0,a.__endIndex=0,a.__prevStartIndex=null,a.__prevEndIndex=null;var o;n=n||rn,typeof e=="string"?o=M1(e,i,n):H(e)&&(o=e,e=o.id),a.id=e,a.dom=o;var s=o.style;return s&&(io(o),o.onselectstart=function(){return!1},s.padding="0",s.margin="0",s.borderWidth="0"),a.painter=i,a.dpr=n,a}return t.prototype.getElementCount=function(){return this.__endIndex-this.__startIndex},t.prototype.afterBrush=function(){this.__prevStartIndex=this.__startIndex,this.__prevEndIndex=this.__endIndex},t.prototype.initContext=function(){this.ctx=this.dom.getContext("2d"),this.ctx.dpr=this.dpr},t.prototype.setUnpainted=function(){this.__firstTimePaint=!0},t.prototype.createBackBuffer=function(){var e=this.dpr;this.domBack=M1("back-"+this.id,this.painter,e),this.ctxBack=this.domBack.getContext("2d"),e!==1&&this.ctxBack.scale(e,e)},t.prototype.createRepaintRects=function(e,i,n,a){if(this.__firstTimePaint)return this.__firstTimePaint=!1,null;var o=[],s=this.maxRepaintRectCount,l=!1,u=new J(0,0,0,0);function f(y){if(!(!y.isFinite()||y.isZero()))if(o.length===0){var _=new J(0,0,0,0);_.copy(y),o.push(_)}else{for(var x=!1,b=1/0,S=0,T=0;T=s)}}for(var h=this.__startIndex;h15)break}}E.prevElClipPaths&&g.restore()};if(y)if(y.length===0)C=d.__endIndex;else for(var M=p.dpr,D=0;D0&&t>n[0]){for(l=0;lt);l++);s=i[n[l]]}if(n.splice(l+1,0,t),i[t]=e,!e.virtual)if(s){var u=s.dom;u.nextSibling?o.insertBefore(e.dom,u.nextSibling):o.appendChild(e.dom)}else o.firstChild?o.insertBefore(e.dom,o.firstChild):o.appendChild(e.dom);e.painter||(e.painter=this)}},r.prototype.eachLayer=function(t,e){for(var i=this._zlevelList,n=0;n0?jf:0),this._needsManuallyCompositing),f.__builtin__||Ui("ZLevel "+u+" has been used by unkown layer "+f.id),f!==a&&(f.__used=!0,f.__startIndex!==l&&(f.__dirty=!0),f.__startIndex=l,f.incremental?f.__drawIndex=-1:f.__drawIndex=l,e(l),a=f),n.__dirty&zt&&!n.__inHover&&(f.__dirty=!0,f.incremental&&f.__drawIndex<0&&(f.__drawIndex=l))}e(l),this.eachBuiltinLayer(function(h,c){!h.__used&&h.getElementCount()>0&&(h.__dirty=!0,h.__startIndex=h.__endIndex=h.__drawIndex=0),h.__dirty&&h.__drawIndex<0&&(h.__drawIndex=h.__startIndex)})},r.prototype.clear=function(){return this.eachBuiltinLayer(this._clearLayer),this},r.prototype._clearLayer=function(t){t.clear()},r.prototype.setBackgroundColor=function(t){this._backgroundColor=t,w(this._layers,function(e){e.setUnpainted()})},r.prototype.configLayer=function(t,e){if(e){var i=this._layerConfig;i[t]?nt(i[t],e,!0):i[t]=e;for(var n=0;n svg, +.leaflet-pane > canvas, +.leaflet-zoom-box, +.leaflet-image-layer, +.leaflet-layer { + position: absolute; + left: 0; + top: 0; + } +.leaflet-container { + overflow: hidden; + } +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + -webkit-user-drag: none; + } +/* Prevents IE11 from highlighting tiles in blue */ +.leaflet-tile::selection { + background: transparent; +} +/* Safari renders non-retina tile on retina better with this, but Chrome is worse */ +.leaflet-safari .leaflet-tile { + image-rendering: -webkit-optimize-contrast; + } +/* hack that prevents hw layers "stretching" when loading new tiles */ +.leaflet-safari .leaflet-tile-container { + width: 1600px; + height: 1600px; + -webkit-transform-origin: 0 0; + } +.leaflet-marker-icon, +.leaflet-marker-shadow { + display: block; + } +/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ +/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */ +.leaflet-container .leaflet-overlay-pane svg { + max-width: none !important; + max-height: none !important; + } +.leaflet-container .leaflet-marker-pane img, +.leaflet-container .leaflet-shadow-pane img, +.leaflet-container .leaflet-tile-pane img, +.leaflet-container img.leaflet-image-layer, +.leaflet-container .leaflet-tile { + max-width: none !important; + max-height: none !important; + width: auto; + padding: 0; + } + +.leaflet-container img.leaflet-tile { + /* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */ + mix-blend-mode: plus-lighter; +} + +.leaflet-container.leaflet-touch-zoom { + -ms-touch-action: pan-x pan-y; + touch-action: pan-x pan-y; + } +.leaflet-container.leaflet-touch-drag { + -ms-touch-action: pinch-zoom; + /* Fallback for FF which doesn't support pinch-zoom */ + touch-action: none; + touch-action: pinch-zoom; +} +.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom { + -ms-touch-action: none; + touch-action: none; +} +.leaflet-container { + -webkit-tap-highlight-color: transparent; +} +.leaflet-container a { + -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4); +} +.leaflet-tile { + filter: inherit; + visibility: hidden; + } +.leaflet-tile-loaded { + visibility: inherit; + } +.leaflet-zoom-box { + width: 0; + height: 0; + -moz-box-sizing: border-box; + box-sizing: border-box; + z-index: 800; + } +/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ +.leaflet-overlay-pane svg { + -moz-user-select: none; + } + +.leaflet-pane { z-index: 400; } + +.leaflet-tile-pane { z-index: 200; } +.leaflet-overlay-pane { z-index: 400; } +.leaflet-shadow-pane { z-index: 500; } +.leaflet-marker-pane { z-index: 600; } +.leaflet-tooltip-pane { z-index: 650; } +.leaflet-popup-pane { z-index: 700; } + +.leaflet-map-pane canvas { z-index: 100; } +.leaflet-map-pane svg { z-index: 200; } + +.leaflet-vml-shape { + width: 1px; + height: 1px; + } +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute; + } + + +/* control positioning */ + +.leaflet-control { + position: relative; + z-index: 800; + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } +.leaflet-top, +.leaflet-bottom { + position: absolute; + z-index: 1000; + pointer-events: none; + } +.leaflet-top { + top: 0; + } +.leaflet-right { + right: 0; + } +.leaflet-bottom { + bottom: 0; + } +.leaflet-left { + left: 0; + } +.leaflet-control { + float: left; + clear: both; + } +.leaflet-right .leaflet-control { + float: right; + } +.leaflet-top .leaflet-control { + margin-top: 10px; + } +.leaflet-bottom .leaflet-control { + margin-bottom: 10px; + } +.leaflet-left .leaflet-control { + margin-left: 10px; + } +.leaflet-right .leaflet-control { + margin-right: 10px; + } + + +/* zoom and fade animations */ + +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1; + } +.leaflet-zoom-animated { + -webkit-transform-origin: 0 0; + -ms-transform-origin: 0 0; + transform-origin: 0 0; + } +svg.leaflet-zoom-animated { + will-change: transform; +} + +.leaflet-zoom-anim .leaflet-zoom-animated { + -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); + -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); + transition: transform 0.25s cubic-bezier(0,0,0.25,1); + } +.leaflet-zoom-anim .leaflet-tile, +.leaflet-pan-anim .leaflet-tile { + -webkit-transition: none; + -moz-transition: none; + transition: none; + } + +.leaflet-zoom-anim .leaflet-zoom-hide { + visibility: hidden; + } + + +/* cursors */ + +.leaflet-interactive { + cursor: pointer; + } +.leaflet-grab { + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; + } +.leaflet-crosshair, +.leaflet-crosshair .leaflet-interactive { + cursor: crosshair; + } +.leaflet-popup-pane, +.leaflet-control { + cursor: auto; + } +.leaflet-dragging .leaflet-grab, +.leaflet-dragging .leaflet-grab .leaflet-interactive, +.leaflet-dragging .leaflet-marker-draggable { + cursor: move; + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: grabbing; + } + +/* marker & overlays interactivity */ +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-image-layer, +.leaflet-pane > svg path, +.leaflet-tile-container { + pointer-events: none; + } + +.leaflet-marker-icon.leaflet-interactive, +.leaflet-image-layer.leaflet-interactive, +.leaflet-pane > svg path.leaflet-interactive, +svg.leaflet-image-layer.leaflet-interactive path { + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } + +/* visual tweaks */ + +.leaflet-container { + background: #ddd; + outline-offset: 1px; + } +.leaflet-container a { + color: #0078A8; + } +.leaflet-zoom-box { + border: 2px dotted #38f; + background: rgba(255,255,255,0.5); + } + + +/* general typography */ +.leaflet-container { + font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; + font-size: 12px; + font-size: 0.75rem; + line-height: 1.5; + } + + +/* general toolbar styles */ + +.leaflet-bar { + box-shadow: 0 1px 5px rgba(0,0,0,0.65); + border-radius: 4px; + } +.leaflet-bar a { + background-color: #fff; + border-bottom: 1px solid #ccc; + width: 26px; + height: 26px; + line-height: 26px; + display: block; + text-align: center; + text-decoration: none; + color: black; + } +.leaflet-bar a, +.leaflet-control-layers-toggle { + background-position: 50% 50%; + background-repeat: no-repeat; + display: block; + } +.leaflet-bar a:hover, +.leaflet-bar a:focus { + background-color: #f4f4f4; + } +.leaflet-bar a:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + } +.leaflet-bar a:last-child { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom: none; + } +.leaflet-bar a.leaflet-disabled { + cursor: default; + background-color: #f4f4f4; + color: #bbb; + } + +.leaflet-touch .leaflet-bar a { + width: 30px; + height: 30px; + line-height: 30px; + } +.leaflet-touch .leaflet-bar a:first-child { + border-top-left-radius: 2px; + border-top-right-radius: 2px; + } +.leaflet-touch .leaflet-bar a:last-child { + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + } + +/* zoom control */ + +.leaflet-control-zoom-in, +.leaflet-control-zoom-out { + font: bold 18px 'Lucida Console', Monaco, monospace; + text-indent: 1px; + } + +.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out { + font-size: 22px; + } + + +/* layers control */ + +.leaflet-control-layers { + box-shadow: 0 1px 5px rgba(0,0,0,0.4); + background: #fff; + border-radius: 5px; + } +.leaflet-control-layers-toggle { + background-image: url(images/layers.png); + width: 36px; + height: 36px; + } +.leaflet-retina .leaflet-control-layers-toggle { + background-image: url(images/layers-2x.png); + background-size: 26px 26px; + } +.leaflet-touch .leaflet-control-layers-toggle { + width: 44px; + height: 44px; + } +.leaflet-control-layers .leaflet-control-layers-list, +.leaflet-control-layers-expanded .leaflet-control-layers-toggle { + display: none; + } +.leaflet-control-layers-expanded .leaflet-control-layers-list { + display: block; + position: relative; + } +.leaflet-control-layers-expanded { + padding: 6px 10px 6px 6px; + color: #333; + background: #fff; + } +.leaflet-control-layers-scrollbar { + overflow-y: scroll; + overflow-x: hidden; + padding-right: 5px; + } +.leaflet-control-layers-selector { + margin-top: 2px; + position: relative; + top: 1px; + } +.leaflet-control-layers label { + display: block; + font-size: 13px; + font-size: 1.08333em; + } +.leaflet-control-layers-separator { + height: 0; + border-top: 1px solid #ddd; + margin: 5px -10px 5px -6px; + } + +/* Default icon URLs */ +.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */ + background-image: url(images/marker-icon.png); + } + + +/* attribution and scale controls */ + +.leaflet-container .leaflet-control-attribution { + background: #fff; + background: rgba(255, 255, 255, 0.8); + margin: 0; + } +.leaflet-control-attribution, +.leaflet-control-scale-line { + padding: 0 5px; + color: #333; + line-height: 1.4; + } +.leaflet-control-attribution a { + text-decoration: none; + } +.leaflet-control-attribution a:hover, +.leaflet-control-attribution a:focus { + text-decoration: underline; + } +.leaflet-attribution-flag { + display: inline !important; + vertical-align: baseline !important; + width: 1em; + height: 0.6669em; + } +.leaflet-left .leaflet-control-scale { + margin-left: 5px; + } +.leaflet-bottom .leaflet-control-scale { + margin-bottom: 5px; + } +.leaflet-control-scale-line { + border: 2px solid #777; + border-top: none; + line-height: 1.1; + padding: 2px 5px 1px; + white-space: nowrap; + -moz-box-sizing: border-box; + box-sizing: border-box; + background: rgba(255, 255, 255, 0.8); + text-shadow: 1px 1px #fff; + } +.leaflet-control-scale-line:not(:first-child) { + border-top: 2px solid #777; + border-bottom: none; + margin-top: -2px; + } +.leaflet-control-scale-line:not(:first-child):not(:last-child) { + border-bottom: 2px solid #777; + } + +.leaflet-touch .leaflet-control-attribution, +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + box-shadow: none; + } +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + border: 2px solid rgba(0,0,0,0.2); + background-clip: padding-box; + } + + +/* popup */ + +.leaflet-popup { + position: absolute; + text-align: center; + margin-bottom: 20px; + } +.leaflet-popup-content-wrapper { + padding: 1px; + text-align: left; + border-radius: 12px; + } +.leaflet-popup-content { + margin: 13px 24px 13px 20px; + line-height: 1.3; + font-size: 13px; + font-size: 1.08333em; + min-height: 1px; + } +.leaflet-popup-content p { + margin: 17px 0; + margin: 1.3em 0; + } +.leaflet-popup-tip-container { + width: 40px; + height: 20px; + position: absolute; + left: 50%; + margin-top: -1px; + margin-left: -20px; + overflow: hidden; + pointer-events: none; + } +.leaflet-popup-tip { + width: 17px; + height: 17px; + padding: 1px; + + margin: -10px auto 0; + pointer-events: auto; + + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); + } +.leaflet-popup-content-wrapper, +.leaflet-popup-tip { + background: white; + color: #333; + box-shadow: 0 3px 14px rgba(0,0,0,0.4); + } +.leaflet-container a.leaflet-popup-close-button { + position: absolute; + top: 0; + right: 0; + border: none; + text-align: center; + width: 24px; + height: 24px; + font: 16px/24px Tahoma, Verdana, sans-serif; + color: #757575; + text-decoration: none; + background: transparent; + } +.leaflet-container a.leaflet-popup-close-button:hover, +.leaflet-container a.leaflet-popup-close-button:focus { + color: #585858; + } +.leaflet-popup-scrolled { + overflow: auto; + } + +.leaflet-oldie .leaflet-popup-content-wrapper { + -ms-zoom: 1; + } +.leaflet-oldie .leaflet-popup-tip { + width: 24px; + margin: 0 auto; + + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); + } + +.leaflet-oldie .leaflet-control-zoom, +.leaflet-oldie .leaflet-control-layers, +.leaflet-oldie .leaflet-popup-content-wrapper, +.leaflet-oldie .leaflet-popup-tip { + border: 1px solid #999; + } + + +/* div icon */ + +.leaflet-div-icon { + background: #fff; + border: 1px solid #666; + } + + +/* Tooltip */ +/* Base styles for the element that has a tooltip */ +.leaflet-tooltip { + position: absolute; + padding: 6px; + background-color: #fff; + border: 1px solid #fff; + border-radius: 3px; + color: #222; + white-space: nowrap; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + pointer-events: none; + box-shadow: 0 1px 3px rgba(0,0,0,0.4); + } +.leaflet-tooltip.leaflet-interactive { + cursor: pointer; + pointer-events: auto; + } +.leaflet-tooltip-top:before, +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + position: absolute; + pointer-events: none; + border: 6px solid transparent; + background: transparent; + content: ""; + } + +/* Directions */ + +.leaflet-tooltip-bottom { + margin-top: 6px; +} +.leaflet-tooltip-top { + margin-top: -6px; +} +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-top:before { + left: 50%; + margin-left: -6px; + } +.leaflet-tooltip-top:before { + bottom: 0; + margin-bottom: -12px; + border-top-color: #fff; + } +.leaflet-tooltip-bottom:before { + top: 0; + margin-top: -12px; + margin-left: -6px; + border-bottom-color: #fff; + } +.leaflet-tooltip-left { + margin-left: -6px; +} +.leaflet-tooltip-right { + margin-left: 6px; +} +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + top: 50%; + margin-top: -6px; + } +.leaflet-tooltip-left:before { + right: 0; + margin-right: -12px; + border-left-color: #fff; + } +.leaflet-tooltip-right:before { + left: 0; + margin-left: -12px; + border-right-color: #fff; + } + +/* Printing */ + +@media print { + /* Prevent printers from removing background-images of controls. */ + .leaflet-control { + -webkit-print-color-adjust: exact; + print-color-adjust: exact; + } + } diff --git a/floatcsep/postprocess/web/static/vendor/leaflet/leaflet.js b/floatcsep/postprocess/web/static/vendor/leaflet/leaflet.js new file mode 100644 index 0000000..a3bf693 --- /dev/null +++ b/floatcsep/postprocess/web/static/vendor/leaflet/leaflet.js @@ -0,0 +1,6 @@ +/* @preserve + * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com + * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).leaflet={})}(this,function(t){"use strict";function l(t){for(var e,i,n=1,o=arguments.length;n=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>=e.x&&n.x<=i.x,t=t.y>=e.y&&n.y<=i.y;return o&&t},overlaps:function(t){t=_(t);var e=this.min,i=this.max,n=t.min,t=t.max,o=t.x>e.x&&n.xe.y&&n.y=n.lat&&i.lat<=o.lat&&e.lng>=n.lng&&i.lng<=o.lng},intersects:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>=e.lat&&n.lat<=i.lat,t=t.lng>=e.lng&&n.lng<=i.lng;return o&&t},overlaps:function(t){t=g(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),t=t.getNorthEast(),o=t.lat>e.lat&&n.late.lng&&n.lng","http://www.w3.org/2000/svg"===(Wt.firstChild&&Wt.firstChild.namespaceURI));function y(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var b={ie:pt,ielt9:mt,edge:n,webkit:ft,android:gt,android23:vt,androidStock:yt,opera:xt,chrome:wt,gecko:bt,safari:Pt,phantom:Lt,opera12:o,win:Tt,ie3d:Mt,webkit3d:zt,gecko3d:_t,any3d:Ct,mobile:Zt,mobileWebkit:St,mobileWebkit3d:Et,msPointer:kt,pointer:Ot,touch:Bt,touchNative:At,mobileOpera:It,mobileGecko:Rt,retina:Nt,passiveEvents:Dt,canvas:jt,svg:Ht,vml:!Ht&&function(){try{var t=document.createElement("div"),e=(t.innerHTML='',t.firstChild);return e.style.behavior="url(#default#VML)",e&&"object"==typeof e.adj}catch(t){return!1}}(),inlineSvg:Wt,mac:0===navigator.platform.indexOf("Mac"),linux:0===navigator.platform.indexOf("Linux")},Ft=b.msPointer?"MSPointerDown":"pointerdown",Ut=b.msPointer?"MSPointerMove":"pointermove",Vt=b.msPointer?"MSPointerUp":"pointerup",qt=b.msPointer?"MSPointerCancel":"pointercancel",Gt={touchstart:Ft,touchmove:Ut,touchend:Vt,touchcancel:qt},Kt={touchstart:function(t,e){e.MSPOINTER_TYPE_TOUCH&&e.pointerType===e.MSPOINTER_TYPE_TOUCH&&O(e);ee(t,e)},touchmove:ee,touchend:ee,touchcancel:ee},Yt={},Xt=!1;function Jt(t,e,i){return"touchstart"!==e||Xt||(document.addEventListener(Ft,$t,!0),document.addEventListener(Ut,Qt,!0),document.addEventListener(Vt,te,!0),document.addEventListener(qt,te,!0),Xt=!0),Kt[e]?(i=Kt[e].bind(this,i),t.addEventListener(Gt[e],i,!1),i):(console.warn("wrong event specified:",e),u)}function $t(t){Yt[t.pointerId]=t}function Qt(t){Yt[t.pointerId]&&(Yt[t.pointerId]=t)}function te(t){delete Yt[t.pointerId]}function ee(t,e){if(e.pointerType!==(e.MSPOINTER_TYPE_MOUSE||"mouse")){for(var i in e.touches=[],Yt)e.touches.push(Yt[i]);e.changedTouches=[e],t(e)}}var ie=200;function ne(t,i){t.addEventListener("dblclick",i);var n,o=0;function e(t){var e;1!==t.detail?n=t.detail:"mouse"===t.pointerType||t.sourceCapabilities&&!t.sourceCapabilities.firesTouchEvents||((e=Ne(t)).some(function(t){return t instanceof HTMLLabelElement&&t.attributes.for})&&!e.some(function(t){return t instanceof HTMLInputElement||t instanceof HTMLSelectElement})||((e=Date.now())-o<=ie?2===++n&&i(function(t){var e,i,n={};for(i in t)e=t[i],n[i]=e&&e.bind?e.bind(t):e;return(t=n).type="dblclick",n.detail=2,n.isTrusted=!1,n._simulated=!0,n}(t)):n=1,o=e))}return t.addEventListener("click",e),{dblclick:i,simDblclick:e}}var oe,se,re,ae,he,le,ue=we(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),ce=we(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),de="webkitTransition"===ce||"OTransition"===ce?ce+"End":"transitionend";function _e(t){return"string"==typeof t?document.getElementById(t):t}function pe(t,e){var i=t.style[e]||t.currentStyle&&t.currentStyle[e];return"auto"===(i=i&&"auto"!==i||!document.defaultView?i:(t=document.defaultView.getComputedStyle(t,null))?t[e]:null)?null:i}function P(t,e,i){t=document.createElement(t);return t.className=e||"",i&&i.appendChild(t),t}function T(t){var e=t.parentNode;e&&e.removeChild(t)}function me(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function fe(t){var e=t.parentNode;e&&e.lastChild!==t&&e.appendChild(t)}function ge(t){var e=t.parentNode;e&&e.firstChild!==t&&e.insertBefore(t,e.firstChild)}function ve(t,e){return void 0!==t.classList?t.classList.contains(e):0<(t=xe(t)).length&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(t)}function M(t,e){var i;if(void 0!==t.classList)for(var n=F(e),o=0,s=n.length;othis.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,e){this._enforcingBounds=!0;var i=this.getCenter(),t=this._limitCenter(i,this._zoom,g(t));return i.equals(t)||this.panTo(t,e),this._enforcingBounds=!1,this},panInside:function(t,e){var i=m((e=e||{}).paddingTopLeft||e.padding||[0,0]),n=m(e.paddingBottomRight||e.padding||[0,0]),o=this.project(this.getCenter()),t=this.project(t),s=this.getPixelBounds(),i=_([s.min.add(i),s.max.subtract(n)]),s=i.getSize();return i.contains(t)||(this._enforcingBounds=!0,n=t.subtract(i.getCenter()),i=i.extend(t).getSize().subtract(s),o.x+=n.x<0?-i.x:i.x,o.y+=n.y<0?-i.y:i.y,this.panTo(this.unproject(o),e),this._enforcingBounds=!1),this},invalidateSize:function(t){if(!this._loaded)return this;t=l({animate:!1,pan:!0},!0===t?{animate:!0}:t);var e=this.getSize(),i=(this._sizeChanged=!0,this._lastCenter=null,this.getSize()),n=e.divideBy(2).round(),o=i.divideBy(2).round(),n=n.subtract(o);return n.x||n.y?(t.animate&&t.pan?this.panBy(n):(t.pan&&this._rawPanBy(n),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(a(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:e,newSize:i})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){var e,i;return t=this._locateOptions=l({timeout:1e4,watch:!1},t),"geolocation"in navigator?(e=a(this._handleGeolocationResponse,this),i=a(this._handleGeolocationError,this),t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t)):this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e;this._container._leaflet_id&&(e=t.code,t=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout"),this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+t+"."}))},_handleGeolocationResponse:function(t){if(this._container._leaflet_id){var e,i,n=new v(t.coords.latitude,t.coords.longitude),o=n.toBounds(2*t.coords.accuracy),s=this._locateOptions,r=(s.setView&&(e=this.getBoundsZoom(o),this.setView(n,s.maxZoom?Math.min(e,s.maxZoom):e)),{latlng:n,bounds:o,timestamp:t.timestamp});for(i in t.coords)"number"==typeof t.coords[i]&&(r[i]=t.coords[i]);this.fire("locationfound",r)}},addHandler:function(t,e){return e&&(e=this[t]=new e(this),this._handlers.push(e),this.options[t]&&e.enable()),this},remove:function(){if(this._initEvents(!0),this.options.maxBounds&&this.off("moveend",this._panInsideMaxBounds),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}for(var t in void 0!==this._locationWatchId&&this.stopLocate(),this._stop(),T(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._resizeRequest&&(r(this._resizeRequest),this._resizeRequest=null),this._clearHandlers(),this._loaded&&this.fire("unload"),this._layers)this._layers[t].remove();for(t in this._panes)T(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,e){e=P("div","leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),e||this._mapPane);return t&&(this._panes[t]=e),e},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter.clone():this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new s(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=g(t),i=m(i||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),t=t.getSouthEast(),i=this.getSize().subtract(i),t=_(this.project(t,n),this.project(r,n)).getSize(),r=b.any3d?this.options.zoomSnap:1,a=i.x/t.x,i=i.y/t.y,t=e?Math.max(a,i):Math.min(a,i),n=this.getScaleZoom(t,n);return r&&(n=Math.round(n/(r/100))*(r/100),n=e?Math.ceil(n/r)*r:Math.floor(n/r)*r),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new p(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,e){t=this._getTopLeftPoint(t,e);return new f(t,t.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,e){var i=this.options.crs;return e=void 0===e?this._zoom:e,i.scale(t)/i.scale(e)},getScaleZoom:function(t,e){var i=this.options.crs,t=(e=void 0===e?this._zoom:e,i.zoom(t*i.scale(e)));return isNaN(t)?1/0:t},project:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.latLngToPoint(w(t),e)},unproject:function(t,e){return e=void 0===e?this._zoom:e,this.options.crs.pointToLatLng(m(t),e)},layerPointToLatLng:function(t){t=m(t).add(this.getPixelOrigin());return this.unproject(t)},latLngToLayerPoint:function(t){return this.project(w(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(w(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(g(t))},distance:function(t,e){return this.options.crs.distance(w(t),w(e))},containerPointToLayerPoint:function(t){return m(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return m(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){t=this.containerPointToLayerPoint(m(t));return this.layerPointToLatLng(t)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(w(t)))},mouseEventToContainerPoint:function(t){return De(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){t=this._container=_e(t);if(!t)throw new Error("Map container not found.");if(t._leaflet_id)throw new Error("Map container is already initialized.");S(t,"scroll",this._onScroll,this),this._containerId=h(t)},_initLayout:function(){var t=this._container,e=(this._fadeAnimated=this.options.fadeAnimation&&b.any3d,M(t,"leaflet-container"+(b.touch?" leaflet-touch":"")+(b.retina?" leaflet-retina":"")+(b.ielt9?" leaflet-oldie":"")+(b.safari?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":"")),pe(t,"position"));"absolute"!==e&&"relative"!==e&&"fixed"!==e&&"sticky"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),Z(this._mapPane,new p(0,0)),this.createPane("tilePane"),this.createPane("overlayPane"),this.createPane("shadowPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(M(t.markerPane,"leaflet-zoom-hide"),M(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,e,i){Z(this._mapPane,new p(0,0));var n=!this._loaded,o=(this._loaded=!0,e=this._limitZoom(e),this.fire("viewprereset"),this._zoom!==e);this._moveStart(o,i)._move(t,e)._moveEnd(o),this.fire("viewreset"),n&&this.fire("load")},_moveStart:function(t,e){return t&&this.fire("zoomstart"),e||this.fire("movestart"),this},_move:function(t,e,i,n){void 0===e&&(e=this._zoom);var o=this._zoom!==e;return this._zoom=e,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),n?i&&i.pinch&&this.fire("zoom",i):((o||i&&i.pinch)&&this.fire("zoom",i),this.fire("move",i)),this},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return r(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){Z(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(t){this._targets={};var e=t?k:S;e((this._targets[h(this._container)]=this)._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup",this._handleDOMEvent,this),this.options.trackResize&&e(window,"resize",this._onResize,this),b.any3d&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,"moveend",this._onMoveEnd)},_onResize:function(){r(this._resizeRequest),this._resizeRequest=x(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,e){for(var i,n=[],o="mouseout"===e||"mouseover"===e,s=t.target||t.srcElement,r=!1;s;){if((i=this._targets[h(s)])&&("click"===e||"preclick"===e)&&this._draggableMoved(i)){r=!0;break}if(i&&i.listens(e,!0)){if(o&&!We(s,t))break;if(n.push(i),o)break}if(s===this._container)break;s=s.parentNode}return n=n.length||r||o||!this.listens(e,!0)?n:[this]},_isClickDisabled:function(t){for(;t&&t!==this._container;){if(t._leaflet_disable_click)return!0;t=t.parentNode}},_handleDOMEvent:function(t){var e,i=t.target||t.srcElement;!this._loaded||i._leaflet_disable_events||"click"===t.type&&this._isClickDisabled(i)||("mousedown"===(e=t.type)&&Me(i),this._fireDOMEvent(t,e))},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,e,i){"click"===t.type&&((a=l({},t)).type="preclick",this._fireDOMEvent(a,a.type,i));var n=this._findEventTargets(t,e);if(i){for(var o=[],s=0;sthis.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),n=this._getCenterOffset(t)._divideBy(1-1/n);if(!0!==i.animate&&!this.getSize().contains(n))return!1;x(function(){this._moveStart(!0,i.noMoveStart||!1)._animateZoom(t,e,!0)},this)}return!0},_animateZoom:function(t,e,i,n){this._mapPane&&(i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,M(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:e,noUpdate:n}),this._tempFireZoomEvent||(this._tempFireZoomEvent=this._zoom!==this._animateToZoom),this._move(this._animateToCenter,this._animateToZoom,void 0,!0),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&z(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom,void 0,!0),this._tempFireZoomEvent&&this.fire("zoom"),delete this._tempFireZoomEvent,this.fire("move"),this._moveEnd(!0))}});function Ue(t){return new B(t)}var B=et.extend({options:{position:"topright"},initialize:function(t){c(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var e=this._map;return e&&e.removeControl(this),this.options.position=t,e&&e.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),t=t._controlCorners[i];return M(e,"leaflet-control"),-1!==i.indexOf("bottom")?t.insertBefore(e,t.firstChild):t.appendChild(e),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(T(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0",e=document.createElement("div");return e.innerHTML=t,e.firstChild},_addItem:function(t){var e,i=document.createElement("label"),n=this._map.hasLayer(t.layer),n=(t.overlay?((e=document.createElement("input")).type="checkbox",e.className="leaflet-control-layers-selector",e.defaultChecked=n):e=this._createRadioElement("leaflet-base-layers_"+h(this),n),this._layerControlInputs.push(e),e.layerId=h(t.layer),S(e,"click",this._onInputClick,this),document.createElement("span")),o=(n.innerHTML=" "+t.name,document.createElement("span"));return i.appendChild(o),o.appendChild(e),o.appendChild(n),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(i),this._checkDisabledLayers(),i},_onInputClick:function(){if(!this._preventClick){var t,e,i=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=i.length-1;0<=s;s--)t=i[s],e=this._getLayer(t.layerId).layer,t.checked?n.push(e):t.checked||o.push(e);for(s=0;se.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expandSafely:function(){var t=this._section,e=(this._preventClick=!0,S(t,"click",O),this.expand(),this);setTimeout(function(){k(t,"click",O),e._preventClick=!1})}})),qe=B.extend({options:{position:"topleft",zoomInText:'',zoomInTitle:"Zoom in",zoomOutText:'',zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=P("div",e+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoomthis._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,e,i,n,o){i=P("a",i,n);return i.innerHTML=t,i.href="#",i.title=e,i.setAttribute("role","button"),i.setAttribute("aria-label",e),Ie(i),S(i,"click",Re),S(i,"click",o,this),S(i,"click",this._refocusOnMap,this),i},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";z(this._zoomInButton,e),z(this._zoomOutButton,e),this._zoomInButton.setAttribute("aria-disabled","false"),this._zoomOutButton.setAttribute("aria-disabled","false"),!this._disabled&&t._zoom!==t.getMinZoom()||(M(this._zoomOutButton,e),this._zoomOutButton.setAttribute("aria-disabled","true")),!this._disabled&&t._zoom!==t.getMaxZoom()||(M(this._zoomInButton,e),this._zoomInButton.setAttribute("aria-disabled","true"))}}),Ge=(A.mergeOptions({zoomControl:!0}),A.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new qe,this.addControl(this.zoomControl))}),B.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var e="leaflet-control-scale",i=P("div",e),n=this.options;return this._addScales(n,e+"-line",i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=P("div",e,i)),t.imperial&&(this._iScale=P("div",e,i))},_update:function(){var t=this._map,e=t.getSize().y/2,t=t.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(t)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var e=this._getRoundNum(t);this._updateScale(this._mScale,e<1e3?e+" m":e/1e3+" km",e/t)},_updateImperial:function(t){var e,i,t=3.2808399*t;5280'+(b.inlineSvg?' ':"")+"Leaflet"},initialize:function(t){c(this,t),this._attributions={}},onAdd:function(t){for(var e in(t.attributionControl=this)._container=P("div","leaflet-control-attribution"),Ie(this._container),t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return this._update(),t.on("layeradd",this._addAttribution,this),this._container},onRemove:function(t){t.off("layeradd",this._addAttribution,this)},_addAttribution:function(t){t.layer.getAttribution&&(this.addAttribution(t.layer.getAttribution()),t.layer.once("remove",function(){this.removeAttribution(t.layer.getAttribution())},this))},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t,e=[];for(t in this._attributions)this._attributions[t]&&e.push(t);var i=[];this.options.prefix&&i.push(this.options.prefix),e.length&&i.push(e.join(", ")),this._container.innerHTML=i.join(' ')}}}),n=(A.mergeOptions({attributionControl:!0}),A.addInitHook(function(){this.options.attributionControl&&(new Ke).addTo(this)}),B.Layers=Ve,B.Zoom=qe,B.Scale=Ge,B.Attribution=Ke,Ue.layers=function(t,e,i){return new Ve(t,e,i)},Ue.zoom=function(t){return new qe(t)},Ue.scale=function(t){return new Ge(t)},Ue.attribution=function(t){return new Ke(t)},et.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}})),ft=(n.addTo=function(t,e){return t.addHandler(e,this),this},{Events:e}),Ye=b.touch?"touchstart mousedown":"mousedown",Xe=it.extend({options:{clickTolerance:3},initialize:function(t,e,i,n){c(this,n),this._element=t,this._dragStartTarget=e||t,this._preventOutline=i},enable:function(){this._enabled||(S(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(Xe._dragging===this&&this.finishDrag(!0),k(this._dragStartTarget,Ye,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){var e,i;this._enabled&&(this._moved=!1,ve(this._element,"leaflet-zoom-anim")||(t.touches&&1!==t.touches.length?Xe._dragging===this&&this.finishDrag():Xe._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((Xe._dragging=this)._preventOutline&&Me(this._element),Le(),re(),this._moving||(this.fire("down"),i=t.touches?t.touches[0]:t,e=Ce(this._element),this._startPoint=new p(i.clientX,i.clientY),this._startPos=Pe(this._element),this._parentScale=Ze(e),i="mousedown"===t.type,S(document,i?"mousemove":"touchmove",this._onMove,this),S(document,i?"mouseup":"touchend touchcancel",this._onUp,this)))))},_onMove:function(t){var e;this._enabled&&(t.touches&&1e&&(i.push(t[n]),o=n);oe.max.x&&(i|=2),t.ye.max.y&&(i|=8),i}function ri(t,e,i,n){var o=e.x,e=e.y,s=i.x-o,r=i.y-e,a=s*s+r*r;return 0this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()t.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(l=!l);return l||yi.prototype._containsPoint.call(this,t,!0)}});var wi=ci.extend({initialize:function(t,e){c(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,o=d(t)?t:t.features;if(o){for(e=0,i=o.length;es.x&&(r=i.x+a-s.x+o.x),i.x-r-n.x<(a=0)&&(r=i.x-n.x),i.y+e+o.y>s.y&&(a=i.y+e-s.y+o.y),i.y-a-n.y<0&&(a=i.y-n.y),(r||a)&&(this.options.keepInView&&(this._autopanning=!0),t.fire("autopanstart").panBy([r,a]))))},_getAnchor:function(){return m(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}})),Ii=(A.mergeOptions({closePopupOnClick:!0}),A.include({openPopup:function(t,e,i){return this._initOverlay(Bi,t,e,i).openOn(this),this},closePopup:function(t){return(t=arguments.length?t:this._popup)&&t.close(),this}}),o.include({bindPopup:function(t,e){return this._popup=this._initOverlay(Bi,this._popup,t,e),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t){return this._popup&&(this instanceof ci||(this._popup._source=this),this._popup._prepareOpen(t||this._latlng)&&this._popup.openOn(this._map)),this},closePopup:function(){return this._popup&&this._popup.close(),this},togglePopup:function(){return this._popup&&this._popup.toggle(this),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var e;this._popup&&this._map&&(Re(t),e=t.layer||t.target,this._popup._source!==e||e instanceof fi?(this._popup._source=e,this.openPopup(t.latlng)):this._map.hasLayer(this._popup)?this.closePopup():this.openPopup(t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}}),Ai.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,opacity:.9},onAdd:function(t){Ai.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&(this.addEventParent(this._source),this._source.fire("tooltipopen",{tooltip:this},!0))},onRemove:function(t){Ai.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&(this.removeEventParent(this._source),this._source.fire("tooltipclose",{tooltip:this},!0))},getEvents:function(){var t=Ai.prototype.getEvents.call(this);return this.options.permanent||(t.preclick=this.close),t},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=P("div",t),this._container.setAttribute("role","tooltip"),this._container.setAttribute("id","leaflet-tooltip-"+h(this))},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var e,i=this._map,n=this._container,o=i.latLngToContainerPoint(i.getCenter()),i=i.layerPointToContainerPoint(t),s=this.options.direction,r=n.offsetWidth,a=n.offsetHeight,h=m(this.options.offset),l=this._getAnchor(),i="top"===s?(e=r/2,a):"bottom"===s?(e=r/2,0):(e="center"===s?r/2:"right"===s?0:"left"===s?r:i.xthis.options.maxZoom||nthis.options.maxZoom||void 0!==this.options.minZoom&&oi.max.x)||!e.wrapLat&&(t.yi.max.y))return!1}return!this.options.bounds||(e=this._tileCoordsToBounds(t),g(this.options.bounds).overlaps(e))},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var e=this._map,i=this.getTileSize(),n=t.scaleBy(i),i=n.add(i);return[e.unproject(n,t.z),e.unproject(i,t.z)]},_tileCoordsToBounds:function(t){t=this._tileCoordsToNwSe(t),t=new s(t[0],t[1]);return t=this.options.noWrap?t:this._map.wrapLatLngBounds(t)},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var t=t.split(":"),e=new p(+t[0],+t[1]);return e.z=+t[2],e},_removeTile:function(t){var e=this._tiles[t];e&&(T(e.el),delete this._tiles[t],this.fire("tileunload",{tile:e.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){M(t,"leaflet-tile");var e=this.getTileSize();t.style.width=e.x+"px",t.style.height=e.y+"px",t.onselectstart=u,t.onmousemove=u,b.ielt9&&this.options.opacity<1&&C(t,this.options.opacity)},_addTile:function(t,e){var i=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),a(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&x(a(this._tileReady,this,t,null,o)),Z(o,i),this._tiles[n]={el:o,coords:t,current:!0},e.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,e,i){e&&this.fire("tileerror",{error:e,tile:i,coords:t});var n=this._tileCoordsToKey(t);(i=this._tiles[n])&&(i.loaded=+new Date,this._map._fadeAnimated?(C(i.el,0),r(this._fadeFrame),this._fadeFrame=x(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),e||(M(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:i.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),b.ielt9||!this._map._fadeAnimated?x(this._pruneTiles,this):setTimeout(a(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var e=new p(this._wrapX?H(t.x,this._wrapX):t.x,this._wrapY?H(t.y,this._wrapY):t.y);return e.z=t.z,e},_pxBoundsToTileRange:function(t){var e=this.getTileSize();return new f(t.min.unscaleBy(e).floor(),t.max.unscaleBy(e).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var Di=Ni.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1,referrerPolicy:!1},initialize:function(t,e){this._url=t,(e=c(this,e)).detectRetina&&b.retina&&0')}}catch(t){}return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}(),zt={_initContainer:function(){this._container=P("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(Wi.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var e=t._container=Vi("shape");M(e,"leaflet-vml-shape "+(this.options.className||"")),e.coordsize="1 1",t._path=Vi("path"),e.appendChild(t._path),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){var e=t._container;this._container.appendChild(e),t.options.interactive&&t.addInteractiveTarget(e)},_removePath:function(t){var e=t._container;T(e),t.removeInteractiveTarget(e),delete this._layers[h(t)]},_updateStyle:function(t){var e=t._stroke,i=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(e=e||(t._stroke=Vi("stroke")),o.appendChild(e),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=d(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):e.dashStyle="",e.endcap=n.lineCap.replace("butt","flat"),e.joinstyle=n.lineJoin):e&&(o.removeChild(e),t._stroke=null),n.fill?(i=i||(t._fill=Vi("fill")),o.appendChild(i),i.color=n.fillColor||n.color,i.opacity=n.fillOpacity):i&&(o.removeChild(i),t._fill=null)},_updateCircle:function(t){var e=t._point.round(),i=Math.round(t._radius),n=Math.round(t._radiusY||i);this._setPath(t,t._empty()?"M0 0":"AL "+e.x+","+e.y+" "+i+","+n+" 0,23592600")},_setPath:function(t,e){t._path.v=e},_bringToFront:function(t){fe(t._container)},_bringToBack:function(t){ge(t._container)}},qi=b.vml?Vi:ct,Gi=Wi.extend({_initContainer:function(){this._container=qi("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=qi("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){T(this._container),k(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_update:function(){var t,e,i;this._map._animatingZoom&&this._bounds||(Wi.prototype._update.call(this),e=(t=this._bounds).getSize(),i=this._container,this._svgSize&&this._svgSize.equals(e)||(this._svgSize=e,i.setAttribute("width",e.x),i.setAttribute("height",e.y)),Z(i,t.min),i.setAttribute("viewBox",[t.min.x,t.min.y,e.x,e.y].join(" ")),this.fire("update"))},_initPath:function(t){var e=t._path=qi("path");t.options.className&&M(e,t.options.className),t.options.interactive&&M(e,"leaflet-interactive"),this._updateStyle(t),this._layers[h(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){T(t._path),t.removeInteractiveTarget(t._path),delete this._layers[h(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var e=t._path,t=t.options;e&&(t.stroke?(e.setAttribute("stroke",t.color),e.setAttribute("stroke-opacity",t.opacity),e.setAttribute("stroke-width",t.weight),e.setAttribute("stroke-linecap",t.lineCap),e.setAttribute("stroke-linejoin",t.lineJoin),t.dashArray?e.setAttribute("stroke-dasharray",t.dashArray):e.removeAttribute("stroke-dasharray"),t.dashOffset?e.setAttribute("stroke-dashoffset",t.dashOffset):e.removeAttribute("stroke-dashoffset")):e.setAttribute("stroke","none"),t.fill?(e.setAttribute("fill",t.fillColor||t.color),e.setAttribute("fill-opacity",t.fillOpacity),e.setAttribute("fill-rule",t.fillRule||"evenodd")):e.setAttribute("fill","none"))},_updatePoly:function(t,e){this._setPath(t,dt(t._parts,e))},_updateCircle:function(t){var e=t._point,i=Math.max(Math.round(t._radius),1),n="a"+i+","+(Math.max(Math.round(t._radiusY),1)||i)+" 0 1,0 ",e=t._empty()?"M0 0":"M"+(e.x-i)+","+e.y+n+2*i+",0 "+n+2*-i+",0 ";this._setPath(t,e)},_setPath:function(t,e){t._path.setAttribute("d",e)},_bringToFront:function(t){fe(t._path)},_bringToBack:function(t){ge(t._path)}});function Ki(t){return b.svg||b.vml?new Gi(t):null}b.vml&&Gi.include(zt),A.include({getRenderer:function(t){t=(t=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer)||(this._renderer=this._createRenderer());return this.hasLayer(t)||this.addLayer(t),t},_getPaneRenderer:function(t){var e;return"overlayPane"!==t&&void 0!==t&&(void 0===(e=this._paneRenderers[t])&&(e=this._createRenderer({pane:t}),this._paneRenderers[t]=e),e)},_createRenderer:function(t){return this.options.preferCanvas&&Ui(t)||Ki(t)}});var Yi=xi.extend({initialize:function(t,e){xi.prototype.initialize.call(this,this._boundsToLatLngs(t),e)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=g(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});Gi.create=qi,Gi.pointsToPath=dt,wi.geometryToLayer=bi,wi.coordsToLatLng=Li,wi.coordsToLatLngs=Ti,wi.latLngToCoords=Mi,wi.latLngsToCoords=zi,wi.getFeature=Ci,wi.asFeature=Zi,A.mergeOptions({boxZoom:!0});var _t=n.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){S(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){k(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){T(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),re(),Le(),this._startPoint=this._map.mouseEventToContainerPoint(t),S(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=P("div","leaflet-zoom-box",this._container),M(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var t=new f(this._point,this._startPoint),e=t.getSize();Z(this._box,t.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(T(this._box),z(this._container,"leaflet-crosshair")),ae(),Te(),k(document,{contextmenu:Re,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){1!==t.which&&1!==t.button||(this._finish(),this._moved&&(this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(a(this._resetState,this),0),t=new s(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point)),this._map.fitBounds(t).fire("boxzoomend",{boxZoomBounds:t})))},_onKeyDown:function(t){27===t.keyCode&&(this._finish(),this._clearDeferredResetState(),this._resetState())}}),Ct=(A.addInitHook("addHandler","boxZoom",_t),A.mergeOptions({doubleClickZoom:!0}),n.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var e=this._map,i=e.getZoom(),n=e.options.zoomDelta,i=t.originalEvent.shiftKey?i-n:i+n;"center"===e.options.doubleClickZoom?e.setZoom(i):e.setZoomAround(t.containerPoint,i)}})),Zt=(A.addInitHook("addHandler","doubleClickZoom",Ct),A.mergeOptions({dragging:!0,inertia:!0,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0}),n.extend({addHooks:function(){var t;this._draggable||(t=this._map,this._draggable=new Xe(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))),M(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){z(this._map._container,"leaflet-grab"),z(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t,e=this._map;e._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity?(t=g(this._map.options.maxBounds),this._offsetLimit=_(this._map.latLngToContainerPoint(t.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(t.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))):this._offsetLimit=null,e.fire("movestart").fire("dragstart"),e.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){var e,i;this._map.options.inertia&&(e=this._lastTime=+new Date,i=this._lastPos=this._draggable._absPos||this._draggable._newPos,this._positions.push(i),this._times.push(e),this._prunePositions(e)),this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1e.max.x&&(t.x=this._viscousLimit(t.x,e.max.x)),t.y>e.max.y&&(t.y=this._viscousLimit(t.y,e.max.y)),this._draggable._newPos=this._draggable._startPos.add(t))},_onPreDragWrap:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,n=(n+e+i)%t-e-i,t=Math.abs(o+i)e.getMaxZoom()&&1 0) - - def test_i(self): - fig, n_cells, dh, bx, by = build_region_basemap(None) - self.assertIsNotNone(fig) - self.assertIsNone(n_cells) - self.assertIsNone(dh) - self.assertEqual(bx, (None, None)) - self.assertEqual(by, (None, None)) - - def test_j(self): - with tempfile.TemporaryDirectory() as td: - root = Path(td) - cell1 = _Cell([(0, 0), (0, 1), (1, 1), (1, 0)]) - cell2 = _Cell([(1, 0), (1, 1), (2, 1), (2, 0)]) - region = _Region([cell1, cell2], dh=0.5) - - fig, n_cells, dh, bx, by = build_region_basemap(region, plot_cells=True, min_height=111) - self.assertIsNotNone(fig) - self.assertEqual(n_cells, 2) - self.assertEqual(dh, 0.5) - self.assertEqual(bx, [0.0, 2.0]) - self.assertEqual(by, [0.0, 1.0]) - self.assertGreaterEqual(fig.min_height, 111) - - def test_k(self): - with tempfile.TemporaryDirectory() as td: - root = Path(td) - (root / "figures").mkdir(parents=True, exist_ok=True) - (root / "forecasts").mkdir(parents=True, exist_ok=True) - - for nm in ["main_catalog_map", "main_catalog_time"]: - (root / "figures" / f"{nm}.png").write_text("x") - - (root / "figures" / "tw1__T1.png").write_text("x") - (root / "figures" / "tw1__T1_M1.png").write_text("x") - - reg = _Registry(root, exists={("tw1", "T1_M1")}) - cat_repo = _CatRepo(Path("cats") / "main.csv") - m1 = _Model(root, "M1") - m2 = _Model(root, "M2") - t1 = _Test("T1") - - exp = SimpleNamespace( - registry=reg, - catalog_repo=cat_repo, - name="x", - start_date=datetime(2020, 1, 1), - end_date=datetime(2020, 2, 1), - authors=["a", "b"], - doi="d", - journal="j", - manuscript_doi=None, - exp_time="t", - floatcsep_version="v1", - pycsep_version="v2", - last_run="now", - catalog_doi="cd", - LICENSE="MIT", - magnitudes=[1.0, 2.0], - region=None, - time_windows=["tw1", "tw2"], - models=[m1, m2], - tests=[t1], - time_config={ - "exp_class": "td", - "intervals": 2, - "horizon": timedelta(days=365), - "offset": timedelta(days=2), - "growth": "incremental", - }, - region_config={}, - exp_class="td", - run_mode="sequential", - run_dir="results", - config_file="config.yml", - model_config="models.yml", - test_config="tests.yml", - mag_min=1.0, - mag_max=2.0, - mag_bin=0.1, - depth_min=-2.0, - depth_max=30.0, - ) - - tw_map = {"tw1": "2020-01-01_2020-01-31", "tw2": "2020-02-01_2020-02-28"} - - def fake_t2s(x): - return tw_map[x] - - with patch("floatcsep.postprocess.panel.manifest.timewindow2str", new=fake_t2s): - man = build_manifest(exp, app_root=str(root)) - - self.assertEqual(man.name, "x") - self.assertEqual(man.start_date, "2020-01-01") - self.assertEqual(man.end_date, "2020-02-01") - self.assertEqual(man.authors, "a, b") - self.assertEqual(man.exp_class, "Time-Dependent") - self.assertEqual(man.n_intervals, 2) - self.assertEqual(man.horizon, "1 year") - self.assertEqual(man.offset, "2 days") - - self.assertIn("path", man.catalog) - self.assertIn("map", man.catalog) - self.assertIn("time", man.catalog) - - tw1s = "2020-01-01 to 2020-01-31" - self.assertIn((tw1s, "T1"), man.results_main) - self.assertIn((tw1s, "T1", "M1"), man.results_model) - self.assertNotIn((tw1s, "T1", "M2"), man.results_model) - - names = [m["name"] for m in man.models] - self.assertEqual(set(names), {"M1", "M2"}) - self.assertIn(tw1s, man.models[0]["forecasts"]) - self.assertIn(tw1s, man.models[1]["forecasts"]) - - def test_l(self): - with tempfile.TemporaryDirectory() as td: - root = Path(td) - (root / "figures").mkdir(parents=True, exist_ok=True) - (root / "forecasts").mkdir(parents=True, exist_ok=True) - - reg = _Registry(root, fail_catalog=True) - cat_repo = _CatRepo(Path("cats") / "main.csv") - m1 = _Model(root, "M1") - t1 = _Test("T1") - - exp = SimpleNamespace( - registry=reg, - catalog_repo=cat_repo, - name="x", - start_date=datetime(2020, 1, 1), - end_date=datetime(2020, 1, 2), - authors="a", - doi=None, - journal=None, - manuscript_doi=None, - exp_time=None, - floatcsep_version=None, - pycsep_version=None, - last_run=None, - catalog_doi=None, - LICENSE=None, - magnitudes=[], - region=None, - time_windows=["tw1"], - models=[m1], - tests=[t1], - time_config={}, - region_config={}, - ) - - with patch("floatcsep.postprocess.panel.manifest.timewindow2str", new=lambda x: "2020-01-01_2020-01-02"): - man = build_manifest(exp, app_root=str(root)) - - self.assertIsInstance(man.catalog, dict) - self.assertEqual(man.catalog, {}) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/unit/test_web_export.py b/tests/unit/test_web_export.py new file mode 100644 index 0000000..ce15cae --- /dev/null +++ b/tests/unit/test_web_export.py @@ -0,0 +1,45 @@ +import base64 +import json + +import numpy as np + +from floatcsep.postprocess.web.export import _encode_rates, _summary, _outline, STATIC + + +def test_encode_rates_roundtrip(): + rates = np.array([[1.0, 0.5, 0.0], [0.0, 0.0, 0.0], [0.01, 0.02, 0.03]]) + enc = _encode_rates(rates) + q = np.frombuffer(base64.b64decode(enc["data"]), dtype=" 0 + decoded = enc["vmin"] + (q[q > 0] - 1) / 65534 * (enc["vmax"] - enc["vmin"]) + np.testing.assert_allclose(10**decoded, cum[cum > 0], rtol=1e-3) + np.testing.assert_allclose(enc["totals"], cum.sum(axis=0), atol=1e-4) + + +def test_summary_shapes(): + cons = _summary({"name": "S", "observed_statistic": -3.0, "quantile": 0.2, "status": "normal", + "test_distribution": list(np.linspace(-5, 0, 100))}, "consistency") + assert cons["n_sim"] == 100 and len(cons["dist_q"]) == 7 + + ntest = _summary({"name": "N", "observed_statistic": 7, "quantile": [0.3, 0.8], + "test_distribution": ["poisson", 6.5]}, "consistency") + assert ntest["dist"] == {"type": "poisson", "params": [6.5]} + + ttest = _summary({"name": "T", "observed_statistic": 0.4, "quantile": [1.2, 2.0, 0.05], + "test_distribution": [0.1, 0.7]}, "comparative") + assert ttest["ci"] == [0.1, 0.7] + + +def test_outline_is_single_polygon(): + xs, ys = np.meshgrid(np.arange(0, 1, 0.1), np.arange(0, 0.5, 0.1)) + origins = np.column_stack([xs.ravel(), ys.ravel()]) + geom = _outline(origins, 0.1) + assert geom is None or geom["type"] == "Polygon" + + +def test_static_files_present(): + for rel in ["index.html", "js/app.js", "css/app.css", "vendor/leaflet/leaflet.js", "vendor/echarts/echarts.min.js"]: + assert (STATIC / rel).exists(), rel diff --git a/tutorials/case_h/catalog.csv b/tutorials/case_h/catalog.csv index 23c11a0..4e78d68 100644 --- a/tutorials/case_h/catalog.csv +++ b/tutorials/case_h/catalog.csv @@ -9,7 +9,7 @@ lon,lat,mag,time_string,depth,catalog_id,event_id 14.166,41.713,2.2,2005-04-18T18:00:51.980000,9.3,-1,1592589 9.724,44.77,3.8,2005-04-19T07:42:01.250000,25.2,-1,1592819 9.687,44.769,3.5,2005-04-19T08:27:39.880000,25.6,-1,1592839 -9.74,44.742,2.7,2005-04-19T09:39:28.x860000,29.2,-1,1592859 +9.74,44.742,2.7,2005-04-19T09:39:28.860000,29.2,-1,1592859 9.71,44.716,2.7,2005-04-19T09:45:50.710000,29.8,-1,1592869 12.872,43.129,2.3,2005-04-19T10:35:36.410000,16.8,-1,1592899 9.74,44.751,2.1,2005-04-19T10:59:50.810000,27.3,-1,1592919