From a65adcc2e5d890ee2dc7938f38e75f6f8ac8f14b Mon Sep 17 00:00:00 2001 From: wangyitong Date: Mon, 13 Jul 2026 14:47:12 +0800 Subject: [PATCH] Initial commit: merged, deduplicated, and vetted skill collection Sources: extracted from two upstream archives (skill-repo, skills-main), merged with the following policy: - 15 broken symlinks (pointing to /Users/jameslee/.cc-switch/skills or ../../.agents/skills on a foreign machine) discarded - 3 real name collisions with identical content (ai-pair, ifind-http-api, zhipu-websearch) kept as one copy - Functional overlaps deduped keeping the strongest variant: - docx family: kept docx (official, full toolchain) + docx-cn (GB/T 9704 Chinese official-document constants), dropped docx_writer (no scripts, name collided with docx) - humanizer family: kept humanizer-zh (6 zh reference docs), dropped humanizer (en, redundant for CN workflow) - Skills that only ran in a foreign environment removed: ablemind-ops, app-publish, hlb-design-system, openclaw-adj-skill, claude-driver - alphapai excluded from this public repo because its SKILL.md hard-coded live credentials Result: 25 skills, 572 files, ~7.5 MB. Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitignore | 25 + README.md | 84 + agentrs-map/SKILL.md | 48 + agentrs-map/scripts/amap.py | 107 + agentrs-search/SKILL.md | 50 + agentrs-search/scripts/search.py | 103 + agentrs-weather/SKILL.md | 51 + agentrs-weather/scripts/weather.py | 98 + ai-pair/.gitignore | 4 + ai-pair/LICENSE | 21 + ai-pair/README.md | 218 + ai-pair/SKILL.md | 609 +++ ai-pair/examples/content-team.md | 102 + ai-pair/examples/dev-team.md | 81 + annuity-disclosure-crawler/SKILL.md | 112 + .../references/registry.json | 421 ++ annuity-disclosure-crawler/scripts/crawl.py | 372 ++ .../scripts/crawl_headless.py | 218 + asset-monitor/SKILL.md | 192 + .../references/monitor-config-example.json | 37 + asset-monitor/scripts/monitor.py | 253 + docx-cn/SKILL.md | 489 ++ docx-cn/scripts/gongwen_constants.js | 287 ++ docx/LICENSE.txt | 30 + docx/SKILL.md | 198 + docx/docx-js.md | 499 ++ docx/ooxml.md | 610 +++ .../schemas/ISO-IEC29500-4_2016/dml-chart.xsd | 1499 ++++++ .../ISO-IEC29500-4_2016/dml-chartDrawing.xsd | 146 + .../ISO-IEC29500-4_2016/dml-diagram.xsd | 1085 ++++ .../ISO-IEC29500-4_2016/dml-lockedCanvas.xsd | 11 + .../schemas/ISO-IEC29500-4_2016/dml-main.xsd | 3081 ++++++++++++ .../ISO-IEC29500-4_2016/dml-picture.xsd | 23 + .../dml-spreadsheetDrawing.xsd | 185 + .../dml-wordprocessingDrawing.xsd | 287 ++ .../ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd | 1676 +++++++ .../shared-additionalCharacteristics.xsd | 28 + .../shared-bibliography.xsd | 144 + .../shared-commonSimpleTypes.xsd | 174 + .../shared-customXmlDataProperties.xsd | 25 + .../shared-customXmlSchemaProperties.xsd | 18 + .../shared-documentPropertiesCustom.xsd | 59 + .../shared-documentPropertiesExtended.xsd | 56 + .../shared-documentPropertiesVariantTypes.xsd | 195 + .../ISO-IEC29500-4_2016/shared-math.xsd | 582 +++ .../shared-relationshipReference.xsd | 25 + .../ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd | 4439 +++++++++++++++++ .../schemas/ISO-IEC29500-4_2016/vml-main.xsd | 570 +++ .../ISO-IEC29500-4_2016/vml-officeDrawing.xsd | 509 ++ .../vml-presentationDrawing.xsd | 12 + .../vml-spreadsheetDrawing.xsd | 108 + .../vml-wordprocessingDrawing.xsd | 96 + .../ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd | 3646 ++++++++++++++ .../ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd | 116 + .../ecma/fouth-edition/opc-contentTypes.xsd | 42 + .../ecma/fouth-edition/opc-coreProperties.xsd | 50 + .../schemas/ecma/fouth-edition/opc-digSig.xsd | 49 + .../ecma/fouth-edition/opc-relationships.xsd | 33 + docx/ooxml/schemas/mce/mc.xsd | 75 + docx/ooxml/schemas/microsoft/wml-2010.xsd | 560 +++ docx/ooxml/schemas/microsoft/wml-2012.xsd | 67 + docx/ooxml/schemas/microsoft/wml-2018.xsd | 14 + docx/ooxml/schemas/microsoft/wml-cex-2018.xsd | 20 + docx/ooxml/schemas/microsoft/wml-cid-2016.xsd | 13 + .../microsoft/wml-sdtdatahash-2020.xsd | 4 + .../schemas/microsoft/wml-symex-2015.xsd | 8 + docx/ooxml/scripts/pack.py | 159 + docx/ooxml/scripts/unpack.py | 29 + docx/ooxml/scripts/validate.py | 69 + docx/ooxml/scripts/validation/__init__.py | 15 + docx/ooxml/scripts/validation/base.py | 951 ++++ docx/ooxml/scripts/validation/docx.py | 274 + docx/ooxml/scripts/validation/pptx.py | 315 ++ docx/ooxml/scripts/validation/redlining.py | 279 ++ docx/scripts/__init__.py | 1 + docx/scripts/document.py | 1276 +++++ docx/scripts/templates/comments.xml | 3 + docx/scripts/templates/commentsExtended.xml | 3 + docx/scripts/templates/commentsExtensible.xml | 3 + docx/scripts/templates/commentsIds.xml | 3 + docx/scripts/templates/people.xml | 3 + docx/scripts/utilities.py | 374 ++ financial-report-writing/SKILL.md | 685 +++ .../references/best_practices.md | 337 ++ .../scripts/analysis_engine.py | 469 ++ .../scripts/chart_utils.py | 311 ++ .../scripts/data_fetcher.py | 265 + .../scripts/document_formatter.py | 377 ++ .../scripts/generate_report.py | 313 ++ find-skills/SKILL.md | 133 + fund-slides/LICENSE | 22 + fund-slides/README.md | 120 + fund-slides/SKILL.md | 307 ++ fund-slides/STYLE_PRESETS.md | 559 +++ fund-slides/content-mapping.md | 211 + fund-slides/references/animation-patterns.md | 204 + fund-slides/references/charts-base.md | 226 + fund-slides/references/charts-composition.md | 236 + fund-slides/references/charts-flow.md | 233 + fund-slides/references/charts-matrix.md | 146 + fund-slides/references/charts-trend.md | 178 + fund-slides/references/echarts.min.js | 45 + fund-slides/references/financial-layouts.md | 580 +++ fund-slides/references/html-template.md | 417 ++ .../references/safe-base-template.html | 297 ++ fund-slides/references/viewport-base.css | 210 + fund-slides/scripts/extract-pptx.py | 96 + gangtise/SKILL.md | 299 ++ humanizer-zh/SKILL.md | 140 + .../references/communication-patterns-zh.md | 75 + .../references/content-patterns-zh.md | 83 + humanizer-zh/references/formal-writing-zh.md | 105 + humanizer-zh/references/full-example-zh.md | 51 + .../references/language-patterns-zh.md | 75 + humanizer-zh/references/style-patterns-zh.md | 57 + ifind-http-api/SKILL.md | 896 ++++ ifind-http-api/references/error-codes.md | 77 + .../history-quotation-indicators.md | 101 + .../references/pension-db-schema.md | 101 + .../references/pension-fund-products.md | 339 ++ .../references/technical-indicators.md | 117 + ifind-http-api/scripts/build_pension_db.py | 380 ++ ifind-http-api/scripts/query_pension.py | 388 ++ pdf/LICENSE.txt | 30 + pdf/SKILL.md | 340 ++ pdf/forms.md | 205 + pdf/reference.md | 612 +++ pdf/scripts/check_bounding_boxes.py | 70 + pdf/scripts/check_bounding_boxes_test.py | 226 + pdf/scripts/check_fillable_fields.py | 12 + pdf/scripts/convert_pdf_to_images.py | 35 + pdf/scripts/create_validation_image.py | 41 + pdf/scripts/extract_form_field_info.py | 152 + pdf/scripts/fill_fillable_fields.py | 114 + pdf/scripts/fill_pdf_form_with_annotations.py | 108 + plotly/SKILL.md | 261 + plotly/reference/chart-types.md | 488 ++ plotly/reference/export-interactivity.md | 453 ++ plotly/reference/graph-objects.md | 302 ++ plotly/reference/layouts-styling.md | 457 ++ plotly/reference/plotly-express.md | 213 + portfolio-analyzer/SKILL.md | 369 ++ .../references/data-loading-guide.md | 256 + .../references/risk-metrics-formulas.md | 336 ++ .../references/shenwan-industry-codes.md | 103 + .../scripts/portfolio_analyzer.py | 713 +++ ppt-station-skill/README.md | 195 + ppt-station-skill/SKILL.md | 361 ++ ppt-station-skill/data/data_drawdown.csv | 21 + ppt-station-skill/data/data_returns_vol.csv | 21 + ppt-station-skill/data/data_risk_table.csv | 11 + ppt-station-skill/data/data_sharpe.csv | 21 + ppt-station-skill/designer-brief.md | 227 + ppt-station-skill/difference.md | 86 + ppt-station-skill/ppt_station/__init__.py | 12 + .../ppt_station/chart_builder/__init__.py | 149 + .../ppt_station/chart_builder/api.py | 364 ++ .../ppt_station/chart_builder/builder.py | 317 ++ .../ppt_station/chart_builder/cleaner.py | 144 + .../ppt_station/chart_builder/date_axis.py | 587 +++ .../ppt_station/chart_builder/layout.py | 534 ++ .../chart_builder/oxml/__init__.py | 22 + .../ppt_station/chart_builder/oxml/axes.py | 215 + .../ppt_station/chart_builder/oxml/plots.py | 227 + .../ppt_station/chart_builder/oxml/series.py | 424 ++ .../ppt_station/chart_builder/oxml_ns.py | 8 + .../ppt_station/chart_builder/parser.py | 627 +++ .../ppt_station/chart_builder/styles.py | 333 ++ .../ppt_station/composer/__init__.py | 7 + .../ppt_station/composer/blocks.py | 547 ++ .../ppt_station/composer/helpers.py | 535 ++ .../ppt_station/composer/layouts/__init__.py | 37 + .../ppt_station/composer/layouts/chart.py | 341 ++ .../composer/layouts/conclusion.py | 135 + .../ppt_station/composer/layouts/content.py | 147 + .../ppt_station/composer/layouts/diagram.py | 146 + .../composer/layouts/image_text.py | 123 + .../ppt_station/composer/layouts/kpi.py | 92 + .../ppt_station/composer/layouts/table.py | 56 + .../ppt_station/composer/layouts/title.py | 99 + .../ppt_station/composer/page_composer.py | 160 + .../composer/template_assembler.py | 337 ++ .../ppt_station/composer/themes.py | 294 ++ ppt-station-skill/ppt_station/config.py | 49 + .../ppt_station/connectors/__init__.py | 16 + .../ppt_station/connectors/base.py | 43 + .../ppt_station/connectors/csv_connector.py | 61 + .../connectors/tushare_connector.py | 92 + ppt-station-skill/ppt_station/engine.py | 308 ++ .../ppt_station/models/__init__.py | 26 + ppt-station-skill/ppt_station/models/job.py | 176 + .../ppt_station/parsers/__init__.py | 6 + .../ppt_station/parsers/ppt_parser.py | 256 + ppt-station-skill/ppt_station/qa/__init__.py | 3 + .../ppt_station/qa/deck_linter.py | 298 ++ .../ppt_station/renderers/__init__.py | 9 + .../ppt_station/renderers/ppt_renderer.py | 339 ++ .../ppt_station/renderers/table_renderer.py | 72 + .../ppt_station/renderers/text_renderer.py | 46 + .../ppt_station/template/__init__.py | 6 + .../ppt_station/template/chart_presets.py | 309 ++ .../ppt_station/template/replacer.py | 566 +++ .../ppt_station/transformers/__init__.py | 8 + .../ppt_station/transformers/dataframe_ops.py | 83 + .../ppt_station/utils/__init__.py | 8 + .../ppt_station/utils/template_utils.py | 37 + ppt-station-skill/reference/api-contracts.md | 444 ++ ppt-station-skill/reference/chart-config.md | 175 + .../reference/connectors-transforms.md | 157 + ppt-station-skill/reference/design-rules.md | 197 + ppt-station-skill/reference/design-themes.md | 475 ++ .../institutional-design-analysis.md | 1143 +++++ ppt-station-skill/reference/job-schema.md | 438 ++ ppt-station-skill/reference/layout-agenda.md | 244 + .../reference/layout-chart-table.md | 304 ++ .../reference/layout-comparison-cards.md | 264 + .../reference/layout-dashboard.md | 392 ++ .../reference/layout-highlight-number.md | 193 + .../reference/layout-icon-grid.md | 262 + .../reference/layout-image-text.md | 290 ++ .../reference/layout-progress-bars.md | 270 + ppt-station-skill/reference/layout-quote.md | 222 + .../reference/layout-three-columns.md | 281 ++ .../reference/layout-timeline.md | 184 + .../reference/layout-waterfall.md | 292 ++ .../reference/placeholder-syntax.md | 70 + .../reference/workflow-engine.md | 111 + .../reference/workflow-parse-rebuild.md | 80 + .../reference/workflow-template.md | 107 + .../reference/workflow-tushare.md | 105 + ppt-station-skill/scripts/add_placeholders.py | 65 + ppt-station-skill/scripts/describe_chart.py | 118 + ppt-station-skill/scripts/fetch_data.py | 105 + ppt-station-skill/scripts/gen_anker_report.py | 412 ++ .../scripts/gen_moutai_report.py | 338 ++ ppt-station-skill/scripts/gen_moutai_risk.py | 248 + ppt-station-skill/scripts/generate_ppt.py | 188 + ppt-station-skill/scripts/list_presets.py | 78 + ppt-station-skill/scripts/parse_ppt.py | 49 + ppt-station-skill/scripts/parse_template.py | 45 + ppt-station-skill/scripts/rebuild_ppt.py | 43 + ppt-station-skill/scripts/render_ppt.py | 75 + ppt-station-skill/scripts/run_job.py | 78 + ppt-station-skill/scripts/validate_job.py | 124 + .../tests/test_describe_chart.sh | 36 + ppt-station-skill/tests/test_generate_ppt.sh | 55 + ppt-station-skill/tests/test_parse_rebuild.sh | 51 + .../tests/test_parse_template.sh | 36 + ppt-station-skill/tests/test_run_job.sh | 68 + pptx/LICENSE.txt | 30 + pptx/SKILL.md | 512 ++ pptx/html2pptx.md | 625 +++ pptx/ooxml.md | 427 ++ .../schemas/ISO-IEC29500-4_2016/dml-chart.xsd | 1499 ++++++ .../ISO-IEC29500-4_2016/dml-chartDrawing.xsd | 146 + .../ISO-IEC29500-4_2016/dml-diagram.xsd | 1085 ++++ .../ISO-IEC29500-4_2016/dml-lockedCanvas.xsd | 11 + .../schemas/ISO-IEC29500-4_2016/dml-main.xsd | 3081 ++++++++++++ .../ISO-IEC29500-4_2016/dml-picture.xsd | 23 + .../dml-spreadsheetDrawing.xsd | 185 + .../dml-wordprocessingDrawing.xsd | 287 ++ .../ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd | 1676 +++++++ .../shared-additionalCharacteristics.xsd | 28 + .../shared-bibliography.xsd | 144 + .../shared-commonSimpleTypes.xsd | 174 + .../shared-customXmlDataProperties.xsd | 25 + .../shared-customXmlSchemaProperties.xsd | 18 + .../shared-documentPropertiesCustom.xsd | 59 + .../shared-documentPropertiesExtended.xsd | 56 + .../shared-documentPropertiesVariantTypes.xsd | 195 + .../ISO-IEC29500-4_2016/shared-math.xsd | 582 +++ .../shared-relationshipReference.xsd | 25 + .../ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd | 4439 +++++++++++++++++ .../schemas/ISO-IEC29500-4_2016/vml-main.xsd | 570 +++ .../ISO-IEC29500-4_2016/vml-officeDrawing.xsd | 509 ++ .../vml-presentationDrawing.xsd | 12 + .../vml-spreadsheetDrawing.xsd | 108 + .../vml-wordprocessingDrawing.xsd | 96 + .../ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd | 3646 ++++++++++++++ .../ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd | 116 + .../ecma/fouth-edition/opc-contentTypes.xsd | 42 + .../ecma/fouth-edition/opc-coreProperties.xsd | 50 + .../schemas/ecma/fouth-edition/opc-digSig.xsd | 49 + .../ecma/fouth-edition/opc-relationships.xsd | 33 + pptx/ooxml/schemas/mce/mc.xsd | 75 + pptx/ooxml/schemas/microsoft/wml-2010.xsd | 560 +++ pptx/ooxml/schemas/microsoft/wml-2012.xsd | 67 + pptx/ooxml/schemas/microsoft/wml-2018.xsd | 14 + pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd | 20 + pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd | 13 + .../microsoft/wml-sdtdatahash-2020.xsd | 4 + .../schemas/microsoft/wml-symex-2015.xsd | 8 + pptx/ooxml/scripts/pack.py | 159 + pptx/ooxml/scripts/unpack.py | 29 + pptx/ooxml/scripts/validate.py | 69 + pptx/ooxml/scripts/validation/__init__.py | 15 + pptx/ooxml/scripts/validation/base.py | 951 ++++ pptx/ooxml/scripts/validation/docx.py | 274 + pptx/ooxml/scripts/validation/pptx.py | 315 ++ pptx/ooxml/scripts/validation/redlining.py | 279 ++ pptx/scripts/html2pptx.js | 979 ++++ pptx/scripts/inventory.py | 1020 ++++ pptx/scripts/rearrange.py | 231 + pptx/scripts/replace.py | 385 ++ pptx/scripts/thumbnail.py | 450 ++ skill-creator/LICENSE.txt | 202 + skill-creator/SKILL.md | 357 ++ skill-creator/references/output-patterns.md | 82 + skill-creator/references/workflows.md | 28 + skill-creator/scripts/init_skill.py | 303 ++ skill-creator/scripts/package_skill.py | 110 + skill-creator/scripts/quick_validate.py | 103 + technical-analyst/SKILL.md | 238 + technical-analyst/assets/analysis_template.md | 183 + .../technical_analysis_framework.md | 282 ++ tushare-data-1.0.5/SKILL.md | 68 + tushare-data-1.0.5/_meta.json | 6 + tushare-data-1.0.5/references/使用tushare.md | 165 + tushare-data-1.0.5/references/安装tushare.md | 36 + .../数据接口/ETF专题/ETF份额规模.md | 61 + .../数据接口/ETF专题/ETF分钟行情.md | 84 + .../数据接口/ETF专题/ETF基准指数.md | 63 + .../数据接口/ETF专题/ETF基本信息.md | 109 + .../数据接口/ETF专题/ETF复权因子.md | 82 + .../数据接口/ETF专题/ETF实时日线.md | 77 + .../数据接口/ETF专题/ETF日线行情.md | 75 + .../数据接口/债券专题/债券回购日行情.md | 106 + .../数据接口/债券专题/全球财经事件.md | 100 + .../数据接口/债券专题/可转债发行.md | 100 + .../数据接口/债券专题/可转债基础信息.md | 89 + .../债券专题/可转债技术面因子(专业版).md | 143 + .../数据接口/债券专题/可转债票面利率.md | 58 + .../数据接口/债券专题/可转债行情.md | 111 + .../数据接口/债券专题/可转债赎回信息.md | 63 + .../数据接口/债券专题/可转债转股价变动.md | 51 + .../数据接口/债券专题/可转债转股结果.md | 74 + .../数据接口/债券专题/国债收益率曲线.md | 67 + .../references/数据接口/债券专题/大宗交易.md | 67 + .../数据接口/债券专题/大宗交易明细.md | 67 + .../数据接口/债券专题/柜台流通式债券报价.md | 63 + .../债券专题/柜台流通式债券最优报价.md | 57 + .../references/数据接口/公募基金/基金净值.md | 58 + .../references/数据接口/公募基金/基金分红.md | 70 + .../references/数据接口/公募基金/基金列表.md | 69 + .../公募基金/基金技术面因子(专业版).md | 113 + .../references/数据接口/公募基金/基金持仓.md | 71 + .../数据接口/公募基金/基金管理人.md | 60 + .../references/数据接口/公募基金/基金经理.md | 65 + .../references/数据接口/公募基金/基金规模.md | 72 + .../数据接口/另类数据/上市公司公告.md | 63 + .../数据接口/另类数据/新闻联播文字稿.md | 74 + .../数据接口/外汇数据/外汇基础信息(海外).md | 87 + .../数据接口/外汇数据/外汇日线行情.md | 107 + .../大模型语料专题数据/上证e互动问答.md | 72 + .../数据接口/大模型语料专题数据/国家政策库.md | 68 + .../大模型语料专题数据/新闻快讯(短讯).md | 76 + .../大模型语料专题数据/新闻通讯(长篇).md | 70 + .../大模型语料专题数据/深证易互动问答.md | 82 + .../数据接口/宏观经济/国内宏观/价格指数.md | 8 + .../国内宏观/价格指数/居民消费价格指数(CPI).md | 77 + .../价格指数/工业生产者出厂价格指数(PPI).md | 90 + .../数据接口/宏观经济/国内宏观/利率数据.md | 11 + .../宏观经济/国内宏观/利率数据/Hibor利率.md | 100 + .../宏观经济/国内宏观/利率数据/LPR贷款基础利率.md | 78 + .../宏观经济/国内宏观/利率数据/Libor利率.md | 102 + .../宏观经济/国内宏观/利率数据/Shibor利率.md | 85 + .../宏观经济/国内宏观/利率数据/Shibor报价数据.md | 106 + .../国内宏观/利率数据/广州民间借贷利率.md | 74 + .../国内宏观/利率数据/温州民间借贷利率.md | 107 + .../数据接口/宏观经济/国内宏观/国民经济.md | 7 + .../国内宏观/国民经济/国内生产总值(GDP).md | 72 + .../国内宏观/景气度/采购经理指数(PMI).md | 112 + .../国内宏观/金融/社会融资/社融增量(月度).md | 76 + .../国内宏观/金融/货币供应量/货币供应量(月).md | 63 + .../数据接口/宏观经济/国际宏观/美国利率.md | 5 + .../国际宏观/美国利率/国债实际收益率曲线利率.md | 69 + .../国际宏观/美国利率/国债收益率曲线利率.md | 81 + .../宏观经济/国际宏观/美国利率/国债长期利率.md | 65 + .../国际宏观/美国利率/国债长期利率平均值.md | 65 + .../宏观经济/国际宏观/美国利率/短期国债利率.md | 79 + .../数据接口/指数专题/中信行业成分.md | 124 + .../数据接口/指数专题/中信行业指数日行情.md | 73 + .../数据接口/指数专题/国际主要指数.md | 120 + .../数据接口/指数专题/大盘指数每日指标.md | 62 + .../references/数据接口/指数专题/实时日线.md | 63 + .../数据接口/指数专题/指数周线行情.md | 96 + .../数据接口/指数专题/指数基本信息.md | 102 + .../数据接口/指数专题/指数成分和权重.md | 52 + .../指数专题/指数技术面因子(专业版).md | 112 + .../数据接口/指数专题/指数日线行情.md | 82 + .../数据接口/指数专题/指数月线行情.md | 97 + .../数据接口/指数专题/沪深市场每日交易统计.md | 116 + .../数据接口/指数专题/深圳市场每日交易情况.md | 101 + .../数据接口/指数专题/申万行业分类.md | 614 +++ .../数据接口/指数专题/申万行业成分(分级).md | 82 + .../数据接口/指数专题/申万行业指数日行情.md | 73 + .../数据接口/期权数据/期权分钟行情.md | 85 + .../数据接口/期权数据/期权合约信息.md | 86 + .../数据接口/期权数据/期权日线行情.md | 73 + .../references/数据接口/期货数据/交易日历.md | 108 + .../references/数据接口/期货数据/仓单日报.md | 78 + .../数据接口/期货数据/南华期货指数行情.md | 141 + .../数据接口/期货数据/历史Tick行情.md | 37 + .../数据接口/期货数据/历史分钟行情.md | 87 + .../references/数据接口/期货数据/合约信息.md | 78 + .../数据接口/期货数据/实时分钟行情.md | 83 + .../references/数据接口/期货数据/日线行情.md | 127 + .../数据接口/期货数据/期货主力与连续合约.md | 75 + .../数据接口/期货数据/期货主要品种交易周报.md | 139 + .../数据接口/期货数据/期货合约涨跌停价格.md | 75 + .../期货数据/期货周-月线行情(每日更新).md | 42 + .../数据接口/期货数据/每日持仓排名.md | 92 + .../数据接口/期货数据/每日结算参数.md | 117 + .../数据接口/港股数据/港股交易日历.md | 62 + .../数据接口/港股数据/港股分钟行情.md | 83 + .../数据接口/港股数据/港股利润表.md | 85 + .../数据接口/港股数据/港股基础信息.md | 84 + .../数据接口/港股数据/港股复权因子.md | 68 + .../数据接口/港股数据/港股复权行情.md | 86 + .../数据接口/港股数据/港股实时日线.md | 71 + .../数据接口/港股数据/港股日线行情.md | 86 + .../数据接口/港股数据/港股现金流量表.md | 110 + .../数据接口/港股数据/港股财务指标数据.md | 153 + .../数据接口/港股数据/港股资产负债表.md | 112 + .../数据接口/现货数据/上海黄金基础信息.md | 68 + .../数据接口/现货数据/上海黄金现货日行情.md | 85 + .../数据接口/美股数据/美股交易日历.md | 62 + .../数据接口/美股数据/美股利润表.md | 73 + .../数据接口/美股数据/美股基础信息.md | 68 + .../数据接口/美股数据/美股复权因子.md | 70 + .../数据接口/美股数据/美股复权行情.md | 86 + .../数据接口/美股数据/美股日线行情.md | 77 + .../数据接口/美股数据/美股现金流量表.md | 77 + .../数据接口/美股数据/美股财务指标数据.md | 138 + .../数据接口/美股数据/美股资产负债表.md | 74 + .../股票数据/两融及转融通/做市借券交易汇总(停).md | 66 + .../股票数据/两融及转融通/融资融券交易明细.md | 126 + .../股票数据/两融及转融通/融资融券交易汇总.md | 82 + .../股票数据/两融及转融通/融资融券标的(盘前).md | 67 + .../股票数据/两融及转融通/转融券交易明细(停).md | 66 + .../股票数据/两融及转融通/转融券交易汇总(停).md | 67 + .../股票数据/两融及转融通/转融资交易汇总.md | 66 + .../股票数据/参考数据/前十大流通股东.md | 64 + .../数据接口/股票数据/参考数据/前十大股东.md | 65 + .../数据接口/股票数据/参考数据/大宗交易.md | 94 + .../数据接口/股票数据/参考数据/股东人数.md | 68 + .../数据接口/股票数据/参考数据/股东增减持.md | 92 + .../股票数据/参考数据/股权质押明细数据.md | 64 + .../股票数据/参考数据/股权质押统计数据.md | 67 + .../数据接口/股票数据/参考数据/股票回购.md | 77 + .../股票数据/参考数据/股票开户数据(停).md | 80 + .../股票数据/参考数据/股票开户数据(旧).md | 101 + .../数据接口/股票数据/参考数据/限售股解禁.md | 99 + .../数据接口/股票数据/基础数据/IPO新股上市.md | 74 + .../数据接口/股票数据/基础数据/ST股票列表.md | 66 + .../股票数据/基础数据/上市公司基本信息.md | 71 + .../股票数据/基础数据/上市公司管理层.md | 87 + .../数据接口/股票数据/基础数据/交易日历.md | 68 + .../股票数据/基础数据/北交所新旧代码对照.md | 55 + .../股票数据/基础数据/每日股本(盘前).md | 68 + .../股票数据/基础数据/沪深港通股票列表.md | 79 + .../股票数据/基础数据/管理层薪酬和持股.md | 75 + .../数据接口/股票数据/基础数据/股票列表.md | 91 + .../股票数据/基础数据/股票历史列表.md | 68 + .../数据接口/股票数据/基础数据/股票曾用名.md | 46 + .../股票数据/打板专题数据/东方财富App热榜.md | 77 + .../股票数据/打板专题数据/东方财富概念成分.md | 65 + .../股票数据/打板专题数据/东方财富概念板块.md | 73 + .../打板专题数据/东财概念和行业指数行情.md | 75 + .../股票数据/打板专题数据/同花顺App热榜数.md | 80 + .../打板专题数据/同花顺概念和行业指数行情.md | 74 + .../股票数据/打板专题数据/同花顺涨跌停榜单.md | 82 + .../股票数据/打板专题数据/同花顺行业概念成分.md | 68 + .../股票数据/打板专题数据/同花顺行业概念板块.md | 66 + .../股票数据/打板专题数据/市场游资最全名录.md | 141 + .../股票数据/打板专题数据/开盘竞价成交(当日).md | 70 + .../股票数据/打板专题数据/榜单数据(开盘啦).md | 86 + .../股票数据/打板专题数据/涨停最强板块统计.md | 76 + .../股票数据/打板专题数据/涨停股票连板天梯.md | 100 + .../股票数据/打板专题数据/涨跌停和炸板数据.md | 76 + .../股票数据/打板专题数据/游资交易每日明细.md | 61 + .../股票数据/打板专题数据/通达信板块信息.md | 70 + .../股票数据/打板专题数据/通达信板块成分.md | 63 + .../股票数据/打板专题数据/通达信板块行情.md | 98 + .../股票数据/打板专题数据/题材成分(开盘啦).md | 69 + .../股票数据/打板专题数据/题材数据(开盘啦).md | 65 + .../股票数据/打板专题数据/龙虎榜机构交易单.md | 76 + .../股票数据/打板专题数据/龙虎榜每日统计单.md | 136 + .../数据接口/股票数据/特色数据/AH股比价.md | 74 + .../股票数据/特色数据/中央结算系统持股明细.md | 63 + .../股票数据/特色数据/中央结算系统持股统计.md | 60 + .../股票数据/特色数据/券商月度金股.md | 49 + .../股票数据/特色数据/券商盈利预测数据.md | 80 + .../股票数据/特色数据/机构调研数据.md | 66 + .../股票数据/特色数据/每日筹码分布.md | 64 + .../股票数据/特色数据/每日筹码及胜率.md | 70 + .../股票数据/特色数据/沪深股通持股明细.md | 90 + .../股票数据/特色数据/神奇九转指标.md | 73 + .../股票数据/特色数据/股票开盘集合竞价数据.md | 66 + .../股票数据/特色数据/股票技术面因子(专业版).md | 284 ++ .../股票数据/特色数据/股票技术面因子.md | 94 + .../股票数据/特色数据/股票收盘集合竞价数据.md | 67 + .../数据接口/股票数据/行情数据/历史分钟.md | 85 + .../数据接口/股票数据/行情数据/历史日线.md | 80 + .../行情数据/周-月线复权行情(每日更新).md | 77 + .../股票数据/行情数据/周-月线行情(每日更新).md | 74 + .../数据接口/股票数据/行情数据/周线行情.md | 103 + .../数据接口/股票数据/行情数据/备用行情.md | 80 + .../数据接口/股票数据/行情数据/复权因子.md | 75 + .../数据接口/股票数据/行情数据/复权行情.md | 85 + .../股票数据/行情数据/实时Tick(爬虫).md | 100 + .../数据接口/股票数据/行情数据/实时分钟.md | 65 + .../股票数据/行情数据/实时成交(爬虫).md | 74 + .../股票数据/行情数据/实时排名(爬虫).md | 96 + .../数据接口/股票数据/行情数据/实时日线.md | 81 + .../数据接口/股票数据/行情数据/月线行情.md | 102 + .../股票数据/行情数据/每日停复牌信息.md | 70 + .../数据接口/股票数据/行情数据/每日指标.md | 83 + .../股票数据/行情数据/每日涨跌停价格.md | 82 + .../股票数据/行情数据/沪深股通十大成交股.md | 74 + .../股票数据/行情数据/港股通十大成交股.md | 123 + .../股票数据/行情数据/港股通每日成交统计.md | 83 + .../股票数据/行情数据/港股通每月成交统计.md | 83 + .../股票数据/行情数据/通用行情接口.md | 127 + .../数据接口/股票数据/财务数据/业绩快报.md | 83 + .../数据接口/股票数据/财务数据/业绩预告.md | 80 + .../股票数据/财务数据/主营业务构成.md | 59 + .../股票数据/财务数据/分红送股数据.md | 71 + .../数据接口/股票数据/财务数据/利润表.md | 168 + .../数据接口/股票数据/财务数据/现金流量表.md | 174 + .../股票数据/财务数据/财务审计意见.md | 53 + .../股票数据/财务数据/财务指标数据.md | 224 + .../股票数据/财务数据/财报披露日期表.md | 61 + .../数据接口/股票数据/财务数据/资产负债表.md | 230 + .../股票数据/资金流向数据/个股资金流向.md | 127 + .../股票数据/资金流向数据/个股资金流向(DC).md | 77 + .../股票数据/资金流向数据/个股资金流向(THS).md | 68 + .../股票数据/资金流向数据/大盘资金流向(DC).md | 79 + .../股票数据/资金流向数据/板块资金流向(THS).md | 71 + .../股票数据/资金流向数据/板块资金流向(DC).md | 80 + .../股票数据/资金流向数据/沪深港通资金流向.md | 69 + .../股票数据/资金流向数据/行业资金流向(THS).md | 73 + .../各渠道公募基金销售保有规模占比.md | 57 + .../基金销售行业数据/销售机构公募基金销售保有规模.md | 80 + tushare-data-1.0.5/references/目录索引.md | 282 ++ .../scripts/fund_data_example.py | 88 + .../scripts/stock_data_example.py | 89 + windpy-sdk/SKILL.md | 565 +++ windpy-sdk/references/README.md | 368 ++ windpy-sdk/references/asset-type-codes.md | 212 + windpy-sdk/references/bond-fields.md | 295 ++ windpy-sdk/references/edb-indicators.md | 215 + windpy-sdk/references/error-codes.md | 61 + windpy-sdk/references/field-catalog.md | 275 + windpy-sdk/references/fund-fields.md | 239 + windpy-sdk/references/future-fields.md | 178 + windpy-sdk/references/fx-fields.md | 90 + windpy-sdk/references/options-cheatsheet.md | 160 + windpy-sdk/references/options-fields.md | 117 + windpy-sdk/references/sector-ids.md | 138 + windpy-sdk/references/sectorid-catalog.md | 420 ++ windpy-sdk/references/technical-indicators.md | 93 + windpy-sdk/references/wset-tables.md | 167 + windpy-sdk/scripts/setup_windpy.py | 353 ++ windpy-sdk/scripts/wind_client.py | 286 ++ windpy-sdk/scripts/wind_client_win.py | 164 + windpy-sdk/scripts/wind_server.py | 341 ++ windpy-sdk/scripts/wind_server_win.py | 150 + xlsx/LICENSE.txt | 30 + xlsx/SKILL.md | 292 ++ xlsx/recalc.py | 178 + zhipu-websearch/SKILL.md | 226 + 572 files changed, 118507 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 agentrs-map/SKILL.md create mode 100644 agentrs-map/scripts/amap.py create mode 100644 agentrs-search/SKILL.md create mode 100644 agentrs-search/scripts/search.py create mode 100644 agentrs-weather/SKILL.md create mode 100644 agentrs-weather/scripts/weather.py create mode 100644 ai-pair/.gitignore create mode 100644 ai-pair/LICENSE create mode 100644 ai-pair/README.md create mode 100644 ai-pair/SKILL.md create mode 100644 ai-pair/examples/content-team.md create mode 100644 ai-pair/examples/dev-team.md create mode 100644 annuity-disclosure-crawler/SKILL.md create mode 100644 annuity-disclosure-crawler/references/registry.json create mode 100755 annuity-disclosure-crawler/scripts/crawl.py create mode 100755 annuity-disclosure-crawler/scripts/crawl_headless.py create mode 100644 asset-monitor/SKILL.md create mode 100644 asset-monitor/references/monitor-config-example.json create mode 100644 asset-monitor/scripts/monitor.py create mode 100644 docx-cn/SKILL.md create mode 100644 docx-cn/scripts/gongwen_constants.js create mode 100644 docx/LICENSE.txt create mode 100644 docx/SKILL.md create mode 100644 docx/docx-js.md create mode 100644 docx/ooxml.md create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd create mode 100644 docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd create mode 100644 docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd create mode 100644 docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd create mode 100644 docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd create mode 100644 docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd create mode 100644 docx/ooxml/schemas/mce/mc.xsd create mode 100644 docx/ooxml/schemas/microsoft/wml-2010.xsd create mode 100644 docx/ooxml/schemas/microsoft/wml-2012.xsd create mode 100644 docx/ooxml/schemas/microsoft/wml-2018.xsd create mode 100644 docx/ooxml/schemas/microsoft/wml-cex-2018.xsd create mode 100644 docx/ooxml/schemas/microsoft/wml-cid-2016.xsd create mode 100644 docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd create mode 100644 docx/ooxml/schemas/microsoft/wml-symex-2015.xsd create mode 100755 docx/ooxml/scripts/pack.py create mode 100755 docx/ooxml/scripts/unpack.py create mode 100755 docx/ooxml/scripts/validate.py create mode 100644 docx/ooxml/scripts/validation/__init__.py create mode 100644 docx/ooxml/scripts/validation/base.py create mode 100644 docx/ooxml/scripts/validation/docx.py create mode 100644 docx/ooxml/scripts/validation/pptx.py create mode 100644 docx/ooxml/scripts/validation/redlining.py create mode 100755 docx/scripts/__init__.py create mode 100755 docx/scripts/document.py create mode 100644 docx/scripts/templates/comments.xml create mode 100644 docx/scripts/templates/commentsExtended.xml create mode 100644 docx/scripts/templates/commentsExtensible.xml create mode 100644 docx/scripts/templates/commentsIds.xml create mode 100644 docx/scripts/templates/people.xml create mode 100755 docx/scripts/utilities.py create mode 100644 financial-report-writing/SKILL.md create mode 100644 financial-report-writing/references/best_practices.md create mode 100644 financial-report-writing/scripts/analysis_engine.py create mode 100644 financial-report-writing/scripts/chart_utils.py create mode 100644 financial-report-writing/scripts/data_fetcher.py create mode 100644 financial-report-writing/scripts/document_formatter.py create mode 100644 financial-report-writing/scripts/generate_report.py create mode 100644 find-skills/SKILL.md create mode 100644 fund-slides/LICENSE create mode 100644 fund-slides/README.md create mode 100644 fund-slides/SKILL.md create mode 100644 fund-slides/STYLE_PRESETS.md create mode 100644 fund-slides/content-mapping.md create mode 100644 fund-slides/references/animation-patterns.md create mode 100644 fund-slides/references/charts-base.md create mode 100644 fund-slides/references/charts-composition.md create mode 100644 fund-slides/references/charts-flow.md create mode 100644 fund-slides/references/charts-matrix.md create mode 100644 fund-slides/references/charts-trend.md create mode 100644 fund-slides/references/echarts.min.js create mode 100644 fund-slides/references/financial-layouts.md create mode 100644 fund-slides/references/html-template.md create mode 100644 fund-slides/references/safe-base-template.html create mode 100644 fund-slides/references/viewport-base.css create mode 100644 fund-slides/scripts/extract-pptx.py create mode 100644 gangtise/SKILL.md create mode 100644 humanizer-zh/SKILL.md create mode 100644 humanizer-zh/references/communication-patterns-zh.md create mode 100644 humanizer-zh/references/content-patterns-zh.md create mode 100644 humanizer-zh/references/formal-writing-zh.md create mode 100644 humanizer-zh/references/full-example-zh.md create mode 100644 humanizer-zh/references/language-patterns-zh.md create mode 100644 humanizer-zh/references/style-patterns-zh.md create mode 100644 ifind-http-api/SKILL.md create mode 100644 ifind-http-api/references/error-codes.md create mode 100644 ifind-http-api/references/history-quotation-indicators.md create mode 100644 ifind-http-api/references/pension-db-schema.md create mode 100644 ifind-http-api/references/pension-fund-products.md create mode 100644 ifind-http-api/references/technical-indicators.md create mode 100644 ifind-http-api/scripts/build_pension_db.py create mode 100644 ifind-http-api/scripts/query_pension.py create mode 100644 pdf/LICENSE.txt create mode 100644 pdf/SKILL.md create mode 100644 pdf/forms.md create mode 100644 pdf/reference.md create mode 100644 pdf/scripts/check_bounding_boxes.py create mode 100644 pdf/scripts/check_bounding_boxes_test.py create mode 100644 pdf/scripts/check_fillable_fields.py create mode 100644 pdf/scripts/convert_pdf_to_images.py create mode 100644 pdf/scripts/create_validation_image.py create mode 100644 pdf/scripts/extract_form_field_info.py create mode 100644 pdf/scripts/fill_fillable_fields.py create mode 100644 pdf/scripts/fill_pdf_form_with_annotations.py create mode 100755 plotly/SKILL.md create mode 100755 plotly/reference/chart-types.md create mode 100755 plotly/reference/export-interactivity.md create mode 100755 plotly/reference/graph-objects.md create mode 100755 plotly/reference/layouts-styling.md create mode 100755 plotly/reference/plotly-express.md create mode 100644 portfolio-analyzer/SKILL.md create mode 100644 portfolio-analyzer/references/data-loading-guide.md create mode 100644 portfolio-analyzer/references/risk-metrics-formulas.md create mode 100644 portfolio-analyzer/references/shenwan-industry-codes.md create mode 100644 portfolio-analyzer/scripts/portfolio_analyzer.py create mode 100644 ppt-station-skill/README.md create mode 100644 ppt-station-skill/SKILL.md create mode 100644 ppt-station-skill/data/data_drawdown.csv create mode 100644 ppt-station-skill/data/data_returns_vol.csv create mode 100644 ppt-station-skill/data/data_risk_table.csv create mode 100644 ppt-station-skill/data/data_sharpe.csv create mode 100644 ppt-station-skill/designer-brief.md create mode 100644 ppt-station-skill/difference.md create mode 100644 ppt-station-skill/ppt_station/__init__.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/__init__.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/api.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/builder.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/cleaner.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/date_axis.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/layout.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/oxml/__init__.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/oxml/axes.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/oxml/plots.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/oxml/series.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/oxml_ns.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/parser.py create mode 100644 ppt-station-skill/ppt_station/chart_builder/styles.py create mode 100644 ppt-station-skill/ppt_station/composer/__init__.py create mode 100644 ppt-station-skill/ppt_station/composer/blocks.py create mode 100644 ppt-station-skill/ppt_station/composer/helpers.py create mode 100644 ppt-station-skill/ppt_station/composer/layouts/__init__.py create mode 100644 ppt-station-skill/ppt_station/composer/layouts/chart.py create mode 100644 ppt-station-skill/ppt_station/composer/layouts/conclusion.py create mode 100644 ppt-station-skill/ppt_station/composer/layouts/content.py create mode 100644 ppt-station-skill/ppt_station/composer/layouts/diagram.py create mode 100644 ppt-station-skill/ppt_station/composer/layouts/image_text.py create mode 100644 ppt-station-skill/ppt_station/composer/layouts/kpi.py create mode 100644 ppt-station-skill/ppt_station/composer/layouts/table.py create mode 100644 ppt-station-skill/ppt_station/composer/layouts/title.py create mode 100644 ppt-station-skill/ppt_station/composer/page_composer.py create mode 100644 ppt-station-skill/ppt_station/composer/template_assembler.py create mode 100644 ppt-station-skill/ppt_station/composer/themes.py create mode 100644 ppt-station-skill/ppt_station/config.py create mode 100644 ppt-station-skill/ppt_station/connectors/__init__.py create mode 100644 ppt-station-skill/ppt_station/connectors/base.py create mode 100644 ppt-station-skill/ppt_station/connectors/csv_connector.py create mode 100644 ppt-station-skill/ppt_station/connectors/tushare_connector.py create mode 100644 ppt-station-skill/ppt_station/engine.py create mode 100644 ppt-station-skill/ppt_station/models/__init__.py create mode 100644 ppt-station-skill/ppt_station/models/job.py create mode 100644 ppt-station-skill/ppt_station/parsers/__init__.py create mode 100644 ppt-station-skill/ppt_station/parsers/ppt_parser.py create mode 100644 ppt-station-skill/ppt_station/qa/__init__.py create mode 100644 ppt-station-skill/ppt_station/qa/deck_linter.py create mode 100644 ppt-station-skill/ppt_station/renderers/__init__.py create mode 100644 ppt-station-skill/ppt_station/renderers/ppt_renderer.py create mode 100644 ppt-station-skill/ppt_station/renderers/table_renderer.py create mode 100644 ppt-station-skill/ppt_station/renderers/text_renderer.py create mode 100644 ppt-station-skill/ppt_station/template/__init__.py create mode 100644 ppt-station-skill/ppt_station/template/chart_presets.py create mode 100644 ppt-station-skill/ppt_station/template/replacer.py create mode 100644 ppt-station-skill/ppt_station/transformers/__init__.py create mode 100644 ppt-station-skill/ppt_station/transformers/dataframe_ops.py create mode 100644 ppt-station-skill/ppt_station/utils/__init__.py create mode 100644 ppt-station-skill/ppt_station/utils/template_utils.py create mode 100644 ppt-station-skill/reference/api-contracts.md create mode 100644 ppt-station-skill/reference/chart-config.md create mode 100644 ppt-station-skill/reference/connectors-transforms.md create mode 100644 ppt-station-skill/reference/design-rules.md create mode 100644 ppt-station-skill/reference/design-themes.md create mode 100644 ppt-station-skill/reference/institutional-design-analysis.md create mode 100644 ppt-station-skill/reference/job-schema.md create mode 100644 ppt-station-skill/reference/layout-agenda.md create mode 100644 ppt-station-skill/reference/layout-chart-table.md create mode 100644 ppt-station-skill/reference/layout-comparison-cards.md create mode 100644 ppt-station-skill/reference/layout-dashboard.md create mode 100644 ppt-station-skill/reference/layout-highlight-number.md create mode 100644 ppt-station-skill/reference/layout-icon-grid.md create mode 100644 ppt-station-skill/reference/layout-image-text.md create mode 100644 ppt-station-skill/reference/layout-progress-bars.md create mode 100644 ppt-station-skill/reference/layout-quote.md create mode 100644 ppt-station-skill/reference/layout-three-columns.md create mode 100644 ppt-station-skill/reference/layout-timeline.md create mode 100644 ppt-station-skill/reference/layout-waterfall.md create mode 100644 ppt-station-skill/reference/placeholder-syntax.md create mode 100644 ppt-station-skill/reference/workflow-engine.md create mode 100644 ppt-station-skill/reference/workflow-parse-rebuild.md create mode 100644 ppt-station-skill/reference/workflow-template.md create mode 100644 ppt-station-skill/reference/workflow-tushare.md create mode 100644 ppt-station-skill/scripts/add_placeholders.py create mode 100644 ppt-station-skill/scripts/describe_chart.py create mode 100644 ppt-station-skill/scripts/fetch_data.py create mode 100644 ppt-station-skill/scripts/gen_anker_report.py create mode 100644 ppt-station-skill/scripts/gen_moutai_report.py create mode 100644 ppt-station-skill/scripts/gen_moutai_risk.py create mode 100644 ppt-station-skill/scripts/generate_ppt.py create mode 100644 ppt-station-skill/scripts/list_presets.py create mode 100644 ppt-station-skill/scripts/parse_ppt.py create mode 100644 ppt-station-skill/scripts/parse_template.py create mode 100644 ppt-station-skill/scripts/rebuild_ppt.py create mode 100644 ppt-station-skill/scripts/render_ppt.py create mode 100644 ppt-station-skill/scripts/run_job.py create mode 100644 ppt-station-skill/scripts/validate_job.py create mode 100755 ppt-station-skill/tests/test_describe_chart.sh create mode 100755 ppt-station-skill/tests/test_generate_ppt.sh create mode 100755 ppt-station-skill/tests/test_parse_rebuild.sh create mode 100755 ppt-station-skill/tests/test_parse_template.sh create mode 100755 ppt-station-skill/tests/test_run_job.sh create mode 100644 pptx/LICENSE.txt create mode 100644 pptx/SKILL.md create mode 100644 pptx/html2pptx.md create mode 100644 pptx/ooxml.md create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd create mode 100644 pptx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd create mode 100644 pptx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd create mode 100644 pptx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd create mode 100644 pptx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd create mode 100644 pptx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd create mode 100644 pptx/ooxml/schemas/mce/mc.xsd create mode 100644 pptx/ooxml/schemas/microsoft/wml-2010.xsd create mode 100644 pptx/ooxml/schemas/microsoft/wml-2012.xsd create mode 100644 pptx/ooxml/schemas/microsoft/wml-2018.xsd create mode 100644 pptx/ooxml/schemas/microsoft/wml-cex-2018.xsd create mode 100644 pptx/ooxml/schemas/microsoft/wml-cid-2016.xsd create mode 100644 pptx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd create mode 100644 pptx/ooxml/schemas/microsoft/wml-symex-2015.xsd create mode 100644 pptx/ooxml/scripts/pack.py create mode 100644 pptx/ooxml/scripts/unpack.py create mode 100644 pptx/ooxml/scripts/validate.py create mode 100644 pptx/ooxml/scripts/validation/__init__.py create mode 100644 pptx/ooxml/scripts/validation/base.py create mode 100644 pptx/ooxml/scripts/validation/docx.py create mode 100644 pptx/ooxml/scripts/validation/pptx.py create mode 100644 pptx/ooxml/scripts/validation/redlining.py create mode 100644 pptx/scripts/html2pptx.js create mode 100644 pptx/scripts/inventory.py create mode 100644 pptx/scripts/rearrange.py create mode 100644 pptx/scripts/replace.py create mode 100644 pptx/scripts/thumbnail.py create mode 100644 skill-creator/LICENSE.txt create mode 100644 skill-creator/SKILL.md create mode 100644 skill-creator/references/output-patterns.md create mode 100644 skill-creator/references/workflows.md create mode 100644 skill-creator/scripts/init_skill.py create mode 100644 skill-creator/scripts/package_skill.py create mode 100644 skill-creator/scripts/quick_validate.py create mode 100644 technical-analyst/SKILL.md create mode 100644 technical-analyst/assets/analysis_template.md create mode 100644 technical-analyst/references/technical_analysis_framework.md create mode 100644 tushare-data-1.0.5/SKILL.md create mode 100644 tushare-data-1.0.5/_meta.json create mode 100644 tushare-data-1.0.5/references/使用tushare.md create mode 100644 tushare-data-1.0.5/references/安装tushare.md create mode 100644 tushare-data-1.0.5/references/数据接口/ETF专题/ETF份额规模.md create mode 100644 tushare-data-1.0.5/references/数据接口/ETF专题/ETF分钟行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/ETF专题/ETF基准指数.md create mode 100644 tushare-data-1.0.5/references/数据接口/ETF专题/ETF基本信息.md create mode 100644 tushare-data-1.0.5/references/数据接口/ETF专题/ETF复权因子.md create mode 100644 tushare-data-1.0.5/references/数据接口/ETF专题/ETF实时日线.md create mode 100644 tushare-data-1.0.5/references/数据接口/ETF专题/ETF日线行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/债券回购日行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/全球财经事件.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/可转债发行.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/可转债基础信息.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/可转债技术面因子(专业版).md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/可转债票面利率.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/可转债行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/可转债赎回信息.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/可转债转股价变动.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/可转债转股结果.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/国债收益率曲线.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/大宗交易.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/大宗交易明细.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/柜台流通式债券报价.md create mode 100644 tushare-data-1.0.5/references/数据接口/债券专题/柜台流通式债券最优报价.md create mode 100644 tushare-data-1.0.5/references/数据接口/公募基金/基金净值.md create mode 100644 tushare-data-1.0.5/references/数据接口/公募基金/基金分红.md create mode 100644 tushare-data-1.0.5/references/数据接口/公募基金/基金列表.md create mode 100644 tushare-data-1.0.5/references/数据接口/公募基金/基金技术面因子(专业版).md create mode 100644 tushare-data-1.0.5/references/数据接口/公募基金/基金持仓.md create mode 100644 tushare-data-1.0.5/references/数据接口/公募基金/基金管理人.md create mode 100644 tushare-data-1.0.5/references/数据接口/公募基金/基金经理.md create mode 100644 tushare-data-1.0.5/references/数据接口/公募基金/基金规模.md create mode 100644 tushare-data-1.0.5/references/数据接口/另类数据/上市公司公告.md create mode 100644 tushare-data-1.0.5/references/数据接口/另类数据/新闻联播文字稿.md create mode 100644 tushare-data-1.0.5/references/数据接口/外汇数据/外汇基础信息(海外).md create mode 100644 tushare-data-1.0.5/references/数据接口/外汇数据/外汇日线行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/大模型语料专题数据/上证e互动问答.md create mode 100644 tushare-data-1.0.5/references/数据接口/大模型语料专题数据/国家政策库.md create mode 100644 tushare-data-1.0.5/references/数据接口/大模型语料专题数据/新闻快讯(短讯).md create mode 100644 tushare-data-1.0.5/references/数据接口/大模型语料专题数据/新闻通讯(长篇).md create mode 100644 tushare-data-1.0.5/references/数据接口/大模型语料专题数据/深证易互动问答.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/价格指数.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/价格指数/居民消费价格指数(CPI).md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/价格指数/工业生产者出厂价格指数(PPI).md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/利率数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/利率数据/Hibor利率.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/利率数据/LPR贷款基础利率.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/利率数据/Libor利率.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/利率数据/Shibor利率.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/利率数据/Shibor报价数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/利率数据/广州民间借贷利率.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/利率数据/温州民间借贷利率.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/国民经济.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/国民经济/国内生产总值(GDP).md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/景气度/采购经理指数(PMI).md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/金融/社会融资/社融增量(月度).md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国内宏观/金融/货币供应量/货币供应量(月).md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国际宏观/美国利率.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国际宏观/美国利率/国债实际收益率曲线利率.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国际宏观/美国利率/国债收益率曲线利率.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国际宏观/美国利率/国债长期利率.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国际宏观/美国利率/国债长期利率平均值.md create mode 100644 tushare-data-1.0.5/references/数据接口/宏观经济/国际宏观/美国利率/短期国债利率.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/中信行业成分.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/中信行业指数日行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/国际主要指数.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/大盘指数每日指标.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/实时日线.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/指数周线行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/指数基本信息.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/指数成分和权重.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/指数技术面因子(专业版).md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/指数日线行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/指数月线行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/沪深市场每日交易统计.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/深圳市场每日交易情况.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/申万行业分类.md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/申万行业成分(分级).md create mode 100644 tushare-data-1.0.5/references/数据接口/指数专题/申万行业指数日行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/期权数据/期权分钟行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/期权数据/期权合约信息.md create mode 100644 tushare-data-1.0.5/references/数据接口/期权数据/期权日线行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/交易日历.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/仓单日报.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/南华期货指数行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/历史Tick行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/历史分钟行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/合约信息.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/实时分钟行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/日线行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/期货主力与连续合约.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/期货主要品种交易周报.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/期货合约涨跌停价格.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/期货周-月线行情(每日更新).md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/每日持仓排名.md create mode 100644 tushare-data-1.0.5/references/数据接口/期货数据/每日结算参数.md create mode 100644 tushare-data-1.0.5/references/数据接口/港股数据/港股交易日历.md create mode 100644 tushare-data-1.0.5/references/数据接口/港股数据/港股分钟行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/港股数据/港股利润表.md create mode 100644 tushare-data-1.0.5/references/数据接口/港股数据/港股基础信息.md create mode 100644 tushare-data-1.0.5/references/数据接口/港股数据/港股复权因子.md create mode 100644 tushare-data-1.0.5/references/数据接口/港股数据/港股复权行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/港股数据/港股实时日线.md create mode 100644 tushare-data-1.0.5/references/数据接口/港股数据/港股日线行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/港股数据/港股现金流量表.md create mode 100644 tushare-data-1.0.5/references/数据接口/港股数据/港股财务指标数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/港股数据/港股资产负债表.md create mode 100644 tushare-data-1.0.5/references/数据接口/现货数据/上海黄金基础信息.md create mode 100644 tushare-data-1.0.5/references/数据接口/现货数据/上海黄金现货日行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/美股数据/美股交易日历.md create mode 100644 tushare-data-1.0.5/references/数据接口/美股数据/美股利润表.md create mode 100644 tushare-data-1.0.5/references/数据接口/美股数据/美股基础信息.md create mode 100644 tushare-data-1.0.5/references/数据接口/美股数据/美股复权因子.md create mode 100644 tushare-data-1.0.5/references/数据接口/美股数据/美股复权行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/美股数据/美股日线行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/美股数据/美股现金流量表.md create mode 100644 tushare-data-1.0.5/references/数据接口/美股数据/美股财务指标数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/美股数据/美股资产负债表.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/两融及转融通/做市借券交易汇总(停).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/两融及转融通/融资融券交易明细.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/两融及转融通/融资融券交易汇总.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/两融及转融通/融资融券标的(盘前).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/两融及转融通/转融券交易明细(停).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/两融及转融通/转融券交易汇总(停).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/两融及转融通/转融资交易汇总.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/参考数据/前十大流通股东.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/参考数据/前十大股东.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/参考数据/大宗交易.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/参考数据/股东人数.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/参考数据/股东增减持.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/参考数据/股权质押明细数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/参考数据/股权质押统计数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/参考数据/股票回购.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/参考数据/股票开户数据(停).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/参考数据/股票开户数据(旧).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/参考数据/限售股解禁.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/基础数据/IPO新股上市.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/基础数据/ST股票列表.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/基础数据/上市公司基本信息.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/基础数据/上市公司管理层.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/基础数据/交易日历.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/基础数据/北交所新旧代码对照.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/基础数据/每日股本(盘前).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/基础数据/沪深港通股票列表.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/基础数据/管理层薪酬和持股.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/基础数据/股票列表.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/基础数据/股票历史列表.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/基础数据/股票曾用名.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/东方财富App热榜.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/东方财富概念成分.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/东方财富概念板块.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/东财概念和行业指数行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/同花顺App热榜数.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/同花顺概念和行业指数行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/同花顺涨跌停榜单.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/同花顺行业概念成分.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/同花顺行业概念板块.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/市场游资最全名录.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/开盘竞价成交(当日).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/榜单数据(开盘啦).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/涨停最强板块统计.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/涨停股票连板天梯.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/涨跌停和炸板数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/游资交易每日明细.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/通达信板块信息.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/通达信板块成分.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/通达信板块行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/题材成分(开盘啦).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/题材数据(开盘啦).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/龙虎榜机构交易单.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/打板专题数据/龙虎榜每日统计单.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/AH股比价.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/中央结算系统持股明细.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/中央结算系统持股统计.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/券商月度金股.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/券商盈利预测数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/机构调研数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/每日筹码分布.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/每日筹码及胜率.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/沪深股通持股明细.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/神奇九转指标.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/股票开盘集合竞价数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/股票技术面因子(专业版).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/股票技术面因子.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/特色数据/股票收盘集合竞价数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/历史分钟.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/历史日线.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/周-月线复权行情(每日更新).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/周-月线行情(每日更新).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/周线行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/备用行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/复权因子.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/复权行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/实时Tick(爬虫).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/实时分钟.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/实时成交(爬虫).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/实时排名(爬虫).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/实时日线.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/月线行情.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/每日停复牌信息.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/每日指标.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/每日涨跌停价格.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/沪深股通十大成交股.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/港股通十大成交股.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/港股通每日成交统计.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/港股通每月成交统计.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/行情数据/通用行情接口.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/财务数据/业绩快报.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/财务数据/业绩预告.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/财务数据/主营业务构成.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/财务数据/分红送股数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/财务数据/利润表.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/财务数据/现金流量表.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/财务数据/财务审计意见.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/财务数据/财务指标数据.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/财务数据/财报披露日期表.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/财务数据/资产负债表.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/资金流向数据/个股资金流向.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/资金流向数据/个股资金流向(DC).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/资金流向数据/个股资金流向(THS).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/资金流向数据/大盘资金流向(DC).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/资金流向数据/板块资金流向(THS).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/资金流向数据/板块资金流向(DC).md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/资金流向数据/沪深港通资金流向.md create mode 100644 tushare-data-1.0.5/references/数据接口/股票数据/资金流向数据/行业资金流向(THS).md create mode 100644 tushare-data-1.0.5/references/数据接口/财富管理/基金销售行业数据/各渠道公募基金销售保有规模占比.md create mode 100644 tushare-data-1.0.5/references/数据接口/财富管理/基金销售行业数据/销售机构公募基金销售保有规模.md create mode 100644 tushare-data-1.0.5/references/目录索引.md create mode 100644 tushare-data-1.0.5/scripts/fund_data_example.py create mode 100644 tushare-data-1.0.5/scripts/stock_data_example.py create mode 100644 windpy-sdk/SKILL.md create mode 100644 windpy-sdk/references/README.md create mode 100644 windpy-sdk/references/asset-type-codes.md create mode 100644 windpy-sdk/references/bond-fields.md create mode 100644 windpy-sdk/references/edb-indicators.md create mode 100644 windpy-sdk/references/error-codes.md create mode 100644 windpy-sdk/references/field-catalog.md create mode 100644 windpy-sdk/references/fund-fields.md create mode 100644 windpy-sdk/references/future-fields.md create mode 100644 windpy-sdk/references/fx-fields.md create mode 100644 windpy-sdk/references/options-cheatsheet.md create mode 100644 windpy-sdk/references/options-fields.md create mode 100644 windpy-sdk/references/sector-ids.md create mode 100644 windpy-sdk/references/sectorid-catalog.md create mode 100644 windpy-sdk/references/technical-indicators.md create mode 100644 windpy-sdk/references/wset-tables.md create mode 100644 windpy-sdk/scripts/setup_windpy.py create mode 100644 windpy-sdk/scripts/wind_client.py create mode 100644 windpy-sdk/scripts/wind_client_win.py create mode 100644 windpy-sdk/scripts/wind_server.py create mode 100644 windpy-sdk/scripts/wind_server_win.py create mode 100644 xlsx/LICENSE.txt create mode 100644 xlsx/SKILL.md create mode 100644 xlsx/recalc.py create mode 100644 zhipu-websearch/SKILL.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1571dff --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +# Editor / IDE +.DS_Store +.idea/ +.vscode/ +*.swp +*~ + +# Python +__pycache__/ +*.pyc +*.pyo +.venv/ +venv/ + +# Node +node_modules/ + +# Local secrets +.env +.env.local +*.local + +# Skill-generated artifacts +**/output/ +**/.agent/runs/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..6377106 --- /dev/null +++ b/README.md @@ -0,0 +1,84 @@ +# Skills + +Claude Code 技能集 — 金融数据、文档处理、数据可视化、联网搜索、写作与元技能。 + +## 目录 + +### 金融数据与研究 + +| 技能 | 说明 | +|------|------| +| [windpy-sdk](windpy-sdk/) | Wind 金融终端 Python API — 17 个函数、常驻服务、13 份参考文档,覆盖 A 股/债券/基金/期货/期权/外汇/宏观 | +| [tushare-data-1.0.5](tushare-data-1.0.5/) | Tushare 财经数据接口 — 股票/基金/期货/数字货币行情 + 公司财务/基金经理基本面 | +| [ifind-http-api](ifind-http-api/) | 同花顺 iFinD HTTP API — 18 个端点参考手册,支持股票/基金/债券/期货/期权/宏观数据 | +| [gangtise](gangtise/) | 冈底斯港股/A 股研报知识库 + 投研 AI Agent + 经济指标查询 | +| [annuity-disclosure-crawler](annuity-disclosure-crawler/) | 企业年金季度管理报告全量爬虫 — 22 家投资管理人官网披露栏目 | +| [asset-monitor](asset-monitor/) | 资产异常波动日频监控 — Z-Score 检测偏离 > 2σ 的异常,自动生成 Excel 报告 | +| [technical-analyst](technical-analyst/) | 周线 K 线技术分析 — 趋势识别、支撑阻力位、形态、概率场景推演(纯图表) | +| [portfolio-analyzer](portfolio-analyzer/) | 投资组合多维分析 — 8 项风险指标、Brinson 三因素归因、6-sheet Excel 报告 | +| [financial-report-writing](financial-report-writing/) | A 股上市公司投研报告写作 — 数据获取、分析、Word 输出全流程 | + +### 文档与可视化 + +| 技能 | 说明 | +|------|------| +| [docx](docx/) | Word 文档创建/编辑 — 修订追踪、批注、格式保留、文本提取,含 docx-js + ooxml 工具链 | +| [docx-cn](docx-cn/) | 中文公文 Word 文档(GB/T 9704-2012) — 依赖 `docx` skill,提供公文常量与排版规范 | +| [xlsx](xlsx/) | Excel 电子表格 — 公式、格式、数据分析、可视化、公式重算 | +| [pdf](pdf/) | PDF 处理工具包 — 文本/表格提取、创建、合并/拆分、表单填写 | +| [pptx](pptx/) | PowerPoint 创建/编辑/分析 — 布局、母版、图表、演讲备注,含 OOXML schema | +| [ppt-station-skill](ppt-station-skill/) | 数据 → 金融报告 PPT — 12 种页面布局、10 主题、ChartJunkCleaner、DeckLinter 合规审计 | +| [fund-slides](fund-slides/) | 零依赖 HTML 演示 — 智能内容-可视化映射、ECharts 内联、中文字体支持 | +| [plotly](plotly/) | Plotly 交互式可视化 — 散点/折线/热力/3D/地图/金融图表,输出 HTML 或静态图 | + +### 联网搜索与工具箱 + +| 技能 | 说明 | +|------|------| +| [agentrs-search](agentrs-search/) | 京东 agentrs 网关四搜索引擎 — tavily / cloudsway(Bing)/ searchpro(搜狗)/ jdcloud RAG | +| [agentrs-map](agentrs-map/) | 高德地图 6 工具 — POI / 地理编码 / 行政区 / IP 定位 / 步行导航 / 坐标转换 | +| [agentrs-weather](agentrs-weather/) | 高德天气 — 实况 + 未来预报,支持 adcode 或地址自动解析 | +| [zhipu-websearch](zhipu-websearch/) | 智谱 AI Web Search — 双引擎、时间过滤、域名过滤 | + +### 写作与协作 + +| 技能 | 说明 | +|------|------| +| [humanizer-zh](humanizer-zh/) | 中文去 AI 痕迹 — 交互式工作流,33 种模式分 6 篇 reference 按需加载,支持学术/公文/商业报告 | +| [ai-pair](ai-pair/) | 多模型协同 — 一个创作(Author),多个审阅(可配 Codex/Gemini/Kimi),覆盖不同 review 维度 | + +### 元技能 + +| 技能 | 说明 | +|------|------| +| [skill-creator](skill-creator/) | 技能创建指南 — 帮助创建和优化 Claude Code skill | +| [find-skills](find-skills/) | 技能发现与安装 — 从开源技能生态中搜索和安装 skill | + +## 使用方式 + +将技能目录放入项目的 `.claude/skills/` 下,Claude Code 自动识别加载。 + +```bash +# 克隆整个仓库 +git clone https://codehub.ablemind.cc/public/skills.git .claude/skills + +# 或只安装单个技能 +cp -r windpy-sdk /.claude/skills/windpy-sdk +``` + +## 依赖关系 + +``` +asset-monitor ── uses ── WindPy SDK ── ref ── windpy-sdk +portfolio-analyzer ── uses ── WindPy SDK ── ref ── windpy-sdk + └─ uses ── xlsx(recalc.py 公式验证) +docx-cn ── uses ── docx(unpack/pack/validate 工具链) +其余 skill 均独立,无交叉依赖 +``` + +需要外部凭证的 skill(首次使用时会自动检测 env / .env,未命中则通过 AskUserQuestion 询问): + +- `windpy-sdk` / `tushare-data-1.0.5` / `ifind-http-api` — 各自数据源账号 +- `gangtise` — `GANGTISE_TOKEN` +- `agentrs-*` — `JD_AGENTRS_TOKEN` +- `zhipu-websearch` — `ZHIPU_API_KEY` diff --git a/agentrs-map/SKILL.md b/agentrs-map/SKILL.md new file mode 100644 index 0000000..4b2938a --- /dev/null +++ b/agentrs-map/SKILL.md @@ -0,0 +1,48 @@ +--- +name: agentrs-map +description: > + 高德地图 / 地理工具箱 —— 通过京东 agentrs 代理网关,用单一 Bearer Token 调 6 个高德(Amap)工具: + POI 地点检索、地理编码(地址↔经纬度/adcode)、行政区域查询、IP 定位、步行路径规划、坐标转换。 + 当需要查地点经纬度与 adcode、找附近地点(POI)、做步行导航、转换坐标系、 + 按 IP 定位、查行政区划时使用。触发词:高德、地图、经纬度、坐标、adcode、地理编码、 + POI、附近、步行路线、导航、坐标转换、IP定位、行政区、省市区。 +--- + +# agentrs-map —— 高德地图 / 地理(6 工具) + +通过 `https://agentrs.jd.com/api/saas/proxy-k/v1/`,单一 Bearer Token 调 6 个高德工具。 + +## 鉴权与调用约定(先读) +- 环境变量取密钥,**不硬编码**:`export JD_AGENTRS_TOKEN='你的token'` +- **网关只认 JSON body**:文档标 GET/POST 都不影响,query string 会报"缺少必要输入参数"。 +- HTTP 恒 200,业务看 body:`1001`=token 未授权;`9999 缺少必要输入参数`=参数错;`9999 用户积分不足`=余额不足(重试常能通)。 + +## 6 个工具 +| 工具 | 入参 | 返回要点 | +|---|---|---| +| `poi` | `{keywords(必填), city(拼音如 beijing)}` | POI 文本检索(名虽 around 但**非按经纬度周边**);`pois[]` 含 rating/人均/营业时间/招牌菜/电话/location | +| `geocode` | `{address, city}` | 地址→坐标;`geocodes[]` 含 location/adcode/level/district | +| `region` | `{keywords, subdistrict, offset, page}` | 行政区树;`districts[]` 含 adcode/center/level/下级 | +| `ip` | `{ip}`(留空取请求 IP,仅国内) | province/city/adcode/rectangle | +| `walk` | `{origin:"lon,lat", destination:"lon,lat"}` | `route.paths[]` 含 distance/duration/steps[] 分段导航 | +| `coord` | `{locations:"lon,lat", coordsys: gps/baidu/mapbar/autonavi}` | 转成高德坐标 | + +## 用法 +```bash +export JD_AGENTRS_TOKEN='...' +python3 scripts/amap.py poi --keywords 故宫 --city beijing +python3 scripts/amap.py geocode --address "北京市朝阳区建国路88号" +python3 scripts/amap.py region --keywords 北京 --subdistrict 1 +python3 scripts/amap.py ip --ip 114.247.50.2 +python3 scripts/amap.py walk --origin 116.397455,39.909187 --destination 116.417854,39.914888 +python3 scripts/amap.py coord --locations 116.481499,39.990475 --coordsys gps +``` +打印规整 JSON;遇 1001/9999 在 stderr 给可读提示。 + +## 组合范式 +- **"附近有什么 / 某地点信息"**:`poi --keywords X --city Y`。 +- **"A 到 B 步行怎么走"**:两端各 `geocode`/`poi` 拿经纬度 → `walk`。 +- **坐标系不一致**(GPS/百度坐标接入高德):先 `coord` 统一到高德。 +- **查天气**:`geocode` 拿到的 `adcode` 即天气入参 → 见姊妹 skill **agentrs-weather**。 + +> 联网搜索见 **agentrs-search**;天气见 **agentrs-weather**。三者共用同一个 JD_AGENTRS_TOKEN。 diff --git a/agentrs-map/scripts/amap.py b/agentrs-map/scripts/amap.py new file mode 100644 index 0000000..cdddbad --- /dev/null +++ b/agentrs-map/scripts/amap.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +""" +agentrs-map —— 京东 agentrs 代理网关的「高德地图 / 地理 / 天气」客户端。 + +封装 6 个高德(Amap)工具: + poi(POI检索) / geocode(地理编码) / region(行政区) / ip(IP定位) / + walk(步行路径) / coord(坐标转换) +端点:https://agentrs.jd.com/api/saas/proxy-k/v1/ + +鉴权:环境变量 JD_AGENTRS_TOKEN(不硬编码密钥)。 +约定:网关一律从 JSON body 取参(query string 不生效);HTTP 恒 200,业务看 body。 + +注:天气查询见姊妹 skill agentrs-weather(geocode 拿到的 adcode 即天气入参)。 + +用法: + python3 amap.py poi --keywords 故宫 --city beijing + python3 amap.py geocode --address "北京市朝阳区建国路88号" + python3 amap.py region --keywords 北京 --subdistrict 1 + python3 amap.py ip --ip 114.247.50.2 + python3 amap.py walk --origin 116.397455,39.909187 --destination 116.417854,39.914888 + python3 amap.py coord --locations 116.481499,39.990475 --coordsys gps +""" +import os, sys, json, argparse, urllib.request, urllib.error + +BASE = "https://agentrs.jd.com/api/saas/proxy-k/v1" + + +def _token(): + tok = os.environ.get("JD_AGENTRS_TOKEN") + if not tok: + sys.exit("错误:未设置 JD_AGENTRS_TOKEN。\n export JD_AGENTRS_TOKEN='你的token'") + return tok + + +def call(tool, body, timeout=30): + payload = {k: v for k, v in body.items() if v not in ("", None)} + data = json.dumps(payload, ensure_ascii=False).encode("utf-8") + req = urllib.request.Request(f"{BASE}/{tool}", data=data, method="POST", + headers={"Content-Type": "application/json", + "Authorization": f"Bearer {_token()}"}) + try: + with urllib.request.urlopen(req, timeout=timeout) as r: + raw = r.read().decode("utf-8") + except urllib.error.URLError as e: + return {"_error": f"网络错误: {e}"} + try: + return json.loads(raw) + except json.JSONDecodeError: + return {"_raw": raw} + + +def biz_error(resp): + if not isinstance(resp, dict): + return None + code, msg = resp.get("code"), resp.get("msg") or "" + if code in (1001, "1001"): + return f"[未授权 1001] 该 token 未开通此工具:{msg}" + if code in (9999, "9999") or "积分不足" in msg or "缺少必要输入参数" in msg: + return f"[业务失败 {code}] {msg}" + return None + + +# 7 个高德工具 ------------------------------------------------- +def poi(keywords, city="", **k): + return call("search_around_gaode", dict(keywords=keywords, city=city)) + +def geocode(address, city="", **k): + return call("geocoding", dict(address=address, city=city)) + +def region(keywords, subdistrict="", page="", offset="", extensions="", filter="", **k): + return call("administrative_region_inquiry", dict(keywords=keywords, + subdistrict=subdistrict, page=page, offset=offset, + extensions=extensions, filter=filter)) + +def ip(ip="", **k): + return call("ip_locating", dict(ip=ip)) + +def walk(origin, destination, origin_id="", destination_id="", **k): + return call("pedestrian_path_planning", dict(origin=origin, destination=destination, + origin_id=origin_id, destination_id=destination_id)) + +def coord(locations, coordsys="gps", **k): + return call("coordinate_transformation", dict(locations=locations, coordsys=coordsys)) + + +TOOLS = {"poi": poi, "geocode": geocode, "region": region, "ip": ip, + "walk": walk, "coord": coord} + + +def main(): + p = argparse.ArgumentParser(description="京东 agentrs 高德地图/地理(6 工具)") + p.add_argument("tool", choices=list(TOOLS)) + for opt in ("keywords", "city", "address", "subdistrict", "page", "offset", + "extensions", "filter", "ip", "origin", "destination", + "origin_id", "destination_id", "locations", "coordsys"): + p.add_argument(f"--{opt}", default=None) + a = p.parse_args() + kw = {k: v for k, v in vars(a).items() if k != "tool" and v is not None} + resp = TOOLS[a.tool](**kw) + err = biz_error(resp) + if err: + print(err, file=sys.stderr) + print(json.dumps(resp, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/agentrs-search/SKILL.md b/agentrs-search/SKILL.md new file mode 100644 index 0000000..2c1c900 --- /dev/null +++ b/agentrs-search/SKILL.md @@ -0,0 +1,50 @@ +--- +name: agentrs-search +description: > + 联网搜索工具箱 —— 通过京东 agentrs 代理网关,用单一 Bearer Token 调用 4 个搜索引擎: + tavily(AI搜索)、cloudsway(必应/Bing,可拿网页全文)、SearchPro(搜狗,实时新闻时效最强)、 + jdcloud_search(京东云RAG,返回整页正文)。当需要联网检索资讯、新闻、研报、实时信息, + 或要抓取网页正文做后续分析时使用。触发词:联网搜索、实时搜索、查资讯、查新闻、 + 搜一下、tavily、bing、cloudsway、搜狗、京东搜索、web search、抓网页正文。 +--- + +# agentrs-search —— 联网搜索(4 引擎) + +通过 `https://agentrs.jd.com/api/saas/proxy-k/v1/`,单一 Bearer Token 调 4 个搜索引擎。 + +## 鉴权与调用约定(先读) +- 环境变量取密钥,**不硬编码**:`export JD_AGENTRS_TOKEN='你的token'` +- **网关只认 JSON body**:文档标 GET/POST 都不影响,query string 会报"缺少必要输入参数"。 +- HTTP 恒 200,业务看 body:`1001`=token 未授权(充值/补参无用);`9999 缺少必要输入参数`=参数错;`9999 用户积分不足`=余额不足(**重试常能通**)。 + +## 4 个引擎怎么选 +| 引擎 | 底层 | 入参 | 结果路径 | 选用场景 | +|---|---|---|---|---| +| `tavily` | Tavily | `{query}` | `results[]` | 通用 AI 搜索,默认首选 | +| `cloudsway` | Bing/必应 | `{q,count,freshness,enableContent,contentType,mainText,sites,blockWebsites}` | `webPages.value[]` | 中文好;`enableContent=true` 直接拿网页**正文**;`sites/blockWebsites` 站点过滤;`freshness=Day/Week/Month` 时间过滤 | +| `searchpro` | 搜狗 | `{Query,Cnt,Site,Industry,...}` | `Response.Pages[]`(**元素是字符串化JSON,需二次 parse**) | **实时新闻/天气,时效性最强** | +| `jdcloud` | 京东云 RAG | `{query}` | `data[]`(`page_content` 整页正文 + `recall_distance`) | 要**整页全文**做分析时 | + +## 用法 +```bash +export JD_AGENTRS_TOKEN='...' +python3 scripts/search.py tavily "人工智能最新趋势" +python3 scripts/search.py cloudsway "中信建投证券" --count 5 --enableContent true --mainText true +python3 scripts/search.py searchpro "今天北京天气" +python3 scripts/search.py jdcloud "AI agent 发展" +``` +打印规整 JSON;遇 1001/9999 在 stderr 给可读提示。 + +## 直接 curl +```bash +curl -s https://agentrs.jd.com/api/saas/proxy-k/v1/tavily_search \ + -X POST -H "Content-Type: application/json" \ + -H "Authorization: Bearer $JD_AGENTRS_TOKEN" \ + -d '{"query":"搜索关键词"}' +``` +工具名换 `cloudsway`/`SearchPro`/`jdcloud_search`、body 换对应入参即可。 + +## 选用范式 +- 通用检索 → `tavily`;要最新时效 → `searchpro`;要网页正文做分析 → `jdcloud`(或 `cloudsway --enableContent true`);要限定站点 → `cloudsway --sites baijiahao.baidu.com`。 + +> 地图/经纬度/POI/路径 等见姊妹 skill **agentrs-map**;天气见 **agentrs-weather**。三者共用同一个 JD_AGENTRS_TOKEN。 diff --git a/agentrs-search/scripts/search.py b/agentrs-search/scripts/search.py new file mode 100644 index 0000000..e2018ef --- /dev/null +++ b/agentrs-search/scripts/search.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +""" +agentrs-search —— 京东 agentrs 代理网关的「联网搜索」客户端。 + +封装 4 个搜索引擎:tavily / cloudsway(Bing) / SearchPro(搜狗) / jdcloud_search(京东云RAG)。 +端点:https://agentrs.jd.com/api/saas/proxy-k/v1/ + +鉴权:环境变量 JD_AGENTRS_TOKEN(不硬编码密钥)。 + export JD_AGENTRS_TOKEN='...' + +约定:网关一律从 JSON body 取参(query string 不生效);HTTP 恒 200,业务看 body。 + 1001=工具未授权 | 9999"缺少必要输入参数"=参数错 | 9999"积分不足"=余额不足(可重试)。 + +用法: + python3 search.py tavily "人工智能最新趋势" + python3 search.py cloudsway "中信建投证券" --count 5 --enableContent true --mainText true + python3 search.py searchpro "今天北京天气" + python3 search.py jdcloud "AI agent 发展" +""" +import os, sys, json, argparse, urllib.request, urllib.error + +BASE = "https://agentrs.jd.com/api/saas/proxy-k/v1" + + +def _token(): + tok = os.environ.get("JD_AGENTRS_TOKEN") + if not tok: + sys.exit("错误:未设置 JD_AGENTRS_TOKEN。\n export JD_AGENTRS_TOKEN='你的token'") + return tok + + +def call(tool, body, timeout=30): + payload = {k: v for k, v in body.items() if v not in ("", None)} + data = json.dumps(payload, ensure_ascii=False).encode("utf-8") + req = urllib.request.Request(f"{BASE}/{tool}", data=data, method="POST", + headers={"Content-Type": "application/json", + "Authorization": f"Bearer {_token()}"}) + try: + with urllib.request.urlopen(req, timeout=timeout) as r: + raw = r.read().decode("utf-8") + except urllib.error.URLError as e: + return {"_error": f"网络错误: {e}"} + try: + return json.loads(raw) + except json.JSONDecodeError: + return {"_raw": raw} + + +def biz_error(resp): + if not isinstance(resp, dict): + return None + code, msg = resp.get("code"), resp.get("msg") or "" + if code in (1001, "1001"): + return f"[未授权 1001] 该 token 未开通此工具:{msg}" + if code in (9999, "9999") or "积分不足" in msg or "缺少必要输入参数" in msg: + return f"[业务失败 {code}] {msg}" + return None + + +# 4 个搜索引擎 ------------------------------------------------- +def tavily(query, **k): + return call("tavily_search", {"query": query}) + +def cloudsway(q, count="", freshness="", offset="", enableContent="", + contentType="", mainText="", sites="", blockWebsites="", **k): + return call("cloudsway", dict(q=q, count=count, freshness=freshness, offset=offset, + enableContent=enableContent, contentType=contentType, mainText=mainText, + sites=sites, blockWebsites=blockWebsites)) + +def searchpro(query, region="", mode="", site="", cnt="", industry="", **k): + return call("SearchPro", dict(Query=query, Region=region, Mode=mode, + site=site, Cnt=cnt, Industry=industry)) + +def jdcloud(query, **k): + return call("jdcloud_search", {"query": query}) + + +TOOLS = {"tavily": tavily, "cloudsway": cloudsway, + "searchpro": searchpro, "jdcloud": jdcloud} + + +def main(): + p = argparse.ArgumentParser(description="京东 agentrs 联网搜索(4 引擎)") + p.add_argument("engine", choices=list(TOOLS)) + p.add_argument("query", nargs="?", help="查询词") + for opt in ("count", "freshness", "offset", "enableContent", "contentType", + "mainText", "sites", "blockWebsites", "region", "mode", + "site", "cnt", "industry"): + p.add_argument(f"--{opt}", default=None) + a = p.parse_args() + kw = {k: v for k, v in vars(a).items() + if k not in ("engine", "query") and v is not None} + if a.query: + kw["q" if a.engine == "cloudsway" else "query"] = a.query + resp = TOOLS[a.engine](**kw) + err = biz_error(resp) + if err: + print(err, file=sys.stderr) + print(json.dumps(resp, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/agentrs-weather/SKILL.md b/agentrs-weather/SKILL.md new file mode 100644 index 0000000..40d0066 --- /dev/null +++ b/agentrs-weather/SKILL.md @@ -0,0 +1,51 @@ +--- +name: agentrs-weather +description: > + 天气查询工具 —— 通过京东 agentrs 代理网关调用高德天气,返回城市实况(气温/天气/湿度/风力) + 或未来预报。支持直接传高德 adcode,也支持传城市名/地址自动解析 adcode。当用户问某地天气、 + 气温、今天/明天下不下雨、出门带不带伞、未来几天天气这类问题时使用。 + 触发词:天气、气温、下雨、温度、湿度、风力、今天天气、明天天气、未来天气、weather、带伞。 +--- + +# agentrs-weather —— 高德天气(实况 / 预报) + +通过 `https://agentrs.jd.com/api/saas/proxy-k/v1/weather_inquiry` 查高德天气。 + +## 鉴权与调用约定(先读) +- 环境变量取密钥,**不硬编码**:`export JD_AGENTRS_TOKEN='你的token'` +- **网关只认 JSON body**(query string 不生效);HTTP 恒 200,业务看 body:`1001`=未授权 / `9999 缺少必要输入参数`=参数错 / `9999 用户积分不足`=余额不足(重试常能通)。 + +## 关键:入参是 adcode +高德天气的 `city` 参数是**高德 adcode**(如北京=110100),**不是经纬度,也不是和风天气的 LocationID**。 +本 skill 的脚本内置「城市名→adcode」自动解析(借地理编码),所以两种方式都行: +- 已知 adcode:`--city 110100` +- 只知城市名:`--address 北京` / `--address 上海市黄浦区`(自动解析) + +| 入参 | 说明 | +|---|---| +| `city` | 高德 adcode(与 `address` 二选一) | +| `address` | 城市名/地址,脚本自动解析成 adcode | +| `extensions` | `base`=实况(默认) / `all`=预报 | + +返回 `lives[]`(实况)含 weather/temperature/humidity/winddirection/windpower/reporttime; +`extensions=all` 时返回 `forecasts[]` 未来数日预报。 + +## 用法 +```bash +export JD_AGENTRS_TOKEN='...' +python3 scripts/weather.py --city 110100 # 北京实况 +python3 scripts/weather.py --city 110100 --extensions all # 北京预报 +python3 scripts/weather.py --address 上海市黄浦区 # 城市名自动解析 +``` +打印规整 JSON;遇 1001/9999 在 stderr 给可读提示。 + +## 直接 curl(需先有 adcode) +```bash +curl -s https://agentrs.jd.com/api/saas/proxy-k/v1/weather_inquiry \ + -X POST -H "Content-Type: application/json" \ + -H "Authorization: Bearer $JD_AGENTRS_TOKEN" \ + -d '{"city":"110100","extensions":"base"}' +``` + +> adcode/经纬度/POI/路径 等地图地理能力见姊妹 skill **agentrs-map**; +> 联网搜索见 **agentrs-search**。三者共用同一个 JD_AGENTRS_TOKEN。 diff --git a/agentrs-weather/scripts/weather.py b/agentrs-weather/scripts/weather.py new file mode 100644 index 0000000..99f02fb --- /dev/null +++ b/agentrs-weather/scripts/weather.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +""" +agentrs-weather —— 京东 agentrs 代理网关的「高德天气」客户端。 + +封装高德 weather_inquiry:实况(base) / 预报(all)。 +端点:https://agentrs.jd.com/api/saas/proxy-k/v1/ + +⚠️ 高德天气入参是 adcode(北京=110100),不是经纬度也不是和风 LocationID。 +本脚本内置「城市名→adcode」自动解析(借 geocoding),使天气查询可独立使用: + --city 110100 直接给 adcode + --address 北京 / 朝阳区 自动 geocoding 解析出 adcode 再查 + +鉴权:环境变量 JD_AGENTRS_TOKEN(不硬编码密钥)。 +约定:网关一律从 JSON body 取参(query string 不生效);HTTP 恒 200,业务看 body。 + +用法: + python3 weather.py --city 110100 # 北京实况 + python3 weather.py --city 110100 --extensions all # 预报 + python3 weather.py --address 上海市黄浦区 # 城市名自动解析 +""" +import os, sys, json, argparse, urllib.request, urllib.error + +BASE = "https://agentrs.jd.com/api/saas/proxy-k/v1" + + +def _token(): + tok = os.environ.get("JD_AGENTRS_TOKEN") + if not tok: + sys.exit("错误:未设置 JD_AGENTRS_TOKEN。\n export JD_AGENTRS_TOKEN='你的token'") + return tok + + +def call(tool, body, timeout=30): + payload = {k: v for k, v in body.items() if v not in ("", None)} + data = json.dumps(payload, ensure_ascii=False).encode("utf-8") + req = urllib.request.Request(f"{BASE}/{tool}", data=data, method="POST", + headers={"Content-Type": "application/json", + "Authorization": f"Bearer {_token()}"}) + try: + with urllib.request.urlopen(req, timeout=timeout) as r: + raw = r.read().decode("utf-8") + except urllib.error.URLError as e: + return {"_error": f"网络错误: {e}"} + try: + return json.loads(raw) + except json.JSONDecodeError: + return {"_raw": raw} + + +def biz_error(resp): + if not isinstance(resp, dict): + return None + code, msg = resp.get("code"), resp.get("msg") or "" + if code in (1001, "1001"): + return f"[未授权 1001] 该 token 未开通此工具:{msg}" + if code in (9999, "9999") or "积分不足" in msg or "缺少必要输入参数" in msg: + return f"[业务失败 {code}] {msg}" + return None + + +def resolve_adcode(address): + """城市名/地址 → adcode(借 geocoding 第一条结果)。""" + resp = call("geocoding", dict(address=address)) + geos = resp.get("geocodes") if isinstance(resp, dict) else None + if geos: + return geos[0].get("adcode") + return None + + +def weather(city, extensions="base"): + return call("weather_inquiry", dict(city=city, extensions=extensions)) + + +def main(): + p = argparse.ArgumentParser(description="京东 agentrs 高德天气(实况/预报)") + p.add_argument("--city", default=None, help="高德 adcode,如北京 110100") + p.add_argument("--address", default=None, help="城市名/地址,自动解析 adcode") + p.add_argument("--extensions", default="base", help="base 实况 / all 预报") + a = p.parse_args() + + city = a.city + if not city and a.address: + city = resolve_adcode(a.address) + if not city: + sys.exit(f"无法从“{a.address}”解析出 adcode") + print(f"[解析] {a.address} → adcode {city}", file=sys.stderr) + if not city: + sys.exit("需提供 --city 或 --address <城市名>") + + resp = weather(city, a.extensions) + err = biz_error(resp) + if err: + print(err, file=sys.stderr) + print(json.dumps(resp, ensure_ascii=False, indent=2)) + + +if __name__ == "__main__": + main() diff --git a/ai-pair/.gitignore b/ai-pair/.gitignore new file mode 100644 index 0000000..f3893d0 --- /dev/null +++ b/ai-pair/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +*.pyc +__pycache__/ +.claude/ diff --git a/ai-pair/LICENSE b/ai-pair/LICENSE new file mode 100644 index 0000000..372b7ee --- /dev/null +++ b/ai-pair/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Axton Liu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ai-pair/README.md b/ai-pair/README.md new file mode 100644 index 0000000..156cf8a --- /dev/null +++ b/ai-pair/README.md @@ -0,0 +1,218 @@ +# AI-Pair: Heterogeneous AI Team Collaboration + +# AI-Pair:异构 AI 团队协作 + +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![Status: Experimental](https://img.shields.io/badge/Status-Experimental-orange.svg)](#status) +[![Claude Code Skill](https://img.shields.io/badge/Claude%20Code-Skill-blue)](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/skills) + +Coordinate multiple AI models to work together as a team. One creates, two review — not for redundancy, but because different models naturally focus on different dimensions. + +让不同 AI 模型组成团队协作。一个创作,两个审查 — 不是为了冗余,而是因为不同模型天然关注不同维度。 + +> **Next Step:** Want to turn Skills from demo to asset? Check out [Agent Skills Resource Library](https://www.axtonliu.ai/agent-skills) (includes slides, PDF, diagnostics) + +## Status + +> **Status: Experimental | 状态:实验性** +> +> - This is a public prototype that works for real workflows, but does not yet cover all edge cases. | 公开原型,可用于实际工作流,但未覆盖所有边界情况。 +> - Requires Claude Code + Codex CLI + Gemini CLI +> - My primary focus is demonstrating how tools and systems work together, not maintaining this codebase. | 重点是展示工具和系统如何协作,而非维护这个代码库。 +> - If you encounter issues, please submit a reproducible case (input + output + steps to reproduce). | 如遇问题,请提交可复现的案例。 + +## Why This Exists | 为什么做这个 + +Most people use multiple AI subscriptions by asking the same question to each and comparing answers. That's useful sometimes, but it only uses one dimension of what different models can do — you get multiple answers to the same question, instead of multiple perspectives on the same work. + +大部分人用多个 AI 的方式是:同一个问题分别问一遍,然后对比答案。这有时候有用,但只用到了不同模型能力的一个维度 — 你得到的是同一个问题的多个回答,而不是同一份工作的多个视角。 + +AI-Pair turns model differences into a structured workflow: assign each model a role that matches its strength, and let them review the same work from different angles. It's a [Claude Code Skill](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/skills) — a reusable instruction set that extends Claude Code's capabilities. + +AI-Pair 把模型差异变成结构化的工作流:给每个模型分配匹配其特长的角色,让它们从不同角度审查同一份工作。它是一个 [Claude Code Skill](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/skills) — 一组可复用的指令,扩展 Claude Code 的能力。 + +## How It Works | 工作原理 + +``` +User (you) | 用户(你) + | +Team Lead (Claude Code session) | 团队领导(Claude Code 会话) + |-- creator (Claude Code agent) — writes code or content | 创作者 — 写代码或内容 + |-- codex-reviewer (agent → Codex CLI) — analytical review | 分析型审查 + |-- gemini-reviewer (agent → Gemini CLI) — editorial review | 编辑型审查 +``` + +The workflow is semi-automatic — you stay in control at every step: + +工作流是半自动的 — 每一步你都保持控制权: + +1. You assign a task → creator executes | 你下达任务 → 创作者执行 +2. Creator reports back → you decide whether to send for review | 创作者回报 → 你决定是否送审 +3. Both reviewers analyze in parallel → consolidated report | 两个审查者并行分析 → 汇总报告 +4. You decide: revise or pass → loop or next task | 你决定:修改还是通过 → 循环或下一个任务 + +## Prerequisites | 前置条件 + +All three are **command-line tools** that run in your terminal (Terminal, iTerm2, etc.), not desktop apps. + +三个都是**命令行工具**,在终端中运行(Terminal、iTerm2 等),不是桌面应用。 + +| Tool | Purpose | Install | +|------|---------|---------| +| [Claude Code](https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview) | Team Lead + agent runtime | `npm install -g @anthropic-ai/claude-code` | +| [Codex CLI](https://github.com/openai/codex) | GPT-powered reviewer | `npm install -g @openai/codex` | +| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | Gemini-powered reviewer | `npm install -g @google/gemini-cli` | + +All three CLIs must have authentication configured before use. + +三个 CLI 使用前都需要配置好认证。 + +> **Quick check | 快速检查:** Run `claude --version`, `codex --version`, and `gemini --version` to verify all three are installed. + +## Installation | 安装 + +### Option A: Direct Install (Recommended) | 直接安装(推荐) + +```bash +# Clone to your global Claude Code skills directory +# 克隆到 Claude Code 全局 skills 目录 +git clone https://github.com/axtonliu/ai-pair.git ~/.claude/skills/ai-pair +``` + +For project-level installation, clone into `.claude/skills/ai-pair` within your project directory instead. + +如需项目级安装,克隆到项目目录下的 `.claude/skills/ai-pair`。 + +### Option B: Manual | 手动安装 + +1. Download `SKILL.md` from this repo | 下载本仓库的 `SKILL.md` +2. Place it in `~/.claude/skills/ai-pair/SKILL.md` | 放到 `~/.claude/skills/ai-pair/SKILL.md` +3. Restart Claude Code | 重启 Claude Code + +## Usage | 使用 + +### Dev Team — for code, bugs, refactoring | 开发团队 — 写代码、修 bug、重构 + +```bash +/ai-pair dev-team MyProject +``` + +Team Lead creates | 团队领导创建: +- **developer** — writes code | 写代码 +- **codex-reviewer** — checks bugs, security, performance, edge cases | 审查 bug、安全、性能、边界条件 +- **gemini-reviewer** — checks architecture, design patterns, maintainability | 审查架构、设计模式、可维护性 + +### Content Team — for articles, scripts, newsletters | 内容团队 — 写文章、脚本、Newsletter + +```bash +/ai-pair content-team AI-Newsletter +``` + +Team Lead creates | 团队领导创建: +- **author** — writes content | 写内容 +- **codex-reviewer** — checks logic, accuracy, structure, fact-checking | 审查逻辑、准确性、结构、事实核查 +- **gemini-reviewer** — checks readability, engagement, style, audience fit | 审查可读性、吸引力、风格、受众适配 + +### Stop Team | 关闭团队 + +```bash +/ai-pair team-stop +``` + +## Real-World Example | 真实案例 + +We used `content-team` to review a newsletter article. The three AIs found completely different issues: + +我们用 `content-team` 审查了一篇 Newsletter 文章。三个 AI 发现的问题完全不同: + +- **Claude** (Team Lead): spotted an overreach in interpreting a cited source | 发现对引用来源的过度解读 +- **GPT** (Codex): dissected the argument chain and challenged a logical leap | 拆解论证链,质疑逻辑跳跃 +- **Gemini**: suggested the opening was too academic for the target audience | 建议开头对目标读者来说太学术化 + +None of these overlapped. That's the point. See [`examples/`](examples/) for step-by-step walkthrough scenarios. + +三者零重叠。这就是意义所在。查看 [`examples/`](examples/) 获取分步演示场景。 + +## File Structure | 文件结构 + +``` +ai-pair/ +├── SKILL.md # Claude Code skill definition | Skill 定义文件 +├── README.md # This file | 本文件 +├── LICENSE # MIT +└── examples/ # Usage examples | 使用示例 + ├── dev-team.md + └── content-team.md +``` + +## Troubleshooting | 常见问题 + +### Reviewers not actually calling Codex/Gemini CLI | 审查者没有真正调用 Codex/Gemini CLI + +**Symptom:** Reviews complete but only Claude Code's usage decreases; Codex/Gemini CLI usage stays flat. The sub-agents are role-playing as Codex/Gemini instead of actually invoking them. + +**症状:** 审查完成但只有 Claude Code 的用量在下降;Codex/Gemini CLI 用量没有任何变化。Sub-agent 在角色扮演而非真正调用外部 CLI。 + +**How to verify | 如何验证:** Check the review output for the `**Source: Codex CLI**` / `**Source: Gemini CLI**` label and the `### CLI Raw Output` section. If these are missing, the CLI was not called. + +**如何验证:** 检查审查输出中是否有 `**Source: Codex CLI**` / `**Source: Gemini CLI**` 标签和 `### CLI Raw Output` 部分。如果缺失,说明 CLI 没有被调用。 + +**Fix | 解决方案:** This was addressed in v1.1.0 with mandatory CLI invocation rules. If you're on an older version, update your SKILL.md. If the issue persists, ensure both CLIs are installed and authenticated (`codex --version`, `gemini --version`). + +**解决方案:** 此问题已在 v1.1.0 中通过强制 CLI 调用规则修复。如果你使用旧版本,请更新 SKILL.md。如果问题仍然存在,确认两个 CLI 都已安装并完成认证(`codex --version`、`gemini --version`)。 + +## What's Not Included | 未包含的功能 + +This open-source version includes the **Agent Teams mode** only. The full private version also has: + +开源版仅包含 **Agent Teams 模式**。完整私有版还包括: + +- **Manual mode** — two CLI instances communicating via shared file | 手动模式 — 两个 CLI 通过共享文件通信 +- **iTerm2 orchestration** — automated Author/Reviewer relay with file watchers | iTerm2 编排 — 自动化的创作/审查中继 + +These require specific local setup and are maintained separately. + +这些需要特定的本地配置,单独维护。 + +## Evolution | 演变 + +AI-Pair evolved from [AI Roundtable](https://github.com/axtonliu/ai-roundtable), a Chrome extension that lets multiple AI web interfaces discuss and cross-review in the same panel. AI-Pair moves this concept to the command line with structured role assignments, making it more practical for daily workflows. + +AI-Pair 从 [AI Roundtable](https://github.com/axtonliu/ai-roundtable) 演变而来。AI Roundtable 是一个 Chrome 扩展,让多个 AI 的网页版在同一个面板里讨论和互评。AI-Pair 把这个概念搬到了命令行,加入了结构化的角色分工,更适合日常工作流。 + +## Contributing | 贡献 + +Contributions welcome (low-maintenance project): + +欢迎贡献(低维护项目): + +- Reproducible bug reports (input + output + steps + environment) | 可复现的 bug 报告 +- Documentation improvements | 文档改进 +- Small PRs (fixes/docs) | 小型 PR(修复/文档) + +> **Note:** Feature requests may not be acted on due to limited maintenance capacity. | 功能需求可能因维护精力有限而无法响应。 + +## License | 许可证 + +[MIT](LICENSE) - Axton Liu + +--- + +## Author | 作者 + +**Axton Liu** — AI Educator & Creator + +- Website: [axtonliu.ai](https://www.axtonliu.ai) +- YouTube: [@AxtonLiu](https://youtube.com/@AxtonLiu) +- Twitter/X: [@axtonliu](https://x.com/axtonliu) + +### Learn More + +- [MAPS™ AI Agent Course](https://www.axtonliu.ai/aiagent) - Systematic AI agent skills training +- [Claude Skills: A Systematic Guide](https://www.axtonliu.ai/newsletters/ai-2/posts/claude-agent-skills-maps-framework) - Complete methodology +- [AI Elite Weekly Newsletter](https://www.axtonliu.ai/newsletters/ai-2) - Weekly AI insights +- [Free AI Course](https://www.axtonliu.ai/axton-free-course) - Get started with AI + +--- + +© AXTONLIU™ & AI 精英学院™ 版权所有 diff --git a/ai-pair/SKILL.md b/ai-pair/SKILL.md new file mode 100644 index 0000000..bfaf021 --- /dev/null +++ b/ai-pair/SKILL.md @@ -0,0 +1,609 @@ +--- +name: ai-pair +description: | + AI Pair Collaboration Skill. Coordinate multiple AI models to work together: + one creates (Author/Developer), others review (configurable: Codex, Gemini, Kimi). + Works for code, articles, video scripts, and any creative task. + + Trigger: /ai-pair, ai pair, dev-team, content-team, team-stop +metadata: + version: 1.4.0 +--- + +# AI Pair Collaboration + +Coordinate heterogeneous AI teams: one creates, others review from different angles. +Uses Claude Code's native Agent Teams capability with configurable reviewers (Codex, Gemini, Kimi). + +## Why Multiple AI Reviewers? + +Different AI models have fundamentally different review tendencies. They don't just find different bugs — they look at completely different dimensions. Using reviewers from different model families maximizes coverage. + +- **Codex** (OpenAI) — analytical, detail-oriented: bugs, security, edge cases +- **Gemini** (Google) — architectural, big-picture: design patterns, maintainability +- **Kimi** (Moonshot AI) — quality-focused, Chinese-native: code quality, naming, readability, Chinese context + +## Commands + +```bash +/ai-pair dev-team [project] # Default reviewers: codex + gemini +/ai-pair dev-team [project] --reviewers codex,gemini # Same as default +/ai-pair dev-team [project] --reviewers codex,kimi # Codex + Kimi +/ai-pair dev-team [project] --reviewers gemini,kimi # Gemini + Kimi +/ai-pair dev-team [project] --reviewers codex,gemini,kimi # All three +/ai-pair dev-team [project] --reviewers kimi # Kimi only +/ai-pair content-team [topic] # Default reviewers: codex + gemini +/ai-pair content-team [topic] --reviewers codex,kimi # Codex + Kimi +/ai-pair team-stop # Shut down the team +``` + +### `--reviewers` Flag + +- Comma-separated list of reviewer names: `codex`, `gemini`, `kimi` +- Default (when omitted): `codex,gemini` (backward compatible) +- At least one reviewer must be specified +- Team Lead parses the argument and only launches the selected reviewer agents +- If an invalid name is given, report error and list valid options + +Examples: +```bash +/ai-pair dev-team HighlightCut # codex + gemini (default) +/ai-pair dev-team HighlightCut --reviewers kimi # kimi only +/ai-pair dev-team HighlightCut --reviewers codex,kimi # codex + kimi +/ai-pair content-team AI-Newsletter --reviewers gemini,kimi # gemini + kimi +/ai-pair team-stop # Shut down team +``` + +## Prerequisites + +- **Claude Code** — Team Lead + agent runtime +- **Codex CLI** (`codex`) — for codex-reviewer (when selected) +- **Gemini CLI** (`gemini`) — for gemini-reviewer (when selected) +- **Kimi CLI** (`kimi`) — for kimi-reviewer (when selected), Moonshot AI's model +- Selected external CLIs must have authentication configured + +## Team Architecture + +### Dev Team (`/ai-pair dev-team [project]`) + +``` +User (Commander) + | +Team Lead (current Claude session) + |-- developer (Claude Code agent) — writes code, implements features + |-- codex-reviewer (when selected) — via codex CLI + | Focus: bugs, security, concurrency, performance, edge cases + |-- gemini-reviewer (when selected) — via gemini CLI + | Focus: architecture, design patterns, maintainability, alternatives + |-- kimi-reviewer (when selected) — via kimi CLI + Focus: code quality, naming conventions, readability, Chinese comments +``` + +### Content Team (`/ai-pair content-team [topic]`) + +``` +User (Commander) + | +Team Lead (current Claude session) + |-- author (Claude Code agent) — writes articles, scripts, newsletters + |-- codex-reviewer (when selected) — via codex CLI + | Focus: logic, accuracy, structure, fact-checking + |-- gemini-reviewer (when selected) — via gemini CLI + | Focus: readability, engagement, style consistency, audience fit + |-- kimi-reviewer (when selected) — via kimi CLI + Focus: narrative flow, emotional resonance, cultural sensitivity (Chinese audience) +``` + +## Workflow (Semi-Automatic) + +Team Lead coordinates the following loop: + +1. **User assigns task** → Team Lead sends to developer/author +2. **Developer/author completes** → Team Lead shows result to user +3. **User approves for review** → Team Lead sends to all selected reviewers in parallel +4. **Reviewers report back** → Team Lead consolidates and presents (only selected reviewers appear): + ``` + ## {Reviewer-Name} Review + {reviewer feedback summary} + + ## {Reviewer-Name} Review + {reviewer feedback summary} + ``` +5. **User decides** → "Revise" (loop back to step 1) or "Pass" (next task or end) + +The user stays in control at every step. No autonomous loops. + +## Project Detection + +The project/topic is determined by: + +1. **Explicitly specified** → use as-is +2. **Current directory is inside a project** → extract project name from path +3. **Ambiguous** → ask user to choose + +## Team Lead Execution Steps + +### Step 1: Parse Arguments + +Parse the command for: +- Team type: `dev-team` or `content-team` +- Project/topic name +- `--reviewers` flag (default: `codex,gemini`) + +Validate reviewer names. Valid values: `codex`, `gemini`, `kimi`. If invalid name found, report error immediately. + +### Step 2: Create Team + +``` +TeamCreate: team_name = "{project}-dev" or "{topic}-content" +``` + +### Step 3: Create Tasks + +Use TaskCreate to set up initial task structure: +1. "Awaiting task assignment" — for developer/author, status: pending + +For each selected reviewer: +- "Awaiting review" — for {reviewer}-reviewer, status: pending, blockedBy task 1 + +Example with `--reviewers codex,kimi`: +1. "Awaiting task assignment" — for developer, status: pending +2. "Awaiting review" — for codex-reviewer, status: pending, blockedBy task 1 +3. "Awaiting review" — for kimi-reviewer, status: pending, blockedBy task 1 + +### Step 4: Pre-flight CLI Check + +Before launching agents, verify ONLY the selected reviewers' CLIs: + +```bash +# Only check CLIs that are selected via --reviewers +# For codex (if selected): +command -v codex && codex --version || echo "CODEX_MISSING" +# For gemini (if selected): +command -v gemini && gemini --version || echo "GEMINI_MISSING" +# For kimi (if selected): +command -v kimi && kimi --version || echo "KIMI_MISSING" +``` + +If any selected CLI is missing, warn the user immediately and ask whether to: +- Proceed with degraded mode (Claude-only review for that reviewer, clearly labeled) +- Remove that reviewer from the team +- Abort + +### Step 5: Launch Agents + +Launch 1 + N agents (1 developer/author + N selected reviewers) using the Agent tool with `subagent_type: "general-purpose"` and `mode: "bypassPermissions"` (required because reviewers need to execute external CLI commands and read project files). + +See Agent Prompt Templates below for each agent's startup prompt. Only launch agents for selected reviewers. + +### Step 6: Confirm to User + +``` +Team ready. + +Team: {team_name} +Type: {Dev Team / Content Team} +Reviewers: {comma-separated selected reviewers} (via --reviewers) +Members: + - developer/author: ready + - {reviewer-1}-reviewer: ready + - {reviewer-2}-reviewer: ready + [... for each selected reviewer ...] + +Awaiting your first task. +``` + +## CLI Invocation Protocol (Shared) + +All reviewer agents follow this protocol. Team Lead includes it in each reviewer's prompt. + +``` +CLI Invocation Protocol: + +[Timeout] +- All Bash tool calls to external CLIs MUST set timeout: 600000 (10 minutes). +- External CLIs (codex/gemini/kimi) need 10-15 seconds to load, + plus model reasoning time. The default 2-minute timeout is far too short. + +[Degradation Retry by CLI] + +Codex CLI: +- Defaults to xhigh reasoning level. +- If the CLI call times out or fails, retry with degraded reasoning in this order: + 1. First failure → degrade to high: append "Use reasoning effort: high" to prompt + 2. Second failure → degrade to medium: append "Use reasoning effort: medium" + 3. Third failure → degrade to low: append "Use reasoning effort: low" + 4. Fourth failure → Claude fallback analysis (last resort) + +Gemini CLI: +- If timeout, append simplified instructions / reduce analysis dimensions. + 1. First failure → simplify prompt (fewer analysis dimensions) + 2. Second failure → minimal prompt (single-focus review) + 3. Third failure → Claude fallback analysis (last resort) + +Kimi CLI: +- Defaults to full thinking mode with --print. +- If the CLI call times out or fails, retry with degraded mode in this order: + 1. First failure → switch to --quiet (--print --output-format text --final-message-only) + 2. Second failure → add --no-thinking to disable extended thinking + 3. Third failure → simplified prompt (reduce analysis dimensions) + 4. Fourth failure → Claude fallback analysis (last resort) + +- Report the current degradation level to team-lead on each retry. + +[Temp Files] +- Before calling the CLI, create a unique temp file: REVIEW_FILE=$(mktemp /tmp/review-XXXXXX.txt) + Write content to $REVIEW_FILE. This prevents concurrent tasks from overwriting each other. + +[Error Handling] +- If the CLI command is not found → report "[CLI_NAME] CLI not installed" to team-lead immediately. Do NOT substitute your own review. +- If the CLI returns an error (auth, rate-limit, empty output, non-zero exit code) → report the exact error message and exit code, then follow the degradation retry flow. +- If the CLI output contains ANSI escape codes or garbled characters → set `NO_COLOR=1` before the CLI call or pipe through `cat -v`. +- NEVER silently skip the CLI call. +- Only use Claude fallback after ALL degradation retries have failed, clearly labeled "[Claude Fallback — [CLI_NAME] all retries failed]". + +[Cleanup] +- Clean up: rm -f $REVIEW_FILE after capturing output. +``` + +## Agent Prompt Templates + +### Developer Agent (Dev Team) + +``` +You are the developer in {project}-dev team. You write code. + +Project path: {project_path} +Project info: {CLAUDE.md summary if available} + +Workflow: +1. Read relevant files to understand context +2. Implement the feature / fix the bug / refactor +3. Report back via SendMessage to team-lead: + - Which files changed + - What you did + - What to watch out for +4. When receiving reviewer feedback, address items and report again +5. Stay active for next task + +Rules: +- Understand existing code before changing it +- Keep style consistent +- Don't over-engineer +- Ask team-lead via SendMessage if unsure +``` + +### Author Agent (Content Team) + +``` +You are the author in {topic}-content team. You write content. + +Working directory: {working_directory} +Topic: {topic} + +Workflow: +1. Understand the writing task and reference materials +2. If style-memory.md exists, read and follow it +3. Write content following the appropriate format +4. Report back via SendMessage to team-lead with full content or summary +5. When receiving reviewer feedback, revise and report again +6. Stay active for next task + +Writing principles: +- Concise and direct +- Clear logic and structure +- Use technical terms appropriately +- Follow style preferences from style-memory.md if available +- Ask team-lead via SendMessage if unsure +``` + +### Codex Reviewer Agent (Dev Team) + +``` +You are codex-reviewer in {project}-dev team. Your job is to get CODE REVIEW from the real Codex CLI. + +CRITICAL RULE: You MUST use the Bash tool to invoke the `codex` command. You are a dispatcher, NOT a reviewer. +DO NOT review the code yourself. DO NOT role-play as Codex. Your value is that you bring a DIFFERENT model's perspective. +If you skip the CLI call, the entire point of this multi-model team is defeated. + +Project path: {project_path} + +Review process: +1. Read relevant code changes using Read/Glob/Grep +2. Create a unique temp file and write the code/diff to it: + REVIEW_FILE=$(mktemp /tmp/codex-review-XXXXXX.txt) +3. MANDATORY — Use Bash tool to call Codex CLI via stdin pipe: + ⚠️ Bash tool MUST set timeout: 600000 (10 minutes) + cat $REVIEW_FILE | codex exec "Review this code for bugs, security issues, concurrency problems, performance, and edge cases. Be specific about file paths and line numbers. Output in Chinese." 2>&1 +4. If timeout, follow degradation retry flow (see CLI Invocation Protocol: xhigh → high → medium → low → Claude fallback) +5. Capture the FULL CLI output. Do not summarize or rewrite it. +6. Clean up: rm -f $REVIEW_FILE +7. Report to team-lead via SendMessage: + + ## Codex Code Review + + **Source: Codex CLI [reasoning level]** (or "Source: Claude Fallback — four retries all failed" if all failed) + + ### CLI Raw Output + {paste the actual codex CLI output here} + + ### Consolidated Assessment + + #### CRITICAL (blocking issues) + - {description + file:line + suggested fix} + + #### WARNING (important issues) + - {description + suggestion} + + #### SUGGESTION (improvements) + - {suggestion} + + ### Summary + {one-line quality assessment} + +Focus: bugs, security vulnerabilities, concurrency/race conditions, performance, edge cases. + +Follow the shared CLI Invocation Protocol (timeout + degradation retry). Stay active for next review task. +``` + +### Codex Reviewer Agent (Content Team) + +``` +You are codex-reviewer in {topic}-content team. Your job is to get CONTENT REVIEW from the real Codex CLI. + +CRITICAL RULE: You MUST use the Bash tool to invoke the `codex` command. You are a dispatcher, NOT a reviewer. +DO NOT review the content yourself. DO NOT role-play as Codex. Your value is that you bring a DIFFERENT model's perspective. +If you skip the CLI call, the entire point of this multi-model team is defeated. + +Review process: +1. Understand the content and context +2. Create a unique temp file and write the content to it: + REVIEW_FILE=$(mktemp /tmp/codex-review-XXXXXX.txt) +3. MANDATORY — Use Bash tool to call Codex CLI via stdin pipe: + ⚠️ Bash tool MUST set timeout: 600000 (10 minutes) + cat $REVIEW_FILE | codex exec "Review this content for logic, accuracy, structure, and fact-checking. Be specific. Output in Chinese." 2>&1 +4. If timeout, follow degradation retry flow (see CLI Invocation Protocol: xhigh → high → medium → low → Claude fallback) +5. Capture the FULL CLI output. +6. Clean up: rm -f $REVIEW_FILE +7. Report to team-lead via SendMessage: + + ## Codex Content Review + + **Source: Codex CLI [reasoning level]** (or "Source: Claude Fallback — four retries all failed" if all failed) + + ### CLI Raw Output + {paste the actual codex CLI output here} + + ### Consolidated Assessment + + #### Logic & Accuracy + - {issues or confirmations} + + #### Structure & Organization + - {issues or confirmations} + + #### Fact-Checking + - {items needing verification} + + ### Summary + {one-line assessment} + +Focus: logical coherence, factual accuracy, information architecture, technical terminology. + +Follow the shared CLI Invocation Protocol (timeout + degradation retry). Stay active for next review task. +``` + +### Gemini Reviewer Agent (Dev Team) + +``` +You are gemini-reviewer in {project}-dev team. Your job is to get CODE REVIEW from the real Gemini CLI. + +CRITICAL RULE: You MUST use the Bash tool to invoke the `gemini` command. You are a dispatcher, NOT a reviewer. +DO NOT review the code yourself. DO NOT role-play as Gemini. Your value is that you bring a DIFFERENT model's perspective. +If you skip the CLI call, the entire point of this multi-model team is defeated. + +Project path: {project_path} + +Review process: +1. Read relevant code changes using Read/Glob/Grep +2. Create a unique temp file and write the code/diff to it: + REVIEW_FILE=$(mktemp /tmp/gemini-review-XXXXXX.txt) +3. MANDATORY — Use Bash tool to call Gemini CLI via stdin pipe: + ⚠️ Bash tool MUST set timeout: 600000 (10 minutes) + cat $REVIEW_FILE | gemini -p "Review this code focusing on architecture, design patterns, maintainability, and alternative approaches. Be specific about file paths and line numbers. Output in Chinese." 2>&1 +4. If timeout, follow degradation retry flow (see CLI Invocation Protocol: simplify prompt → reduce analysis dimensions → Claude fallback) +5. Capture the FULL CLI output. Do not summarize or rewrite it. +6. Clean up: rm -f $REVIEW_FILE +7. Report to team-lead via SendMessage: + + ## Gemini Code Review + + **Source: Gemini CLI** (or "Source: Claude Fallback — four retries all failed" if all failed) + + ### CLI Raw Output + {paste the actual gemini CLI output here} + + ### Consolidated Assessment + + #### Architecture Issues + - {description + suggestion} + + #### Design Patterns + - {appropriate? + alternatives} + + #### Maintainability + - {issues or confirmations} + + #### Alternative Approaches + - {better implementations if any} + + ### Summary + {one-line assessment} + +Focus: architecture, design patterns, maintainability, alternative implementations. + +Follow the shared CLI Invocation Protocol (timeout + degradation retry). Stay active for next review task. +``` + +### Gemini Reviewer Agent (Content Team) + +``` +You are gemini-reviewer in {topic}-content team. Your job is to get CONTENT REVIEW from the real Gemini CLI. + +CRITICAL RULE: You MUST use the Bash tool to invoke the `gemini` command. You are a dispatcher, NOT a reviewer. +DO NOT review the content yourself. DO NOT role-play as Gemini. Your value is that you bring a DIFFERENT model's perspective. +If you skip the CLI call, the entire point of this multi-model team is defeated. + +Review process: +1. Understand the content and context +2. Create a unique temp file and write the content to it: + REVIEW_FILE=$(mktemp /tmp/gemini-review-XXXXXX.txt) +3. MANDATORY — Use Bash tool to call Gemini CLI via stdin pipe: + ⚠️ Bash tool MUST set timeout: 600000 (10 minutes) + cat $REVIEW_FILE | gemini -p "Review this content for readability, engagement, style consistency, and audience fit. Be specific. Output in Chinese." 2>&1 +4. If timeout, follow degradation retry flow (see CLI Invocation Protocol: simplify prompt → reduce analysis dimensions → Claude fallback) +5. Capture the FULL CLI output. +6. Clean up: rm -f $REVIEW_FILE +7. Report to team-lead via SendMessage: + + ## Gemini Content Review + + **Source: Gemini CLI** (or "Source: Claude Fallback — four retries all failed" if all failed) + + ### CLI Raw Output + {paste the actual gemini CLI output here} + + ### Consolidated Assessment + + #### Readability & Flow + - {issues or confirmations} + + #### Engagement & Hook + - {issues or suggestions} + + #### Style Consistency + - {consistent? + specific deviations} + + #### Audience Fit + - {appropriate? + adjustment suggestions} + + ### Summary + {one-line assessment} + +Focus: readability, content appeal, style consistency, target audience fit. + +Follow the shared CLI Invocation Protocol (timeout + degradation retry). Stay active for next review task. +``` + +### Kimi Reviewer Agent (Dev Team) + +``` +You are kimi-reviewer in {project}-dev team. Your job is to get CODE REVIEW from the real Kimi CLI. + +CRITICAL RULE: You MUST use the Bash tool to invoke the `kimi` command. You are a dispatcher, NOT a reviewer. +DO NOT review the code yourself. DO NOT role-play as Kimi. Your value is that you bring a DIFFERENT model's perspective (Moonshot AI / Kimi K2). +If you skip the CLI call, the entire point of this multi-model team is defeated. + +Project path: {project_path} + +Review process: +1. Read relevant code changes using Read/Glob/Grep +2. Create a unique temp file and write the code/diff to it: + REVIEW_FILE=$(mktemp /tmp/kimi-review-XXXXXX.txt) +3. MANDATORY — Use Bash tool to call Kimi CLI via stdin pipe: + ⚠️ Bash tool MUST set timeout: 600000 (10 minutes) + cat $REVIEW_FILE | kimi --print -p "审查这段代码,重点关注:代码质量(简洁性、DRY原则、单一职责)、命名规范(变量/函数/类名是否清晰准确、风格是否一致)、可读性(逻辑是否易懂、是否需要注释)、中文注释质量(如有中文注释,检查准确性和表达)。请指出具体文件路径和行号。用中文输出。" 2>&1 +4. If timeout, follow degradation retry flow (see CLI Invocation Protocol: --print → --quiet → --no-thinking → simplified prompt → Claude fallback) +5. Capture the FULL CLI output. Do not summarize or rewrite it. +6. Clean up: rm -f $REVIEW_FILE +7. Report to team-lead via SendMessage: + + ## Kimi Code Review + + **Source: Kimi CLI** (or "Source: Claude Fallback — all retries failed" if all failed) + + ### CLI Raw Output + {paste the actual kimi CLI output here} + + ### Consolidated Assessment + + #### Code Quality + - {simplicity, DRY, single responsibility + file:line + suggested fix} + + #### Naming Conventions + - {variable/function/class names: clear? consistent? following project conventions?} + + #### Readability + - {code clarity, complexity, self-documenting quality} + + #### Chinese Comments Quality + - {accuracy, completeness, grammar of Chinese comments if present; or "N/A" if no Chinese comments} + + ### Summary + {one-line quality assessment} + +Focus: code quality, naming conventions, readability, Chinese code comments quality. + +Follow the shared CLI Invocation Protocol (timeout + degradation retry). Stay active for next review task. +``` + +### Kimi Reviewer Agent (Content Team) + +``` +You are kimi-reviewer in {topic}-content team. Your job is to get CONTENT REVIEW from the real Kimi CLI. + +CRITICAL RULE: You MUST use the Bash tool to invoke the `kimi` command. You are a dispatcher, NOT a reviewer. +DO NOT review the content yourself. DO NOT role-play as Kimi. Your value is that you bring a DIFFERENT model's perspective (Moonshot AI / Kimi K2). +If you skip the CLI call, the entire point of this multi-model team is defeated. + +Review process: +1. Understand the content and context +2. Create a unique temp file and write the content to it: + REVIEW_FILE=$(mktemp /tmp/kimi-review-XXXXXX.txt) +3. MANDATORY — Use Bash tool to call Kimi CLI via stdin pipe: + ⚠️ Bash tool MUST set timeout: 600000 (10 minutes) + cat $REVIEW_FILE | kimi --print -p "审查这篇内容,重点关注:叙事节奏(故事弧线、段落衔接、起承转合)、情感共鸣(情感冲击力、读者代入感、语调把控)、中文受众文化适配(文化引用是否恰当、表达是否符合中文读者习惯、本地化质量)。请具体指出问题位置。用中文输出。" 2>&1 +4. If timeout, follow degradation retry flow (see CLI Invocation Protocol: --print → --quiet → --no-thinking → simplified prompt → Claude fallback) +5. Capture the FULL CLI output. +6. Clean up: rm -f $REVIEW_FILE +7. Report to team-lead via SendMessage: + + ## Kimi Content Review + + **Source: Kimi CLI** (or "Source: Claude Fallback — all retries failed" if all failed) + + ### CLI Raw Output + {paste the actual kimi CLI output here} + + ### Consolidated Assessment + + #### Narrative Flow + - {story arc, pacing, transitions between sections} + + #### Emotional Resonance + - {emotional impact, reader connection, tone consistency} + + #### Cultural Sensitivity (Chinese Audience) + - {cultural references, idioms, audience-appropriate expressions, localization quality} + + ### Summary + {one-line assessment} + +Focus: narrative flow, emotional resonance, cultural sensitivity for Chinese audience. + +Follow the shared CLI Invocation Protocol (timeout + degradation retry). Stay active for next review task. +``` + +## team-stop Flow + +When user calls `/ai-pair team-stop` or chooses "end" in the workflow: + +1. Send `shutdown_request` to all active agents +2. Wait for all agents to confirm shutdown +3. Call `TeamDelete` to clean up team resources +4. Output: + ``` + Team shut down. + Closed members: developer/author, {list of active reviewers} + Resources cleaned up. + ``` diff --git a/ai-pair/examples/content-team.md b/ai-pair/examples/content-team.md new file mode 100644 index 0000000..3c797d6 --- /dev/null +++ b/ai-pair/examples/content-team.md @@ -0,0 +1,102 @@ +# Content Team Example + +## Scenario: Review a Newsletter Article + +You've drafted a newsletter about AI memory systems and want multi-perspective feedback before publishing. + +### Start the team + +```bash +/ai-pair content-team AI-Newsletter +``` + +Output: +``` +Team ready. + +Team: AI-Newsletter-content +Type: Content Team +Members: + - author: ready + - codex-reviewer: ready + - gemini-reviewer: ready + +Awaiting your first task. +``` + +### Assign a task + +``` +Review this draft newsletter article about why AI memory +(like MEMORY.md in Claude Code) isn't actually "memory" in the +way most people think. The article argues that it's closer to +a post-it note than a brain. + +[paste your draft or provide file path] +``` + +The author agent reads the draft and prepares it for review. You approve sending to reviewers. + +### Review results + +``` +## Codex Review + +### Logic & Accuracy +- The claim "LLMs have no persistent state between sessions" is technically + correct but oversimplified. Some systems do maintain vector stores that + persist. Consider qualifying with "by default" or "natively". +- The analogy to post-it notes breaks down: post-it notes don't have + retrieval logic. MEMORY.md is more like a briefing document. + +### Fact-Checking +- The reference to "context window limits of 200K tokens" should specify + this is Claude's limit. GPT-4 Turbo is 128K. + +### Summary +Solid argument, but two factual claims need tightening. + +## Gemini Review + +### Readability & Flow +- The opening paragraph uses three technical terms before the reader + gets the hook. Consider leading with the relatable scenario first. + +### Engagement & Hook +- The "post-it note" metaphor is strong but introduced too late (paragraph 4). + Move it to the opening for immediate impact. + +### Audience Fit +- Tone shifts between casual (paragraphs 1-3) and academic (paragraphs 4-6). + The casual tone matches the target audience better — maintain it throughout. + +### Summary +Good content, needs structural reorganization for maximum impact. +``` + +Codex caught **factual precision issues**. Gemini caught **readability and structure issues**. Zero overlap. + +### Iterate + +You tell Team Lead: +``` +Fix the factual claims Codex flagged. +Move the post-it metaphor to the opening as Gemini suggested. +Keep the casual tone throughout. +Don't change the core argument. +``` + +The author revises. You can send for another round of review or pass. + +### End the session + +```bash +/ai-pair team-stop +``` + +## Tips for Content Team + +1. **Provide context about your audience** — reviewers give better feedback when they know who's reading +2. **Don't fix everything** — you decide which feedback matters. Codex tends to over-index on precision; Gemini tends to over-index on accessibility +3. **Use iteratively** — first round for big issues, second round for polish +4. **Style memory** — if you have a `style-memory.md` file, the author agent will automatically follow your style preferences diff --git a/ai-pair/examples/dev-team.md b/ai-pair/examples/dev-team.md new file mode 100644 index 0000000..0bd8f0a --- /dev/null +++ b/ai-pair/examples/dev-team.md @@ -0,0 +1,81 @@ +# Dev Team Example + +## Scenario: Review a Pull Request + +You're working on a project and want multiple AI perspectives on your code changes. + +### Start the team + +```bash +/ai-pair dev-team my-web-app +``` + +Output: +``` +Team ready. + +Team: my-web-app-dev +Type: Dev Team +Members: + - developer: ready + - codex-reviewer: ready + - gemini-reviewer: ready + +Awaiting your first task. +``` + +### Assign a task + +``` +Implement rate limiting for the /api/login endpoint. +Max 5 attempts per IP per 15 minutes. +``` + +The developer agent reads the codebase, implements the feature, and reports back. + +### Review results + +After you approve sending for review, both reviewers analyze in parallel: + +``` +## Codex Review + +### WARNING +- Rate limit key uses only IP address. Behind a proxy, all users share one IP. + Consider combining IP + user-agent or using X-Forwarded-For. +- No cleanup mechanism for expired entries in the rate limit store. + +### SUGGESTION +- Add a header (X-RateLimit-Remaining) so clients know their status. + +### Summary +Functional implementation, but proxy scenario needs attention. + +## Gemini Review + +### Architecture Issues +- In-memory store won't work with multiple server instances. + Consider Redis or a shared store. + +### Design Patterns +- Rate limiter is tightly coupled to the route handler. + Extract as middleware for reuse on other endpoints. + +### Summary +Works for single-instance deployment. Needs abstraction for production scale. +``` + +Notice how Codex found a **security edge case** (proxy IP sharing) while Gemini found an **architecture limitation** (single-instance only). Different dimensions, both valuable. + +### Decide + +You can say: +- **"Revise"** — feedback gets sent to developer, loop continues +- **"Pass"** — move to next task or end team +- **"Revise, but only fix the proxy issue and Redis. Skip the middleware refactor for now."** — you control the scope + +### End the session + +```bash +/ai-pair team-stop +``` diff --git a/annuity-disclosure-crawler/SKILL.md b/annuity-disclosure-crawler/SKILL.md new file mode 100644 index 0000000..f921d7f --- /dev/null +++ b/annuity-disclosure-crawler/SKILL.md @@ -0,0 +1,112 @@ +--- +name: annuity-disclosure-crawler +description: 全量爬取中国企业年金基金投资管理人在其官网发布的《企业年金基金投资管理情况》季度管理报告。内置人社部许可的22家投资管理人名录+每家官网披露栏目入口、抓取策略与站点反爬坑位;驱动脚本按季全量下载并做真伪校验与清单记录。当需要采集/批量下载企业年金(或职业年金)季度管理报告/信息披露、定位某投资管理人官网披露页、更新报告库、或做年金管理人季报数据集时使用。触发词:企业年金、投资管理人、季度报告、季报、信息披露、管理情况、年金爬取、全量爬取、年金披露、pension disclosure crawl。 +--- + +# 企业年金投资管理人季报全量爬取 + +## 这个技能做什么 + +把人社部许可的 **22 家企业年金基金投资管理人**在各自官网公开发布的 +《企业年金基金投资管理情况》**季度报告**,按季**全量**抓取到本地,做真伪校验并生成清单。 +名录、每家披露栏目 URL、抓取策略、站点反爬坑位都已固化在 `references/registry.json`, +两个脚本读它干活,无需每次重新摸索。 + +核心事实(先读懂再动手): + +- **口径**:抓的是投资管理人**自披露**的《企业年金基金投资管理情况》季度信息披露表。它 ≠ 受托人向委托人/人社部报送的完整《企业年金基金管理情况季度报告》全文(后者按规定不公开)。检索时排在前面的“集合型企业年金计划管理情况信息披露表”常是**受托人口径**(如工商银行、各托管行),别混进投资管理人季报。 +- **不是每家都公开**:约 19 家官网公开可下;博时、招商的季报仅登录客户门户可见;建信养老金官网只发“养老金产品”层报告且被 WAF+加密挡住。详见 registry 里各家 `access`。 +- **报告形态三种**:PDF(多数)、**DOCX**(泰康资产,链接无扩展名)、**HTML 网页正文**(海富通/南方/长江/中信证券/人保,无 PDF 附件,存网页)。 +- **数据坑**:人保养老(picc)官网自 2022Q1 起正文区为空,只登记标题+日期,近四年数据未公开。 + +## 两层抓取工作流 + +先用纯 HTTP(快、无依赖),搞不定的再上无头浏览器。 + +### 第 1 步:看名录与策略 + +```bash +python3 scripts/crawl.py --list +``` + +列出 22 家的 slug / 简称 / access(public|waf|login) / strategy / 披露入口。 + +### 第 2 步:HTTP 全量抓取(默认路径) + +```bash +# 全量抓所有可 HTTP 抓取的机构(跳过 waf/login,会明确提示哪几家要换 headless) +python3 scripts/crawl.py --out annuity_reports + +# 只抓某几家;--latest N 只留最新 N 期(0=全量,默认全量) +python3 scripts/crawl.py --only m04,m09,m17 --latest 4 --out annuity_reports +``` + +`strategy` 含义(脚本自动按此处理,一般无需关心): +`pdf_index` 列表页直给 PDF 直链 · `detail_index` 列表→详情页→再取文件 · +`html_index` 报告本身是 HTML 网页(存网页)· `spa_api` 列表走后端 JSON · +`headless` 需浏览器(脚本会跳过并提示)· `login_blocked` 非公开(跳过并说明)。 + +脚本已内置的通用能力:列表翻页(首页 index.html + index_1/2… 自动补全)、 +GBK/UTF-8 自适应解码、pdfjs `viewer.html?file=` 包装解包、相对链接补全、 +期次识别(`2026Q1`/`2026年1季度`/中文数字季度)、真伪校验(PDF 看 `%PDF` 魔数、 +DOCX 看 `PK`、HTML 看大小+关键字)、内容 MD5 去重、同期两类报告防覆盖。 + +### 第 3 步:无头浏览器兜底(WAF/SPA 机构) + +当第 2 步对某家提示“0 命中:请改用 crawl_headless.py”,或该家 `access=waf`/`strategy=headless`: + +```bash +pip install playwright --break-system-packages && python3 -m playwright install chromium + +# 默认抓所有需浏览器的机构;也可 --only 指定;--headful 显示窗口调试 +python3 scripts/crawl_headless.py --only m15,m21 --latest 4 --out annuity_reports +``` + +真实 Chromium 会自动过瑞数(botgate 412)、加速乐(jsl 521)等 JS 挑战, +渲染出 SPA 列表后用带 Cookie 的浏览器上下文下载(含跨域文件站)。复用 crawl.py 的 +识别/校验/命名逻辑,落地到**同一** `--out` 目录,另出 `manifest_headless.*`。 + +典型需 headless 的:富国/工银瑞信/嘉实/易方达(SPA 列表)、平安养老/华泰资产(动态列表)、 +银华/太平养老/中金(反爬 WAF)。 + +## 输出结构与清单 + +``` +annuity_reports/ +├── m04/ m04_2026Q1.pdf m04_2025Q4.pdf ... _disclosure_page.html +├── m13/ m13_2026Q1.docx ... +├── m22/ m22_2026Q1.html ... +├── manifest.csv / manifest.json # crawl.py 清单:机构·期次·状态·字节·本地路径·源URL +└── manifest_headless.csv / .json # crawl_headless.py 清单 +``` + +`status` 取值:`ok`(校验通过)/ `not-pdf`/`not-docx`/`suspect`(存为 `*.suspect` 待查)/ `download-fail:*`。 +交付前用 manifest 核对每家是否抓全、有无 suspect。 + +## 全量 vs 增量 + +- **全量**:不加 `--latest`(默认 0),脚本翻完列表所有分页,抓每家全部历史季度。 + 首轮建议单跑几家验证:`--only m04,m17,m13`,确认无误再整体跑。 +- **增量**:定期只补新季度用 `--latest 2`,MD5 去重会跳过已存在的同内容文件(但会重新下载比对, + 真正省流可结合已存在文件名跳过)。季度披露节奏:一般次季度中下旬发布(如 Q1 报告约 6 月中下旬)。 + +## 排障速查 + +- **HTTP 0 命中** → 列表 JS 渲染或被 WAF 挡:改 `crawl_headless.py`。 +- **headless 仍 0 命中** → 可能需登录、或报告藏在需点击的折叠/下一页里:加 `--headful` 肉眼看, + 必要时在 registry 该家 `list_url` 填精确分页模板或改 `strategy`。 +- **拿到的 PDF 打不开/很小** → 多半是 WAF 降级的 HTML 错误页;脚本已标 `suspect`。换 headless。 +- **404 一堆中文名 .pdf** → 详情页里的“显示用文件名”被误当链接;已在 `files_in_page` 收敛,若仍有属噪声可忽略(不影响真链)。 +- **工银瑞信**:官网迁 icbccs→icbcubs 成 SPA,直链多 404;可靠源是 Wayback 快照 + `https://web.archive.org/web/{ts}id_/{原PDF直链}`(快照止于 2024Q2)。 +- **name 冲突** `rtk gain` 无关;与本技能无关的报错先 `--list` 自检 registry 是否可读。 + +## 维护 registry(增删改机构或修坑) + +`references/registry.json` 是唯一事实源,字段语义见其 `meta.field_notes`。常见维护: + +- 名单变动:以**人社部社保基金监管司**最新《企业年金基金管理机构名单》为准,增删 `managers` 条目。 +- 某家官网改版:更新其 `disclosure_url` / `list_url`(分页模板,`{n}` 为页码) / `file_url_pattern`(报告文件或报告页 URL 正则) / `strategy`。 +- 加新机构:复制一条,填 `slug`(mNN)、`short`、`name`、`category`、`access`、`strategy`、`item_type`、入口与正则,先 `--only 新slug --latest 2` 验证。 + +registry 里每家的 `notes` 记录了该站的真实坑位(编码、反爬类型、命名规律、口径提醒),改站点前先读。 diff --git a/annuity-disclosure-crawler/references/registry.json b/annuity-disclosure-crawler/references/registry.json new file mode 100644 index 0000000..3e8af06 --- /dev/null +++ b/annuity-disclosure-crawler/references/registry.json @@ -0,0 +1,421 @@ +{ + "meta": { + "title": "企业年金基金投资管理人 · 官网季度管理报告披露源登记", + "roster_size": 22, + "roster_source": "人社部 2021-10《关于企业年金基金管理机构资格延续的通告》中的投资管理人(22家)+ 基金业协会 amac.org.cn 查询栏目交叉核对。以人社部社保基金监管司最新《企业年金基金管理机构名单》为最终依据。", + "verified": "2026-07", + "report_title_canonical": "企业年金基金投资管理情况(季度)", + "field_notes": { + "access": "public=官网公开可匿名下载; waf=官网有披露栏目但被反爬WAF/JS挑战拦截,需无头浏览器; login=季报仅登录客户门户可见,不公开", + "strategy": "驱动脚本 scripts/crawl.py 的抓取策略:pdf_index=列表页直接给文件直链; detail_index=列表→详情页→再取文件链; html_index=报告本身是HTML网页(无PDF附件),存网页; spa_api=列表走后端JSON接口; headless=需 playwright 渲染(WAF/SPA); login_blocked=跳过", + "item_type": "报告落地文件类型:pdf / docx / html", + "list_url": "披露列表页;{n} 为翻页占位符(全量抓取时从1递增直到空页)" + } + }, + "managers": [ + { + "slug": "m01", + "short": "博时", + "name": "博时基金管理有限公司", + "category": "基金公司", + "homepage": "https://www.bosera.com", + "access": "login", + "strategy": "login_blocked", + "item_type": "html", + "disclosure_url": "https://www.bosera.com/column/index.do?classid=00020002000600090001", + "list_url": null, + "page_param": null, + "file_url_pattern": null, + "notes": "官网养老/年金板块的季度管理报告、动态月报、净值持仓在「年金客户专区」,需账号密码登录 trade.bosera.com,不对公众公开。客服 95105568。" + }, + { + "slug": "m02", + "short": "富国", + "name": "富国基金管理有限公司", + "category": "基金公司", + "homepage": "https://www.fullgoal.com.cn", + "access": "public", + "strategy": "detail_index", + "item_type": "pdf", + "disclosure_url": "https://www.fullgoal.com.cn/main/InstiServices/Retirement/RetirementInfoDis/qynjtzgl/index.html", + "list_url": "https://www.fullgoal.com.cn/main/InstiServices/Retirement/RetirementInfoDis/qynjtzgl/index.html", + "page_param": null, + "file_url_pattern": "https?://www\\.fullgoal\\.com\\.cn/(upload/fck/userfiles/file|wbs-file/ws)/[^\"'\\s]+\\.pdf", + "example_links": [ + "https://www.fullgoal.com.cn/wbs-file/ws/20250320/73059d0333984f7cb04df6ac6fe35fec.pdf" + ], + "notes": "Vue SPA 但列表/文章页 SSR,PDF 直链稳定。栏目→机构服务→养老金信息披露→企业年金投资管理。命名早期 fgjjglyxgsqynjjjtzglqk(YYYYnXjd).pdf,后期哈希名。抓取时官网疑似停留在 2024Q4。SPA 渲染不全时用 headless 兜底。\n\n[2026-07-07 全量验证] crawl.py HTTP 全量抓取通过,10期(2023Q4-2026Q1)。⚠️该披露页无翻页控件,就是官网展示的全部——早于2023Q4的报告在当前官网结构下不存在任何入口,历史更早数据对公众不可得(非爬虫限制,是官网只保留近~2年展示)。" + }, + { + "slug": "m03", + "short": "工银瑞信", + "name": "工银瑞信基金管理有限公司", + "category": "基金公司", + "homepage": "https://www.icbcubs.com.cn", + "access": "waf", + "strategy": "headless", + "item_type": "pdf", + "disclosure_url": "https://www.icbccs.com.cn/gyrx/yljj/qynj/qynjxxpl/pages/1.html", + "list_url": "https://www.icbccs.com.cn/gyrx/yljj/qynj/qynjxxpl/pages/{n}.html", + "page_param": "{n}", + "file_url_pattern": "https?://www\\.icbc(cs|ubs)\\.com\\.cn/upload/[0-9]+/[0-9]+/[^\"'\\s]+\\.pdf", + "example_links": [ + "https://www.icbccs.com.cn/upload/2427/2023/20240905qynjglqk.pdf" + ], + "notes": "因瑞信被UBS收购,域名 icbccs→icbcubs 迁移为 Vue SPA,旧直链多404。可靠来源为 Wayback:https://web.archive.org/web/{ts}id_/{原PDF直链}(快照止于2024Q2)。新站列表接口 /gyrx-article/app/article/searchPage 需未公开 POST 参数。注意别混入工商银行(受托人)口径的披露表。\n\n[2026-07-07 复核] 确认 icbccs.com.cn 旧路径headless渲染下仍404(\"此次请求暂不能处理\"),域名迁移导致的失效是稳定状态非偶发。当前可靠来源仍只有 Wayback 快照(止于2024Q2);2024Q3至今(含2026Q1)在新站(icbcubs.com.cn) SPA 后台是否已发布不明——新站文章接口需要的POST参数未逆向出来,这段历史目前对我们不可得。" + }, + { + "slug": "m04", + "short": "国泰", + "name": "国泰基金管理有限公司", + "category": "基金公司", + "homepage": "https://www.gtfund.com", + "access": "public", + "strategy": "pdf_index", + "item_type": "pdf", + "disclosure_url": "https://www.gtfund.com/Etrade/Report/nianjinreport/", + "list_url": "https://www.gtfund.com/Etrade/Report/nianjinreport/", + "page_param": null, + "file_url_pattern": "https?://st\\.gtfund\\.com/report/[0-9]{4}/[0-9]{2}/[^\"'\\s]+\\.pdf", + "example_links": [ + "https://st.gtfund.com/report/2026/06/企业年金基金信息披露表_企业年金基金投资管理情况2026Q1.pdf" + ], + "notes": "最省事的正面样本:单个列表页即列出从2022至今十余期,PDF 托管 st.gtfund.com/report/YYYY/MM/,文件名含中文与 YYYYQn,需 URL 编码。" + }, + { + "slug": "m05", + "short": "海富通", + "name": "海富通基金管理有限公司", + "category": "基金公司", + "homepage": "https://www.hftfund.com", + "access": "public", + "strategy": "html_index", + "item_type": "html", + "disclosure_url": "https://www.hftfund.com/annuity/info/index.html", + "list_url": "https://www.hftfund.com/annuity/info/index{n}.html", + "page_param": "{n}", + "file_url_pattern": "https?://www\\.hftfund\\.com/contents/[0-9]{4}/[0-9]+/[^\"'\\s]+\\.html", + "example_links": [ + "https://www.hftfund.com/contents/2025/6/13-399abf20de9f46a59c180b96a9eb12f3.html" + ], + "notes": "报告为 HTML 正文页(无PDF附件),存网页存档即可。列表分页 index.html/index2.html/index3.html;列表 AJAX 渲染,静态只拿到部分历史,全量需 headless 枚举分页。detail URL 用随机哈希。\n\n[2026-07-07 全量验证] HTTP 静态分页拿到 2012A-2023Q2 共46期,历史深度全名录最佳。⚠️但2023Q3至今(含2026Q1最新)在静态HTML里不存在——该区间列表改为AJAX渲染,HTTP拿不到,需 crawl_headless.py 专门补最近这一段;即“旧历史全,新数据缺”,两种手段需配合使用才能补全全部期次。" + }, + { + "slug": "m06", + "short": "华夏", + "name": "华夏基金管理有限公司", + "category": "基金公司", + "homepage": "https://www.chinaamc.com.cn", + "access": "public", + "strategy": "detail_index", + "item_type": "pdf", + "disclosure_url": "https://www.chinaamc.com.cn/yanglaojijin/nianjin/nianjinyeji/index.shtml", + "list_url": "https://www.chinaamc.com.cn/yanglaojijin/nianjin/nianjinyeji/index_{n}.shtml", + "page_param": "{n}", + "file_url_pattern": "https?://www\\.chinaamc\\.com/(upload/resources/file/[^\"'\\s]+\\.pdf|front/ui/contentcore/resource/download\\?ID=[0-9]+)", + "example_links": [ + "https://www.chinaamc.com/upload/resources/file/2026/06/18/453207.pdf", + "https://www.chinaamc.com/front/ui/contentcore/resource/download?ID=433263" + ], + "notes": "养老金频道→年金→年金业绩。列表每条→详情页 /c/YYYY-MM-DD/xxxxxx.shtml,内含PDF直链或 contentcore/resource/download?ID= 下载接口。覆盖2017至今,最新2026Q1。首页 index.shtml,翻页 index_1.shtml…" + }, + { + "slug": "m07", + "short": "嘉实", + "name": "嘉实基金管理有限公司", + "category": "基金公司", + "homepage": "https://www.jsfund.cn", + "access": "public", + "strategy": "spa_api", + "item_type": "pdf", + "disclosure_url": "https://www.jsfund.cn/main/pensions/AnnuityBusiness/index.shtml", + "list_url": "https://www.jsfund.cn/main/pensions/AnnuityBusiness/index.shtml", + "page_param": null, + "file_url_pattern": "https?://www\\.jsfund\\.cn/ueditor/jsp/upload/file/[0-9]{8}/[0-9]+\\.pdf", + "api": { + "endpoint": "https://www.jsfund.cn/servlet/json?random={rand}", + "method": "POST", + "params": { + "funcNo": "741002", + "type": "2", + "article_id": "{id}", + "rows": "1" + }, + "pdf_field": "content" + }, + "example_links": [ + "https://www.jsfund.cn/ueditor/jsp/upload/file/20260617/1781691526655083303.pdf" + ], + "notes": "Thinkive 框架 SPA。列表详情页 /main/a/{YYYYMMDD}/{articleId}.shtml 正文异步加载:POST /servlet/json funcNo=741002 取 content(内嵌PDF直链),无需登录/签名。PDF 路径 /ueditor/jsp/upload/file/{YYYYMMDD}/{雪花id}.pdf。\n\n[2026-07-07 已知缺陷] crawl.py 只做静态HTML抓取,未真正调用 registry 里记录的 servlet/json(funcNo=741002) API,故全量运行只抓到列表首屏SSR的最新1期(2026Q1),2025Q4及更早的历史期次未被抓取。这是 crawl.py 的功能缺口(spa_api策略未落地为真实API调用),不是网站不可得——需在 crawl.py 里为 spa_api 策略实现 POST /servlet/json 二次取件才能补全历史。" + }, + { + "slug": "m08", + "short": "南方", + "name": "南方基金管理股份有限公司", + "category": "基金公司", + "homepage": "https://www.nffund.com", + "access": "public", + "strategy": "html_index", + "item_type": "html", + "disclosure_url": "https://www.nffund.com/main/newCCZX/qynj/xxpl/index.shtml", + "list_url": "https://www.nffund.com/main/newCCZX/qynj/xxpl/index_{n}.shtml", + "page_param": "{n}", + "file_url_pattern": "https?://www\\.nffund\\.com/main/newCCZX/qynj/xxpl/[0-9]+\\.shtml", + "example_links": [ + "https://www.nffund.com/main/newCCZX/qynj/xxpl/133350.shtml" + ], + "notes": "持仓资讯→企业年金→信息披露。报告为 HTML 正文(GBK/gb18030 编码,抓后 iconv 转 UTF-8)。无PDF。nffund.com 与 southernfund.com 同主体,直连 nffund.com 抓。\n\n[2026-07-07 诊断] HTTP 0命中(原始HTML里根本没有报告文本,纯AJAX注入)。headless 渲染后报告标题确实可见(2024Q3-2026Q1一路可读),但这些条目不是 而是无链接的文本行/onclick,故现有 headless 脚本(只扫标签)仍抓不到文件直链。需针对该站定制:抓可见文本+配对同页的隐藏 data-id/onclick 参数,或抓包找底层 AJAX/JSON 接口。" + }, + { + "slug": "m09", + "short": "易方达", + "name": "易方达基金管理有限公司", + "category": "基金公司", + "homepage": "https://www.efunds.com.cn", + "access": "public", + "strategy": "detail_index", + "item_type": "pdf", + "disclosure_url": "https://www.efunds.com.cn/Mobile/lm/yljxxpl/qynjtzglqk/", + "list_url": "https://www.efunds.com.cn/Mobile/lm/yljxxpl/qynjtzglqk/", + "page_param": null, + "file_url_pattern": "https?://cdn\\.efunds\\.com\\.cn/owch/data/bulletin/[0-9]{8}/[^\"'\\s]+\\.pdf", + "example_links": [ + "https://cdn.efunds.com.cn/owch/data/bulletin/20260618/易方达基金管理有限公司企业年金基金投资管理情况-2026年1季度.pdf" + ], + "notes": "机构服务→养老金信息披露→企业年金投资管理情况报告。PDF 在 CDN cdn.efunds.com.cn/owch/data/bulletin/{发布日}/,命名固定「易方达基金管理有限公司企业年金基金投资管理情况-YYYY年N季度.pdf」。列表动态,全量枚举用 headless 或按季推日期。PC 入口 /lm/jgfw/xxpl/。" + }, + { + "slug": "m10", + "short": "银华", + "name": "银华基金管理股份有限公司", + "category": "基金公司", + "homepage": "https://www.yhfund.com.cn", + "access": "waf", + "strategy": "headless", + "item_type": "pdf", + "disclosure_url": "http://www.yhfund.com.cn/main/corporatePension/report/index.shtml", + "list_url": "http://www.yhfund.com.cn/main/corporatePension/report/index.shtml", + "page_param": null, + "file_url_pattern": "https?://www\\.yhfund\\.com\\.cn/upload/[0-9]{8}/[^\"'\\s]+\\.pdf", + "example_links": [ + "https://www.yhfund.com.cn/upload/20240528/202405281716881071862.pdf" + ], + "notes": "报告栏目 /main/corporatePension/report/。所有动态 .shtml 页对数据中心IP被WAF拦(837B「可疑访问」页),列表需 headless/住宅IP。但 /upload/YYYYMMDD/ 下的PDF不受WAF限,拿到直链即可curl。文件名含随机时间戳,不可猜,须从列表页取。\n\n[2026-07-07 复核] 确认 headless(无stealth) 仍被WAF拦:返回 `可疑访问行为被拒绝`(200状态码但内容为拦截页)。说明该WAF会指纹识别headless/自动化浏览器,不是简单等待JS渲染能绕过的,需要更强的反检测(stealth插件/真实指纹)或人工过一次拿到cookie复用。已知可行的是:若能从其它渠道(搜索引擎缓存等)拿到具体PDF直链,/upload/路径本身不拦,可以直接下载——但发现新链接这一步现阶段做不到。" + }, + { + "slug": "m11", + "short": "招商", + "name": "招商基金管理有限公司", + "category": "基金公司", + "homepage": "https://www.cmfchina.com", + "access": "login", + "strategy": "login_blocked", + "item_type": "pdf", + "disclosure_url": "https://www.cmfchina.com/web/elderlyCare/enterprisePension/index.html", + "list_url": null, + "page_param": null, + "file_url_pattern": null, + "notes": "企业年金页有「信息披露」入口,但跳转客户门户 qy.cmfchina.com/#/pensionInfo,未登录一律 redirect /login,需 fundAccount+计划号+验证码换 token 才能下载季报。公开的只有「养老金产品公告」(分红/变更等),非季度管理报告。" + }, + { + "slug": "m12", + "short": "华泰资产", + "name": "华泰资产管理有限公司", + "category": "保险资管", + "homepage": "https://www.htam.com.cn", + "access": "public", + "strategy": "detail_index", + "item_type": "pdf", + "disclosure_url": "https://www.htam.com.cn/product/notice", + "list_url": "https://www.htam.com.cn/product/notice", + "page_param": null, + "file_url_pattern": "https?://www\\.htam\\.com\\.cn/(File|Uploads/Picture)/[^\"'\\s]+\\.pdf", + "api": { + "endpoint": "https://www.htam.com.cn/api/v1/article/{id}", + "method": "GET", + "pdf_field": "content" + }, + "example_links": [ + "https://www.htam.com.cn/File/2026/6/22/202606221619312026年1季度企业年金基金投资管理情况.pdf" + ], + "notes": "产品→公告。PDF 在 /File/YYYY/M/D/ 或 /Uploads/Picture/;详情走 /api/v1/article/{id} 返回含PDF链。文件名含中文季度标识。\n\n[2026-07-07 诊断] 与首次人工爬取(2026-07-06)相比,官网疑似已改版:headless 渲染「产品公告→养老金产品」页面正常200且标题正确,但列表区显示「暂无数据」,此前记录的 /File/...pdf 与 /api/v1/article/{id} 路径当前均取不到任何条目。需重新踩点新的筛选/接口方式,此为站点近期变动导致的临时失效,非永久不可得。" + }, + { + "slug": "m13", + "short": "泰康资产", + "name": "泰康资产管理有限责任公司", + "category": "保险资管", + "homepage": "https://www.taikangasset.cn", + "access": "public", + "strategy": "detail_index", + "item_type": "docx", + "disclosure_url": "https://www.taikangasset.cn/comproduct/ylbusiness/enterprisefunds/enterpriseinfo/list_294_1.html", + "list_url": "https://www.taikangasset.cn/comproduct/ylbusiness/enterprisefunds/enterpriseinfo/list_294_{n}.html", + "page_param": "{n}", + "list_pages_known": 6, + "file_url_pattern": "https?://files\\.taikangasset\\.cn/(service/business/website/download/[0-9A-F]{32}|customer/websiteDownload\\.do\\?id=[0-9]+)", + "example_links": [ + "https://files.taikangasset.cn/service/business/website/download/76CBEEB8DCFA465FB436646D8624585B", + "https://files.taikangasset.cn/customer/websiteDownload.do?id=154963234050491764318476102" + ], + "notes": "养老金业务→企业年金→信息披露。⚠️报告是 .docx(Word) 不是PDF,下载链接无扩展名,服务端返回Word,按 .docx 命名。列表倒序6页。新报告走 /service/business/website/download/{32位HEX},旧报告 /customer/websiteDownload.do?id={数字}。" + }, + { + "slug": "m14", + "short": "长江养老", + "name": "长江养老保险股份有限公司", + "category": "养老保险公司", + "homepage": "https://www.cj-pension.com.cn", + "access": "public", + "strategy": "html_index", + "item_type": "html", + "disclosure_url": "https://www.cj-pension.com.cn/cjyl/Channel/3505179_1/qynjcpxxpl/jdxxpl", + "list_url": "https://www.cj-pension.com.cn/cjyl/Channel/3505179_{n}/qynjcpxxpl/jdxxpl", + "page_param": "{n}", + "list_pages_known": 11, + "file_url_pattern": "https?://www\\.cj-pension\\.com\\.cn/c/[0-9]{4}-[0-9]{2}-[0-9]{2}/[0-9]+\\.shtml", + "example_links": [ + "https://www.cj-pension.com.cn/c/2026-06-18/1884003.shtml" + ], + "notes": "信息披露→企业年金产品信息披露→季度/年度信息披露。每季两类:①企业年金集合计划管理情况 ②企业年金基金投资管理情况。报告为 HTML(.shtml) 正文,无PDF。分11页。别混入 health.cpic.com.cn 的公司年度PDF。" + }, + { + "slug": "m15", + "short": "平安养老", + "name": "平安养老保险股份有限公司", + "category": "养老保险公司", + "homepage": "https://yl.pingan.com", + "access": "public", + "strategy": "headless", + "item_type": "pdf", + "disclosure_url": "https://yl.pingan.com/branding/products", + "list_url": "https://yl.pingan.com/branding/products", + "page_param": null, + "file_url_pattern": "https?://yl\\.pingan\\.com/app_upload/file/[0-9]{8}/[^\"'\\s]+\\.pdf", + "example_links": [ + "https://yl.pingan.com/app_upload/file/20251128/企业年金基金投资管理情况2025Q3_1470.pdf" + ], + "notes": "产品及方案→年金→企业年金投资管理业绩披露。PDF 在 /app_upload/file/{YYYYMMDD}/,文件名含 YYYYQn。列表页动态渲染(WebFetch只得标题),全量枚举用 headless;PDF直链本身可匿名curl。yl.pingan.com=pension.pingan.com。" + }, + { + "slug": "m16", + "short": "太平养老", + "name": "太平养老保险股份有限公司", + "category": "养老保险公司", + "homepage": "http://tppension.cntaiping.com", + "access": "waf", + "strategy": "headless", + "item_type": "pdf", + "disclosure_url": "https://tppension.cntaiping.com/njjylbz-jhxqynjjhglqk/", + "list_url": "https://tppension.cntaiping.com/njjylbz-jhxqynjjhglqk/", + "page_param": null, + "file_url_pattern": null, + "notes": "公开信息披露→企业年金信息披露(/info-qynjxxpl/);报告列表在 /njjylbz-jhxqynjjhglqk/(集合型企业年金计划管理情况,按季)。⚠️全域瑞数(botgate)动态JS反爬:首请求 HTTP 412,需浏览器执行 $_ts JS 挑战算 Cookie。必须 headless(playwright/真浏览器)。个案账户走登录门户 service.tppension.cntaiping.com。\n\n[2026-07-07 复核] 确认 headless(无stealth) 仍卡在瑞数botgate挑战:HTTP 412,body仅39字节。这是主动的JS人机验证(不只是异步渲染延迟),需要专门的挑战破解逻辑(执行页面下发的混淆JS算出正确Cookie),通用playwright耐心等待解决不了。当前仍无法从官网直接爬到任何报告直链。" + }, + { + "slug": "m17", + "short": "新华养老", + "name": "新华养老保险股份有限公司", + "category": "养老保险公司", + "homepage": "https://www.newchinapension.com", + "access": "public", + "strategy": "detail_index", + "item_type": "pdf", + "disclosure_url": "https://www.newchinapension.com/xhylbx/_300468/312175/index.html", + "list_url": "https://www.newchinapension.com/xhylbx/_300468/312175/index_{n}.html", + "page_param": "{n}", + "file_url_pattern": "https?://www\\.newchinapension\\.com/xhylbx/articleFileDir/[0-9]{4}-[0-9]{2}/[0-9]+/[^\"'\\s]+\\.pdf", + "example_links": [ + "https://www.newchinapension.com/xhylbx/articleFileDir/2026-06/25/ccedf2a37bcf433f9d21a9e20eedcf0a/新华养老保险股份有限公司_企业年金基金投资管理情况2026Q1.pdf" + ], + "notes": "公开信息披露→企业年金投管业务信息披露,共29条,最新2026Q1。PDF直链含中文文件名(需URL编码),命名「新华养老保险股份有限公司_企业年金基金投资管理情况YYYYQn.pdf」。另有「年度信息披露报告」为不同栏目。" + }, + { + "slug": "m18", + "short": "国寿养老", + "name": "中国人寿养老保险股份有限公司", + "category": "养老保险公司", + "homepage": "https://www.clpc.com.cn", + "access": "public", + "strategy": "detail_index", + "item_type": "pdf", + "disclosure_url": "https://www.clpc.com.cn/chinalifepension/jgkh/qynj_yljcpxxpl/index.html", + "list_url": "https://www.clpc.com.cn/chinalifepension/jgkh/qynj_yljcpxxpl/index_{n}.html", + "page_param": "{n}", + "file_url_pattern": "https?://www\\.clpc\\.com\\.cn/chinalifepension/articleFileDir/[0-9]{4}-[0-9]{2}/[0-9]+/[^\"'\\s]+\\.pdf", + "example_links": [ + "https://www.clpc.com.cn/chinalifepension/articleFileDir/2026-06/23/543e6a924dbd470f86913e5d570d903d.pdf" + ], + "notes": "机构客户→企业年金/养老金产品信息披露。每季两份:①企业年金基金投资管理情况 ②集合型企业年金计划管理情况。PDF 在 /articleFileDir/YYYY-MM/DD/{hash}.pdf。公司层面「信息披露」(/gkxxpl/)是另一独立栏目。" + }, + { + "slug": "m19", + "short": "人保养老", + "name": "中国人民养老保险有限责任公司", + "category": "养老保险公司", + "homepage": "https://www.picc-pension.com.cn", + "access": "public", + "strategy": "html_index", + "item_type": "html", + "disclosure_url": "https://www.picc-pension.com.cn/html/category/1812/200019-1.htm", + "list_url": "https://www.picc-pension.com.cn/html/category/1812/200019-{n}.htm", + "page_param": "{n}", + "file_url_pattern": "https?://www\\.picc-pension\\.com\\.cn/html/report/[0-9]{4}/[0-9]+-1\\.htm", + "example_links": [ + "https://www.picc-pension.com.cn/html/report/2606/0007-1.htm" + ], + "notes": "信息披露→企业年金信息披露,2018Q3–2026Q1 共62条,每季两类(投资管理情况/集合计划受托)。报告为内联 HTML 表格(),无附件。⚠️注意:仅 2018Q3–2021Q4 正文含完整数据表;2022Q1 起官网正文区为空(只有标题+日期),近四年数据未公开。\n\n[2026-07-07 诊断] 双重问题:①技术层——该页文章列表由站点自有的 `/asset/dyn/a_article/script.js` 挂件异步注入,headless 渲染10秒后 body 仍完全为空(0字节),该挂件在无头环境下未能执行/未能取到数据,尚未查明原因(可能校验referrer/viewport/需真实交互),导致列表拿不到,是当前爬虫的真实缺口;②数据层——即使解决①、能进入具体报告页,此前已确认自2022Q1起正文区``本身为空(仅标题+日期),即近四年官网自己就没有公开数据,这部分是官网侧的历史数据缺失,与技术能力无关,无法通过改进爬虫解决。" + }, + { + "slug": "m20", + "short": "建信养老金", + "name": "建信养老金管理有限责任公司", + "category": "养老金管理公司", + "homepage": "http://www.ccbpension.com", + "access": "waf", + "strategy": "login_blocked", + "item_type": "pdf", + "disclosure_url": "http://www.ccbpension.com/xxpl_yyjnbg.html", + "list_url": null, + "page_param": null, + "file_url_pattern": null, + "notes": "Vue SPA,信息披露走 /api/modules/disclosure/product/pageQuery,⚠️整站WAF(「访问拦截」页)+ API返回加密密文({jsonData:base64},需 /api/crypto/getKey 解密),无头浏览器也难。且官网披露的是「养老金产品」层报告,非计划层企业年金季报——计划层季报不在官网公开(报送受托人/人社部)。第三方(企查查)缓存可见零星产品年报,非官网、非季度。" + }, + { + "slug": "m21", + "short": "中金", + "name": "中国国际金融股份有限公司", + "category": "证券公司", + "homepage": "http://www.cicc.com", + "access": "waf", + "strategy": "headless", + "item_type": "pdf", + "disclosure_url": "http://www.cicc.com/portal/investor/info/fnancial_cn.xhtml?columnId=718", + "list_url": "http://www.cicc.com/portal/investor/info/fnancial_cn.xhtml?columnId=718", + "page_param": null, + "file_url_pattern": "https?://www\\.cicc\\.com/upload/file/[^\"'\\s]+\\.pdf", + "example_links": [ + "https://www.cicc.com/upload/file/2025/10/27/a9a6eb17-36b4-49ba-ae3f-8ec0f9c86eb5.pdf" + ], + "notes": "投资者关系→信息披露(columnId=718)。⚠️加速乐(jsl)反爬:首请求521+JS挑战,需两级cookie(__jsluid_s + __jsl_clearance_s),第二级为混淆VM挑战,需 node/浏览器执行算出。用 headless 最稳。披露为「养老金产品管理情况报告」(产品层,中金作投管人)。\n\n[2026-07-07 复核] 确认 headless(无stealth) 仍返回 HTTP 521(加速乐jsl挑战页)。此前人工爬取是用 node 手写脚本模拟执行两级混淆VM挑战才拿到 __jsl_clearance_s cookie 换到真实PDF——这是一次性手工破解,未固化进 crawl_headless.py 的通用逻辑,故本次自动化复测未能复现,仍需人工/定制脚本介入。" + }, + { + "slug": "m22", + "short": "中信证券", + "name": "中信证券股份有限公司", + "category": "证券公司", + "homepage": "http://www.cs.ecitic.com", + "access": "public", + "strategy": "html_index", + "item_type": "html", + "disclosure_url": "http://www.cs.ecitic.com/newsite/ywzx/zcgl/qynj/xxdt/", + "list_url": "http://www.cs.ecitic.com/newsite/ywzx/zcgl/qynj/xxdt/index_{n}.html", + "page_param": "{n}", + "file_url_pattern": "https?://www\\.cs\\.ecitic\\.com/newsite/ywzx/zcgl/qynj/xxdt/[0-9]{6}/t[0-9]{8}_[0-9]+\\.html", + "example_links": [ + "http://www.cs.ecitic.com/newsite/ywzx/zcgl/qynj/xxdt/202606/t20260618_1213353.html" + ], + "notes": "业务专区→资产管理→企业年金→信息动态。《中信证券企业年金基金投资管理情况》按季,报告为 HTML 正文(无PDF附件),列表可追溯至2023Q4。www.cs.ecitic.com=www.citics.com。首页 xxdt/,翻页 index_1.html…" + } + ] +} \ No newline at end of file diff --git a/annuity-disclosure-crawler/scripts/crawl.py b/annuity-disclosure-crawler/scripts/crawl.py new file mode 100755 index 0000000..e037a36 --- /dev/null +++ b/annuity-disclosure-crawler/scripts/crawl.py @@ -0,0 +1,372 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +企业年金投资管理人 · 官网季度管理报告 全量爬取驱动 +================================================= +读取 references/registry.json,按每家机构的 strategy 抓取官网披露栏目下 +**全部历史季度**的《企业年金基金投资管理情况》报告,落地到 --out 目录, +并做真伪校验(魔数/大小)与清单(manifest)记录。 + +纯 HTTP 可搞定的策略:pdf_index / detail_index / html_index / spa_api(部分) +需浏览器的策略:headless(本脚本跳过并提示改用 crawl_headless.py) +不公开:login_blocked(跳过并说明) + +用法: + python3 crawl.py --list # 只列出名录与每家策略/入口 + python3 crawl.py # 全量抓取所有可 HTTP 抓取的机构 + python3 crawl.py --only m04,m09,m17 # 只抓指定机构(逗号分隔 slug 或简称) + python3 crawl.py --latest 3 # 每家只保留最新 N 期(默认0=全量) + python3 crawl.py --out /path/to/out # 指定输出目录(默认 ./annuity_reports) + python3 crawl.py --max-pages 40 # 列表分页最多翻多少页(默认30) + python3 crawl.py --include-waf # 也尝试对 waf 机构做HTTP直取(多半失败,仅留痕) + +依赖: requests (pip install requests --break-system-packages) +""" +import argparse, json, os, re, sys, time, hashlib +from urllib.parse import urljoin, urlparse, unquote + +try: + import requests +except ImportError: + sys.exit("需要 requests: pip install requests --break-system-packages") + +HERE = os.path.dirname(os.path.abspath(__file__)) +REGISTRY = os.path.join(os.path.dirname(HERE), "references", "registry.json") + +UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36" + +# 期次识别: 2026Q1 / 2026年1季度 / 2026年第一季度 / 2026-1季度 +CN_NUM = {"一": "1", "二": "2", "三": "3", "四": "4"} +PERIOD_RES = [ + re.compile(r"(20\d{2})\s*[Qq]\s*([1-4])"), + re.compile(r"(20\d{2})\D{0,4}?第?\s*([1-4一二三四])\s*季度"), +] + + +# 报告标题判别词(区分季报条目 vs 栏目里的其它通知) +TITLE_KW = re.compile(r"管理情况|投资管理|年金.{0,6}报告") + + +def parse_period(*texts): + for t in texts: + if not t: + continue + t = unquote(t) + for rx in PERIOD_RES: + m = rx.search(t) + if m: + q = CN_NUM.get(m.group(2), m.group(2)) + return f"{m.group(1)}Q{q}" + # 年度报告 + m = re.search(r"(20\d{2})\s*年度", t) + if m: + return f"{m.group(1)}A" + return None + + +def fetch(url, referer=None, binary=False, timeout=60, session=None): + s = session or requests + h = {"User-Agent": UA, "Accept-Language": "zh-CN,zh;q=0.9"} + if referer: + h["Referer"] = referer + r = s.get(url, headers=h, timeout=timeout, allow_redirects=True, verify=False) + r.raise_for_status() + if binary: + return r.content, r.headers.get("Content-Type", "") + # 文本:尝试正确解码(GBK 站点很多) + raw = r.content + ct = r.headers.get("Content-Type", "").lower() + enc = None + m = re.search(r"charset=([\w-]+)", ct) + if m: + enc = m.group(1) + if not enc: + head = raw[:2000].decode("ascii", "ignore").lower() + m = re.search(r'charset=["\']?([\w-]+)', head) + if m: + enc = m.group(1) + for e in ([enc] if enc else []) + ["utf-8", "gb18030"]: + try: + return raw.decode(e), r.headers.get("Content-Type", "") + except Exception: + continue + return raw.decode("utf-8", "ignore"), r.headers.get("Content-Type", "") + + +def abs_links(html, base): + """返回 [(href_abs, anchor_text)]""" + out = [] + for m in re.finditer(r']*?href=["\']([^"\']+)["\'][^>]*>(.*?)', html, re.I | re.S): + href = m.group(1).strip() + if href.startswith(("javascript:", "#", "mailto:")): + continue + text = re.sub(r"<[^>]+>", "", m.group(2)).strip() + out.append((urljoin(base, href), text)) + return out + + +def file_from_href(href, base, rx): + """判断一个链接是否指向报告文件,返回可下载的绝对 URL 或 None。 + 处理 pdfjs 包装(viewer.html?file=xxx.pdf)、相对路径、以及 .pdf/.docx 后缀兜底。""" + cands = [href] + m = re.search(r"[?&]file=([^&]+)", href) + if m: + cands.append(unquote(m.group(1))) + for c in cands: + cabs = urljoin(base, c) + if rx and (rx.search(c) or rx.search(cabs)): + return cabs + if c.split("?")[0].lower().endswith((".pdf", ".docx", ".doc", ".xlsx")): + return cabs + return None + + +def files_in_page(html, base, rx): + """从一个页面里挖出所有报告文件直链(详情页二跳用)。""" + hits = set() + for href, _ in abs_links(html, base): + f = file_from_href(href, base, rx) + if f: + hits.add(f) + if rx: + for m in rx.finditer(html): + hits.add(urljoin(base, m.group(0))) + # 裸露的 .pdf/.docx 直链(在 JS/iframe src 里)——必须是真路径(以 / 或 http 开头), + # 避免把详情页里的“显示用中文文件名”误当成同目录相对链接 + for m in re.finditer(r'["\']((?:https?:)?/[^"\'\s]+\.(?:pdf|docx))["\']', html, re.I): + hits.add(urljoin(base, m.group(1))) + return list(hits) + + +def list_pages(mgr, max_pages): + """生成要翻的列表页 URL(去重、保序)。 + 很多站点第 1 页是 index.html(无编号),第 2 页起才是 index_1/index2…, + 因此始终把 disclosure_url 作为首页,再拼编号页。""" + lu = mgr.get("list_url") + disc = mgr.get("disclosure_url") + if not lu: + return [disc] if disc else [] + if "{n}" not in lu: + return [lu] + known = mgr.get("list_pages_known") + top = known if known else max_pages + seq = [disc] + [lu.replace("{n}", str(i)) for i in range(1, top + 1)] + seen, out = set(), [] + for u in seq: + if u and u not in seen: + seen.add(u); out.append(u) + return out + + +def verify(path, item_type): + try: + sz = os.path.getsize(path) + except OSError: + return False, 0, "missing" + if sz < 512: + return False, sz, "too-small" + with open(path, "rb") as f: + head = f.read(8) + if item_type == "pdf": + return (head[:4] == b"%PDF", sz, "ok" if head[:4] == b"%PDF" else "not-pdf") + if item_type == "docx": + return (head[:2] == b"PK", sz, "ok" if head[:2] == b"PK" else "not-docx") + # html + with open(path, "rb") as f: + body = f.read(60000) + txt = body.decode("utf-8", "ignore") + body.decode("gb18030", "ignore") + ok = ("年金" in txt or " 3000 + return (bool(ok), sz, "ok" if ok else "suspect") + + +def safe_name(period, url, item_type, slug): + ext = {"pdf": ".pdf", "docx": ".docx", "html": ".html"}[item_type] + base = period or ("item_" + hashlib.md5(url.encode()).hexdigest()[:8]) + return f"{slug}_{base}{ext}" + + +def crawl_manager(mgr, outdir, latest, max_pages, include_waf): + slug = mgr["slug"] + strat = mgr["strategy"] + item_type = mgr["item_type"] + res = {"slug": slug, "name": mgr["name"], "strategy": strat, "access": mgr["access"], + "disclosure_url": mgr["disclosure_url"], "files": [], "skipped": None} + + if strat == "login_blocked": + res["skipped"] = "login/非公开:季报仅登录客户门户可见或未在官网公开" + return res + if strat in ("headless",) and not include_waf: + res["skipped"] = "需无头浏览器(WAF/SPA):改用 crawl_headless.py 或加 --include-waf 试探" + return res + + d = os.path.join(outdir, slug) + os.makedirs(d, exist_ok=True) + sess = requests.Session() + pat = mgr.get("file_url_pattern") + rx = re.compile(pat) if pat else None + + # 1) 逐列表页收集候选(锚点为主,带标题文本→可解析期次并过滤非报告条目) + found = {} # file_url -> period (pdf_index/html_index 的最终文件) + detail_q = {} # detail_url -> period (detail_index 需二跳) + pages = list_pages(mgr, max_pages) or [mgr["disclosure_url"]] + empty_streak = 0 + for i, pg in enumerate(pages): + try: + html, _ = fetch(pg, referer=mgr["disclosure_url"], session=sess) + except Exception: + empty_streak += 1 + if empty_streak >= 2: + break + continue + if i == 0: + with open(os.path.join(d, "_disclosure_page.html"), "w", encoding="utf-8", errors="ignore") as f: + f.write(html) + new = 0 + for href, text in abs_links(html, pg): + p = parse_period(text, href) + titled = bool(text and TITLE_KW.search(text)) + if not (p or titled): + continue # 不像报告条目,跳过(滤掉栏目里的其它通知/导航) + direct = file_from_href(href, pg, rx) + if direct: # 锚点本身就是文件(或 pdfjs 包装) → 直接收 + if direct not in found: + found[direct] = p; new += 1 + elif rx and rx.search(href): # 锚点是 html 报告页(html_index) → 收 + if href not in found: + found[href] = p; new += 1 + elif strat in ("detail_index", "spa_api"): # 是详情页 → 二跳 + if href not in detail_q: + detail_q[href] = (p, text); new += 1 + # pdf_index 兜底:直链可能不在 里(onclick 等),用正则再捞一遍(要求文件名自带期次) + if strat == "pdf_index" and rx: + for m in rx.finditer(html): + u = urljoin(pg, m.group(0)) + pu = parse_period(u) + if pu and u not in found: + found[u] = pu; new += 1 + empty_streak = 0 if new else empty_streak + 1 + if empty_streak >= 3: + break + time.sleep(0.3) + + # 2) detail_index:进详情页取文件直链 + for href, (p, text) in detail_q.items(): + try: + html, _ = fetch(href, referer=mgr["disclosure_url"], session=sess) + except Exception: + continue + for u in files_in_page(html, href, rx): + if u not in found: + found[u] = parse_period(u) or p + time.sleep(0.2) + + if not found: + res["skipped"] = "HTTP 抓取 0 命中:列表多为 JS 渲染或被拦,请改用 crawl_headless.py" + return res + + # 3) 排序、按 latest 截断(保留最新 N 个不同期次的全部报告)、下载 + items = sorted(found.items(), key=lambda kv: (kv[1] or ""), reverse=True) + if latest and latest > 0: + periods_kept, kept = [], [] + for u, p in items: + if p is None: + continue # 无法定期次的条目在 latest 模式下略过 + if p not in periods_kept: + if len(periods_kept) >= latest: + break + periods_kept.append(p) + kept.append((u, p)) + items = kept + + seen_md5 = set() + for u, period in items: + try: + content, ct = fetch(u, referer=mgr["disclosure_url"], binary=True, session=sess) + except Exception as e: + res["files"].append({"url": u, "period": period, "status": f"download-fail:{e}", "local": None, "bytes": 0}) + continue + h = hashlib.md5(content).hexdigest() + if h in seen_md5: + continue # 同一报告被多个 URL 变体重复收录,按内容去重 + seen_md5.add(h) + # 若声明 pdf 却拿到 html 错误页 + it = item_type + if item_type == "pdf" and content[:4] != b"%PDF" and content[:2] == b"PK": + it = "docx" + name = safe_name(period, u, it, slug) + path = os.path.join(d, name) + if os.path.exists(path): # 同期两类报告(投资管理/集合计划)等→加短哈希防覆盖 + stem, ext = os.path.splitext(name) + path = os.path.join(d, f"{stem}_{hashlib.md5(u.encode()).hexdigest()[:6]}{ext}") + with open(path, "wb") as f: + f.write(content) + ok, sz, why = verify(path, it) + if not ok: + os.rename(path, path + ".suspect") + path = path + ".suspect" + res["files"].append({"url": u, "period": period, "status": why, + "local": os.path.relpath(path), "bytes": sz}) + time.sleep(0.2) + return res + + +def main(): + import urllib3 + urllib3.disable_warnings() + ap = argparse.ArgumentParser() + ap.add_argument("--registry", default=REGISTRY) + ap.add_argument("--out", default="annuity_reports") + ap.add_argument("--only", default="") + ap.add_argument("--latest", type=int, default=0, help="每家保留最新N期,0=全量") + ap.add_argument("--max-pages", type=int, default=30) + ap.add_argument("--include-waf", action="store_true") + ap.add_argument("--list", action="store_true") + args = ap.parse_args() + + reg = json.load(open(args.registry, encoding="utf-8")) + managers = reg["managers"] + + if args.list: + print(f"{'slug':5} {'简称':10} {'access':7} {'strategy':13} 披露入口") + for m in managers: + print(f"{m['slug']:5} {m['short']:10} {m['access']:7} {m['strategy']:13} {m['disclosure_url']}") + return + + only = [x.strip() for x in args.only.split(",") if x.strip()] + if only: + managers = [m for m in managers if m["slug"] in only or m["short"] in only] + + os.makedirs(args.out, exist_ok=True) + all_res = [] + for m in managers: + print(f"\n=== {m['slug']} {m['short']} [{m['strategy']}/{m['access']}] ===", flush=True) + r = crawl_manager(m, args.out, args.latest, args.max_pages, args.include_waf) + if r["skipped"]: + print(" ⏭ " + r["skipped"]) + else: + okn = sum(1 for f in r["files"] if f["status"] == "ok") + print(f" ✓ {okn}/{len(r['files'])} 个文件有效,落地 {os.path.join(args.out, m['slug'])}/") + for f in r["files"][:6]: + print(f" [{f['period']}] {f['status']} {f['bytes']}B {f['local']}") + all_res.append(r) + + # manifest + mani = os.path.join(args.out, "manifest.json") + json.dump({"generated": time.strftime("%Y-%m-%d %H:%M"), "results": all_res}, + open(mani, "w", encoding="utf-8"), ensure_ascii=False, indent=2) + import csv + with open(os.path.join(args.out, "manifest.csv"), "w", newline="", encoding="utf-8-sig") as fp: + w = csv.writer(fp) + w.writerow(["slug", "机构", "策略", "access", "期次", "状态", "字节", "本地路径", "源URL"]) + for r in all_res: + if r["skipped"]: + w.writerow([r["slug"], r["name"], r["strategy"], r["access"], "", "SKIP:" + r["skipped"], "", "", ""]) + for f in r["files"]: + w.writerow([r["slug"], r["name"], r["strategy"], r["access"], f["period"], f["status"], f["bytes"], f["local"], f["url"]]) + tot = sum(len(r["files"]) for r in all_res) + okt = sum(1 for r in all_res for f in r["files"] if f["status"] == "ok") + print(f"\n完成:{okt}/{tot} 个有效文件。清单:{mani} 及 manifest.csv") + + +if __name__ == "__main__": + main() diff --git a/annuity-disclosure-crawler/scripts/crawl_headless.py b/annuity-disclosure-crawler/scripts/crawl_headless.py new file mode 100755 index 0000000..ecf7938 --- /dev/null +++ b/annuity-disclosure-crawler/scripts/crawl_headless.py @@ -0,0 +1,218 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +企业年金季报爬取 · 无头浏览器兜底 +================================ +用于 crawl.py 搞不定的机构:列表页是 SPA(JS 渲染) 或整站有反爬 WAF/JS 挑战 +(strategy=headless / spa_api,或 access=waf)。用真实 Chromium 渲染页面、 +自动通过瑞数/加速乐等 JS 挑战、取到报告链接后用带 Cookie 的浏览器上下文下载。 + +依赖: + pip install playwright --break-system-packages + python3 -m playwright install chromium + +用法: + python3 crawl_headless.py --only m15,m21 # 指定机构 + python3 crawl_headless.py # 默认抓所有 headless/spa_api/waf 机构 + python3 crawl_headless.py --latest 3 --out DIR # 同 crawl.py 语义 + python3 crawl_headless.py --only m21 --headful # 显示浏览器窗口(调试/过人机) + +与 crawl.py 复用同一 registry.json 与期次识别/校验/命名逻辑。 +""" +import argparse, json, os, sys, time, hashlib, re, csv + +HERE = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, HERE) +import crawl # 复用 parse_period / file_from_href / files_in_page / verify / safe_name / TITLE_KW / list_pages + +from playwright.sync_api import sync_playwright + +UA = crawl.UA +REGISTRY = crawl.REGISTRY + + +def harvest_links(page): + """返回页面上所有 的 (href_abs, text)。""" + return page.eval_on_selector_all( + "a", + "els => els.map(a => [a.href, (a.innerText||a.textContent||'').trim()])", + ) + + +def crawl_manager(ctx, mgr, outdir, latest, max_pages): + slug = mgr["slug"] + strat = mgr["strategy"] + item_type = mgr["item_type"] + rx = re.compile(mgr["file_url_pattern"]) if mgr.get("file_url_pattern") else None + res = {"slug": slug, "name": mgr["name"], "strategy": strat, "access": mgr["access"], + "disclosure_url": mgr["disclosure_url"], "files": [], "skipped": None} + if strat == "login_blocked": + res["skipped"] = "登录墙/非公开,浏览器也无法匿名取得" + return res + + d = os.path.join(outdir, slug) + os.makedirs(d, exist_ok=True) + page = ctx.new_page() + found = {} # file_url -> period + detail_q = {} + + pages = crawl.list_pages(mgr, max_pages) or [mgr["disclosure_url"]] + empty = 0 + for i, pg in enumerate(pages): + try: + page.goto(pg, wait_until="networkidle", timeout=45000) + except Exception: + try: + page.goto(pg, wait_until="domcontentloaded", timeout=45000) + except Exception: + empty += 1 + if empty >= 2: + break + continue + time.sleep(2.5) # 等 JS 挑战/异步渲染 + for _ in range(4): # 滚动触发懒加载 + page.mouse.wheel(0, 20000) + time.sleep(0.6) + if i == 0: + try: + open(os.path.join(d, "_disclosure_rendered.html"), "w", encoding="utf-8").write(page.content()) + except Exception: + pass + new = 0 + for href, text in harvest_links(page): + if not href: + continue + p = crawl.parse_period(text, href) + titled = bool(text and crawl.TITLE_KW.search(text)) + if not (p or titled): + continue + direct = crawl.file_from_href(href, pg, rx) + if direct: + if direct not in found: + found[direct] = p; new += 1 + elif strat in ("detail_index", "spa_api", "headless"): + if href not in detail_q: + detail_q[href] = (p, text); new += 1 + empty = 0 if new else empty + 1 + if empty >= 3: + break + + # 详情页二跳(渲染后取文件链) + for href, (p, text) in list(detail_q.items()): + try: + page.goto(href, wait_until="networkidle", timeout=40000) + time.sleep(1.5) + except Exception: + continue + html = page.content() + for u in crawl.files_in_page(html, href, rx): + if u not in found: + found[u] = crawl.parse_period(u) or p + + if not found: + res["skipped"] = "渲染后仍 0 命中:可能需登录、或分页/下载入口需交互(试 --headful 观察)" + page.close() + return res + + items = sorted(found.items(), key=lambda kv: (kv[1] or ""), reverse=True) + if latest and latest > 0: + periods_kept, kept = [], [] + for u, pp in items: + if pp is None: + continue + if pp not in periods_kept: + if len(periods_kept) >= latest: + break + periods_kept.append(pp) + kept.append((u, pp)) + items = kept + + seen_md5 = set() + for u, period in items: + try: + r = ctx.request.get(u, timeout=60000) # 带浏览器 Cookie 下载,过 WAF + content = r.body() + except Exception as e: + res["files"].append({"url": u, "period": period, "status": f"download-fail:{e}", "local": None, "bytes": 0}) + continue + h = hashlib.md5(content).hexdigest() + if h in seen_md5: + continue + seen_md5.add(h) + it = item_type + if item_type == "pdf" and content[:4] != b"%PDF" and content[:2] == b"PK": + it = "docx" + name = crawl.safe_name(period, u, it, slug) + path = os.path.join(d, name) + if os.path.exists(path): + stem, ext = os.path.splitext(name) + path = os.path.join(d, f"{stem}_{hashlib.md5(u.encode()).hexdigest()[:6]}{ext}") + open(path, "wb").write(content) + ok, sz, why = crawl.verify(path, it) + if not ok: + os.rename(path, path + ".suspect"); path += ".suspect" + res["files"].append({"url": u, "period": period, "status": why, "local": os.path.relpath(path), "bytes": sz}) + time.sleep(0.2) + page.close() + return res + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--registry", default=REGISTRY) + ap.add_argument("--out", default="annuity_reports") + ap.add_argument("--only", default="") + ap.add_argument("--latest", type=int, default=0) + ap.add_argument("--max-pages", type=int, default=30) + ap.add_argument("--headful", action="store_true") + args = ap.parse_args() + + reg = json.load(open(args.registry, encoding="utf-8")) + managers = reg["managers"] + only = [x.strip() for x in args.only.split(",") if x.strip()] + if only: + managers = [m for m in managers if m["slug"] in only or m["short"] in only] + else: # 默认:需浏览器的那批 + managers = [m for m in managers if m["strategy"] in ("headless", "spa_api") or m["access"] == "waf"] + managers = [m for m in managers if m["strategy"] != "login_blocked"] + + os.makedirs(args.out, exist_ok=True) + all_res = [] + with sync_playwright() as pw: + browser = pw.chromium.launch(headless=not args.headful) + ctx = browser.new_context(user_agent=UA, locale="zh-CN", ignore_https_errors=True, + extra_http_headers={"Accept-Language": "zh-CN,zh;q=0.9"}) + for m in managers: + print(f"\n=== {m['slug']} {m['short']} [{m['strategy']}/{m['access']}] ===", flush=True) + try: + r = crawl_manager(ctx, m, args.out, args.latest, args.max_pages) + except Exception as e: + r = {"slug": m["slug"], "name": m["name"], "strategy": m["strategy"], "access": m["access"], + "disclosure_url": m["disclosure_url"], "files": [], "skipped": f"异常:{e}"} + if r["skipped"]: + print(" ⏭ " + r["skipped"]) + else: + okn = sum(1 for f in r["files"] if f["status"] == "ok") + print(f" ✓ {okn}/{len(r['files'])} 个有效,落地 {os.path.join(args.out, m['slug'])}/") + for f in r["files"][:6]: + print(f" [{f['period']}] {f['status']} {f['bytes']}B {f['local']}") + all_res.append(r) + browser.close() + + mani = os.path.join(args.out, "manifest_headless.json") + json.dump({"generated": time.strftime("%Y-%m-%d %H:%M"), "results": all_res}, + open(mani, "w", encoding="utf-8"), ensure_ascii=False, indent=2) + with open(os.path.join(args.out, "manifest_headless.csv"), "w", newline="", encoding="utf-8-sig") as fp: + w = csv.writer(fp) + w.writerow(["slug", "机构", "策略", "access", "期次", "状态", "字节", "本地路径", "源URL"]) + for r in all_res: + if r["skipped"]: + w.writerow([r["slug"], r["name"], r["strategy"], r["access"], "", "SKIP:" + r["skipped"], "", "", ""]) + for f in r["files"]: + w.writerow([r["slug"], r["name"], r["strategy"], r["access"], f["period"], f["status"], f["bytes"], f["local"], f["url"]]) + okt = sum(1 for r in all_res for f in r["files"] if f["status"] == "ok") + print(f"\n完成:{okt} 个有效文件。清单:{mani}") + + +if __name__ == "__main__": + main() diff --git a/asset-monitor/SKILL.md b/asset-monitor/SKILL.md new file mode 100644 index 0000000..b9f6ffa --- /dev/null +++ b/asset-monitor/SKILL.md @@ -0,0 +1,192 @@ +--- +name: asset-monitor +description: 资产异常波动日频监控与报告生成。当用户需要对股票、指数、商品等资产进行日频异常波动监控,检测偏离历史均值超过2倍标准差的异常,并生成Excel报告时使用此技能。 +--- + +# 资产异常波动日频监控 + +## 触发条件 + +当用户需要: +- 监控多资产类别的日频异常波动 +- 检测偏离历史均值超过2倍标准差的资产 +- 生成异常波动报告(Excel/Markdown) +- 批量分析申万三级行业、A股指数、商品期货、全球指数等 + +## 依赖 + +本 skill 依赖 windpy-sdk 获取数据。使用时需要: +1. Wind 金融终端已启动 +2. 参考 windpy-sdk skill 了解数据获取方法 + +## 监控脚本 + +使用 `scripts/monitor.py` 进行监控: + +```bash +# 基础监控 +python scripts/monitor.py + +# 带报告输出 +python scripts/monitor.py --notify + +# 自定义参数 +python scripts/monitor.py --threshold 2.5 --min-days 60 +``` + +## 监控资产范围 + +| 资产类别 | 数量 | 说明 | +|---------|------|------| +| 申万三级行业 | 259个 | 全量三级行业指数 | +| A股主要指数 | 9个 | 沪深300、中证500等 | +| 中债指数 | 5个 | 中债总指数、国债指数等 | +| 主流ETF | 8个 | 沪深300ETF、创业板ETF等 | +| 商品期货 | 8个 | 黄金、白银、铜、原油等 | +| 全球指数 | 9个 | 标普500、纳指、道指等 | + +**总计**: 298个资产 + +## 核心监控逻辑 + +### Z-Score 异常检测 + +```python +# 计算Z值 +z_score = (今日涨跌幅 - 历史均值) / 历史标准差 + +# 异常判定 +if abs(z_score) > 2.0: + 标记为异常 +``` + +### 筛选条件 + +- 历史数据 > 30个交易日 +- 历史标准差 > 0 +- 按 |Z| 绝对值降序排列 + +## 输出结果 + +### Excel 报告 + +| 字段 | 说明 | +|------|------| +| category | 资产类别 | +| code | 资产代码 | +| name | 资产名称 | +| today_return | 今日涨跌幅(%) | +| z_score | Z值 | +| direction | 大涨/大跌 | + +### 监控输出示例 + +``` +================================================================================ +📊 资产异常波动监控 +时间: 2026-02-09 06:22 +Z值阈值: 2.0 +================================================================================ + +[监控] 申万三级行业 (259个) + 共 259 个资产 + ⚠️ 印染(申万): +5.30% (Z=+3.33) + ⚠️ 纺织化学制品(申万): +5.35% (Z=+3.22) + 发现 5 个异常 + +[监控] 商品期货 (8个) + ⚠️ 沪银近月: -14.02% (Z=-4.39) + 发现 1 个异常 + +[监控] 全球指数 (9个) + ⚠️ 道琼斯: +2.47% (Z=+2.34) + ⚠️ VIX波动率: -18.42% (Z=-2.26) + 发现 2 个异常 + +================================================================================ +✅ 监控完成,共发现 8 个异常 +================================================================================ +``` + +## 脚本使用方法 + +详见 `scripts/monitor.py` 代码注释。 + +### 命令行参数 + +```bash +python scripts/monitor.py --help + +Options: + --threshold FLOAT Z-Score阈值,默认2.0 + --min-days INT 最小交易日,默认30 + --output DIR 输出目录,默认output + --notify 打印文本报告 +``` + +### Python API + +```python +# 直接导入脚本中的函数使用 +import sys +sys.path.insert(0, 'scripts') +from monitor import run_monitoring, generate_excel_report + +# 运行监控(需先连接Wind) +from WindPy import w +w.start() +anomalies = run_monitoring(threshold_z=2.0) +w.stop() + +# 生成报告 +excel_path = generate_excel_report(anomalies) +``` + +## 定时任务设置 + +```bash +# crontab -e +# 每日15:30运行 +30 15 * * * cd /path/to/skill && python scripts/monitor.py --notify +``` + +## 配置文件 + +配置示例见 `references/monitor-config-example.json` + +```json +{ + "monitor": { + "threshold_z": 2.0, + "min_trading_days": 30 + }, + "assets": { + "sw3_industry": {"enabled": true}, + "ashare_index": {"enabled": true}, + "commodity": {"enabled": true} + } +} +``` + +## 故障排查 + +| 问题 | 原因 | 解决方案 | +|------|------|---------| +| Wind连接失败 | Wind终端未启动 | 启动Wind终端 | +| 无数据返回 | 无数据权限 | 联系Wind开通权限 | +| 报告为空 | 今日无异常 | 正常现象 | + +## 与其他 Skill 的关系 + +``` +asset-monitor (监控逻辑 + 报告生成) + ↓ 使用 WindPy 获取数据 +WindPy SDK (Wind 金融终端 API) +``` + +**注意**: asset-monitor 直接使用 WindPy,但字段和板块代码可参考 windpy-sdk skill 的文档。 + +## 参考 + +- windpy-sdk skill - WindPy 函数参考和字段速查 +- `references/monitor-config-example.json` - 配置示例 diff --git a/asset-monitor/references/monitor-config-example.json b/asset-monitor/references/monitor-config-example.json new file mode 100644 index 0000000..c2b2012 --- /dev/null +++ b/asset-monitor/references/monitor-config-example.json @@ -0,0 +1,37 @@ +{ + "monitor": { + "threshold_z": 2.0, + "min_trading_days": 30, + "lookback_period": "-252TD" + }, + "assets": { + "sw3_industry": { + "enabled": true, + "description": "申万三级行业(259个全量)" + }, + "ashare_index": { + "enabled": true, + "description": "A股主要指数(9个)" + }, + "bond_index": { + "enabled": true, + "description": "中债指数(5个)" + }, + "etf": { + "enabled": true, + "description": "主流ETF(8个)" + }, + "commodity": { + "enabled": true, + "description": "商品期货(8个主要品种)" + }, + "global_index": { + "enabled": true, + "description": "全球指数(9个主要指数)" + } + }, + "notification": { + "excel": true, + "markdown": true + } +} diff --git a/asset-monitor/scripts/monitor.py b/asset-monitor/scripts/monitor.py new file mode 100644 index 0000000..a167e38 --- /dev/null +++ b/asset-monitor/scripts/monitor.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python3 +""" +资产异常波动日频监控脚本 + +使用方法: + python scripts/monitor.py + python scripts/monitor.py --notify +""" + +from WindPy import w +import pandas as pd +import numpy as np +from datetime import datetime, timedelta +import os +import sys + +# 监控资产配置 +ASSET_CONFIG = { + "sw3_industry": { + "name": "申万三级行业", + "type": "sector", + "sectorid": "a39901011i000000", # 259个 + }, + "ashare_index": { + "name": "A股主要指数", + "type": "direct", + "codes": [ + "000300.SH", "000905.SH", "000016.SH", "000852.SH", + "000001.SH", "399001.SZ", "399006.SZ", "000688.SH", "883985.WI" + ], + }, + "bond_index": { + "name": "中债指数", + "type": "direct", + "codes": [ + "CBA00101.CS", "CBA00301.CS", "CBA00401.CS", + "CBA00501.CS", "CBA00601.CS" + ], + }, + "etf": { + "name": "主流ETF", + "type": "direct", + "codes": [ + "510300.SH", "510500.SH", "510050.SH", "159915.SZ", + "588000.SH", "512480.SH", "515030.SH", "512760.SH" + ], + }, + "commodity": { + "name": "商品期货", + "type": "direct", + "codes": [ + "AU00.SHF", "AG00.SHF", "CU00.SHF", "AL00.SHF", + "ZN00.SHF", "RB00.SHF", "SC00.INE", "TA00.CZC" + ], + }, + "global_index": { + "name": "全球指数", + "type": "direct", + "codes": [ + "SPX.GI", "IXIC.GI", "DJI.GI", "VIX.GI", + "HSI.HI", "N225.GI", "KS11.GI", "GDAXI.GI", "FTSE.GI" + ], + }, +} + + +def analyze_asset(code, name, category, threshold_z=2.0, min_days=30): + """分析单个资产的波动""" + try: + one_year_ago = (datetime.now() - timedelta(days=365)).strftime('%Y%m%d') + today_str = datetime.now().strftime('%Y%m%d') + + hist = w.wsd(code, "pct_chg", one_year_ago, today_str, "", usedf=True) + + if hist[0] == 0 and len(hist[1]) > min_days: + returns = hist[1]['PCT_CHG'].dropna() + if len(returns) > min_days: + mean_ret = returns.mean() + std_ret = returns.std() + today_ret = returns.iloc[-1] if len(returns) > 0 else None + + if today_ret is not None and std_ret > 0: + z_score = (today_ret - mean_ret) / std_ret + + if abs(z_score) > threshold_z: + return { + 'category': category, + 'code': code, + 'name': name, + 'today_return': float(today_ret), + 'z_score': float(z_score), + 'direction': '大涨' if z_score > 0 else '大跌' + } + except Exception: + pass + return None + + +def monitor_sector(config, threshold_z=2.0): + """监控板块类资产""" + print(f"\n[监控] {config['name']}") + + today_str = datetime.now().strftime('%Y%m%d') + result = w.wset("sectorconstituent", f"date={today_str};sectorid={config['sectorid']}") + + if result.ErrorCode != 0 or len(result.Data) < 2: + print(f" ⚠️ 未获取到数据") + return [] + + codes = result.Data[1] + names = result.Data[2] + + print(f" 共 {len(codes)} 个资产") + + anomalies = [] + for code, name in zip(codes, names): + result = analyze_asset(code, name, config['name'], threshold_z) + if result: + anomalies.append(result) + print(f" ⚠️ {name}: {result['today_return']:+.2f}% (Z={result['z_score']:+.2f})") + + print(f" 发现 {len(anomalies)} 个异常") + return anomalies + + +def monitor_direct(config, threshold_z=2.0): + """监控直接代码类资产""" + print(f"\n[监控] {config['name']} ({len(config['codes'])}个)") + + # 获取名称 + try: + result = w.wss(','.join(config['codes']), "sec_name", "", usedf=True) + name_map = dict(zip(result[1].index, result[1]['SEC_NAME'])) if result[0] == 0 else {} + except: + name_map = {code: code for code in config['codes']} + + anomalies = [] + for code in config['codes']: + name = name_map.get(code, code) + result = analyze_asset(code, name, config['name'], threshold_z) + if result: + anomalies.append(result) + print(f" ⚠️ {name}: {result['today_return']:+.2f}% (Z={result['z_score']:+.2f})") + + print(f" 发现 {len(anomalies)} 个异常") + return anomalies + + +def run_monitoring(threshold_z=2.0): + """运行完整监控""" + today = datetime.now() + + print("="*70) + print(f"📊 资产异常波动监控") + print(f"时间: {today.strftime('%Y-%m-%d %H:%M')}") + print(f"Z值阈值: {threshold_z}") + print("="*70) + + all_anomalies = [] + + for key, config in ASSET_CONFIG.items(): + try: + if config['type'] == 'sector': + anomalies = monitor_sector(config, threshold_z) + else: + anomalies = monitor_direct(config, threshold_z) + all_anomalies.extend(anomalies) + except Exception as e: + print(f" ❌ {config['name']} 监控失败: {e}") + + print(f"\n{'='*70}") + print(f"✅ 监控完成,共发现 {len(all_anomalies)} 个异常") + print(f"{'='*70}\n") + + return all_anomalies + + +def generate_excel_report(anomalies, output_dir="output"): + """生成 Excel 报告""" + if not anomalies: + return None + + os.makedirs(output_dir, exist_ok=True) + + df = pd.DataFrame(anomalies) + df = df.sort_values('z_score', key=abs, ascending=False) + + today_str = datetime.now().strftime('%Y%m%d') + excel_path = os.path.join(output_dir, f"asset_anomaly_report_{today_str}.xlsx") + df.to_excel(excel_path, index=False, sheet_name='异常波动资产') + + print(f"✅ Excel 报告: {excel_path}") + return excel_path + + +def generate_text_report(anomalies): + """生成文本报告""" + if not anomalies: + return "📊 资产异常监控\n\n✅ 今日无异常资产。" + + lines = [ + "📊 资产异常波动报告", + f"报告时间: {datetime.now().strftime('%Y-%m-%d')}", + "", + f"共发现 {len(anomalies)} 个异常资产:", + "", + ] + + for i, item in enumerate(anomalies, 1): + emoji = "🚀" if item['z_score'] > 0 else "📉" + lines.append( + f"{i}. {emoji} {item['name']} ({item['category']})\n" + f" 涨跌幅: {item['today_return']:+.2f}% | Z值: {item['z_score']:+.2f}" + ) + + return '\n'.join(lines) + + +def main(): + import argparse + + parser = argparse.ArgumentParser(description='资产异常波动监控') + parser.add_argument('--threshold', type=float, default=2.0, help='Z-Score阈值') + parser.add_argument('--output', type=str, default='output', help='输出目录') + parser.add_argument('--notify', action='store_true', help='打印报告') + + args = parser.parse_args() + + # 连接 Wind + print("正在连接 Wind...") + w.start() + print("✅ Wind 连接成功\n") + + try: + # 运行监控 + anomalies = run_monitoring(threshold_z=args.threshold) + + # 生成报告 + if anomalies: + excel_path = generate_excel_report(anomalies, args.output) + + if args.notify: + print("\n" + generate_text_report(anomalies)) + else: + print("✅ 今日无异常资产") + + finally: + w.stop() + print("\nWind 连接已断开") + + +if __name__ == "__main__": + main() diff --git a/docx-cn/SKILL.md b/docx-cn/SKILL.md new file mode 100644 index 0000000..8e97314 --- /dev/null +++ b/docx-cn/SKILL.md @@ -0,0 +1,489 @@ +--- +name: docx-cn +description: "基于 docx-js (Node.js) 创建和编辑符合 GB/T 9704-2012 中国公文格式标准的 Word 文档。当用户需要生成公文、研究报告、内部文件等中文 Word 文档时使用。触发词:公文、Word、docx、报告排版、格式规范、GB/T 9704。" +--- + +# 中文公文 Word 文档生成(docx-js) + +## 概述 + +基于官方 docx skill 微调,专为中文公文 / 金融研究报告场景优化。 +使用 **docx-js**(Node.js)生成文档,配合官方 skill 的 unpack/pack/validate 工具链编辑现有文档。 + +## 核心工具链 + +| 任务 | 方法 | +|------|------| +| **新建文档** | `docx-js` — 本文件中的模板 | +| **编辑现有文档** | unpack XML → 编辑 → repack(见「编辑现有文档」节) | +| **验证** | `python .claude/skills/docx/scripts/office/validate.py output.docx` | +| **读取内容** | `pandoc document.docx -o output.md` | + +--- + +## GB/T 9704-2012 公文格式常量 + +### 单位换算速查 + +``` +1 inch = 1440 DXA = 72 pt = 25.4 mm +1 mm = 56.693 DXA +1 pt = 20 DXA(spacing/行距用) +font size 单位 = half-point(半磅),如 14pt = 28 +``` + +### 页面设置(A4) + +```javascript +const PAGE = { + WIDTH: 11906, // 210mm + HEIGHT: 16838, // 297mm + MARGIN_TOP: 2098, // 37mm + MARGIN_BOTTOM: 1985, // 35mm + MARGIN_LEFT: 1588, // 28mm + MARGIN_RIGHT: 1474, // 26mm + CONTENT_WIDTH: 8844, // 210mm - 28mm - 26mm +}; +``` + +### 字号对照表 + +| 中文字号 | pt | half-point (docx-js size) | 用途 | +|----------|-----|---------------------------|------| +| 二号 | 22 | 44 | 大标题 | +| 三号 | 16 | 32 | 一级标题 | +| 四号 | 14 | 28 | 正文 / 二级标题 | +| 小四 | 12 | 24 | 表格内容 | +| 五号 | 10.5 | 21 | 页脚、注释 | + +### 字体规范 + +```javascript +// 中文字体必须同时设置 eastAsia,否则 Word 渲染时可能回退到宋体 +const FONT = { + HEITI: { ascii: "SimHei", eastAsia: "黑体", hAnsi: "SimHei" }, // 标题 + FANGSONG: { ascii: "FangSong", eastAsia: "仿宋", hAnsi: "FangSong" }, // 正文 + KAITI: { ascii: "KaiTi", eastAsia: "楷体", hAnsi: "KaiTi" }, // 二级标题 + SONGTI: { ascii: "SimSun", eastAsia: "宋体", hAnsi: "SimSun" }, // 备用 +}; +``` + +### 行距与段落 + +```javascript +const SPACING = { + // 行距(twips = pt × 20),lineRule: "exact" → 固定值 + BODY: { line: 560, lineRule: "exact" }, // 28pt 固定行距 + HEADING1: { line: 640, lineRule: "exact" }, // 32pt + HEADING2: { line: 560, lineRule: "exact" }, // 28pt + TABLE: { line: 440, lineRule: "exact" }, // 22pt + + // 段前段后(twips) + H1_BEFORE: 240, H1_AFTER: 120, // 12pt / 6pt + H2_BEFORE: 120, H2_AFTER: 60, // 6pt / 3pt +}; + +const INDENT = { + FIRST_LINE: 560, // 首行缩进 2 字符 ≈ 28pt = 560 DXA +}; +``` + +--- + +## 创建新文档 + +### 安装 + +```bash +npm install docx # 项目内安装即可,无需全局 +``` + +### 完整模板:公文报告(无封面) + +```javascript +const fs = require("fs"); +const { + Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, + Header, Footer, AlignmentType, HeadingLevel, BorderStyle, WidthType, + ShadingType, PageNumber, PageBreak, LevelFormat, TabStopType, TabStopPosition, +} = require("docx"); + +// ─── GB/T 9704-2012 格式常量 ───────────────────────────── +const PAGE = { + WIDTH: 11906, HEIGHT: 16838, + MARGIN_TOP: 2098, MARGIN_BOTTOM: 1985, + MARGIN_LEFT: 1588, MARGIN_RIGHT: 1474, + CONTENT_WIDTH: 8844, +}; + +const FONT = { + HEITI: { ascii: "SimHei", eastAsia: "黑体", hAnsi: "SimHei" }, + FANGSONG: { ascii: "FangSong", eastAsia: "仿宋", hAnsi: "FangSong" }, + KAITI: { ascii: "KaiTi", eastAsia: "楷体", hAnsi: "KaiTi" }, +}; + +// ─── 样式定义 ───────────────────────────────────────────── +const styles = { + default: { + document: { + run: { font: FONT.FANGSONG, size: 28 }, // 默认:仿宋四号 + paragraph: { + spacing: { line: 560, lineRule: "exact" }, + }, + }, + }, + paragraphStyles: [ + { + id: "Heading1", name: "Heading 1", + basedOn: "Normal", next: "Normal", quickFormat: true, + run: { font: FONT.HEITI, size: 32, bold: true }, // 黑体三号 + paragraph: { + spacing: { line: 640, lineRule: "exact", before: 240, after: 120 }, + outlineLevel: 0, + }, + }, + { + id: "Heading2", name: "Heading 2", + basedOn: "Normal", next: "Normal", quickFormat: true, + run: { font: FONT.KAITI, size: 28, bold: true }, // 楷体四号加粗 + paragraph: { + spacing: { line: 560, lineRule: "exact", before: 120, after: 60 }, + outlineLevel: 1, + }, + }, + ], +}; + +// ─── 列表定义 ───────────────────────────────────────────── +const numbering = { + config: [ + { + reference: "bullets", + levels: [{ + level: 0, format: LevelFormat.BULLET, text: "\u2022", + alignment: AlignmentType.LEFT, + style: { + run: { font: FONT.FANGSONG, size: 28 }, + paragraph: { indent: { left: 1120, hanging: 560 } }, // 缩进 2 字符 + 悬挂 + }, + }], + }, + ], +}; + +// ─── 辅助函数 ───────────────────────────────────────────── + +/** 创建正文段落(仿宋四号,首行缩进 2 字符) */ +function bodyParagraph(text, options = {}) { + const { bold = false, alignment = AlignmentType.JUSTIFIED } = options; + return new Paragraph({ + alignment, + indent: { firstLine: 560 }, + spacing: { line: 560, lineRule: "exact" }, + children: [new TextRun({ text, font: FONT.FANGSONG, size: 28, bold })], + }); +} + +/** 创建一级标题(黑体三号) */ +function heading1(text) { + return new Paragraph({ + heading: HeadingLevel.HEADING_1, + children: [new TextRun({ text, font: FONT.HEITI, size: 32, bold: true })], + }); +} + +/** 创建二级标题(楷体四号加粗) */ +function heading2(text) { + return new Paragraph({ + heading: HeadingLevel.HEADING_2, + children: [new TextRun({ text, font: FONT.KAITI, size: 28, bold: true })], + }); +} + +/** 创建三线表 */ +function threeLineTable(headers, rows) { + const noBorder = { style: BorderStyle.NONE, size: 0 }; + const thickBorder = { style: BorderStyle.SINGLE, size: 12, color: "000000" }; // 1.5pt + const thinBorder = { style: BorderStyle.SINGLE, size: 6, color: "000000" }; // 0.75pt + + // 表头行边框:顶粗 + 底细 + const headerBorders = { + top: thickBorder, bottom: thinBorder, + left: noBorder, right: noBorder, + }; + // 数据行边框:无顶底左右(靠 insideH 提供行间线) + const dataBorders = { + top: noBorder, bottom: noBorder, + left: noBorder, right: noBorder, + }; + // 最后一行底部:粗线 + const lastRowBorders = { + top: noBorder, bottom: thickBorder, + left: noBorder, right: noBorder, + }; + + const colWidths = headers.map(() => Math.floor(PAGE.CONTENT_WIDTH / headers.length)); + + function makeCell(text, isHeader, borders) { + return new TableCell({ + borders, + width: { size: colWidths[0], type: WidthType.DXA }, + shading: isHeader + ? { fill: "F2F2F2", type: ShadingType.CLEAR } + : undefined, + margins: { top: 40, bottom: 40, left: 80, right: 80 }, + children: [new Paragraph({ + alignment: AlignmentType.CENTER, + spacing: { line: 440, lineRule: "exact" }, + children: [new TextRun({ + text, + font: isHeader ? FONT.HEITI : FONT.FANGSONG, + size: 24, // 小四 12pt + bold: isHeader, + })], + })], + }); + } + + const tableRows = [ + // 表头 + new TableRow({ + children: headers.map(h => makeCell(h, true, headerBorders)), + }), + // 数据行 + ...rows.map((row, rowIdx) => + new TableRow({ + children: row.map(cell => + makeCell(cell, false, rowIdx === rows.length - 1 ? lastRowBorders : dataBorders) + ), + }) + ), + ]; + + return new Table({ + width: { size: PAGE.CONTENT_WIDTH, type: WidthType.DXA }, + columnWidths: colWidths, + rows: tableRows, + }); +} + +/** 报告标题区(居中,无封面) */ +function titleBlock(title, subtitle, date, institution) { + return [ + new Paragraph({ + alignment: AlignmentType.CENTER, + spacing: { line: 640, lineRule: "exact", after: 0 }, + children: [new TextRun({ text: title, font: FONT.HEITI, size: 32, bold: true })], + }), + subtitle ? new Paragraph({ + alignment: AlignmentType.CENTER, + spacing: { line: 640, lineRule: "exact", after: 120 }, + children: [new TextRun({ text: subtitle, font: FONT.HEITI, size: 32 })], + }) : null, + new Paragraph({ + alignment: AlignmentType.CENTER, + spacing: { line: 560, lineRule: "exact", after: 0 }, + children: [new TextRun({ text: date, font: FONT.FANGSONG, size: 28 })], + }), + institution ? new Paragraph({ + alignment: AlignmentType.CENTER, + spacing: { line: 560, lineRule: "exact", after: 240 }, + children: [new TextRun({ text: institution, font: FONT.FANGSONG, size: 28 })], + }) : null, + ].filter(Boolean); +} + +// ─── 使用示例:构建文档 ────────────────────────────────── + +const doc = new Document({ + styles, + numbering, + sections: [{ + properties: { + page: { + size: { width: PAGE.WIDTH, height: PAGE.HEIGHT }, + margin: { + top: PAGE.MARGIN_TOP, bottom: PAGE.MARGIN_BOTTOM, + left: PAGE.MARGIN_LEFT, right: PAGE.MARGIN_RIGHT, + }, + }, + }, + headers: { + default: new Header({ + children: [new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ + text: "内部资料 注意保密", + font: FONT.FANGSONG, size: 21, color: "808080", + })], + })], + }), + }, + footers: { + default: new Footer({ + children: [new Paragraph({ + alignment: AlignmentType.CENTER, + children: [ + new TextRun({ text: "— ", font: FONT.FANGSONG, size: 21 }), + new TextRun({ children: [PageNumber.CURRENT], font: FONT.FANGSONG, size: 21 }), + new TextRun({ text: " —", font: FONT.FANGSONG, size: 21 }), + ], + })], + }), + }, + children: [ + // 标题区 + ...titleBlock( + "zn04(鲁肆号)年金组合", + "权益投资分析与策略展望报告", + "估值日:2026年3月10日", + "工银瑞信基金管理有限公司" + ), + + // 正文 + heading1("一、投资策略与研判框架"), + bodyParagraph("本组合采用"多维度全局配置"策略,横跨A股和港股市场..."), + + heading2("1.1 八大核心研判及验证"), + threeLineTable( + ["#", "核心判断", "验证状态", "关键证据"], + [ + ["1", "恒生科技有超额收益", "1月验证后逆转", "1月+4.2%→3月-12.45%"], + ["2", "AI国内参与性价比不高", "已验证", "A股AI概念高位回落"], + ] + ), + + heading1("二、组合现状概览"), + bodyParagraph("截至估值日,组合单位净值1.4430,权益仓位合计占比约23%。"), + ], + }], +}); + +// 导出 +Packer.toBuffer(doc).then(buffer => { + fs.writeFileSync("output.docx", buffer); + console.log("✅ 已生成: output.docx"); +}); +``` + +### 运行 + +```bash +node generate_report.js +# 验证(可选,使用官方 docx skill 的验证工具) +python .claude/skills/docx/scripts/office/validate.py output.docx +``` + +--- + +## 辅助函数速查 + +| 函数 | 用途 | 格式 | +|------|------|------| +| `titleBlock(title, subtitle, date, institution)` | 报告标题区(无封面) | 黑体三号居中 | +| `heading1(text)` | 一级标题 | 黑体三号 16pt | +| `heading2(text)` | 二级标题 | 楷体四号加粗 | +| `bodyParagraph(text, {bold, alignment})` | 正文段落 | 仿宋四号,首行缩进,28pt行距 | +| `threeLineTable(headers, rows)` | 三线表 | 顶底1.5pt,内部0.75pt,无竖线 | + +--- + +## 编辑现有文档 + +当需要修改已有 .docx 文件时,使用官方 docx skill 的 unpack/pack 工作流: + +```bash +# 1. 解包 +python .claude/skills/docx/scripts/office/unpack.py document.docx unpacked/ + +# 2. 编辑 unpacked/word/document.xml(直接用 Edit 工具修改 XML) + +# 3. 重新打包 +python .claude/skills/docx/scripts/office/pack.py unpacked/ output.docx --original document.docx +``` + +### 公文格式关键 XML 片段 + +#### 页面设置(插入 `` 中) + +```xml + + +``` + +#### 正文段落格式 + +```xml + + + + + + + + + + +``` + +#### 一级标题 + +```xml + + + + + + + + + + +``` + +#### 三线表边框(`` 内) + +```xml + + + + + + +``` + +--- + +## 从现有文档提取内容并重建 + +当需要对已有文档「重排版」时,推荐提取内容后用 docx-js 重建: + +```bash +# 提取为 Markdown +pandoc original.docx -o content.md + +# 然后读取 content.md,用上面的模板函数构建新文档 +``` + +这比原地修改格式更可靠,避免了样式冲突和继承问题。 + +--- + +## 格式检查清单 + +- [ ] 纸张:A4(11906 × 16838 DXA) +- [ ] 页边距:上37 / 下35 / 左28 / 右26 mm +- [ ] 一级标题:黑体三号(16pt),固定行距 32pt +- [ ] 二级标题:楷体四号加粗(14pt),固定行距 28pt +- [ ] 正文:仿宋四号(14pt),固定行距 28pt,首行缩进 2 字符 +- [ ] 表格:三线表,表头黑体小四 + 浅灰底,内容仿宋小四 +- [ ] 页脚:居中 "— 页码 —",仿宋五号 +- [ ] 字体必须设置 `eastAsia` 属性 + +## 依赖 + +- **Node.js**: v18+ +- **docx**: `npm install docx`(docx-js 库) +- **pandoc**: 文本提取(可选) +- **官方 docx skill**: 提供 validate.py / unpack.py / pack.py diff --git a/docx-cn/scripts/gongwen_constants.js b/docx-cn/scripts/gongwen_constants.js new file mode 100644 index 0000000..663c754 --- /dev/null +++ b/docx-cn/scripts/gongwen_constants.js @@ -0,0 +1,287 @@ +/** + * GB/T 9704-2012 公文格式常量 + * 供所有公文文档生成脚本共享 + */ + +const { AlignmentType, BorderStyle, WidthType, ShadingType, LevelFormat, + HeadingLevel, Paragraph, TextRun, Table, TableRow, TableCell, + Header, Footer, PageNumber } = require("docx"); + +// ─── 页面 ───────────────────────────────────────────────── +const PAGE = { + WIDTH: 11906, // 210mm + HEIGHT: 16838, // 297mm + MARGIN_TOP: 2098, // 37mm + MARGIN_BOTTOM: 1985, // 35mm + MARGIN_LEFT: 1588, // 28mm + MARGIN_RIGHT: 1474, // 26mm + CONTENT_WIDTH: 8844, // 210 - 28 - 26 mm +}; + +// ─── 字体 ───────────────────────────────────────────────── +const FONT = { + HEITI: { ascii: "SimHei", eastAsia: "黑体", hAnsi: "SimHei" }, + FANGSONG: { ascii: "FangSong", eastAsia: "仿宋", hAnsi: "FangSong" }, + KAITI: { ascii: "KaiTi", eastAsia: "楷体", hAnsi: "KaiTi" }, + SONGTI: { ascii: "SimSun", eastAsia: "宋体", hAnsi: "SimSun" }, +}; + +// ─── 字号(half-point) ─────────────────────────────────── +const SIZE = { + ER_HAO: 44, // 二号 22pt + SAN_HAO: 32, // 三号 16pt + SI_HAO: 28, // 四号 14pt + XIAO_SI: 24, // 小四 12pt + WU_HAO: 21, // 五号 10.5pt +}; + +// ─── 行距(twips = pt × 20) ───────────────────────────── +const LINE = { + BODY: { line: 560, lineRule: "exact" }, // 28pt + HEADING1: { line: 640, lineRule: "exact" }, // 32pt + HEADING2: { line: 560, lineRule: "exact" }, // 28pt + TABLE: { line: 440, lineRule: "exact" }, // 22pt + TITLE: { line: 640, lineRule: "exact" }, // 32pt + COMPACT: { line: 360, lineRule: "exact" }, // 18pt +}; + +// ─── 缩进(DXA) ───────────────────────────────────────── +const INDENT = { + FIRST_LINE: 560, // 首行缩进 2 字符 + BULLET_LEFT: 1120, + BULLET_HANG: 560, +}; + +// ─── 边框 ───────────────────────────────────────────────── +const BORDER = { + NONE: { style: BorderStyle.NONE, size: 0 }, + THICK: { style: BorderStyle.SINGLE, size: 12, color: "000000" }, // 1.5pt + THIN: { style: BorderStyle.SINGLE, size: 6, color: "000000" }, // 0.75pt +}; + +// ─── 样式预设 ───────────────────────────────────────────── +function getStyles() { + return { + default: { + document: { + run: { font: FONT.FANGSONG, size: SIZE.SI_HAO }, + paragraph: { spacing: LINE.BODY }, + }, + }, + paragraphStyles: [ + { + id: "Heading1", name: "Heading 1", + basedOn: "Normal", next: "Normal", quickFormat: true, + run: { font: FONT.HEITI, size: SIZE.SAN_HAO, bold: true }, + paragraph: { spacing: { ...LINE.HEADING1, before: 240, after: 120 }, outlineLevel: 0 }, + }, + { + id: "Heading2", name: "Heading 2", + basedOn: "Normal", next: "Normal", quickFormat: true, + run: { font: FONT.KAITI, size: SIZE.SI_HAO, bold: true }, + paragraph: { spacing: { ...LINE.HEADING2, before: 120, after: 60 }, outlineLevel: 1 }, + }, + ], + }; +} + +function getNumbering() { + return { + config: [{ + reference: "bullets", + levels: [{ + level: 0, format: LevelFormat.BULLET, text: "\u2022", + alignment: AlignmentType.LEFT, + style: { + run: { font: FONT.FANGSONG, size: SIZE.SI_HAO }, + paragraph: { indent: { left: INDENT.BULLET_LEFT, hanging: INDENT.BULLET_HANG } }, + }, + }], + }], + }; +} + +// ─── 辅助函数 ───────────────────────────────────────────── + +/** 报告标题区(无封面,居中) */ +function titleBlock(title, subtitle, date, institution) { + const items = []; + items.push(new Paragraph({ + alignment: AlignmentType.CENTER, + spacing: { ...LINE.TITLE, after: 0 }, + children: [new TextRun({ text: title, font: FONT.HEITI, size: SIZE.SAN_HAO, bold: true })], + })); + if (subtitle) { + items.push(new Paragraph({ + alignment: AlignmentType.CENTER, + spacing: { ...LINE.TITLE, after: 120 }, + children: [new TextRun({ text: subtitle, font: FONT.HEITI, size: SIZE.SAN_HAO })], + })); + } + items.push(new Paragraph({ + alignment: AlignmentType.CENTER, + spacing: { ...LINE.BODY, after: 0 }, + children: [new TextRun({ text: date, font: FONT.FANGSONG, size: SIZE.SI_HAO })], + })); + if (institution) { + items.push(new Paragraph({ + alignment: AlignmentType.CENTER, + spacing: { ...LINE.BODY, after: 240 }, + children: [new TextRun({ text: institution, font: FONT.FANGSONG, size: SIZE.SI_HAO })], + })); + } + return items; +} + +/** 一级标题 */ +function h1(text) { + return new Paragraph({ + heading: HeadingLevel.HEADING_1, + spacing: { ...LINE.HEADING1, before: 240, after: 120 }, + children: [new TextRun({ text, font: FONT.HEITI, size: SIZE.SAN_HAO, bold: true })], + }); +} + +/** 二级标题 */ +function h2(text) { + return new Paragraph({ + heading: HeadingLevel.HEADING_2, + spacing: { ...LINE.HEADING2, before: 120, after: 60 }, + children: [new TextRun({ text, font: FONT.KAITI, size: SIZE.SI_HAO, bold: true })], + }); +} + +/** 正文段落 */ +function body(text, opts = {}) { + const { bold = false, align = AlignmentType.JUSTIFIED, indent = true } = opts; + return new Paragraph({ + alignment: align, + indent: indent ? { firstLine: INDENT.FIRST_LINE } : undefined, + spacing: LINE.BODY, + children: [new TextRun({ text, font: FONT.FANGSONG, size: SIZE.SI_HAO, bold })], + }); +} + +/** 多 run 正文段落(支持混排加粗) */ +function bodyRuns(runs, opts = {}) { + const { align = AlignmentType.JUSTIFIED, indent = true } = opts; + return new Paragraph({ + alignment: align, + indent: indent ? { firstLine: INDENT.FIRST_LINE } : undefined, + spacing: LINE.BODY, + children: runs.map(r => { + if (typeof r === "string") { + return new TextRun({ text: r, font: FONT.FANGSONG, size: SIZE.SI_HAO }); + } + return new TextRun({ font: FONT.FANGSONG, size: SIZE.SI_HAO, ...r }); + }), + }); +} + +/** 列表项 */ +function bullet(text) { + return new Paragraph({ + numbering: { reference: "bullets", level: 0 }, + spacing: LINE.BODY, + children: [new TextRun({ text, font: FONT.FANGSONG, size: SIZE.SI_HAO })], + }); +} + +/** 三线表 */ +function threeLineTable(headers, rows, opts = {}) { + const { colWidths } = opts; + const widths = colWidths || headers.map(() => Math.floor(PAGE.CONTENT_WIDTH / headers.length)); + + function cell(text, isHeader, isLastRow, colIdx) { + const borders = { + top: isHeader ? BORDER.THICK : BORDER.NONE, + bottom: isHeader ? BORDER.THIN : (isLastRow ? BORDER.THICK : BORDER.NONE), + left: BORDER.NONE, + right: BORDER.NONE, + }; + return new TableCell({ + borders, + width: { size: widths[colIdx], type: WidthType.DXA }, + shading: isHeader ? { fill: "1F3864", type: ShadingType.CLEAR } : undefined, + margins: { top: 40, bottom: 40, left: 80, right: 80 }, + children: [new Paragraph({ + alignment: AlignmentType.CENTER, + spacing: LINE.TABLE, + children: [new TextRun({ + text: String(text), + font: isHeader ? FONT.HEITI : FONT.FANGSONG, + size: SIZE.XIAO_SI, + bold: isHeader, + color: isHeader ? "FFFFFF" : undefined, + })], + })], + }); + } + + // 表级边框全部 NONE,由 cell 级别控制三线效果 + const noBorder = { style: BorderStyle.NONE, size: 0, color: "FFFFFF" }; + return new Table({ + width: { size: PAGE.CONTENT_WIDTH, type: WidthType.DXA }, + columnWidths: widths, + borders: { + top: noBorder, bottom: noBorder, + left: noBorder, right: noBorder, + insideHorizontal: noBorder, insideVertical: noBorder, + }, + rows: [ + new TableRow({ children: headers.map((h, i) => cell(h, true, false, i)) }), + ...rows.map((row, ri) => + new TableRow({ + children: row.map((c, ci) => cell(c, false, ri === rows.length - 1, ci)), + }) + ), + ], + }); +} + +/** 标准页脚(— 页码 —) */ +function pageFooter() { + return new Footer({ + children: [new Paragraph({ + alignment: AlignmentType.CENTER, + children: [ + new TextRun({ text: "— ", font: FONT.FANGSONG, size: SIZE.WU_HAO }), + new TextRun({ children: [PageNumber.CURRENT], font: FONT.FANGSONG, size: SIZE.WU_HAO }), + new TextRun({ text: " —", font: FONT.FANGSONG, size: SIZE.WU_HAO }), + ], + })], + }); +} + +/** 标准页眉 */ +function pageHeader(text = "内部资料 注意保密") { + return new Header({ + children: [new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ + text, font: FONT.FANGSONG, size: SIZE.WU_HAO, color: "808080", + })], + })], + }); +} + +/** section 属性(页面设置) */ +function sectionProps(opts = {}) { + return { + page: { + size: { width: PAGE.WIDTH, height: PAGE.HEIGHT }, + margin: { + top: PAGE.MARGIN_TOP, bottom: PAGE.MARGIN_BOTTOM, + left: PAGE.MARGIN_LEFT, right: PAGE.MARGIN_RIGHT, + }, + }, + ...opts, + }; +} + +module.exports = { + PAGE, FONT, SIZE, LINE, INDENT, BORDER, + getStyles, getNumbering, sectionProps, + titleBlock, h1, h2, body, bodyRuns, bullet, + threeLineTable, pageFooter, pageHeader, +}; diff --git a/docx/LICENSE.txt b/docx/LICENSE.txt new file mode 100644 index 0000000..c55ab42 --- /dev/null +++ b/docx/LICENSE.txt @@ -0,0 +1,30 @@ +© 2025 Anthropic, PBC. All rights reserved. + +LICENSE: Use of these materials (including all code, prompts, assets, files, +and other components of this Skill) is governed by your agreement with +Anthropic regarding use of Anthropic's services. If no separate agreement +exists, use is governed by Anthropic's Consumer Terms of Service or +Commercial Terms of Service, as applicable: +https://www.anthropic.com/legal/consumer-terms +https://www.anthropic.com/legal/commercial-terms +Your applicable agreement is referred to as the "Agreement." "Services" are +as defined in the Agreement. + +ADDITIONAL RESTRICTIONS: Notwithstanding anything in the Agreement to the +contrary, users may not: + +- Extract these materials from the Services or retain copies of these + materials outside the Services +- Reproduce or copy these materials, except for temporary copies created + automatically during authorized use of the Services +- Create derivative works based on these materials +- Distribute, sublicense, or transfer these materials to any third party +- Make, offer to sell, sell, or import any inventions embodied in these + materials +- Reverse engineer, decompile, or disassemble these materials + +The receipt, viewing, or possession of these materials does not convey or +imply any license or right beyond those expressly granted above. + +Anthropic retains all right, title, and interest in these materials, +including all copyrights, patents, and other intellectual property rights. diff --git a/docx/SKILL.md b/docx/SKILL.md new file mode 100644 index 0000000..a819ac1 --- /dev/null +++ b/docx/SKILL.md @@ -0,0 +1,198 @@ +--- +name: docx +description: "Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. When Claude needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks" +license: Proprietary. LICENSE.txt has complete terms +--- + +# DOCX creation, editing, and analysis + +## Overview + +A user may ask you to create, edit, or analyze the contents of a .docx file. A .docx file is essentially a ZIP archive containing XML files and other resources that you can read or edit. You have different tools and workflows available for different tasks. + +## Workflow Decision Tree + +### Reading/Analyzing Content +Use "Text extraction" or "Raw XML access" sections below + +### Creating New Document +Use "Creating a new Word document" workflow + +### Editing Existing Document +- **Your own document + simple changes** + Use "Basic OOXML editing" workflow + +- **Someone else's document** + Use **"Redlining workflow"** (recommended default) + +- **Legal, academic, business, or government docs** + Use **"Redlining workflow"** (required) + +## Reading and analyzing content + +### Text extraction +If you just need to read the text contents of a document, you should convert the document to markdown using pandoc. Pandoc provides excellent support for preserving document structure and can show tracked changes: + +```bash +# Convert document to markdown with tracked changes +pandoc --track-changes=all path-to-file.docx -o output.md +# Options: --track-changes=accept/reject/all +``` + +### Raw XML access +You need raw XML access for: comments, complex formatting, document structure, embedded media, and metadata. For any of these features, you'll need to unpack a document and read its raw XML contents. + +#### Unpacking a file +`python ooxml/scripts/unpack.py ` + +#### Key file structures +* `word/document.xml` - Main document contents +* `word/comments.xml` - Comments referenced in document.xml +* `word/media/` - Embedded images and media files +* Tracked changes use `` (insertions) and `` (deletions) tags + +## Creating a new Word document + +When creating a new Word document from scratch, use **docx-js**, which allows you to create Word documents using JavaScript/TypeScript. + +### Workflow +1. **MANDATORY - READ ENTIRE FILE**: Read [`docx-js.md`](docx-js.md) (~500 lines) completely from start to finish. **NEVER set any range limits when reading this file.** Read the full file content for detailed syntax, critical formatting rules, and best practices before proceeding with document creation. +2. Create a JavaScript/TypeScript file using Document, Paragraph, TextRun components (You can assume all dependencies are installed, but if not, refer to the dependencies section below) +3. Export as .docx using Packer.toBuffer() + +## Editing an existing Word document + +When editing an existing Word document, use the **Document library** (a Python library for OOXML manipulation). The library automatically handles infrastructure setup and provides methods for document manipulation. For complex scenarios, you can access the underlying DOM directly through the library. + +### Workflow +1. **MANDATORY - READ ENTIRE FILE**: Read [`ooxml.md`](ooxml.md) (~600 lines) completely from start to finish. **NEVER set any range limits when reading this file.** Read the full file content for the Document library API and XML patterns for directly editing document files. +2. Unpack the document: `python ooxml/scripts/unpack.py ` +3. Create and run a Python script using the Document library (see "Document Library" section in ooxml.md) +4. Pack the final document: `python ooxml/scripts/pack.py ` + +The Document library provides both high-level methods for common operations and direct DOM access for complex scenarios. + +## Redlining workflow for document review + +This workflow allows you to plan comprehensive tracked changes using markdown before implementing them in OOXML. **CRITICAL**: For complete tracked changes, you must implement ALL changes systematically. + +**Batching Strategy**: Group related changes into batches of 3-10 changes. This makes debugging manageable while maintaining efficiency. Test each batch before moving to the next. + +**Principle: Minimal, Precise Edits** +When implementing tracked changes, only mark text that actually changes. Repeating unchanged text makes edits harder to review and appears unprofessional. Break replacements into: [unchanged text] + [deletion] + [insertion] + [unchanged text]. Preserve the original run's RSID for unchanged text by extracting the `` element from the original and reusing it. + +Example - Changing "30 days" to "60 days" in a sentence: +```python +# BAD - Replaces entire sentence +'The term is 30 days.The term is 60 days.' + +# GOOD - Only marks what changed, preserves original for unchanged text +'The term is 3060 days.' +``` + +### Tracked changes workflow + +1. **Get markdown representation**: Convert document to markdown with tracked changes preserved: + ```bash + pandoc --track-changes=all path-to-file.docx -o current.md + ``` + +2. **Identify and group changes**: Review the document and identify ALL changes needed, organizing them into logical batches: + + **Location methods** (for finding changes in XML): + - Section/heading numbers (e.g., "Section 3.2", "Article IV") + - Paragraph identifiers if numbered + - Grep patterns with unique surrounding text + - Document structure (e.g., "first paragraph", "signature block") + - **DO NOT use markdown line numbers** - they don't map to XML structure + + **Batch organization** (group 3-10 related changes per batch): + - By section: "Batch 1: Section 2 amendments", "Batch 2: Section 5 updates" + - By type: "Batch 1: Date corrections", "Batch 2: Party name changes" + - By complexity: Start with simple text replacements, then tackle complex structural changes + - Sequential: "Batch 1: Pages 1-3", "Batch 2: Pages 4-6" + +3. **Read documentation and unpack**: + - **MANDATORY - READ ENTIRE FILE**: Read [`ooxml.md`](ooxml.md) (~600 lines) completely from start to finish. **NEVER set any range limits when reading this file.** Pay special attention to the "Document Library" and "Tracked Change Patterns" sections. + - **Unpack the document**: `python ooxml/scripts/unpack.py ` + - **Note the suggested RSID**: The unpack script will suggest an RSID to use for your tracked changes. Copy this RSID for use in step 4b. + +4. **Implement changes in batches**: Group changes logically (by section, by type, or by proximity) and implement them together in a single script. This approach: + - Makes debugging easier (smaller batch = easier to isolate errors) + - Allows incremental progress + - Maintains efficiency (batch size of 3-10 changes works well) + + **Suggested batch groupings:** + - By document section (e.g., "Section 3 changes", "Definitions", "Termination clause") + - By change type (e.g., "Date changes", "Party name updates", "Legal term replacements") + - By proximity (e.g., "Changes on pages 1-3", "Changes in first half of document") + + For each batch of related changes: + + **a. Map text to XML**: Grep for text in `word/document.xml` to verify how text is split across `` elements. + + **b. Create and run script**: Use `get_node` to find nodes, implement changes, then `doc.save()`. See **"Document Library"** section in ooxml.md for patterns. + + **Note**: Always grep `word/document.xml` immediately before writing a script to get current line numbers and verify text content. Line numbers change after each script run. + +5. **Pack the document**: After all batches are complete, convert the unpacked directory back to .docx: + ```bash + python ooxml/scripts/pack.py unpacked reviewed-document.docx + ``` + +6. **Final verification**: Do a comprehensive check of the complete document: + - Convert final document to markdown: + ```bash + pandoc --track-changes=all reviewed-document.docx -o verification.md + ``` + - Verify ALL changes were applied correctly: + ```bash + grep "original phrase" verification.md # Should NOT find it + grep "replacement phrase" verification.md # Should find it + ``` + - Check that no unintended changes were introduced + + +## Converting Documents to Images + +To visually analyze Word documents, convert them to images using a two-step process: + +1. **Convert DOCX to PDF**: + ```bash + soffice --headless --convert-to pdf document.docx + ``` + +2. **Convert PDF pages to JPEG images**: + ```bash + pdftoppm -jpeg -r 150 document.pdf page + ``` + This creates files like `page-1.jpg`, `page-2.jpg`, etc. + +Options: +- `-r 150`: Sets resolution to 150 DPI (adjust for quality/size balance) +- `-jpeg`: Output JPEG format (use `-png` for PNG if preferred) +- `-f N`: First page to convert (e.g., `-f 2` starts from page 2) +- `-l N`: Last page to convert (e.g., `-l 5` stops at page 5) +- `page`: Prefix for output files + +Example for specific range: +```bash +pdftoppm -jpeg -r 150 -f 2 -l 5 document.pdf page # Converts only pages 2-5 +``` + +## Code Style Guidelines +**IMPORTANT**: When generating code for DOCX operations: +- Write concise code +- Avoid verbose variable names and redundant operations +- Avoid unnecessary print statements +- **跨平台路径**: 始终用 `path.join()` (JS) 或 `os.path.join()` (Python) 拼接路径,不要硬编码 `/` 或 `\\`。详见 docx-js.md「Cross-Platform 路径处理」章节 + +## Dependencies + +Required dependencies (install if not available): + +- **pandoc**: `sudo apt-get install pandoc` (for text extraction) +- **docx**: `npm install -g docx` (for creating new documents) +- **LibreOffice**: `sudo apt-get install libreoffice` (for PDF conversion) +- **Poppler**: `sudo apt-get install poppler-utils` (for pdftoppm to convert PDF to images) +- **defusedxml**: `pip install defusedxml` (for secure XML parsing) \ No newline at end of file diff --git a/docx/docx-js.md b/docx/docx-js.md new file mode 100644 index 0000000..bab0d45 --- /dev/null +++ b/docx/docx-js.md @@ -0,0 +1,499 @@ +# DOCX Library Tutorial + +Generate .docx files with JavaScript/TypeScript. + +**Important: Read this entire document before starting.** Critical formatting rules and common pitfalls are covered throughout - skipping sections may result in corrupted files or rendering issues. + +## Setup +Assumes docx is already installed globally +If not installed: `npm install -g docx` + +```javascript +const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, ImageRun, Media, + Header, Footer, AlignmentType, PageOrientation, LevelFormat, ExternalHyperlink, + InternalHyperlink, TableOfContents, HeadingLevel, BorderStyle, WidthType, TabStopType, + TabStopPosition, UnderlineType, ShadingType, VerticalAlign, SymbolRun, PageNumber, + FootnoteReferenceRun, Footnote, PageBreak } = require('docx'); + +// Create & Save +const doc = new Document({ sections: [{ children: [/* content */] }] }); +Packer.toBuffer(doc).then(buffer => fs.writeFileSync("doc.docx", buffer)); // Node.js +Packer.toBlob(doc).then(blob => { /* download logic */ }); // Browser +``` + +## Text & Formatting +```javascript +// IMPORTANT: Never use \n for line breaks - always use separate Paragraph elements +// ❌ WRONG: new TextRun("Line 1\nLine 2") +// ✅ CORRECT: new Paragraph({ children: [new TextRun("Line 1")] }), new Paragraph({ children: [new TextRun("Line 2")] }) + +// Basic text with all formatting options (公文配置:仿宋 14pt 默认) +new Paragraph({ + alignment: AlignmentType.JUSTIFIED, // 公文两端对齐 + spacing: { before: 200, after: 200 }, + indent: { firstLine: 560 }, // 公文首行缩进 2em + children: [ + new TextRun({ text: "加粗", bold: true }), + new TextRun({ text: "斜体", italics: true }), + new TextRun({ text: "下划线", underline: { type: UnderlineType.SINGLE, color: "000000" } }), // 公文用黑色 + new TextRun({ text: "指定字号", size: 28, font: "STFangsong" }), // 仿宋 14pt + new TextRun({ text: "高亮", highlight: "yellow" }), + new TextRun({ text: "删除线", strike: true }), + new TextRun({ text: "x2", superScript: true }), + new TextRun({ text: "H2O", subScript: true }), + new SymbolRun({ char: "2022", font: "Symbol" }), // Bullet • + new SymbolRun({ char: "00A9", font: "STFangsong" }) // Copyright © + ] +}) +``` + +## Styles — AbleMind 公文 UI 设计系统 + +### 字体体系 + +| 变量 | 字体栈 | 用途 | +|------|--------|------| +| `--gov-font-body` | STFangsong → FangSong → Fangsong SC → Noto Serif SC → serif | 正文(仿宋体) | +| `--gov-font-heading` | Heiti SC → PingFang SC → SimHei → Noto Sans SC → sans-serif | 标题(黑体) | +| `--gov-font-mono` | IBM Plex Mono → JetBrains Mono → monospace | UI 等宽 | +| `--gov-font-code` | Courier New → monospace | 代码块 | + +在 docx-js 中使用时,font 值按优先级取第一个系统可用字体即可(macOS 优先 STFangsong / Heiti SC)。 + +### 公文排版规范 + +| 元素 | 字体 | 字号 | 其他 | +|------|------|------|------| +| 正文 | 仿宋 (STFangsong) | 14pt (size: 28) | 行距 1.5,首行缩进 2em,两端对齐 | +| h1 | 黑体 (Heiti SC) | 16pt (size: 32) | 居中,加粗 | +| h2 | 黑体 (Heiti SC) | 15pt (size: 30) | 左对齐,加粗 | +| h3–h6 | 黑体 (Heiti SC) | 14pt (size: 28) | 左对齐,加粗 | +| 表格 | 仿宋 (STFangsong) | 小四 12pt (size: 24) | 全线框,表头灰底 | +| 代码 | Courier New | 12pt (size: 24) | 灰底框线 | +| 链接 | 同正文 | 同正文 | 黑色下划线(公文不用彩色链接) | + +### 标准公文样式模板 + +```javascript +// AbleMind 公文配置 — 默认样式 +const GOV_FONT_BODY = "STFangsong"; // 仿宋体(正文) +const GOV_FONT_HEADING = "Heiti SC"; // 黑体(标题) +const GOV_FONT_CODE = "Courier New"; // 代码块 + +const doc = new Document({ + styles: { + default: { + document: { + run: { font: GOV_FONT_BODY, size: 28 }, // 仿宋 14pt + paragraph: { + spacing: { line: 360 }, // 行距 1.5 (240 * 1.5) + alignment: AlignmentType.JUSTIFIED // 两端对齐 + } + } + }, + paragraphStyles: [ + // 公文标题 — 黑体 16pt 居中 + { id: "Title", name: "Title", basedOn: "Normal", + run: { size: 32, bold: true, color: "000000", font: GOV_FONT_HEADING }, + paragraph: { spacing: { before: 240, after: 120 }, alignment: AlignmentType.CENTER } }, + // h1 — 黑体 16pt 居中 + { id: "Heading1", name: "Heading 1", basedOn: "Normal", next: "Normal", quickFormat: true, + run: { size: 32, bold: true, color: "000000", font: GOV_FONT_HEADING }, + paragraph: { spacing: { before: 240, after: 240, line: 360 }, alignment: AlignmentType.CENTER, outlineLevel: 0 } }, + // h2 — 黑体 15pt 左对齐 + { id: "Heading2", name: "Heading 2", basedOn: "Normal", next: "Normal", quickFormat: true, + run: { size: 30, bold: true, color: "000000", font: GOV_FONT_HEADING }, + paragraph: { spacing: { before: 180, after: 180, line: 360 }, outlineLevel: 1 } }, + // h3–h6 — 黑体 14pt 左对齐 + { id: "Heading3", name: "Heading 3", basedOn: "Normal", next: "Normal", quickFormat: true, + run: { size: 28, bold: true, color: "000000", font: GOV_FONT_HEADING }, + paragraph: { spacing: { before: 120, after: 120, line: 360 }, outlineLevel: 2 } }, + { id: "Heading4", name: "Heading 4", basedOn: "Normal", next: "Normal", quickFormat: true, + run: { size: 28, bold: true, color: "000000", font: GOV_FONT_HEADING }, + paragraph: { spacing: { before: 120, after: 120, line: 360 }, outlineLevel: 3 } }, + // 自定义样式仍可添加 + { id: "govNote", name: "Gov Note", basedOn: "Normal", + run: { size: 24, color: "333333", font: GOV_FONT_BODY }, + paragraph: { spacing: { after: 60 } } } + ], + characterStyles: [ + // 公文链接:黑色下划线,不用彩色 + { id: "Hyperlink", name: "Hyperlink", + run: { color: "000000", underline: { type: UnderlineType.SINGLE, color: "000000" } } }, + { id: "govEmphasis", name: "Gov Emphasis", + run: { bold: true, font: GOV_FONT_HEADING } } + ] + }, + sections: [{ + properties: { + page: { + margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 }, // A4 标准页边距 1 英寸 + size: { width: 11906, height: 16838 } // A4 尺寸 (210mm × 297mm in DXA) + } + }, + children: [ + new Paragraph({ heading: HeadingLevel.TITLE, children: [new TextRun("公文标题")] }), + new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun("一级标题")] }), + new Paragraph({ heading: HeadingLevel.HEADING_2, children: [new TextRun("二级标题")] }), + // 正文段落 — 首行缩进 2em(仿宋14pt ≈ 560 DXA) + new Paragraph({ + indent: { firstLine: 560 }, + children: [new TextRun("正文内容,仿宋14pt,行距1.5,首行缩进2em,两端对齐。")] + }) + ] + }] +}); +``` + +### 公文首行缩进说明 +- 首行缩进 2em = 2 × 字号对应的 DXA 值 +- 仿宋 14pt → `firstLine: 560` (14pt × 20 DXA/pt × 2) +- 小四 12pt → `firstLine: 480` (12pt × 20 DXA/pt × 2) +- 通过 `indent: { firstLine: 560 }` 设置在每个正文 Paragraph 上 + +### 跨平台字体回退 +- **macOS**: STFangsong / Heiti SC(系统自带) +- **Windows**: FangSong / SimHei(系统自带) +- **Linux/CI**: Noto Serif SC / Noto Sans SC(需安装 Google Noto CJK) +- docx-js 的 `font` 属性只写一个字体名,Word 打开时自动使用系统可用字体 + +**Key Styling Principles:** +- **Override built-in styles**: Use exact IDs like "Heading1", "Heading2", "Heading3" to override Word's built-in heading styles +- **HeadingLevel constants**: `HeadingLevel.HEADING_1` uses "Heading1" style, `HeadingLevel.HEADING_2` uses "Heading2" style, etc. +- **Include outlineLevel**: Set `outlineLevel: 0` for H1, `outlineLevel: 1` for H2, etc. to ensure TOC works correctly +- **公文字体一致性**: 正文统一仿宋,标题统一黑体,不混用其他字体 +- **公文不用彩色**: 链接、标题全部黑色,不使用蓝色超链接或灰色标题 +- **A4 纸张**: 使用 `size: { width: 11906, height: 16838 }` 设置 A4 尺寸 +- **行距 1.5**: 在 default paragraph spacing 中设置 `line: 360` +- **首行缩进**: 正文段落添加 `indent: { firstLine: 560 }` + + +## Lists (ALWAYS USE PROPER LISTS - NEVER USE UNICODE BULLETS) +```javascript +// Bullets - ALWAYS use the numbering config, NOT unicode symbols +// CRITICAL: Use LevelFormat.BULLET constant, NOT the string "bullet" +const doc = new Document({ + numbering: { + config: [ + { reference: "bullet-list", + levels: [{ level: 0, format: LevelFormat.BULLET, text: "•", alignment: AlignmentType.LEFT, + style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] }, + { reference: "first-numbered-list", + levels: [{ level: 0, format: LevelFormat.DECIMAL, text: "%1.", alignment: AlignmentType.LEFT, + style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] }, + { reference: "second-numbered-list", // Different reference = restarts at 1 + levels: [{ level: 0, format: LevelFormat.DECIMAL, text: "%1.", alignment: AlignmentType.LEFT, + style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] } + ] + }, + sections: [{ + children: [ + // Bullet list items + new Paragraph({ numbering: { reference: "bullet-list", level: 0 }, + children: [new TextRun("First bullet point")] }), + new Paragraph({ numbering: { reference: "bullet-list", level: 0 }, + children: [new TextRun("Second bullet point")] }), + // Numbered list items + new Paragraph({ numbering: { reference: "first-numbered-list", level: 0 }, + children: [new TextRun("First numbered item")] }), + new Paragraph({ numbering: { reference: "first-numbered-list", level: 0 }, + children: [new TextRun("Second numbered item")] }), + // ⚠️ CRITICAL: Different reference = INDEPENDENT list that restarts at 1 + // Same reference = CONTINUES previous numbering + new Paragraph({ numbering: { reference: "second-numbered-list", level: 0 }, + children: [new TextRun("Starts at 1 again (because different reference)")] }) + ] + }] +}); + +// ⚠️ CRITICAL NUMBERING RULE: Each reference creates an INDEPENDENT numbered list +// - Same reference = continues numbering (1, 2, 3... then 4, 5, 6...) +// - Different reference = restarts at 1 (1, 2, 3... then 1, 2, 3...) +// Use unique reference names for each separate numbered section! + +// ⚠️ CRITICAL: NEVER use unicode bullets - they create fake lists that don't work properly +// new TextRun("• Item") // WRONG +// new SymbolRun({ char: "2022" }) // WRONG +// ✅ ALWAYS use numbering config with LevelFormat.BULLET for real Word lists +``` + +## Tables — 公文表格规范 +```javascript +// 公文表格:小四 12pt 仿宋,全线框,表头灰底居中加粗 +const GOV_FONT_BODY = "STFangsong"; +const tableBorder = { style: BorderStyle.SINGLE, size: 1, color: "000000" }; // 公文用黑色全线框 +const cellBorders = { top: tableBorder, bottom: tableBorder, left: tableBorder, right: tableBorder }; + +new Table({ + columnWidths: [4680, 4680], // ⚠️ CRITICAL: Set column widths at table level - values in DXA (twentieths of a point) + margins: { top: 80, bottom: 80, left: 120, right: 120 }, // Set once for all cells + rows: [ + // 表头行:灰底居中加粗 + new TableRow({ + tableHeader: true, + children: [ + new TableCell({ + borders: cellBorders, + width: { size: 4680, type: WidthType.DXA }, + // ⚠️ CRITICAL: Always use ShadingType.CLEAR to prevent black backgrounds in Word. + shading: { fill: "D9D9D9", type: ShadingType.CLEAR }, // 浅灰底 + verticalAlign: VerticalAlign.CENTER, + children: [new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: "表头", bold: true, size: 24, font: GOV_FONT_BODY })] // 小四 12pt + })] + }), + new TableCell({ + borders: cellBorders, + width: { size: 4680, type: WidthType.DXA }, + shading: { fill: "D9D9D9", type: ShadingType.CLEAR }, + verticalAlign: VerticalAlign.CENTER, + children: [new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun({ text: "列标题", bold: true, size: 24, font: GOV_FONT_BODY })] + })] + }) + ] + }), + // 数据行:小四仿宋,左对齐 + new TableRow({ + children: [ + new TableCell({ + borders: cellBorders, + width: { size: 4680, type: WidthType.DXA }, + children: [new Paragraph({ children: [new TextRun({ text: "数据内容", size: 24, font: GOV_FONT_BODY })] })] + }), + new TableCell({ + borders: cellBorders, + width: { size: 4680, type: WidthType.DXA }, + children: [ + new Paragraph({ + numbering: { reference: "bullet-list", level: 0 }, + children: [new TextRun({ text: "列表项一", size: 24, font: GOV_FONT_BODY })] + }), + new Paragraph({ + numbering: { reference: "bullet-list", level: 0 }, + children: [new TextRun({ text: "列表项二", size: 24, font: GOV_FONT_BODY })] + }) + ] + }) + ] + }) + ] +}) +``` + +**IMPORTANT: Table Width & Borders** +- Use BOTH `columnWidths: [width1, width2, ...]` array AND `width: { size: X, type: WidthType.DXA }` on each cell +- Values in DXA (twentieths of a point): 1440 = 1 inch, Letter usable width = 9360 DXA (with 1" margins) +- Apply borders to individual `TableCell` elements, NOT the `Table` itself + +**Precomputed Column Widths (Letter size with 1" margins = 9360 DXA total):** +- **2 columns:** `columnWidths: [4680, 4680]` (equal width) +- **3 columns:** `columnWidths: [3120, 3120, 3120]` (equal width) + +## Links & Navigation +```javascript +// TOC (requires headings) - CRITICAL: Use HeadingLevel only, NOT custom styles +// ❌ WRONG: new Paragraph({ heading: HeadingLevel.HEADING_1, style: "customHeader", children: [new TextRun("Title")] }) +// ✅ CORRECT: new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun("Title")] }) +new TableOfContents("Table of Contents", { hyperlink: true, headingStyleRange: "1-3" }), + +// External link +new Paragraph({ + children: [new ExternalHyperlink({ + children: [new TextRun({ text: "Google", style: "Hyperlink" })], + link: "https://www.google.com" + })] +}), + +// Internal link & bookmark +new Paragraph({ + children: [new InternalHyperlink({ + children: [new TextRun({ text: "Go to Section", style: "Hyperlink" })], + anchor: "section1" + })] +}), +new Paragraph({ + children: [new TextRun("Section Content")], + bookmark: { id: "section1", name: "section1" } +}), +``` + +## Images & Media +```javascript +// Basic image with sizing & positioning +// CRITICAL: Always specify 'type' parameter - it's REQUIRED for ImageRun +new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new ImageRun({ + type: "png", // NEW REQUIREMENT: Must specify image type (png, jpg, jpeg, gif, bmp, svg) + data: fs.readFileSync("image.png"), + transformation: { width: 200, height: 150, rotation: 0 }, // rotation in degrees + altText: { title: "Logo", description: "Company logo", name: "Name" } // IMPORTANT: All three fields are required + })] +}) +``` + +## Page Breaks +```javascript +// Manual page break +new Paragraph({ children: [new PageBreak()] }), + +// Page break before paragraph +new Paragraph({ + pageBreakBefore: true, + children: [new TextRun("This starts on a new page")] +}) + +// ⚠️ CRITICAL: NEVER use PageBreak standalone - it will create invalid XML that Word cannot open +// ❌ WRONG: new PageBreak() +// ✅ CORRECT: new Paragraph({ children: [new PageBreak()] }) +``` + +## Headers/Footers & Page Setup +```javascript +const doc = new Document({ + sections: [{ + properties: { + page: { + margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 }, // 1440 = 1 inch + size: { orientation: PageOrientation.LANDSCAPE }, + pageNumbers: { start: 1, formatType: "decimal" } // "upperRoman", "lowerRoman", "upperLetter", "lowerLetter" + } + }, + headers: { + default: new Header({ children: [new Paragraph({ + alignment: AlignmentType.RIGHT, + children: [new TextRun("Header Text")] + })] }) + }, + footers: { + default: new Footer({ children: [new Paragraph({ + alignment: AlignmentType.CENTER, + children: [new TextRun("Page "), new TextRun({ children: [PageNumber.CURRENT] }), new TextRun(" of "), new TextRun({ children: [PageNumber.TOTAL_PAGES] })] + })] }) + }, + children: [/* content */] + }] +}); +``` + +## Tabs +```javascript +new Paragraph({ + tabStops: [ + { type: TabStopType.LEFT, position: TabStopPosition.MAX / 4 }, + { type: TabStopType.CENTER, position: TabStopPosition.MAX / 2 }, + { type: TabStopType.RIGHT, position: TabStopPosition.MAX * 3 / 4 } + ], + children: [new TextRun("Left\tCenter\tRight")] +}) +``` + +## Constants & Quick Reference +- **Underlines:** `SINGLE`, `DOUBLE`, `WAVY`, `DASH` +- **Borders:** `SINGLE`, `DOUBLE`, `DASHED`, `DOTTED` +- **Numbering:** `DECIMAL` (1,2,3), `UPPER_ROMAN` (I,II,III), `LOWER_LETTER` (a,b,c) +- **Tabs:** `LEFT`, `CENTER`, `RIGHT`, `DECIMAL` +- **Symbols:** `"2022"` (•), `"00A9"` (©), `"00AE"` (®), `"2122"` (™), `"00B0"` (°), `"F070"` (✓), `"F0FC"` (✗) + +## Cross-Platform 路径处理(Windows / macOS / Linux) + +**根本原因**: Windows 用 `\` 作路径分隔符,macOS/Linux 用 `/`。在 JS 字符串中 `\` 是转义符,直接写 `"C:\Users\file"` 会被解析为 `"C:Usersile"`。 + +### 必须遵守的规则 + +```javascript +const path = require('path'); +const fs = require('fs'); + +// ❌ 硬编码斜杠 — Windows 上可能失败 +const img = fs.readFileSync("images/logo.png"); +const out = "output/report.docx"; + +// ✅ 始终用 path.join() 拼接路径 +const img = fs.readFileSync(path.join("images", "logo.png")); +const out = path.join("output", "report.docx"); + +// ❌ 模板字符串拼路径 +const file = `${dir}/report.docx`; + +// ✅ path.join 拼接 +const file = path.join(dir, "report.docx"); + +// ❌ __dirname + 硬编码斜杠 +const tpl = __dirname + "/templates/header.xml"; + +// ✅ path.join(__dirname, ...) +const tpl = path.join(__dirname, "templates", "header.xml"); +``` + +### 输出文件名注意事项 + +```javascript +// ✅ 写文件前确保目录存在 +const outDir = path.join("output"); +if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true }); +Packer.toBuffer(doc).then(buf => fs.writeFileSync(path.join(outDir, "report.docx"), buf)); +``` + +### Python 脚本同样适用 + +```python +import os + +# ❌ 硬编码斜杠 +doc_path = "word/document.xml" + +# ✅ os.path.join +doc_path = os.path.join("word", "document.xml") + +# ✅ pathlib (Python 3.4+) 更优雅 +from pathlib import Path +doc_path = Path("word") / "document.xml" +``` + +### Shell 命令中的路径 + +```bash +# ✅ 正斜杠在所有平台的 shell 中都能工作(包括 Windows PowerShell/cmd) +python ooxml/scripts/unpack.py input.docx output_dir + +# ⚠️ 但如果路径来自变量且含空格,务必加引号 +python "ooxml/scripts/unpack.py" "$INPUT_FILE" "$OUTPUT_DIR" +``` + +### 快速检查清单 + +| 检查项 | 说明 | +|--------|------| +| 不出现 `"/"` 拼路径 | 用 `path.join()` / `os.path.join()` | +| 不出现 `"\\"` 拼路径 | 同上 | +| 不出现 `` `${x}/y` `` 拼路径 | 用 `path.join(x, "y")` | +| `fs.mkdirSync` 带 `recursive` | 确保输出目录存在 | +| 文件名不含 `: * ? " < > \|` | Windows 保留字符,会导致写入失败 | +| 路径含空格时加引号 | shell 命令中 `"$PATH"` | + +## Critical Issues & Common Mistakes +- **CRITICAL: PageBreak must ALWAYS be inside a Paragraph** - standalone PageBreak creates invalid XML that Word cannot open +- **ALWAYS use ShadingType.CLEAR for table cell shading** - Never use ShadingType.SOLID (causes black background). +- Measurements in DXA (1440 = 1 inch) | Each table cell needs ≥1 Paragraph | TOC requires HeadingLevel styles only +- **公文字体**: 正文用仿宋 (STFangsong),标题用黑体 (Heiti SC),表格用小四仿宋,代码用 Courier New +- **公文默认字号**: 正文 14pt (size: 28),h1 16pt (size: 32),h2 15pt (size: 30),h3+ 14pt (size: 28),表格 12pt (size: 24) +- **公文行距**: 在 default paragraph 中设置 `spacing: { line: 360 }` (1.5 倍行距) +- **公文首行缩进**: 正文段落添加 `indent: { firstLine: 560 }`(14pt × 20 × 2) +- **公文纸张**: A4 尺寸 `size: { width: 11906, height: 16838 }` +- **公文链接**: 黑色下划线,覆盖 Hyperlink 字符样式为 `color: "000000"` +- **公文表格**: 黑色全线框 `color: "000000"`,表头灰底 `fill: "D9D9D9"` +- **ALWAYS use columnWidths array for tables** + individual cell widths for compatibility +- **NEVER use unicode symbols for bullets** - always use proper numbering configuration with `LevelFormat.BULLET` constant (NOT the string "bullet") +- **NEVER use \n for line breaks anywhere** - always use separate Paragraph elements for each line +- **ALWAYS use TextRun objects within Paragraph children** - never use text property directly on Paragraph +- **CRITICAL for images**: ImageRun REQUIRES `type` parameter - always specify "png", "jpg", "jpeg", "gif", "bmp", or "svg" +- **CRITICAL for bullets**: Must use `LevelFormat.BULLET` constant, not string "bullet", and include `text: "•"` for the bullet character +- **CRITICAL for numbering**: Each numbering reference creates an INDEPENDENT list. Same reference = continues numbering (1,2,3 then 4,5,6). Different reference = restarts at 1 (1,2,3 then 1,2,3). Use unique reference names for each separate numbered section! +- **CRITICAL for TOC**: When using TableOfContents, headings must use HeadingLevel ONLY - do NOT add custom styles to heading paragraphs or TOC will break +- **Tables**: Set `columnWidths` array + individual cell widths, apply borders to cells not table +- **Set table margins at TABLE level** for consistent cell padding (avoids repetition per cell) +- **跨平台路径**: 始终用 `path.join()` 拼接路径,不硬编码 `/` 或 `\\`。写文件前用 `fs.mkdirSync(dir, { recursive: true })` 确保目录存在 \ No newline at end of file diff --git a/docx/ooxml.md b/docx/ooxml.md new file mode 100644 index 0000000..7677e7b --- /dev/null +++ b/docx/ooxml.md @@ -0,0 +1,610 @@ +# Office Open XML Technical Reference + +**Important: Read this entire document before starting.** This document covers: +- [Technical Guidelines](#technical-guidelines) - Schema compliance rules and validation requirements +- [Document Content Patterns](#document-content-patterns) - XML patterns for headings, lists, tables, formatting, etc. +- [Document Library (Python)](#document-library-python) - Recommended approach for OOXML manipulation with automatic infrastructure setup +- [Tracked Changes (Redlining)](#tracked-changes-redlining) - XML patterns for implementing tracked changes + +## Technical Guidelines + +### Schema Compliance +- **Element ordering in ``**: ``, ``, ``, ``, `` +- **Whitespace**: Add `xml:space='preserve'` to `` elements with leading/trailing spaces +- **Unicode**: Escape characters in ASCII content: `"` becomes `“` + - **Character encoding reference**: Curly quotes `""` become `“”`, apostrophe `'` becomes `’`, em-dash `—` becomes `—` +- **Tracked changes**: Use `` and `` tags with `w:author="Claude"` outside `` elements + - **Critical**: `` closes with ``, `` closes with `` - never mix + - **RSIDs must be 8-digit hex**: Use values like `00AB1234` (only 0-9, A-F characters) + - **trackRevisions placement**: Add `` after `` in settings.xml +- **Images**: Add to `word/media/`, reference in `document.xml`, set dimensions to prevent overflow + +## Document Content Patterns + +### Basic Structure +```xml + + Text content + +``` + +### Headings and Styles +```xml + + + + + + Document Title + + + + + Section Heading + +``` + +### Text Formatting +```xml + +Bold + +Italic + +Underlined + +Highlighted +``` + +### Lists +```xml + + + + + + + + First item + + + + + + + + + + New list item 1 + + + + + + + + + + + Bullet item + +``` + +### Tables +```xml + + + + + + + + + + + + Cell 1 + + + + Cell 2 + + + +``` + +### Layout +```xml + + + + + + + + + + + + New Section Title + + + + + + + + + + Centered text + + + + + + + + Monospace text + + + + + + + This text is Courier New + + and this text uses default font + +``` + +## File Updates + +When adding content, update these files: + +**`word/_rels/document.xml.rels`:** +```xml + + +``` + +**`[Content_Types].xml`:** +```xml + + +``` + +### Images +**CRITICAL**: Calculate dimensions to prevent page overflow and maintain aspect ratio. + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +### Links (Hyperlinks) + +**IMPORTANT**: All hyperlinks (both internal and external) require the Hyperlink style to be defined in styles.xml. Without this style, links will look like regular text instead of blue underlined clickable links. + +**External Links:** +```xml + + + + + Link Text + + + + + +``` + +**Internal Links:** + +```xml + + + + + Link Text + + + + + +Target content + +``` + +**Hyperlink Style (required in styles.xml):** +```xml + + + + + + + + + + +``` + +## Document Library (Python) + +Use the Document class from `scripts/document.py` for all tracked changes and comments. It automatically handles infrastructure setup (people.xml, RSIDs, settings.xml, comment files, relationships, content types). Only use direct XML manipulation for complex scenarios not supported by the library. + +**Working with Unicode and Entities:** +- **Searching**: Both entity notation and Unicode characters work - `contains="“Company"` and `contains="\u201cCompany"` find the same text +- **Replacing**: Use either entities (`“`) or Unicode (`\u201c`) - both work and will be converted appropriately based on the file's encoding (ascii → entities, utf-8 → Unicode) + +### Initialization + +**Find the docx skill root** (directory containing `scripts/` and `ooxml/`): +```bash +# Search for document.py to locate the skill root +# Note: /mnt/skills is used here as an example; check your context for the actual location +find /mnt/skills -name "document.py" -path "*/docx/scripts/*" 2>/dev/null | head -1 +# Example output: /mnt/skills/docx/scripts/document.py +# Skill root is: /mnt/skills/docx +``` + +**Run your script with PYTHONPATH** set to the docx skill root: +```bash +PYTHONPATH=/mnt/skills/docx python your_script.py +``` + +**In your script**, import from the skill root: +```python +from scripts.document import Document, DocxXMLEditor + +# Basic initialization (automatically creates temp copy and sets up infrastructure) +doc = Document('unpacked') + +# Customize author and initials +doc = Document('unpacked', author="John Doe", initials="JD") + +# Enable track revisions mode +doc = Document('unpacked', track_revisions=True) + +# Specify custom RSID (auto-generated if not provided) +doc = Document('unpacked', rsid="07DC5ECB") +``` + +### Creating Tracked Changes + +**CRITICAL**: Only mark text that actually changes. Keep ALL unchanged text outside ``/`` tags. Marking unchanged text makes edits unprofessional and harder to review. + +**Attribute Handling**: The Document class auto-injects attributes (w:id, w:date, w:rsidR, w:rsidDel, w16du:dateUtc, xml:space) into new elements. When preserving unchanged text from the original document, copy the original `` element with its existing attributes to maintain document integrity. + +**Method Selection Guide**: +- **Adding your own changes to regular text**: Use `replace_node()` with ``/`` tags, or `suggest_deletion()` for removing entire `` or `` elements +- **Partially modifying another author's tracked change**: Use `replace_node()` to nest your changes inside their ``/`` +- **Completely rejecting another author's insertion**: Use `revert_insertion()` on the `` element (NOT `suggest_deletion()`) +- **Completely rejecting another author's deletion**: Use `revert_deletion()` on the `` element to restore deleted content using tracked changes + +```python +# Minimal edit - change one word: "The report is monthly" → "The report is quarterly" +# Original: The report is monthly +node = doc["word/document.xml"].get_node(tag="w:r", contains="The report is monthly") +rpr = tags[0].toxml() if (tags := node.getElementsByTagName("w:rPr")) else "" +replacement = f'{rpr}The report is {rpr}monthly{rpr}quarterly' +doc["word/document.xml"].replace_node(node, replacement) + +# Minimal edit - change number: "within 30 days" → "within 45 days" +# Original: within 30 days +node = doc["word/document.xml"].get_node(tag="w:r", contains="within 30 days") +rpr = tags[0].toxml() if (tags := node.getElementsByTagName("w:rPr")) else "" +replacement = f'{rpr}within {rpr}30{rpr}45{rpr} days' +doc["word/document.xml"].replace_node(node, replacement) + +# Complete replacement - preserve formatting even when replacing all text +node = doc["word/document.xml"].get_node(tag="w:r", contains="apple") +rpr = tags[0].toxml() if (tags := node.getElementsByTagName("w:rPr")) else "" +replacement = f'{rpr}apple{rpr}banana orange' +doc["word/document.xml"].replace_node(node, replacement) + +# Insert new content (no attributes needed - auto-injected) +node = doc["word/document.xml"].get_node(tag="w:r", contains="existing text") +doc["word/document.xml"].insert_after(node, 'new text') + +# Partially delete another author's insertion +# Original: quarterly financial report +# Goal: Delete only "financial" to make it "quarterly report" +node = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "5"}) +# IMPORTANT: Preserve w:author="Jane Smith" on the outer to maintain authorship +replacement = ''' + quarterly + financial + report +''' +doc["word/document.xml"].replace_node(node, replacement) + +# Change part of another author's insertion +# Original: in silence, safe and sound +# Goal: Change "safe and sound" to "soft and unbound" +node = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "8"}) +replacement = f''' + in silence, + + + soft and unbound + + + safe and sound +''' +doc["word/document.xml"].replace_node(node, replacement) + +# Delete entire run (use only when deleting all content; use replace_node for partial deletions) +node = doc["word/document.xml"].get_node(tag="w:r", contains="text to delete") +doc["word/document.xml"].suggest_deletion(node) + +# Delete entire paragraph (in-place, handles both regular and numbered list paragraphs) +para = doc["word/document.xml"].get_node(tag="w:p", contains="paragraph to delete") +doc["word/document.xml"].suggest_deletion(para) + +# Add new numbered list item +target_para = doc["word/document.xml"].get_node(tag="w:p", contains="existing list item") +pPr = tags[0].toxml() if (tags := target_para.getElementsByTagName("w:pPr")) else "" +new_item = f'{pPr}New item' +tracked_para = DocxXMLEditor.suggest_paragraph(new_item) +doc["word/document.xml"].insert_after(target_para, tracked_para) +# Optional: add spacing paragraph before content for better visual separation +# spacing = DocxXMLEditor.suggest_paragraph('') +# doc["word/document.xml"].insert_after(target_para, spacing + tracked_para) +``` + +### Adding Comments + +```python +# Add comment spanning two existing tracked changes +# Note: w:id is auto-generated. Only search by w:id if you know it from XML inspection +start_node = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "1"}) +end_node = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "2"}) +doc.add_comment(start=start_node, end=end_node, text="Explanation of this change") + +# Add comment on a paragraph +para = doc["word/document.xml"].get_node(tag="w:p", contains="paragraph text") +doc.add_comment(start=para, end=para, text="Comment on this paragraph") + +# Add comment on newly created tracked change +# First create the tracked change +node = doc["word/document.xml"].get_node(tag="w:r", contains="old") +new_nodes = doc["word/document.xml"].replace_node( + node, + 'oldnew' +) +# Then add comment on the newly created elements +# new_nodes[0] is the , new_nodes[1] is the +doc.add_comment(start=new_nodes[0], end=new_nodes[1], text="Changed old to new per requirements") + +# Reply to existing comment +doc.reply_to_comment(parent_comment_id=0, text="I agree with this change") +``` + +### Rejecting Tracked Changes + +**IMPORTANT**: Use `revert_insertion()` to reject insertions and `revert_deletion()` to restore deletions using tracked changes. Use `suggest_deletion()` only for regular unmarked content. + +```python +# Reject insertion (wraps it in deletion) +# Use this when another author inserted text that you want to delete +ins = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "5"}) +nodes = doc["word/document.xml"].revert_insertion(ins) # Returns [ins] + +# Reject deletion (creates insertion to restore deleted content) +# Use this when another author deleted text that you want to restore +del_elem = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "3"}) +nodes = doc["word/document.xml"].revert_deletion(del_elem) # Returns [del_elem, new_ins] + +# Reject all insertions in a paragraph +para = doc["word/document.xml"].get_node(tag="w:p", contains="paragraph text") +nodes = doc["word/document.xml"].revert_insertion(para) # Returns [para] + +# Reject all deletions in a paragraph +para = doc["word/document.xml"].get_node(tag="w:p", contains="paragraph text") +nodes = doc["word/document.xml"].revert_deletion(para) # Returns [para] +``` + +### Inserting Images + +**CRITICAL**: The Document class works with a temporary copy at `doc.unpacked_path`. Always copy images to this temp directory, not the original unpacked folder. + +```python +from PIL import Image +import shutil, os + +# Initialize document first +doc = Document('unpacked') + +# Copy image and calculate full-width dimensions with aspect ratio +media_dir = os.path.join(doc.unpacked_path, 'word/media') +os.makedirs(media_dir, exist_ok=True) +shutil.copy('image.png', os.path.join(media_dir, 'image1.png')) +img = Image.open(os.path.join(media_dir, 'image1.png')) +width_emus = int(6.5 * 914400) # 6.5" usable width, 914400 EMUs/inch +height_emus = int(width_emus * img.size[1] / img.size[0]) + +# Add relationship and content type +rels_editor = doc['word/_rels/document.xml.rels'] +next_rid = rels_editor.get_next_rid() +rels_editor.append_to(rels_editor.dom.documentElement, + f'') +doc['[Content_Types].xml'].append_to(doc['[Content_Types].xml'].dom.documentElement, + '') + +# Insert image +node = doc["word/document.xml"].get_node(tag="w:p", line_number=100) +doc["word/document.xml"].insert_after(node, f''' + + + + + + + + + + + + + + + + + +''') +``` + +### Getting Nodes + +```python +# By text content +node = doc["word/document.xml"].get_node(tag="w:p", contains="specific text") + +# By line range +para = doc["word/document.xml"].get_node(tag="w:p", line_number=range(100, 150)) + +# By attributes +node = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "1"}) + +# By exact line number (must be line number where tag opens) +para = doc["word/document.xml"].get_node(tag="w:p", line_number=42) + +# Combine filters +node = doc["word/document.xml"].get_node(tag="w:r", line_number=range(40, 60), contains="text") + +# Disambiguate when text appears multiple times - add line_number range +node = doc["word/document.xml"].get_node(tag="w:r", contains="Section", line_number=range(2400, 2500)) +``` + +### Saving + +```python +# Save with automatic validation (copies back to original directory) +doc.save() # Validates by default, raises error if validation fails + +# Save to different location +doc.save('modified-unpacked') + +# Skip validation (debugging only - needing this in production indicates XML issues) +doc.save(validate=False) +``` + +### Direct DOM Manipulation + +For complex scenarios not covered by the library: + +```python +# Access any XML file +editor = doc["word/document.xml"] +editor = doc["word/comments.xml"] + +# Direct DOM access (defusedxml.minidom.Document) +node = doc["word/document.xml"].get_node(tag="w:p", line_number=5) +parent = node.parentNode +parent.removeChild(node) +parent.appendChild(node) # Move to end + +# General document manipulation (without tracked changes) +old_node = doc["word/document.xml"].get_node(tag="w:p", contains="original text") +doc["word/document.xml"].replace_node(old_node, "replacement text") + +# Multiple insertions - use return value to maintain order +node = doc["word/document.xml"].get_node(tag="w:r", line_number=100) +nodes = doc["word/document.xml"].insert_after(node, "A") +nodes = doc["word/document.xml"].insert_after(nodes[-1], "B") +nodes = doc["word/document.xml"].insert_after(nodes[-1], "C") +# Results in: original_node, A, B, C +``` + +## Tracked Changes (Redlining) + +**Use the Document class above for all tracked changes.** The patterns below are for reference when constructing replacement XML strings. + +### Validation Rules +The validator checks that the document text matches the original after reverting Claude's changes. This means: +- **NEVER modify text inside another author's `` or `` tags** +- **ALWAYS use nested deletions** to remove another author's insertions +- **Every edit must be properly tracked** with `` or `` tags + +### Tracked Change Patterns + +**CRITICAL RULES**: +1. Never modify the content inside another author's tracked changes. Always use nested deletions. +2. **XML Structure**: Always place `` and `` at paragraph level containing complete `` elements. Never nest inside `` elements - this creates invalid XML that breaks document processing. + +**Text Insertion:** +```xml + + + inserted text + + +``` + +**Text Deletion:** +```xml + + + deleted text + + +``` + +**Deleting Another Author's Insertion (MUST use nested structure):** +```xml + + + + monthly + + + + weekly + +``` + +**Restoring Another Author's Deletion:** +```xml + + + within 30 days + + + within 30 days + +``` \ No newline at end of file diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd new file mode 100644 index 0000000..6454ef9 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd @@ -0,0 +1,1499 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd new file mode 100644 index 0000000..afa4f46 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd new file mode 100644 index 0000000..64e66b8 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd @@ -0,0 +1,1085 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd new file mode 100644 index 0000000..687eea8 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd @@ -0,0 +1,11 @@ + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd new file mode 100644 index 0000000..6ac81b0 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd @@ -0,0 +1,3081 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd new file mode 100644 index 0000000..1dbf051 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd new file mode 100644 index 0000000..f1af17d --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd new file mode 100644 index 0000000..0a185ab --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd new file mode 100644 index 0000000..14ef488 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd @@ -0,0 +1,1676 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd new file mode 100644 index 0000000..c20f3bf --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd new file mode 100644 index 0000000..ac60252 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd new file mode 100644 index 0000000..424b8ba --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd new file mode 100644 index 0000000..2bddce2 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd new file mode 100644 index 0000000..8a8c18b --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd new file mode 100644 index 0000000..5c42706 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd new file mode 100644 index 0000000..853c341 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd new file mode 100644 index 0000000..da835ee --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd @@ -0,0 +1,195 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd new file mode 100644 index 0000000..87ad265 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd @@ -0,0 +1,582 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd new file mode 100644 index 0000000..9e86f1b --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd new file mode 100644 index 0000000..d0be42e --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd @@ -0,0 +1,4439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd new file mode 100644 index 0000000..8821dd1 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd @@ -0,0 +1,570 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd new file mode 100644 index 0000000..ca2575c --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd @@ -0,0 +1,509 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd new file mode 100644 index 0000000..dd079e6 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd new file mode 100644 index 0000000..3dd6cf6 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd new file mode 100644 index 0000000..f1041e3 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd new file mode 100644 index 0000000..9c5b7a6 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd @@ -0,0 +1,3646 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd b/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd new file mode 100644 index 0000000..0f13678 --- /dev/null +++ b/docx/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd @@ -0,0 +1,116 @@ + + + + + + See http://www.w3.org/XML/1998/namespace.html and + http://www.w3.org/TR/REC-xml for information about this namespace. + + This schema document describes the XML namespace, in a form + suitable for import by other schema documents. + + Note that local names in this namespace are intended to be defined + only by the World Wide Web Consortium or its subgroups. The + following names are currently defined in this namespace and should + not be used with conflicting semantics by any Working Group, + specification, or document instance: + + base (as an attribute name): denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification. + + lang (as an attribute name): denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification. + + space (as an attribute name): denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification. + + Father (in any context at all): denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: + + In appreciation for his vision, leadership and dedication + the W3C XML Plenary on this 10th day of February, 2000 + reserves for Jon Bosak in perpetuity the XML name + xml:Father + + + + + This schema defines attributes and an attribute group + suitable for use by + schemas wishing to allow xml:base, xml:lang or xml:space attributes + on elements they define. + + To enable this, such a schema must import this schema + for the XML namespace, e.g. as follows: + <schema . . .> + . . . + <import namespace="http://www.w3.org/XML/1998/namespace" + schemaLocation="http://www.w3.org/2001/03/xml.xsd"/> + + Subsequently, qualified reference to any of the attributes + or the group defined below will have the desired effect, e.g. + + <type . . .> + . . . + <attributeGroup ref="xml:specialAttrs"/> + + will define a type which will schema-validate an instance + element with any of those attributes + + + + In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + http://www.w3.org/2001/03/xml.xsd. + At the date of issue it can also be found at + http://www.w3.org/2001/xml.xsd. + The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML Schema + itself. In other words, if the XML Schema namespace changes, the version + of this document at + http://www.w3.org/2001/xml.xsd will change + accordingly; the version at + http://www.w3.org/2001/03/xml.xsd will not change. + + + + + + In due course, we should install the relevant ISO 2- and 3-letter + codes as the enumerated possible values . . . + + + + + + + + + + + + + + + See http://www.w3.org/TR/xmlbase/ for + information about this attribute. + + + + + + + + + + diff --git a/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd b/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd new file mode 100644 index 0000000..a6de9d2 --- /dev/null +++ b/docx/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd b/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd new file mode 100644 index 0000000..10e978b --- /dev/null +++ b/docx/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd b/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd new file mode 100644 index 0000000..4248bf7 --- /dev/null +++ b/docx/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd b/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd new file mode 100644 index 0000000..5649746 --- /dev/null +++ b/docx/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/mce/mc.xsd b/docx/ooxml/schemas/mce/mc.xsd new file mode 100644 index 0000000..ef72545 --- /dev/null +++ b/docx/ooxml/schemas/mce/mc.xsd @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/microsoft/wml-2010.xsd b/docx/ooxml/schemas/microsoft/wml-2010.xsd new file mode 100644 index 0000000..f65f777 --- /dev/null +++ b/docx/ooxml/schemas/microsoft/wml-2010.xsd @@ -0,0 +1,560 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/microsoft/wml-2012.xsd b/docx/ooxml/schemas/microsoft/wml-2012.xsd new file mode 100644 index 0000000..6b00755 --- /dev/null +++ b/docx/ooxml/schemas/microsoft/wml-2012.xsd @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/microsoft/wml-2018.xsd b/docx/ooxml/schemas/microsoft/wml-2018.xsd new file mode 100644 index 0000000..f321d33 --- /dev/null +++ b/docx/ooxml/schemas/microsoft/wml-2018.xsd @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd b/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd new file mode 100644 index 0000000..364c6a9 --- /dev/null +++ b/docx/ooxml/schemas/microsoft/wml-cex-2018.xsd @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd b/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd new file mode 100644 index 0000000..fed9d15 --- /dev/null +++ b/docx/ooxml/schemas/microsoft/wml-cid-2016.xsd @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd b/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd new file mode 100644 index 0000000..680cf15 --- /dev/null +++ b/docx/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd @@ -0,0 +1,4 @@ + + + + diff --git a/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd b/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd new file mode 100644 index 0000000..89ada90 --- /dev/null +++ b/docx/ooxml/schemas/microsoft/wml-symex-2015.xsd @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/docx/ooxml/scripts/pack.py b/docx/ooxml/scripts/pack.py new file mode 100755 index 0000000..68bc088 --- /dev/null +++ b/docx/ooxml/scripts/pack.py @@ -0,0 +1,159 @@ +#!/usr/bin/env python3 +""" +Tool to pack a directory into a .docx, .pptx, or .xlsx file with XML formatting undone. + +Example usage: + python pack.py [--force] +""" + +import argparse +import shutil +import subprocess +import sys +import tempfile +import defusedxml.minidom +import zipfile +from pathlib import Path + + +def main(): + parser = argparse.ArgumentParser(description="Pack a directory into an Office file") + parser.add_argument("input_directory", help="Unpacked Office document directory") + parser.add_argument("output_file", help="Output Office file (.docx/.pptx/.xlsx)") + parser.add_argument("--force", action="store_true", help="Skip validation") + args = parser.parse_args() + + try: + success = pack_document( + args.input_directory, args.output_file, validate=not args.force + ) + + # Show warning if validation was skipped + if args.force: + print("Warning: Skipped validation, file may be corrupt", file=sys.stderr) + # Exit with error if validation failed + elif not success: + print("Contents would produce a corrupt file.", file=sys.stderr) + print("Please validate XML before repacking.", file=sys.stderr) + print("Use --force to skip validation and pack anyway.", file=sys.stderr) + sys.exit(1) + + except ValueError as e: + sys.exit(f"Error: {e}") + + +def pack_document(input_dir, output_file, validate=False): + """Pack a directory into an Office file (.docx/.pptx/.xlsx). + + Args: + input_dir: Path to unpacked Office document directory + output_file: Path to output Office file + validate: If True, validates with soffice (default: False) + + Returns: + bool: True if successful, False if validation failed + """ + input_dir = Path(input_dir) + output_file = Path(output_file) + + if not input_dir.is_dir(): + raise ValueError(f"{input_dir} is not a directory") + if output_file.suffix.lower() not in {".docx", ".pptx", ".xlsx"}: + raise ValueError(f"{output_file} must be a .docx, .pptx, or .xlsx file") + + # Work in temporary directory to avoid modifying original + with tempfile.TemporaryDirectory() as temp_dir: + temp_content_dir = Path(temp_dir) / "content" + shutil.copytree(input_dir, temp_content_dir) + + # Process XML files to remove pretty-printing whitespace + for pattern in ["*.xml", "*.rels"]: + for xml_file in temp_content_dir.rglob(pattern): + condense_xml(xml_file) + + # Create final Office file as zip archive + output_file.parent.mkdir(parents=True, exist_ok=True) + with zipfile.ZipFile(output_file, "w", zipfile.ZIP_DEFLATED) as zf: + for f in temp_content_dir.rglob("*"): + if f.is_file(): + zf.write(f, f.relative_to(temp_content_dir)) + + # Validate if requested + if validate: + if not validate_document(output_file): + output_file.unlink() # Delete the corrupt file + return False + + return True + + +def validate_document(doc_path): + """Validate document by converting to HTML with soffice.""" + # Determine the correct filter based on file extension + match doc_path.suffix.lower(): + case ".docx": + filter_name = "html:HTML" + case ".pptx": + filter_name = "html:impress_html_Export" + case ".xlsx": + filter_name = "html:HTML (StarCalc)" + + with tempfile.TemporaryDirectory() as temp_dir: + try: + result = subprocess.run( + [ + "soffice", + "--headless", + "--convert-to", + filter_name, + "--outdir", + temp_dir, + str(doc_path), + ], + capture_output=True, + timeout=10, + text=True, + ) + if not (Path(temp_dir) / f"{doc_path.stem}.html").exists(): + error_msg = result.stderr.strip() or "Document validation failed" + print(f"Validation error: {error_msg}", file=sys.stderr) + return False + return True + except FileNotFoundError: + print("Warning: soffice not found. Skipping validation.", file=sys.stderr) + return True + except subprocess.TimeoutExpired: + print("Validation error: Timeout during conversion", file=sys.stderr) + return False + except Exception as e: + print(f"Validation error: {e}", file=sys.stderr) + return False + + +def condense_xml(xml_file): + """Strip unnecessary whitespace and remove comments.""" + with open(xml_file, "r", encoding="utf-8") as f: + dom = defusedxml.minidom.parse(f) + + # Process each element to remove whitespace and comments + for element in dom.getElementsByTagName("*"): + # Skip w:t elements and their processing + if element.tagName.endswith(":t"): + continue + + # Remove whitespace-only text nodes and comment nodes + for child in list(element.childNodes): + if ( + child.nodeType == child.TEXT_NODE + and child.nodeValue + and child.nodeValue.strip() == "" + ) or child.nodeType == child.COMMENT_NODE: + element.removeChild(child) + + # Write back the condensed XML + with open(xml_file, "wb") as f: + f.write(dom.toxml(encoding="UTF-8")) + + +if __name__ == "__main__": + main() diff --git a/docx/ooxml/scripts/unpack.py b/docx/ooxml/scripts/unpack.py new file mode 100755 index 0000000..4938798 --- /dev/null +++ b/docx/ooxml/scripts/unpack.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +"""Unpack and format XML contents of Office files (.docx, .pptx, .xlsx)""" + +import random +import sys +import defusedxml.minidom +import zipfile +from pathlib import Path + +# Get command line arguments +assert len(sys.argv) == 3, "Usage: python unpack.py " +input_file, output_dir = sys.argv[1], sys.argv[2] + +# Extract and format +output_path = Path(output_dir) +output_path.mkdir(parents=True, exist_ok=True) +zipfile.ZipFile(input_file).extractall(output_path) + +# Pretty print all XML files +xml_files = list(output_path.rglob("*.xml")) + list(output_path.rglob("*.rels")) +for xml_file in xml_files: + content = xml_file.read_text(encoding="utf-8") + dom = defusedxml.minidom.parseString(content) + xml_file.write_bytes(dom.toprettyxml(indent=" ", encoding="ascii")) + +# For .docx files, suggest an RSID for tracked changes +if input_file.endswith(".docx"): + suggested_rsid = "".join(random.choices("0123456789ABCDEF", k=8)) + print(f"Suggested RSID for edit session: {suggested_rsid}") diff --git a/docx/ooxml/scripts/validate.py b/docx/ooxml/scripts/validate.py new file mode 100755 index 0000000..508c589 --- /dev/null +++ b/docx/ooxml/scripts/validate.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +""" +Command line tool to validate Office document XML files against XSD schemas and tracked changes. + +Usage: + python validate.py --original +""" + +import argparse +import sys +from pathlib import Path + +from validation import DOCXSchemaValidator, PPTXSchemaValidator, RedliningValidator + + +def main(): + parser = argparse.ArgumentParser(description="Validate Office document XML files") + parser.add_argument( + "unpacked_dir", + help="Path to unpacked Office document directory", + ) + parser.add_argument( + "--original", + required=True, + help="Path to original file (.docx/.pptx/.xlsx)", + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="Enable verbose output", + ) + args = parser.parse_args() + + # Validate paths + unpacked_dir = Path(args.unpacked_dir) + original_file = Path(args.original) + file_extension = original_file.suffix.lower() + assert unpacked_dir.is_dir(), f"Error: {unpacked_dir} is not a directory" + assert original_file.is_file(), f"Error: {original_file} is not a file" + assert file_extension in [".docx", ".pptx", ".xlsx"], ( + f"Error: {original_file} must be a .docx, .pptx, or .xlsx file" + ) + + # Run validations + match file_extension: + case ".docx": + validators = [DOCXSchemaValidator, RedliningValidator] + case ".pptx": + validators = [PPTXSchemaValidator] + case _: + print(f"Error: Validation not supported for file type {file_extension}") + sys.exit(1) + + # Run validators + success = True + for V in validators: + validator = V(unpacked_dir, original_file, verbose=args.verbose) + if not validator.validate(): + success = False + + if success: + print("All validations PASSED!") + + sys.exit(0 if success else 1) + + +if __name__ == "__main__": + main() diff --git a/docx/ooxml/scripts/validation/__init__.py b/docx/ooxml/scripts/validation/__init__.py new file mode 100644 index 0000000..db092ec --- /dev/null +++ b/docx/ooxml/scripts/validation/__init__.py @@ -0,0 +1,15 @@ +""" +Validation modules for Word document processing. +""" + +from .base import BaseSchemaValidator +from .docx import DOCXSchemaValidator +from .pptx import PPTXSchemaValidator +from .redlining import RedliningValidator + +__all__ = [ + "BaseSchemaValidator", + "DOCXSchemaValidator", + "PPTXSchemaValidator", + "RedliningValidator", +] diff --git a/docx/ooxml/scripts/validation/base.py b/docx/ooxml/scripts/validation/base.py new file mode 100644 index 0000000..0681b19 --- /dev/null +++ b/docx/ooxml/scripts/validation/base.py @@ -0,0 +1,951 @@ +""" +Base validator with common validation logic for document files. +""" + +import re +from pathlib import Path + +import lxml.etree + + +class BaseSchemaValidator: + """Base validator with common validation logic for document files.""" + + # Elements whose 'id' attributes must be unique within their file + # Format: element_name -> (attribute_name, scope) + # scope can be 'file' (unique within file) or 'global' (unique across all files) + UNIQUE_ID_REQUIREMENTS = { + # Word elements + "comment": ("id", "file"), # Comment IDs in comments.xml + "commentrangestart": ("id", "file"), # Must match comment IDs + "commentrangeend": ("id", "file"), # Must match comment IDs + "bookmarkstart": ("id", "file"), # Bookmark start IDs + "bookmarkend": ("id", "file"), # Bookmark end IDs + # Note: ins and del (track changes) can share IDs when part of same revision + # PowerPoint elements + "sldid": ("id", "file"), # Slide IDs in presentation.xml + "sldmasterid": ("id", "global"), # Slide master IDs must be globally unique + "sldlayoutid": ("id", "global"), # Slide layout IDs must be globally unique + "cm": ("authorid", "file"), # Comment author IDs + # Excel elements + "sheet": ("sheetid", "file"), # Sheet IDs in workbook.xml + "definedname": ("id", "file"), # Named range IDs + # Drawing/Shape elements (all formats) + "cxnsp": ("id", "file"), # Connection shape IDs + "sp": ("id", "file"), # Shape IDs + "pic": ("id", "file"), # Picture IDs + "grpsp": ("id", "file"), # Group shape IDs + } + + # Mapping of element names to expected relationship types + # Subclasses should override this with format-specific mappings + ELEMENT_RELATIONSHIP_TYPES = {} + + # Unified schema mappings for all Office document types + SCHEMA_MAPPINGS = { + # Document type specific schemas + "word": "ISO-IEC29500-4_2016/wml.xsd", # Word documents + "ppt": "ISO-IEC29500-4_2016/pml.xsd", # PowerPoint presentations + "xl": "ISO-IEC29500-4_2016/sml.xsd", # Excel spreadsheets + # Common file types + "[Content_Types].xml": "ecma/fouth-edition/opc-contentTypes.xsd", + "app.xml": "ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd", + "core.xml": "ecma/fouth-edition/opc-coreProperties.xsd", + "custom.xml": "ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd", + ".rels": "ecma/fouth-edition/opc-relationships.xsd", + # Word-specific files + "people.xml": "microsoft/wml-2012.xsd", + "commentsIds.xml": "microsoft/wml-cid-2016.xsd", + "commentsExtensible.xml": "microsoft/wml-cex-2018.xsd", + "commentsExtended.xml": "microsoft/wml-2012.xsd", + # Chart files (common across document types) + "chart": "ISO-IEC29500-4_2016/dml-chart.xsd", + # Theme files (common across document types) + "theme": "ISO-IEC29500-4_2016/dml-main.xsd", + # Drawing and media files + "drawing": "ISO-IEC29500-4_2016/dml-main.xsd", + } + + # Unified namespace constants + MC_NAMESPACE = "http://schemas.openxmlformats.org/markup-compatibility/2006" + XML_NAMESPACE = "http://www.w3.org/XML/1998/namespace" + + # Common OOXML namespaces used across validators + PACKAGE_RELATIONSHIPS_NAMESPACE = ( + "http://schemas.openxmlformats.org/package/2006/relationships" + ) + OFFICE_RELATIONSHIPS_NAMESPACE = ( + "http://schemas.openxmlformats.org/officeDocument/2006/relationships" + ) + CONTENT_TYPES_NAMESPACE = ( + "http://schemas.openxmlformats.org/package/2006/content-types" + ) + + # Folders where we should clean ignorable namespaces + MAIN_CONTENT_FOLDERS = {"word", "ppt", "xl"} + + # All allowed OOXML namespaces (superset of all document types) + OOXML_NAMESPACES = { + "http://schemas.openxmlformats.org/officeDocument/2006/math", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + "http://schemas.openxmlformats.org/schemaLibrary/2006/main", + "http://schemas.openxmlformats.org/drawingml/2006/main", + "http://schemas.openxmlformats.org/drawingml/2006/chart", + "http://schemas.openxmlformats.org/drawingml/2006/chartDrawing", + "http://schemas.openxmlformats.org/drawingml/2006/diagram", + "http://schemas.openxmlformats.org/drawingml/2006/picture", + "http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing", + "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", + "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + "http://schemas.openxmlformats.org/presentationml/2006/main", + "http://schemas.openxmlformats.org/spreadsheetml/2006/main", + "http://schemas.openxmlformats.org/officeDocument/2006/sharedTypes", + "http://www.w3.org/XML/1998/namespace", + } + + def __init__(self, unpacked_dir, original_file, verbose=False): + self.unpacked_dir = Path(unpacked_dir).resolve() + self.original_file = Path(original_file) + self.verbose = verbose + + # Set schemas directory + self.schemas_dir = Path(__file__).parent.parent.parent / "schemas" + + # Get all XML and .rels files + patterns = ["*.xml", "*.rels"] + self.xml_files = [ + f for pattern in patterns for f in self.unpacked_dir.rglob(pattern) + ] + + if not self.xml_files: + print(f"Warning: No XML files found in {self.unpacked_dir}") + + def validate(self): + """Run all validation checks and return True if all pass.""" + raise NotImplementedError("Subclasses must implement the validate method") + + def validate_xml(self): + """Validate that all XML files are well-formed.""" + errors = [] + + for xml_file in self.xml_files: + try: + # Try to parse the XML file + lxml.etree.parse(str(xml_file)) + except lxml.etree.XMLSyntaxError as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {e.lineno}: {e.msg}" + ) + except Exception as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Unexpected error: {str(e)}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} XML violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All XML files are well-formed") + return True + + def validate_namespaces(self): + """Validate that namespace prefixes in Ignorable attributes are declared.""" + errors = [] + + for xml_file in self.xml_files: + try: + root = lxml.etree.parse(str(xml_file)).getroot() + declared = set(root.nsmap.keys()) - {None} # Exclude default namespace + + for attr_val in [ + v for k, v in root.attrib.items() if k.endswith("Ignorable") + ]: + undeclared = set(attr_val.split()) - declared + errors.extend( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Namespace '{ns}' in Ignorable but not declared" + for ns in undeclared + ) + except lxml.etree.XMLSyntaxError: + continue + + if errors: + print(f"FAILED - {len(errors)} namespace issues:") + for error in errors: + print(error) + return False + if self.verbose: + print("PASSED - All namespace prefixes properly declared") + return True + + def validate_unique_ids(self): + """Validate that specific IDs are unique according to OOXML requirements.""" + errors = [] + global_ids = {} # Track globally unique IDs across all files + + for xml_file in self.xml_files: + try: + root = lxml.etree.parse(str(xml_file)).getroot() + file_ids = {} # Track IDs that must be unique within this file + + # Remove all mc:AlternateContent elements from the tree + mc_elements = root.xpath( + ".//mc:AlternateContent", namespaces={"mc": self.MC_NAMESPACE} + ) + for elem in mc_elements: + elem.getparent().remove(elem) + + # Now check IDs in the cleaned tree + for elem in root.iter(): + # Get the element name without namespace + tag = ( + elem.tag.split("}")[-1].lower() + if "}" in elem.tag + else elem.tag.lower() + ) + + # Check if this element type has ID uniqueness requirements + if tag in self.UNIQUE_ID_REQUIREMENTS: + attr_name, scope = self.UNIQUE_ID_REQUIREMENTS[tag] + + # Look for the specified attribute + id_value = None + for attr, value in elem.attrib.items(): + attr_local = ( + attr.split("}")[-1].lower() + if "}" in attr + else attr.lower() + ) + if attr_local == attr_name: + id_value = value + break + + if id_value is not None: + if scope == "global": + # Check global uniqueness + if id_value in global_ids: + prev_file, prev_line, prev_tag = global_ids[ + id_value + ] + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: Global ID '{id_value}' in <{tag}> " + f"already used in {prev_file} at line {prev_line} in <{prev_tag}>" + ) + else: + global_ids[id_value] = ( + xml_file.relative_to(self.unpacked_dir), + elem.sourceline, + tag, + ) + elif scope == "file": + # Check file-level uniqueness + key = (tag, attr_name) + if key not in file_ids: + file_ids[key] = {} + + if id_value in file_ids[key]: + prev_line = file_ids[key][id_value] + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: Duplicate {attr_name}='{id_value}' in <{tag}> " + f"(first occurrence at line {prev_line})" + ) + else: + file_ids[key][id_value] = elem.sourceline + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} ID uniqueness violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All required IDs are unique") + return True + + def validate_file_references(self): + """ + Validate that all .rels files properly reference files and that all files are referenced. + """ + errors = [] + + # Find all .rels files + rels_files = list(self.unpacked_dir.rglob("*.rels")) + + if not rels_files: + if self.verbose: + print("PASSED - No .rels files found") + return True + + # Get all files in the unpacked directory (excluding reference files) + all_files = [] + for file_path in self.unpacked_dir.rglob("*"): + if ( + file_path.is_file() + and file_path.name != "[Content_Types].xml" + and not file_path.name.endswith(".rels") + ): # This file is not referenced by .rels + all_files.append(file_path.resolve()) + + # Track all files that are referenced by any .rels file + all_referenced_files = set() + + if self.verbose: + print( + f"Found {len(rels_files)} .rels files and {len(all_files)} target files" + ) + + # Check each .rels file + for rels_file in rels_files: + try: + # Parse relationships file + rels_root = lxml.etree.parse(str(rels_file)).getroot() + + # Get the directory where this .rels file is located + rels_dir = rels_file.parent + + # Find all relationships and their targets + referenced_files = set() + broken_refs = [] + + for rel in rels_root.findall( + ".//ns:Relationship", + namespaces={"ns": self.PACKAGE_RELATIONSHIPS_NAMESPACE}, + ): + target = rel.get("Target") + if target and not target.startswith( + ("http", "mailto:") + ): # Skip external URLs + # Resolve the target path relative to the .rels file location + if rels_file.name == ".rels": + # Root .rels file - targets are relative to unpacked_dir + target_path = self.unpacked_dir / target + else: + # Other .rels files - targets are relative to their parent's parent + # e.g., word/_rels/document.xml.rels -> targets relative to word/ + base_dir = rels_dir.parent + target_path = base_dir / target + + # Normalize the path and check if it exists + try: + target_path = target_path.resolve() + if target_path.exists() and target_path.is_file(): + referenced_files.add(target_path) + all_referenced_files.add(target_path) + else: + broken_refs.append((target, rel.sourceline)) + except (OSError, ValueError): + broken_refs.append((target, rel.sourceline)) + + # Report broken references + if broken_refs: + rel_path = rels_file.relative_to(self.unpacked_dir) + for broken_ref, line_num in broken_refs: + errors.append( + f" {rel_path}: Line {line_num}: Broken reference to {broken_ref}" + ) + + except Exception as e: + rel_path = rels_file.relative_to(self.unpacked_dir) + errors.append(f" Error parsing {rel_path}: {e}") + + # Check for unreferenced files (files that exist but are not referenced anywhere) + unreferenced_files = set(all_files) - all_referenced_files + + if unreferenced_files: + for unref_file in sorted(unreferenced_files): + unref_rel_path = unref_file.relative_to(self.unpacked_dir) + errors.append(f" Unreferenced file: {unref_rel_path}") + + if errors: + print(f"FAILED - Found {len(errors)} relationship validation errors:") + for error in errors: + print(error) + print( + "CRITICAL: These errors will cause the document to appear corrupt. " + + "Broken references MUST be fixed, " + + "and unreferenced files MUST be referenced or removed." + ) + return False + else: + if self.verbose: + print( + "PASSED - All references are valid and all files are properly referenced" + ) + return True + + def validate_all_relationship_ids(self): + """ + Validate that all r:id attributes in XML files reference existing IDs + in their corresponding .rels files, and optionally validate relationship types. + """ + import lxml.etree + + errors = [] + + # Process each XML file that might contain r:id references + for xml_file in self.xml_files: + # Skip .rels files themselves + if xml_file.suffix == ".rels": + continue + + # Determine the corresponding .rels file + # For dir/file.xml, it's dir/_rels/file.xml.rels + rels_dir = xml_file.parent / "_rels" + rels_file = rels_dir / f"{xml_file.name}.rels" + + # Skip if there's no corresponding .rels file (that's okay) + if not rels_file.exists(): + continue + + try: + # Parse the .rels file to get valid relationship IDs and their types + rels_root = lxml.etree.parse(str(rels_file)).getroot() + rid_to_type = {} + + for rel in rels_root.findall( + f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship" + ): + rid = rel.get("Id") + rel_type = rel.get("Type", "") + if rid: + # Check for duplicate rIds + if rid in rid_to_type: + rels_rel_path = rels_file.relative_to(self.unpacked_dir) + errors.append( + f" {rels_rel_path}: Line {rel.sourceline}: " + f"Duplicate relationship ID '{rid}' (IDs must be unique)" + ) + # Extract just the type name from the full URL + type_name = ( + rel_type.split("/")[-1] if "/" in rel_type else rel_type + ) + rid_to_type[rid] = type_name + + # Parse the XML file to find all r:id references + xml_root = lxml.etree.parse(str(xml_file)).getroot() + + # Find all elements with r:id attributes + for elem in xml_root.iter(): + # Check for r:id attribute (relationship ID) + rid_attr = elem.get(f"{{{self.OFFICE_RELATIONSHIPS_NAMESPACE}}}id") + if rid_attr: + xml_rel_path = xml_file.relative_to(self.unpacked_dir) + elem_name = ( + elem.tag.split("}")[-1] if "}" in elem.tag else elem.tag + ) + + # Check if the ID exists + if rid_attr not in rid_to_type: + errors.append( + f" {xml_rel_path}: Line {elem.sourceline}: " + f"<{elem_name}> references non-existent relationship '{rid_attr}' " + f"(valid IDs: {', '.join(sorted(rid_to_type.keys())[:5])}{'...' if len(rid_to_type) > 5 else ''})" + ) + # Check if we have type expectations for this element + elif self.ELEMENT_RELATIONSHIP_TYPES: + expected_type = self._get_expected_relationship_type( + elem_name + ) + if expected_type: + actual_type = rid_to_type[rid_attr] + # Check if the actual type matches or contains the expected type + if expected_type not in actual_type.lower(): + errors.append( + f" {xml_rel_path}: Line {elem.sourceline}: " + f"<{elem_name}> references '{rid_attr}' which points to '{actual_type}' " + f"but should point to a '{expected_type}' relationship" + ) + + except Exception as e: + xml_rel_path = xml_file.relative_to(self.unpacked_dir) + errors.append(f" Error processing {xml_rel_path}: {e}") + + if errors: + print(f"FAILED - Found {len(errors)} relationship ID reference errors:") + for error in errors: + print(error) + print("\nThese ID mismatches will cause the document to appear corrupt!") + return False + else: + if self.verbose: + print("PASSED - All relationship ID references are valid") + return True + + def _get_expected_relationship_type(self, element_name): + """ + Get the expected relationship type for an element. + First checks the explicit mapping, then tries pattern detection. + """ + # Normalize element name to lowercase + elem_lower = element_name.lower() + + # Check explicit mapping first + if elem_lower in self.ELEMENT_RELATIONSHIP_TYPES: + return self.ELEMENT_RELATIONSHIP_TYPES[elem_lower] + + # Try pattern detection for common patterns + # Pattern 1: Elements ending in "Id" often expect a relationship of the prefix type + if elem_lower.endswith("id") and len(elem_lower) > 2: + # e.g., "sldId" -> "sld", "sldMasterId" -> "sldMaster" + prefix = elem_lower[:-2] # Remove "id" + # Check if this might be a compound like "sldMasterId" + if prefix.endswith("master"): + return prefix.lower() + elif prefix.endswith("layout"): + return prefix.lower() + else: + # Simple case like "sldId" -> "slide" + # Common transformations + if prefix == "sld": + return "slide" + return prefix.lower() + + # Pattern 2: Elements ending in "Reference" expect a relationship of the prefix type + if elem_lower.endswith("reference") and len(elem_lower) > 9: + prefix = elem_lower[:-9] # Remove "reference" + return prefix.lower() + + return None + + def validate_content_types(self): + """Validate that all content files are properly declared in [Content_Types].xml.""" + errors = [] + + # Find [Content_Types].xml file + content_types_file = self.unpacked_dir / "[Content_Types].xml" + if not content_types_file.exists(): + print("FAILED - [Content_Types].xml file not found") + return False + + try: + # Parse and get all declared parts and extensions + root = lxml.etree.parse(str(content_types_file)).getroot() + declared_parts = set() + declared_extensions = set() + + # Get Override declarations (specific files) + for override in root.findall( + f".//{{{self.CONTENT_TYPES_NAMESPACE}}}Override" + ): + part_name = override.get("PartName") + if part_name is not None: + declared_parts.add(part_name.lstrip("/")) + + # Get Default declarations (by extension) + for default in root.findall( + f".//{{{self.CONTENT_TYPES_NAMESPACE}}}Default" + ): + extension = default.get("Extension") + if extension is not None: + declared_extensions.add(extension.lower()) + + # Root elements that require content type declaration + declarable_roots = { + "sld", + "sldLayout", + "sldMaster", + "presentation", # PowerPoint + "document", # Word + "workbook", + "worksheet", # Excel + "theme", # Common + } + + # Common media file extensions that should be declared + media_extensions = { + "png": "image/png", + "jpg": "image/jpeg", + "jpeg": "image/jpeg", + "gif": "image/gif", + "bmp": "image/bmp", + "tiff": "image/tiff", + "wmf": "image/x-wmf", + "emf": "image/x-emf", + } + + # Get all files in the unpacked directory + all_files = list(self.unpacked_dir.rglob("*")) + all_files = [f for f in all_files if f.is_file()] + + # Check all XML files for Override declarations + for xml_file in self.xml_files: + path_str = str(xml_file.relative_to(self.unpacked_dir)).replace( + "\\", "/" + ) + + # Skip non-content files + if any( + skip in path_str + for skip in [".rels", "[Content_Types]", "docProps/", "_rels/"] + ): + continue + + try: + root_tag = lxml.etree.parse(str(xml_file)).getroot().tag + root_name = root_tag.split("}")[-1] if "}" in root_tag else root_tag + + if root_name in declarable_roots and path_str not in declared_parts: + errors.append( + f" {path_str}: File with <{root_name}> root not declared in [Content_Types].xml" + ) + + except Exception: + continue # Skip unparseable files + + # Check all non-XML files for Default extension declarations + for file_path in all_files: + # Skip XML files and metadata files (already checked above) + if file_path.suffix.lower() in {".xml", ".rels"}: + continue + if file_path.name == "[Content_Types].xml": + continue + if "_rels" in file_path.parts or "docProps" in file_path.parts: + continue + + extension = file_path.suffix.lstrip(".").lower() + if extension and extension not in declared_extensions: + # Check if it's a known media extension that should be declared + if extension in media_extensions: + relative_path = file_path.relative_to(self.unpacked_dir) + errors.append( + f' {relative_path}: File with extension \'{extension}\' not declared in [Content_Types].xml - should add: ' + ) + + except Exception as e: + errors.append(f" Error parsing [Content_Types].xml: {e}") + + if errors: + print(f"FAILED - Found {len(errors)} content type declaration errors:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print( + "PASSED - All content files are properly declared in [Content_Types].xml" + ) + return True + + def validate_file_against_xsd(self, xml_file, verbose=False): + """Validate a single XML file against XSD schema, comparing with original. + + Args: + xml_file: Path to XML file to validate + verbose: Enable verbose output + + Returns: + tuple: (is_valid, new_errors_set) where is_valid is True/False/None (skipped) + """ + # Resolve both paths to handle symlinks + xml_file = Path(xml_file).resolve() + unpacked_dir = self.unpacked_dir.resolve() + + # Validate current file + is_valid, current_errors = self._validate_single_file_xsd( + xml_file, unpacked_dir + ) + + if is_valid is None: + return None, set() # Skipped + elif is_valid: + return True, set() # Valid, no errors + + # Get errors from original file for this specific file + original_errors = self._get_original_file_errors(xml_file) + + # Compare with original (both are guaranteed to be sets here) + assert current_errors is not None + new_errors = current_errors - original_errors + + if new_errors: + if verbose: + relative_path = xml_file.relative_to(unpacked_dir) + print(f"FAILED - {relative_path}: {len(new_errors)} new error(s)") + for error in list(new_errors)[:3]: + truncated = error[:250] + "..." if len(error) > 250 else error + print(f" - {truncated}") + return False, new_errors + else: + # All errors existed in original + if verbose: + print( + f"PASSED - No new errors (original had {len(current_errors)} errors)" + ) + return True, set() + + def validate_against_xsd(self): + """Validate XML files against XSD schemas, showing only new errors compared to original.""" + new_errors = [] + original_error_count = 0 + valid_count = 0 + skipped_count = 0 + + for xml_file in self.xml_files: + relative_path = str(xml_file.relative_to(self.unpacked_dir)) + is_valid, new_file_errors = self.validate_file_against_xsd( + xml_file, verbose=False + ) + + if is_valid is None: + skipped_count += 1 + continue + elif is_valid and not new_file_errors: + valid_count += 1 + continue + elif is_valid: + # Had errors but all existed in original + original_error_count += 1 + valid_count += 1 + continue + + # Has new errors + new_errors.append(f" {relative_path}: {len(new_file_errors)} new error(s)") + for error in list(new_file_errors)[:3]: # Show first 3 errors + new_errors.append( + f" - {error[:250]}..." if len(error) > 250 else f" - {error}" + ) + + # Print summary + if self.verbose: + print(f"Validated {len(self.xml_files)} files:") + print(f" - Valid: {valid_count}") + print(f" - Skipped (no schema): {skipped_count}") + if original_error_count: + print(f" - With original errors (ignored): {original_error_count}") + print( + f" - With NEW errors: {len(new_errors) > 0 and len([e for e in new_errors if not e.startswith(' ')]) or 0}" + ) + + if new_errors: + print("\nFAILED - Found NEW validation errors:") + for error in new_errors: + print(error) + return False + else: + if self.verbose: + print("\nPASSED - No new XSD validation errors introduced") + return True + + def _get_schema_path(self, xml_file): + """Determine the appropriate schema path for an XML file.""" + # Check exact filename match + if xml_file.name in self.SCHEMA_MAPPINGS: + return self.schemas_dir / self.SCHEMA_MAPPINGS[xml_file.name] + + # Check .rels files + if xml_file.suffix == ".rels": + return self.schemas_dir / self.SCHEMA_MAPPINGS[".rels"] + + # Check chart files + if "charts/" in str(xml_file) and xml_file.name.startswith("chart"): + return self.schemas_dir / self.SCHEMA_MAPPINGS["chart"] + + # Check theme files + if "theme/" in str(xml_file) and xml_file.name.startswith("theme"): + return self.schemas_dir / self.SCHEMA_MAPPINGS["theme"] + + # Check if file is in a main content folder and use appropriate schema + if xml_file.parent.name in self.MAIN_CONTENT_FOLDERS: + return self.schemas_dir / self.SCHEMA_MAPPINGS[xml_file.parent.name] + + return None + + def _clean_ignorable_namespaces(self, xml_doc): + """Remove attributes and elements not in allowed namespaces.""" + # Create a clean copy + xml_string = lxml.etree.tostring(xml_doc, encoding="unicode") + xml_copy = lxml.etree.fromstring(xml_string) + + # Remove attributes not in allowed namespaces + for elem in xml_copy.iter(): + attrs_to_remove = [] + + for attr in elem.attrib: + # Check if attribute is from a namespace other than allowed ones + if "{" in attr: + ns = attr.split("}")[0][1:] + if ns not in self.OOXML_NAMESPACES: + attrs_to_remove.append(attr) + + # Remove collected attributes + for attr in attrs_to_remove: + del elem.attrib[attr] + + # Remove elements not in allowed namespaces + self._remove_ignorable_elements(xml_copy) + + return lxml.etree.ElementTree(xml_copy) + + def _remove_ignorable_elements(self, root): + """Recursively remove all elements not in allowed namespaces.""" + elements_to_remove = [] + + # Find elements to remove + for elem in list(root): + # Skip non-element nodes (comments, processing instructions, etc.) + if not hasattr(elem, "tag") or callable(elem.tag): + continue + + tag_str = str(elem.tag) + if tag_str.startswith("{"): + ns = tag_str.split("}")[0][1:] + if ns not in self.OOXML_NAMESPACES: + elements_to_remove.append(elem) + continue + + # Recursively clean child elements + self._remove_ignorable_elements(elem) + + # Remove collected elements + for elem in elements_to_remove: + root.remove(elem) + + def _preprocess_for_mc_ignorable(self, xml_doc): + """Preprocess XML to handle mc:Ignorable attribute properly.""" + # Remove mc:Ignorable attributes before validation + root = xml_doc.getroot() + + # Remove mc:Ignorable attribute from root + if f"{{{self.MC_NAMESPACE}}}Ignorable" in root.attrib: + del root.attrib[f"{{{self.MC_NAMESPACE}}}Ignorable"] + + return xml_doc + + def _validate_single_file_xsd(self, xml_file, base_path): + """Validate a single XML file against XSD schema. Returns (is_valid, errors_set).""" + schema_path = self._get_schema_path(xml_file) + if not schema_path: + return None, None # Skip file + + try: + # Load schema + with open(schema_path, "rb") as xsd_file: + parser = lxml.etree.XMLParser() + xsd_doc = lxml.etree.parse( + xsd_file, parser=parser, base_url=str(schema_path) + ) + schema = lxml.etree.XMLSchema(xsd_doc) + + # Load and preprocess XML + with open(xml_file, "r") as f: + xml_doc = lxml.etree.parse(f) + + xml_doc, _ = self._remove_template_tags_from_text_nodes(xml_doc) + xml_doc = self._preprocess_for_mc_ignorable(xml_doc) + + # Clean ignorable namespaces if needed + relative_path = xml_file.relative_to(base_path) + if ( + relative_path.parts + and relative_path.parts[0] in self.MAIN_CONTENT_FOLDERS + ): + xml_doc = self._clean_ignorable_namespaces(xml_doc) + + # Validate + if schema.validate(xml_doc): + return True, set() + else: + errors = set() + for error in schema.error_log: + # Store normalized error message (without line numbers for comparison) + errors.add(error.message) + return False, errors + + except Exception as e: + return False, {str(e)} + + def _get_original_file_errors(self, xml_file): + """Get XSD validation errors from a single file in the original document. + + Args: + xml_file: Path to the XML file in unpacked_dir to check + + Returns: + set: Set of error messages from the original file + """ + import tempfile + import zipfile + + # Resolve both paths to handle symlinks (e.g., /var vs /private/var on macOS) + xml_file = Path(xml_file).resolve() + unpacked_dir = self.unpacked_dir.resolve() + relative_path = xml_file.relative_to(unpacked_dir) + + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + + # Extract original file + with zipfile.ZipFile(self.original_file, "r") as zip_ref: + zip_ref.extractall(temp_path) + + # Find corresponding file in original + original_xml_file = temp_path / relative_path + + if not original_xml_file.exists(): + # File didn't exist in original, so no original errors + return set() + + # Validate the specific file in original + is_valid, errors = self._validate_single_file_xsd( + original_xml_file, temp_path + ) + return errors if errors else set() + + def _remove_template_tags_from_text_nodes(self, xml_doc): + """Remove template tags from XML text nodes and collect warnings. + + Template tags follow the pattern {{ ... }} and are used as placeholders + for content replacement. They should be removed from text content before + XSD validation while preserving XML structure. + + Returns: + tuple: (cleaned_xml_doc, warnings_list) + """ + warnings = [] + template_pattern = re.compile(r"\{\{[^}]*\}\}") + + # Create a copy of the document to avoid modifying the original + xml_string = lxml.etree.tostring(xml_doc, encoding="unicode") + xml_copy = lxml.etree.fromstring(xml_string) + + def process_text_content(text, content_type): + if not text: + return text + matches = list(template_pattern.finditer(text)) + if matches: + for match in matches: + warnings.append( + f"Found template tag in {content_type}: {match.group()}" + ) + return template_pattern.sub("", text) + return text + + # Process all text nodes in the document + for elem in xml_copy.iter(): + # Skip processing if this is a w:t element + if not hasattr(elem, "tag") or callable(elem.tag): + continue + tag_str = str(elem.tag) + if tag_str.endswith("}t") or tag_str == "t": + continue + + elem.text = process_text_content(elem.text, "text content") + elem.tail = process_text_content(elem.tail, "tail content") + + return lxml.etree.ElementTree(xml_copy), warnings + + +if __name__ == "__main__": + raise RuntimeError("This module should not be run directly.") diff --git a/docx/ooxml/scripts/validation/docx.py b/docx/ooxml/scripts/validation/docx.py new file mode 100644 index 0000000..602c470 --- /dev/null +++ b/docx/ooxml/scripts/validation/docx.py @@ -0,0 +1,274 @@ +""" +Validator for Word document XML files against XSD schemas. +""" + +import re +import tempfile +import zipfile + +import lxml.etree + +from .base import BaseSchemaValidator + + +class DOCXSchemaValidator(BaseSchemaValidator): + """Validator for Word document XML files against XSD schemas.""" + + # Word-specific namespace + WORD_2006_NAMESPACE = "http://schemas.openxmlformats.org/wordprocessingml/2006/main" + + # Word-specific element to relationship type mappings + # Start with empty mapping - add specific cases as we discover them + ELEMENT_RELATIONSHIP_TYPES = {} + + def validate(self): + """Run all validation checks and return True if all pass.""" + # Test 0: XML well-formedness + if not self.validate_xml(): + return False + + # Test 1: Namespace declarations + all_valid = True + if not self.validate_namespaces(): + all_valid = False + + # Test 2: Unique IDs + if not self.validate_unique_ids(): + all_valid = False + + # Test 3: Relationship and file reference validation + if not self.validate_file_references(): + all_valid = False + + # Test 4: Content type declarations + if not self.validate_content_types(): + all_valid = False + + # Test 5: XSD schema validation + if not self.validate_against_xsd(): + all_valid = False + + # Test 6: Whitespace preservation + if not self.validate_whitespace_preservation(): + all_valid = False + + # Test 7: Deletion validation + if not self.validate_deletions(): + all_valid = False + + # Test 8: Insertion validation + if not self.validate_insertions(): + all_valid = False + + # Test 9: Relationship ID reference validation + if not self.validate_all_relationship_ids(): + all_valid = False + + # Count and compare paragraphs + self.compare_paragraph_counts() + + return all_valid + + def validate_whitespace_preservation(self): + """ + Validate that w:t elements with whitespace have xml:space='preserve'. + """ + errors = [] + + for xml_file in self.xml_files: + # Only check document.xml files + if xml_file.name != "document.xml": + continue + + try: + root = lxml.etree.parse(str(xml_file)).getroot() + + # Find all w:t elements + for elem in root.iter(f"{{{self.WORD_2006_NAMESPACE}}}t"): + if elem.text: + text = elem.text + # Check if text starts or ends with whitespace + if re.match(r"^\s.*", text) or re.match(r".*\s$", text): + # Check if xml:space="preserve" attribute exists + xml_space_attr = f"{{{self.XML_NAMESPACE}}}space" + if ( + xml_space_attr not in elem.attrib + or elem.attrib[xml_space_attr] != "preserve" + ): + # Show a preview of the text + text_preview = ( + repr(text)[:50] + "..." + if len(repr(text)) > 50 + else repr(text) + ) + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: w:t element with whitespace missing xml:space='preserve': {text_preview}" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} whitespace preservation violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All whitespace is properly preserved") + return True + + def validate_deletions(self): + """ + Validate that w:t elements are not within w:del elements. + For some reason, XSD validation does not catch this, so we do it manually. + """ + errors = [] + + for xml_file in self.xml_files: + # Only check document.xml files + if xml_file.name != "document.xml": + continue + + try: + root = lxml.etree.parse(str(xml_file)).getroot() + + # Find all w:t elements that are descendants of w:del elements + namespaces = {"w": self.WORD_2006_NAMESPACE} + xpath_expression = ".//w:del//w:t" + problematic_t_elements = root.xpath( + xpath_expression, namespaces=namespaces + ) + for t_elem in problematic_t_elements: + if t_elem.text: + # Show a preview of the text + text_preview = ( + repr(t_elem.text)[:50] + "..." + if len(repr(t_elem.text)) > 50 + else repr(t_elem.text) + ) + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {t_elem.sourceline}: found within : {text_preview}" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} deletion validation violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - No w:t elements found within w:del elements") + return True + + def count_paragraphs_in_unpacked(self): + """Count the number of paragraphs in the unpacked document.""" + count = 0 + + for xml_file in self.xml_files: + # Only check document.xml files + if xml_file.name != "document.xml": + continue + + try: + root = lxml.etree.parse(str(xml_file)).getroot() + # Count all w:p elements + paragraphs = root.findall(f".//{{{self.WORD_2006_NAMESPACE}}}p") + count = len(paragraphs) + except Exception as e: + print(f"Error counting paragraphs in unpacked document: {e}") + + return count + + def count_paragraphs_in_original(self): + """Count the number of paragraphs in the original docx file.""" + count = 0 + + try: + # Create temporary directory to unpack original + with tempfile.TemporaryDirectory() as temp_dir: + # Unpack original docx + with zipfile.ZipFile(self.original_file, "r") as zip_ref: + zip_ref.extractall(temp_dir) + + # Parse document.xml + doc_xml_path = temp_dir + "/word/document.xml" + root = lxml.etree.parse(doc_xml_path).getroot() + + # Count all w:p elements + paragraphs = root.findall(f".//{{{self.WORD_2006_NAMESPACE}}}p") + count = len(paragraphs) + + except Exception as e: + print(f"Error counting paragraphs in original document: {e}") + + return count + + def validate_insertions(self): + """ + Validate that w:delText elements are not within w:ins elements. + w:delText is only allowed in w:ins if nested within a w:del. + """ + errors = [] + + for xml_file in self.xml_files: + if xml_file.name != "document.xml": + continue + + try: + root = lxml.etree.parse(str(xml_file)).getroot() + namespaces = {"w": self.WORD_2006_NAMESPACE} + + # Find w:delText in w:ins that are NOT within w:del + invalid_elements = root.xpath( + ".//w:ins//w:delText[not(ancestor::w:del)]", + namespaces=namespaces + ) + + for elem in invalid_elements: + text_preview = ( + repr(elem.text or "")[:50] + "..." + if len(repr(elem.text or "")) > 50 + else repr(elem.text or "") + ) + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: within : {text_preview}" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} insertion validation violations:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - No w:delText elements within w:ins elements") + return True + + def compare_paragraph_counts(self): + """Compare paragraph counts between original and new document.""" + original_count = self.count_paragraphs_in_original() + new_count = self.count_paragraphs_in_unpacked() + + diff = new_count - original_count + diff_str = f"+{diff}" if diff > 0 else str(diff) + print(f"\nParagraphs: {original_count} → {new_count} ({diff_str})") + + +if __name__ == "__main__": + raise RuntimeError("This module should not be run directly.") diff --git a/docx/ooxml/scripts/validation/pptx.py b/docx/ooxml/scripts/validation/pptx.py new file mode 100644 index 0000000..66d5b1e --- /dev/null +++ b/docx/ooxml/scripts/validation/pptx.py @@ -0,0 +1,315 @@ +""" +Validator for PowerPoint presentation XML files against XSD schemas. +""" + +import re + +from .base import BaseSchemaValidator + + +class PPTXSchemaValidator(BaseSchemaValidator): + """Validator for PowerPoint presentation XML files against XSD schemas.""" + + # PowerPoint presentation namespace + PRESENTATIONML_NAMESPACE = ( + "http://schemas.openxmlformats.org/presentationml/2006/main" + ) + + # PowerPoint-specific element to relationship type mappings + ELEMENT_RELATIONSHIP_TYPES = { + "sldid": "slide", + "sldmasterid": "slidemaster", + "notesmasterid": "notesmaster", + "sldlayoutid": "slidelayout", + "themeid": "theme", + "tablestyleid": "tablestyles", + } + + def validate(self): + """Run all validation checks and return True if all pass.""" + # Test 0: XML well-formedness + if not self.validate_xml(): + return False + + # Test 1: Namespace declarations + all_valid = True + if not self.validate_namespaces(): + all_valid = False + + # Test 2: Unique IDs + if not self.validate_unique_ids(): + all_valid = False + + # Test 3: UUID ID validation + if not self.validate_uuid_ids(): + all_valid = False + + # Test 4: Relationship and file reference validation + if not self.validate_file_references(): + all_valid = False + + # Test 5: Slide layout ID validation + if not self.validate_slide_layout_ids(): + all_valid = False + + # Test 6: Content type declarations + if not self.validate_content_types(): + all_valid = False + + # Test 7: XSD schema validation + if not self.validate_against_xsd(): + all_valid = False + + # Test 8: Notes slide reference validation + if not self.validate_notes_slide_references(): + all_valid = False + + # Test 9: Relationship ID reference validation + if not self.validate_all_relationship_ids(): + all_valid = False + + # Test 10: Duplicate slide layout references validation + if not self.validate_no_duplicate_slide_layouts(): + all_valid = False + + return all_valid + + def validate_uuid_ids(self): + """Validate that ID attributes that look like UUIDs contain only hex values.""" + import lxml.etree + + errors = [] + # UUID pattern: 8-4-4-4-12 hex digits with optional braces/hyphens + uuid_pattern = re.compile( + r"^[\{\(]?[0-9A-Fa-f]{8}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{4}-?[0-9A-Fa-f]{12}[\}\)]?$" + ) + + for xml_file in self.xml_files: + try: + root = lxml.etree.parse(str(xml_file)).getroot() + + # Check all elements for ID attributes + for elem in root.iter(): + for attr, value in elem.attrib.items(): + # Check if this is an ID attribute + attr_name = attr.split("}")[-1].lower() + if attr_name == "id" or attr_name.endswith("id"): + # Check if value looks like a UUID (has the right length and pattern structure) + if self._looks_like_uuid(value): + # Validate that it contains only hex characters in the right positions + if not uuid_pattern.match(value): + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: " + f"Line {elem.sourceline}: ID '{value}' appears to be a UUID but contains invalid hex characters" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {xml_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} UUID ID validation errors:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All UUID-like IDs contain valid hex values") + return True + + def _looks_like_uuid(self, value): + """Check if a value has the general structure of a UUID.""" + # Remove common UUID delimiters + clean_value = value.strip("{}()").replace("-", "") + # Check if it's 32 hex-like characters (could include invalid hex chars) + return len(clean_value) == 32 and all(c.isalnum() for c in clean_value) + + def validate_slide_layout_ids(self): + """Validate that sldLayoutId elements in slide masters reference valid slide layouts.""" + import lxml.etree + + errors = [] + + # Find all slide master files + slide_masters = list(self.unpacked_dir.glob("ppt/slideMasters/*.xml")) + + if not slide_masters: + if self.verbose: + print("PASSED - No slide masters found") + return True + + for slide_master in slide_masters: + try: + # Parse the slide master file + root = lxml.etree.parse(str(slide_master)).getroot() + + # Find the corresponding _rels file for this slide master + rels_file = slide_master.parent / "_rels" / f"{slide_master.name}.rels" + + if not rels_file.exists(): + errors.append( + f" {slide_master.relative_to(self.unpacked_dir)}: " + f"Missing relationships file: {rels_file.relative_to(self.unpacked_dir)}" + ) + continue + + # Parse the relationships file + rels_root = lxml.etree.parse(str(rels_file)).getroot() + + # Build a set of valid relationship IDs that point to slide layouts + valid_layout_rids = set() + for rel in rels_root.findall( + f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship" + ): + rel_type = rel.get("Type", "") + if "slideLayout" in rel_type: + valid_layout_rids.add(rel.get("Id")) + + # Find all sldLayoutId elements in the slide master + for sld_layout_id in root.findall( + f".//{{{self.PRESENTATIONML_NAMESPACE}}}sldLayoutId" + ): + r_id = sld_layout_id.get( + f"{{{self.OFFICE_RELATIONSHIPS_NAMESPACE}}}id" + ) + layout_id = sld_layout_id.get("id") + + if r_id and r_id not in valid_layout_rids: + errors.append( + f" {slide_master.relative_to(self.unpacked_dir)}: " + f"Line {sld_layout_id.sourceline}: sldLayoutId with id='{layout_id}' " + f"references r:id='{r_id}' which is not found in slide layout relationships" + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {slide_master.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print(f"FAILED - Found {len(errors)} slide layout ID validation errors:") + for error in errors: + print(error) + print( + "Remove invalid references or add missing slide layouts to the relationships file." + ) + return False + else: + if self.verbose: + print("PASSED - All slide layout IDs reference valid slide layouts") + return True + + def validate_no_duplicate_slide_layouts(self): + """Validate that each slide has exactly one slideLayout reference.""" + import lxml.etree + + errors = [] + slide_rels_files = list(self.unpacked_dir.glob("ppt/slides/_rels/*.xml.rels")) + + for rels_file in slide_rels_files: + try: + root = lxml.etree.parse(str(rels_file)).getroot() + + # Find all slideLayout relationships + layout_rels = [ + rel + for rel in root.findall( + f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship" + ) + if "slideLayout" in rel.get("Type", "") + ] + + if len(layout_rels) > 1: + errors.append( + f" {rels_file.relative_to(self.unpacked_dir)}: has {len(layout_rels)} slideLayout references" + ) + + except Exception as e: + errors.append( + f" {rels_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + if errors: + print("FAILED - Found slides with duplicate slideLayout references:") + for error in errors: + print(error) + return False + else: + if self.verbose: + print("PASSED - All slides have exactly one slideLayout reference") + return True + + def validate_notes_slide_references(self): + """Validate that each notesSlide file is referenced by only one slide.""" + import lxml.etree + + errors = [] + notes_slide_references = {} # Track which slides reference each notesSlide + + # Find all slide relationship files + slide_rels_files = list(self.unpacked_dir.glob("ppt/slides/_rels/*.xml.rels")) + + if not slide_rels_files: + if self.verbose: + print("PASSED - No slide relationship files found") + return True + + for rels_file in slide_rels_files: + try: + # Parse the relationships file + root = lxml.etree.parse(str(rels_file)).getroot() + + # Find all notesSlide relationships + for rel in root.findall( + f".//{{{self.PACKAGE_RELATIONSHIPS_NAMESPACE}}}Relationship" + ): + rel_type = rel.get("Type", "") + if "notesSlide" in rel_type: + target = rel.get("Target", "") + if target: + # Normalize the target path to handle relative paths + normalized_target = target.replace("../", "") + + # Track which slide references this notesSlide + slide_name = rels_file.stem.replace( + ".xml", "" + ) # e.g., "slide1" + + if normalized_target not in notes_slide_references: + notes_slide_references[normalized_target] = [] + notes_slide_references[normalized_target].append( + (slide_name, rels_file) + ) + + except (lxml.etree.XMLSyntaxError, Exception) as e: + errors.append( + f" {rels_file.relative_to(self.unpacked_dir)}: Error: {e}" + ) + + # Check for duplicate references + for target, references in notes_slide_references.items(): + if len(references) > 1: + slide_names = [ref[0] for ref in references] + errors.append( + f" Notes slide '{target}' is referenced by multiple slides: {', '.join(slide_names)}" + ) + for slide_name, rels_file in references: + errors.append(f" - {rels_file.relative_to(self.unpacked_dir)}") + + if errors: + print( + f"FAILED - Found {len([e for e in errors if not e.startswith(' ')])} notes slide reference validation errors:" + ) + for error in errors: + print(error) + print("Each slide may optionally have its own slide file.") + return False + else: + if self.verbose: + print("PASSED - All notes slide references are unique") + return True + + +if __name__ == "__main__": + raise RuntimeError("This module should not be run directly.") diff --git a/docx/ooxml/scripts/validation/redlining.py b/docx/ooxml/scripts/validation/redlining.py new file mode 100644 index 0000000..7ed425e --- /dev/null +++ b/docx/ooxml/scripts/validation/redlining.py @@ -0,0 +1,279 @@ +""" +Validator for tracked changes in Word documents. +""" + +import subprocess +import tempfile +import zipfile +from pathlib import Path + + +class RedliningValidator: + """Validator for tracked changes in Word documents.""" + + def __init__(self, unpacked_dir, original_docx, verbose=False): + self.unpacked_dir = Path(unpacked_dir) + self.original_docx = Path(original_docx) + self.verbose = verbose + self.namespaces = { + "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main" + } + + def validate(self): + """Main validation method that returns True if valid, False otherwise.""" + # Verify unpacked directory exists and has correct structure + modified_file = self.unpacked_dir / "word" / "document.xml" + if not modified_file.exists(): + print(f"FAILED - Modified document.xml not found at {modified_file}") + return False + + # First, check if there are any tracked changes by Claude to validate + try: + import xml.etree.ElementTree as ET + + tree = ET.parse(modified_file) + root = tree.getroot() + + # Check for w:del or w:ins tags authored by Claude + del_elements = root.findall(".//w:del", self.namespaces) + ins_elements = root.findall(".//w:ins", self.namespaces) + + # Filter to only include changes by Claude + claude_del_elements = [ + elem + for elem in del_elements + if elem.get(f"{{{self.namespaces['w']}}}author") == "Claude" + ] + claude_ins_elements = [ + elem + for elem in ins_elements + if elem.get(f"{{{self.namespaces['w']}}}author") == "Claude" + ] + + # Redlining validation is only needed if tracked changes by Claude have been used. + if not claude_del_elements and not claude_ins_elements: + if self.verbose: + print("PASSED - No tracked changes by Claude found.") + return True + + except Exception: + # If we can't parse the XML, continue with full validation + pass + + # Create temporary directory for unpacking original docx + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + + # Unpack original docx + try: + with zipfile.ZipFile(self.original_docx, "r") as zip_ref: + zip_ref.extractall(temp_path) + except Exception as e: + print(f"FAILED - Error unpacking original docx: {e}") + return False + + original_file = temp_path / "word" / "document.xml" + if not original_file.exists(): + print( + f"FAILED - Original document.xml not found in {self.original_docx}" + ) + return False + + # Parse both XML files using xml.etree.ElementTree for redlining validation + try: + import xml.etree.ElementTree as ET + + modified_tree = ET.parse(modified_file) + modified_root = modified_tree.getroot() + original_tree = ET.parse(original_file) + original_root = original_tree.getroot() + except ET.ParseError as e: + print(f"FAILED - Error parsing XML files: {e}") + return False + + # Remove Claude's tracked changes from both documents + self._remove_claude_tracked_changes(original_root) + self._remove_claude_tracked_changes(modified_root) + + # Extract and compare text content + modified_text = self._extract_text_content(modified_root) + original_text = self._extract_text_content(original_root) + + if modified_text != original_text: + # Show detailed character-level differences for each paragraph + error_message = self._generate_detailed_diff( + original_text, modified_text + ) + print(error_message) + return False + + if self.verbose: + print("PASSED - All changes by Claude are properly tracked") + return True + + def _generate_detailed_diff(self, original_text, modified_text): + """Generate detailed word-level differences using git word diff.""" + error_parts = [ + "FAILED - Document text doesn't match after removing Claude's tracked changes", + "", + "Likely causes:", + " 1. Modified text inside another author's or tags", + " 2. Made edits without proper tracked changes", + " 3. Didn't nest inside when deleting another's insertion", + "", + "For pre-redlined documents, use correct patterns:", + " - To reject another's INSERTION: Nest inside their ", + " - To restore another's DELETION: Add new AFTER their ", + "", + ] + + # Show git word diff + git_diff = self._get_git_word_diff(original_text, modified_text) + if git_diff: + error_parts.extend(["Differences:", "============", git_diff]) + else: + error_parts.append("Unable to generate word diff (git not available)") + + return "\n".join(error_parts) + + def _get_git_word_diff(self, original_text, modified_text): + """Generate word diff using git with character-level precision.""" + try: + with tempfile.TemporaryDirectory() as temp_dir: + temp_path = Path(temp_dir) + + # Create two files + original_file = temp_path / "original.txt" + modified_file = temp_path / "modified.txt" + + original_file.write_text(original_text, encoding="utf-8") + modified_file.write_text(modified_text, encoding="utf-8") + + # Try character-level diff first for precise differences + result = subprocess.run( + [ + "git", + "diff", + "--word-diff=plain", + "--word-diff-regex=.", # Character-by-character diff + "-U0", # Zero lines of context - show only changed lines + "--no-index", + str(original_file), + str(modified_file), + ], + capture_output=True, + text=True, + ) + + if result.stdout.strip(): + # Clean up the output - remove git diff header lines + lines = result.stdout.split("\n") + # Skip the header lines (diff --git, index, +++, ---, @@) + content_lines = [] + in_content = False + for line in lines: + if line.startswith("@@"): + in_content = True + continue + if in_content and line.strip(): + content_lines.append(line) + + if content_lines: + return "\n".join(content_lines) + + # Fallback to word-level diff if character-level is too verbose + result = subprocess.run( + [ + "git", + "diff", + "--word-diff=plain", + "-U0", # Zero lines of context + "--no-index", + str(original_file), + str(modified_file), + ], + capture_output=True, + text=True, + ) + + if result.stdout.strip(): + lines = result.stdout.split("\n") + content_lines = [] + in_content = False + for line in lines: + if line.startswith("@@"): + in_content = True + continue + if in_content and line.strip(): + content_lines.append(line) + return "\n".join(content_lines) + + except (subprocess.CalledProcessError, FileNotFoundError, Exception): + # Git not available or other error, return None to use fallback + pass + + return None + + def _remove_claude_tracked_changes(self, root): + """Remove tracked changes authored by Claude from the XML root.""" + ins_tag = f"{{{self.namespaces['w']}}}ins" + del_tag = f"{{{self.namespaces['w']}}}del" + author_attr = f"{{{self.namespaces['w']}}}author" + + # Remove w:ins elements + for parent in root.iter(): + to_remove = [] + for child in parent: + if child.tag == ins_tag and child.get(author_attr) == "Claude": + to_remove.append(child) + for elem in to_remove: + parent.remove(elem) + + # Unwrap content in w:del elements where author is "Claude" + deltext_tag = f"{{{self.namespaces['w']}}}delText" + t_tag = f"{{{self.namespaces['w']}}}t" + + for parent in root.iter(): + to_process = [] + for child in parent: + if child.tag == del_tag and child.get(author_attr) == "Claude": + to_process.append((child, list(parent).index(child))) + + # Process in reverse order to maintain indices + for del_elem, del_index in reversed(to_process): + # Convert w:delText to w:t before moving + for elem in del_elem.iter(): + if elem.tag == deltext_tag: + elem.tag = t_tag + + # Move all children of w:del to its parent before removing w:del + for child in reversed(list(del_elem)): + parent.insert(del_index, child) + parent.remove(del_elem) + + def _extract_text_content(self, root): + """Extract text content from Word XML, preserving paragraph structure. + + Empty paragraphs are skipped to avoid false positives when tracked + insertions add only structural elements without text content. + """ + p_tag = f"{{{self.namespaces['w']}}}p" + t_tag = f"{{{self.namespaces['w']}}}t" + + paragraphs = [] + for p_elem in root.findall(f".//{p_tag}"): + # Get all text elements within this paragraph + text_parts = [] + for t_elem in p_elem.findall(f".//{t_tag}"): + if t_elem.text: + text_parts.append(t_elem.text) + paragraph_text = "".join(text_parts) + # Skip empty paragraphs - they don't affect content validation + if paragraph_text: + paragraphs.append(paragraph_text) + + return "\n".join(paragraphs) + + +if __name__ == "__main__": + raise RuntimeError("This module should not be run directly.") diff --git a/docx/scripts/__init__.py b/docx/scripts/__init__.py new file mode 100755 index 0000000..bf9c562 --- /dev/null +++ b/docx/scripts/__init__.py @@ -0,0 +1 @@ +# Make scripts directory a package for relative imports in tests diff --git a/docx/scripts/document.py b/docx/scripts/document.py new file mode 100755 index 0000000..ae9328d --- /dev/null +++ b/docx/scripts/document.py @@ -0,0 +1,1276 @@ +#!/usr/bin/env python3 +""" +Library for working with Word documents: comments, tracked changes, and editing. + +Usage: + from skills.docx.scripts.document import Document + + # Initialize + doc = Document('workspace/unpacked') + doc = Document('workspace/unpacked', author="John Doe", initials="JD") + + # Find nodes + node = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "1"}) + node = doc["word/document.xml"].get_node(tag="w:p", line_number=10) + + # Add comments + doc.add_comment(start=node, end=node, text="Comment text") + doc.reply_to_comment(parent_comment_id=0, text="Reply text") + + # Suggest tracked changes + doc["word/document.xml"].suggest_deletion(node) # Delete content + doc["word/document.xml"].revert_insertion(ins_node) # Reject insertion + doc["word/document.xml"].revert_deletion(del_node) # Reject deletion + + # Save + doc.save() +""" + +import html +import random +import shutil +import tempfile +from datetime import datetime, timezone +from pathlib import Path + +from defusedxml import minidom +from ooxml.scripts.pack import pack_document +from ooxml.scripts.validation.docx import DOCXSchemaValidator +from ooxml.scripts.validation.redlining import RedliningValidator + +from .utilities import XMLEditor + +# Path to template files +TEMPLATE_DIR = Path(__file__).parent / "templates" + + +class DocxXMLEditor(XMLEditor): + """XMLEditor that automatically applies RSID, author, and date to new elements. + + Automatically adds attributes to elements that support them when inserting new content: + - w:rsidR, w:rsidRDefault, w:rsidP (for w:p and w:r elements) + - w:author and w:date (for w:ins, w:del, w:comment elements) + - w:id (for w:ins and w:del elements) + + Attributes: + dom (defusedxml.minidom.Document): The DOM document for direct manipulation + """ + + def __init__( + self, xml_path, rsid: str, author: str = "Claude", initials: str = "C" + ): + """Initialize with required RSID and optional author. + + Args: + xml_path: Path to XML file to edit + rsid: RSID to automatically apply to new elements + author: Author name for tracked changes and comments (default: "Claude") + initials: Author initials (default: "C") + """ + super().__init__(xml_path) + self.rsid = rsid + self.author = author + self.initials = initials + + def _get_next_change_id(self): + """Get the next available change ID by checking all tracked change elements.""" + max_id = -1 + for tag in ("w:ins", "w:del"): + elements = self.dom.getElementsByTagName(tag) + for elem in elements: + change_id = elem.getAttribute("w:id") + if change_id: + try: + max_id = max(max_id, int(change_id)) + except ValueError: + pass + return max_id + 1 + + def _ensure_w16du_namespace(self): + """Ensure w16du namespace is declared on the root element.""" + root = self.dom.documentElement + if not root.hasAttribute("xmlns:w16du"): # type: ignore + root.setAttribute( # type: ignore + "xmlns:w16du", + "http://schemas.microsoft.com/office/word/2023/wordml/word16du", + ) + + def _ensure_w16cex_namespace(self): + """Ensure w16cex namespace is declared on the root element.""" + root = self.dom.documentElement + if not root.hasAttribute("xmlns:w16cex"): # type: ignore + root.setAttribute( # type: ignore + "xmlns:w16cex", + "http://schemas.microsoft.com/office/word/2018/wordml/cex", + ) + + def _ensure_w14_namespace(self): + """Ensure w14 namespace is declared on the root element.""" + root = self.dom.documentElement + if not root.hasAttribute("xmlns:w14"): # type: ignore + root.setAttribute( # type: ignore + "xmlns:w14", + "http://schemas.microsoft.com/office/word/2010/wordml", + ) + + def _inject_attributes_to_nodes(self, nodes): + """Inject RSID, author, and date attributes into DOM nodes where applicable. + + Adds attributes to elements that support them: + - w:r: gets w:rsidR (or w:rsidDel if inside w:del) + - w:p: gets w:rsidR, w:rsidRDefault, w:rsidP, w14:paraId, w14:textId + - w:t: gets xml:space="preserve" if text has leading/trailing whitespace + - w:ins, w:del: get w:id, w:author, w:date, w16du:dateUtc + - w:comment: gets w:author, w:date, w:initials + - w16cex:commentExtensible: gets w16cex:dateUtc + + Args: + nodes: List of DOM nodes to process + """ + from datetime import datetime, timezone + + timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + + def is_inside_deletion(elem): + """Check if element is inside a w:del element.""" + parent = elem.parentNode + while parent: + if parent.nodeType == parent.ELEMENT_NODE and parent.tagName == "w:del": + return True + parent = parent.parentNode + return False + + def add_rsid_to_p(elem): + if not elem.hasAttribute("w:rsidR"): + elem.setAttribute("w:rsidR", self.rsid) + if not elem.hasAttribute("w:rsidRDefault"): + elem.setAttribute("w:rsidRDefault", self.rsid) + if not elem.hasAttribute("w:rsidP"): + elem.setAttribute("w:rsidP", self.rsid) + # Add w14:paraId and w14:textId if not present + if not elem.hasAttribute("w14:paraId"): + self._ensure_w14_namespace() + elem.setAttribute("w14:paraId", _generate_hex_id()) + if not elem.hasAttribute("w14:textId"): + self._ensure_w14_namespace() + elem.setAttribute("w14:textId", _generate_hex_id()) + + def add_rsid_to_r(elem): + # Use w:rsidDel for inside , otherwise w:rsidR + if is_inside_deletion(elem): + if not elem.hasAttribute("w:rsidDel"): + elem.setAttribute("w:rsidDel", self.rsid) + else: + if not elem.hasAttribute("w:rsidR"): + elem.setAttribute("w:rsidR", self.rsid) + + def add_tracked_change_attrs(elem): + # Auto-assign w:id if not present + if not elem.hasAttribute("w:id"): + elem.setAttribute("w:id", str(self._get_next_change_id())) + if not elem.hasAttribute("w:author"): + elem.setAttribute("w:author", self.author) + if not elem.hasAttribute("w:date"): + elem.setAttribute("w:date", timestamp) + # Add w16du:dateUtc for tracked changes (same as w:date since we generate UTC timestamps) + if elem.tagName in ("w:ins", "w:del") and not elem.hasAttribute( + "w16du:dateUtc" + ): + self._ensure_w16du_namespace() + elem.setAttribute("w16du:dateUtc", timestamp) + + def add_comment_attrs(elem): + if not elem.hasAttribute("w:author"): + elem.setAttribute("w:author", self.author) + if not elem.hasAttribute("w:date"): + elem.setAttribute("w:date", timestamp) + if not elem.hasAttribute("w:initials"): + elem.setAttribute("w:initials", self.initials) + + def add_comment_extensible_date(elem): + # Add w16cex:dateUtc for comment extensible elements + if not elem.hasAttribute("w16cex:dateUtc"): + self._ensure_w16cex_namespace() + elem.setAttribute("w16cex:dateUtc", timestamp) + + def add_xml_space_to_t(elem): + # Add xml:space="preserve" to w:t if text has leading/trailing whitespace + if ( + elem.firstChild + and elem.firstChild.nodeType == elem.firstChild.TEXT_NODE + ): + text = elem.firstChild.data + if text and (text[0].isspace() or text[-1].isspace()): + if not elem.hasAttribute("xml:space"): + elem.setAttribute("xml:space", "preserve") + + for node in nodes: + if node.nodeType != node.ELEMENT_NODE: + continue + + # Handle the node itself + if node.tagName == "w:p": + add_rsid_to_p(node) + elif node.tagName == "w:r": + add_rsid_to_r(node) + elif node.tagName == "w:t": + add_xml_space_to_t(node) + elif node.tagName in ("w:ins", "w:del"): + add_tracked_change_attrs(node) + elif node.tagName == "w:comment": + add_comment_attrs(node) + elif node.tagName == "w16cex:commentExtensible": + add_comment_extensible_date(node) + + # Process descendants (getElementsByTagName doesn't return the element itself) + for elem in node.getElementsByTagName("w:p"): + add_rsid_to_p(elem) + for elem in node.getElementsByTagName("w:r"): + add_rsid_to_r(elem) + for elem in node.getElementsByTagName("w:t"): + add_xml_space_to_t(elem) + for tag in ("w:ins", "w:del"): + for elem in node.getElementsByTagName(tag): + add_tracked_change_attrs(elem) + for elem in node.getElementsByTagName("w:comment"): + add_comment_attrs(elem) + for elem in node.getElementsByTagName("w16cex:commentExtensible"): + add_comment_extensible_date(elem) + + def replace_node(self, elem, new_content): + """Replace node with automatic attribute injection.""" + nodes = super().replace_node(elem, new_content) + self._inject_attributes_to_nodes(nodes) + return nodes + + def insert_after(self, elem, xml_content): + """Insert after with automatic attribute injection.""" + nodes = super().insert_after(elem, xml_content) + self._inject_attributes_to_nodes(nodes) + return nodes + + def insert_before(self, elem, xml_content): + """Insert before with automatic attribute injection.""" + nodes = super().insert_before(elem, xml_content) + self._inject_attributes_to_nodes(nodes) + return nodes + + def append_to(self, elem, xml_content): + """Append to with automatic attribute injection.""" + nodes = super().append_to(elem, xml_content) + self._inject_attributes_to_nodes(nodes) + return nodes + + def revert_insertion(self, elem): + """Reject an insertion by wrapping its content in a deletion. + + Wraps all runs inside w:ins in w:del, converting w:t to w:delText. + Can process a single w:ins element or a container element with multiple w:ins. + + Args: + elem: Element to process (w:ins, w:p, w:body, etc.) + + Returns: + list: List containing the processed element(s) + + Raises: + ValueError: If the element contains no w:ins elements + + Example: + # Reject a single insertion + ins = doc["word/document.xml"].get_node(tag="w:ins", attrs={"w:id": "5"}) + doc["word/document.xml"].revert_insertion(ins) + + # Reject all insertions in a paragraph + para = doc["word/document.xml"].get_node(tag="w:p", line_number=42) + doc["word/document.xml"].revert_insertion(para) + """ + # Collect insertions + ins_elements = [] + if elem.tagName == "w:ins": + ins_elements.append(elem) + else: + ins_elements.extend(elem.getElementsByTagName("w:ins")) + + # Validate that there are insertions to reject + if not ins_elements: + raise ValueError( + f"revert_insertion requires w:ins elements. " + f"The provided element <{elem.tagName}> contains no insertions. " + ) + + # Process all insertions - wrap all children in w:del + for ins_elem in ins_elements: + runs = list(ins_elem.getElementsByTagName("w:r")) + if not runs: + continue + + # Create deletion wrapper + del_wrapper = self.dom.createElement("w:del") + + # Process each run + for run in runs: + # Convert w:t → w:delText and w:rsidR → w:rsidDel + if run.hasAttribute("w:rsidR"): + run.setAttribute("w:rsidDel", run.getAttribute("w:rsidR")) + run.removeAttribute("w:rsidR") + elif not run.hasAttribute("w:rsidDel"): + run.setAttribute("w:rsidDel", self.rsid) + + for t_elem in list(run.getElementsByTagName("w:t")): + del_text = self.dom.createElement("w:delText") + # Copy ALL child nodes (not just firstChild) to handle entities + while t_elem.firstChild: + del_text.appendChild(t_elem.firstChild) + for i in range(t_elem.attributes.length): + attr = t_elem.attributes.item(i) + del_text.setAttribute(attr.name, attr.value) + t_elem.parentNode.replaceChild(del_text, t_elem) + + # Move all children from ins to del wrapper + while ins_elem.firstChild: + del_wrapper.appendChild(ins_elem.firstChild) + + # Add del wrapper back to ins + ins_elem.appendChild(del_wrapper) + + # Inject attributes to the deletion wrapper + self._inject_attributes_to_nodes([del_wrapper]) + + return [elem] + + def revert_deletion(self, elem): + """Reject a deletion by re-inserting the deleted content. + + Creates w:ins elements after each w:del, copying deleted content and + converting w:delText back to w:t. + Can process a single w:del element or a container element with multiple w:del. + + Args: + elem: Element to process (w:del, w:p, w:body, etc.) + + Returns: + list: If elem is w:del, returns [elem, new_ins]. Otherwise returns [elem]. + + Raises: + ValueError: If the element contains no w:del elements + + Example: + # Reject a single deletion - returns [w:del, w:ins] + del_elem = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "3"}) + nodes = doc["word/document.xml"].revert_deletion(del_elem) + + # Reject all deletions in a paragraph - returns [para] + para = doc["word/document.xml"].get_node(tag="w:p", line_number=42) + nodes = doc["word/document.xml"].revert_deletion(para) + """ + # Collect deletions FIRST - before we modify the DOM + del_elements = [] + is_single_del = elem.tagName == "w:del" + + if is_single_del: + del_elements.append(elem) + else: + del_elements.extend(elem.getElementsByTagName("w:del")) + + # Validate that there are deletions to reject + if not del_elements: + raise ValueError( + f"revert_deletion requires w:del elements. " + f"The provided element <{elem.tagName}> contains no deletions. " + ) + + # Track created insertion (only relevant if elem is a single w:del) + created_insertion = None + + # Process all deletions - create insertions that copy the deleted content + for del_elem in del_elements: + # Clone the deleted runs and convert them to insertions + runs = list(del_elem.getElementsByTagName("w:r")) + if not runs: + continue + + # Create insertion wrapper + ins_elem = self.dom.createElement("w:ins") + + for run in runs: + # Clone the run + new_run = run.cloneNode(True) + + # Convert w:delText → w:t + for del_text in list(new_run.getElementsByTagName("w:delText")): + t_elem = self.dom.createElement("w:t") + # Copy ALL child nodes (not just firstChild) to handle entities + while del_text.firstChild: + t_elem.appendChild(del_text.firstChild) + for i in range(del_text.attributes.length): + attr = del_text.attributes.item(i) + t_elem.setAttribute(attr.name, attr.value) + del_text.parentNode.replaceChild(t_elem, del_text) + + # Update run attributes: w:rsidDel → w:rsidR + if new_run.hasAttribute("w:rsidDel"): + new_run.setAttribute("w:rsidR", new_run.getAttribute("w:rsidDel")) + new_run.removeAttribute("w:rsidDel") + elif not new_run.hasAttribute("w:rsidR"): + new_run.setAttribute("w:rsidR", self.rsid) + + ins_elem.appendChild(new_run) + + # Insert the new insertion after the deletion + nodes = self.insert_after(del_elem, ins_elem.toxml()) + + # If processing a single w:del, track the created insertion + if is_single_del and nodes: + created_insertion = nodes[0] + + # Return based on input type + if is_single_del and created_insertion: + return [elem, created_insertion] + else: + return [elem] + + @staticmethod + def suggest_paragraph(xml_content: str) -> str: + """Transform paragraph XML to add tracked change wrapping for insertion. + + Wraps runs in and adds to w:rPr in w:pPr for numbered lists. + + Args: + xml_content: XML string containing a element + + Returns: + str: Transformed XML with tracked change wrapping + """ + wrapper = f'{xml_content}' + doc = minidom.parseString(wrapper) + para = doc.getElementsByTagName("w:p")[0] + + # Ensure w:pPr exists + pPr_list = para.getElementsByTagName("w:pPr") + if not pPr_list: + pPr = doc.createElement("w:pPr") + para.insertBefore( + pPr, para.firstChild + ) if para.firstChild else para.appendChild(pPr) + else: + pPr = pPr_list[0] + + # Ensure w:rPr exists in w:pPr + rPr_list = pPr.getElementsByTagName("w:rPr") + if not rPr_list: + rPr = doc.createElement("w:rPr") + pPr.appendChild(rPr) + else: + rPr = rPr_list[0] + + # Add to w:rPr + ins_marker = doc.createElement("w:ins") + rPr.insertBefore( + ins_marker, rPr.firstChild + ) if rPr.firstChild else rPr.appendChild(ins_marker) + + # Wrap all non-pPr children in + ins_wrapper = doc.createElement("w:ins") + for child in [c for c in para.childNodes if c.nodeName != "w:pPr"]: + para.removeChild(child) + ins_wrapper.appendChild(child) + para.appendChild(ins_wrapper) + + return para.toxml() + + def suggest_deletion(self, elem): + """Mark a w:r or w:p element as deleted with tracked changes (in-place DOM manipulation). + + For w:r: wraps in , converts to , preserves w:rPr + For w:p (regular): wraps content in , converts to + For w:p (numbered list): adds to w:rPr in w:pPr, wraps content in + + Args: + elem: A w:r or w:p DOM element without existing tracked changes + + Returns: + Element: The modified element + + Raises: + ValueError: If element has existing tracked changes or invalid structure + """ + if elem.nodeName == "w:r": + # Check for existing w:delText + if elem.getElementsByTagName("w:delText"): + raise ValueError("w:r element already contains w:delText") + + # Convert w:t → w:delText + for t_elem in list(elem.getElementsByTagName("w:t")): + del_text = self.dom.createElement("w:delText") + # Copy ALL child nodes (not just firstChild) to handle entities + while t_elem.firstChild: + del_text.appendChild(t_elem.firstChild) + # Preserve attributes like xml:space + for i in range(t_elem.attributes.length): + attr = t_elem.attributes.item(i) + del_text.setAttribute(attr.name, attr.value) + t_elem.parentNode.replaceChild(del_text, t_elem) + + # Update run attributes: w:rsidR → w:rsidDel + if elem.hasAttribute("w:rsidR"): + elem.setAttribute("w:rsidDel", elem.getAttribute("w:rsidR")) + elem.removeAttribute("w:rsidR") + elif not elem.hasAttribute("w:rsidDel"): + elem.setAttribute("w:rsidDel", self.rsid) + + # Wrap in w:del + del_wrapper = self.dom.createElement("w:del") + parent = elem.parentNode + parent.insertBefore(del_wrapper, elem) + parent.removeChild(elem) + del_wrapper.appendChild(elem) + + # Inject attributes to the deletion wrapper + self._inject_attributes_to_nodes([del_wrapper]) + + return del_wrapper + + elif elem.nodeName == "w:p": + # Check for existing tracked changes + if elem.getElementsByTagName("w:ins") or elem.getElementsByTagName("w:del"): + raise ValueError("w:p element already contains tracked changes") + + # Check if it's a numbered list item + pPr_list = elem.getElementsByTagName("w:pPr") + is_numbered = pPr_list and pPr_list[0].getElementsByTagName("w:numPr") + + if is_numbered: + # Add to w:rPr in w:pPr + pPr = pPr_list[0] + rPr_list = pPr.getElementsByTagName("w:rPr") + + if not rPr_list: + rPr = self.dom.createElement("w:rPr") + pPr.appendChild(rPr) + else: + rPr = rPr_list[0] + + # Add marker + del_marker = self.dom.createElement("w:del") + rPr.insertBefore( + del_marker, rPr.firstChild + ) if rPr.firstChild else rPr.appendChild(del_marker) + + # Convert w:t → w:delText in all runs + for t_elem in list(elem.getElementsByTagName("w:t")): + del_text = self.dom.createElement("w:delText") + # Copy ALL child nodes (not just firstChild) to handle entities + while t_elem.firstChild: + del_text.appendChild(t_elem.firstChild) + # Preserve attributes like xml:space + for i in range(t_elem.attributes.length): + attr = t_elem.attributes.item(i) + del_text.setAttribute(attr.name, attr.value) + t_elem.parentNode.replaceChild(del_text, t_elem) + + # Update run attributes: w:rsidR → w:rsidDel + for run in elem.getElementsByTagName("w:r"): + if run.hasAttribute("w:rsidR"): + run.setAttribute("w:rsidDel", run.getAttribute("w:rsidR")) + run.removeAttribute("w:rsidR") + elif not run.hasAttribute("w:rsidDel"): + run.setAttribute("w:rsidDel", self.rsid) + + # Wrap all non-pPr children in + del_wrapper = self.dom.createElement("w:del") + for child in [c for c in elem.childNodes if c.nodeName != "w:pPr"]: + elem.removeChild(child) + del_wrapper.appendChild(child) + elem.appendChild(del_wrapper) + + # Inject attributes to the deletion wrapper + self._inject_attributes_to_nodes([del_wrapper]) + + return elem + + else: + raise ValueError(f"Element must be w:r or w:p, got {elem.nodeName}") + + +def _generate_hex_id() -> str: + """Generate random 8-character hex ID for para/durable IDs. + + Values are constrained to be less than 0x7FFFFFFF per OOXML spec: + - paraId must be < 0x80000000 + - durableId must be < 0x7FFFFFFF + We use the stricter constraint (0x7FFFFFFF) for both. + """ + return f"{random.randint(1, 0x7FFFFFFE):08X}" + + +def _generate_rsid() -> str: + """Generate random 8-character hex RSID.""" + return "".join(random.choices("0123456789ABCDEF", k=8)) + + +class Document: + """Manages comments in unpacked Word documents.""" + + def __init__( + self, + unpacked_dir, + rsid=None, + track_revisions=False, + author="Claude", + initials="C", + ): + """ + Initialize with path to unpacked Word document directory. + Automatically sets up comment infrastructure (people.xml, RSIDs). + + Args: + unpacked_dir: Path to unpacked DOCX directory (must contain word/ subdirectory) + rsid: Optional RSID to use for all comment elements. If not provided, one will be generated. + track_revisions: If True, enables track revisions in settings.xml (default: False) + author: Default author name for comments (default: "Claude") + initials: Default author initials for comments (default: "C") + """ + self.original_path = Path(unpacked_dir) + + if not self.original_path.exists() or not self.original_path.is_dir(): + raise ValueError(f"Directory not found: {unpacked_dir}") + + # Create temporary directory with subdirectories for unpacked content and baseline + self.temp_dir = tempfile.mkdtemp(prefix="docx_") + self.unpacked_path = Path(self.temp_dir) / "unpacked" + shutil.copytree(self.original_path, self.unpacked_path) + + # Pack original directory into temporary .docx for validation baseline (outside unpacked dir) + self.original_docx = Path(self.temp_dir) / "original.docx" + pack_document(self.original_path, self.original_docx, validate=False) + + self.word_path = self.unpacked_path / "word" + + # Generate RSID if not provided + self.rsid = rsid if rsid else _generate_rsid() + print(f"Using RSID: {self.rsid}") + + # Set default author and initials + self.author = author + self.initials = initials + + # Cache for lazy-loaded editors + self._editors = {} + + # Comment file paths + self.comments_path = self.word_path / "comments.xml" + self.comments_extended_path = self.word_path / "commentsExtended.xml" + self.comments_ids_path = self.word_path / "commentsIds.xml" + self.comments_extensible_path = self.word_path / "commentsExtensible.xml" + + # Load existing comments and determine next ID (before setup modifies files) + self.existing_comments = self._load_existing_comments() + self.next_comment_id = self._get_next_comment_id() + + # Convenient access to document.xml editor (semi-private) + self._document = self["word/document.xml"] + + # Setup tracked changes infrastructure + self._setup_tracking(track_revisions=track_revisions) + + # Add author to people.xml + self._add_author_to_people(author) + + def __getitem__(self, xml_path: str) -> DocxXMLEditor: + """ + Get or create a DocxXMLEditor for the specified XML file. + + Enables lazy-loaded editors with bracket notation: + node = doc["word/document.xml"].get_node(tag="w:p", line_number=42) + + Args: + xml_path: Relative path to XML file (e.g., "word/document.xml", "word/comments.xml") + + Returns: + DocxXMLEditor instance for the specified file + + Raises: + ValueError: If the file does not exist + + Example: + # Get node from document.xml + node = doc["word/document.xml"].get_node(tag="w:del", attrs={"w:id": "1"}) + + # Get node from comments.xml + comment = doc["word/comments.xml"].get_node(tag="w:comment", attrs={"w:id": "0"}) + """ + if xml_path not in self._editors: + file_path = self.unpacked_path / xml_path + if not file_path.exists(): + raise ValueError(f"XML file not found: {xml_path}") + # Use DocxXMLEditor with RSID, author, and initials for all editors + self._editors[xml_path] = DocxXMLEditor( + file_path, rsid=self.rsid, author=self.author, initials=self.initials + ) + return self._editors[xml_path] + + def add_comment(self, start, end, text: str) -> int: + """ + Add a comment spanning from one element to another. + + Args: + start: DOM element for the starting point + end: DOM element for the ending point + text: Comment content + + Returns: + The comment ID that was created + + Example: + start_node = cm.get_document_node(tag="w:del", id="1") + end_node = cm.get_document_node(tag="w:ins", id="2") + cm.add_comment(start=start_node, end=end_node, text="Explanation") + """ + comment_id = self.next_comment_id + para_id = _generate_hex_id() + durable_id = _generate_hex_id() + timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + + # Add comment ranges to document.xml immediately + self._document.insert_before(start, self._comment_range_start_xml(comment_id)) + + # If end node is a paragraph, append comment markup inside it + # Otherwise insert after it (for run-level anchors) + if end.tagName == "w:p": + self._document.append_to(end, self._comment_range_end_xml(comment_id)) + else: + self._document.insert_after(end, self._comment_range_end_xml(comment_id)) + + # Add to comments.xml immediately + self._add_to_comments_xml( + comment_id, para_id, text, self.author, self.initials, timestamp + ) + + # Add to commentsExtended.xml immediately + self._add_to_comments_extended_xml(para_id, parent_para_id=None) + + # Add to commentsIds.xml immediately + self._add_to_comments_ids_xml(para_id, durable_id) + + # Add to commentsExtensible.xml immediately + self._add_to_comments_extensible_xml(durable_id) + + # Update existing_comments so replies work + self.existing_comments[comment_id] = {"para_id": para_id} + + self.next_comment_id += 1 + return comment_id + + def reply_to_comment( + self, + parent_comment_id: int, + text: str, + ) -> int: + """ + Add a reply to an existing comment. + + Args: + parent_comment_id: The w:id of the parent comment to reply to + text: Reply text + + Returns: + The comment ID that was created for the reply + + Example: + cm.reply_to_comment(parent_comment_id=0, text="I agree with this change") + """ + if parent_comment_id not in self.existing_comments: + raise ValueError(f"Parent comment with id={parent_comment_id} not found") + + parent_info = self.existing_comments[parent_comment_id] + comment_id = self.next_comment_id + para_id = _generate_hex_id() + durable_id = _generate_hex_id() + timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + + # Add comment ranges to document.xml immediately + parent_start_elem = self._document.get_node( + tag="w:commentRangeStart", attrs={"w:id": str(parent_comment_id)} + ) + parent_ref_elem = self._document.get_node( + tag="w:commentReference", attrs={"w:id": str(parent_comment_id)} + ) + + self._document.insert_after( + parent_start_elem, self._comment_range_start_xml(comment_id) + ) + parent_ref_run = parent_ref_elem.parentNode + self._document.insert_after( + parent_ref_run, f'' + ) + self._document.insert_after( + parent_ref_run, self._comment_ref_run_xml(comment_id) + ) + + # Add to comments.xml immediately + self._add_to_comments_xml( + comment_id, para_id, text, self.author, self.initials, timestamp + ) + + # Add to commentsExtended.xml immediately (with parent) + self._add_to_comments_extended_xml( + para_id, parent_para_id=parent_info["para_id"] + ) + + # Add to commentsIds.xml immediately + self._add_to_comments_ids_xml(para_id, durable_id) + + # Add to commentsExtensible.xml immediately + self._add_to_comments_extensible_xml(durable_id) + + # Update existing_comments so replies work + self.existing_comments[comment_id] = {"para_id": para_id} + + self.next_comment_id += 1 + return comment_id + + def __del__(self): + """Clean up temporary directory on deletion.""" + if hasattr(self, "temp_dir") and Path(self.temp_dir).exists(): + shutil.rmtree(self.temp_dir) + + def validate(self) -> None: + """ + Validate the document against XSD schema and redlining rules. + + Raises: + ValueError: If validation fails. + """ + # Create validators with current state + schema_validator = DOCXSchemaValidator( + self.unpacked_path, self.original_docx, verbose=False + ) + redlining_validator = RedliningValidator( + self.unpacked_path, self.original_docx, verbose=False + ) + + # Run validations + if not schema_validator.validate(): + raise ValueError("Schema validation failed") + if not redlining_validator.validate(): + raise ValueError("Redlining validation failed") + + def save(self, destination=None, validate=True) -> None: + """ + Save all modified XML files to disk and copy to destination directory. + + This persists all changes made via add_comment() and reply_to_comment(). + + Args: + destination: Optional path to save to. If None, saves back to original directory. + validate: If True, validates document before saving (default: True). + """ + # Only ensure comment relationships and content types if comment files exist + if self.comments_path.exists(): + self._ensure_comment_relationships() + self._ensure_comment_content_types() + + # Save all modified XML files in temp directory + for editor in self._editors.values(): + editor.save() + + # Validate by default + if validate: + self.validate() + + # Copy contents from temp directory to destination (or original directory) + target_path = Path(destination) if destination else self.original_path + shutil.copytree(self.unpacked_path, target_path, dirs_exist_ok=True) + + # ==================== Private: Initialization ==================== + + def _get_next_comment_id(self): + """Get the next available comment ID.""" + if not self.comments_path.exists(): + return 0 + + editor = self["word/comments.xml"] + max_id = -1 + for comment_elem in editor.dom.getElementsByTagName("w:comment"): + comment_id = comment_elem.getAttribute("w:id") + if comment_id: + try: + max_id = max(max_id, int(comment_id)) + except ValueError: + pass + return max_id + 1 + + def _load_existing_comments(self): + """Load existing comments from files to enable replies.""" + if not self.comments_path.exists(): + return {} + + editor = self["word/comments.xml"] + existing = {} + + for comment_elem in editor.dom.getElementsByTagName("w:comment"): + comment_id = comment_elem.getAttribute("w:id") + if not comment_id: + continue + + # Find para_id from the w:p element within the comment + para_id = None + for p_elem in comment_elem.getElementsByTagName("w:p"): + para_id = p_elem.getAttribute("w14:paraId") + if para_id: + break + + if not para_id: + continue + + existing[int(comment_id)] = {"para_id": para_id} + + return existing + + # ==================== Private: Setup Methods ==================== + + def _setup_tracking(self, track_revisions=False): + """Set up comment infrastructure in unpacked directory. + + Args: + track_revisions: If True, enables track revisions in settings.xml + """ + # Create or update word/people.xml + people_file = self.word_path / "people.xml" + self._update_people_xml(people_file) + + # Update XML files + self._add_content_type_for_people(self.unpacked_path / "[Content_Types].xml") + self._add_relationship_for_people( + self.word_path / "_rels" / "document.xml.rels" + ) + + # Always add RSID to settings.xml, optionally enable trackRevisions + self._update_settings( + self.word_path / "settings.xml", track_revisions=track_revisions + ) + + def _update_people_xml(self, path): + """Create people.xml if it doesn't exist.""" + if not path.exists(): + # Copy from template + shutil.copy(TEMPLATE_DIR / "people.xml", path) + + def _add_content_type_for_people(self, path): + """Add people.xml content type to [Content_Types].xml if not already present.""" + editor = self["[Content_Types].xml"] + + if self._has_override(editor, "/word/people.xml"): + return + + # Add Override element + root = editor.dom.documentElement + override_xml = '' + editor.append_to(root, override_xml) + + def _add_relationship_for_people(self, path): + """Add people.xml relationship to document.xml.rels if not already present.""" + editor = self["word/_rels/document.xml.rels"] + + if self._has_relationship(editor, "people.xml"): + return + + root = editor.dom.documentElement + root_tag = root.tagName # type: ignore + prefix = root_tag.split(":")[0] + ":" if ":" in root_tag else "" + next_rid = editor.get_next_rid() + + # Create the relationship entry + rel_xml = f'<{prefix}Relationship Id="{next_rid}" Type="http://schemas.microsoft.com/office/2011/relationships/people" Target="people.xml"/>' + editor.append_to(root, rel_xml) + + def _update_settings(self, path, track_revisions=False): + """Add RSID and optionally enable track revisions in settings.xml. + + Args: + path: Path to settings.xml + track_revisions: If True, adds trackRevisions element + + Places elements per OOXML schema order: + - trackRevisions: early (before defaultTabStop) + - rsids: late (after compat) + """ + editor = self["word/settings.xml"] + root = editor.get_node(tag="w:settings") + prefix = root.tagName.split(":")[0] if ":" in root.tagName else "w" + + # Conditionally add trackRevisions if requested + if track_revisions: + track_revisions_exists = any( + elem.tagName == f"{prefix}:trackRevisions" + for elem in editor.dom.getElementsByTagName(f"{prefix}:trackRevisions") + ) + + if not track_revisions_exists: + track_rev_xml = f"<{prefix}:trackRevisions/>" + # Try to insert before documentProtection, defaultTabStop, or at start + inserted = False + for tag in [f"{prefix}:documentProtection", f"{prefix}:defaultTabStop"]: + elements = editor.dom.getElementsByTagName(tag) + if elements: + editor.insert_before(elements[0], track_rev_xml) + inserted = True + break + if not inserted: + # Insert as first child of settings + if root.firstChild: + editor.insert_before(root.firstChild, track_rev_xml) + else: + editor.append_to(root, track_rev_xml) + + # Always check if rsids section exists + rsids_elements = editor.dom.getElementsByTagName(f"{prefix}:rsids") + + if not rsids_elements: + # Add new rsids section + rsids_xml = f'''<{prefix}:rsids> + <{prefix}:rsidRoot {prefix}:val="{self.rsid}"/> + <{prefix}:rsid {prefix}:val="{self.rsid}"/> +''' + + # Try to insert after compat, before clrSchemeMapping, or before closing tag + inserted = False + compat_elements = editor.dom.getElementsByTagName(f"{prefix}:compat") + if compat_elements: + editor.insert_after(compat_elements[0], rsids_xml) + inserted = True + + if not inserted: + clr_elements = editor.dom.getElementsByTagName( + f"{prefix}:clrSchemeMapping" + ) + if clr_elements: + editor.insert_before(clr_elements[0], rsids_xml) + inserted = True + + if not inserted: + editor.append_to(root, rsids_xml) + else: + # Check if this rsid already exists + rsids_elem = rsids_elements[0] + rsid_exists = any( + elem.getAttribute(f"{prefix}:val") == self.rsid + for elem in rsids_elem.getElementsByTagName(f"{prefix}:rsid") + ) + + if not rsid_exists: + rsid_xml = f'<{prefix}:rsid {prefix}:val="{self.rsid}"/>' + editor.append_to(rsids_elem, rsid_xml) + + # ==================== Private: XML File Creation ==================== + + def _add_to_comments_xml( + self, comment_id, para_id, text, author, initials, timestamp + ): + """Add a single comment to comments.xml.""" + if not self.comments_path.exists(): + shutil.copy(TEMPLATE_DIR / "comments.xml", self.comments_path) + + editor = self["word/comments.xml"] + root = editor.get_node(tag="w:comments") + + escaped_text = ( + text.replace("&", "&").replace("<", "<").replace(">", ">") + ) + # Note: w:rsidR, w:rsidRDefault, w:rsidP on w:p, w:rsidR on w:r, + # and w:author, w:date, w:initials on w:comment are automatically added by DocxXMLEditor + comment_xml = f''' + + + {escaped_text} + +''' + editor.append_to(root, comment_xml) + + def _add_to_comments_extended_xml(self, para_id, parent_para_id): + """Add a single comment to commentsExtended.xml.""" + if not self.comments_extended_path.exists(): + shutil.copy( + TEMPLATE_DIR / "commentsExtended.xml", self.comments_extended_path + ) + + editor = self["word/commentsExtended.xml"] + root = editor.get_node(tag="w15:commentsEx") + + if parent_para_id: + xml = f'' + else: + xml = f'' + editor.append_to(root, xml) + + def _add_to_comments_ids_xml(self, para_id, durable_id): + """Add a single comment to commentsIds.xml.""" + if not self.comments_ids_path.exists(): + shutil.copy(TEMPLATE_DIR / "commentsIds.xml", self.comments_ids_path) + + editor = self["word/commentsIds.xml"] + root = editor.get_node(tag="w16cid:commentsIds") + + xml = f'' + editor.append_to(root, xml) + + def _add_to_comments_extensible_xml(self, durable_id): + """Add a single comment to commentsExtensible.xml.""" + if not self.comments_extensible_path.exists(): + shutil.copy( + TEMPLATE_DIR / "commentsExtensible.xml", self.comments_extensible_path + ) + + editor = self["word/commentsExtensible.xml"] + root = editor.get_node(tag="w16cex:commentsExtensible") + + xml = f'' + editor.append_to(root, xml) + + # ==================== Private: XML Fragments ==================== + + def _comment_range_start_xml(self, comment_id): + """Generate XML for comment range start.""" + return f'' + + def _comment_range_end_xml(self, comment_id): + """Generate XML for comment range end with reference run. + + Note: w:rsidR is automatically added by DocxXMLEditor. + """ + return f''' + + + +''' + + def _comment_ref_run_xml(self, comment_id): + """Generate XML for comment reference run. + + Note: w:rsidR is automatically added by DocxXMLEditor. + """ + return f''' + + +''' + + # ==================== Private: Metadata Updates ==================== + + def _has_relationship(self, editor, target): + """Check if a relationship with given target exists.""" + for rel_elem in editor.dom.getElementsByTagName("Relationship"): + if rel_elem.getAttribute("Target") == target: + return True + return False + + def _has_override(self, editor, part_name): + """Check if an override with given part name exists.""" + for override_elem in editor.dom.getElementsByTagName("Override"): + if override_elem.getAttribute("PartName") == part_name: + return True + return False + + def _has_author(self, editor, author): + """Check if an author already exists in people.xml.""" + for person_elem in editor.dom.getElementsByTagName("w15:person"): + if person_elem.getAttribute("w15:author") == author: + return True + return False + + def _add_author_to_people(self, author): + """Add author to people.xml (called during initialization).""" + people_path = self.word_path / "people.xml" + + # people.xml should already exist from _setup_tracking + if not people_path.exists(): + raise ValueError("people.xml should exist after _setup_tracking") + + editor = self["word/people.xml"] + root = editor.get_node(tag="w15:people") + + # Check if author already exists + if self._has_author(editor, author): + return + + # Add author with proper XML escaping to prevent injection + escaped_author = html.escape(author, quote=True) + person_xml = f''' + +''' + editor.append_to(root, person_xml) + + def _ensure_comment_relationships(self): + """Ensure word/_rels/document.xml.rels has comment relationships.""" + editor = self["word/_rels/document.xml.rels"] + + if self._has_relationship(editor, "comments.xml"): + return + + root = editor.dom.documentElement + root_tag = root.tagName # type: ignore + prefix = root_tag.split(":")[0] + ":" if ":" in root_tag else "" + next_rid_num = int(editor.get_next_rid()[3:]) + + # Add relationship elements + rels = [ + ( + next_rid_num, + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", + "comments.xml", + ), + ( + next_rid_num + 1, + "http://schemas.microsoft.com/office/2011/relationships/commentsExtended", + "commentsExtended.xml", + ), + ( + next_rid_num + 2, + "http://schemas.microsoft.com/office/2016/09/relationships/commentsIds", + "commentsIds.xml", + ), + ( + next_rid_num + 3, + "http://schemas.microsoft.com/office/2018/08/relationships/commentsExtensible", + "commentsExtensible.xml", + ), + ] + + for rel_id, rel_type, target in rels: + rel_xml = f'<{prefix}Relationship Id="rId{rel_id}" Type="{rel_type}" Target="{target}"/>' + editor.append_to(root, rel_xml) + + def _ensure_comment_content_types(self): + """Ensure [Content_Types].xml has comment content types.""" + editor = self["[Content_Types].xml"] + + if self._has_override(editor, "/word/comments.xml"): + return + + root = editor.dom.documentElement + + # Add Override elements + overrides = [ + ( + "/word/comments.xml", + "application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml", + ), + ( + "/word/commentsExtended.xml", + "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtended+xml", + ), + ( + "/word/commentsIds.xml", + "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsIds+xml", + ), + ( + "/word/commentsExtensible.xml", + "application/vnd.openxmlformats-officedocument.wordprocessingml.commentsExtensible+xml", + ), + ] + + for part_name, content_type in overrides: + override_xml = ( + f'' + ) + editor.append_to(root, override_xml) diff --git a/docx/scripts/templates/comments.xml b/docx/scripts/templates/comments.xml new file mode 100644 index 0000000..b5dace0 --- /dev/null +++ b/docx/scripts/templates/comments.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docx/scripts/templates/commentsExtended.xml b/docx/scripts/templates/commentsExtended.xml new file mode 100644 index 0000000..b4cf23e --- /dev/null +++ b/docx/scripts/templates/commentsExtended.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docx/scripts/templates/commentsExtensible.xml b/docx/scripts/templates/commentsExtensible.xml new file mode 100644 index 0000000..e32a05e --- /dev/null +++ b/docx/scripts/templates/commentsExtensible.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docx/scripts/templates/commentsIds.xml b/docx/scripts/templates/commentsIds.xml new file mode 100644 index 0000000..d04bc8e --- /dev/null +++ b/docx/scripts/templates/commentsIds.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docx/scripts/templates/people.xml b/docx/scripts/templates/people.xml new file mode 100644 index 0000000..a839caf --- /dev/null +++ b/docx/scripts/templates/people.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docx/scripts/utilities.py b/docx/scripts/utilities.py new file mode 100755 index 0000000..d92dae6 --- /dev/null +++ b/docx/scripts/utilities.py @@ -0,0 +1,374 @@ +#!/usr/bin/env python3 +""" +Utilities for editing OOXML documents. + +This module provides XMLEditor, a tool for manipulating XML files with support for +line-number-based node finding and DOM manipulation. Each element is automatically +annotated with its original line and column position during parsing. + +Example usage: + editor = XMLEditor("document.xml") + + # Find node by line number or range + elem = editor.get_node(tag="w:r", line_number=519) + elem = editor.get_node(tag="w:p", line_number=range(100, 200)) + + # Find node by text content + elem = editor.get_node(tag="w:p", contains="specific text") + + # Find node by attributes + elem = editor.get_node(tag="w:r", attrs={"w:id": "target"}) + + # Combine filters + elem = editor.get_node(tag="w:p", line_number=range(1, 50), contains="text") + + # Replace, insert, or manipulate + new_elem = editor.replace_node(elem, "new text") + editor.insert_after(new_elem, "more") + + # Save changes + editor.save() +""" + +import html +from pathlib import Path +from typing import Optional, Union + +import defusedxml.minidom +import defusedxml.sax + + +class XMLEditor: + """ + Editor for manipulating OOXML XML files with line-number-based node finding. + + This class parses XML files and tracks the original line and column position + of each element. This enables finding nodes by their line number in the original + file, which is useful when working with Read tool output. + + Attributes: + xml_path: Path to the XML file being edited + encoding: Detected encoding of the XML file ('ascii' or 'utf-8') + dom: Parsed DOM tree with parse_position attributes on elements + """ + + def __init__(self, xml_path): + """ + Initialize with path to XML file and parse with line number tracking. + + Args: + xml_path: Path to XML file to edit (str or Path) + + Raises: + ValueError: If the XML file does not exist + """ + self.xml_path = Path(xml_path) + if not self.xml_path.exists(): + raise ValueError(f"XML file not found: {xml_path}") + + with open(self.xml_path, "rb") as f: + header = f.read(200).decode("utf-8", errors="ignore") + self.encoding = "ascii" if 'encoding="ascii"' in header else "utf-8" + + parser = _create_line_tracking_parser() + self.dom = defusedxml.minidom.parse(str(self.xml_path), parser) + + def get_node( + self, + tag: str, + attrs: Optional[dict[str, str]] = None, + line_number: Optional[Union[int, range]] = None, + contains: Optional[str] = None, + ): + """ + Get a DOM element by tag and identifier. + + Finds an element by either its line number in the original file or by + matching attribute values. Exactly one match must be found. + + Args: + tag: The XML tag name (e.g., "w:del", "w:ins", "w:r") + attrs: Dictionary of attribute name-value pairs to match (e.g., {"w:id": "1"}) + line_number: Line number (int) or line range (range) in original XML file (1-indexed) + contains: Text string that must appear in any text node within the element. + Supports both entity notation (“) and Unicode characters (\u201c). + + Returns: + defusedxml.minidom.Element: The matching DOM element + + Raises: + ValueError: If node not found or multiple matches found + + Example: + elem = editor.get_node(tag="w:r", line_number=519) + elem = editor.get_node(tag="w:r", line_number=range(100, 200)) + elem = editor.get_node(tag="w:del", attrs={"w:id": "1"}) + elem = editor.get_node(tag="w:p", attrs={"w14:paraId": "12345678"}) + elem = editor.get_node(tag="w:commentRangeStart", attrs={"w:id": "0"}) + elem = editor.get_node(tag="w:p", contains="specific text") + elem = editor.get_node(tag="w:t", contains="“Agreement") # Entity notation + elem = editor.get_node(tag="w:t", contains="\u201cAgreement") # Unicode character + """ + matches = [] + for elem in self.dom.getElementsByTagName(tag): + # Check line_number filter + if line_number is not None: + parse_pos = getattr(elem, "parse_position", (None,)) + elem_line = parse_pos[0] + + # Handle both single line number and range + if isinstance(line_number, range): + if elem_line not in line_number: + continue + else: + if elem_line != line_number: + continue + + # Check attrs filter + if attrs is not None: + if not all( + elem.getAttribute(attr_name) == attr_value + for attr_name, attr_value in attrs.items() + ): + continue + + # Check contains filter + if contains is not None: + elem_text = self._get_element_text(elem) + # Normalize the search string: convert HTML entities to Unicode characters + # This allows searching for both "“Rowan" and ""Rowan" + normalized_contains = html.unescape(contains) + if normalized_contains not in elem_text: + continue + + # If all applicable filters passed, this is a match + matches.append(elem) + + if not matches: + # Build descriptive error message + filters = [] + if line_number is not None: + line_str = ( + f"lines {line_number.start}-{line_number.stop - 1}" + if isinstance(line_number, range) + else f"line {line_number}" + ) + filters.append(f"at {line_str}") + if attrs is not None: + filters.append(f"with attributes {attrs}") + if contains is not None: + filters.append(f"containing '{contains}'") + + filter_desc = " ".join(filters) if filters else "" + base_msg = f"Node not found: <{tag}> {filter_desc}".strip() + + # Add helpful hint based on filters used + if contains: + hint = "Text may be split across elements or use different wording." + elif line_number: + hint = "Line numbers may have changed if document was modified." + elif attrs: + hint = "Verify attribute values are correct." + else: + hint = "Try adding filters (attrs, line_number, or contains)." + + raise ValueError(f"{base_msg}. {hint}") + if len(matches) > 1: + raise ValueError( + f"Multiple nodes found: <{tag}>. " + f"Add more filters (attrs, line_number, or contains) to narrow the search." + ) + return matches[0] + + def _get_element_text(self, elem): + """ + Recursively extract all text content from an element. + + Skips text nodes that contain only whitespace (spaces, tabs, newlines), + which typically represent XML formatting rather than document content. + + Args: + elem: defusedxml.minidom.Element to extract text from + + Returns: + str: Concatenated text from all non-whitespace text nodes within the element + """ + text_parts = [] + for node in elem.childNodes: + if node.nodeType == node.TEXT_NODE: + # Skip whitespace-only text nodes (XML formatting) + if node.data.strip(): + text_parts.append(node.data) + elif node.nodeType == node.ELEMENT_NODE: + text_parts.append(self._get_element_text(node)) + return "".join(text_parts) + + def replace_node(self, elem, new_content): + """ + Replace a DOM element with new XML content. + + Args: + elem: defusedxml.minidom.Element to replace + new_content: String containing XML to replace the node with + + Returns: + List[defusedxml.minidom.Node]: All inserted nodes + + Example: + new_nodes = editor.replace_node(old_elem, "text") + """ + parent = elem.parentNode + nodes = self._parse_fragment(new_content) + for node in nodes: + parent.insertBefore(node, elem) + parent.removeChild(elem) + return nodes + + def insert_after(self, elem, xml_content): + """ + Insert XML content after a DOM element. + + Args: + elem: defusedxml.minidom.Element to insert after + xml_content: String containing XML to insert + + Returns: + List[defusedxml.minidom.Node]: All inserted nodes + + Example: + new_nodes = editor.insert_after(elem, "text") + """ + parent = elem.parentNode + next_sibling = elem.nextSibling + nodes = self._parse_fragment(xml_content) + for node in nodes: + if next_sibling: + parent.insertBefore(node, next_sibling) + else: + parent.appendChild(node) + return nodes + + def insert_before(self, elem, xml_content): + """ + Insert XML content before a DOM element. + + Args: + elem: defusedxml.minidom.Element to insert before + xml_content: String containing XML to insert + + Returns: + List[defusedxml.minidom.Node]: All inserted nodes + + Example: + new_nodes = editor.insert_before(elem, "text") + """ + parent = elem.parentNode + nodes = self._parse_fragment(xml_content) + for node in nodes: + parent.insertBefore(node, elem) + return nodes + + def append_to(self, elem, xml_content): + """ + Append XML content as a child of a DOM element. + + Args: + elem: defusedxml.minidom.Element to append to + xml_content: String containing XML to append + + Returns: + List[defusedxml.minidom.Node]: All inserted nodes + + Example: + new_nodes = editor.append_to(elem, "text") + """ + nodes = self._parse_fragment(xml_content) + for node in nodes: + elem.appendChild(node) + return nodes + + def get_next_rid(self): + """Get the next available rId for relationships files.""" + max_id = 0 + for rel_elem in self.dom.getElementsByTagName("Relationship"): + rel_id = rel_elem.getAttribute("Id") + if rel_id.startswith("rId"): + try: + max_id = max(max_id, int(rel_id[3:])) + except ValueError: + pass + return f"rId{max_id + 1}" + + def save(self): + """ + Save the edited XML back to the file. + + Serializes the DOM tree and writes it back to the original file path, + preserving the original encoding (ascii or utf-8). + """ + content = self.dom.toxml(encoding=self.encoding) + self.xml_path.write_bytes(content) + + def _parse_fragment(self, xml_content): + """ + Parse XML fragment and return list of imported nodes. + + Args: + xml_content: String containing XML fragment + + Returns: + List of defusedxml.minidom.Node objects imported into this document + + Raises: + AssertionError: If fragment contains no element nodes + """ + # Extract namespace declarations from the root document element + root_elem = self.dom.documentElement + namespaces = [] + if root_elem and root_elem.attributes: + for i in range(root_elem.attributes.length): + attr = root_elem.attributes.item(i) + if attr.name.startswith("xmlns"): # type: ignore + namespaces.append(f'{attr.name}="{attr.value}"') # type: ignore + + ns_decl = " ".join(namespaces) + wrapper = f"{xml_content}" + fragment_doc = defusedxml.minidom.parseString(wrapper) + nodes = [ + self.dom.importNode(child, deep=True) + for child in fragment_doc.documentElement.childNodes # type: ignore + ] + elements = [n for n in nodes if n.nodeType == n.ELEMENT_NODE] + assert elements, "Fragment must contain at least one element" + return nodes + + +def _create_line_tracking_parser(): + """ + Create a SAX parser that tracks line and column numbers for each element. + + Monkey patches the SAX content handler to store the current line and column + position from the underlying expat parser onto each element as a parse_position + attribute (line, column) tuple. + + Returns: + defusedxml.sax.xmlreader.XMLReader: Configured SAX parser + """ + + def set_content_handler(dom_handler): + def startElementNS(name, tagName, attrs): + orig_start_cb(name, tagName, attrs) + cur_elem = dom_handler.elementStack[-1] + cur_elem.parse_position = ( + parser._parser.CurrentLineNumber, # type: ignore + parser._parser.CurrentColumnNumber, # type: ignore + ) + + orig_start_cb = dom_handler.startElementNS + dom_handler.startElementNS = startElementNS + orig_set_content_handler(dom_handler) + + parser = defusedxml.sax.make_parser() + orig_set_content_handler = parser.setContentHandler + parser.setContentHandler = set_content_handler # type: ignore + return parser diff --git a/financial-report-writing/SKILL.md b/financial-report-writing/SKILL.md new file mode 100644 index 0000000..44cbbed --- /dev/null +++ b/financial-report-writing/SKILL.md @@ -0,0 +1,685 @@ +# 金融研究报告撰写技能 + +## 概述 +本技能用于协助用户撰写专业的A股上市公司投资研究报告,涵盖数据获取、分析和文档格式化等全流程。 + +## 适用场景 +- 撰写上市公司周报、月报或专项研究报告 +- 需要使用Wind金融终端获取实时或历史数据 +- 生成符合中国国家标准的Word格式文档 +- 技术分析与基本面分析相结合的投资报告 + +## 核心能力 + +### 1. 数据获取(WindPy SDK) + +#### 连接Wind终端 +```python +from WindPy import w +w.start() +data = w.wsd("300866.SZ", "close", "2025-11-01", "2026-02-06") +w.stop() +``` + +#### 常用数据函数 +- `w.wsd()` - 日线序列数据 +- `w.wsi()` - 分钟线数据 +- `w.wss()` - 截面数据(最新值) +- `wsd` 常用字段: + - `close` - 收盘价 + - `open`/`high`/`low` - 开盘/最高/最低价 + - `volume`/`amt` - 成交量/成交额 + - `pct_chg` - 涨跌幅 + - `ma5`, `ma10`, `ma20`, `ma60` - 均线 + - `roe` - 净资产收益率 + - `pe_ttm`, `pb_lf` - 市盈率/市净率 + +#### 技术指标计算 +- 移动平均线:MA5, MA10, MA20, MA60 +- 波动率:使用标准差计算年化波动率 +- 支撑位/阻力位:基于高低点分析 + +### 2. Word文档格式化(python-docx) + +#### 国家标准 GB/T 9704-2012 + +**页面设置** +```python +from docx.shared import Mm +section.top_margin = Mm(37) +section.bottom_margin = Mm(35) +section.left_margin = Mm(28) +section.right_margin = Mm(26) +``` + +**字体规范** +```python +def set_font(run, font_name, size=None, bold=None): + run.font.name = font_name + run.font.size = Pt(size) if size else None + if bold is not None: + run.font.bold = bold + # 设置中文字体 + run._element.rPr.rFonts.set(qn('w:eastAsia'), font_name) + +# 三号标题:16pt +# 四号正文:14pt +# 小四表格:12pt +``` + +**字号对照表** +- 三号:16pt +- 四号:14pt +- 小四:12pt +- 五号:10.5pt + +**行距设置** +```python +paragraph.paragraph_format.line_spacing = Pt(28) # 正文 +paragraph.paragraph_format.line_spacing = Pt(25) # 小标题 +paragraph.paragraph_format.line_spacing_rule = 2 # 固定值 +``` + +**段落格式** +```python +# 首行缩进2字符(28pt) +paragraph.paragraph_format.first_line_indent = Pt(28) + +# 两端对齐 +paragraph.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY + +# 段前段后距 +paragraph.paragraph_format.space_before = Pt(0) +paragraph.paragraph_format.space_after = Pt(0) +``` + +#### 三线表格式 + +```python +def set_table_borders(table): + tblPr = table._tbl.tblPr + tblBorders = OxmlElement('w:tblBorders') + # 顶底边框 1.5pt (sz=18) + for pos in ['top', 'bottom']: + border = OxmlElement(f'w:{pos}') + border.set(qn('w:val'), 'single') + border.set(qn('w:sz'), '18') + border.set(qn('w:color'), 'auto') + tblBorders.append(border) + # 内部横线 0.75pt (sz=9) + for pos in ['insideH']: + border = OxmlElement(f'w:{pos}') + border.set(qn('w:val'), 'single') + border.set(qn('w:sz'), '9') + border.set(qn('w:color'), 'auto') + tblBorders.append(border) + # 无左右和竖线 + for pos in ['left', 'right', 'insideV']: + border = OxmlElement(f'w:{pos}') + border.set(qn('w:val'), 'none') + tblBorders.append(border) + tblPr.append(tblBorders) +``` + +#### 页脚页码 +```python +from docx.enum.text import WD_ALIGN_PARAGRAPH +footer = section.footer +p = footer.paragraphs[0] if footer.paragraphs else footer.add_paragraph() +p.alignment = WD_ALIGN_PARAGRAPH.CENTER +r1 = p.add_run('—') +set_font(r1, '仿宋', 12) +r2 = p.add_run() # 页码占位 +set_font(r2, '仿宋', 12) +r3 = p.add_run(' ') +set_font(r3, '仿宋', 12) +r4 = p.add_run() # 页码占位 +set_font(r4, '仿宋', 12) +r5 = p.add_run('—') +set_font(r5, '仿宋', 12) +``` + +### 3. 报告结构标准 + +#### 完整报告结构(可选封面版) +1. **封面页** + - 标题:黑体三号(16pt),居中 + - 报告机构和日期:黑体三号(16pt),居中 + +2. **免责声明**(可选) + - 标题:黑体三号(16pt),居中 + - 内容:仿宋四号(14pt),两端对齐 + +3. **核心提要** + - 标题:黑体三号(16pt),居中 + - 内容:3-4个要点,仿宋四号(14pt),首行缩进2字符 + +4. **一、投资评级** + - 标题:黑体三号(16pt) + - 评级表格:小四(12pt),三线表 + - 内容:投资建议、目标价格、有效期、风险等级 + +5. **二、核心观点** + - 标题:黑体三号(16pt) + - 内容:基本面+技术面分析+投资建议 + +6. **三、市场表现回顾** + - 标题:黑体三号(16pt) + - (一)价格走势分析:黑体三号(16pt) + - (二)K线数据表:标题黑体小四(12pt) + +#### 简化报告结构(无封面) +- 核心提要 → 一、投资评级 → 二、核心观点 → 三、市场表现回顾 +- 不使用分页符,保持内容连贯 + +### 4. 内容撰写要点 + +#### 核心提要 +- 突出关键数据(ROE、涨跌幅等) +- 简明扼要,3-4个要点 +- 包含明确的投资建议 + +#### 核心观点 +- 基本面:盈利能力(ROE)、估值水平(PE/PB) +- 技术面:价格趋势、均线、支撑阻力位 +- 投资建议:具体操作策略 + +#### 市场表现回顾 +- 时间周期:近13周(周线数据) +- 价格区间:最高价、最低价、累计涨跌幅 +- 数据表格:日期、开盘、最高、最低、收盘、涨跌幅、成交量 + +### 5. 数据处理技巧 + +#### 时间序列对齐 +```python +import pandas as pd +df = pd.DataFrame(data, columns=['date', 'open', 'high', 'low', 'close']) +df['date'] = pd.to_datetime(df['date']) +df.sort_values('date', ascending=True) +``` + +#### 周线数据汇总 +```python +df_weekly = df.resample('W').agg({ + 'open': 'first', + 'high': 'max', + 'low': 'min', + 'close': 'last', + 'volume': 'sum' +}) +``` + +#### 波动率计算 +```python +import numpy as np +returns = df['close'].pct_change().dropna() +volatility = returns.std() * np.sqrt(52) * 100 # 年化百分比 +``` + +### 6. 常见问题解决 + +#### 字体显示问题 +- 必须同时设置中文字体:`run._element.rPr.rFonts.set(qn('w:eastAsia'), font_name)` +- 不要只设置 `run.font.name` + +#### 表格单元格格式 +- Cell对象没有 `paragraph_format` 属性 +- 需要通过 `cell.paragraphs[0].paragraph_format` 访问 + +#### Run对象访问 +- Run对象没有 `runs` 属性 +- 段落的runs通过 `paragraph.runs` 访问 + +#### 行距单位 +- 使用 `Pt()` 设置固定行距(点) +- `line_spacing_rule = 2` 表示固定值 + +## 使用示例 + +### 基本流程 +1. 使用WindPy SDK获取股票数据 +2. 计算技术指标(MA、波动率等) +3. 分析基本面指标(ROE、PE等) +4. 整理分析结论 +5. 使用python-docx生成Word文档 +6. 应用GB/T 9704-2012格式规范 +7. 保存文档 + +### 快速检查清单(Word文档) +- [ ] 页面边距:37/35/28/26mm +- [ ] 字体:标题黑体三号、正文仿宋四号、表格小四 +- [ ] 行距:正文28pt、小标题25pt +- [ ] 首行缩进:正文2字符(28pt) +- [ ] 三线表:顶底1.5pt、内部0.75pt、无边框 +- [ ] 数据来源注脚:右对齐,小四(12pt) + +### Excel图表检查清单 +详见「图表设置检查清单」表格(第7节末尾) + +## 注意事项 + +1. **字体重要性**:中文文本必须设置 `w:eastAsia` 属性,否则可能显示为默认字体 +2. **表格边框**:使用三线表格式,无左右和竖线 +3. **段落缩进**:正文段落需要首行缩进,标题不需要 +4. **分页控制**:根据需要决定是否分页,简化版通常不分页 +5. **数据时效**:注意数据更新日期,避免使用过期数据 +6. **投资建议**:提供明确的操作策略,但需提醒风险 + +### 7. Excel 图表绘制(openpyxl) + +本技能支持生成包含原生 Excel 图表的 .xlsx 文件,图表可在 Excel 中编辑和交互。 + +#### 基础图表创建 + +```python +from openpyxl import Workbook +from openpyxl.chart import LineChart, BarChart, Reference +from openpyxl.chart.axis import DateAxis + +# 创建工作簿 +wb = Workbook() +ws = wb.active +ws.title = "股价走势" + +# 写入数据 +ws.append(["日期", "收盘价", "成交量"]) +for date, close, vol in data: + ws.append([date, close, vol]) + +# 创建折线图(股价走势) +chart = LineChart() +chart.title = "股价走势" +chart.y_axis.title = "价格(元)" +chart.x_axis.title = "日期" + +# 设置数据区域 +data_ref = Reference(ws, min_col=2, min_row=1, max_row=len(data)+1) +cats_ref = Reference(ws, min_col=1, min_row=2, max_row=len(data)+1) +chart.add_data(data_ref, titles_from_data=True) +chart.set_categories(cats_ref) + +# 设置样式 +chart.style = 10 +chart.height = 10 # 高度(厘米) +chart.width = 20 # 宽度(厘米) + +# 添加到工作表 +ws.add_chart(chart, "D2") +wb.save("股价走势.xlsx") +``` + +#### 常用图表类型 + +**折线图(LineChart)** +- 适用:股价走势、均线趋势 +- 特点:展示时间序列变化 + +```python +from openpyxl.chart import LineChart +chart = LineChart() +chart.add_data(data_ref) +chart.set_categories(cats_ref) +``` + +**柱状图(BarChart)** +- 适用:成交量对比、财务数据对比 +- 特点:横向展示数据大小 + +```python +from openpyxl.chart import BarChart +chart = BarChart() +chart.type = "col" # 垂直柱状图 +chart.add_data(data_ref) +``` + +**组合图表(股价+成交量)** +- 适用:K线+成交量组合展示 +- 特点:双Y轴,价格+量能 + +```python +from openpyxl.chart import LineChart, BarChart +from openpyxl.chart.series import DataPoint + +# 主图:股价线 +price_chart = LineChart() +price_chart.add_data(price_ref, titles_from_data=True) +price_chart.y_axis.title = "价格(元)" + +# 副图:成交量柱状 +vol_chart = BarChart() +vol_chart.add_data(vol_ref, titles_from_data=True) +vol_chart.y_axis.axId = 200 # 设置次要Y轴 +vol_chart.y_axis.title = "成交量(手)" + +# 组合图表 +price_chart += vol_chart +price_chart.y_axis.crosses = "max" # 成交量轴在右侧 +``` + +#### 图表样式设置 + +**线条与颜色规范** +```python +# 线条样式 +from openpyxl.chart.series import DataPoint +from openpyxl.drawing.fill import SolidColorFillProperties +from openpyxl.drawing.line import LineProperties + +series = chart.series[0] +series.graphicalProperties.line.solidFill = "4472C4" # 线条颜色 +series.graphicalProperties.line.width = 25000 # 线条粗细(EMUs) + +# 标记点样式 +series.marker.symbol = "circle" +series.marker.size = 5 +``` + +**A股颜色规范(涨跌自动着色)** +```python +# 柱状图根据涨跌自动设置颜色(红涨绿跌) +from openpyxl.drawing.fill import PatternFillProperties, ColorChoice +from openpyxl.chart.series import DataPoint + +# 为每个数据点设置颜色 +for i, val in enumerate(values): + pt = DataPoint(idx=i) + # A股规范:上涨红色,下跌绿色 + fill_color = "FF0000" if val >= 0 else "00B050" + pt.graphicalProperties = GraphicalProperties( + solidFill=fill_color + ) + series.data_points.append(pt) +``` + +**网格线与图例** +```python +# 网格线设置(研报风格:仅水平主网格线) +chart.x_axis.majorGridlines = None # 隐藏X轴网格 +chart.y_axis.majorGridlines = None # 或设置为浅灰色虚线 + +# 图例位置 +chart.legend.position = "b" # 底部:b, 右侧:r, 顶部:t, 左侧:l +``` + +#### 双轴图表(价格+涨跌幅) + +```python +from openpyxl.chart import LineChart +from openpyxl.chart.axis import DateAxis + +# 主图:股价 +price_chart = LineChart() +price_chart.add_data(price_ref, titles_from_data=True) +price_chart.y_axis.title = "价格(元)" + +# 副图:涨跌幅(柱状) +pct_chart = LineChart() +pct_chart.add_data(pct_ref, titles_from_data=True) +pct_chart.y_axis.axId = 200 +pct_chart.y_axis.title = "涨跌幅(%)" + +# 组合 +price_chart += pct_chart +price_chart.y_axis.crosses = "max" +``` + +#### 坐标轴精修(研报级设置) + +**数值轴(Y轴)刻度设置** +```python +# 设置Y轴最大最小值(避免自动刻度导致的空白过多) +chart.y_axis.scaling.min = 10 # 根据实际数据调整 +chart.y_axis.scaling.max = 50 + +# 设置主要刻度单位 +chart.y_axis.majorUnit = 5 + +# 对于大数值(如成交量),建议数据预处理转换为"亿"或"万" +# 并在轴标题中注明单位 +chart.y_axis.title = "成交量(亿元)" +``` + +**日期轴(X轴)标签优化** +```python +from openpyxl.chart.axis import DateAxis +from openpyxl.drawing.text import Paragraph, ParagraphProperties, CharacterProperties + +# 设置X轴为日期轴 +chart.x_axis = DateAxis() +chart.x_axis.title = "日期" + +# 标签间隔(避免数据点过多导致重叠) +chart.x_axis.tickLblSkip = 5 # 每5个数据点显示一个标签 + +# 标签旋转(防止重叠) +from copy import deepcopy +from openpyxl.drawing.text import RichText +rt = RichText(p=[Paragraph( + pPr=ParagraphProperties(defRPr=CharacterProperties(sz=900)), + endParaRPr=CharacterProperties(sz=900) +)]) +chart.x_axis.txPr = rt +``` + +**坐标轴数字格式** +```python +# Y轴数字格式(保留2位小数) +chart.y_axis.numFmt = '0.00' + +# 百分比格式 +chart.y_axis.numFmt = '0.00%' +``` + +#### 数据标签与参考线(视觉增强) + +**数据标签设置** +```python +from openpyxl.chart.label import DataLabelList + +# 显示所有数据点的值 +chart.dataLabels = DataLabelList() +chart.dataLabels.showVal = True + +# 仅显示最后一个点(标注最新价)- 需要手动设置 +from openpyxl.chart.series import DataPoint +last_pt = DataPoint(idx=len(values)-1) +last_pt.graphicalProperties = GraphicalProperties(solidFill="FF0000") +series.data_points = [last_pt] +``` + +**参考线(均值/目标价)** +```python +from openpyxl.chart.series import SeriesLabel + +# 添加均值参考线(作为单独的数据系列) +mean_value = sum(values) / len(values) +ws.append([""] * (len(headers)-1) + ["均值"]) +for i in range(len(values)): + ws.append([""] * (len(headers)-1) + [mean_value]) + +mean_ref = Reference(ws, min_col=len(headers), min_row=len(values)+2, max_row=len(values)*2+1) +mean_series = Series(mean_ref, title="均值线") +chart.series.append(mean_series) +``` + +#### 财务数据可视化 + +**营收利润趋势图** +```python +# 数据准备 +ws.append(["报告期", "营业收入", "净利润"]) +for period, revenue, profit in financial_data: + ws.append([period, revenue/1e8, profit/1e8]) # 转换为亿元 + +# 组合图表 +chart = BarChart() +chart.type = "col" +chart.grouping = "clustered" +chart.title = "营业收入与净利润" +chart.y_axis.title = "金额(亿元)" + +data = Reference(ws, min_col=2, max_col=3, min_row=1, max_row=len(financial_data)+1) +cats = Reference(ws, min_col=1, min_row=2, max_row=len(financial_data)+1) +chart.add_data(data, titles_from_data=True) +chart.set_categories(cats) + +# 添加数据标签 +chart.dataLabels = DataLabelList() +chart.dataLabels.showVal = True +``` + +**ROE 柱状图** +```python +chart = BarChart() +chart.type = "col" +data = Reference(ws, min_col=2, min_row=1, max_row=5) +cats = Reference(ws, min_col=1, min_row=2, max_row=5) +chart.add_data(data, titles_from_data=True) +chart.set_categories(cats) +chart.title = "年度 ROE 对比" +``` + +#### Excel 文件与 Word 报告配合 + +**方案A:Excel 作为附件** +```python +# 生成带图表的 Excel 文件 +wb.save(f"{stock_name}_数据分析.xlsx") + +# 在 Word 中引用 +paragraph = doc.add_paragraph() +run = paragraph.add_run(f"详细数据及图表请参见附件《{stock_name}_数据分析.xlsx》") +set_font(run, "仿宋", 12) +``` + +**方案B:图表图片直接插入 Word(推荐)** +```python +import matplotlib.pyplot as plt +import matplotlib.dates as mdates +from docx.shared import Inches + +# 使用 Matplotlib 生成符合 GB/T 9704 字体要求的图表 +plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei'] +plt.rcParams['axes.unicode_minus'] = False + +fig, ax = plt.subplots(figsize=(8, 4.5)) +ax.plot(dates, prices, color='#4472C4', linewidth=1.5) +ax.set_title('股价走势', fontsize=12, fontweight='bold') +ax.set_xlabel('日期', fontsize=10) +ax.set_ylabel('价格(元)', fontsize=10) +ax.grid(True, alpha=0.3) + +# 保存为图片 +fig.savefig('chart.png', dpi=150, bbox_inches='tight') +plt.close() + +# 插入 Word +doc.add_picture('chart.png', width=Inches(6)) +``` + +**方案C:Word 原生图表(功能有限)** +```python +from docx.chart import Chart +from docx.enum.chart import XL_CHART_TYPE + +# 注意:docx.chart 功能较弱,仅支持基础图表类型 +# 如需复杂图表,建议使用方案A或B +``` + +#### 图表最佳实践 + +1. **数据准备**:使用 pandas 预处理数据,确保格式正确 +2. **图表选择**: + - 时间序列 → 折线图 + - 对比分析 → 柱状图 + - 价格+成交量 → 组合图 +3. **颜色规范**(A股标准): + - 上涨:红色(FF0000) + - 下跌:绿色(00B050,推荐)或(00AA00) + - 中性:蓝色(4472C4) +4. **数据单位**:图表标题或轴标题中注明单位(元、%、亿元等) +5. **数据来源**:图表下方注明数据来源,如"数据来源:Wind" + +#### 图表设置检查清单 + +| 检查项 | 专业要求 | 常见错误 | +|--------|----------|----------| +| **坐标轴标题** | 必须包含单位,如"价格(元)"、"比例(%)" | 漏写单位或单位不统一 | +| **色彩方案** | 涨红跌绿(A股规范),多序列使用高对比度商务色 | 使用 Excel 默认全家桶配色 | +| **网格线** | 仅保留水平主网格线,且设为浅灰色/虚线,或直接隐藏 | 粗黑实线网格,遮盖趋势线 | +| **字体统一** | 图表内字体需与 Word 正文匹配(建议微软雅黑或等线,9pt) | 默认小号宋体,缩放后模糊 | +| **数据源标注** | 图表下方须注明:数据来源:Wind,XX证券研究所 | 来源不明 | +| **标签间隔** | X轴数据点密集时需设置 `tickLblSkip` 防止重叠 | 标签重叠难以辨认 | +| **数值精度** | Y轴根据数据类型设置合适的小数位(价格2位,百分比1-2位) | 小数位过多或过少 | + +#### 高度封装工具函数 + +工具函数已封装在 `scripts/chart_utils.py` 中,使用时直接导入: + +```python +import sys +sys.path.insert(0, ".claude/skills/financial-report-writing/scripts") +from chart_utils import create_research_chart, create_price_volume_chart + +import pandas as pd + +# 准备数据 +df = pd.DataFrame({ + "date": ["2024-01", "2024-02", "2024-03"], + "close": [10.5, 11.2, 10.8] +}) + +# 生成股价走势图 +wb = create_research_chart( + df, + chart_type="line", + title="股价走势", + x_col="date", + y_cols="close", + y_axis_title="价格(元)", + show_last_label_only=True, + add_mean_line=True, + output_path="股价走势.xlsx" +) +``` + +**可用函数** + +| 函数 | 用途 | +|------|------| +| `create_research_chart()` | 通用图表(折线/柱状/多序列) | +| `create_price_volume_chart()` | 股价+成交量双Y轴组合图 | + +**`create_research_chart()` 主要参数** + +| 参数 | 说明 | 默认值 | +|------|------|--------| +| `df` | DataFrame数据源 | 必填 | +| `chart_type` | 图表类型:"line"/"bar" | "line" | +| `x_col` | X轴列名 | 必填 | +| `y_cols` | Y轴列名(支持列表) | 必填 | +| `y_axis_title` | Y轴标题(建议带单位) | "" | +| `y_format` | 数字格式 | "0.00" | +| `show_last_label_only` | 仅显示最后一个标签 | False | +| `add_mean_line` | 添加均值参考线 | False | +| `color_up/color_down` | 涨跌颜色 | FF0000/00B050 | +| `tick_skip` | X轴标签间隔 | 5 | + +完整函数定义和源码见:`scripts/chart_utils.py` + +## 相关工具 + +- **WindPy**:Wind金融终端Python API +- **python-docx**:Word文档操作库 +- **openpyxl**:Excel文件操作,支持原生图表 +- **pandas**:数据处理和分析 +- **numpy**:数值计算 +- **GB/T 9704-2012**:党政机关公文格式标准 + +## 参考资源 + +- WindPy SDK官方文档 +- python-docx API文档 +- GB/T 9704-2012国家公文格式标准 +- 券商研究报告格式规范 diff --git a/financial-report-writing/references/best_practices.md b/financial-report-writing/references/best_practices.md new file mode 100644 index 0000000..a356370 --- /dev/null +++ b/financial-report-writing/references/best_practices.md @@ -0,0 +1,337 @@ +# 金融研究报告最佳实践 + +## 目录 +1. [数据获取最佳实践](#数据获取最佳实践) +2. [分析框架](#分析框架) +3. [报告撰写规范](#报告撰写规范) +4. [常见陷阱](#常见陷阱) +5. [质量控制检查清单](#质量控制检查清单) +6. [案例分析](#案例分析) + +--- + +## 数据获取最佳实践 + +### WindPy 连接管理 +```python +# 推荐做法:使用上下文管理器 +with WindDataFetcher() as fetcher: + df = fetcher.get_daily_data(stock_code, start_date, end_date, fields) + # 自动处理连接关闭 + +# 不推荐:手动管理连接 +w.start() +# ... 代码 ... +w.stop() # 容易遗漏 +``` + +### 日期处理 +- 始终使用标准格式 `YYYY-MM-DD` +- 获取周线数据时,使用 `resample('W')` 而非手动计算 +- 处理交易日历,避免非交易日数据的干扰 + +### 数据校验 +```python +def validate_data(df, required_columns): + """数据质量检查""" + # 检查空值 + if df.isnull().any().any(): + print(f"警告:数据包含空值") + df = df.dropna() + + # 检查异常值 + for col in ['close', 'high', 'low']: + if col in df.columns: + if (df[col] <= 0).any(): + raise ValueError(f"{col} 包含非正值") + + # 检查必需字段 + missing_cols = set(required_columns) - set(df.columns) + if missing_cols: + raise ValueError(f"缺少必需字段: {missing_cols}") + + return df +``` + +--- + +## 分析框架 + +### 基本面分析维度 +1. **盈利能力** + - ROE(净资产收益率):\>15% 优秀,10-15% 良好 + - ROA(总资产收益率):\>8% 优秀 + - 毛利率:行业对比 + - 净利率:趋势分析 + +2. **成长能力** + - 营收增长率 + - 净利润增长率 + - 复合年均增长率(CAGR) + +3. **运营效率** + - 存货周转率 + - 应收账款周转率 + - 总资产周转率 + +4. **偿债能力** + - 资产负债率:<70% 安全 + - 流动比率:>1.5 较好 + - 速动比率:>1 较好 + +5. **现金流** + - 经营现金流净额 + - 自由现金流 + - 现金流/净利润 比率 + +### 技术面分析维度 +1. **趋势判断** + - 均线系统(MA5/10/20/60) + - 高低点连线 + - 趋势线斜率 + +2. **支撑阻力** + - 历史高低点 + - 密集成交区 + - 均线支撑 + +3. **波动特征** + - 历史波动率 + - 振幅统计 + - 布林带宽度 + +### 估值分析框架 +1. **相对估值** + - PE(市盈率):与历史/行业对比 + - PB(市净率):适用于重资产行业 + - PS(市销率):适用于成长型企业 + +2. **绝对估值** + - DCF模型 + - DDM模型 + +--- + +## 报告撰写规范 + +### 标题层级 +``` +一级标题:黑体三号(16pt),如"一、投资评级" +二级标题:黑体三号(16pt),如"(一)基本面分析" +三级标题:黑体小四(12pt),如"1. 盈利能力" +``` + +### 正文写作原则 +1. **数据先行**:先陈述事实数据,后给出分析结论 +2. **逻辑清晰**:使用"首先...其次...最后..."等逻辑连接词 +3. **客观中立**:避免使用"必然"、"一定"等绝对化表述 +4. **风险提示**:每个投资建议都应附带风险提示 + +### 表格规范 +- **表头**:黑体小四(12pt),居中 +- **数据**:仿宋小四(12pt),居中 +- **对齐**:日期左对齐,数值右对齐 +- **单位**:在表头或表注中明确标注 + +### 数字格式 +```python +# 价格:保留2位小数 +price_str = f"{price:.2f}元" + +# 百分比:保留2位小数,带%号 +pct_str = f"{pct:.2f}%" + +# 大数字:使用万/亿单位 +amount_wan = f"{amount / 10000:.0f}万元" +amount_yi = f"{amount / 100000000:.2f}亿元" +``` + +--- + +## 常见陷阱 + +### 数据陷阱 +1. **前复权与后复权混淆** + - 计算收益率时必须使用前复权数据 + - 查看历史价格时注意复权方式 + +2. **停牌数据处理** + - 停牌期间数据可能为空 + - 成交量为0需要特殊处理 + +3. **财报季节效应** + - Q4数据通常包含全年调整 + - 同比计算时注意去年同期特殊情况 + +### 分析陷阱 +1. **幸存者偏差** + - 只分析现有公司,忽视已退市公司 + - 行业对比时使用可比较样本 + +2. **过度拟合** + - 避免基于历史数据过度优化参数 + - 使用滚动回测验证策略 + +3. **相关性不等于因果性** + - 相关系数高不代表因果关系 + - 考虑第三变量的影响 + +### 报告陷阱 +1. **目标价计算过于乐观** + - 考虑多种情景(乐观/中性/悲观) + - 明确目标价有效期 + +2. **忽视流动性风险** + - 小市值股票注意流动性 + - 考虑交易成本影响 + +3. **风险提示流于形式** + - 针对具体股票的风险要具体化 + - 量化风险等级 + +--- + +## 质量控制检查清单 + +### 数据检查 +- [ ] 数据来源明确标注 +- [ ] 数据时间范围正确 +- [ ] 无缺失值或已说明处理方式 +- [ ] 价格数据使用正确复权方式 +- [ ] 财务数据使用最新财报 + +### 分析检查 +- [ ] ROE、PE等关键指标计算正确 +- [ ] 涨跌幅计算准确 +- [ ] 均线计算无未来函数 +- [ ] 支撑阻力位基于实际高低点 + +### 格式检查 +- [ ] 页面边距:37/35/28/26mm +- [ ] 标题使用黑体三号 +- [ ] 正文使用仿宋四号 +- [ ] 表格使用小四 +- [ ] 三线表格式正确 +- [ ] 页脚页码格式正确 + +### 内容检查 +- [ ] 核心提要包含4个要点 +- [ ] 投资评级明确 +- [ ] 目标价格合理且有依据 +- [ ] 风险提示具体充分 +- [ ] 无明显错别字 +- [ ] 语句通顺无歧义 + +--- + +## 案例分析 + +### 案例1:成长股分析报告 +**股票特征**:高ROE、高PE、快速增长 + +**分析重点**: +- 关注营收和利润增长持续性 +- 分析行业空间和竞争格局 +- 评估估值合理性(PEG指标) + +**报告结构**: +``` +核心提要 +├── 高速增长:营收/利润CAGR > 30% +├── 行业龙头:市场份额持续提升 +├── 估值偏高:PE高于行业平均 +└── 给予"增持"评级 + +一、投资评级 +├── 增持 +├── 目标价 +└── 风险提示:增速放缓风险 + +二、核心观点 +├── (一)基本面分析 +│ ├── 1. 成长性:营收增长35%,净利润增长42% +│ ├── 2. 盈利能力:ROE 22%,毛利率58% +│ └── 3. 估值:PE 45倍,PEG 1.1 +├── (二)技术面分析 +│ ├── 1. 趋势:长期上升通道 +│ ├── 2. 支撑:MA60支撑有效 +│ └── 3. 成交量:放量突破 +└── (三)投资建议 + └── 关注回调至支撑位买入机会 +``` + +### 案例2:价值股分析报告 +**股票特征**:低PE、高股息、稳定增长 + +**分析重点**: +- 关注股息率和分红稳定性 +- 分析护城河和竞争优势 +- 评估安全边际 + +**核心指标对比**: +| 指标 | 该公司 | 行业平均 | 评价 | +|------|--------|----------|------| +| PE TTM | 8.5 | 15.2 | 低估 | +| PB LF | 1.2 | 2.1 | 低估 | +| 股息率 | 5.2% | 2.8% | 优秀 | +| ROE | 14.5% | 12.3% | 良好 | + +### 案例3:周期股分析报告 +**股票特征**:业绩波动大、与宏观经济高度相关 + +**分析重点**: +- 关注行业景气度周期 +- 分析产能利用率和库存 +- 判断周期位置(顶部/底部/上升/下降) + +**风险提示模板**: +``` +风险提示: +1. 宏观经济下行风险 +2. 行业产能过剩风险 +3. 原材料价格波动风险 +4. 下游需求不及预期风险 +5. 政策监管变化风险 +``` + +--- + +## 附录:常用 Wind 字段速查 + +### 价格字段 +| 字段 | 说明 | 用途 | +|------|------|------| +| close | 收盘价 | 技术分析基础 | +| open | 开盘价 | 日K线 | +| high | 最高价 | 支撑阻力分析 | +| low | 最低价 | 支撑阻力分析 | +| volume | 成交量 | 量价分析 | +| amt | 成交额 | 流动性分析 | +| pct_chg | 涨跌幅 | 收益率计算 | + +### 技术指标字段 +| 字段 | 说明 | 用途 | +|------|------|------| +| ma5/ma10/ma20/ma60 | 均线 | 趋势判断 | +| pe_ttm | 市盈率TTM | 估值分析 | +| pb_lf | 市净率LF | 估值分析 | +| ps_ttm | 市销率TTM | 估值分析 | +| turnover | 换手率 | 活跃度分析 | + +### 财务字段 +| 字段 | 说明 | 用途 | +|------|------|------| +| roe_wgt | 加权ROE | 盈利能力 | +| roa2 | 总资产报酬率 | 盈利能力 | +| grossprofitmargin | 毛利率 | 盈利能力 | +| netprofitmargin | 净利率 | 盈利能力 | +| debt_to_assets | 资产负债率 | 偿债能力 | +| current_ratio | 流动比率 | 偿债能力 | + +--- + +## 版本记录 + +| 版本 | 日期 | 更新内容 | +|------|------|----------| +| 1.0 | 2026-02-06 | 初始版本,包含基础最佳实践 | diff --git a/financial-report-writing/scripts/analysis_engine.py b/financial-report-writing/scripts/analysis_engine.py new file mode 100644 index 0000000..da76eb9 --- /dev/null +++ b/financial-report-writing/scripts/analysis_engine.py @@ -0,0 +1,469 @@ +""" +投资分析引擎 +提供基本面分析、技术面分析和估值分析功能 +""" + +import pandas as pd +import numpy as np +from typing import Dict, List, Tuple, Optional +from dataclasses import dataclass +from enum import Enum + + +class InvestmentRating(Enum): + """投资评级""" + BUY = "买入" + ACCUMULATE = "增持" + HOLD = "持有" + REDUCE = "减持" + SELL = "卖出" + + +class RiskLevel(Enum): + """风险等级""" + LOW = "低风险" + LOW_MEDIUM = "中低风险" + MEDIUM = "中等风险" + MEDIUM_HIGH = "中高风险" + HIGH = "高风险" + + +@dataclass +class TechnicalAnalysis: + """技术分析结果""" + trend: str # 趋势判断 + support_level: float # 支撑位 + resistance_level: float # 阻力位 + volatility: float # 波动率 + ma_status: str # 均线状态 + technical_summary: str # 技术总结 + + +@dataclass +class FundamentalAnalysis: + """基本面分析结果""" + roe: float # 净资产收益率 + roe_comment: str # ROE评价 + pe_ttm: float # 市盈率TTM + pb_lf: float # 市净率LF + valuation_comment: str # 估值评价 + fundamental_summary: str # 基本面总结 + + +@dataclass +class InvestmentRecommendation: + """投资建议""" + rating: InvestmentRating + target_price: float + risk_level: RiskLevel + recommendation_text: str + key_factors: List[str] + + +class AnalysisEngine: + """ + 投资分析引擎 + """ + + # ROE评价标准 + ROE_THRESHOLDS = { + 'excellent': 20, + 'good': 15, + 'average': 10, + 'poor': 5 + } + + # PE评价标准(参考值,实际应根据行业调整) + PE_THRESHOLDS = { + 'undervalued': 15, + 'fair': 25, + 'overvalued': 35 + } + + # PB评价标准 + PB_THRESHOLDS = { + 'undervalued': 1.5, + 'fair': 3.0, + 'overvalued': 5.0 + } + + def __init__(self, price_df: pd.DataFrame, financial_data: Dict): + """ + 初始化分析引擎 + + Args: + price_df: 价格数据DataFrame + financial_data: 财务数据字典 + """ + self.price_df = price_df.copy() + self.financial_data = financial_data + + # 计算涨跌幅和收益率 + if 'pct_chg' not in self.price_df.columns and 'close' in self.price_df.columns: + self.price_df['pct_chg'] = self.price_df['close'].pct_change() * 100 + + def analyze_technical(self) -> TechnicalAnalysis: + """ + 技术分析 + + Returns: + TechnicalAnalysis对象 + """ + df = self.price_df + + # 计算均线 + if 'ma5' not in df.columns: + df['ma5'] = df['close'].rolling(window=5).mean() + if 'ma10' not in df.columns: + df['ma10'] = df['close'].rolling(window=10).mean() + if 'ma20' not in df.columns: + df['ma20'] = df['close'].rolling(window=20).mean() + + latest = df.iloc[-1] + + # 趋势判断 + if latest['close'] > latest['ma5'] > latest['ma10'] > latest['ma20']: + trend = "强势上涨" + elif latest['close'] > latest['ma5'] > latest['ma10']: + trend = "震荡上行" + elif latest['close'] < latest['ma5'] < latest['ma10'] < latest['ma20']: + trend = "强势下跌" + elif latest['close'] < latest['ma5'] < latest['ma10']: + trend = "震荡下行" + else: + trend = "震荡整理" + + # 计算支撑位和阻力位(基于近期高低点) + recent_data = df.tail(20) + support_level = recent_data['low'].min() + resistance_level = recent_data['high'].max() + + # 计算波动率 + returns = df['close'].pct_change().dropna() + volatility = returns.std() * np.sqrt(52) * 100 # 年化波动率 + + # 均线状态 + if latest['ma5'] > latest['ma20']: + ma_status = "多头排列" + elif latest['ma5'] < latest['ma20']: + ma_status = "空头排列" + else: + ma_status = "均线粘合" + + # 技术总结 + if trend in ["强势上涨", "震荡上行"] and ma_status == "多头排列": + technical_summary = "技术面呈上升趋势,建议关注回调买入机会。" + elif trend in ["强势下跌", "震荡下行"]: + technical_summary = "技术面呈下降趋势,建议观望或减仓。" + else: + technical_summary = "技术面呈震荡格局,建议高抛低吸。" + + return TechnicalAnalysis( + trend=trend, + support_level=round(support_level, 2), + resistance_level=round(resistance_level, 2), + volatility=round(volatility, 2), + ma_status=ma_status, + technical_summary=technical_summary + ) + + def analyze_fundamental(self) -> FundamentalAnalysis: + """ + 基本面分析 + + Returns: + FundamentalAnalysis对象 + """ + # 获取ROE + roe = self.financial_data.get('roe_wgt', 0) or self.financial_data.get('roe', 0) + + # ROE评价 + if roe >= self.ROE_THRESHOLDS['excellent']: + roe_comment = "ROE表现优异,公司盈利能力强劲" + elif roe >= self.ROE_THRESHOLDS['good']: + roe_comment = "ROE表现良好,盈利能力较强" + elif roe >= self.ROE_THRESHOLDS['average']: + roe_comment = "ROE处于行业平均水平" + else: + roe_comment = "ROE偏低,需关注盈利能力改善" + + # 获取PE和PB + pe_ttm = self.financial_data.get('pe_ttm', 0) or self.price_df['pe_ttm'].iloc[-1] if 'pe_ttm' in self.price_df.columns else 0 + pb_lf = self.financial_data.get('pb_lf', 0) or self.price_df['pb_lf'].iloc[-1] if 'pb_lf' in self.price_df.columns else 0 + + # 估值评价 + if pe_ttm <= self.PE_THRESHOLDS['undervalued'] and pb_lf <= self.PB_THRESHOLDS['undervalued']: + valuation_comment = "估值处于历史低位,具备较高安全边际" + elif pe_ttm <= self.PE_THRESHOLDS['fair']: + valuation_comment = "估值处于合理区间" + elif pe_ttm <= self.PE_THRESHOLDS['overvalued']: + valuation_comment = "估值略高,需关注业绩成长性" + else: + valuation_comment = "估值偏高,注意追高风险" + + # 基本面总结 + if roe >= self.ROE_THRESHOLDS['good'] and pe_ttm <= self.PE_THRESHOLDS['fair']: + fundamental_summary = "公司基本面健康,盈利能力强,估值合理,具备投资价值。" + elif roe >= self.ROE_THRESHOLDS['good']: + fundamental_summary = "公司盈利能力较强,但估值偏高,建议等待回调机会。" + else: + fundamental_summary = "公司基本面一般,建议谨慎观望。" + + return FundamentalAnalysis( + roe=round(roe, 2) if roe else 0, + roe_comment=roe_comment, + pe_ttm=round(pe_ttm, 2) if pe_ttm else 0, + pb_lf=round(pb_lf, 2) if pb_lf else 0, + valuation_comment=valuation_comment, + fundamental_summary=fundamental_summary + ) + + def generate_recommendation(self, + current_price: float, + fundamental: FundamentalAnalysis = None, + technical: TechnicalAnalysis = None) -> InvestmentRecommendation: + """ + 生成投资建议 + + Args: + current_price: 当前价格 + fundamental: 基本面分析结果 + technical: 技术面分析结果 + + Returns: + InvestmentRecommendation对象 + """ + if fundamental is None: + fundamental = self.analyze_fundamental() + if technical is None: + technical = self.analyze_technical() + + # 综合评分 + score = 0 + + # 基本面评分 + if fundamental.roe >= self.ROE_THRESHOLDS['excellent']: + score += 3 + elif fundamental.roe >= self.ROE_THRESHOLDS['good']: + score += 2 + elif fundamental.roe >= self.ROE_THRESHOLDS['average']: + score += 1 + + # 估值评分 + if fundamental.pe_ttm <= self.PE_THRESHOLDS['undervalued']: + score += 3 + elif fundamental.pe_ttm <= self.PE_THRESHOLDS['fair']: + score += 2 + elif fundamental.pe_ttm <= self.PE_THRESHOLDS['overvalued']: + score += 1 + + # 技术面评分 + if technical.trend in ["强势上涨", "震荡上行"]: + score += 2 + elif technical.trend == "震荡整理": + score += 1 + + # 风险等级 + if technical.volatility > 50: + risk_level = RiskLevel.HIGH + elif technical.volatility > 35: + risk_level = RiskLevel.MEDIUM_HIGH + elif technical.volatility > 25: + risk_level = RiskLevel.MEDIUM + elif technical.volatility > 15: + risk_level = RiskLevel.LOW_MEDIUM + else: + risk_level = RiskLevel.LOW + + # 目标价格计算(基于PE和支撑阻力) + target_price_pe = current_price * (self.PE_THRESHOLDS['fair'] / max(fundamental.pe_ttm, 1)) + target_price_resistance = technical.resistance_level * 1.1 + target_price = round((target_price_pe + target_price_resistance) / 2, 2) + + # 投资建议 + key_factors = [] + + if score >= 6: + rating = InvestmentRating.BUY + recommendation_text = f"综合基本面和技术面分析,该股投资价值较高。目标价{target_price}元,建议逢低买入。" + key_factors.append("盈利能力强劲,ROE表现优异") + elif score >= 4: + rating = InvestmentRating.ACCUMULATE + recommendation_text = f"公司基本面良好,建议关注回调机会逐步建仓。目标价{target_price}元。" + key_factors.append("基本面稳健,估值合理") + elif score >= 2: + rating = InvestmentRating.HOLD + recommendation_text = "公司基本面一般,当前估值合理,建议持有观望。" + key_factors.append("基本面中性,估值合理") + else: + rating = InvestmentRating.REDUCE + recommendation_text = "公司基本面较弱或估值偏高,建议谨慎或减仓。" + key_factors.append("基本面一般或估值偏高") + + if technical.trend in ["强势上涨", "震荡上行"]: + key_factors.append("技术面呈上升趋势") + elif technical.trend in ["强势下跌", "震荡下行"]: + key_factors.append("技术面呈下降趋势") + + if fundamental.pe_ttm <= self.PE_THRESHOLDS['undervalued']: + key_factors.append("估值处于历史低位") + + return InvestmentRecommendation( + rating=rating, + target_price=target_price, + risk_level=risk_level, + recommendation_text=recommendation_text, + key_factors=key_factors + ) + + def generate_core_summary(self, + fundamental: FundamentalAnalysis = None, + technical: TechnicalAnalysis = None, + recommendation: InvestmentRecommendation = None) -> List[str]: + """ + 生成核心提要要点 + + Returns: + 要点列表 + """ + if fundamental is None: + fundamental = self.analyze_fundamental() + if technical is None: + technical = self.analyze_technical() + if recommendation is None: + # 获取最新价格 + latest_price = self.price_df['close'].iloc[-1] if 'close' in self.price_df.columns else 0 + recommendation = self.generate_recommendation(latest_price, fundamental, technical) + + summary_points = [] + + # ROE要点 + if fundamental.roe > 0: + summary_points.append( + f"该公司最新净资产收益率(ROE)为{fundamental.roe}%,{fundamental.roe_comment}" + ) + + # 估值要点 + if fundamental.pe_ttm > 0: + summary_points.append( + f"当前市盈率(TTM)为{fundamental.pe_ttm}倍,{fundamental.valuation_comment}" + ) + + # 技术面要点 + summary_points.append( + f"技术面显示股价呈现{technical.trend}趋势,{technical.technical_summary}" + ) + + # 投资建议要点 + summary_points.append( + f"给予\"{recommendation.rating.value}\"评级,目标价格{recommendation.target_price}元,风险等级为{recommendation.risk_level.value}" + ) + + return summary_points + + def get_price_statistics(self) -> Dict: + """ + 获取价格统计数据 + + Returns: + 统计数据字典 + """ + df = self.price_df + + if len(df) == 0: + return {} + + return { + 'latest_price': round(df['close'].iloc[-1], 2), + 'highest_price': round(df['high'].max(), 2), + 'lowest_price': round(df['low'].min(), 2), + 'avg_price': round(df['close'].mean(), 2), + 'total_change': round(((df['close'].iloc[-1] / df['close'].iloc[0]) - 1) * 100, 2), + 'max_daily_gain': round(df['pct_chg'].max(), 2) if 'pct_chg' in df.columns else 0, + 'max_daily_loss': round(df['pct_chg'].min(), 2) if 'pct_chg' in df.columns else 0, + 'volatility': round(df['close'].pct_change().std() * np.sqrt(52) * 100, 2) + } + + +def perform_comprehensive_analysis(price_df: pd.DataFrame, + financial_data: Dict, + current_price: float = None) -> Dict: + """ + 执行综合分析并返回所有结果 + + Args: + price_df: 价格数据 + financial_data: 财务数据 + current_price: 当前价格(可选) + + Returns: + 包含所有分析结果的字典 + """ + engine = AnalysisEngine(price_df, financial_data) + + if current_price is None: + current_price = price_df['close'].iloc[-1] + + technical = engine.analyze_technical() + fundamental = engine.analyze_fundamental() + recommendation = engine.generate_recommendation(current_price, fundamental, technical) + summary_points = engine.generate_core_summary(fundamental, technical, recommendation) + price_stats = engine.get_price_statistics() + + return { + 'technical': technical, + 'fundamental': fundamental, + 'recommendation': recommendation, + 'summary_points': summary_points, + 'price_stats': price_stats + } + + +if __name__ == '__main__': + # 测试代码 + import numpy as np + + # 创建模拟数据 + dates = pd.date_range(start='2025-01-01', periods=60, freq='W') + np.random.seed(42) + prices = 30 + np.cumsum(np.random.randn(60) * 0.5) + + price_df = pd.DataFrame({ + 'date': dates, + 'open': prices * 0.98, + 'high': prices * 1.03, + 'low': prices * 0.97, + 'close': prices, + 'volume': np.random.randint(1000000, 5000000, 60), + 'pe_ttm': 25 + np.random.randn(60) * 2, + 'pb_lf': 3 + np.random.randn(60) * 0.2 + }) + + financial_data = { + 'roe_wgt': 16.5, + 'pe_ttm': 25.3, + 'pb_lf': 3.1, + 'sec_name': '测试公司' + } + + # 执行分析 + results = perform_comprehensive_analysis(price_df, financial_data) + + print("=== 技术分析 ===") + print(f"趋势: {results['technical'].trend}") + print(f"支撑位: {results['technical'].support_level}") + print(f"阻力位: {results['technical'].resistance_level}") + + print("\n=== 基本面分析 ===") + print(f"ROE: {results['fundamental'].roe}%") + print(f"PE TTM: {results['fundamental'].pe_ttm}") + print(f"PB LF: {results['fundamental'].pb_lf}") + + print("\n=== 投资建议 ===") + print(f"评级: {results['recommendation'].rating.value}") + print(f"目标价: {results['recommendation'].target_price}元") + print(f"风险等级: {results['recommendation'].risk_level.value}") + + print("\n=== 核心提要 ===") + for i, point in enumerate(results['summary_points'], 1): + print(f"{i}. {point}") diff --git a/financial-report-writing/scripts/chart_utils.py b/financial-report-writing/scripts/chart_utils.py new file mode 100644 index 0000000..9371889 --- /dev/null +++ b/financial-report-writing/scripts/chart_utils.py @@ -0,0 +1,311 @@ +""" +金融研究报告图表工具函数 +============================ + +提供符合研报规范的高度封装图表生成函数。 + +Usage: + from chart_utils import create_research_chart, create_price_volume_chart + + wb = create_research_chart( + df, + chart_type="line", + title="股价走势", + x_col="date", + y_cols="close", + output_path="report.xlsx" + ) +""" + +from openpyxl import Workbook +from openpyxl.chart import LineChart, BarChart, Reference +from openpyxl.chart.axis import DateAxis +from openpyxl.chart.label import DataLabelList +from openpyxl.chart.series import DataPoint, Series +from openpyxl.chart.shapes import GraphicalProperties +import pandas as pd +from typing import Optional, List, Union + + +def create_research_chart( + df: pd.DataFrame, + chart_type: str = "line", + title: str = "", + x_col: str = None, + y_cols: Union[str, List[str]] = None, + y_axis_title: str = "", + x_axis_title: str = "", + y_format: str = "0.00", + show_data_labels: bool = False, + show_last_label_only: bool = False, + add_mean_line: bool = False, + color_up: str = "FF0000", + color_down: str = "00B050", + tick_skip: int = 5, + height: int = 10, + width: int = 20, + output_path: str = None +) -> Workbook: + """ + 生成符合研报规范的 Excel 图表 + + Parameters: + ----------- + df : pd.DataFrame + 数据源,必须包含 x_col 和 y_cols 指定的列 + chart_type : str + 图表类型:"line"(折线图), "bar"(柱状图) + title : str + 图表标题 + x_col : str + X轴数据列名(日期/类别) + y_cols : str or List[str] + Y轴数据列名,支持多序列 + y_axis_title : str + Y轴标题(建议带单位,如"价格(元)") + x_axis_title : str + X轴标题 + y_format : str + Y轴数字格式,默认"0.00",百分比用"0.00%" + show_data_labels : bool + 是否显示所有数据标签 + show_last_label_only : bool + 是否仅显示最后一个数据点的标签(标注最新值) + add_mean_line : bool + 是否添加均值参考线 + color_up : str + 上涨/正值颜色(默认红色 FF0000) + color_down : str + 下跌/负值颜色(默认绿色 00B050) + tick_skip : int + X轴标签间隔(防止重叠) + height : int + 图表高度(厘米) + width : int + 图表宽度(厘米) + output_path : str + 输出文件路径,None则返回Workbook对象 + + Returns: + -------- + Workbook : openpyxl Workbook对象 + + Examples: + --------- + >>> # 股价走势图 + >>> df = pd.DataFrame({ + ... 'date': ['2024-01', '2024-02', '2024-03'], + ... 'close': [10.5, 11.2, 10.8] + ... }) + >>> wb = create_research_chart( + ... df, chart_type="line", + ... title="股价走势", + ... x_col="date", y_cols="close", + ... y_axis_title="价格(元)", + ... show_last_label_only=True, + ... output_path="股价走势.xlsx" + ... ) + + >>> # 营收利润对比图 + >>> wb = create_research_chart( + ... df, chart_type="bar", + ... title="营业收入与净利润", + ... x_col="period", y_cols=["revenue", "profit"], + ... y_axis_title="金额(亿元)", + ... y_format="0.0" + ... ) + """ + # 标准化 y_cols + if isinstance(y_cols, str): + y_cols = [y_cols] + + # 创建工作簿 + wb = Workbook() + ws = wb.active + ws.title = "数据" + + # 写入表头 + headers = [x_col] + y_cols + ws.append(headers) + + # 写入数据 + for _, row in df.iterrows(): + ws.append([row[col] for col in headers]) + + # 创建图表 + if chart_type == "line": + chart = LineChart() + elif chart_type == "bar": + chart = BarChart() + chart.type = "col" + chart.grouping = "clustered" + else: + chart = LineChart() + + # 设置标题和轴 + chart.title = title + chart.y_axis.title = y_axis_title + chart.x_axis.title = x_axis_title + + # 设置图表尺寸 + chart.height = height + chart.width = width + + # 设置数据区域 + data_start_row = 1 + data_end_row = len(df) + 1 + + for i, y_col in enumerate(y_cols): + col_idx = headers.index(y_col) + 1 + data_ref = Reference(ws, min_col=col_idx, min_row=data_start_row, + max_row=data_end_row) + cats_ref = Reference(ws, min_col=1, min_row=2, max_row=data_end_row) + + chart.add_data(data_ref, titles_from_data=True) + if i == 0: + chart.set_categories(cats_ref) + + # 设置Y轴格式 + chart.y_axis.numFmt = y_format + + # 设置X轴标签间隔 + chart.x_axis.tickLblSkip = tick_skip + + # 网格线设置(仅保留水平主网格线) + chart.x_axis.majorGridlines = None + + # 数据标签设置 + if show_data_labels: + chart.dataLabels = DataLabelList() + chart.dataLabels.showVal = True + + # 仅显示最后一个标签 + if show_last_label_only and chart.series: + series = chart.series[0] + last_idx = len(df) - 1 + pt = DataPoint(idx=last_idx) + pt.graphicalProperties = GraphicalProperties(solidFill=color_up) + series.data_points = [pt] + + # 柱状图涨跌着色 + if chart_type == "bar" and len(y_cols) == 1: + series = chart.series[0] + values = df[y_cols[0]].tolist() + for i, val in enumerate(values): + pt = DataPoint(idx=i) + fill_color = color_up if val >= 0 else color_down + pt.graphicalProperties = GraphicalProperties(solidFill=fill_color) + series.data_points.append(pt) + + # 添加均值参考线 + if add_mean_line and chart.series: + series = chart.series[0] + values = df[y_cols[0]].tolist() + mean_val = sum(values) / len(values) + + # 在工作表添加均值列 + mean_col = len(headers) + 1 + ws.cell(row=1, column=mean_col, value="均值") + for i in range(2, data_end_row + 1): + ws.cell(row=i, column=mean_col, value=mean_val) + + mean_ref = Reference(ws, min_col=mean_col, min_row=1, max_row=data_end_row) + mean_series = Series(mean_ref, title="均值") + chart.series.append(mean_series) + + # 图例位置(多序列时显示在底部) + if len(y_cols) > 1 or add_mean_line: + chart.legend.position = "b" + else: + chart.legend = None + + # 添加图表到工作表 + ws.add_chart(chart, "E2") + + # 添加数据来源注脚 + ws["A" + str(data_end_row + 2)] = "数据来源:Wind" + + # 保存或返回 + if output_path: + wb.save(output_path) + + return wb + + +def create_price_volume_chart( + df: pd.DataFrame, + title: str = "股价与成交量", + date_col: str = "date", + price_col: str = "close", + volume_col: str = "volume", + output_path: str = None +) -> Workbook: + """ + 生成股价+成交量组合图表(双Y轴) + + Parameters: + ----------- + df : pd.DataFrame + 包含日期、收盘价、成交量的数据 + title : str + 图表标题 + date_col, price_col, volume_col : str + 各数据列名 + output_path : str + 输出路径 + + Returns: + -------- + Workbook + """ + wb = Workbook() + ws = wb.active + ws.title = "数据" + + # 写入数据 + ws.append([date_col, price_col, volume_col]) + for _, row in df.iterrows(): + ws.append([row[date_col], row[price_col], row[volume_col]]) + + # 创建价格折线图(主Y轴) + price_chart = LineChart() + price_chart.title = title + price_chart.y_axis.title = "价格(元)" + price_chart.x_axis.title = date_col + + price_ref = Reference(ws, min_col=2, min_row=1, max_row=len(df)+1) + cats_ref = Reference(ws, min_col=1, min_row=2, max_row=len(df)+1) + + price_chart.add_data(price_ref, titles_from_data=True) + price_chart.set_categories(cats_ref) + price_chart.y_axis.numFmt = "0.00" + price_chart.x_axis.tickLblSkip = max(1, len(df) // 10) + + # 创建成交量柱状图(次Y轴) + vol_chart = BarChart() + vol_chart.type = "col" + vol_chart.grouping = "clustered" + vol_chart.y_axis.axId = 200 + vol_chart.y_axis.title = "成交量(手)" + + vol_ref = Reference(ws, min_col=3, min_row=1, max_row=len(df)+1) + vol_chart.add_data(vol_ref, titles_from_data=True) + + # 组合图表 + price_chart += vol_chart + price_chart.y_axis.crosses = "max" + + # 尺寸设置 + price_chart.height = 10 + price_chart.width = 20 + + # 隐藏网格线 + price_chart.x_axis.majorGridlines = None + + ws.add_chart(price_chart, "E2") + ws["A" + str(len(df) + 3)] = "数据来源:Wind" + + if output_path: + wb.save(output_path) + + return wb diff --git a/financial-report-writing/scripts/data_fetcher.py b/financial-report-writing/scripts/data_fetcher.py new file mode 100644 index 0000000..46255a6 --- /dev/null +++ b/financial-report-writing/scripts/data_fetcher.py @@ -0,0 +1,265 @@ +""" +Wind 数据获取模块 +提供统一的接口获取股票历史数据、财务数据和技术指标 +""" + +from WindPy import w +import pandas as pd +from datetime import datetime, timedelta +from typing import List, Dict, Optional, Tuple + + +class WindDataFetcher: + """Wind数据获取器""" + + def __init__(self): + """初始化Wind连接""" + self._start() + + def _start(self): + """启动Wind连接""" + result = w.start() + if result.ErrorCode != 0: + raise ConnectionError(f"Wind连接失败: {result.Data}") + print("Wind连接成功") + + def _stop(self): + """关闭Wind连接""" + w.stop() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self._stop() + + @staticmethod + def _handle_wsd_result(result, field_names): + """处理wsd返回结果""" + if result.ErrorCode != 0: + raise ValueError(f"数据获取失败: {result.Data}") + + # 转换为DataFrame + data_dict = dict(zip(field_names, result.Data)) + df = pd.DataFrame(data_dict, columns=field_names) + df['date'] = result.Times + return df + + def get_daily_data(self, + stock_code: str, + start_date: str, + end_date: str, + fields: List[str]) -> pd.DataFrame: + """ + 获取日线数据 + + Args: + stock_code: 股票代码,如 '300866.SZ' + start_date: 开始日期,格式 'YYYY-MM-DD' + end_date: 结束日期,格式 'YYYY-MM-DD' + fields: 数据字段列表 + + Returns: + DataFrame包含日期和指定字段的数据 + """ + result = w.wsd(stock_code, fields, start_date, end_date) + return self._handle_wsd_result(result, fields) + + def get_stock_basic(self, stock_code: str) -> Dict: + """ + 获取股票基本信息 + + Args: + stock_code: 股票代码 + + Returns: + 包含股票名称、行业、上市日期等信息的字典 + """ + fields = ['sec_name', 'industry', 'ipo_date', 'list_date', 'trade_status'] + result = w.wss(stock_code, fields) + + if result.ErrorCode != 0: + raise ValueError(f"基本信息获取失败: {result.Data}") + + return dict(zip(fields, result.Data[0])) + + def get_technical_indicators(self, + stock_code: str, + start_date: str, + end_date: str) -> pd.DataFrame: + """ + 获取技术指标数据 + + Args: + stock_code: 股票代码 + start_date: 开始日期 + end_date: 结束日期 + + Returns: + DataFrame包含MA、成交量等技术指标 + """ + fields = [ + 'close', 'open', 'high', 'low', 'volume', 'amt', 'pct_chg', + 'ma5', 'ma10', 'ma20', 'ma60', + 'pe_ttm', 'pb_lf', 'ps_ttm', 'pcf_ncf_ttm' + ] + return self.get_daily_data(stock_code, start_date, end_date, fields) + + def get_financial_data(self, + stock_code: str, + report_date: str = '') -> Dict: + """ + 获取财务数据 + + Args: + stock_code: 股票代码 + report_date: 报告期,格式 'YYYYMMDD',默认最新 + + Returns: + 包含ROE、营收、净利润等财务指标的字典 + """ + fields = [ + 'roe_wgt', 'roa2', 'net_profit_to_profit', 'total_revenue_ps', + 'profit_to_gr', 'ebit_ps', 'assets_to_eqt', 'debt_to_assets', + 'current_ratio', 'quick_ratio', 'op_income_to_revenue' + ] + + result = w.wss(stock_code, fields, 'rptDate={}'.format(report_date)) + + if result.ErrorCode != 0: + raise ValueError(f"财务数据获取失败: {result.Data}") + + return dict(zip(fields, result.Data[0])) + + def get_weekly_data(self, + stock_code: str, + start_date: str, + end_date: str, + fields: List[str] = None) -> pd.DataFrame: + """ + 获取并汇总周线数据 + + Args: + stock_code: 股票代码 + start_date: 开始日期 + end_date: 结束日期 + fields: 数据字段,默认为基本OHLCV + + Returns: + DataFrame包含周线数据 + """ + if fields is None: + fields = ['close', 'open', 'high', 'low', 'volume', 'amt', 'pct_chg'] + + # 获取日线数据 + df_daily = self.get_daily_data(stock_code, start_date, end_date, fields) + + # 转换为周线数据 + df_daily.set_index('date', inplace=True) + df_weekly = df_daily.resample('W').agg({ + 'open': 'first', + 'high': 'max', + 'low': 'min', + 'close': 'last', + 'volume': 'sum', + 'amt': 'sum', + 'pct_chg': 'sum' # 周涨跌幅近似为日涨跌幅之和 + }).dropna() + + df_weekly.reset_index(inplace=True) + return df_weekly + + def get_stock_list_by_sector(self, sector_name: str, limit: int = 10) -> List[str]: + """ + 获取某行业的龙头股票列表 + + Args: + sector_name: 行业名称 + limit: 返回数量 + + Returns: + 股票代码列表 + """ + # 使用Wind的行业板块数据 + fields = ['sec_name', 'ipo_date'] + # 这里简化处理,实际需要根据Wind板块接口调整 + print(f"注意: 行业股票列表获取需要根据实际Wind板块接口实现") + return [] + + def calculate_volatility(self, df: pd.DataFrame, annualized: bool = True) -> float: + """ + 计算波动率 + + Args: + df: 包含收盘价的DataFrame + annualized: 是否年化 + + Returns: + 波动率(百分比) + """ + returns = df['close'].pct_change().dropna() + volatility = returns.std() + + if annualized: + # 日数据年化系数:sqrt(252),周数据年化系数:sqrt(52) + n = len(df) + if n > 250: # 日线数据 + volatility *= 252 ** 0.5 + else: # 周线数据 + volatility *= 52 ** 0.5 + + return volatility * 100 # 转换为百分比 + + +# 便捷函数 +def fetch_stock_report_data(stock_code: str, + days_back: int = 90, + weekly: bool = True) -> Tuple[pd.DataFrame, Dict]: + """ + 获取股票报告所需的数据 + + Args: + stock_code: 股票代码 + days_back: 获取多少天的数据 + weekly: 是否为周线数据 + + Returns: + (price_df, financial_dict) 价格数据和财务数据 + """ + end_date = datetime.now().strftime('%Y-%m-%d') + start_date = (datetime.now() - timedelta(days=days_back)).strftime('%Y-%m-%d') + + with WindDataFetcher() as fetcher: + # 获取价格数据 + if weekly: + price_df = fetcher.get_weekly_data(stock_code, start_date, end_date) + else: + price_df = fetcher.get_technical_indicators(stock_code, start_date, end_date) + + # 获取财务数据 + financial_data = fetcher.get_financial_data(stock_code) + + # 获取基本信息 + basic_info = fetcher.get_stock_basic(stock_code) + + # 合并财务信息 + financial_data.update(basic_info) + + return price_df, financial_data + + +if __name__ == '__main__': + # 测试代码 + with WindDataFetcher() as fetcher: + # 示例:获取某股票的数据 + code = '300866.SZ' + start = '2025-01-01' + end = '2026-02-06' + + print(f"获取 {code} 的日线数据...") + df = fetcher.get_technical_indicators(code, start, end) + print(df.tail()) + + print(f"\n获取 {code} 的基本信息...") + info = fetcher.get_stock_basic(code) + print(info) diff --git a/financial-report-writing/scripts/document_formatter.py b/financial-report-writing/scripts/document_formatter.py new file mode 100644 index 0000000..cefa9ba --- /dev/null +++ b/financial-report-writing/scripts/document_formatter.py @@ -0,0 +1,377 @@ +""" +Word文档格式化模块 +按照GB/T 9704-2012标准格式化金融研究报告 +""" + +from docx import Document +from docx.shared import Pt, Mm, RGBColor +from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_LINE_SPACING +from docx.oxml.ns import qn +from docx.oxml import OxmlElement + + +class GBT9704Formatter: + """ + GB/T 9704-2012党政机关公文格式化器 + """ + + # 字体映射(号数 -> 磅值) + FONT_SIZES = { + '三号': 16, + '四号': 14, + '小四': 12, + '五号': 10.5 + } + + def __init__(self, doc: Document): + """ + 初始化格式化器 + + Args: + doc: Document对象 + """ + self.doc = doc + self._setup_page() + + def _setup_page(self): + """设置页面格式""" + for section in self.doc.sections: + # 页面边距(单位:毫米) + section.top_margin = Mm(37) + section.bottom_margin = Mm(35) + section.left_margin = Mm(28) + section.right_margin = Mm(26) + + def set_font(self, run, font_name: str, size: int = None, bold: bool = None, color: RGBColor = None): + """ + 设置字体 + + Args: + run: Run对象 + font_name: 字体名称(中文字体) + size: 字号(磅值),如 16, 14, 12 + bold: 是否加粗 + color: 字体颜色 + """ + run.font.name = font_name + run._element.rPr.rFonts.set(qn('w:eastAsia'), font_name) + + if size is not None: + run.font.size = Pt(size) + if bold is not None: + run.font.bold = bold + if color is not None: + run.font.color.rgb = color + + def add_heading(self, text: str, level: int = 1, font_name: str = '黑体', size: int = 16): + """ + 添加标题 + + Args: + text: 标题文本 + level: 标题级别(1-3) + font_name: 字体名称 + size: 字号 + + Returns: + Paragraph对象 + """ + if level == 1: + heading = self.doc.add_heading(text, level=1) + run = heading.runs[0] + self.set_font(run, font_name, size, bold=True) + heading.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY + heading.paragraph_format.space_before = Pt(0) + heading.paragraph_format.space_after = Pt(0) + return heading + else: + # 二级、三级标题使用"一、"、"(一)"等格式 + prefix_map = {1: '一、', 2: '(一)', 3: '1.'} + prefix = prefix_map.get(level, '') + + paragraph = self.doc.add_paragraph(f"{prefix}{text}") + run = paragraph.runs[0] + self.set_font(run, font_name, size, bold=True) + + # 段落格式 + paragraph.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY + paragraph.paragraph_format.space_before = Pt(0) + paragraph.paragraph_format.space_after = Pt(0) + paragraph.paragraph_format.line_spacing = Pt(25) + paragraph.paragraph_format.line_spacing_rule = WD_LINE_SPACING.EXACTLY + + return paragraph + + def add_paragraph(self, text: str, + font_name: str = '仿宋', + size: int = 14, + first_line_indent: bool = True, + alignment: str = 'justify'): + """ + 添加正文段落 + + Args: + text: 段落文本 + font_name: 字体名称 + size: 字号(磅值) + first_line_indent: 是否首行缩进 + alignment: 对齐方式('left', 'center', 'right', 'justify') + + Returns: + Paragraph对象 + """ + paragraph = self.doc.add_paragraph(text) + run = paragraph.runs[0] + self.set_font(run, font_name, size) + + # 段落格式 + alignment_map = { + 'left': WD_ALIGN_PARAGRAPH.LEFT, + 'center': WD_ALIGN_PARAGRAPH.CENTER, + 'right': WD_ALIGN_PARAGRAPH.RIGHT, + 'justify': WD_ALIGN_PARAGRAPH.JUSTIFY + } + paragraph.paragraph_format.alignment = alignment_map.get(alignment, WD_ALIGN_PARAGRAPH.JUSTIFY) + + if first_line_indent: + # 首行缩进2字符(28pt) + paragraph.paragraph_format.first_line_indent = Pt(28) + + # 行距固定值28pt + paragraph.paragraph_format.line_spacing = Pt(28) + paragraph.paragraph_format.line_spacing_rule = WD_LINE_SPACING.EXACTLY + + # 段前段后距为0 + paragraph.paragraph_format.space_before = Pt(0) + paragraph.paragraph_format.space_after = Pt(0) + + return paragraph + + def add_bullet_list(self, items: List[str], font_name: str = '仿宋', size: int = 14): + """ + 添加项目符号列表 + + Args: + items: 列表项 + font_name: 字体名称 + size: 字号 + """ + for item in items: + paragraph = self.doc.add_paragraph(item, style='List Bullet') + run = paragraph.runs[0] + self.set_font(run, font_name, size) + paragraph.paragraph_format.line_spacing = Pt(28) + paragraph.paragraph_format.line_spacing_rule = WD_LINE_SPACING.EXACTLY + paragraph.paragraph_format.space_before = Pt(0) + paragraph.paragraph_format.space_after = Pt(0) + + def add_three_line_table(self, data: List[List[str]], + headers: List[str], + font_name: str = '仿宋', + size: int = 12): + """ + 添加三线表 + + Args: + data: 表格数据(二维列表) + headers: 表头 + font_name: 字体名称 + size: 字号 + + Returns: + Table对象 + """ + # 创建表格 + table = self.doc.add_table(rows=len(data) + 1, cols=len(headers)) + self._set_three_line_table_borders(table) + + # 设置表头 + header_cells = table.rows[0].cells + for i, header in enumerate(headers): + cell = header_cells[i] + self._set_cell_font(cell, header, font_name, size, bold=True) + cell.paragraphs[0].paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER + + # 设置数据行 + for row_idx, row_data in enumerate(data, start=1): + cells = table.rows[row_idx].cells + for i, cell_data in enumerate(row_data): + cell = cells[i] + self._set_cell_font(cell, str(cell_data), font_name, size) + cell.paragraphs[0].paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER + + return table + + def _set_three_line_table_borders(self, table): + """设置三线表边框""" + tblPr = table._tbl.tblPr + tblBorders = OxmlElement('w:tblBorders') + + # 顶底边框 1.5pt (sz=18) + for pos in ['top', 'bottom']: + border = OxmlElement(f'w:{pos}') + border.set(qn('w:val'), 'single') + border.set(qn('w:sz'), '18') + border.set(qn('w:color'), 'auto') + tblBorders.append(border) + + # 内部横线 0.75pt (sz=9) + for pos in ['insideH']: + border = OxmlElement(f'w:{pos}') + border.set(qn('w:val'), 'single') + border.set(qn('w:sz'), '9') + border.set(qn('w:color'), 'auto') + tblBorders.append(border) + + # 无左右和竖线 + for pos in ['left', 'right', 'insideV']: + border = OxmlElement(f'w:{pos}') + border.set(qn('w:val'), 'none') + tblBorders.append(border) + + tblPr.append(tblBorders) + + def _set_cell_font(self, cell, text: str, font_name: str, size: int, bold: bool = False): + """设置单元格字体""" + cell.text = '' + run = cell.paragraphs[0].add_run(text) + self.set_font(run, font_name, size, bold=bold) + + def add_page_number_footer(self): + """添加页码页脚""" + for section in self.doc.sections: + footer = section.footer + + # 添加页码段落 + p = footer.paragraphs[0] if footer.paragraphs else footer.add_paragraph() + p.alignment = WD_ALIGN_PARAGRAPH.CENTER + + # 页码格式:— 1 — + self.add_footer_run(p, '— ', font_name='仿宋', size=12) + + # 添加页码字段 + self.add_page_number_field(p) + + self.add_footer_run(p, ' ', font_name='仿宋', size=12) + self.add_footer_run(p, '—', font_name='仿宋', size=12) + + def add_footer_run(self, paragraph, text: str, font_name: str, size: int): + """添加页脚run""" + run = paragraph.add_run(text) + self.set_font(run, font_name, size) + + def add_page_number_field(self, paragraph): + """添加页码字段""" + fldChar1 = OxmlElement('w:fldChar') + fldChar1.set(qn('w:fldCharType'), 'begin') + + instrText = OxmlElement('w:instrText') + instrText.set(qn('xml:space'), 'preserve') + instrText.text = "PAGE" + + fldChar2 = OxmlElement('w:fldChar') + fldChar2.set(qn('w:fldCharType'), 'end') + + run = paragraph.add_run() + run._r.append(fldChar1) + run._r.append(instrText) + run._r.append(fldChar2) + + self.set_font(run, '仿宋', 12) + + def add_cover_page(self, title: str, organization: str, date_str: str): + """ + 添加封面页 + + Args: + title: 报告标题 + organization: 机构名称 + date_str: 日期 + """ + # 标题 + paragraph = self.doc.add_paragraph() + run = paragraph.add_run(title) + self.set_font(run, '黑体', 22, bold=True) + paragraph.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER + paragraph.paragraph_format.space_before = Pt(100) + paragraph.paragraph_format.space_after = Pt(50) + + # 机构名称 + paragraph = self.doc.add_paragraph() + run = paragraph.add_run(organization) + self.set_font(run, '黑体', 16) + paragraph.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER + paragraph.paragraph_format.space_after = Pt(20) + + # 日期 + paragraph = self.doc.add_paragraph() + run = paragraph.add_run(date_str) + self.set_font(run, '黑体', 16) + paragraph.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.CENTER + + # 添加分页符 + self.doc.add_page_break() + + def add_data_source_footnote(self, text: str = "数据来源:Wind资讯"): + """ + 添加数据来源注脚 + + Args: + text: 注脚文本 + """ + paragraph = self.doc.add_paragraph() + run = paragraph.add_run(text) + self.set_font(run, '仿宋', 12) + paragraph.paragraph_format.alignment = WD_ALIGN_PARAGRAPH.RIGHT + + +# 便捷函数 +def create_formatted_document() -> Tuple[Document, GBT9704Formatter]: + """ + 创建格式化的Word文档 + + Returns: + (Document, GBT9704Formatter) 文档对象和格式化器 + """ + doc = Document() + formatter = GBT9704Formatter(doc) + return doc, formatter + + +if __name__ == '__main__': + # 测试代码 + doc, formatter = create_formatted_document() + + # 添加封面 + formatter.add_cover_page( + '某某股票投资研究报告', + '某某证券研究所', + '2026年2月6日' + ) + + # 添加核心提要 + formatter.add_heading('核心提要', level=1) + formatter.add_bullet_list([ + '该公司2025年三季度净资产收益率(ROE)为15.2%,盈利能力较强', + '当前市盈率(TTM)为25.3倍,略高于行业平均水平', + '技术面显示股价呈现震荡上行趋势,建议关注回调机会', + '给予"买入"评级,目标价格35元' + ]) + + # 添加投资评级表格 + formatter.add_heading('一、投资评级', level=1) + data = [ + ['买入', '35.00元', '2026年12月31日', '中风险'] + ] + formatter.add_three_line_table( + data, + ['投资建议', '目标价格', '有效期', '风险等级'] + ) + + # 添加数据来源 + formatter.add_data_source_footnote() + + # 保存文档 + output_path = 'test_report.docx' + doc.save(output_path) + print(f"测试报告已保存到: {output_path}") diff --git a/financial-report-writing/scripts/generate_report.py b/financial-report-writing/scripts/generate_report.py new file mode 100644 index 0000000..2fcf5d1 --- /dev/null +++ b/financial-report-writing/scripts/generate_report.py @@ -0,0 +1,313 @@ +""" +金融研究报告生成器 +整合数据获取、分析和文档生成功能,一键生成完整报告 +""" + +import sys +import argparse +from datetime import datetime, timedelta +from pathlib import Path +from typing import Optional + +# 添加脚本目录到路径 +sys.path.insert(0, str(Path(__file__).parent)) + +from docx import Document +from docx.shared import Pt +from docx.enum.text import WD_ALIGN_PARAGRAPH + +from data_fetcher import WindDataFetcher, fetch_stock_report_data +from document_formatter import create_formatted_document, GBT9704Formatter +from analysis_engine import perform_comprehensive_analysis + + +class ReportGenerator: + """ + 金融研究报告生成器 + """ + + def __init__(self): + self.doc = None + self.formatter = None + self.analysis_results = None + + def generate_report(self, + stock_code: str, + stock_name: str = None, + organization: str = "某某证券研究所", + author: str = "", + include_cover: bool = True, + output_path: str = None) -> str: + """ + 生成完整的投资研究报告 + + Args: + stock_code: 股票代码,如 '300866.SZ' + stock_name: 股票名称(如不提供则自动获取) + organization: 研究机构名称 + author: 分析师姓名 + include_cover: 是否包含封面 + output_path: 输出文件路径 + + Returns: + 生成的文件路径 + """ + print(f"开始生成 {stock_code} 的投资研究报告...") + + # 1. 获取数据 + print("正在获取股票数据...") + try: + price_df, financial_data = fetch_stock_report_data(stock_code, days_back=90, weekly=True) + except Exception as e: + print(f"数据获取失败: {e}") + raise + + # 如果未提供股票名称,从财务数据获取 + if stock_name is None: + stock_name = financial_data.get('sec_name', stock_code) + + print(f"获取到 {len(price_df)} 条周线数据") + + # 2. 执行分析 + print("正在执行投资分析...") + current_price = price_df['close'].iloc[-1] + self.analysis_results = perform_comprehensive_analysis( + price_df, financial_data, current_price + ) + + # 3. 创建文档 + print("正在生成Word文档...") + self.doc, self.formatter = create_formatted_document() + + # 4. 添加封面(可选) + if include_cover: + self._add_cover_page(stock_name, organization) + + # 5. 添加免责声明 + self._add_disclaimer() + + # 6. 添加核心提要 + self._add_core_summary(stock_name) + + # 7. 添加投资评级 + self._add_investment_rating(stock_name, current_price) + + # 8. 添加核心观点 + self._add_core_views() + + # 9. 添加市场表现回顾 + self._add_market_review(price_df) + + # 10. 添加页脚 + self.formatter.add_page_number_footer() + + # 11. 保存文档 + if output_path is None: + date_str = datetime.now().strftime('%Y%m%d') + output_path = f"{stock_name}_{stock_code.replace('.', '_')}_研究报告_{date_str}.docx" + + self.doc.save(output_path) + print(f"报告已保存: {output_path}") + + return output_path + + def _add_cover_page(self, stock_name: str, organization: str): + """添加封面页""" + date_str = datetime.now().strftime('%Y年%m月%d日') + self.formatter.add_cover_page( + title=f"{stock_name}投资研究报告", + organization=organization, + date_str=date_str + ) + + def _add_disclaimer(self): + """添加免责声明""" + self.formatter.add_heading('免责声明', level=1) + self.formatter.add_paragraph( + "本报告所载资料的来源及观点皆为公开信息,但并不能保证其准确性和完整性。本报告仅供参考," + "不构成任何投资建议或承诺,投资者应审慎决策,独立判断,自行承担投资风险。" + ) + self.formatter.add_paragraph( + "本报告版权归本公司所有,未经书面许可,任何机构和个人不得以任何形式翻版、复制、刊登、" + "发表或引用。如征得本公司同意进行引用、刊发的,需在允许的范围内使用,并注明出处为" + "'某某证券研究所',且不得对本报告进行任何有悖原意的引用、删节和修改。" + ) + + def _add_core_summary(self, stock_name: str): + """添加核心提要""" + self.formatter.add_heading('核心提要', level=1) + + summary_points = self.analysis_results['summary_points'] + for i, point in enumerate(summary_points, 1): + # 添加项目符号 + paragraph = self.doc.add_paragraph() + run = paragraph.add_run(f"{i}. {point}") + self.formatter.set_font(run, '仿宋', 14) + paragraph.paragraph_format.line_spacing = Pt(28) + paragraph.paragraph_format.line_spacing_rule = 2 + paragraph.paragraph_format.space_before = Pt(0) + paragraph.paragraph_format.space_after = Pt(0) + + def _add_investment_rating(self, stock_name: str, current_price: float): + """添加投资评级""" + self.formatter.add_heading('一、投资评级', level=1) + + # 表格数据 + recommendation = self.analysis_results['recommendation'] + + data = [[ + recommendation.rating.value, + f"{recommendation.target_price:.2f}元", + (datetime.now() + timedelta(days=365)).strftime('%Y年%m月%d日'), + recommendation.risk_level.value + ]] + + self.formatter.add_three_line_table( + data, + ['投资建议', '目标价格', '有效期', '风险等级'], + font_name='仿宋', + size=12 + ) + + # 添加说明文字 + self.formatter.add_paragraph( + f"当前股价:{current_price:.2f}元。" + f"目标价较当前价格{'上涨' if recommendation.target_price > current_price else '下跌'}" + f"{abs((recommendation.target_price / current_price - 1) * 100):.2f}%。" + ) + + def _add_core_views(self): + """添加核心观点""" + self.formatter.add_heading('二、核心观点', level=1) + + # 基本面分析 + fundamental = self.analysis_results['fundamental'] + self.formatter.add_heading('(一)基本面分析', level=2) + self.formatter.add_paragraph( + f"1. 盈利能力:公司最新净资产收益率(ROE)为{fundamental.roe}%," + f"{fundamental.roe_comment}。" + ) + self.formatter.add_paragraph( + f"2. 估值水平:当前市盈率(TTM)为{fundamental.pe_ttm}倍," + f"市净率(LF)为{fundamental.pb_lf}倍。{fundamental.valuation_comment}。" + ) + self.formatter.add_paragraph(f"3. 结论:{fundamental.fundamental_summary}") + + # 技术面分析 + technical = self.analysis_results['technical'] + self.formatter.add_heading('(二)技术面分析', level=2) + self.formatter.add_paragraph( + f"1. 价格趋势:近期股价呈现{technical.trend}态势," + f"{technical.ma_status}。" + ) + self.formatter.add_paragraph( + f"2. 支撑与阻力:近期支撑位{technical.support_level}元," + f"阻力位{technical.resistance_level}元。" + ) + self.formatter.add_paragraph( + f"3. 波动率:近期年化波动率为{technical.volatility}%," + f"{'属于高波动品种' if technical.volatility > 40 else '波动适中' if technical.volatility > 25 else '波动较低'}。" + ) + + # 投资建议 + recommendation = self.analysis_results['recommendation'] + self.formatter.add_heading('(三)投资建议', level=2) + self.formatter.add_paragraph(recommendation.recommendation_text) + + self.formatter.add_paragraph("主要投资逻辑:") + for factor in recommendation.key_factors: + paragraph = self.doc.add_paragraph() + run = paragraph.add_run(f"• {factor}") + self.formatter.set_font(run, '仿宋', 14) + paragraph.paragraph_format.line_spacing = Pt(28) + paragraph.paragraph_format.line_spacing_rule = 2 + paragraph.paragraph_format.first_line_indent = Pt(28) + + def _add_market_review(self, price_df): + """添加市场表现回顾""" + self.formatter.add_heading('三、市场表现回顾', level=1) + + # 价格走势分析 + self.formatter.add_heading('(一)价格走势分析', level=2) + + price_stats = self.analysis_results['price_stats'] + + self.formatter.add_paragraph( + f"近期股价最高达到{price_stats['highest_price']}元," + f"最低下探至{price_stats['lowest_price']}元," + f"区间累计涨跌幅为{price_stats['total_change']:.2f}%。" + f"最新收盘价为{price_stats['latest_price']}元," + f"区间平均价格为{price_stats['avg_price']}元。" + ) + + # K线数据表 + self.formatter.add_heading('(二)K线数据', level=2) + + # 准备表格数据(最近13周) + recent_data = price_df.tail(13).copy() + table_data = [] + + for _, row in recent_data.iterrows(): + date_str = row['date'].strftime('%Y-%m-%d') if hasattr(row['date'], 'strftime') else str(row['date'])[:10] + table_data.append([ + date_str, + f"{row['open']:.2f}", + f"{row['high']:.2f}", + f"{row['low']:.2f}", + f"{row['close']:.2f}", + f"{row.get('pct_chg', 0):.2f}%", + f"{row.get('volume', 0) / 10000:.0f}" + ]) + + self.formatter.add_three_line_table( + table_data, + ['日期', '开盘价', '最高价', '最低价', '收盘价', '涨跌幅', '成交量(万股)'], + font_name='仿宋', + size=12 + ) + + # 数据来源 + self.formatter.add_data_source_footnote() + + +def main(): + """主函数""" + parser = argparse.ArgumentParser(description='生成金融投资研究报告') + parser.add_argument('stock_code', help='股票代码,如 300866.SZ 或 000001') + parser.add_argument('--name', '-n', help='股票名称') + parser.add_argument('--org', '-o', default='某某证券研究所', help='研究机构名称') + parser.add_argument('--author', '-a', default='', help='分析师姓名') + parser.add_argument('--no-cover', action='store_true', help='不包含封面') + parser.add_argument('--output', '-p', help='输出文件路径') + + args = parser.parse_args() + + # 标准化股票代码 + stock_code = args.stock_code + if '.' not in stock_code: + if stock_code.startswith('6'): + stock_code = f"{stock_code}.SH" + else: + stock_code = f"{stock_code}.SZ" + + generator = ReportGenerator() + + try: + output_path = generator.generate_report( + stock_code=stock_code, + stock_name=args.name, + organization=args.org, + author=args.author, + include_cover=not args.no_cover, + output_path=args.output + ) + print(f"\n报告生成成功: {output_path}") + except Exception as e: + print(f"\n报告生成失败: {e}") + import traceback + traceback.print_exc() + sys.exit(1) + + +if __name__ == '__main__': + main() diff --git a/find-skills/SKILL.md b/find-skills/SKILL.md new file mode 100644 index 0000000..c797184 --- /dev/null +++ b/find-skills/SKILL.md @@ -0,0 +1,133 @@ +--- +name: find-skills +description: Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill. +--- + +# Find Skills + +This skill helps you discover and install skills from the open agent skills ecosystem. + +## When to Use This Skill + +Use this skill when the user: + +- Asks "how do I do X" where X might be a common task with an existing skill +- Says "find a skill for X" or "is there a skill for X" +- Asks "can you do X" where X is a specialized capability +- Expresses interest in extending agent capabilities +- Wants to search for tools, templates, or workflows +- Mentions they wish they had help with a specific domain (design, testing, deployment, etc.) + +## What is the Skills CLI? + +The Skills CLI (`npx skills`) is the package manager for the open agent skills ecosystem. Skills are modular packages that extend agent capabilities with specialized knowledge, workflows, and tools. + +**Key commands:** + +- `npx skills find [query]` - Search for skills interactively or by keyword +- `npx skills add ` - Install a skill from GitHub or other sources +- `npx skills check` - Check for skill updates +- `npx skills update` - Update all installed skills + +**Browse skills at:** https://skills.sh/ + +## How to Help Users Find Skills + +### Step 1: Understand What They Need + +When a user asks for help with something, identify: + +1. The domain (e.g., React, testing, design, deployment) +2. The specific task (e.g., writing tests, creating animations, reviewing PRs) +3. Whether this is a common enough task that a skill likely exists + +### Step 2: Search for Skills + +Run the find command with a relevant query: + +```bash +npx skills find [query] +``` + +For example: + +- User asks "how do I make my React app faster?" → `npx skills find react performance` +- User asks "can you help me with PR reviews?" → `npx skills find pr review` +- User asks "I need to create a changelog" → `npx skills find changelog` + +The command will return results like: + +``` +Install with npx skills add + +vercel-labs/agent-skills@vercel-react-best-practices +└ https://skills.sh/vercel-labs/agent-skills/vercel-react-best-practices +``` + +### Step 3: Present Options to the User + +When you find relevant skills, present them to the user with: + +1. The skill name and what it does +2. The install command they can run +3. A link to learn more at skills.sh + +Example response: + +``` +I found a skill that might help! The "vercel-react-best-practices" skill provides +React and Next.js performance optimization guidelines from Vercel Engineering. + +To install it: +npx skills add vercel-labs/agent-skills@vercel-react-best-practices + +Learn more: https://skills.sh/vercel-labs/agent-skills/vercel-react-best-practices +``` + +### Step 4: Offer to Install + +If the user wants to proceed, you can install the skill for them: + +```bash +npx skills add -g -y +``` + +The `-g` flag installs globally (user-level) and `-y` skips confirmation prompts. + +## Common Skill Categories + +When searching, consider these common categories: + +| Category | Example Queries | +| --------------- | ---------------------------------------- | +| Web Development | react, nextjs, typescript, css, tailwind | +| Testing | testing, jest, playwright, e2e | +| DevOps | deploy, docker, kubernetes, ci-cd | +| Documentation | docs, readme, changelog, api-docs | +| Code Quality | review, lint, refactor, best-practices | +| Design | ui, ux, design-system, accessibility | +| Productivity | workflow, automation, git | + +## Tips for Effective Searches + +1. **Use specific keywords**: "react testing" is better than just "testing" +2. **Try alternative terms**: If "deploy" doesn't work, try "deployment" or "ci-cd" +3. **Check popular sources**: Many skills come from `vercel-labs/agent-skills` or `ComposioHQ/awesome-claude-skills` + +## When No Skills Are Found + +If no relevant skills exist: + +1. Acknowledge that no existing skill was found +2. Offer to help with the task directly using your general capabilities +3. Suggest the user could create their own skill with `npx skills init` + +Example: + +``` +I searched for skills related to "xyz" but didn't find any matches. +I can still help you with this task directly! Would you like me to proceed? + +If this is something you do often, you could create your own skill: +npx skills init my-xyz-skill +``` diff --git a/fund-slides/LICENSE b/fund-slides/LICENSE new file mode 100644 index 0000000..d6a1c00 --- /dev/null +++ b/fund-slides/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2025 Zara Zhang (original author) +Copyright (c) 2026 hanlinlibham (fork with financial enhancements) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/fund-slides/README.md b/fund-slides/README.md new file mode 100644 index 0000000..cd3ae02 --- /dev/null +++ b/fund-slides/README.md @@ -0,0 +1,120 @@ +# Fund Slides + +> Forked from [frontend-slides](https://github.com/zarazhangrui/frontend-slides) by [@zarazhangrui](https://github.com/zarazhangrui) (Zara Zhang). +> Enhanced by [@hanlinlibham](https://github.com/hanlinlibham) with financial chart integration and offline optimizations. + +A Claude Code skill for creating animation-rich HTML presentations from any content — with first-class support for financial data visualization. + +## What This Does + +**Fund Slides** helps non-designers create beautiful web presentations without knowing CSS or JavaScript. It uses a "show, don't tell" approach: instead of asking you to describe your aesthetic preferences in words, it generates visual previews and lets you pick what you like. + +Here is a deck about the original skill, made through the skill: + +https://github.com/user-attachments/assets/ef57333e-f879-432a-afb9-180388982478 + +### Key Features + +- **Zero Dependencies** — Single HTML files with inline CSS/JS. No npm, no build tools, no frameworks. +- **Offline-Ready** — ECharts library (~1MB) is inlined directly into the HTML. No CDN, no network required. +- **Visual Style Discovery** — Can't articulate design preferences? No problem. Pick from generated visual previews. +- **PPT Conversion** — Convert existing PowerPoint files to web, preserving all images and content. +- **Anti-AI-Slop** — Curated distinctive styles that avoid generic AI aesthetics. +- **Production Quality** — Accessible, responsive, well-commented code you can customize. + +### What's New in This Fork + +Compared to the original `frontend-slides`: + +- **ECharts Inline Integration** — ECharts v5 library pre-bundled in `references/echarts.min.js`, inlined at generation time for fully offline HTML output. The original used CDN `` 中 +3. 放入模板的 `` 位置 +4. **禁止使用 `` 中 +3. 放置位置:模板的 `` 处(在 SLOT: SLIDES 之后、base JS 之前) + +```html + + + + + +``` + +## 容器规范 + +```html +
+``` + +```css +.chart-container { + width: min(90vw, 800px); + height: min(50vh, 400px); + margin: 0 auto; +} +@media (max-height: 700px) { .chart-container { height: min(40vh, 300px); } } +@media (max-height: 500px) { .chart-container { height: min(35vh, 250px); } } +``` + +## 初始化模式 + +图表必须在 slide 可见时初始化,否则容器尺寸为 0: + +```javascript +const chartObserver = new IntersectionObserver((entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + const charts = entry.target.querySelectorAll('.chart-container[data-chart]'); + charts.forEach(el => { + if (!el._echartInstance) { + const chart = echarts.init(el); + chart.setOption(JSON.parse(el.dataset.chart)); + el._echartInstance = chart; + } + }); + } + }); +}, { threshold: 0.3 }); +``` + +## 窗口 resize + +```javascript +window.addEventListener('resize', () => { + document.querySelectorAll('.chart-container').forEach(el => { + if (el._echartInstance) el._echartInstance.resize(); + }); +}); +``` + +--- + +## 中文数字格式化工具 + +每个包含数据的演示必须内嵌: + +```javascript +function formatCN(num, decimals = 1) { + if (num === null || num === undefined) return '--'; + const abs = Math.abs(num); + const sign = num < 0 ? '-' : ''; + if (abs >= 1e8) return sign + (abs / 1e8).toFixed(decimals).replace(/\.0$/, '') + '\u4ebf'; + if (abs >= 1e4) return sign + (abs / 1e4).toFixed(decimals).replace(/\.0$/, '') + '\u4e07'; + return sign + abs.toLocaleString('zh-CN'); +} + +function formatPct(num, decimals = 2) { + if (num === null || num === undefined) return '--'; + return (num * 100).toFixed(decimals) + '%'; +} + +function formatDateCN(dateStr) { + const d = new Date(dateStr); + return d.getFullYear() + '\u5e74' + (d.getMonth() + 1) + '\u6708' + d.getDate() + '\u65e5'; +} +``` + +--- + +## 配色适配 + +```javascript +function getThemeColors() { + const s = getComputedStyle(document.documentElement); + return { + primary: s.getPropertyValue('--accent').trim() || '#2563eb', + secondary: s.getPropertyValue('--accent-secondary').trim() || '#60a5fa', + negative: s.getPropertyValue('--color-negative').trim() || '#dc2626', + positive: s.getPropertyValue('--color-positive').trim() || '#16a34a', + text: s.getPropertyValue('--text-primary').trim() || '#333', + textSec: s.getPropertyValue('--text-secondary').trim() || '#666', + bg: s.getPropertyValue('--bg-primary').trim() || '#fff' + }; +} + +function initThemedChart(el, option) { + const colors = getThemeColors(); + const chart = echarts.init(el, null, { renderer: 'canvas' }); + option.textStyle = option.textStyle || {}; + option.textStyle.fontFamily = getComputedStyle(document.documentElement) + .getPropertyValue('--font-body').trim() || 'Noto Sans SC, sans-serif'; + option.textStyle.color = colors.text; + chart.setOption(option); + return chart; +} +``` + +--- + +## 图表类型速查 + +| 要表达什么 | 推荐图表 | 次选 | 配置文件 | +|-----------|---------|------|---------| +| 单指标趋势 | 面积图 | 折线图 | charts-trend | +| 多指标趋势 | 柱线混合图 | 堆叠面积图 | charts-trend | +| 增长率趋势 | 双Y轴折线 | 面积图 | charts-trend | +| 构成占比 (3-6项) | 环形饼图 | 玫瑰图 | charts-composition | +| 差异大的占比 | 玫瑰图 | Treemap | charts-composition | +| 两级分类构成 | 嵌套环形图 | Treemap | charts-composition | +| 三级以上层级 | 旭日图 | Treemap | charts-composition | +| 面积=数值的层级 | Treemap | 旭日图 | charts-composition | +| 单一达标率 | 半环仪表盘 | KPI卡片 | charts-composition | +| 排名 / Top N | 横向条形图 | 柱状图 | charts-flow | +| 多主体多指标对比 | 分组柱状图 | 雷达图 | charts-trend | +| 构成+时间趋势 | 堆叠柱状图 | 堆叠面积图 | charts-trend | +| 多维综合评分 | 雷达图 | CSS评分条 | charts-matrix | +| 两变量相关性 | 散点图 | 热力图 | charts-matrix | +| NxM 矩阵数据 | 热力图 | 表格 | charts-matrix | +| 相关系数矩阵 | 相关性热力图 | 表格 | charts-matrix | +| 逐步递减/转化 | 漏斗图 | 瀑布图 | charts-flow | +| 加减拆解 | 瀑布图 | 堆叠柱 | charts-flow | +| 流向/流转 | 桑基图 | 嵌套环形 | charts-flow | +| 股价走势 | K线图 | 面积折线 | charts-flow | + +--- + +## Inline SVG (零依赖) + +不引入 ECharts 时,用 SVG 实现简单图表。 + +### 简单柱状图 + +```html + + + + + + + + Q1 + Q2 + Q3 + Q4 + 1.2亿 + 0.9亿 + 1.4亿 + 1.1亿 + +``` + +### 简单折线图 + +```html + + + + + + + + + + + + + + + + + +``` + +```css +.chart-svg { + width: min(90vw, 600px); + height: min(40vh, 300px); + display: block; + margin: 0 auto; +} +``` diff --git a/fund-slides/references/charts-composition.md b/fund-slides/references/charts-composition.md new file mode 100644 index 0000000..c087fad --- /dev/null +++ b/fund-slides/references/charts-composition.md @@ -0,0 +1,236 @@ +# Charts -- Composition (构成类) + +饼图、环形图、Treemap、旭日图等。基础设施见 [charts-base.md](charts-base.md)。 + +--- + +## 环形饼图(3-6 项占比) + +```javascript +const pieOption = { + color: ['#1a365d', '#2563eb', '#60a5fa', '#93c5fd', '#c5963a'], + tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' }, + legend: { orient: 'vertical', right: '5%', top: 'center' }, + series: [{ + type: 'pie', + radius: ['40%', '70%'], + center: ['40%', '50%'], + padAngle: 2, + itemStyle: { borderRadius: 4 }, + label: { formatter: '{b}\n{d}%', fontSize: 11 }, + emphasis: { + label: { fontSize: 14, fontWeight: 'bold' }, + itemStyle: { shadowBlur: 10, shadowColor: 'rgba(0,0,0,0.2)' } + }, + data: [ + { value: 4500, name: '业务A' }, + { value: 3200, name: '业务B' }, + { value: 2100, name: '业务C' }, + { value: 1500, name: '其他' } + ] + }] +}; +``` + +--- + +## 玫瑰图 / 南丁格尔图 + +各项数值差异大时,用半径缩放强调差异。 + +```javascript +const roseOption = { + color: ['#1a365d', '#2563eb', '#3b82f6', '#60a5fa', '#93c5fd', '#c5963a'], + tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' }, + legend: { bottom: '3%', left: 'center' }, + series: [{ + type: 'pie', + radius: ['15%', '70%'], + center: ['50%', '45%'], + roseType: 'area', /* 'radius' = 半径缩放, 'area' = 面积缩放 */ + itemStyle: { borderRadius: 5 }, + label: { formatter: '{b}\n{c}亿', fontSize: 11 }, + data: [ + { value: 1843, name: '游戏' }, + { value: 1200, name: '社交网络' }, + { value: 1240, name: '网络广告' }, + { value: 2100, name: '金融科技' }, + { value: 69, name: '其他' } + ] + }] +}; +``` + +--- + +## 嵌套环形图(两级分类) + +内环大类,外环细分。 + +```javascript +const nestedPieOption = { + tooltip: { trigger: 'item', formatter: '{a}
{b}: {c} ({d}%)' }, + series: [ + { + name: '大类', + type: 'pie', + radius: ['0%', '35%'], + label: { position: 'inner', fontSize: 10, color: '#fff' }, + data: [ + { value: 3043, name: '增值服务' }, + { value: 2100, name: '金融科技' }, + { value: 1240, name: '广告' } + ] + }, + { + name: '细分', + type: 'pie', + radius: ['45%', '70%'], + label: { formatter: '{b}: {d}%', fontSize: 10 }, + data: [ + { value: 1843, name: '游戏' }, + { value: 1200, name: '社交网络' }, + { value: 1100, name: '支付' }, + { value: 1000, name: '企业服务' }, + { value: 740, name: '媒体广告' }, + { value: 500, name: '社交广告' } + ] + } + ] +}; +``` + +--- + +## 半环仪表盘(单指标达标率) + +```javascript +const gaugeOption = { + series: [{ + type: 'gauge', + startAngle: 180, + endAngle: 0, + radius: '90%', + center: ['50%', '65%'], + min: 0, max: 100, + pointer: { show: false }, + progress: { show: true, overlap: false, roundCap: true, width: 18, itemStyle: { color: '#2563eb' } }, + axisLine: { lineStyle: { width: 18, color: [[1, '#e5e7eb']] } }, + axisTick: { show: false }, + splitLine: { show: false }, + axisLabel: { show: false }, + detail: { + fontSize: 28, fontFamily: 'Noto Sans SC', fontWeight: 700, + formatter: '{value}%', offsetCenter: [0, '-15%'], color: '#1a1a2e' + }, + title: { fontSize: 13, offsetCenter: [0, '15%'], color: '#5a5a7a' }, + data: [{ value: 73.5, name: '目标达成率' }] + }] +}; +``` + +--- + +## Treemap 矩形树图 + +面积 = 数值大小。适合两层层级构成。 + +```javascript +const treemapOption = { + tooltip: { + formatter: p => { + const path = p.treePathInfo.map(n => n.name).filter(n => n).join(' > '); + return path + '
金额: ' + formatCN(p.value); + } + }, + series: [{ + type: 'treemap', + roam: false, + width: '92%', height: '85%', top: '8%', + breadcrumb: { show: true, bottom: 0 }, + label: { show: true, formatter: '{b}\n{c}亿', fontSize: 12, fontFamily: 'Noto Sans SC' }, + upperLabel: { show: true, height: 24, fontSize: 12, fontWeight: 600, color: '#fff' }, + levels: [ + { itemStyle: { borderColor: '#fff', borderWidth: 3, gapWidth: 3 }, upperLabel: { show: true } }, + { itemStyle: { borderColor: 'rgba(255,255,255,0.5)', borderWidth: 1, gapWidth: 1 }, colorSaturation: [0.3, 0.6] } + ], + data: [ + { + name: '增值服务', value: 3043, + children: [ + { name: '本土游戏', value: 1200, itemStyle: { color: '#1a365d' } }, + { name: '海外游戏', value: 643, itemStyle: { color: '#2563eb' } }, + { name: '社交网络', value: 1200, itemStyle: { color: '#3b82f6' } } + ] + }, + { + name: '金融科技', value: 2100, + children: [ + { name: '支付', value: 1100, itemStyle: { color: '#c5963a' } }, + { name: '云服务', value: 600, itemStyle: { color: '#d4a853' } }, + { name: '其他', value: 400, itemStyle: { color: '#e8c882' } } + ] + }, + { + name: '网络广告', value: 1240, + children: [ + { name: '社交广告', value: 740, itemStyle: { color: '#16a34a' } }, + { name: '媒体广告', value: 500, itemStyle: { color: '#22c55e' } } + ] + } + ] + }] +}; +``` + +--- + +## 旭日图 Sunburst(多层级环形) + +从内到外逐层细化。适合 3 层以上层级。 + +```javascript +const sunburstOption = { + tooltip: { + formatter: p => { + const path = p.treePathInfo.map(n => n.name).filter(n => n).join(' > '); + return path + '
金额: ' + formatCN(p.value); + } + }, + series: [{ + type: 'sunburst', + radius: ['12%', '85%'], + sort: 'desc', + emphasis: { focus: 'ancestor' }, + label: { fontSize: 10, fontFamily: 'Noto Sans SC', rotate: 'radial', minAngle: 10 }, + levels: [ + {}, + { r0: '12%', r: '40%', label: { fontSize: 12, fontWeight: 600 }, itemStyle: { borderWidth: 2, borderColor: '#fff' } }, + { r0: '40%', r: '65%', label: { fontSize: 10 }, itemStyle: { borderWidth: 1.5, borderColor: '#fff' } }, + { r0: '65%', r: '85%', label: { fontSize: 9, align: 'right' }, itemStyle: { borderWidth: 1, borderColor: 'rgba(255,255,255,0.6)' } } + ], + data: [ + { + name: '增值服务', itemStyle: { color: '#1a365d' }, + children: [ + { name: '游戏', value: 1843, children: [ + { name: '王者荣耀', value: 500 }, { name: '和平精英', value: 350 }, + { name: 'LoL/Valorant', value: 400 }, { name: '其他', value: 593 } + ]}, + { name: '社交网络', value: 1200, children: [ + { name: '会员订阅', value: 650 }, { name: '虚拟道具', value: 550 } + ]} + ] + }, + { + name: '金融科技', itemStyle: { color: '#c5963a' }, + children: [ { name: '支付', value: 1100 }, { name: '云服务', value: 600 }, { name: '其他', value: 400 } ] + }, + { + name: '广告', itemStyle: { color: '#16a34a' }, + children: [ { name: '社交广告', value: 740 }, { name: '媒体广告', value: 500 } ] + } + ] + }] +}; +``` diff --git a/fund-slides/references/charts-flow.md b/fund-slides/references/charts-flow.md new file mode 100644 index 0000000..dc39051 --- /dev/null +++ b/fund-slides/references/charts-flow.md @@ -0,0 +1,233 @@ +# Charts -- Flow (流向与特殊类型) + +瀑布图、K 线、横向条形、漏斗图、桑基图。基础设施见 [charts-base.md](charts-base.md)。 + +--- + +## 瀑布图(加减拆解) + +从总量逐步拆解到净值。正/负值不同颜色。 + +```javascript +const waterfallOption = { + tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }, + grid: { left: '10%', right: '5%', top: '10%', bottom: '12%' }, + xAxis: { type: 'category', data: ['营业收入', '营业成本', '毛利', '销售费用', '管理费用', '财务费用', '营业利润'] }, + yAxis: { type: 'value', axisLabel: { formatter: v => formatCN(v) } }, + series: [ + { + name: '辅助', + type: 'bar', stack: 'total', + itemStyle: { borderColor: 'transparent', color: 'transparent' }, + data: [0, 0, 0, 0, 0, 0, 0] /* 计算后的偏移量 */ + }, + { + name: '数值', + type: 'bar', stack: 'total', barWidth: '40%', + label: { show: true, position: 'top', formatter: p => formatCN(p.value) }, + data: [ + { value: 10000, itemStyle: { color: '#2563eb' } }, + { value: -6000, itemStyle: { color: '#dc2626' } }, + { value: 4000, itemStyle: { color: '#2563eb' } }, + { value: -800, itemStyle: { color: '#dc2626' } }, + { value: -600, itemStyle: { color: '#dc2626' } }, + { value: -200, itemStyle: { color: '#dc2626' } }, + { value: 2400, itemStyle: { color: '#16a34a' } } + ] + } + ] +}; +``` + +**瀑布图辅助层计算逻辑:** + +```javascript +// 自动计算 transparent 辅助柱的高度 +function buildWaterfall(items) { + // items: [{ label, value, type: 'start'|'add'|'sub'|'total' }] + let running = 0; + const categories = [], assist = [], values = []; + items.forEach(item => { + categories.push(item.label); + if (item.type === 'start' || item.type === 'total') { + assist.push(0); + values.push({ value: item.value, itemStyle: { color: item.type === 'total' ? '#16a34a' : '#2563eb' } }); + running = item.value; + } else { + const v = item.type === 'sub' ? -Math.abs(item.value) : Math.abs(item.value); + assist.push(Math.max(0, running + Math.min(0, v))); + values.push({ value: v, itemStyle: { color: v >= 0 ? '#2563eb' : '#dc2626' } }); + running += v; + } + }); + return { categories, assist, values }; +} +``` + +--- + +## K 线图(股价走势) + +A 股惯例:红涨绿跌。 + +```javascript +const candlestickOption = { + tooltip: { trigger: 'axis' }, + grid: { left: '10%', right: '5%', top: '10%', bottom: '15%' }, + xAxis: { type: 'category', data: ['03-01', '03-04', '03-05', '03-06', '03-07', '03-08', '03-11', '03-12'] }, + yAxis: { type: 'value', scale: true }, + series: [{ + type: 'candlestick', + itemStyle: { + color: '#dc2626', /* 阳线填充 */ + color0: '#16a34a', /* 阴线填充 */ + borderColor: '#dc2626', + borderColor0: '#16a34a' + }, + data: [ + /* [open, close, low, high] */ + [540, 548, 536, 552], + [548, 545, 540, 550], + [545, 555, 543, 558], + [555, 550, 546, 556], + [550, 560, 548, 562], + [560, 558, 554, 563], + [558, 565, 555, 568], + [565, 550, 548, 566] + ] + }] +}; +``` + +K 线 + 成交量组合: + +```javascript +const klineWithVolOption = { + tooltip: { trigger: 'axis' }, + grid: [ + { left: '10%', right: '5%', top: '8%', height: '55%' }, /* K 线区域 */ + { left: '10%', right: '5%', top: '72%', height: '18%' } /* 成交量区域 */ + ], + xAxis: [ + { type: 'category', data: /* dates */, gridIndex: 0 }, + { type: 'category', data: /* dates */, gridIndex: 1 } + ], + yAxis: [ + { type: 'value', scale: true, gridIndex: 0 }, + { type: 'value', gridIndex: 1, axisLabel: { formatter: v => formatCN(v) } } + ], + series: [ + { + type: 'candlestick', + xAxisIndex: 0, yAxisIndex: 0, + itemStyle: { color: '#dc2626', color0: '#16a34a', borderColor: '#dc2626', borderColor0: '#16a34a' }, + data: /* [[open,close,low,high], ...] */ + }, + { + type: 'bar', + xAxisIndex: 1, yAxisIndex: 1, + barWidth: '60%', + data: /* volume array, with itemStyle per bar based on up/down */ + } + ] +}; +``` + +--- + +## 横向条形图(排名 / Top N) + +横向更易阅读长标签。inverse 从上到下递减。 + +```javascript +const horizontalBarOption = { + tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } }, + grid: { left: '22%', right: '10%', top: '5%', bottom: '5%' }, + xAxis: { type: 'value', axisLabel: { formatter: v => formatCN(v) } }, + yAxis: { + type: 'category', + inverse: true, + data: ['腾讯', 'Sony', '微软', '任天堂', 'EA', '动视暴雪'], + axisLabel: { fontSize: 12 } + }, + series: [{ + type: 'bar', + barWidth: '55%', + data: [ + { value: 1843, itemStyle: { color: '#1a365d' } }, + { value: 1250, itemStyle: { color: '#93c5fd' } }, + { value: 1180, itemStyle: { color: '#93c5fd' } }, + { value: 920, itemStyle: { color: '#93c5fd' } }, + { value: 580, itemStyle: { color: '#93c5fd' } }, + { value: 520, itemStyle: { color: '#93c5fd' } } + ], + label: { show: true, position: 'right', formatter: p => formatCN(p.value), fontSize: 11 }, + itemStyle: { borderRadius: [0, 3, 3, 0] } + }] +}; +``` + +--- + +## 漏斗图(转化/筛选流程) + +逐步递减的转化过程。 + +```javascript +const funnelOption = { + tooltip: { trigger: 'item', formatter: '{b}: {c} ({d}%)' }, + series: [{ + type: 'funnel', + left: '15%', right: '15%', top: '8%', bottom: '8%', + width: '70%', + minSize: '15%', maxSize: '100%', + sort: 'descending', + gap: 4, + label: { show: true, position: 'inside', formatter: '{b}\n{c}', fontSize: 12, fontFamily: 'Noto Sans SC' }, + itemStyle: { borderWidth: 0 }, + data: [ + { value: 5000, name: '初筛股票池', itemStyle: { color: '#93c5fd' } }, + { value: 2800, name: '基本面过滤', itemStyle: { color: '#60a5fa' } }, + { value: 1200, name: '估值合理', itemStyle: { color: '#3b82f6' } }, + { value: 450, name: '技术面确认', itemStyle: { color: '#2563eb' } }, + { value: 120, name: '最终标的', itemStyle: { color: '#1a365d' } } + ] + }] +}; +``` + +--- + +## 桑基图 Sankey(价值流向) + +从来源到去向的流转关系。 + +```javascript +const sankeyOption = { + tooltip: { trigger: 'item', formatter: '{b}: {c}亿' }, + series: [{ + type: 'sankey', + layout: 'none', + top: '5%', bottom: '5%', left: '5%', right: '15%', + nodeWidth: 20, + nodeGap: 12, + label: { fontSize: 11, fontFamily: 'Noto Sans SC' }, + lineStyle: { color: 'gradient', curveness: 0.5, opacity: 0.4 }, + emphasis: { lineStyle: { opacity: 0.7 } }, + data: [ + { name: '游戏' }, { name: '社交' }, { name: '广告' }, { name: '金融科技' }, + { name: '营业收入' }, { name: '营业成本' }, { name: '毛利' }, { name: '费用' }, { name: '净利润' } + ], + links: [ + { source: '游戏', target: '营业收入', value: 1843 }, + { source: '社交', target: '营业收入', value: 1200 }, + { source: '广告', target: '营业收入', value: 1240 }, + { source: '金融科技', target: '营业收入', value: 2100 }, + { source: '营业收入', target: '营业成本', value: 3073 }, + { source: '营业收入', target: '毛利', value: 3536 }, + { source: '毛利', target: '费用', value: 1515 }, + { source: '毛利', target: '净利润', value: 2021 } + ] + }] +}; +``` diff --git a/fund-slides/references/charts-matrix.md b/fund-slides/references/charts-matrix.md new file mode 100644 index 0000000..f942fb2 --- /dev/null +++ b/fund-slides/references/charts-matrix.md @@ -0,0 +1,146 @@ +# Charts -- Matrix (矩阵与分布类) + +热力图、相关性矩阵、雷达图、散点图。基础设施见 [charts-base.md](charts-base.md)。 + +--- + +## 热力图(NxM 矩阵数据) + +两个维度交叉的数值强度,颜色深浅表示大小。 + +```javascript +const heatmapOption = { + tooltip: { position: 'top', formatter: p => p.data[1] + ' x ' + p.data[0] + ': ' + p.data[2] }, + grid: { left: '12%', right: '8%', top: '8%', bottom: '15%' }, + xAxis: { + type: 'category', + data: ['Q1', 'Q2', 'Q3', 'Q4'], + splitArea: { show: true }, + axisLabel: { fontSize: 11 } + }, + yAxis: { + type: 'category', + data: ['游戏', '社交', '广告', '金融科技', '云服务'], + splitArea: { show: true }, + axisLabel: { fontSize: 11 } + }, + visualMap: { + min: 0, max: 600, + calculable: true, + orient: 'horizontal', + left: 'center', bottom: '0%', + inRange: { color: ['#f0f4ff', '#93c5fd', '#2563eb', '#1a365d'] }, + textStyle: { fontSize: 10 } + }, + series: [{ + type: 'heatmap', + data: [ + ['Q1', '游戏', 480], ['Q2', '游戏', 520], ['Q3', '游戏', 460], ['Q4', '游戏', 580], + ['Q1', '社交', 290], ['Q2', '社交', 310], ['Q3', '社交', 300], ['Q4', '社交', 320], + ['Q1', '广告', 250], ['Q2', '广告', 340], ['Q3', '广告', 310], ['Q4', '广告', 380], + ['Q1', '金融科技', 490], ['Q2', '金融科技', 530], ['Q3', '金融科技', 510], ['Q4', '金融科技', 560], + ['Q1', '云服务', 130], ['Q2', '云服务', 150], ['Q3', '云服务', 155], ['Q4', '云服务', 170] + ], + label: { show: true, fontSize: 10, color: '#333', formatter: p => p.data[2] }, + emphasis: { itemStyle: { shadowBlur: 10, shadowColor: 'rgba(0,0,0,0.3)' } } + }] +}; +``` + +--- + +## 相关性热力图(方阵) + +对称矩阵,-1 到 +1 色阶。适用于多资产/多因子相关系数。 + +```javascript +const labels = ['贵州茅台', '五粮液', '泸州老窖', '山西汾酒', '洋河股份']; +const corrData = [ + [0,0,1.0],[1,0,0.85],[2,0,0.82],[3,0,0.71],[4,0,0.68], + [0,1,0.85],[1,1,1.0],[2,1,0.91],[3,1,0.78],[4,1,0.74], + [0,2,0.82],[1,2,0.91],[2,2,1.0],[3,2,0.80],[4,2,0.72], + [0,3,0.71],[1,3,0.78],[2,3,0.80],[3,3,1.0],[4,3,0.65], + [0,4,0.68],[1,4,0.74],[2,4,0.72],[3,4,0.65],[4,4,1.0] +]; + +const corrMatrixOption = { + tooltip: { formatter: p => labels[p.data[0]] + ' vs ' + labels[p.data[1]] + ': ' + p.data[2].toFixed(2) }, + grid: { left: '15%', right: '12%', top: '15%', bottom: '5%' }, + xAxis: { type: 'category', data: labels, axisLabel: { rotate: 30, fontSize: 10 } }, + yAxis: { type: 'category', data: labels, axisLabel: { fontSize: 10 } }, + visualMap: { + min: -1, max: 1, + inRange: { color: ['#dc2626', '#fef2f2', '#ffffff', '#eff6ff', '#2563eb'] }, + orient: 'horizontal', left: 'center', bottom: '0%', + text: ['+1.0', '-1.0'] + }, + series: [{ + type: 'heatmap', + data: corrData, + label: { show: true, fontSize: 10, formatter: p => p.data[2].toFixed(2) } + }] +}; +``` + +--- + +## 雷达图(多维评分对比) + +多个维度的综合评分。2 个主体对比最佳。 + +```javascript +const radarOption = { + tooltip: {}, + legend: { top: '2%' }, + radar: { + indicator: [ + { name: '网络效应', max: 10 }, + { name: '转换成本', max: 10 }, + { name: '品牌价值', max: 10 }, + { name: '规模经济', max: 10 }, + { name: '无形资产', max: 10 }, + { name: '成本优势', max: 10 } + ], + radius: '65%', + axisName: { fontSize: 11, fontFamily: 'Noto Sans SC' }, + splitArea: { areaStyle: { color: ['rgba(37,99,235,0.02)', 'rgba(37,99,235,0.05)'] } } + }, + series: [{ + type: 'radar', + data: [ + { name: '腾讯', value: [9.5, 9.0, 7.0, 8.0, 8.5, 5.0], areaStyle: { opacity: 0.25 }, lineStyle: { width: 2 } }, + { name: '阿里巴巴', value: [7.0, 7.5, 6.5, 8.5, 6.0, 6.0], areaStyle: { opacity: 0.15 }, lineStyle: { width: 2 } } + ] + }] +}; +``` + +--- + +## 散点图 / 气泡图 + +两变量相关性,气泡大小编码第三维度。 + +```javascript +const scatterOption = { + tooltip: { + formatter: p => p.data[3] + '
PE: ' + p.data[0] + 'x
ROE: ' + p.data[1] + '%
市值: ' + formatCN(p.data[2]) + }, + grid: { left: '10%', right: '8%', top: '8%', bottom: '12%' }, + xAxis: { name: 'PE (TTM)', nameLocation: 'center', nameGap: 30, scale: true }, + yAxis: { name: 'ROE (%)', nameLocation: 'center', nameGap: 35, scale: true }, + series: [{ + type: 'scatter', + symbolSize: p => Math.sqrt(p[2]) / 800, + data: [ + [22.8, 22.5, 53000e8, '腾讯'], + [16.2, 12.8, 22000e8, '阿里巴巴'], + [28.5, 35.2, 16000e8, 'Meta'], + [35.0, 42.0, 33000e8, '微软'], + [25.0, 30.0, 25000e8, '字节(估)'] + ], + label: { show: true, formatter: p => p.data[3], position: 'top', fontSize: 10 }, + emphasis: { itemStyle: { shadowBlur: 10, shadowColor: 'rgba(0,0,0,0.3)' } } + }] +}; +``` diff --git a/fund-slides/references/charts-trend.md b/fund-slides/references/charts-trend.md new file mode 100644 index 0000000..d49e3eb --- /dev/null +++ b/fund-slides/references/charts-trend.md @@ -0,0 +1,178 @@ +# Charts -- Trend (趋势类) + +折线图、面积图、柱状图及其变体。基础设施见 [charts-base.md](charts-base.md)。 + +--- + +## 折线图(多指标趋势) + +```javascript +const lineOption = { + color: ['#2563eb', '#dc2626'], + tooltip: { trigger: 'axis' }, + legend: { data: ['营业收入', '净利润'] }, + grid: { left: '8%', right: '5%', top: '15%', bottom: '12%' }, + xAxis: { type: 'category', data: ['2021', '2022', '2023', '2024', '2025E'] }, + yAxis: { type: 'value', axisLabel: { formatter: v => formatCN(v) } }, + series: [ + { name: '营业收入', type: 'line', smooth: true, data: [1200e6, 1500e6, 1800e6, 2100e6, 2400e6] }, + { name: '净利润', type: 'line', smooth: true, data: [300e6, 380e6, 450e6, 520e6, 600e6] } + ] +}; +``` + +--- + +## 面积图(单指标 + 渐变填充) + +强调规模感和趋势方向。 + +```javascript +const areaOption = { + tooltip: { trigger: 'axis' }, + grid: { left: '8%', right: '5%', top: '10%', bottom: '10%' }, + xAxis: { type: 'category', boundaryGap: false, data: ['2019', '2020', '2021', '2022', '2023', '2024'] }, + yAxis: { type: 'value', axisLabel: { formatter: v => formatCN(v) } }, + series: [{ + name: '用户规模', + type: 'line', + smooth: true, + symbol: 'circle', + symbolSize: 6, + lineStyle: { width: 2.5 }, + areaStyle: { + color: { + type: 'linear', x: 0, y: 0, x2: 0, y2: 1, + colorStops: [ + { offset: 0, color: 'rgba(37, 99, 235, 0.35)' }, + { offset: 1, color: 'rgba(37, 99, 235, 0.02)' } + ] + } + }, + data: [89000, 112000, 135000, 148000, 162000, 178000] + }] +}; +``` + +--- + +## 堆叠面积图(多组分构成趋势) + +同时展示各部分和总量随时间的变化。 + +```javascript +const stackedAreaOption = { + tooltip: { + trigger: 'axis', + formatter: params => { + let s = params[0].name + '
', total = 0; + params.forEach(p => { s += p.marker + p.seriesName + ': ' + formatCN(p.value) + '
'; total += p.value; }); + return s + '合计: ' + formatCN(total) + ''; + } + }, + legend: { top: '2%' }, + grid: { left: '8%', right: '5%', top: '15%', bottom: '10%' }, + xAxis: { type: 'category', boundaryGap: false, data: ['2020', '2021', '2022', '2023', '2024'] }, + yAxis: { type: 'value', axisLabel: { formatter: v => formatCN(v) } }, + series: [ + { name: '游戏', type: 'line', stack: 'total', smooth: true, areaStyle: { opacity: 0.6 }, data: [1561, 1743, 1707, 1799, 1843] }, + { name: '社交网络', type: 'line', stack: 'total', smooth: true, areaStyle: { opacity: 0.6 }, data: [1082, 1173, 1118, 1181, 1200] }, + { name: '广告', type: 'line', stack: 'total', smooth: true, areaStyle: { opacity: 0.6 }, data: [823, 886, 827, 1015, 1240] }, + { name: '金融科技', type: 'line', stack: 'total', smooth: true, areaStyle: { opacity: 0.6 }, data: [1281, 1722, 1771, 2038, 2100] } + ] +}; +``` + +--- + +## 双 Y 轴(绝对值 + 增速) + +左轴柱状/面积展示绝对值,右轴折线展示增长率。 + +```javascript +const dualAxisOption = { + tooltip: { trigger: 'axis' }, + legend: { top: '2%' }, + grid: { left: '8%', right: '8%', top: '15%', bottom: '10%' }, + xAxis: { type: 'category', data: ['2020', '2021', '2022', '2023', '2024'] }, + yAxis: [ + { type: 'value', name: '营收 (亿)', axisLabel: { formatter: v => v } }, + { type: 'value', name: 'YoY (%)', axisLabel: { formatter: v => v + '%' }, splitLine: { show: false } } + ], + series: [ + { name: '营业收入', type: 'bar', barWidth: '35%', data: [4821, 5601, 5546, 6090, 6609], itemStyle: { borderRadius: [3, 3, 0, 0] } }, + { name: 'YoY 增速', type: 'line', yAxisIndex: 1, smooth: true, symbol: 'circle', symbolSize: 7, lineStyle: { width: 2.5, type: 'dashed' }, data: [27.8, 16.2, -1.0, 9.8, 8.5] } + ] +}; +``` + +--- + +## 柱状图(季度对比) + +```javascript +const barOption = { + color: ['#2563eb', '#60a5fa'], + tooltip: { trigger: 'axis' }, + grid: { left: '8%', right: '5%', top: '12%', bottom: '12%' }, + xAxis: { type: 'category', data: ['Q1', 'Q2', 'Q3', 'Q4'] }, + yAxis: { type: 'value', axisLabel: { formatter: v => formatCN(v) } }, + series: [ + { name: '2024', type: 'bar', barWidth: '30%', data: [820, 932, 901, 1034] }, + { name: '2025', type: 'bar', barWidth: '30%', data: [920, 1032, 1001, 1134] } + ] +}; +``` + +--- + +## 分组柱状图(多主体对比) + +2-4 个主体在多个维度上直接对比。 + +```javascript +const groupedBarOption = { + color: ['#1a365d', '#2563eb', '#60a5fa', '#c5963a'], + tooltip: { trigger: 'axis' }, + legend: { top: '2%' }, + grid: { left: '8%', right: '5%', top: '15%', bottom: '10%' }, + xAxis: { type: 'category', data: ['营收增速', '净利率', 'ROE', 'PE'] }, + yAxis: { type: 'value', axisLabel: { formatter: v => v + '%' } }, + series: [ + { name: '腾讯', type: 'bar', barWidth: '18%', data: [8.5, 30.6, 22.5, 22.8] }, + { name: '阿里', type: 'bar', barWidth: '18%', data: [5.2, 13.1, 12.8, 16.2] }, + { name: '字节', type: 'bar', barWidth: '18%', data: [30, 20, 30, 25] }, + { name: 'Meta', type: 'bar', barWidth: '18%', data: [22, 35.6, 35.2, 28.5] } + ] +}; +``` + +--- + +## 堆叠柱状图(构成 + 趋势) + +同时展示各组成部分和总量的变化。 + +```javascript +const stackedBarOption = { + color: ['#1a365d', '#2563eb', '#60a5fa', '#c5963a'], + tooltip: { + trigger: 'axis', + formatter: params => { + let s = params[0].name + '
', total = 0; + params.forEach(p => { s += p.marker + p.seriesName + ': ' + p.value + '亿
'; total += p.value; }); + return s + '合计: ' + total + '亿'; + } + }, + legend: { top: '2%' }, + grid: { left: '8%', right: '5%', top: '15%', bottom: '10%' }, + xAxis: { type: 'category', data: ['2020', '2021', '2022', '2023', '2024'] }, + yAxis: { type: 'value', axisLabel: { formatter: v => v + '亿' } }, + series: [ + { name: '游戏', type: 'bar', stack: 'total', barWidth: '40%', data: [1561, 1743, 1707, 1799, 1843] }, + { name: '社交', type: 'bar', stack: 'total', data: [1082, 1173, 1118, 1181, 1200] }, + { name: '广告', type: 'bar', stack: 'total', data: [823, 886, 827, 1015, 1240] }, + { name: '金融科技', type: 'bar', stack: 'total', data: [1281, 1722, 1771, 2038, 2100] } + ] +}; +``` diff --git a/fund-slides/references/echarts.min.js b/fund-slides/references/echarts.min.js new file mode 100644 index 0000000..a3e9805 --- /dev/null +++ b/fund-slides/references/echarts.min.js @@ -0,0 +1,45 @@ + +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +!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).echarts={})}(this,(function(t){"use strict"; +/*! ***************************************************************************** + Copyright (c) Microsoft Corporation. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + ***************************************************************************** */var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])},e(t,n)};function n(t,n){if("function"!=typeof n&&null!==n)throw new TypeError("Class extends value "+String(n)+" is not a constructor or null");function i(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(i.prototype=n.prototype,new i)}var i=function(){this.firefox=!1,this.ie=!1,this.edge=!1,this.newEdge=!1,this.weChat=!1},r=new function(){this.browser=new i,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="undefined"!=typeof window};"object"==typeof wx&&"function"==typeof wx.getSystemInfoSync?(r.wxa=!0,r.touchEventsSupported=!0):"undefined"==typeof document&&"undefined"!=typeof self?r.worker=!0:!r.hasGlobalWindow||"Deno"in window?(r.node=!0,r.svgSupported=!0):function(t,e){var n=e.browser,i=t.match(/Firefox\/([\d.]+)/),r=t.match(/MSIE\s([\d.]+)/)||t.match(/Trident\/.+?rv:(([\d.]+))/),o=t.match(/Edge?\/([\d.]+)/),a=/micromessenger/i.test(t);i&&(n.firefox=!0,n.version=i[1]);r&&(n.ie=!0,n.version=r[1]);o&&(n.edge=!0,n.version=o[1],n.newEdge=+o[1].split(".")[0]>18);a&&(n.weChat=!0);e.svgSupported="undefined"!=typeof SVGRect,e.touchEventsSupported="ontouchstart"in window&&!n.ie&&!n.edge,e.pointerEventsSupported="onpointerdown"in window&&(n.edge||n.ie&&+n.version>=11),e.domSupported="undefined"!=typeof document;var s=document.documentElement.style;e.transform3dSupported=(n.ie&&"transition"in s||n.edge||"WebKitCSSMatrix"in window&&"m11"in new WebKitCSSMatrix||"MozPerspective"in s)&&!("OTransition"in s),e.transformSupported=e.transform3dSupported||n.ie&&+n.version>=9}(navigator.userAgent,r);var o="sans-serif",a="12px "+o;var s,l,u=function(t){var e={};if("undefined"==typeof JSON)return e;for(var n=0;n=0)o=r*t.length;else for(var c=0;c>1)%2;a.style.cssText=["position: absolute","visibility: hidden","padding: 0","margin: 0","border-width: 0","user-select: none","width:0","height:0",i[s]+":0",r[l]+":0",i[1-s]+":auto",r[1-l]+":auto",""].join("!important;"),t.appendChild(a),n.push(a)}return n}(e,a),l=function(t,e,n){for(var i=n?"invTrans":"trans",r=e[i],o=e.srcCoords,a=[],s=[],l=!0,u=0;u<4;u++){var h=t[u].getBoundingClientRect(),c=2*u,p=h.left,d=h.top;a.push(p,d),l=l&&o&&p===o[c]&&d===o[c+1],s.push(t[u].offsetLeft,t[u].offsetTop)}return l&&r?r:(e.srcCoords=a,e[i]=n?$t(s,a):$t(a,s))}(s,a,o);if(l)return l(t,n,i),!0}return!1}function ee(t){return"CANVAS"===t.nodeName.toUpperCase()}var ne=/([&<>"'])/g,ie={"&":"&","<":"<",">":">",'"':""","'":"'"};function re(t){return null==t?"":(t+"").replace(ne,(function(t,e){return ie[e]}))}var oe=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ae=[],se=r.browser.firefox&&+r.browser.version.split(".")[0]<39;function le(t,e,n,i){return n=n||{},i?ue(t,e,n):se&&null!=e.layerX&&e.layerX!==e.offsetX?(n.zrX=e.layerX,n.zrY=e.layerY):null!=e.offsetX?(n.zrX=e.offsetX,n.zrY=e.offsetY):ue(t,e,n),n}function ue(t,e,n){if(r.domSupported&&t.getBoundingClientRect){var i=e.clientX,o=e.clientY;if(ee(t)){var a=t.getBoundingClientRect();return n.zrX=i-a.left,void(n.zrY=o-a.top)}if(te(ae,t,i,o))return n.zrX=ae[0],void(n.zrY=ae[1])}n.zrX=n.zrY=0}function he(t){return t||window.event}function ce(t,e,n){if(null!=(e=he(e)).zrX)return e;var i=e.type;if(i&&i.indexOf("touch")>=0){var r="touchend"!==i?e.targetTouches[0]:e.changedTouches[0];r&&le(t,r,e,n)}else{le(t,e,e,n);var o=function(t){var e=t.wheelDelta;if(e)return e;var n=t.deltaX,i=t.deltaY;if(null==n||null==i)return e;return 3*(0!==i?Math.abs(i):Math.abs(n))*(i>0?-1:i<0?1:n>0?-1:1)}(e);e.zrDelta=o?o/120:-(e.detail||0)/3}var a=e.button;return null==e.which&&void 0!==a&&oe.test(e.type)&&(e.which=1&a?1:2&a?3:4&a?2:0),e}function pe(t,e,n,i){t.addEventListener(e,n,i)}var de=function(t){t.preventDefault(),t.stopPropagation(),t.cancelBubble=!0};function fe(t){return 2===t.which||3===t.which}var ge=function(){function t(){this._track=[]}return t.prototype.recognize=function(t,e,n){return this._doTrack(t,e,n),this._recognize(t)},t.prototype.clear=function(){return this._track.length=0,this},t.prototype._doTrack=function(t,e,n){var i=t.touches;if(i){for(var r={points:[],touches:[],target:e,event:t},o=0,a=i.length;o1&&r&&r.length>1){var a=ye(r)/ye(o);!isFinite(a)&&(a=1),e.pinchScale=a;var s=[((i=r)[0][0]+i[1][0])/2,(i[0][1]+i[1][1])/2];return e.pinchX=s[0],e.pinchY=s[1],{type:"pinch",target:t[0].target,event:e}}}}};function me(){return[1,0,0,1,0,0]}function xe(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=1,t[4]=0,t[5]=0,t}function _e(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t}function be(t,e,n){var i=e[0]*n[0]+e[2]*n[1],r=e[1]*n[0]+e[3]*n[1],o=e[0]*n[2]+e[2]*n[3],a=e[1]*n[2]+e[3]*n[3],s=e[0]*n[4]+e[2]*n[5]+e[4],l=e[1]*n[4]+e[3]*n[5]+e[5];return t[0]=i,t[1]=r,t[2]=o,t[3]=a,t[4]=s,t[5]=l,t}function we(t,e,n){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4]+n[0],t[5]=e[5]+n[1],t}function Se(t,e,n,i){void 0===i&&(i=[0,0]);var r=e[0],o=e[2],a=e[4],s=e[1],l=e[3],u=e[5],h=Math.sin(n),c=Math.cos(n);return t[0]=r*c+s*h,t[1]=-r*h+s*c,t[2]=o*c+l*h,t[3]=-o*h+c*l,t[4]=c*(a-i[0])+h*(u-i[1])+i[0],t[5]=c*(u-i[1])-h*(a-i[0])+i[1],t}function Me(t,e,n){var i=n[0],r=n[1];return t[0]=e[0]*i,t[1]=e[1]*r,t[2]=e[2]*i,t[3]=e[3]*r,t[4]=e[4]*i,t[5]=e[5]*r,t}function Ie(t,e){var n=e[0],i=e[2],r=e[4],o=e[1],a=e[3],s=e[5],l=n*a-o*i;return l?(l=1/l,t[0]=a*l,t[1]=-o*l,t[2]=-i*l,t[3]=n*l,t[4]=(i*s-a*r)*l,t[5]=(o*r-n*s)*l,t):null}function Te(t){var e=[1,0,0,1,0,0];return _e(e,t),e}var Ce=Object.freeze({__proto__:null,create:me,identity:xe,copy:_e,mul:be,translate:we,rotate:Se,scale:Me,invert:Ie,clone:Te}),De=function(){function t(t,e){this.x=t||0,this.y=e||0}return t.prototype.copy=function(t){return this.x=t.x,this.y=t.y,this},t.prototype.clone=function(){return new t(this.x,this.y)},t.prototype.set=function(t,e){return this.x=t,this.y=e,this},t.prototype.equal=function(t){return t.x===this.x&&t.y===this.y},t.prototype.add=function(t){return this.x+=t.x,this.y+=t.y,this},t.prototype.scale=function(t){this.x*=t,this.y*=t},t.prototype.scaleAndAdd=function(t,e){this.x+=t.x*e,this.y+=t.y*e},t.prototype.sub=function(t){return this.x-=t.x,this.y-=t.y,this},t.prototype.dot=function(t){return this.x*t.x+this.y*t.y},t.prototype.len=function(){return Math.sqrt(this.x*this.x+this.y*this.y)},t.prototype.lenSquare=function(){return this.x*this.x+this.y*this.y},t.prototype.normalize=function(){var t=this.len();return this.x/=t,this.y/=t,this},t.prototype.distance=function(t){var e=this.x-t.x,n=this.y-t.y;return Math.sqrt(e*e+n*n)},t.prototype.distanceSquare=function(t){var e=this.x-t.x,n=this.y-t.y;return e*e+n*n},t.prototype.negate=function(){return this.x=-this.x,this.y=-this.y,this},t.prototype.transform=function(t){if(t){var e=this.x,n=this.y;return this.x=t[0]*e+t[2]*n+t[4],this.y=t[1]*e+t[3]*n+t[5],this}},t.prototype.toArray=function(t){return t[0]=this.x,t[1]=this.y,t},t.prototype.fromArray=function(t){this.x=t[0],this.y=t[1]},t.set=function(t,e,n){t.x=e,t.y=n},t.copy=function(t,e){t.x=e.x,t.y=e.y},t.len=function(t){return Math.sqrt(t.x*t.x+t.y*t.y)},t.lenSquare=function(t){return t.x*t.x+t.y*t.y},t.dot=function(t,e){return t.x*e.x+t.y*e.y},t.add=function(t,e,n){t.x=e.x+n.x,t.y=e.y+n.y},t.sub=function(t,e,n){t.x=e.x-n.x,t.y=e.y-n.y},t.scale=function(t,e,n){t.x=e.x*n,t.y=e.y*n},t.scaleAndAdd=function(t,e,n,i){t.x=e.x+n.x*i,t.y=e.y+n.y*i},t.lerp=function(t,e,n,i){var r=1-i;t.x=r*e.x+i*n.x,t.y=r*e.y+i*n.y},t}(),Ae=Math.min,ke=Math.max,Le=new De,Pe=new De,Oe=new De,Re=new De,Ne=new De,Ee=new De,ze=function(){function t(t,e,n,i){n<0&&(t+=n,n=-n),i<0&&(e+=i,i=-i),this.x=t,this.y=e,this.width=n,this.height=i}return t.prototype.union=function(t){var e=Ae(t.x,this.x),n=Ae(t.y,this.y);isFinite(this.x)&&isFinite(this.width)?this.width=ke(t.x+t.width,this.x+this.width)-e:this.width=t.width,isFinite(this.y)&&isFinite(this.height)?this.height=ke(t.y+t.height,this.y+this.height)-n:this.height=t.height,this.x=e,this.y=n},t.prototype.applyTransform=function(e){t.applyTransform(this,this,e)},t.prototype.calculateTransform=function(t){var e=this,n=t.width/e.width,i=t.height/e.height,r=[1,0,0,1,0,0];return we(r,r,[-e.x,-e.y]),Me(r,r,[n,i]),we(r,r,[t.x,t.y]),r},t.prototype.intersect=function(e,n){if(!e)return!1;e instanceof t||(e=t.create(e));var i=this,r=i.x,o=i.x+i.width,a=i.y,s=i.y+i.height,l=e.x,u=e.x+e.width,h=e.y,c=e.y+e.height,p=!(of&&(f=x,gf&&(f=_,v=n.x&&t<=n.x+n.width&&e>=n.y&&e<=n.y+n.height},t.prototype.clone=function(){return new t(this.x,this.y,this.width,this.height)},t.prototype.copy=function(e){t.copy(this,e)},t.prototype.plain=function(){return{x:this.x,y:this.y,width:this.width,height:this.height}},t.prototype.isFinite=function(){return isFinite(this.x)&&isFinite(this.y)&&isFinite(this.width)&&isFinite(this.height)},t.prototype.isZero=function(){return 0===this.width||0===this.height},t.create=function(e){return new t(e.x,e.y,e.width,e.height)},t.copy=function(t,e){t.x=e.x,t.y=e.y,t.width=e.width,t.height=e.height},t.applyTransform=function(e,n,i){if(i){if(i[1]<1e-5&&i[1]>-1e-5&&i[2]<1e-5&&i[2]>-1e-5){var r=i[0],o=i[3],a=i[4],s=i[5];return e.x=n.x*r+a,e.y=n.y*o+s,e.width=n.width*r,e.height=n.height*o,e.width<0&&(e.x+=e.width,e.width=-e.width),void(e.height<0&&(e.y+=e.height,e.height=-e.height))}Le.x=Oe.x=n.x,Le.y=Re.y=n.y,Pe.x=Re.x=n.x+n.width,Pe.y=Oe.y=n.y+n.height,Le.transform(i),Re.transform(i),Pe.transform(i),Oe.transform(i),e.x=Ae(Le.x,Pe.x,Oe.x,Re.x),e.y=Ae(Le.y,Pe.y,Oe.y,Re.y);var l=ke(Le.x,Pe.x,Oe.x,Re.x),u=ke(Le.y,Pe.y,Oe.y,Re.y);e.width=l-e.x,e.height=u-e.y}else e!==n&&t.copy(e,n)},t}(),Ve="silent";function Be(){de(this.event)}var Fe=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.handler=null,e}return n(e,t),e.prototype.dispose=function(){},e.prototype.setCursor=function(){},e}(jt),Ge=function(t,e){this.x=t,this.y=e},We=["click","dblclick","mousewheel","mouseout","mouseup","mousedown","mousemove","contextmenu"],He=new ze(0,0,0,0),Ye=function(t){function e(e,n,i,r,o){var a=t.call(this)||this;return a._hovered=new Ge(0,0),a.storage=e,a.painter=n,a.painterRoot=r,a._pointerSize=o,i=i||new Fe,a.proxy=null,a.setHandlerProxy(i),a._draggingMgr=new Zt(a),a}return n(e,t),e.prototype.setHandlerProxy=function(t){this.proxy&&this.proxy.dispose(),t&&(E(We,(function(e){t.on&&t.on(e,this[e],this)}),this),t.handler=this),this.proxy=t},e.prototype.mousemove=function(t){var e=t.zrX,n=t.zrY,i=Ze(this,e,n),r=this._hovered,o=r.target;o&&!o.__zr&&(o=(r=this.findHover(r.x,r.y)).target);var a=this._hovered=i?new Ge(e,n):this.findHover(e,n),s=a.target,l=this.proxy;l.setCursor&&l.setCursor(s?s.cursor:"default"),o&&s!==o&&this.dispatchToElement(r,"mouseout",t),this.dispatchToElement(a,"mousemove",t),s&&s!==o&&this.dispatchToElement(a,"mouseover",t)},e.prototype.mouseout=function(t){var e=t.zrEventControl;"only_globalout"!==e&&this.dispatchToElement(this._hovered,"mouseout",t),"no_globalout"!==e&&this.trigger("globalout",{type:"globalout",event:t})},e.prototype.resize=function(){this._hovered=new Ge(0,0)},e.prototype.dispatch=function(t,e){var n=this[t];n&&n.call(this,e)},e.prototype.dispose=function(){this.proxy.dispose(),this.storage=null,this.proxy=null,this.painter=null},e.prototype.setCursorStyle=function(t){var e=this.proxy;e.setCursor&&e.setCursor(t)},e.prototype.dispatchToElement=function(t,e,n){var i=(t=t||{}).target;if(!i||!i.silent){for(var r="on"+e,o=function(t,e,n){return{type:t,event:n,target:e.target,topTarget:e.topTarget,cancelBubble:!1,offsetX:n.zrX,offsetY:n.zrY,gestureEvent:n.gestureEvent,pinchX:n.pinchX,pinchY:n.pinchY,pinchScale:n.pinchScale,wheelDelta:n.zrDelta,zrByTouch:n.zrByTouch,which:n.which,stop:Be}}(e,t,n);i&&(i[r]&&(o.cancelBubble=!!i[r].call(i,o)),i.trigger(e,o),i=i.__hostTarget?i.__hostTarget:i.parent,!o.cancelBubble););o.cancelBubble||(this.trigger(e,o),this.painter&&this.painter.eachOtherLayer&&this.painter.eachOtherLayer((function(t){"function"==typeof t[r]&&t[r].call(t,o),t.trigger&&t.trigger(e,o)})))}},e.prototype.findHover=function(t,e,n){var i=this.storage.getDisplayList(),r=new Ge(t,e);if(Ue(i,r,t,e,n),this._pointerSize&&!r.target){for(var o=[],a=this._pointerSize,s=a/2,l=new ze(t-s,e-s,a,a),u=i.length-1;u>=0;u--){var h=i[u];h===n||h.ignore||h.ignoreCoarsePointer||h.parent&&h.parent.ignoreCoarsePointer||(He.copy(h.getBoundingRect()),h.transform&&He.applyTransform(h.transform),He.intersect(l)&&o.push(h))}if(o.length)for(var c=Math.PI/12,p=2*Math.PI,d=0;d=0;o--){var a=t[o],s=void 0;if(a!==r&&!a.ignore&&(s=Xe(a,n,i))&&(!e.topTarget&&(e.topTarget=a),s!==Ve)){e.target=a;break}}}function Ze(t,e,n){var i=t.painter;return e<0||e>i.getWidth()||n<0||n>i.getHeight()}E(["click","mousedown","mouseup","mousewheel","dblclick","contextmenu"],(function(t){Ye.prototype[t]=function(e){var n,i,r=e.zrX,o=e.zrY,a=Ze(this,r,o);if("mouseup"===t&&a||(i=(n=this.findHover(r,o)).target),"mousedown"===t)this._downEl=i,this._downPoint=[e.zrX,e.zrY],this._upEl=i;else if("mouseup"===t)this._upEl=i;else if("click"===t){if(this._downEl!==this._upEl||!this._downPoint||Vt(this._downPoint,[e.zrX,e.zrY])>4)return;this._downPoint=null}this.dispatchToElement(n,t,e)}}));function je(t,e,n,i){var r=e+1;if(r===n)return 1;if(i(t[r++],t[e])<0){for(;r=0;)r++;return r-e}function qe(t,e,n,i,r){for(i===e&&i++;i>>1])<0?l=o:s=o+1;var u=i-s;switch(u){case 3:t[s+3]=t[s+2];case 2:t[s+2]=t[s+1];case 1:t[s+1]=t[s];break;default:for(;u>0;)t[s+u]=t[s+u-1],u--}t[s]=a}}function Ke(t,e,n,i,r,o){var a=0,s=0,l=1;if(o(t,e[n+r])>0){for(s=i-r;l0;)a=l,(l=1+(l<<1))<=0&&(l=s);l>s&&(l=s),a+=r,l+=r}else{for(s=r+1;ls&&(l=s);var u=a;a=r-l,l=r-u}for(a++;a>>1);o(t,e[n+h])>0?a=h+1:l=h}return l}function $e(t,e,n,i,r,o){var a=0,s=0,l=1;if(o(t,e[n+r])<0){for(s=r+1;ls&&(l=s);var u=a;a=r-l,l=r-u}else{for(s=i-r;l=0;)a=l,(l=1+(l<<1))<=0&&(l=s);l>s&&(l=s),a+=r,l+=r}for(a++;a>>1);o(t,e[n+h])<0?l=h:a=h+1}return l}function Je(t,e){var n,i,r=7,o=0,a=[];function s(s){var l=n[s],u=i[s],h=n[s+1],c=i[s+1];i[s]=u+c,s===o-3&&(n[s+1]=n[s+2],i[s+1]=i[s+2]),o--;var p=$e(t[h],t,l,u,0,e);l+=p,0!==(u-=p)&&0!==(c=Ke(t[l+u-1],t,h,c,c-1,e))&&(u<=c?function(n,i,o,s){var l=0;for(l=0;l=7||d>=7);if(f)break;g<0&&(g=0),g+=2}if((r=g)<1&&(r=1),1===i){for(l=0;l=0;l--)t[d+l]=t[p+l];return void(t[c]=a[h])}var f=r;for(;;){var g=0,y=0,v=!1;do{if(e(a[h],t[u])<0){if(t[c--]=t[u--],g++,y=0,0==--i){v=!0;break}}else if(t[c--]=a[h--],y++,g=0,1==--s){v=!0;break}}while((g|y)=0;l--)t[d+l]=t[p+l];if(0===i){v=!0;break}}if(t[c--]=a[h--],1==--s){v=!0;break}if(0!==(y=s-Ke(t[u],a,0,s,s-1,e))){for(s-=y,d=(c-=y)+1,p=(h-=y)+1,l=0;l=7||y>=7);if(v)break;f<0&&(f=0),f+=2}(r=f)<1&&(r=1);if(1===s){for(d=(c-=i)+1,p=(u-=i)+1,l=i-1;l>=0;l--)t[d+l]=t[p+l];t[c]=a[h]}else{if(0===s)throw new Error;for(p=c-(s-1),l=0;l1;){var t=o-2;if(t>=1&&i[t-1]<=i[t]+i[t+1]||t>=2&&i[t-2]<=i[t]+i[t-1])i[t-1]i[t+1])break;s(t)}},forceMergeRuns:function(){for(;o>1;){var t=o-2;t>0&&i[t-1]=32;)e|=1&t,t>>=1;return t+e}(r);do{if((o=je(t,n,i,e))s&&(l=s),qe(t,n,n+l,n+o,e),o=l}a.pushRun(n,o),a.mergeRuns(),r-=o,n+=o}while(0!==r);a.forceMergeRuns()}}}var tn=!1;function en(){tn||(tn=!0,console.warn("z / z2 / zlevel of displayable is invalid, which may cause unexpected errors"))}function nn(t,e){return t.zlevel===e.zlevel?t.z===e.z?t.z2-e.z2:t.z-e.z:t.zlevel-e.zlevel}var rn=function(){function t(){this._roots=[],this._displayList=[],this._displayListLen=0,this.displayableSortFunc=nn}return t.prototype.traverse=function(t,e){for(var n=0;n0&&(u.__clipPaths=[]),isNaN(u.z)&&(en(),u.z=0),isNaN(u.z2)&&(en(),u.z2=0),isNaN(u.zlevel)&&(en(),u.zlevel=0),this._displayList[this._displayListLen++]=u}var h=t.getDecalElement&&t.getDecalElement();h&&this._updateAndAddDisplayable(h,e,n);var c=t.getTextGuideLine();c&&this._updateAndAddDisplayable(c,e,n);var p=t.getTextContent();p&&this._updateAndAddDisplayable(p,e,n)}},t.prototype.addRoot=function(t){t.__zr&&t.__zr.storage===this||this._roots.push(t)},t.prototype.delRoot=function(t){if(t instanceof Array)for(var e=0,n=t.length;e=0&&this._roots.splice(i,1)}},t.prototype.delAllRoots=function(){this._roots=[],this._displayList=[],this._displayListLen=0},t.prototype.getRoots=function(){return this._roots},t.prototype.dispose=function(){this._displayList=null,this._roots=null},t}(),on=r.hasGlobalWindow&&(window.requestAnimationFrame&&window.requestAnimationFrame.bind(window)||window.msRequestAnimationFrame&&window.msRequestAnimationFrame.bind(window)||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame)||function(t){return setTimeout(t,16)},an={linear:function(t){return t},quadraticIn:function(t){return t*t},quadraticOut:function(t){return t*(2-t)},quadraticInOut:function(t){return(t*=2)<1?.5*t*t:-.5*(--t*(t-2)-1)},cubicIn:function(t){return t*t*t},cubicOut:function(t){return--t*t*t+1},cubicInOut:function(t){return(t*=2)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},quarticIn:function(t){return t*t*t*t},quarticOut:function(t){return 1- --t*t*t*t},quarticInOut:function(t){return(t*=2)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},quinticIn:function(t){return t*t*t*t*t},quinticOut:function(t){return--t*t*t*t*t+1},quinticInOut:function(t){return(t*=2)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},sinusoidalIn:function(t){return 1-Math.cos(t*Math.PI/2)},sinusoidalOut:function(t){return Math.sin(t*Math.PI/2)},sinusoidalInOut:function(t){return.5*(1-Math.cos(Math.PI*t))},exponentialIn:function(t){return 0===t?0:Math.pow(1024,t-1)},exponentialOut:function(t){return 1===t?1:1-Math.pow(2,-10*t)},exponentialInOut:function(t){return 0===t?0:1===t?1:(t*=2)<1?.5*Math.pow(1024,t-1):.5*(2-Math.pow(2,-10*(t-1)))},circularIn:function(t){return 1-Math.sqrt(1-t*t)},circularOut:function(t){return Math.sqrt(1- --t*t)},circularInOut:function(t){return(t*=2)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},elasticIn:function(t){var e,n=.1;return 0===t?0:1===t?1:(!n||n<1?(n=1,e=.1):e=.4*Math.asin(1/n)/(2*Math.PI),-n*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/.4))},elasticOut:function(t){var e,n=.1;return 0===t?0:1===t?1:(!n||n<1?(n=1,e=.1):e=.4*Math.asin(1/n)/(2*Math.PI),n*Math.pow(2,-10*t)*Math.sin((t-e)*(2*Math.PI)/.4)+1)},elasticInOut:function(t){var e,n=.1,i=.4;return 0===t?0:1===t?1:(!n||n<1?(n=1,e=.1):e=i*Math.asin(1/n)/(2*Math.PI),(t*=2)<1?n*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i)*-.5:n*Math.pow(2,-10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/i)*.5+1)},backIn:function(t){var e=1.70158;return t*t*((e+1)*t-e)},backOut:function(t){var e=1.70158;return--t*t*((e+1)*t+e)+1},backInOut:function(t){var e=2.5949095;return(t*=2)<1?t*t*((e+1)*t-e)*.5:.5*((t-=2)*t*((e+1)*t+e)+2)},bounceIn:function(t){return 1-an.bounceOut(1-t)},bounceOut:function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},bounceInOut:function(t){return t<.5?.5*an.bounceIn(2*t):.5*an.bounceOut(2*t-1)+.5}},sn=Math.pow,ln=Math.sqrt,un=1e-8,hn=1e-4,cn=ln(3),pn=1/3,dn=Mt(),fn=Mt(),gn=Mt();function yn(t){return t>-1e-8&&tun||t<-1e-8}function mn(t,e,n,i,r){var o=1-r;return o*o*(o*t+3*r*e)+r*r*(r*i+3*o*n)}function xn(t,e,n,i,r){var o=1-r;return 3*(((e-t)*o+2*(n-e)*r)*o+(i-n)*r*r)}function _n(t,e,n,i,r,o){var a=i+3*(e-n)-t,s=3*(n-2*e+t),l=3*(e-t),u=t-r,h=s*s-3*a*l,c=s*l-9*a*u,p=l*l-3*s*u,d=0;if(yn(h)&&yn(c)){if(yn(s))o[0]=0;else(M=-l/s)>=0&&M<=1&&(o[d++]=M)}else{var f=c*c-4*h*p;if(yn(f)){var g=c/h,y=-g/2;(M=-s/a+g)>=0&&M<=1&&(o[d++]=M),y>=0&&y<=1&&(o[d++]=y)}else if(f>0){var v=ln(f),m=h*s+1.5*a*(-c+v),x=h*s+1.5*a*(-c-v);(M=(-s-((m=m<0?-sn(-m,pn):sn(m,pn))+(x=x<0?-sn(-x,pn):sn(x,pn))))/(3*a))>=0&&M<=1&&(o[d++]=M)}else{var _=(2*h*s-3*a*c)/(2*ln(h*h*h)),b=Math.acos(_)/3,w=ln(h),S=Math.cos(b),M=(-s-2*w*S)/(3*a),I=(y=(-s+w*(S+cn*Math.sin(b)))/(3*a),(-s+w*(S-cn*Math.sin(b)))/(3*a));M>=0&&M<=1&&(o[d++]=M),y>=0&&y<=1&&(o[d++]=y),I>=0&&I<=1&&(o[d++]=I)}}return d}function bn(t,e,n,i,r){var o=6*n-12*e+6*t,a=9*e+3*i-3*t-9*n,s=3*e-3*t,l=0;if(yn(a)){if(vn(o))(h=-s/o)>=0&&h<=1&&(r[l++]=h)}else{var u=o*o-4*a*s;if(yn(u))r[0]=-o/(2*a);else if(u>0){var h,c=ln(u),p=(-o-c)/(2*a);(h=(-o+c)/(2*a))>=0&&h<=1&&(r[l++]=h),p>=0&&p<=1&&(r[l++]=p)}}return l}function wn(t,e,n,i,r,o){var a=(e-t)*r+t,s=(n-e)*r+e,l=(i-n)*r+n,u=(s-a)*r+a,h=(l-s)*r+s,c=(h-u)*r+u;o[0]=t,o[1]=a,o[2]=u,o[3]=c,o[4]=c,o[5]=h,o[6]=l,o[7]=i}function Sn(t,e,n,i,r,o,a,s,l,u,h){var c,p,d,f,g,y=.005,v=1/0;dn[0]=l,dn[1]=u;for(var m=0;m<1;m+=.05)fn[0]=mn(t,n,r,a,m),fn[1]=mn(e,i,o,s,m),(f=Ft(dn,fn))=0&&f=0&&y=1?1:_n(0,i,o,1,t,s)&&mn(0,r,a,1,s[0])}}}var On=function(){function t(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||bt,this.ondestroy=t.ondestroy||bt,this.onrestart=t.onrestart||bt,t.easing&&this.setEasing(t.easing)}return t.prototype.step=function(t,e){if(this._inited||(this._startTime=t+this._delay,this._inited=!0),!this._paused){var n=this._life,i=t-this._startTime-this._pausedTime,r=i/n;r<0&&(r=0),r=Math.min(r,1);var o=this.easingFunc,a=o?o(r):r;if(this.onframe(a),1===r){if(!this.loop)return!0;var s=i%n;this._startTime=t-s,this._pausedTime=0,this.onrestart()}return!1}this._pausedTime+=e},t.prototype.pause=function(){this._paused=!0},t.prototype.resume=function(){this._paused=!1},t.prototype.setEasing=function(t){this.easing=t,this.easingFunc=X(t)?t:an[t]||Pn(t)},t}(),Rn=function(t){this.value=t},Nn=function(){function t(){this._len=0}return t.prototype.insert=function(t){var e=new Rn(t);return this.insertEntry(e),e},t.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++},t.prototype.remove=function(t){var e=t.prev,n=t.next;e?e.next=n:this.head=n,n?n.prev=e:this.tail=e,t.next=t.prev=null,this._len--},t.prototype.len=function(){return this._len},t.prototype.clear=function(){this.head=this.tail=null,this._len=0},t}(),En=function(){function t(t){this._list=new Nn,this._maxSize=10,this._map={},this._maxSize=t}return t.prototype.put=function(t,e){var n=this._list,i=this._map,r=null;if(null==i[t]){var o=n.len(),a=this._lastRemovedEntry;if(o>=this._maxSize&&o>0){var s=n.head;n.remove(s),delete i[s.key],r=s.value,this._lastRemovedEntry=s}a?a.value=e:a=new Rn(e),a.key=t,n.insertEntry(a),i[t]=a}return r},t.prototype.get=function(t){var e=this._map[t],n=this._list;if(null!=e)return e!==n.tail&&(n.remove(e),n.insertEntry(e)),e.value},t.prototype.clear=function(){this._list.clear(),this._map={}},t.prototype.len=function(){return this._list.len()},t}(),zn={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 Vn(t){return(t=Math.round(t))<0?0:t>255?255:t}function Bn(t){return t<0?0:t>1?1:t}function Fn(t){var e=t;return e.length&&"%"===e.charAt(e.length-1)?Vn(parseFloat(e)/100*255):Vn(parseInt(e,10))}function Gn(t){var e=t;return e.length&&"%"===e.charAt(e.length-1)?Bn(parseFloat(e)/100):Bn(parseFloat(e))}function Wn(t,e,n){return n<0?n+=1:n>1&&(n-=1),6*n<1?t+(e-t)*n*6:2*n<1?e:3*n<2?t+(e-t)*(2/3-n)*6:t}function Hn(t,e,n){return t+(e-t)*n}function Yn(t,e,n,i,r){return t[0]=e,t[1]=n,t[2]=i,t[3]=r,t}function Xn(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t}var Un=new En(20),Zn=null;function jn(t,e){Zn&&Xn(Zn,e),Zn=Un.put(t,Zn||e.slice())}function qn(t,e){if(t){e=e||[];var n=Un.get(t);if(n)return Xn(e,n);var i=(t+="").replace(/ /g,"").toLowerCase();if(i in zn)return Xn(e,zn[i]),jn(t,e),e;var r,o=i.length;if("#"===i.charAt(0))return 4===o||5===o?(r=parseInt(i.slice(1,4),16))>=0&&r<=4095?(Yn(e,(3840&r)>>4|(3840&r)>>8,240&r|(240&r)>>4,15&r|(15&r)<<4,5===o?parseInt(i.slice(4),16)/15:1),jn(t,e),e):void Yn(e,0,0,0,1):7===o||9===o?(r=parseInt(i.slice(1,7),16))>=0&&r<=16777215?(Yn(e,(16711680&r)>>16,(65280&r)>>8,255&r,9===o?parseInt(i.slice(7),16)/255:1),jn(t,e),e):void Yn(e,0,0,0,1):void 0;var a=i.indexOf("("),s=i.indexOf(")");if(-1!==a&&s+1===o){var l=i.substr(0,a),u=i.substr(a+1,s-(a+1)).split(","),h=1;switch(l){case"rgba":if(4!==u.length)return 3===u.length?Yn(e,+u[0],+u[1],+u[2],1):Yn(e,0,0,0,1);h=Gn(u.pop());case"rgb":return u.length>=3?(Yn(e,Fn(u[0]),Fn(u[1]),Fn(u[2]),3===u.length?h:Gn(u[3])),jn(t,e),e):void Yn(e,0,0,0,1);case"hsla":return 4!==u.length?void Yn(e,0,0,0,1):(u[3]=Gn(u[3]),Kn(u,e),jn(t,e),e);case"hsl":return 3!==u.length?void Yn(e,0,0,0,1):(Kn(u,e),jn(t,e),e);default:return}}Yn(e,0,0,0,1)}}function Kn(t,e){var n=(parseFloat(t[0])%360+360)%360/360,i=Gn(t[1]),r=Gn(t[2]),o=r<=.5?r*(i+1):r+i-r*i,a=2*r-o;return Yn(e=e||[],Vn(255*Wn(a,o,n+1/3)),Vn(255*Wn(a,o,n)),Vn(255*Wn(a,o,n-1/3)),1),4===t.length&&(e[3]=t[3]),e}function $n(t,e){var n=qn(t);if(n){for(var i=0;i<3;i++)n[i]=e<0?n[i]*(1-e)|0:(255-n[i])*e+n[i]|0,n[i]>255?n[i]=255:n[i]<0&&(n[i]=0);return ri(n,4===n.length?"rgba":"rgb")}}function Jn(t,e,n){if(e&&e.length&&t>=0&&t<=1){n=n||[];var i=t*(e.length-1),r=Math.floor(i),o=Math.ceil(i),a=e[r],s=e[o],l=i-r;return n[0]=Vn(Hn(a[0],s[0],l)),n[1]=Vn(Hn(a[1],s[1],l)),n[2]=Vn(Hn(a[2],s[2],l)),n[3]=Bn(Hn(a[3],s[3],l)),n}}var Qn=Jn;function ti(t,e,n){if(e&&e.length&&t>=0&&t<=1){var i=t*(e.length-1),r=Math.floor(i),o=Math.ceil(i),a=qn(e[r]),s=qn(e[o]),l=i-r,u=ri([Vn(Hn(a[0],s[0],l)),Vn(Hn(a[1],s[1],l)),Vn(Hn(a[2],s[2],l)),Bn(Hn(a[3],s[3],l))],"rgba");return n?{color:u,leftIndex:r,rightIndex:o,value:i}:u}}var ei=ti;function ni(t,e,n,i){var r=qn(t);if(t)return r=function(t){if(t){var e,n,i=t[0]/255,r=t[1]/255,o=t[2]/255,a=Math.min(i,r,o),s=Math.max(i,r,o),l=s-a,u=(s+a)/2;if(0===l)e=0,n=0;else{n=u<.5?l/(s+a):l/(2-s-a);var h=((s-i)/6+l/2)/l,c=((s-r)/6+l/2)/l,p=((s-o)/6+l/2)/l;i===s?e=p-c:r===s?e=1/3+h-p:o===s&&(e=2/3+c-h),e<0&&(e+=1),e>1&&(e-=1)}var d=[360*e,n,u];return null!=t[3]&&d.push(t[3]),d}}(r),null!=e&&(r[0]=function(t){return(t=Math.round(t))<0?0:t>360?360:t}(e)),null!=n&&(r[1]=Gn(n)),null!=i&&(r[2]=Gn(i)),ri(Kn(r),"rgba")}function ii(t,e){var n=qn(t);if(n&&null!=e)return n[3]=Bn(e),ri(n,"rgba")}function ri(t,e){if(t&&t.length){var n=t[0]+","+t[1]+","+t[2];return"rgba"!==e&&"hsva"!==e&&"hsla"!==e||(n+=","+t[3]),e+"("+n+")"}}function oi(t,e){var n=qn(t);return n?(.299*n[0]+.587*n[1]+.114*n[2])*n[3]/255+(1-n[3])*e:0}var ai=new En(100);function si(t){if(U(t)){var e=ai.get(t);return e||(e=$n(t,-.1),ai.put(t,e)),e}if(Q(t)){var n=A({},t);return n.colorStops=z(t.colorStops,(function(t){return{offset:t.offset,color:$n(t.color,-.1)}})),n}return t}var li=Object.freeze({__proto__:null,parse:qn,lift:$n,toHex:function(t){var e=qn(t);if(e)return((1<<24)+(e[0]<<16)+(e[1]<<8)+ +e[2]).toString(16).slice(1)},fastLerp:Jn,fastMapToColor:Qn,lerp:ti,mapToColor:ei,modifyHSL:ni,modifyAlpha:ii,stringify:ri,lum:oi,random:function(){return ri([Math.round(255*Math.random()),Math.round(255*Math.random()),Math.round(255*Math.random())],"rgb")},liftColor:si}),ui=Math.round;function hi(t){var e;if(t&&"transparent"!==t){if("string"==typeof t&&t.indexOf("rgba")>-1){var n=qn(t);n&&(t="rgb("+n[0]+","+n[1]+","+n[2]+")",e=n[3])}}else t="none";return{color:t,opacity:null==e?1:e}}var ci=1e-4;function pi(t){return t-1e-4}function di(t){return ui(1e3*t)/1e3}function fi(t){return ui(1e4*t)/1e4}var gi={left:"start",right:"end",center:"middle",middle:"middle"};function yi(t){return t&&!!t.image}function vi(t){return yi(t)||function(t){return t&&!!t.svgElement}(t)}function mi(t){return"linear"===t.type}function xi(t){return"radial"===t.type}function _i(t){return t&&("linear"===t.type||"radial"===t.type)}function bi(t){return"url(#"+t+")"}function wi(t){var e=t.getGlobalScale(),n=Math.max(e[0],e[1]);return Math.max(Math.ceil(Math.log(n)/Math.log(10)),1)}function Si(t){var e=t.x||0,n=t.y||0,i=(t.rotation||0)*wt,r=rt(t.scaleX,1),o=rt(t.scaleY,1),a=t.skewX||0,s=t.skewY||0,l=[];return(e||n)&&l.push("translate("+e+"px,"+n+"px)"),i&&l.push("rotate("+i+")"),1===r&&1===o||l.push("scale("+r+","+o+")"),(a||s)&&l.push("skew("+ui(a*wt)+"deg, "+ui(s*wt)+"deg)"),l.join(" ")}var Mi=r.hasGlobalWindow&&X(window.btoa)?function(t){return window.btoa(unescape(encodeURIComponent(t)))}:"undefined"!=typeof Buffer?function(t){return Buffer.from(t).toString("base64")}:function(t){return null},Ii=Array.prototype.slice;function Ti(t,e,n){return(e-t)*n+t}function Ci(t,e,n,i){for(var r=e.length,o=0;oi?e:t,o=Math.min(n,i),a=r[o-1]||{color:[0,0,0,0],offset:0},s=o;sa)i.length=a;else for(var s=o;s=1},t.prototype.getAdditiveTrack=function(){return this._additiveTrack},t.prototype.addKeyframe=function(t,e,n){this._needsSort=!0;var i=this.keyframes,r=i.length,o=!1,a=6,s=e;if(N(e)){var l=function(t){return N(t&&t[0])?2:1}(e);a=l,(1===l&&!j(e[0])||2===l&&!j(e[0][0]))&&(o=!0)}else if(j(e)&&!nt(e))a=0;else if(U(e))if(isNaN(+e)){var u=qn(e);u&&(s=u,a=3)}else a=0;else if(Q(e)){var h=A({},s);h.colorStops=z(e.colorStops,(function(t){return{offset:t.offset,color:qn(t.color)}})),mi(e)?a=4:xi(e)&&(a=5),s=h}0===r?this.valType=a:a===this.valType&&6!==a||(o=!0),this.discrete=this.discrete||o;var c={time:t,value:s,rawValue:e,percent:0};return n&&(c.easing=n,c.easingFunc=X(n)?n:an[n]||Pn(n)),i.push(c),c},t.prototype.prepare=function(t,e){var n=this.keyframes;this._needsSort&&n.sort((function(t,e){return t.time-e.time}));for(var i=this.valType,r=n.length,o=n[r-1],a=this.discrete,s=Ni(i),l=Ri(i),u=0;u=0&&!(l[n].percent<=e);n--);n=d(n,u-2)}else{for(n=p;ne);n++);n=d(n-1,u-2)}r=l[n+1],i=l[n]}if(i&&r){this._lastFr=n,this._lastFrP=e;var f=r.percent-i.percent,g=0===f?1:d((e-i.percent)/f,1);r.easingFunc&&(g=r.easingFunc(g));var y=o?this._additiveValue:c?Ei:t[h];if(!Ni(s)&&!c||y||(y=this._additiveValue=[]),this.discrete)t[h]=g<1?i.rawValue:r.rawValue;else if(Ni(s))1===s?Ci(y,i[a],r[a],g):function(t,e,n,i){for(var r=e.length,o=r&&e[0].length,a=0;a0&&s.addKeyframe(0,Pi(l),i),this._trackKeys.push(a)}s.addKeyframe(t,Pi(e[a]),i)}return this._maxTime=Math.max(this._maxTime,t),this},t.prototype.pause=function(){this._clip.pause(),this._paused=!0},t.prototype.resume=function(){this._clip.resume(),this._paused=!1},t.prototype.isPaused=function(){return!!this._paused},t.prototype.duration=function(t){return this._maxTime=t,this._force=!0,this},t.prototype._doneCallback=function(){this._setTracksFinished(),this._clip=null;var t=this._doneCbs;if(t)for(var e=t.length,n=0;n0)){this._started=1;for(var e=this,n=[],i=this._maxTime||0,r=0;r1){var a=o.pop();r.addKeyframe(a.time,t[i]),r.prepare(this._maxTime,r.getAdditiveTrack())}}}},t}();function Bi(){return(new Date).getTime()}var Fi,Gi,Wi=function(t){function e(e){var n=t.call(this)||this;return n._running=!1,n._time=0,n._pausedTime=0,n._pauseStart=0,n._paused=!1,e=e||{},n.stage=e.stage||{},n}return n(e,t),e.prototype.addClip=function(t){t.animation&&this.removeClip(t),this._head?(this._tail.next=t,t.prev=this._tail,t.next=null,this._tail=t):this._head=this._tail=t,t.animation=this},e.prototype.addAnimator=function(t){t.animation=this;var e=t.getClip();e&&this.addClip(e)},e.prototype.removeClip=function(t){if(t.animation){var e=t.prev,n=t.next;e?e.next=n:this._head=n,n?n.prev=e:this._tail=e,t.next=t.prev=t.animation=null}},e.prototype.removeAnimator=function(t){var e=t.getClip();e&&this.removeClip(e),t.animation=null},e.prototype.update=function(t){for(var e=Bi()-this._pausedTime,n=e-this._time,i=this._head;i;){var r=i.next;i.step(e,n)?(i.ondestroy(),this.removeClip(i),i=r):i=r}this._time=e,t||(this.trigger("frame",n),this.stage.update&&this.stage.update())},e.prototype._startLoop=function(){var t=this;this._running=!0,on((function e(){t._running&&(on(e),!t._paused&&t.update())}))},e.prototype.start=function(){this._running||(this._time=Bi(),this._pausedTime=0,this._startLoop())},e.prototype.stop=function(){this._running=!1},e.prototype.pause=function(){this._paused||(this._pauseStart=Bi(),this._paused=!0)},e.prototype.resume=function(){this._paused&&(this._pausedTime+=Bi()-this._pauseStart,this._paused=!1)},e.prototype.clear=function(){for(var t=this._head;t;){var e=t.next;t.prev=t.next=t.animation=null,t=e}this._head=this._tail=null},e.prototype.isFinished=function(){return null==this._head},e.prototype.animate=function(t,e){e=e||{},this.start();var n=new Vi(t,e.loop);return this.addAnimator(n),n},e}(jt),Hi=r.domSupported,Yi=(Gi={pointerdown:1,pointerup:1,pointermove:1,pointerout:1},{mouse:Fi=["click","dblclick","mousewheel","wheel","mouseout","mouseup","mousedown","mousemove","contextmenu"],touch:["touchstart","touchend","touchmove"],pointer:z(Fi,(function(t){var e=t.replace("mouse","pointer");return Gi.hasOwnProperty(e)?e:t}))}),Xi=["mousemove","mouseup"],Ui=["pointermove","pointerup"],Zi=!1;function ji(t){var e=t.pointerType;return"pen"===e||"touch"===e}function qi(t){t&&(t.zrByTouch=!0)}function Ki(t,e){for(var n=e,i=!1;n&&9!==n.nodeType&&!(i=n.domBelongToZr||n!==e&&n===t.painterRoot);)n=n.parentNode;return i}var $i=function(t,e){this.stopPropagation=bt,this.stopImmediatePropagation=bt,this.preventDefault=bt,this.type=e.type,this.target=this.currentTarget=t.dom,this.pointerType=e.pointerType,this.clientX=e.clientX,this.clientY=e.clientY},Ji={mousedown:function(t){t=ce(this.dom,t),this.__mayPointerCapture=[t.zrX,t.zrY],this.trigger("mousedown",t)},mousemove:function(t){t=ce(this.dom,t);var e=this.__mayPointerCapture;!e||t.zrX===e[0]&&t.zrY===e[1]||this.__togglePointerCapture(!0),this.trigger("mousemove",t)},mouseup:function(t){t=ce(this.dom,t),this.__togglePointerCapture(!1),this.trigger("mouseup",t)},mouseout:function(t){Ki(this,(t=ce(this.dom,t)).toElement||t.relatedTarget)||(this.__pointerCapturing&&(t.zrEventControl="no_globalout"),this.trigger("mouseout",t))},wheel:function(t){Zi=!0,t=ce(this.dom,t),this.trigger("mousewheel",t)},mousewheel:function(t){Zi||(t=ce(this.dom,t),this.trigger("mousewheel",t))},touchstart:function(t){qi(t=ce(this.dom,t)),this.__lastTouchMoment=new Date,this.handler.processGesture(t,"start"),Ji.mousemove.call(this,t),Ji.mousedown.call(this,t)},touchmove:function(t){qi(t=ce(this.dom,t)),this.handler.processGesture(t,"change"),Ji.mousemove.call(this,t)},touchend:function(t){qi(t=ce(this.dom,t)),this.handler.processGesture(t,"end"),Ji.mouseup.call(this,t),+new Date-+this.__lastTouchMoment<300&&Ji.click.call(this,t)},pointerdown:function(t){Ji.mousedown.call(this,t)},pointermove:function(t){ji(t)||Ji.mousemove.call(this,t)},pointerup:function(t){Ji.mouseup.call(this,t)},pointerout:function(t){ji(t)||Ji.mouseout.call(this,t)}};E(["click","dblclick","contextmenu"],(function(t){Ji[t]=function(e){e=ce(this.dom,e),this.trigger(t,e)}}));var Qi={pointermove:function(t){ji(t)||Qi.mousemove.call(this,t)},pointerup:function(t){Qi.mouseup.call(this,t)},mousemove:function(t){this.trigger("mousemove",t)},mouseup:function(t){var e=this.__pointerCapturing;this.__togglePointerCapture(!1),this.trigger("mouseup",t),e&&(t.zrEventControl="only_globalout",this.trigger("mouseout",t))}};function tr(t,e){var n=e.domHandlers;r.pointerEventsSupported?E(Yi.pointer,(function(i){nr(e,i,(function(e){n[i].call(t,e)}))})):(r.touchEventsSupported&&E(Yi.touch,(function(i){nr(e,i,(function(r){n[i].call(t,r),function(t){t.touching=!0,null!=t.touchTimer&&(clearTimeout(t.touchTimer),t.touchTimer=null),t.touchTimer=setTimeout((function(){t.touching=!1,t.touchTimer=null}),700)}(e)}))})),E(Yi.mouse,(function(i){nr(e,i,(function(r){r=he(r),e.touching||n[i].call(t,r)}))})))}function er(t,e){function n(n){nr(e,n,(function(i){i=he(i),Ki(t,i.target)||(i=function(t,e){return ce(t.dom,new $i(t,e),!0)}(t,i),e.domHandlers[n].call(t,i))}),{capture:!0})}r.pointerEventsSupported?E(Ui,n):r.touchEventsSupported||E(Xi,n)}function nr(t,e,n,i){t.mounted[e]=n,t.listenerOpts[e]=i,pe(t.domTarget,e,n,i)}function ir(t){var e,n,i,r,o=t.mounted;for(var a in o)o.hasOwnProperty(a)&&(e=t.domTarget,n=a,i=o[a],r=t.listenerOpts[a],e.removeEventListener(n,i,r));t.mounted={}}var rr=function(t,e){this.mounted={},this.listenerOpts={},this.touching=!1,this.domTarget=t,this.domHandlers=e},or=function(t){function e(e,n){var i=t.call(this)||this;return i.__pointerCapturing=!1,i.dom=e,i.painterRoot=n,i._localHandlerScope=new rr(e,Ji),Hi&&(i._globalHandlerScope=new rr(document,Qi)),tr(i,i._localHandlerScope),i}return n(e,t),e.prototype.dispose=function(){ir(this._localHandlerScope),Hi&&ir(this._globalHandlerScope)},e.prototype.setCursor=function(t){this.dom.style&&(this.dom.style.cursor=t||"default")},e.prototype.__togglePointerCapture=function(t){if(this.__mayPointerCapture=null,Hi&&+this.__pointerCapturing^+t){this.__pointerCapturing=t;var e=this._globalHandlerScope;t?er(this,e):ir(e)}},e}(jt),ar=1;r.hasGlobalWindow&&(ar=Math.max(window.devicePixelRatio||window.screen&&window.screen.deviceXDPI/window.screen.logicalXDPI||1,1));var sr=ar,lr="#333",ur="#ccc",hr=xe,cr=5e-5;function pr(t){return t>cr||t<-5e-5}var dr=[],fr=[],gr=[1,0,0,1,0,0],yr=Math.abs,vr=function(){function t(){}return t.prototype.getLocalTransform=function(e){return t.getLocalTransform(this,e)},t.prototype.setPosition=function(t){this.x=t[0],this.y=t[1]},t.prototype.setScale=function(t){this.scaleX=t[0],this.scaleY=t[1]},t.prototype.setSkew=function(t){this.skewX=t[0],this.skewY=t[1]},t.prototype.setOrigin=function(t){this.originX=t[0],this.originY=t[1]},t.prototype.needLocalTransform=function(){return pr(this.rotation)||pr(this.x)||pr(this.y)||pr(this.scaleX-1)||pr(this.scaleY-1)||pr(this.skewX)||pr(this.skewY)},t.prototype.updateTransform=function(){var t=this.parent&&this.parent.transform,e=this.needLocalTransform(),n=this.transform;e||t?(n=n||[1,0,0,1,0,0],e?this.getLocalTransform(n):hr(n),t&&(e?be(n,t,n):_e(n,t)),this.transform=n,this._resolveGlobalScaleRatio(n)):n&&(hr(n),this.invTransform=null)},t.prototype._resolveGlobalScaleRatio=function(t){var e=this.globalScaleRatio;if(null!=e&&1!==e){this.getGlobalScale(dr);var n=dr[0]<0?-1:1,i=dr[1]<0?-1:1,r=((dr[0]-n)*e+n)/dr[0]||0,o=((dr[1]-i)*e+i)/dr[1]||0;t[0]*=r,t[1]*=r,t[2]*=o,t[3]*=o}this.invTransform=this.invTransform||[1,0,0,1,0,0],Ie(this.invTransform,t)},t.prototype.getComputedTransform=function(){for(var t=this,e=[];t;)e.push(t),t=t.parent;for(;t=e.pop();)t.updateTransform();return this.transform},t.prototype.setLocalTransform=function(t){if(t){var e=t[0]*t[0]+t[1]*t[1],n=t[2]*t[2]+t[3]*t[3],i=Math.atan2(t[1],t[0]),r=Math.PI/2+i-Math.atan2(t[3],t[2]);n=Math.sqrt(n)*Math.cos(r),e=Math.sqrt(e),this.skewX=r,this.skewY=0,this.rotation=-i,this.x=+t[4],this.y=+t[5],this.scaleX=e,this.scaleY=n,this.originX=0,this.originY=0}},t.prototype.decomposeTransform=function(){if(this.transform){var t=this.parent,e=this.transform;t&&t.transform&&(t.invTransform=t.invTransform||[1,0,0,1,0,0],be(fr,t.invTransform,e),e=fr);var n=this.originX,i=this.originY;(n||i)&&(gr[4]=n,gr[5]=i,be(fr,e,gr),fr[4]-=n,fr[5]-=i,e=fr),this.setLocalTransform(e)}},t.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)},t.prototype.transformCoordToLocal=function(t,e){var n=[t,e],i=this.invTransform;return i&&Wt(n,n,i),n},t.prototype.transformCoordToGlobal=function(t,e){var n=[t,e],i=this.transform;return i&&Wt(n,n,i),n},t.prototype.getLineScale=function(){var t=this.transform;return t&&yr(t[0]-1)>1e-10&&yr(t[3]-1)>1e-10?Math.sqrt(yr(t[0]*t[3]-t[2]*t[1])):1},t.prototype.copyTransform=function(t){xr(this,t)},t.getLocalTransform=function(t,e){e=e||[];var n=t.originX||0,i=t.originY||0,r=t.scaleX,o=t.scaleY,a=t.anchorX,s=t.anchorY,l=t.rotation||0,u=t.x,h=t.y,c=t.skewX?Math.tan(t.skewX):0,p=t.skewY?Math.tan(-t.skewY):0;if(n||i||a||s){var d=n+a,f=i+s;e[4]=-d*r-c*f*o,e[5]=-f*o-p*d*r}else e[4]=e[5]=0;return e[0]=r,e[3]=o,e[1]=p*r,e[2]=c*o,l&&Se(e,e,l),e[4]+=n+u,e[5]+=i+h,e},t.initDefaultProps=function(){var e=t.prototype;e.scaleX=e.scaleY=e.globalScaleRatio=1,e.x=e.y=e.originX=e.originY=e.skewX=e.skewY=e.rotation=e.anchorX=e.anchorY=0}(),t}(),mr=["x","y","originX","originY","anchorX","anchorY","rotation","scaleX","scaleY","skewX","skewY"];function xr(t,e){for(var n=0;n=0?parseFloat(t)/100*e:parseFloat(t):t}function Dr(t,e,n){var i=e.position||"inside",r=null!=e.distance?e.distance:5,o=n.height,a=n.width,s=o/2,l=n.x,u=n.y,h="left",c="top";if(i instanceof Array)l+=Cr(i[0],n.width),u+=Cr(i[1],n.height),h=null,c=null;else switch(i){case"left":l-=r,u+=s,h="right",c="middle";break;case"right":l+=r+a,u+=s,c="middle";break;case"top":l+=a/2,u-=r,h="center",c="bottom";break;case"bottom":l+=a/2,u+=o+r,h="center";break;case"inside":l+=a/2,u+=s,h="center",c="middle";break;case"insideLeft":l+=r,u+=s,c="middle";break;case"insideRight":l+=a-r,u+=s,h="right",c="middle";break;case"insideTop":l+=a/2,u+=r,h="center";break;case"insideBottom":l+=a/2,u+=o-r,h="center",c="bottom";break;case"insideTopLeft":l+=r,u+=r;break;case"insideTopRight":l+=a-r,u+=r,h="right";break;case"insideBottomLeft":l+=r,u+=o-r,c="bottom";break;case"insideBottomRight":l+=a-r,u+=o-r,h="right",c="bottom"}return(t=t||{}).x=l,t.y=u,t.align=h,t.verticalAlign=c,t}var Ar="__zr_normal__",kr=mr.concat(["ignore"]),Lr=V(mr,(function(t,e){return t[e]=!0,t}),{ignore:!1}),Pr={},Or=new ze(0,0,0,0),Rr=function(){function t(t){this.id=M(),this.animators=[],this.currentStates=[],this.states={},this._init(t)}return t.prototype._init=function(t){this.attr(t)},t.prototype.drift=function(t,e,n){switch(this.draggable){case"horizontal":e=0;break;case"vertical":t=0}var i=this.transform;i||(i=this.transform=[1,0,0,1,0,0]),i[4]+=t,i[5]+=e,this.decomposeTransform(),this.markRedraw()},t.prototype.beforeUpdate=function(){},t.prototype.afterUpdate=function(){},t.prototype.update=function(){this.updateTransform(),this.__dirty&&this.updateInnerText()},t.prototype.updateInnerText=function(t){var e=this._textContent;if(e&&(!e.ignore||t)){this.textConfig||(this.textConfig={});var n=this.textConfig,i=n.local,r=e.innerTransformable,o=void 0,a=void 0,s=!1;r.parent=i?this:null;var l=!1;if(r.copyTransform(e),null!=n.position){var u=Or;n.layoutRect?u.copy(n.layoutRect):u.copy(this.getBoundingRect()),i||u.applyTransform(this.transform),this.calculateTextPosition?this.calculateTextPosition(Pr,n,u):Dr(Pr,n,u),r.x=Pr.x,r.y=Pr.y,o=Pr.align,a=Pr.verticalAlign;var h=n.origin;if(h&&null!=n.rotation){var c=void 0,p=void 0;"center"===h?(c=.5*u.width,p=.5*u.height):(c=Cr(h[0],u.width),p=Cr(h[1],u.height)),l=!0,r.originX=-r.x+c+(i?0:u.x),r.originY=-r.y+p+(i?0:u.y)}}null!=n.rotation&&(r.rotation=n.rotation);var d=n.offset;d&&(r.x+=d[0],r.y+=d[1],l||(r.originX=-d[0],r.originY=-d[1]));var f=null==n.inside?"string"==typeof n.position&&n.position.indexOf("inside")>=0:n.inside,g=this._innerTextDefaultStyle||(this._innerTextDefaultStyle={}),y=void 0,v=void 0,m=void 0;f&&this.canBeInsideText()?(y=n.insideFill,v=n.insideStroke,null!=y&&"auto"!==y||(y=this.getInsideTextFill()),null!=v&&"auto"!==v||(v=this.getInsideTextStroke(y),m=!0)):(y=n.outsideFill,v=n.outsideStroke,null!=y&&"auto"!==y||(y=this.getOutsideFill()),null!=v&&"auto"!==v||(v=this.getOutsideStroke(y),m=!0)),(y=y||"#000")===g.fill&&v===g.stroke&&m===g.autoStroke&&o===g.align&&a===g.verticalAlign||(s=!0,g.fill=y,g.stroke=v,g.autoStroke=m,g.align=o,g.verticalAlign=a,e.setDefaultTextStyle(g)),e.__dirty|=1,s&&e.dirtyStyle(!0)}},t.prototype.canBeInsideText=function(){return!0},t.prototype.getInsideTextFill=function(){return"#fff"},t.prototype.getInsideTextStroke=function(t){return"#000"},t.prototype.getOutsideFill=function(){return this.__zr&&this.__zr.isDarkMode()?ur:lr},t.prototype.getOutsideStroke=function(t){var e=this.__zr&&this.__zr.getBackgroundColor(),n="string"==typeof e&&qn(e);n||(n=[255,255,255,1]);for(var i=n[3],r=this.__zr.isDarkMode(),o=0;o<3;o++)n[o]=n[o]*i+(r?0:255)*(1-i);return n[3]=1,ri(n,"rgba")},t.prototype.traverse=function(t,e){},t.prototype.attrKV=function(t,e){"textConfig"===t?this.setTextConfig(e):"textContent"===t?this.setTextContent(e):"clipPath"===t?this.setClipPath(e):"extra"===t?(this.extra=this.extra||{},A(this.extra,e)):this[t]=e},t.prototype.hide=function(){this.ignore=!0,this.markRedraw()},t.prototype.show=function(){this.ignore=!1,this.markRedraw()},t.prototype.attr=function(t,e){if("string"==typeof t)this.attrKV(t,e);else if(q(t))for(var n=G(t),i=0;i0},t.prototype.getState=function(t){return this.states[t]},t.prototype.ensureState=function(t){var e=this.states;return e[t]||(e[t]={}),e[t]},t.prototype.clearStates=function(t){this.useState(Ar,!1,t)},t.prototype.useState=function(t,e,n,i){var r=t===Ar;if(this.hasState()||!r){var o=this.currentStates,a=this.stateTransition;if(!(P(o,t)>=0)||!e&&1!==o.length){var s;if(this.stateProxy&&!r&&(s=this.stateProxy(t)),s||(s=this.states&&this.states[t]),s||r){r||this.saveCurrentToNormalState(s);var l=!!(s&&s.hoverLayer||i);l&&this._toggleHoverLayerFlag(!0),this._applyStateObj(t,s,this._normalState,e,!n&&!this.__inHover&&a&&a.duration>0,a);var u=this._textContent,h=this._textGuide;return u&&u.useState(t,e,n,l),h&&h.useState(t,e,n,l),r?(this.currentStates=[],this._normalState={}):e?this.currentStates.push(t):this.currentStates=[t],this._updateAnimationTargets(),this.markRedraw(),!l&&this.__inHover&&(this._toggleHoverLayerFlag(!1),this.__dirty&=-2),s}I("State "+t+" not exists.")}}},t.prototype.useStates=function(t,e,n){if(t.length){var i=[],r=this.currentStates,o=t.length,a=o===r.length;if(a)for(var s=0;s0,d);var f=this._textContent,g=this._textGuide;f&&f.useStates(t,e,c),g&&g.useStates(t,e,c),this._updateAnimationTargets(),this.currentStates=t.slice(),this.markRedraw(),!c&&this.__inHover&&(this._toggleHoverLayerFlag(!1),this.__dirty&=-2)}else this.clearStates()},t.prototype.isSilent=function(){for(var t=this.silent,e=this.parent;!t&&e;){if(e.silent){t=!0;break}e=e.parent}return t},t.prototype._updateAnimationTargets=function(){for(var t=0;t=0){var n=this.currentStates.slice();n.splice(e,1),this.useStates(n)}},t.prototype.replaceState=function(t,e,n){var i=this.currentStates.slice(),r=P(i,t),o=P(i,e)>=0;r>=0?o?i.splice(r,1):i[r]=e:n&&!o&&i.push(e),this.useStates(i)},t.prototype.toggleState=function(t,e){e?this.useState(t,!0):this.removeState(t)},t.prototype._mergeStates=function(t){for(var e,n={},i=0;i=0&&e.splice(n,1)})),this.animators.push(t),n&&n.animation.addAnimator(t),n&&n.wakeUp()},t.prototype.updateDuringAnimation=function(t){this.markRedraw()},t.prototype.stopAnimation=function(t,e){for(var n=this.animators,i=n.length,r=[],o=0;o0&&n.during&&o[0].during((function(t,e){n.during(e)}));for(var p=0;p0||r.force&&!a.length){var w,S=void 0,M=void 0,I=void 0;if(s){M={},p&&(S={});for(_=0;_=0&&(n.splice(i,0,t),this._doAdd(t))}return this},e.prototype.replace=function(t,e){var n=P(this._children,t);return n>=0&&this.replaceAt(e,n),this},e.prototype.replaceAt=function(t,e){var n=this._children,i=n[e];if(t&&t!==this&&t.parent!==this&&t!==i){n[e]=t,i.parent=null;var r=this.__zr;r&&i.removeSelfFromZr(r),this._doAdd(t)}return this},e.prototype._doAdd=function(t){t.parent&&t.parent.remove(t),t.parent=this;var e=this.__zr;e&&e!==t.__zr&&t.addSelfToZr(e),e&&e.refresh()},e.prototype.remove=function(t){var e=this.__zr,n=this._children,i=P(n,t);return i<0||(n.splice(i,1),t.parent=null,e&&t.removeSelfFromZr(e),e&&e.refresh()),this},e.prototype.removeAll=function(){for(var t=this._children,e=this.__zr,n=0;n0&&(this._stillFrameAccum++,this._stillFrameAccum>this._sleepAfterStill&&this.animation.stop())},t.prototype.setSleepAfterStill=function(t){this._sleepAfterStill=t},t.prototype.wakeUp=function(){this._disposed||(this.animation.start(),this._stillFrameAccum=0)},t.prototype.refreshHover=function(){this._needsRefreshHover=!0},t.prototype.refreshHoverImmediately=function(){this._disposed||(this._needsRefreshHover=!1,this.painter.refreshHover&&"canvas"===this.painter.getType()&&this.painter.refreshHover())},t.prototype.resize=function(t){this._disposed||(t=t||{},this.painter.resize(t.width,t.height),this.handler.resize())},t.prototype.clearAnimation=function(){this._disposed||this.animation.clear()},t.prototype.getWidth=function(){if(!this._disposed)return this.painter.getWidth()},t.prototype.getHeight=function(){if(!this._disposed)return this.painter.getHeight()},t.prototype.setCursorStyle=function(t){this._disposed||this.handler.setCursorStyle(t)},t.prototype.findHover=function(t,e){if(!this._disposed)return this.handler.findHover(t,e)},t.prototype.on=function(t,e,n){return this._disposed||this.handler.on(t,e,n),this},t.prototype.off=function(t,e){this._disposed||this.handler.off(t,e)},t.prototype.trigger=function(t,e){this._disposed||this.handler.trigger(t,e)},t.prototype.clear=function(){if(!this._disposed){for(var t=this.storage.getRoots(),e=0;e0){if(t<=r)return a;if(t>=o)return s}else{if(t>=r)return a;if(t<=o)return s}else{if(t===r)return a;if(t===o)return s}return(t-r)/l*u+a}function $r(t,e){switch(t){case"center":case"middle":t="50%";break;case"left":case"top":t="0%";break;case"right":case"bottom":t="100%"}return U(t)?(n=t,n.replace(/^\s+|\s+$/g,"")).match(/%$/)?parseFloat(t)/100*e:parseFloat(t):null==t?NaN:+t;var n}function Jr(t,e,n){return null==e&&(e=10),e=Math.min(Math.max(0,e),20),t=(+t).toFixed(e),n?t:+t}function Qr(t){return t.sort((function(t,e){return t-e})),t}function to(t){if(t=+t,isNaN(t))return 0;if(t>1e-14)for(var e=1,n=0;n<15;n++,e*=10)if(Math.round(t*e)/e===t)return n;return eo(t)}function eo(t){var e=t.toString().toLowerCase(),n=e.indexOf("e"),i=n>0?+e.slice(n+1):0,r=n>0?n:e.length,o=e.indexOf("."),a=o<0?0:r-1-o;return Math.max(0,a-i)}function no(t,e){var n=Math.log,i=Math.LN10,r=Math.floor(n(t[1]-t[0])/i),o=Math.round(n(Math.abs(e[1]-e[0]))/i),a=Math.min(Math.max(-r+o,0),20);return isFinite(a)?a:20}function io(t,e){var n=V(t,(function(t,e){return t+(isNaN(e)?0:e)}),0);if(0===n)return[];for(var i=Math.pow(10,e),r=z(t,(function(t){return(isNaN(t)?0:t)/n*i*100})),o=100*i,a=z(r,(function(t){return Math.floor(t)})),s=V(a,(function(t,e){return t+e}),0),l=z(r,(function(t,e){return t-a[e]}));su&&(u=l[c],h=c);++a[h],l[h]=0,++s}return z(a,(function(t){return t/i}))}function ro(t,e){var n=Math.max(to(t),to(e)),i=t+e;return n>20?i:Jr(i,n)}var oo=9007199254740991;function ao(t){var e=2*Math.PI;return(t%e+e)%e}function so(t){return t>-1e-4&&t=10&&e++,e}function po(t,e){var n=co(t),i=Math.pow(10,n),r=t/i;return t=(e?r<1.5?1:r<2.5?2:r<4?3:r<7?5:10:r<1?1:r<2?2:r<3?3:r<5?5:10)*i,n>=-20?+t.toFixed(n<0?-n:0):t}function fo(t,e){var n=(t.length-1)*e+1,i=Math.floor(n),r=+t[i-1],o=n-i;return o?r+o*(t[i]-r):r}function go(t){t.sort((function(t,e){return s(t,e,0)?-1:1}));for(var e=-1/0,n=1,i=0;i=0||r&&P(r,s)<0)){var l=n.getShallow(s,e);null!=l&&(o[t[a][0]]=l)}}return o}}var ra=ia([["fill","color"],["shadowBlur"],["shadowOffsetX"],["shadowOffsetY"],["opacity"],["shadowColor"]]),oa=function(){function t(){}return t.prototype.getAreaStyle=function(t,e){return ra(this,t,e)},t}(),aa=new En(50);function sa(t){if("string"==typeof t){var e=aa.get(t);return e&&e.image}return t}function la(t,e,n,i,r){if(t){if("string"==typeof t){if(e&&e.__zrImageSrc===t||!n)return e;var o=aa.get(t),a={hostEl:n,cb:i,cbPayload:r};return o?!ha(e=o.image)&&o.pending.push(a):((e=h.loadImage(t,ua,ua)).__zrImageSrc=t,aa.put(t,e.__cachedImgObj={image:e,pending:[a]})),e}return t}return e}function ua(){var t=this.__cachedImgObj;this.onload=this.onerror=this.__cachedImgObj=null;for(var e=0;e=a;l++)s-=a;var u=br(n,e);return u>s&&(n="",u=0),s=t-u,r.ellipsis=n,r.ellipsisWidth=u,r.contentWidth=s,r.containerWidth=t,r}function fa(t,e,n){var i=n.containerWidth,r=n.font,o=n.contentWidth;if(!i)return t.textLine="",void(t.isTruncated=!1);var a=br(e,r);if(a<=i)return t.textLine=e,void(t.isTruncated=!1);for(var s=0;;s++){if(a<=o||s>=n.maxIterations){e+=n.ellipsis;break}var l=0===s?ga(e,o,n.ascCharWidth,n.cnCharWidth):a>0?Math.floor(e.length*o/a):0;a=br(e=e.substr(0,l),r)}""===e&&(e=n.placeholder),t.textLine=e,t.isTruncated=!0}function ga(t,e,n,i){for(var r=0,o=0,a=t.length;o0&&f+i.accumWidth>i.width&&(o=e.split("\n"),c=!0),i.accumWidth=f}else{var g=wa(e,h,i.width,i.breakAll,i.accumWidth);i.accumWidth=g.accumWidth+d,a=g.linesWidths,o=g.lines}}else o=e.split("\n");for(var y=0;y=32&&e<=591||e>=880&&e<=4351||e>=4608&&e<=5119||e>=7680&&e<=8303}(t)||!!_a[t]}function wa(t,e,n,i,r){for(var o=[],a=[],s="",l="",u=0,h=0,c=0;cn:r+h+d>n)?h?(s||l)&&(f?(s||(s=l,l="",h=u=0),o.push(s),a.push(h-u),l+=p,s="",h=u+=d):(l&&(s+=l,l="",u=0),o.push(s),a.push(h),s=p,h=d)):f?(o.push(l),a.push(u),l=p,u=d):(o.push(p),a.push(d)):(h+=d,f?(l+=p,u+=d):(l&&(s+=l,l="",u=0),s+=p))}else l&&(s+=l,h+=u),o.push(s),a.push(h),s="",l="",u=0,h=0}return o.length||s||(s=t,l="",u=0),l&&(s+=l),s&&(o.push(s),a.push(h)),1===o.length&&(h+=r),{accumWidth:h,lines:o,linesWidths:a}}var Sa="__zr_style_"+Math.round(10*Math.random()),Ma={shadowBlur:0,shadowOffsetX:0,shadowOffsetY:0,shadowColor:"#000",opacity:1,blend:"source-over"},Ia={style:{shadowBlur:!0,shadowOffsetX:!0,shadowOffsetY:!0,shadowColor:!0,opacity:!0}};Ma[Sa]=!0;var Ta=["z","z2","invisible"],Ca=["invisible"],Da=function(t){function e(e){return t.call(this,e)||this}var i;return n(e,t),e.prototype._init=function(e){for(var n=G(e),i=0;i1e-4)return s[0]=t-n,s[1]=e-i,l[0]=t+n,void(l[1]=e+i);if(Ea[0]=Ra(r)*n+t,Ea[1]=Oa(r)*i+e,za[0]=Ra(o)*n+t,za[1]=Oa(o)*i+e,u(s,Ea,za),h(l,Ea,za),(r%=Na)<0&&(r+=Na),(o%=Na)<0&&(o+=Na),r>o&&!a?o+=Na:rr&&(Va[0]=Ra(d)*n+t,Va[1]=Oa(d)*i+e,u(s,Va,s),h(l,Va,l))}var Ua={M:1,L:2,C:3,Q:4,A:5,Z:6,R:7},Za=[],ja=[],qa=[],Ka=[],$a=[],Ja=[],Qa=Math.min,ts=Math.max,es=Math.cos,ns=Math.sin,is=Math.abs,rs=Math.PI,os=2*rs,as="undefined"!=typeof Float32Array,ss=[];function ls(t){return Math.round(t/rs*1e8)/1e8%2*rs}function us(t,e){var n=ls(t[0]);n<0&&(n+=os);var i=n-t[0],r=t[1];r+=i,!e&&r-n>=os?r=n+os:e&&n-r>=os?r=n-os:!e&&n>r?r=n+(os-ls(n-r)):e&&n0&&(this._ux=is(n/sr/t)||0,this._uy=is(n/sr/e)||0)},t.prototype.setDPR=function(t){this.dpr=t},t.prototype.setContext=function(t){this._ctx=t},t.prototype.getContext=function(){return this._ctx},t.prototype.beginPath=function(){return this._ctx&&this._ctx.beginPath(),this.reset(),this},t.prototype.reset=function(){this._saveData&&(this._len=0),this._pathSegLen&&(this._pathSegLen=null,this._pathLen=0),this._version++},t.prototype.moveTo=function(t,e){return this._drawPendingPt(),this.addData(Ua.M,t,e),this._ctx&&this._ctx.moveTo(t,e),this._x0=t,this._y0=e,this._xi=t,this._yi=e,this},t.prototype.lineTo=function(t,e){var n=is(t-this._xi),i=is(e-this._yi),r=n>this._ux||i>this._uy;if(this.addData(Ua.L,t,e),this._ctx&&r&&this._ctx.lineTo(t,e),r)this._xi=t,this._yi=e,this._pendingPtDist=0;else{var o=n*n+i*i;o>this._pendingPtDist&&(this._pendingPtX=t,this._pendingPtY=e,this._pendingPtDist=o)}return this},t.prototype.bezierCurveTo=function(t,e,n,i,r,o){return this._drawPendingPt(),this.addData(Ua.C,t,e,n,i,r,o),this._ctx&&this._ctx.bezierCurveTo(t,e,n,i,r,o),this._xi=r,this._yi=o,this},t.prototype.quadraticCurveTo=function(t,e,n,i){return this._drawPendingPt(),this.addData(Ua.Q,t,e,n,i),this._ctx&&this._ctx.quadraticCurveTo(t,e,n,i),this._xi=n,this._yi=i,this},t.prototype.arc=function(t,e,n,i,r,o){this._drawPendingPt(),ss[0]=i,ss[1]=r,us(ss,o),i=ss[0];var a=(r=ss[1])-i;return this.addData(Ua.A,t,e,n,n,i,a,0,o?0:1),this._ctx&&this._ctx.arc(t,e,n,i,r,o),this._xi=es(r)*n+t,this._yi=ns(r)*n+e,this},t.prototype.arcTo=function(t,e,n,i,r){return this._drawPendingPt(),this._ctx&&this._ctx.arcTo(t,e,n,i,r),this},t.prototype.rect=function(t,e,n,i){return this._drawPendingPt(),this._ctx&&this._ctx.rect(t,e,n,i),this.addData(Ua.R,t,e,n,i),this},t.prototype.closePath=function(){this._drawPendingPt(),this.addData(Ua.Z);var t=this._ctx,e=this._x0,n=this._y0;return t&&t.closePath(),this._xi=e,this._yi=n,this},t.prototype.fill=function(t){t&&t.fill(),this.toStatic()},t.prototype.stroke=function(t){t&&t.stroke(),this.toStatic()},t.prototype.len=function(){return this._len},t.prototype.setData=function(t){var e=t.length;this.data&&this.data.length===e||!as||(this.data=new Float32Array(e));for(var n=0;nu.length&&(this._expandData(),u=this.data);for(var h=0;h0&&(this._ctx&&this._ctx.lineTo(this._pendingPtX,this._pendingPtY),this._pendingPtDist=0)},t.prototype._expandData=function(){if(!(this.data instanceof Array)){for(var t=[],e=0;e11&&(this.data=new Float32Array(t)))}},t.prototype.getBoundingRect=function(){qa[0]=qa[1]=$a[0]=$a[1]=Number.MAX_VALUE,Ka[0]=Ka[1]=Ja[0]=Ja[1]=-Number.MAX_VALUE;var t,e=this.data,n=0,i=0,r=0,o=0;for(t=0;tn||is(y)>i||c===e-1)&&(f=Math.sqrt(A*A+y*y),r=g,o=x);break;case Ua.C:var v=t[c++],m=t[c++],x=(g=t[c++],t[c++]),_=t[c++],b=t[c++];f=Mn(r,o,v,m,g,x,_,b,10),r=_,o=b;break;case Ua.Q:f=kn(r,o,v=t[c++],m=t[c++],g=t[c++],x=t[c++],10),r=g,o=x;break;case Ua.A:var w=t[c++],S=t[c++],M=t[c++],I=t[c++],T=t[c++],C=t[c++],D=C+T;c+=1,d&&(a=es(T)*M+w,s=ns(T)*I+S),f=ts(M,I)*Qa(os,Math.abs(C)),r=es(D)*M+w,o=ns(D)*I+S;break;case Ua.R:a=r=t[c++],s=o=t[c++],f=2*t[c++]+2*t[c++];break;case Ua.Z:var A=a-r;y=s-o;f=Math.sqrt(A*A+y*y),r=a,o=s}f>=0&&(l[h++]=f,u+=f)}return this._pathLen=u,u},t.prototype.rebuildPath=function(t,e){var n,i,r,o,a,s,l,u,h,c,p=this.data,d=this._ux,f=this._uy,g=this._len,y=e<1,v=0,m=0,x=0;if(!y||(this._pathSegLen||this._calculateLength(),l=this._pathSegLen,u=e*this._pathLen))t:for(var _=0;_0&&(t.lineTo(h,c),x=0),b){case Ua.M:n=r=p[_++],i=o=p[_++],t.moveTo(r,o);break;case Ua.L:a=p[_++],s=p[_++];var S=is(a-r),M=is(s-o);if(S>d||M>f){if(y){if(v+(j=l[m++])>u){var I=(u-v)/j;t.lineTo(r*(1-I)+a*I,o*(1-I)+s*I);break t}v+=j}t.lineTo(a,s),r=a,o=s,x=0}else{var T=S*S+M*M;T>x&&(h=a,c=s,x=T)}break;case Ua.C:var C=p[_++],D=p[_++],A=p[_++],k=p[_++],L=p[_++],P=p[_++];if(y){if(v+(j=l[m++])>u){wn(r,C,A,L,I=(u-v)/j,Za),wn(o,D,k,P,I,ja),t.bezierCurveTo(Za[1],ja[1],Za[2],ja[2],Za[3],ja[3]);break t}v+=j}t.bezierCurveTo(C,D,A,k,L,P),r=L,o=P;break;case Ua.Q:C=p[_++],D=p[_++],A=p[_++],k=p[_++];if(y){if(v+(j=l[m++])>u){Dn(r,C,A,I=(u-v)/j,Za),Dn(o,D,k,I,ja),t.quadraticCurveTo(Za[1],ja[1],Za[2],ja[2]);break t}v+=j}t.quadraticCurveTo(C,D,A,k),r=A,o=k;break;case Ua.A:var O=p[_++],R=p[_++],N=p[_++],E=p[_++],z=p[_++],V=p[_++],B=p[_++],F=!p[_++],G=N>E?N:E,W=is(N-E)>.001,H=z+V,Y=!1;if(y)v+(j=l[m++])>u&&(H=z+V*(u-v)/j,Y=!0),v+=j;if(W&&t.ellipse?t.ellipse(O,R,N,E,B,z,H,F):t.arc(O,R,G,z,H,F),Y)break t;w&&(n=es(z)*N+O,i=ns(z)*E+R),r=es(H)*N+O,o=ns(H)*E+R;break;case Ua.R:n=r=p[_],i=o=p[_+1],a=p[_++],s=p[_++];var X=p[_++],U=p[_++];if(y){if(v+(j=l[m++])>u){var Z=u-v;t.moveTo(a,s),t.lineTo(a+Qa(Z,X),s),(Z-=X)>0&&t.lineTo(a+X,s+Qa(Z,U)),(Z-=U)>0&&t.lineTo(a+ts(X-Z,0),s+U),(Z-=X)>0&&t.lineTo(a,s+ts(U-Z,0));break t}v+=j}t.rect(a,s,X,U);break;case Ua.Z:if(y){var j;if(v+(j=l[m++])>u){I=(u-v)/j;t.lineTo(r*(1-I)+n*I,o*(1-I)+i*I);break t}v+=j}t.closePath(),r=n,o=i}}},t.prototype.clone=function(){var e=new t,n=this.data;return e.data=n.slice?n.slice():Array.prototype.slice.call(n),e._len=this._len,e},t.CMD=Ua,t.initDefaultProps=function(){var e=t.prototype;e._saveData=!0,e._ux=0,e._uy=0,e._pendingPtDist=0,e._version=0}(),t}();function cs(t,e,n,i,r,o,a){if(0===r)return!1;var s=r,l=0;if(a>e+s&&a>i+s||at+s&&o>n+s||oe+c&&h>i+c&&h>o+c&&h>s+c||ht+c&&u>n+c&&u>r+c&&u>a+c||ue+u&&l>i+u&&l>o+u||lt+u&&s>n+u&&s>r+u||sn||h+ur&&(r+=ys);var p=Math.atan2(l,s);return p<0&&(p+=ys),p>=i&&p<=r||p+ys>=i&&p+ys<=r}function ms(t,e,n,i,r,o){if(o>e&&o>i||or?s:0}var xs=hs.CMD,_s=2*Math.PI;var bs=[-1,-1,-1],ws=[-1,-1];function Ss(t,e,n,i,r,o,a,s,l,u){if(u>e&&u>i&&u>o&&u>s||u1&&(h=void 0,h=ws[0],ws[0]=ws[1],ws[1]=h),f=mn(e,i,o,s,ws[0]),d>1&&(g=mn(e,i,o,s,ws[1]))),2===d?ve&&s>i&&s>o||s=0&&h<=1&&(r[l++]=h);else{var u=a*a-4*o*s;if(yn(u))(h=-a/(2*o))>=0&&h<=1&&(r[l++]=h);else if(u>0){var h,c=ln(u),p=(-a-c)/(2*o);(h=(-a+c)/(2*o))>=0&&h<=1&&(r[l++]=h),p>=0&&p<=1&&(r[l++]=p)}}return l}(e,i,o,s,bs);if(0===l)return 0;var u=Cn(e,i,o);if(u>=0&&u<=1){for(var h=0,c=In(e,i,o,u),p=0;pn||s<-n)return 0;var l=Math.sqrt(n*n-s*s);bs[0]=-l,bs[1]=l;var u=Math.abs(i-r);if(u<1e-4)return 0;if(u>=_s-1e-4){i=0,r=_s;var h=o?1:-1;return a>=bs[0]+t&&a<=bs[1]+t?h:0}if(i>r){var c=i;i=r,r=c}i<0&&(i+=_s,r+=_s);for(var p=0,d=0;d<2;d++){var f=bs[d];if(f+t>a){var g=Math.atan2(s,f);h=o?1:-1;g<0&&(g=_s+g),(g>=i&&g<=r||g+_s>=i&&g+_s<=r)&&(g>Math.PI/2&&g<1.5*Math.PI&&(h=-h),p+=h)}}return p}function Ts(t,e,n,i,r){for(var o,a,s,l,u=t.data,h=t.len(),c=0,p=0,d=0,f=0,g=0,y=0;y1&&(n||(c+=ms(p,d,f,g,i,r))),m&&(f=p=u[y],g=d=u[y+1]),v){case xs.M:p=f=u[y++],d=g=u[y++];break;case xs.L:if(n){if(cs(p,d,u[y],u[y+1],e,i,r))return!0}else c+=ms(p,d,u[y],u[y+1],i,r)||0;p=u[y++],d=u[y++];break;case xs.C:if(n){if(ps(p,d,u[y++],u[y++],u[y++],u[y++],u[y],u[y+1],e,i,r))return!0}else c+=Ss(p,d,u[y++],u[y++],u[y++],u[y++],u[y],u[y+1],i,r)||0;p=u[y++],d=u[y++];break;case xs.Q:if(n){if(ds(p,d,u[y++],u[y++],u[y],u[y+1],e,i,r))return!0}else c+=Ms(p,d,u[y++],u[y++],u[y],u[y+1],i,r)||0;p=u[y++],d=u[y++];break;case xs.A:var x=u[y++],_=u[y++],b=u[y++],w=u[y++],S=u[y++],M=u[y++];y+=1;var I=!!(1-u[y++]);o=Math.cos(S)*b+x,a=Math.sin(S)*w+_,m?(f=o,g=a):c+=ms(p,d,o,a,i,r);var T=(i-x)*w/b+x;if(n){if(vs(x,_,w,S,S+M,I,e,T,r))return!0}else c+=Is(x,_,w,S,S+M,I,T,r);p=Math.cos(S+M)*b+x,d=Math.sin(S+M)*w+_;break;case xs.R:if(f=p=u[y++],g=d=u[y++],o=f+u[y++],a=g+u[y++],n){if(cs(f,g,o,g,e,i,r)||cs(o,g,o,a,e,i,r)||cs(o,a,f,a,e,i,r)||cs(f,a,f,g,e,i,r))return!0}else c+=ms(o,g,o,a,i,r),c+=ms(f,a,f,g,i,r);break;case xs.Z:if(n){if(cs(p,d,f,g,e,i,r))return!0}else c+=ms(p,d,f,g,i,r);p=f,d=g}}return n||(s=d,l=g,Math.abs(s-l)<1e-4)||(c+=ms(p,d,f,g,i,r)||0),0!==c}var Cs=k({fill:"#000",stroke:null,strokePercent:1,fillOpacity:1,strokeOpacity:1,lineDashOffset:0,lineWidth:1,lineCap:"butt",miterLimit:10,strokeNoScale:!1,strokeFirst:!1},Ma),Ds={style:k({fill:!0,stroke:!0,strokePercent:!0,fillOpacity:!0,strokeOpacity:!0,lineDashOffset:!0,lineWidth:!0,miterLimit:!0},Ia.style)},As=mr.concat(["invisible","culling","z","z2","zlevel","parent"]),ks=function(t){function e(e){return t.call(this,e)||this}var i;return n(e,t),e.prototype.update=function(){var n=this;t.prototype.update.call(this);var i=this.style;if(i.decal){var r=this._decalEl=this._decalEl||new e;r.buildPath===e.prototype.buildPath&&(r.buildPath=function(t){n.buildPath(t,n.shape)}),r.silent=!0;var o=r.style;for(var a in i)o[a]!==i[a]&&(o[a]=i[a]);o.fill=i.fill?i.decal:null,o.decal=null,o.shadowColor=null,i.strokeFirst&&(o.stroke=null);for(var s=0;s.5?lr:e>.2?"#eee":ur}if(t)return ur}return lr},e.prototype.getInsideTextStroke=function(t){var e=this.style.fill;if(U(e)){var n=this.__zr;if(!(!n||!n.isDarkMode())===oi(t,0)<.4)return e}},e.prototype.buildPath=function(t,e,n){},e.prototype.pathUpdated=function(){this.__dirty&=-5},e.prototype.getUpdatedPathProxy=function(t){return!this.path&&this.createPathProxy(),this.path.beginPath(),this.buildPath(this.path,this.shape,t),this.path},e.prototype.createPathProxy=function(){this.path=new hs(!1)},e.prototype.hasStroke=function(){var t=this.style,e=t.stroke;return!(null==e||"none"===e||!(t.lineWidth>0))},e.prototype.hasFill=function(){var t=this.style.fill;return null!=t&&"none"!==t},e.prototype.getBoundingRect=function(){var t=this._rect,e=this.style,n=!t;if(n){var i=!1;this.path||(i=!0,this.createPathProxy());var r=this.path;(i||4&this.__dirty)&&(r.beginPath(),this.buildPath(r,this.shape,!1),this.pathUpdated()),t=r.getBoundingRect()}if(this._rect=t,this.hasStroke()&&this.path&&this.path.len()>0){var o=this._rectStroke||(this._rectStroke=t.clone());if(this.__dirty||n){o.copy(t);var a=e.strokeNoScale?this.getLineScale():1,s=e.lineWidth;if(!this.hasFill()){var l=this.strokeContainThreshold;s=Math.max(s,null==l?4:l)}a>1e-10&&(o.width+=s/a,o.height+=s/a,o.x-=s/a/2,o.y-=s/a/2)}return o}return t},e.prototype.contain=function(t,e){var n=this.transformCoordToLocal(t,e),i=this.getBoundingRect(),r=this.style;if(t=n[0],e=n[1],i.contain(t,e)){var o=this.path;if(this.hasStroke()){var a=r.lineWidth,s=r.strokeNoScale?this.getLineScale():1;if(s>1e-10&&(this.hasFill()||(a=Math.max(a,this.strokeContainThreshold)),function(t,e,n,i){return Ts(t,e,!0,n,i)}(o,a/s,t,e)))return!0}if(this.hasFill())return function(t,e,n){return Ts(t,0,!1,e,n)}(o,t,e)}return!1},e.prototype.dirtyShape=function(){this.__dirty|=4,this._rect&&(this._rect=null),this._decalEl&&this._decalEl.dirtyShape(),this.markRedraw()},e.prototype.dirty=function(){this.dirtyStyle(),this.dirtyShape()},e.prototype.animateShape=function(t){return this.animate("shape",t)},e.prototype.updateDuringAnimation=function(t){"style"===t?this.dirtyStyle():"shape"===t?this.dirtyShape():this.markRedraw()},e.prototype.attrKV=function(e,n){"shape"===e?this.setShape(n):t.prototype.attrKV.call(this,e,n)},e.prototype.setShape=function(t,e){var n=this.shape;return n||(n=this.shape={}),"string"==typeof t?n[t]=e:A(n,t),this.dirtyShape(),this},e.prototype.shapeChanged=function(){return!!(4&this.__dirty)},e.prototype.createStyle=function(t){return mt(Cs,t)},e.prototype._innerSaveToNormal=function(e){t.prototype._innerSaveToNormal.call(this,e);var n=this._normalState;e.shape&&!n.shape&&(n.shape=A({},this.shape))},e.prototype._applyStateObj=function(e,n,i,r,o,a){t.prototype._applyStateObj.call(this,e,n,i,r,o,a);var s,l=!(n&&r);if(n&&n.shape?o?r?s=n.shape:(s=A({},i.shape),A(s,n.shape)):(s=A({},r?this.shape:i.shape),A(s,n.shape)):l&&(s=i.shape),s)if(o){this.shape=A({},this.shape);for(var u={},h=G(s),c=0;c0},e.prototype.hasFill=function(){var t=this.style.fill;return null!=t&&"none"!==t},e.prototype.createStyle=function(t){return mt(Ls,t)},e.prototype.setBoundingRect=function(t){this._rect=t},e.prototype.getBoundingRect=function(){var t=this.style;if(!this._rect){var e=t.text;null!=e?e+="":e="";var n=Sr(e,t.font,t.textAlign,t.textBaseline);if(n.x+=t.x||0,n.y+=t.y||0,this.hasStroke()){var i=t.lineWidth;n.x-=i/2,n.y-=i/2,n.width+=i,n.height+=i}this._rect=n}return this._rect},e.initDefaultProps=void(e.prototype.dirtyRectTolerance=10),e}(Da);Ps.prototype.type="tspan";var Os=k({x:0,y:0},Ma),Rs={style:k({x:!0,y:!0,width:!0,height:!0,sx:!0,sy:!0,sWidth:!0,sHeight:!0},Ia.style)};var Ns=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.createStyle=function(t){return mt(Os,t)},e.prototype._getSize=function(t){var e=this.style,n=e[t];if(null!=n)return n;var i,r=(i=e.image)&&"string"!=typeof i&&i.width&&i.height?e.image:this.__image;if(!r)return 0;var o="width"===t?"height":"width",a=e[o];return null==a?r[t]:r[t]/r[o]*a},e.prototype.getWidth=function(){return this._getSize("width")},e.prototype.getHeight=function(){return this._getSize("height")},e.prototype.getAnimationStyleProps=function(){return Rs},e.prototype.getBoundingRect=function(){var t=this.style;return this._rect||(this._rect=new ze(t.x||0,t.y||0,this.getWidth(),this.getHeight())),this._rect},e}(Da);Ns.prototype.type="image";var Es=Math.round;function zs(t,e,n){if(e){var i=e.x1,r=e.x2,o=e.y1,a=e.y2;t.x1=i,t.x2=r,t.y1=o,t.y2=a;var s=n&&n.lineWidth;return s?(Es(2*i)===Es(2*r)&&(t.x1=t.x2=Bs(i,s,!0)),Es(2*o)===Es(2*a)&&(t.y1=t.y2=Bs(o,s,!0)),t):t}}function Vs(t,e,n){if(e){var i=e.x,r=e.y,o=e.width,a=e.height;t.x=i,t.y=r,t.width=o,t.height=a;var s=n&&n.lineWidth;return s?(t.x=Bs(i,s,!0),t.y=Bs(r,s,!0),t.width=Math.max(Bs(i+o,s,!1)-t.x,0===o?0:1),t.height=Math.max(Bs(r+a,s,!1)-t.y,0===a?0:1),t):t}}function Bs(t,e,n){if(!e)return t;var i=Es(2*t);return(i+Es(e))%2==0?i/2:(i+(n?1:-1))/2}var Fs=function(){this.x=0,this.y=0,this.width=0,this.height=0},Gs={},Ws=function(t){function e(e){return t.call(this,e)||this}return n(e,t),e.prototype.getDefaultShape=function(){return new Fs},e.prototype.buildPath=function(t,e){var n,i,r,o;if(this.subPixelOptimize){var a=Vs(Gs,e,this.style);n=a.x,i=a.y,r=a.width,o=a.height,a.r=e.r,e=a}else n=e.x,i=e.y,r=e.width,o=e.height;e.r?function(t,e){var n,i,r,o,a,s=e.x,l=e.y,u=e.width,h=e.height,c=e.r;u<0&&(s+=u,u=-u),h<0&&(l+=h,h=-h),"number"==typeof c?n=i=r=o=c:c instanceof Array?1===c.length?n=i=r=o=c[0]:2===c.length?(n=r=c[0],i=o=c[1]):3===c.length?(n=c[0],i=o=c[1],r=c[2]):(n=c[0],i=c[1],r=c[2],o=c[3]):n=i=r=o=0,n+i>u&&(n*=u/(a=n+i),i*=u/a),r+o>u&&(r*=u/(a=r+o),o*=u/a),i+r>h&&(i*=h/(a=i+r),r*=h/a),n+o>h&&(n*=h/(a=n+o),o*=h/a),t.moveTo(s+n,l),t.lineTo(s+u-i,l),0!==i&&t.arc(s+u-i,l+i,i,-Math.PI/2,0),t.lineTo(s+u,l+h-r),0!==r&&t.arc(s+u-r,l+h-r,r,0,Math.PI/2),t.lineTo(s+o,l+h),0!==o&&t.arc(s+o,l+h-o,o,Math.PI/2,Math.PI),t.lineTo(s,l+n),0!==n&&t.arc(s+n,l+n,n,Math.PI,1.5*Math.PI)}(t,e):t.rect(n,i,r,o)},e.prototype.isZeroArea=function(){return!this.shape.width||!this.shape.height},e}(ks);Ws.prototype.type="rect";var Hs={fill:"#000"},Ys={style:k({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},Ia.style)},Xs=function(t){function e(e){var n=t.call(this)||this;return n.type="text",n._children=[],n._defaultStyle=Hs,n.attr(e),n}return n(e,t),e.prototype.childrenRef=function(){return this._children},e.prototype.update=function(){t.prototype.update.call(this),this.styleChanged()&&this._updateSubTexts();for(var e=0;ef&&h){var g=Math.floor(f/l);c=c||n.length>g,n=n.slice(0,g)}if(t&&a&&null!=p)for(var y=da(p,o,e.ellipsis,{minChar:e.truncateMinChar,placeholder:e.placeholder}),v={},m=0;m0,T=null!=t.width&&("truncate"===t.overflow||"break"===t.overflow||"breakAll"===t.overflow),C=i.calculatedLineHeight,D=0;Dl&&xa(n,t.substring(l,u),e,s),xa(n,i[2],e,s,i[1]),l=ca.lastIndex}lo){var D=n.lines.length;w>0?(x.tokens=x.tokens.slice(0,w),v(x,b,_),n.lines=n.lines.slice(0,m+1)):n.lines=n.lines.slice(0,m),n.isTruncated=n.isTruncated||n.lines.length=0&&"right"===(C=x[T]).align;)this._placeToken(C,t,b,f,I,"right",y),w-=C.width,I-=C.width,T--;for(M+=(n-(M-d)-(g-I)-w)/2;S<=T;)C=x[S],this._placeToken(C,t,b,f,M+C.width/2,"center",y),M+=C.width,S++;f+=b}},e.prototype._placeToken=function(t,e,n,i,r,o,s){var l=e.rich[t.styleName]||{};l.text=t.text;var u=t.verticalAlign,h=i+n/2;"top"===u?h=i+t.height/2:"bottom"===u&&(h=i+n-t.height/2),!t.isLineHolder&&il(l)&&this._renderBackground(l,e,"right"===o?r-t.width:"center"===o?r-t.width/2:r,h-t.height/2,t.width,t.height);var c=!!l.backgroundColor,p=t.textPadding;p&&(r=el(r,o,p),h-=t.height/2-p[0]-t.innerHeight/2);var d=this._getOrCreateChild(Ps),f=d.createStyle();d.useStyle(f);var g=this._defaultStyle,y=!1,v=0,m=tl("fill"in l?l.fill:"fill"in e?e.fill:(y=!0,g.fill)),x=Qs("stroke"in l?l.stroke:"stroke"in e?e.stroke:c||s||g.autoStroke&&!y?null:(v=2,g.stroke)),_=l.textShadowBlur>0||e.textShadowBlur>0;f.text=t.text,f.x=r,f.y=h,_&&(f.shadowBlur=l.textShadowBlur||e.textShadowBlur||0,f.shadowColor=l.textShadowColor||e.textShadowColor||"transparent",f.shadowOffsetX=l.textShadowOffsetX||e.textShadowOffsetX||0,f.shadowOffsetY=l.textShadowOffsetY||e.textShadowOffsetY||0),f.textAlign=o,f.textBaseline="middle",f.font=t.font||a,f.opacity=ot(l.opacity,e.opacity,1),Ks(f,l),x&&(f.lineWidth=ot(l.lineWidth,e.lineWidth,v),f.lineDash=rt(l.lineDash,e.lineDash),f.lineDashOffset=e.lineDashOffset||0,f.stroke=x),m&&(f.fill=m);var b=t.contentWidth,w=t.contentHeight;d.setBoundingRect(new ze(Mr(f.x,b,f.textAlign),Ir(f.y,w,f.textBaseline),b,w))},e.prototype._renderBackground=function(t,e,n,i,r,o){var a,s,l,u=t.backgroundColor,h=t.borderWidth,c=t.borderColor,p=u&&u.image,d=u&&!p,f=t.borderRadius,g=this;if(d||t.lineHeight||h&&c){(a=this._getOrCreateChild(Ws)).useStyle(a.createStyle()),a.style.fill=null;var y=a.shape;y.x=n,y.y=i,y.width=r,y.height=o,y.r=f,a.dirtyShape()}if(d)(l=a.style).fill=u||null,l.fillOpacity=rt(t.fillOpacity,1);else if(p){(s=this._getOrCreateChild(Ns)).onload=function(){g.dirtyStyle()};var v=s.style;v.image=u.image,v.x=n,v.y=i,v.width=r,v.height=o}h&&c&&((l=a.style).lineWidth=h,l.stroke=c,l.strokeOpacity=rt(t.strokeOpacity,1),l.lineDash=t.borderDash,l.lineDashOffset=t.borderDashOffset||0,a.strokeContainThreshold=0,a.hasFill()&&a.hasStroke()&&(l.strokeFirst=!0,l.lineWidth*=2));var m=(a||s).style;m.shadowBlur=t.shadowBlur||0,m.shadowColor=t.shadowColor||"transparent",m.shadowOffsetX=t.shadowOffsetX||0,m.shadowOffsetY=t.shadowOffsetY||0,m.opacity=ot(t.opacity,e.opacity,1)},e.makeFont=function(t){var e="";return $s(t)&&(e=[t.fontStyle,t.fontWeight,qs(t.fontSize),t.fontFamily||"sans-serif"].join(" ")),e&&ut(e)||t.textFont||t.font},e}(Da),Us={left:!0,right:1,center:1},Zs={top:1,bottom:1,middle:1},js=["fontStyle","fontWeight","fontSize","fontFamily"];function qs(t){return"string"!=typeof t||-1===t.indexOf("px")&&-1===t.indexOf("rem")&&-1===t.indexOf("em")?isNaN(+t)?"12px":t+"px":t}function Ks(t,e){for(var n=0;n=0,o=!1;if(t instanceof ks){var a=ll(t),s=r&&a.selectFill||a.normalFill,l=r&&a.selectStroke||a.normalStroke;if(ml(s)||ml(l)){var u=(i=i||{}).style||{};"inherit"===u.fill?(o=!0,i=A({},i),(u=A({},u)).fill=s):!ml(u.fill)&&ml(s)?(o=!0,i=A({},i),(u=A({},u)).fill=si(s)):!ml(u.stroke)&&ml(l)&&(o||(i=A({},i),u=A({},u)),u.stroke=si(l)),i.style=u}}if(i&&null==i.z2){o||(i=A({},i));var h=t.z2EmphasisLift;i.z2=t.z2+(null!=h?h:pl)}return i}(this,0,e,n);if("blur"===t)return function(t,e,n){var i=P(t.currentStates,e)>=0,r=t.style.opacity,o=i?null:function(t,e,n,i){for(var r=t.style,o={},a=0;a0){var o={dataIndex:r,seriesIndex:t.seriesIndex};null!=i&&(o.dataType=i),e.push(o)}}))})),e}function Ul(t,e,n){Jl(t,!0),Cl(t,kl),jl(t,e,n)}function Zl(t,e,n,i){i?function(t){Jl(t,!1)}(t):Ul(t,e,n)}function jl(t,e,n){var i=rl(t);null!=e?(i.focus=e,i.blurScope=n):i.focus&&(i.focus=null)}var ql=["emphasis","blur","select"],Kl={itemStyle:"getItemStyle",lineStyle:"getLineStyle",areaStyle:"getAreaStyle"};function $l(t,e,n,i){n=n||"itemStyle";for(var r=0;r1&&(a*=su(f),s*=su(f));var g=(r===o?-1:1)*su((a*a*(s*s)-a*a*(d*d)-s*s*(p*p))/(a*a*(d*d)+s*s*(p*p)))||0,y=g*a*d/s,v=g*-s*p/a,m=(t+n)/2+uu(c)*y-lu(c)*v,x=(e+i)/2+lu(c)*y+uu(c)*v,_=du([1,0],[(p-y)/a,(d-v)/s]),b=[(p-y)/a,(d-v)/s],w=[(-1*p-y)/a,(-1*d-v)/s],S=du(b,w);if(pu(b,w)<=-1&&(S=hu),pu(b,w)>=1&&(S=0),S<0){var M=Math.round(S/hu*1e6)/1e6;S=2*hu+M%2*hu}h.addData(u,m,x,a,s,_,S,c,o)}var gu=/([mlvhzcqtsa])([^mlvhzcqtsa]*)/gi,yu=/-?([0-9]*\.)?[0-9]+([eE]-?[0-9]+)?/g;var vu=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.applyTransform=function(t){},e}(ks);function mu(t){return null!=t.setData}function xu(t,e){var n=function(t){var e=new hs;if(!t)return e;var n,i=0,r=0,o=i,a=r,s=hs.CMD,l=t.match(gu);if(!l)return e;for(var u=0;uk*k+L*L&&(M=T,I=C),{cx:M,cy:I,x0:-h,y0:-c,x1:M*(r/b-1),y1:I*(r/b-1)}}function Vu(t,e){var n,i=Ru(e.r,0),r=Ru(e.r0||0,0),o=i>0;if(o||r>0){if(o||(i=r,r=0),r>i){var a=i;i=r,r=a}var s=e.startAngle,l=e.endAngle;if(!isNaN(s)&&!isNaN(l)){var u=e.cx,h=e.cy,c=!!e.clockwise,p=Pu(l-s),d=p>Cu&&p%Cu;if(d>Eu&&(p=d),i>Eu)if(p>Cu-Eu)t.moveTo(u+i*Au(s),h+i*Du(s)),t.arc(u,h,i,s,l,!c),r>Eu&&(t.moveTo(u+r*Au(l),h+r*Du(l)),t.arc(u,h,r,l,s,c));else{var f=void 0,g=void 0,y=void 0,v=void 0,m=void 0,x=void 0,_=void 0,b=void 0,w=void 0,S=void 0,M=void 0,I=void 0,T=void 0,C=void 0,D=void 0,A=void 0,k=i*Au(s),L=i*Du(s),P=r*Au(l),O=r*Du(l),R=p>Eu;if(R){var N=e.cornerRadius;N&&(n=function(t){var e;if(Y(t)){var n=t.length;if(!n)return t;e=1===n?[t[0],t[0],0,0]:2===n?[t[0],t[0],t[1],t[1]]:3===n?t.concat(t[2]):t}else e=[t,t,t,t];return e}(N),f=n[0],g=n[1],y=n[2],v=n[3]);var E=Pu(i-r)/2;if(m=Nu(E,y),x=Nu(E,v),_=Nu(E,f),b=Nu(E,g),M=w=Ru(m,x),I=S=Ru(_,b),(w>Eu||S>Eu)&&(T=i*Au(l),C=i*Du(l),D=r*Au(s),A=r*Du(s),pEu){var X=Nu(y,M),U=Nu(v,M),Z=zu(D,A,k,L,i,X,c),j=zu(T,C,P,O,i,U,c);t.moveTo(u+Z.cx+Z.x0,h+Z.cy+Z.y0),M0&&t.arc(u+Z.cx,h+Z.cy,X,Lu(Z.y0,Z.x0),Lu(Z.y1,Z.x1),!c),t.arc(u,h,i,Lu(Z.cy+Z.y1,Z.cx+Z.x1),Lu(j.cy+j.y1,j.cx+j.x1),!c),U>0&&t.arc(u+j.cx,h+j.cy,U,Lu(j.y1,j.x1),Lu(j.y0,j.x0),!c))}else t.moveTo(u+k,h+L),t.arc(u,h,i,s,l,!c);else t.moveTo(u+k,h+L);if(r>Eu&&R)if(I>Eu){X=Nu(f,I),Z=zu(P,O,T,C,r,-(U=Nu(g,I)),c),j=zu(k,L,D,A,r,-X,c);t.lineTo(u+Z.cx+Z.x0,h+Z.cy+Z.y0),I0&&t.arc(u+Z.cx,h+Z.cy,U,Lu(Z.y0,Z.x0),Lu(Z.y1,Z.x1),!c),t.arc(u,h,r,Lu(Z.cy+Z.y1,Z.cx+Z.x1),Lu(j.cy+j.y1,j.cx+j.x1),c),X>0&&t.arc(u+j.cx,h+j.cy,X,Lu(j.y1,j.x1),Lu(j.y0,j.x0),!c))}else t.lineTo(u+P,h+O),t.arc(u,h,r,l,s,c);else t.lineTo(u+P,h+O)}else t.moveTo(u,h);t.closePath()}}}var Bu=function(){this.cx=0,this.cy=0,this.r0=0,this.r=0,this.startAngle=0,this.endAngle=2*Math.PI,this.clockwise=!0,this.cornerRadius=0},Fu=function(t){function e(e){return t.call(this,e)||this}return n(e,t),e.prototype.getDefaultShape=function(){return new Bu},e.prototype.buildPath=function(t,e){Vu(t,e)},e.prototype.isZeroArea=function(){return this.shape.startAngle===this.shape.endAngle||this.shape.r===this.shape.r0},e}(ks);Fu.prototype.type="sector";var Gu=function(){this.cx=0,this.cy=0,this.r=0,this.r0=0},Wu=function(t){function e(e){return t.call(this,e)||this}return n(e,t),e.prototype.getDefaultShape=function(){return new Gu},e.prototype.buildPath=function(t,e){var n=e.cx,i=e.cy,r=2*Math.PI;t.moveTo(n+e.r,i),t.arc(n,i,e.r,0,r,!1),t.moveTo(n+e.r0,i),t.arc(n,i,e.r0,0,r,!0)},e}(ks);function Hu(t,e,n){var i=e.smooth,r=e.points;if(r&&r.length>=2){if(i){var o=function(t,e,n,i){var r,o,a,s,l=[],u=[],h=[],c=[];if(i){a=[1/0,1/0],s=[-1/0,-1/0];for(var p=0,d=t.length;plh[1]){if(a=!1,r)return a;var u=Math.abs(lh[0]-sh[1]),h=Math.abs(sh[0]-lh[1]);Math.min(u,h)>i.len()&&(u0){var c={duration:h.duration,delay:h.delay||0,easing:h.easing,done:o,force:!!o||!!a,setToFinal:!u,scope:t,during:a};l?e.animateFrom(n,c):e.animateTo(n,c)}else e.stopAnimation(),!l&&e.attr(n),a&&a(1),o&&o()}function vh(t,e,n,i,r,o){yh("update",t,e,n,i,r,o)}function mh(t,e,n,i,r,o){yh("enter",t,e,n,i,r,o)}function xh(t){if(!t.__zr)return!0;for(var e=0;eMath.abs(o[1])?o[0]>0?"right":"left":o[1]>0?"bottom":"top"}function Wh(t){return!t.isGroup}function Hh(t,e,n){if(t&&e){var i,r=(i={},t.traverse((function(t){Wh(t)&&t.anid&&(i[t.anid]=t)})),i);e.traverse((function(t){if(Wh(t)&&t.anid){var e=r[t.anid];if(e){var i=o(t);t.attr(o(e)),vh(t,i,n,rl(t).dataIndex)}}}))}function o(t){var e={x:t.x,y:t.y,rotation:t.rotation};return function(t){return null!=t.shape}(t)&&(e.shape=A({},t.shape)),e}}function Yh(t,e){return z(t,(function(t){var n=t[0];n=Mh(n,e.x),n=Ih(n,e.x+e.width);var i=t[1];return i=Mh(i,e.y),[n,i=Ih(i,e.y+e.height)]}))}function Xh(t,e){var n=Mh(t.x,e.x),i=Ih(t.x+t.width,e.x+e.width),r=Mh(t.y,e.y),o=Ih(t.y+t.height,e.y+e.height);if(i>=n&&o>=r)return{x:n,y:r,width:i-n,height:o-r}}function Uh(t,e,n){var i=A({rectHover:!0},e),r=i.style={strokeNoScale:!0};if(n=n||{x:-1,y:-1,width:2,height:2},t)return 0===t.indexOf("image://")?(r.image=t.slice(8),k(r,n),new Ns(i)):Ph(t.replace("path://",""),i,n,"center")}function Zh(t,e,n,i,r){for(var o=0,a=r[r.length-1];o=-1e-6)return!1;var f=t-r,g=e-o,y=qh(f,g,u,h)/d;if(y<0||y>1)return!1;var v=qh(f,g,c,p)/d;return!(v<0||v>1)}function qh(t,e,n,i){return t*i-n*e}function Kh(t){var e=t.itemTooltipOption,n=t.componentModel,i=t.itemName,r=U(e)?{formatter:e}:e,o=n.mainType,a=n.componentIndex,s={componentType:o,name:i,$vars:["name"]};s[o+"Index"]=a;var l=t.formatterParamsExtra;l&&E(G(l),(function(t){_t(s,t)||(s[t]=l[t],s.$vars.push(t))}));var u=rl(t.el);u.componentMainType=o,u.componentIndex=a,u.tooltipConfig={name:i,option:k({content:i,encodeHTMLContent:!0,formatterParams:s},r)}}function $h(t,e){var n;t.isGroup&&(n=e(t)),n||t.traverse(e)}function Jh(t,e){if(t)if(Y(t))for(var n=0;n-1?Lc:Oc;function zc(t,e){t=t.toUpperCase(),Nc[t]=new Cc(e),Rc[t]=e}function Vc(t){return Nc[t]}zc(Pc,{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:". "}}}}),zc(Lc,{time:{month:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],monthAbbr:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],dayOfWeek:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],dayOfWeekAbbr:["日","一","二","三","四","五","六"]},legend:{selector:{all:"全选",inverse:"反选"}},toolbox:{brush:{title:{rect:"矩形选择",polygon:"圈选",lineX:"横向选择",lineY:"纵向选择",keep:"保持选择",clear:"清除选择"}},dataView:{title:"数据视图",lang:["数据视图","关闭","刷新"]},dataZoom:{title:{zoom:"区域缩放",back:"区域缩放还原"}},magicType:{title:{line:"切换为折线图",bar:"切换为柱状图",stack:"切换为堆叠",tiled:"切换为平铺"}},restore:{title:"还原"},saveAsImage:{title:"保存为图片",lang:["右键另存为图片"]}},series:{typeNames:{pie:"饼图",bar:"柱状图",line:"折线图",scatter:"散点图",effectScatter:"涟漪散点图",radar:"雷达图",tree:"树图",treemap:"矩形树图",boxplot:"箱型图",candlestick:"K线图",k:"K线图",heatmap:"热力图",map:"地图",parallel:"平行坐标图",lines:"线图",graph:"关系图",sankey:"桑基图",funnel:"漏斗图",gauge:"仪表盘图",pictorialBar:"象形柱图",themeRiver:"主题河流图",sunburst:"旭日图",custom:"自定义图表",chart:"图表"}},aria:{general:{withTitle:"这是一个关于“{title}”的图表。",withoutTitle:"这是一个图表,"},series:{single:{prefix:"",withName:"图表类型是{seriesType},表示{seriesName}。",withoutName:"图表类型是{seriesType}。"},multiple:{prefix:"它由{seriesCount}个图表系列组成。",withName:"第{seriesId}个系列是一个表示{seriesName}的{seriesType},",withoutName:"第{seriesId}个系列是一个{seriesType},",separator:{middle:";",end:"。"}}},data:{allData:"其数据是——",partialData:"其中,前{displayCnt}项是——",withName:"{name}的数据是{value}",withoutName:"{value}",separator:{middle:",",end:""}}}});var Bc=1e3,Fc=6e4,Gc=36e5,Wc=864e5,Hc=31536e6,Yc={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}"},Xc="{yyyy}-{MM}-{dd}",Uc={year:"{yyyy}",month:"{yyyy}-{MM}",day:Xc,hour:Xc+" "+Yc.hour,minute:Xc+" "+Yc.minute,second:Xc+" "+Yc.second,millisecond:Yc.none},Zc=["year","month","day","hour","minute","second","millisecond"],jc=["year","half-year","quarter","month","week","half-week","day","half-day","quarter-day","hour","minute","second","millisecond"];function qc(t,e){return"0000".substr(0,e-(t+="").length)+t}function Kc(t){switch(t){case"half-year":case"quarter":return"month";case"week":case"half-week":return"day";case"half-day":case"quarter-day":return"hour";default:return t}}function $c(t){return t===Kc(t)}function Jc(t,e,n,i){var r=uo(t),o=r[ep(n)](),a=r[np(n)]()+1,s=Math.floor((a-1)/3)+1,l=r[ip(n)](),u=r["get"+(n?"UTC":"")+"Day"](),h=r[rp(n)](),c=(h-1)%12+1,p=r[op(n)](),d=r[ap(n)](),f=r[sp(n)](),g=h>=12?"pm":"am",y=g.toUpperCase(),v=(i instanceof Cc?i:Vc(i||Ec)||Nc[Oc]).getModel("time"),m=v.get("month"),x=v.get("monthAbbr"),_=v.get("dayOfWeek"),b=v.get("dayOfWeekAbbr");return(e||"").replace(/{a}/g,g+"").replace(/{A}/g,y+"").replace(/{yyyy}/g,o+"").replace(/{yy}/g,qc(o%100+"",2)).replace(/{Q}/g,s+"").replace(/{MMMM}/g,m[a-1]).replace(/{MMM}/g,x[a-1]).replace(/{MM}/g,qc(a,2)).replace(/{M}/g,a+"").replace(/{dd}/g,qc(l,2)).replace(/{d}/g,l+"").replace(/{eeee}/g,_[u]).replace(/{ee}/g,b[u]).replace(/{e}/g,u+"").replace(/{HH}/g,qc(h,2)).replace(/{H}/g,h+"").replace(/{hh}/g,qc(c+"",2)).replace(/{h}/g,c+"").replace(/{mm}/g,qc(p,2)).replace(/{m}/g,p+"").replace(/{ss}/g,qc(d,2)).replace(/{s}/g,d+"").replace(/{SSS}/g,qc(f,3)).replace(/{S}/g,f+"")}function Qc(t,e){var n=uo(t),i=n[np(e)]()+1,r=n[ip(e)](),o=n[rp(e)](),a=n[op(e)](),s=n[ap(e)](),l=0===n[sp(e)](),u=l&&0===s,h=u&&0===a,c=h&&0===o,p=c&&1===r;return p&&1===i?"year":p?"month":c?"day":h?"hour":u?"minute":l?"second":"millisecond"}function tp(t,e,n){var i=j(t)?uo(t):t;switch(e=e||Qc(t,n)){case"year":return i[ep(n)]();case"half-year":return i[np(n)]()>=6?1:0;case"quarter":return Math.floor((i[np(n)]()+1)/4);case"month":return i[np(n)]();case"day":return i[ip(n)]();case"half-day":return i[rp(n)]()/24;case"hour":return i[rp(n)]();case"minute":return i[op(n)]();case"second":return i[ap(n)]();case"millisecond":return i[sp(n)]()}}function ep(t){return t?"getUTCFullYear":"getFullYear"}function np(t){return t?"getUTCMonth":"getMonth"}function ip(t){return t?"getUTCDate":"getDate"}function rp(t){return t?"getUTCHours":"getHours"}function op(t){return t?"getUTCMinutes":"getMinutes"}function ap(t){return t?"getUTCSeconds":"getSeconds"}function sp(t){return t?"getUTCMilliseconds":"getMilliseconds"}function lp(t){return t?"setUTCFullYear":"setFullYear"}function up(t){return t?"setUTCMonth":"setMonth"}function hp(t){return t?"setUTCDate":"setDate"}function cp(t){return t?"setUTCHours":"setHours"}function pp(t){return t?"setUTCMinutes":"setMinutes"}function dp(t){return t?"setUTCSeconds":"setSeconds"}function fp(t){return t?"setUTCMilliseconds":"setMilliseconds"}function gp(t){if(!vo(t))return U(t)?t:"-";var e=(t+"").split(".");return e[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g,"$1,")+(e.length>1?"."+e[1]:"")}function yp(t,e){return t=(t||"").toLowerCase().replace(/-(.)/g,(function(t,e){return e.toUpperCase()})),e&&t&&(t=t.charAt(0).toUpperCase()+t.slice(1)),t}var vp=st;function mp(t,e,n){function i(t){return t&&ut(t)?t:"-"}function r(t){return!(null==t||isNaN(t)||!isFinite(t))}var o="time"===e,a=t instanceof Date;if(o||a){var s=o?uo(t):t;if(!isNaN(+s))return Jc(s,"{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}",n);if(a)return"-"}if("ordinal"===e)return Z(t)?i(t):j(t)&&r(t)?t+"":"-";var l=yo(t);return r(l)?gp(l):Z(t)?i(t):"boolean"==typeof t?t+"":"-"}var xp=["a","b","c","d","e","f","g"],_p=function(t,e){return"{"+t+(null==e?"":e)+"}"};function bp(t,e,n){Y(e)||(e=[e]);var i=e.length;if(!i)return"";for(var r=e[0].$vars||[],o=0;o':'':{renderMode:o,content:"{"+(n.markerId||"markerX")+"|} ",style:"subItem"===r?{width:4,height:4,borderRadius:2,backgroundColor:i}:{width:10,height:10,borderRadius:5,backgroundColor:i}}:""}function Sp(t,e){return e=e||"transparent",U(t)?t:q(t)&&t.colorStops&&(t.colorStops[0]||{}).color||e}function Mp(t,e){if("_blank"===e||"blank"===e){var n=window.open();n.opener=null,n.location.href=t}else window.open(t,e)}var Ip=E,Tp=["left","right","top","bottom","width","height"],Cp=[["width","left","right"],["height","top","bottom"]];function Dp(t,e,n,i,r){var o=0,a=0;null==i&&(i=1/0),null==r&&(r=1/0);var s=0;e.eachChild((function(l,u){var h,c,p=l.getBoundingRect(),d=e.childAt(u+1),f=d&&d.getBoundingRect();if("horizontal"===t){var g=p.width+(f?-f.x+p.x:0);(h=o+g)>i||l.newline?(o=0,h=g,a+=s+n,s=p.height):s=Math.max(s,p.height)}else{var y=p.height+(f?-f.y+p.y:0);(c=a+y)>r||l.newline?(o+=s+n,a=0,c=y,s=p.width):s=Math.max(s,p.width)}l.newline||(l.x=o,l.y=a,l.markRedraw(),"horizontal"===t?o=h+n:a=c+n)}))}var Ap=Dp;H(Dp,"vertical"),H(Dp,"horizontal");function kp(t,e,n){n=vp(n||0);var i=e.width,r=e.height,o=$r(t.left,i),a=$r(t.top,r),s=$r(t.right,i),l=$r(t.bottom,r),u=$r(t.width,i),h=$r(t.height,r),c=n[2]+n[0],p=n[1]+n[3],d=t.aspect;switch(isNaN(u)&&(u=i-s-p-o),isNaN(h)&&(h=r-l-c-a),null!=d&&(isNaN(u)&&isNaN(h)&&(d>i/r?u=.8*i:h=.8*r),isNaN(u)&&(u=d*h),isNaN(h)&&(h=u/d)),isNaN(o)&&(o=i-s-u-p),isNaN(a)&&(a=r-l-h-c),t.left||t.right){case"center":o=i/2-u/2-n[3];break;case"right":o=i-u-p}switch(t.top||t.bottom){case"middle":case"center":a=r/2-h/2-n[0];break;case"bottom":a=r-h-c}o=o||0,a=a||0,isNaN(u)&&(u=i-p-o-(s||0)),isNaN(h)&&(h=r-c-a-(l||0));var f=new ze(o+n[3],a+n[0],u,h);return f.margin=n,f}function Lp(t,e,n,i,r,o){var a,s=!r||!r.hv||r.hv[0],l=!r||!r.hv||r.hv[1],u=r&&r.boundingMode||"all";if((o=o||t).x=t.x,o.y=t.y,!s&&!l)return!1;if("raw"===u)a="group"===t.type?new ze(0,0,+e.width||0,+e.height||0):t.getBoundingRect();else if(a=t.getBoundingRect(),t.needLocalTransform()){var h=t.getLocalTransform();(a=a.clone()).applyTransform(h)}var c=kp(k({width:a.width,height:a.height},e),n,i),p=s?c.x-a.x:0,d=l?c.y-a.y:0;return"raw"===u?(o.x=p,o.y=d):(o.x+=p,o.y+=d),o===t&&t.markRedraw(),!0}function Pp(t){var e=t.layoutMode||t.constructor.layoutMode;return q(e)?e:e?{type:e}:null}function Op(t,e,n){var i=n&&n.ignoreSize;!Y(i)&&(i=[i,i]);var r=a(Cp[0],0),o=a(Cp[1],1);function a(n,r){var o={},a=0,u={},h=0;if(Ip(n,(function(e){u[e]=t[e]})),Ip(n,(function(t){s(e,t)&&(o[t]=u[t]=e[t]),l(o,t)&&a++,l(u,t)&&h++})),i[r])return l(e,n[1])?u[n[2]]=null:l(e,n[2])&&(u[n[1]]=null),u;if(2!==h&&a){if(a>=2)return o;for(var c=0;c=0;a--)o=C(o,n[a],!0);e.defaultOption=o}return e.defaultOption},e.prototype.getReferringComponents=function(t,e){var n=t+"Index",i=t+"Id";return Yo(this.ecModel,t,{index:this.get(n,!0),id:this.get(i,!0)},e)},e.prototype.getBoxLayoutParams=function(){var t=this;return{left:t.get("left"),top:t.get("top"),right:t.get("right"),bottom:t.get("bottom"),width:t.get("width"),height:t.get("height")}},e.prototype.getZLevelKey=function(){return""},e.prototype.setZLevel=function(t){this.option.zlevel=t},e.protoInitialize=function(){var t=e.prototype;t.type="component",t.id="",t.name="",t.mainType="",t.subType="",t.componentIndex=0}(),e}(Cc);Jo(zp,Cc),na(zp),function(t){var e={};t.registerSubTypeDefaulter=function(t,n){var i=Ko(t);e[i.main]=n},t.determineSubType=function(n,i){var r=i.type;if(!r){var o=Ko(n).main;t.hasSubTypes(n)&&e[o]&&(r=e[o](i))}return r}}(zp),function(t,e){function n(t,e){return t[e]||(t[e]={predecessor:[],successor:[]}),t[e]}t.topologicalTravel=function(t,i,r,o){if(t.length){var a=function(t){var i={},r=[];return E(t,(function(o){var a=n(i,o),s=function(t,e){var n=[];return E(t,(function(t){P(e,t)>=0&&n.push(t)})),n}(a.originalDeps=e(o),t);a.entryCount=s.length,0===a.entryCount&&r.push(o),E(s,(function(t){P(a.predecessor,t)<0&&a.predecessor.push(t);var e=n(i,t);P(e.successor,t)<0&&e.successor.push(o)}))})),{graph:i,noEntryList:r}}(i),s=a.graph,l=a.noEntryList,u={};for(E(t,(function(t){u[t]=!0}));l.length;){var h=l.pop(),c=s[h],p=!!u[h];p&&(r.call(o,h,c.originalDeps.slice()),delete u[h]),E(c.successor,p?f:d)}E(u,(function(){var t="";throw new Error(t)}))}function d(t){s[t].entryCount--,0===s[t].entryCount&&l.push(t)}function f(t){u[t]=!0,d(t)}}}(zp,(function(t){var e=[];E(zp.getClassesByMainType(t),(function(t){e=e.concat(t.dependencies||t.prototype.dependencies||[])})),e=z(e,(function(t){return Ko(t).main})),"dataset"!==t&&P(e,"dataset")<=0&&e.unshift("dataset");return e}));var Vp="";"undefined"!=typeof navigator&&(Vp=navigator.platform||"");var Bp="rgba(0, 0, 0, 0.2)",Fp={darkMode:"auto",colorBy:"series",color:["#5470c6","#91cc75","#fac858","#ee6666","#73c0de","#3ba272","#fc8452","#9a60b4","#ea7ccc"],gradientColor:["#f6efa6","#d88273","#bf444c"],aria:{decal:{decals:[{color:Bp,dashArrayX:[1,0],dashArrayY:[2,5],symbolSize:1,rotation:Math.PI/6},{color:Bp,symbol:"circle",dashArrayX:[[8,8],[0,8,8,0]],dashArrayY:[6,0],symbolSize:.8},{color:Bp,dashArrayX:[1,0],dashArrayY:[4,3],rotation:-Math.PI/4},{color:Bp,dashArrayX:[[6,6],[0,6,6,0]],dashArrayY:[6,0]},{color:Bp,dashArrayX:[[1,0],[1,6]],dashArrayY:[1,0,6,0],rotation:Math.PI/4},{color:Bp,symbol:"triangle",dashArrayX:[[9,9],[0,9,9,0]],dashArrayY:[7,2],symbolSize:.75}]}},textStyle:{fontFamily:Vp.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},Gp=yt(["tooltip","label","itemName","itemId","itemGroupId","itemChildGroupId","seriesName"]),Wp="original",Hp="arrayRows",Yp="objectRows",Xp="keyedColumns",Up="typedArray",Zp="unknown",jp="column",qp="row",Kp=1,$p=2,Jp=3,Qp=Vo();function td(t,e,n){var i={},r=nd(e);if(!r||!t)return i;var o,a,s=[],l=[],u=e.ecModel,h=Qp(u).datasetMap,c=r.uid+"_"+n.seriesLayoutBy;E(t=t.slice(),(function(e,n){var r=q(e)?e:t[n]={name:e};"ordinal"===r.type&&null==o&&(o=n,a=f(r)),i[r.name]=[]}));var p=h.get(c)||h.set(c,{categoryWayDim:a,valueWayDim:0});function d(t,e,n){for(var i=0;ie)return t[i];return t[n-1]}(i,a):n;if((h=h||n)&&h.length){var c=h[l];return r&&(u[r]=c),s.paletteIdx=(l+1)%h.length,c}}var fd="\0_ec_inner";var gd=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.init=function(t,e,n,i,r,o){i=i||{},this.option=null,this._theme=new Cc(i),this._locale=new Cc(r),this._optionManager=o},e.prototype.setOption=function(t,e,n){var i=md(e);this._optionManager.setOption(t,n,i),this._resetOption(null,i)},e.prototype.resetOption=function(t,e){return this._resetOption(t,md(e))},e.prototype._resetOption=function(t,e){var n=!1,i=this._optionManager;if(!t||"recreate"===t){var r=i.mountOption("recreate"===t);0,this.option&&"recreate"!==t?(this.restoreData(),this._mergeOption(r,e)):ld(this,r),n=!0}if("timeline"!==t&&"media"!==t||this.restoreData(),!t||"recreate"===t||"timeline"===t){var o=i.getTimelineOption(this);o&&(n=!0,this._mergeOption(o,e))}if(!t||"recreate"===t||"media"===t){var a=i.getMediaOption(this);a.length&&E(a,(function(t){n=!0,this._mergeOption(t,e)}),this)}return n},e.prototype.mergeOption=function(t){this._mergeOption(t,null)},e.prototype._mergeOption=function(t,e){var n=this.option,i=this._componentsMap,r=this._componentsCount,o=[],a=yt(),s=e&&e.replaceMergeMainTypeMap;Qp(this).datasetMap=yt(),E(t,(function(t,e){null!=t&&(zp.hasClass(e)?e&&(o.push(e),a.set(e,!0)):n[e]=null==n[e]?T(t):C(n[e],t,!0))})),s&&s.each((function(t,e){zp.hasClass(e)&&!a.get(e)&&(o.push(e),a.set(e,!0))})),zp.topologicalTravel(o,zp.getAllClassMainTypes(),(function(e){var o=function(t,e,n){var i=od.get(e);if(!i)return n;var r=i(t);return r?n.concat(r):n}(this,e,To(t[e])),a=i.get(e),l=a?s&&s.get(e)?"replaceMerge":"normalMerge":"replaceAll",u=Lo(a,o,l);(function(t,e,n){E(t,(function(t){var i=t.newOption;q(i)&&(t.keyInfo.mainType=e,t.keyInfo.subType=function(t,e,n,i){return e.type?e.type:n?n.subType:i.determineSubType(t,e)}(e,i,t.existing,n))}))})(u,e,zp),n[e]=null,i.set(e,null),r.set(e,0);var h,c=[],p=[],d=0;E(u,(function(t,n){var i=t.existing,r=t.newOption;if(r){var o="series"===e,a=zp.getClass(e,t.keyInfo.subType,!o);if(!a)return;if("tooltip"===e){if(h)return void 0;h=!0}if(i&&i.constructor===a)i.name=t.keyInfo.name,i.mergeOption(r,this),i.optionUpdated(r,!1);else{var s=A({componentIndex:n},t.keyInfo);A(i=new a(r,this,this,s),s),t.brandNew&&(i.__requireNewView=!0),i.init(r,this,this),i.optionUpdated(null,!0)}}else i&&(i.mergeOption({},this),i.optionUpdated({},!1));i?(c.push(i.option),p.push(i),d++):(c.push(void 0),p.push(void 0))}),this),n[e]=c,i.set(e,p),r.set(e,d),"series"===e&&ad(this)}),this),this._seriesIndices||ad(this)},e.prototype.getOption=function(){var t=T(this.option);return E(t,(function(e,n){if(zp.hasClass(n)){for(var i=To(e),r=i.length,o=!1,a=r-1;a>=0;a--)i[a]&&!Eo(i[a])?o=!0:(i[a]=null,!o&&r--);i.length=r,t[n]=i}})),delete t[fd],t},e.prototype.getTheme=function(){return this._theme},e.prototype.getLocaleModel=function(){return this._locale},e.prototype.setUpdatePayload=function(t){this._payload=t},e.prototype.getUpdatePayload=function(){return this._payload},e.prototype.getComponent=function(t,e){var n=this._componentsMap.get(t);if(n){var i=n[e||0];if(i)return i;if(null==e)for(var r=0;r=e:"max"===n?t<=e:t===e})(i[a],t,o)||(r=!1)}})),r}var Td=E,Cd=q,Dd=["areaStyle","lineStyle","nodeStyle","linkStyle","chordStyle","label","labelLine"];function Ad(t){var e=t&&t.itemStyle;if(e)for(var n=0,i=Dd.length;n=0;g--){var y=t[g];if(s||(p=y.data.rawIndexOf(y.stackedByDimension,c)),p>=0){var v=y.data.getByRawIndex(y.stackResultDimension,p);if("all"===l||"positive"===l&&v>0||"negative"===l&&v<0||"samesign"===l&&d>=0&&v>0||"samesign"===l&&d<=0&&v<0){d=ro(d,v),f=v;break}}}return i[0]=d,i[1]=f,i}))}))}var Zd,jd,qd,Kd,$d,Jd=function(t){this.data=t.data||(t.sourceFormat===Xp?{}:[]),this.sourceFormat=t.sourceFormat||Zp,this.seriesLayoutBy=t.seriesLayoutBy||jp,this.startIndex=t.startIndex||0,this.dimensionsDetectedCount=t.dimensionsDetectedCount,this.metaRawOption=t.metaRawOption;var e=this.dimensionsDefine=t.dimensionsDefine;if(e)for(var n=0;nu&&(u=d)}s[0]=l,s[1]=u}},i=function(){return this._data?this._data.length/this._dimSize:0};function r(t){for(var e=0;e=0&&(s=o.interpolatedValue[l])}return null!=s?s+"":""})):void 0},t.prototype.getRawValue=function(t,e){return mf(this.getData(e),t)},t.prototype.formatTooltip=function(t,e,n){},t}();function bf(t){var e,n;return q(t)?t.type&&(n=t):e=t,{text:e,frag:n}}function wf(t){return new Sf(t)}var Sf=function(){function t(t){t=t||{},this._reset=t.reset,this._plan=t.plan,this._count=t.count,this._onDirty=t.onDirty,this._dirty=!0}return t.prototype.perform=function(t){var e,n=this._upstream,i=t&&t.skip;if(this._dirty&&n){var r=this.context;r.data=r.outputData=n.context.outputData}this.__pipeline&&(this.__pipeline.currentTask=this),this._plan&&!i&&(e=this._plan(this.context));var o,a=h(this._modBy),s=this._modDataCount||0,l=h(t&&t.modBy),u=t&&t.modDataCount||0;function h(t){return!(t>=1)&&(t=1),t}a===l&&s===u||(e="reset"),(this._dirty||"reset"===e)&&(this._dirty=!1,o=this._doReset(i)),this._modBy=l,this._modDataCount=u;var c=t&&t.step;if(this._dueEnd=n?n._outputDueEnd:this._count?this._count(this.context):1/0,this._progress){var p=this._dueIndex,d=Math.min(null!=c?this._dueIndex+c:1/0,this._dueEnd);if(!i&&(o||p1&&i>0?s:a}};return o;function a(){return e=t?null:oe},gte:function(t,e){return t>=e}},Af=function(){function t(t,e){if(!j(e)){var n="";0,wo(n)}this._opFn=Df[t],this._rvalFloat=yo(e)}return t.prototype.evaluate=function(t){return j(t)?this._opFn(t,this._rvalFloat):this._opFn(yo(t),this._rvalFloat)},t}(),kf=function(){function t(t,e){var n="desc"===t;this._resultLT=n?1:-1,null==e&&(e=n?"min":"max"),this._incomparable="min"===e?-1/0:1/0}return t.prototype.evaluate=function(t,e){var n=j(t)?t:yo(t),i=j(e)?e:yo(e),r=isNaN(n),o=isNaN(i);if(r&&(n=this._incomparable),o&&(i=this._incomparable),r&&o){var a=U(t),s=U(e);a&&(n=s?t:0),s&&(i=a?e:0)}return ni?-this._resultLT:0},t}(),Lf=function(){function t(t,e){this._rval=e,this._isEQ=t,this._rvalTypeof=typeof e,this._rvalFloat=yo(e)}return t.prototype.evaluate=function(t){var e=t===this._rval;if(!e){var n=typeof t;n===this._rvalTypeof||"number"!==n&&"number"!==this._rvalTypeof||(e=yo(t)===this._rvalFloat)}return this._isEQ?e:!e},t}();function Pf(t,e){return"eq"===t||"ne"===t?new Lf("eq"===t,e):_t(Df,t)?new Af(t,e):null}var Of=function(){function t(){}return t.prototype.getRawData=function(){throw new Error("not supported")},t.prototype.getRawDataItem=function(t){throw new Error("not supported")},t.prototype.cloneRawData=function(){},t.prototype.getDimensionInfo=function(t){},t.prototype.cloneAllDimensionInfo=function(){},t.prototype.count=function(){},t.prototype.retrieveValue=function(t,e){},t.prototype.retrieveValueFromItem=function(t,e){},t.prototype.convertValue=function(t,e){return If(t,e)},t}();function Rf(t){var e=t.sourceFormat;if(!Ff(e)){var n="";0,wo(n)}return t.data}function Nf(t){var e=t.sourceFormat,n=t.data;if(!Ff(e)){var i="";0,wo(i)}if(e===Hp){for(var r=[],o=0,a=n.length;o65535?Hf:Yf}function qf(t,e,n,i,r){var o=Zf[n||"float"];if(r){var a=t[e],s=a&&a.length;if(s!==i){for(var l=new o(i),u=0;ug[1]&&(g[1]=f)}return this._rawCount=this._count=s,{start:a,end:s}},t.prototype._initDataFromProvider=function(t,e,n){for(var i=this._provider,r=this._chunks,o=this._dimensions,a=o.length,s=this._rawExtent,l=z(o,(function(t){return t.property})),u=0;uy[1]&&(y[1]=g)}}!i.persistent&&i.clean&&i.clean(),this._rawCount=this._count=e,this._extent=[]},t.prototype.count=function(){return this._count},t.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,n=e[t];if(null!=n&&nt))return o;r=o-1}}return-1},t.prototype.indicesOfNearest=function(t,e,n){var i=this._chunks[t],r=[];if(!i)return r;null==n&&(n=1/0);for(var o=1/0,a=-1,s=0,l=0,u=this.count();l=0&&a<0)&&(o=c,a=h,s=0),h===a&&(r[s++]=l))}return r.length=s,r},t.prototype.getIndices=function(){var t,e=this._indices;if(e){var n=e.constructor,i=this._count;if(n===Array){t=new n(i);for(var r=0;r=u&&x<=h||isNaN(x))&&(a[s++]=d),d++}p=!0}else if(2===r){f=c[i[0]];var y=c[i[1]],v=t[i[1]][0],m=t[i[1]][1];for(g=0;g=u&&x<=h||isNaN(x))&&(_>=v&&_<=m||isNaN(_))&&(a[s++]=d),d++}p=!0}}if(!p)if(1===r)for(g=0;g=u&&x<=h||isNaN(x))&&(a[s++]=b)}else for(g=0;gt[M][1])&&(w=!1)}w&&(a[s++]=e.getRawIndex(g))}return sy[1]&&(y[1]=g)}}}},t.prototype.lttbDownSample=function(t,e){var n,i,r,o=this.clone([t],!0),a=o._chunks[t],s=this.count(),l=0,u=Math.floor(1/e),h=this.getRawIndex(0),c=new(jf(this._rawCount))(Math.min(2*(Math.ceil(s/u)+2),s));c[l++]=h;for(var p=1;pn&&(n=i,r=I)}M>0&&M<_-x&&(c[l++]=Math.min(S,r),r=Math.max(S,r)),c[l++]=r,h=r}return c[l++]=this.getRawIndex(s-1),o._count=l,o._indices=c,o.getRawIndex=this._getRawIdx,o},t.prototype.minmaxDownSample=function(t,e){for(var n=this.clone([t],!0),i=n._chunks,r=Math.floor(1/e),o=i[t],a=this.count(),s=new(jf(this._rawCount))(2*Math.ceil(a/r)),l=0,u=0;ua&&(f=a-u);for(var g=0;gd&&(d=y,p=u+g)}var v=this.getRawIndex(h),m=this.getRawIndex(p);hu-d&&(s=u-d,a.length=s);for(var f=0;fh[1]&&(h[1]=y),c[p++]=v}return r._count=p,r._indices=c,r._updateGetRawIdx(),r},t.prototype.each=function(t,e){if(this._count)for(var n=t.length,i=this._chunks,r=0,o=this.count();ra&&(a=l)}return i=[o,a],this._extent[t]=i,i},t.prototype.getRawDataItem=function(t){var e=this.getRawIndex(t);if(this._provider.persistent)return this._provider.getItem(e);for(var n=[],i=this._chunks,r=0;r=0?this._indices[t]:-1},t.prototype._updateGetRawIdx=function(){this.getRawIndex=this._indices?this._getRawIdx:this._getRawIdxIdentity},t.internalField=function(){function t(t,e,n,i){return If(t[i],this._dimensions[i])}Gf={arrayRows:t,objectRows:function(t,e,n,i){return If(t[e],this._dimensions[i])},keyedColumns:t,original:function(t,e,n,i){var r=t&&(null==t.value?t:t.value);return If(r instanceof Array?r[i]:r,this._dimensions[i])},typedArray:function(t,e,n,i){return t[i]}}}(),t}(),$f=function(){function t(t){this._sourceList=[],this._storeList=[],this._upstreamSignList=[],this._versionSignBase=0,this._dirty=!0,this._sourceHost=t}return t.prototype.dirty=function(){this._setLocalSource([],[]),this._storeList=[],this._dirty=!0},t.prototype._setLocalSource=function(t,e){this._sourceList=t,this._upstreamSignList=e,this._versionSignBase++,this._versionSignBase>9e10&&(this._versionSignBase=0)},t.prototype._getVersionSign=function(){return this._sourceHost.uid+"_"+this._versionSignBase},t.prototype.prepareSource=function(){this._isDirty()&&(this._createSource(),this._dirty=!1)},t.prototype._createSource=function(){this._setLocalSource([],[]);var t,e,n=this._sourceHost,i=this._getUpstreamSourceManagers(),r=!!i.length;if(Qf(n)){var o=n,a=void 0,s=void 0,l=void 0;if(r){var u=i[0];u.prepareSource(),a=(l=u.getSource()).data,s=l.sourceFormat,e=[u._getVersionSign()]}else s=$(a=o.get("data",!0))?Up:Wp,e=[];var h=this._getSourceMetaRawOption()||{},c=l&&l.metaRawOption||{},p=rt(h.seriesLayoutBy,c.seriesLayoutBy)||null,d=rt(h.sourceHeader,c.sourceHeader),f=rt(h.dimensions,c.dimensions);t=p!==c.seriesLayoutBy||!!d!=!!c.sourceHeader||f?[tf(a,{seriesLayoutBy:p,sourceHeader:d,dimensions:f},s)]:[]}else{var g=n;if(r){var y=this._applyTransform(i);t=y.sourceList,e=y.upstreamSignList}else{t=[tf(g.get("source",!0),this._getSourceMetaRawOption(),null)],e=[]}}this._setLocalSource(t,e)},t.prototype._applyTransform=function(t){var e,n=this._sourceHost,i=n.get("transform",!0),r=n.get("fromTransformResult",!0);if(null!=r){var o="";1!==t.length&&tg(o)}var a,s=[],l=[];return E(t,(function(t){t.prepareSource();var e=t.getSource(r||0),n="";null==r||e||tg(n),s.push(e),l.push(t._getVersionSign())})),i?e=function(t,e,n){var i=To(t),r=i.length,o="";r||wo(o);for(var a=0,s=r;a1||n>0&&!t.noHeader;return E(t.blocks,(function(t){var n=lg(t);n>=e&&(e=n+ +(i&&(!n||ag(t)&&!t.noHeader)))})),e}return 0}function ug(t,e,n,i){var r,o=e.noHeader,a=(r=lg(e),{html:ig[r],richText:rg[r]}),s=[],l=e.blocks||[];lt(!l||Y(l)),l=l||[];var u=t.orderMode;if(e.sortBlocks&&u){l=l.slice();var h={valueAsc:"asc",valueDesc:"desc"};if(_t(h,u)){var c=new kf(h[u],null);l.sort((function(t,e){return c.evaluate(t.sortParam,e.sortParam)}))}else"seriesDesc"===u&&l.reverse()}E(l,(function(n,r){var o=e.valueFormatter,l=sg(n)(o?A(A({},t),{valueFormatter:o}):t,n,r>0?a.html:0,i);null!=l&&s.push(l)}));var p="richText"===t.renderMode?s.join(a.richText):pg(i,s.join(""),o?n:a.html);if(o)return p;var d=mp(e.header,"ordinal",t.useUTC),f=ng(i,t.renderMode).nameStyle,g=eg(i);return"richText"===t.renderMode?dg(t,d,f)+a.richText+p:pg(i,'
'+re(d)+"
"+p,n)}function hg(t,e,n,i){var r=t.renderMode,o=e.noName,a=e.noValue,s=!e.markerType,l=e.name,u=t.useUTC,h=e.valueFormatter||t.valueFormatter||function(t){return z(t=Y(t)?t:[t],(function(t,e){return mp(t,Y(d)?d[e]:d,u)}))};if(!o||!a){var c=s?"":t.markupStyleCreator.makeTooltipMarker(e.markerType,e.markerColor||"#333",r),p=o?"":mp(l,"ordinal",u),d=e.valueType,f=a?[]:h(e.value,e.dataIndex),g=!s||!o,y=!s&&o,v=ng(i,r),m=v.nameStyle,x=v.valueStyle;return"richText"===r?(s?"":c)+(o?"":dg(t,p,m))+(a?"":function(t,e,n,i,r){var o=[r],a=i?10:20;return n&&o.push({padding:[0,0,0,a],align:"right"}),t.markupStyleCreator.wrapRichTextStyle(Y(e)?e.join(" "):e,o)}(t,f,g,y,x)):pg(i,(s?"":c)+(o?"":function(t,e,n){return''+re(t)+""}(p,!s,m))+(a?"":function(t,e,n,i){var r=n?"10px":"20px",o=e?"float:right;margin-left:"+r:"";return t=Y(t)?t:[t],''+z(t,(function(t){return re(t)})).join("  ")+""}(f,g,y,x)),n)}}function cg(t,e,n,i,r,o){if(t)return sg(t)({useUTC:r,renderMode:n,orderMode:i,markupStyleCreator:e,valueFormatter:t.valueFormatter},t,0,o)}function pg(t,e,n){return'
'+e+'
'}function dg(t,e,n){return t.markupStyleCreator.wrapRichTextStyle(e,n)}function fg(t,e){return Sp(t.getData().getItemVisual(e,"style")[t.visualDrawType])}function gg(t,e){var n=t.get("padding");return null!=n?n:"richText"===e?[8,10]:10}var yg=function(){function t(){this.richTextStyles={},this._nextStyleNameId=mo()}return t.prototype._generateStyleName=function(){return"__EC_aUTo_"+this._nextStyleNameId++},t.prototype.makeTooltipMarker=function(t,e,n){var i="richText"===n?this._generateStyleName():null,r=wp({color:e,type:t,renderMode:n,markerId:i});return U(r)?r:(this.richTextStyles[i]=r.style,r.content)},t.prototype.wrapRichTextStyle=function(t,e){var n={};Y(e)?E(e,(function(t){return A(n,t)})):A(n,e);var i=this._generateStyleName();return this.richTextStyles[i]=n,"{"+i+"|"+t+"}"},t}();function vg(t){var e,n,i,r,o=t.series,a=t.dataIndex,s=t.multipleSeries,l=o.getData(),u=l.mapDimensionsAll("defaultedTooltip"),h=u.length,c=o.getRawValue(a),p=Y(c),d=fg(o,a);if(h>1||p&&!h){var f=function(t,e,n,i,r){var o=e.getData(),a=V(t,(function(t,e,n){var i=o.getDimensionInfo(n);return t||i&&!1!==i.tooltip&&null!=i.displayName}),!1),s=[],l=[],u=[];function h(t,e){var n=o.getDimensionInfo(e);n&&!1!==n.otherDims.tooltip&&(a?u.push(og("nameValue",{markerType:"subItem",markerColor:r,name:n.displayName,value:t,valueType:n.type})):(s.push(t),l.push(n.type)))}return i.length?E(i,(function(t){h(mf(o,n,t),t)})):E(t,h),{inlineValues:s,inlineValueTypes:l,blocks:u}}(c,o,a,u,d);e=f.inlineValues,n=f.inlineValueTypes,i=f.blocks,r=f.inlineValues[0]}else if(h){var g=l.getDimensionInfo(u[0]);r=e=mf(l,a,u[0]),n=g.type}else r=e=p?c[0]:c;var y=No(o),v=y&&o.name||"",m=l.getName(a),x=s?v:m;return og("section",{header:v,noHeader:s||!y,sortParam:r,blocks:[og("nameValue",{markerType:"item",markerColor:d,name:x,noName:!ut(x),value:e,valueType:n,dataIndex:a})].concat(i||[])})}var mg=Vo();function xg(t,e){return t.getName(e)||t.getId(e)}var _g="__universalTransitionEnabled",bg=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e._selectedDataIndicesMap={},e}return n(e,t),e.prototype.init=function(t,e,n){this.seriesIndex=this.componentIndex,this.dataTask=wf({count:Sg,reset:Mg}),this.dataTask.context={model:this},this.mergeDefaultAndTheme(t,n),(mg(this).sourceManager=new $f(this)).prepareSource();var i=this.getInitialData(t,n);Tg(i,this),this.dataTask.context.data=i,mg(this).dataBeforeProcessed=i,wg(this),this._initSelectedMapFromData(i)},e.prototype.mergeDefaultAndTheme=function(t,e){var n=Pp(this),i=n?Rp(t):{},r=this.subType;zp.hasClass(r)&&(r+="Series"),C(t,e.getTheme().get(this.subType)),C(t,this.getDefaultOption()),Co(t,"label",["show"]),this.fillDataTextStyle(t.data),n&&Op(t,i,n)},e.prototype.mergeOption=function(t,e){t=C(this.option,t,!0),this.fillDataTextStyle(t.data);var n=Pp(this);n&&Op(this.option,t,n);var i=mg(this).sourceManager;i.dirty(),i.prepareSource();var r=this.getInitialData(t,e);Tg(r,this),this.dataTask.dirty(),this.dataTask.context.data=r,mg(this).dataBeforeProcessed=r,wg(this),this._initSelectedMapFromData(r)},e.prototype.fillDataTextStyle=function(t){if(t&&!$(t))for(var e=["show"],n=0;nthis.getShallow("animationThreshold")&&(e=!1),!!e},e.prototype.restoreData=function(){this.dataTask.dirty()},e.prototype.getColorFromPalette=function(t,e,n){var i=this.ecModel,r=cd.prototype.getColorFromPalette.call(this,t,e,n);return r||(r=i.getColorFromPalette(t,e,n)),r},e.prototype.coordDimToDataDim=function(t){return this.getRawData().mapDimensionsAll(t)},e.prototype.getProgressive=function(){return this.get("progressive")},e.prototype.getProgressiveThreshold=function(){return this.get("progressiveThreshold")},e.prototype.select=function(t,e){this._innerSelect(this.getData(e),t)},e.prototype.unselect=function(t,e){var n=this.option.selectedMap;if(n){var i=this.option.selectedMode,r=this.getData(e);if("series"===i||"all"===n)return this.option.selectedMap={},void(this._selectedDataIndicesMap={});for(var o=0;o=0&&n.push(r)}return n},e.prototype.isSelected=function(t,e){var n=this.option.selectedMap;if(!n)return!1;var i=this.getData(e);return("all"===n||n[xg(i,t)])&&!i.getItemModel(t).get(["select","disabled"])},e.prototype.isUniversalTransitionEnabled=function(){if(this[_g])return!0;var t=this.option.universalTransition;return!!t&&(!0===t||t&&t.enabled)},e.prototype._innerSelect=function(t,e){var n,i,r=this.option,o=r.selectedMode,a=e.length;if(o&&a)if("series"===o)r.selectedMap="all";else if("multiple"===o){q(r.selectedMap)||(r.selectedMap={});for(var s=r.selectedMap,l=0;l0&&this._innerSelect(t,e)}},e.registerClass=function(t){return zp.registerClass(t)},e.protoInitialize=function(){var t=e.prototype;t.type="series.__base__",t.seriesIndex=0,t.ignoreStyleOnData=!1,t.hasSymbolVisual=!1,t.defaultSymbol="circle",t.visualStyleAccessPath="itemStyle",t.visualDrawType="fill"}(),e}(zp);function wg(t){var e=t.name;No(t)||(t.name=function(t){var e=t.getRawData(),n=e.mapDimensionsAll("seriesName"),i=[];return E(n,(function(t){var n=e.getDimensionInfo(t);n.displayName&&i.push(n.displayName)})),i.join(" ")}(t)||e)}function Sg(t){return t.model.getRawData().count()}function Mg(t){var e=t.model;return e.setData(e.getRawData().cloneShallow()),Ig}function Ig(t,e){e.outputData&&t.end>e.outputData.count()&&e.model.getRawData().cloneShallow(e.outputData)}function Tg(t,e){E(vt(t.CHANGABLE_METHODS,t.DOWNSAMPLE_METHODS),(function(n){t.wrapMethod(n,H(Cg,e))}))}function Cg(t,e){var n=Dg(t);return n&&n.setOutputEnd((e||this).count()),e}function Dg(t){var e=(t.ecModel||{}).scheduler,n=e&&e.getPipeline(t.uid);if(n){var i=n.currentTask;if(i){var r=i.agentStubMap;r&&(i=r.get(t.uid))}return i}}R(bg,_f),R(bg,cd),Jo(bg,zp);var Ag=function(){function t(){this.group=new Br,this.uid=Ac("viewComponent")}return t.prototype.init=function(t,e){},t.prototype.render=function(t,e,n,i){},t.prototype.dispose=function(t,e){},t.prototype.updateView=function(t,e,n,i){},t.prototype.updateLayout=function(t,e,n,i){},t.prototype.updateVisual=function(t,e,n,i){},t.prototype.toggleBlurSeries=function(t,e,n){},t.prototype.eachRendered=function(t){var e=this.group;e&&e.traverse(t)},t}();function kg(){var t=Vo();return function(e){var n=t(e),i=e.pipelineContext,r=!!n.large,o=!!n.progressiveRender,a=n.large=!(!i||!i.large),s=n.progressiveRender=!(!i||!i.progressiveRender);return!(r===a&&o===s)&&"reset"}}$o(Ag),na(Ag);var Lg=Vo(),Pg=kg(),Og=function(){function t(){this.group=new Br,this.uid=Ac("viewChart"),this.renderTask=wf({plan:Eg,reset:zg}),this.renderTask.context={view:this}}return t.prototype.init=function(t,e){},t.prototype.render=function(t,e,n,i){0},t.prototype.highlight=function(t,e,n,i){var r=t.getData(i&&i.dataType);r&&Ng(r,i,"emphasis")},t.prototype.downplay=function(t,e,n,i){var r=t.getData(i&&i.dataType);r&&Ng(r,i,"normal")},t.prototype.remove=function(t,e){this.group.removeAll()},t.prototype.dispose=function(t,e){},t.prototype.updateView=function(t,e,n,i){this.render(t,e,n,i)},t.prototype.updateLayout=function(t,e,n,i){this.render(t,e,n,i)},t.prototype.updateVisual=function(t,e,n,i){this.render(t,e,n,i)},t.prototype.eachRendered=function(t){Jh(this.group,t)},t.markUpdateMethod=function(t,e){Lg(t).updateMethod=e},t.protoInitialize=void(t.prototype.type="chart"),t}();function Rg(t,e,n){t&&Ql(t)&&("emphasis"===e?Ol:Rl)(t,n)}function Ng(t,e,n){var i=zo(t,e),r=e&&null!=e.highlightKey?function(t){var e=sl[t];return null==e&&al<=32&&(e=sl[t]=al++),e}(e.highlightKey):null;null!=i?E(To(i),(function(e){Rg(t.getItemGraphicEl(e),n,r)})):t.eachItemGraphicEl((function(t){Rg(t,n,r)}))}function Eg(t){return Pg(t.model)}function zg(t){var e=t.model,n=t.ecModel,i=t.api,r=t.payload,o=e.pipelineContext.progressiveRender,a=t.view,s=r&&Lg(r).updateMethod,l=o?"incrementalPrepareRender":s&&a[s]?s:"render";return"render"!==l&&a[l](e,n,i,r),Vg[l]}$o(Og),na(Og);var Vg={incrementalPrepareRender:{progress:function(t,e){e.view.incrementalRender(t,e.model,e.ecModel,e.api,e.payload)}},render:{forceFirstProgress:!0,progress:function(t,e){e.view.render(e.model,e.ecModel,e.api,e.payload)}}},Bg="\0__throttleOriginMethod",Fg="\0__throttleRate",Gg="\0__throttleType";function Wg(t,e,n){var i,r,o,a,s,l=0,u=0,h=null;function c(){u=(new Date).getTime(),h=null,t.apply(o,a||[])}e=e||0;var p=function(){for(var t=[],p=0;p=0?c():h=setTimeout(c,-r),l=i};return p.clear=function(){h&&(clearTimeout(h),h=null)},p.debounceNextCall=function(t){s=t},p}function Hg(t,e,n,i){var r=t[e];if(r){var o=r[Bg]||r,a=r[Gg];if(r[Fg]!==n||a!==i){if(null==n||!i)return t[e]=o;(r=t[e]=Wg(o,n,"debounce"===i))[Bg]=o,r[Gg]=i,r[Fg]=n}return r}}function Yg(t,e){var n=t[e];n&&n[Bg]&&(n.clear&&n.clear(),t[e]=n[Bg])}var Xg=Vo(),Ug={itemStyle:ia(Mc,!0),lineStyle:ia(bc,!0)},Zg={lineStyle:"stroke",itemStyle:"fill"};function jg(t,e){var n=t.visualStyleMapper||Ug[e];return n||(console.warn("Unknown style type '"+e+"'."),Ug.itemStyle)}function qg(t,e){var n=t.visualDrawType||Zg[e];return n||(console.warn("Unknown style type '"+e+"'."),"fill")}var Kg={createOnAllSeries:!0,performRawSeries:!0,reset:function(t,e){var n=t.getData(),i=t.visualStyleAccessPath||"itemStyle",r=t.getModel(i),o=jg(t,i)(r),a=r.getShallow("decal");a&&(n.setVisual("decal",a),a.dirty=!0);var s=qg(t,i),l=o[s],u=X(l)?l:null,h="auto"===o.fill||"auto"===o.stroke;if(!o[s]||u||h){var c=t.getColorFromPalette(t.name,null,e.getSeriesCount());o[s]||(o[s]=c,n.setVisual("colorFromPalette",!0)),o.fill="auto"===o.fill||X(o.fill)?c:o.fill,o.stroke="auto"===o.stroke||X(o.stroke)?c:o.stroke}if(n.setVisual("style",o),n.setVisual("drawType",s),!e.isSeriesFiltered(t)&&u)return n.setVisual("colorFromPalette",!1),{dataEach:function(e,n){var i=t.getDataParams(n),r=A({},o);r[s]=u(i),e.setItemVisual(n,"style",r)}}}},$g=new Cc,Jg={createOnAllSeries:!0,performRawSeries:!0,reset:function(t,e){if(!t.ignoreStyleOnData&&!e.isSeriesFiltered(t)){var n=t.getData(),i=t.visualStyleAccessPath||"itemStyle",r=jg(t,i),o=n.getVisual("drawType");return{dataEach:n.hasItemOption?function(t,e){var n=t.getRawDataItem(e);if(n&&n[i]){$g.option=n[i];var a=r($g);A(t.ensureUniqueItemVisual(e,"style"),a),$g.option.decal&&(t.setItemVisual(e,"decal",$g.option.decal),$g.option.decal.dirty=!0),o in a&&t.setItemVisual(e,"colorFromPalette",!1)}}:null}}}},Qg={performRawSeries:!0,overallReset:function(t){var e=yt();t.eachSeries((function(t){var n=t.getColorBy();if(!t.isColorBySeries()){var i=t.type+"-"+n,r=e.get(i);r||(r={},e.set(i,r)),Xg(t).scope=r}})),t.eachSeries((function(e){if(!e.isColorBySeries()&&!t.isSeriesFiltered(e)){var n=e.getRawData(),i={},r=e.getData(),o=Xg(e).scope,a=e.visualStyleAccessPath||"itemStyle",s=qg(e,a);r.each((function(t){var e=r.getRawIndex(t);i[e]=t})),n.each((function(t){var a=i[t];if(r.getItemVisual(a,"colorFromPalette")){var l=r.ensureUniqueItemVisual(a,"style"),u=n.getName(t)||t+"",h=n.count();l[s]=e.getColorFromPalette(u,o,h)}}))}}))}},ty=Math.PI;var ey=function(){function t(t,e,n,i){this._stageTaskMap=yt(),this.ecInstance=t,this.api=e,n=this._dataProcessorHandlers=n.slice(),i=this._visualHandlers=i.slice(),this._allHandlers=n.concat(i)}return t.prototype.restoreData=function(t,e){t.restoreData(e),this._stageTaskMap.each((function(t){var e=t.overallTask;e&&e.dirty()}))},t.prototype.getPerformArgs=function(t,e){if(t.__pipeline){var n=this._pipelineMap.get(t.__pipeline.id),i=n.context,r=!e&&n.progressiveEnabled&&(!i||i.progressiveRender)&&t.__idxInPipeline>n.blockIndex?n.step:null,o=i&&i.modDataCount;return{step:r,modBy:null!=o?Math.ceil(o/r):null,modDataCount:o}}},t.prototype.getPipeline=function(t){return this._pipelineMap.get(t)},t.prototype.updateStreamModes=function(t,e){var n=this._pipelineMap.get(t.uid),i=t.getData().count(),r=n.progressiveEnabled&&e.incrementalPrepareRender&&i>=n.threshold,o=t.get("large")&&i>=t.get("largeThreshold"),a="mod"===t.get("progressiveChunkMode")?i:null;t.pipelineContext=n.context={progressiveRender:r,modDataCount:a,large:o}},t.prototype.restorePipelines=function(t){var e=this,n=e._pipelineMap=yt();t.eachSeries((function(t){var i=t.getProgressive(),r=t.uid;n.set(r,{id:r,head:null,tail:null,threshold:t.getProgressiveThreshold(),progressiveEnabled:i&&!(t.preventIncremental&&t.preventIncremental()),blockIndex:-1,step:Math.round(i||700),count:0}),e._pipe(t,t.dataTask)}))},t.prototype.prepareStageTasks=function(){var t=this._stageTaskMap,e=this.api.getModel(),n=this.api;E(this._allHandlers,(function(i){var r=t.get(i.uid)||t.set(i.uid,{}),o="";lt(!(i.reset&&i.overallReset),o),i.reset&&this._createSeriesStageTask(i,r,e,n),i.overallReset&&this._createOverallStageTask(i,r,e,n)}),this)},t.prototype.prepareView=function(t,e,n,i){var r=t.renderTask,o=r.context;o.model=e,o.ecModel=n,o.api=i,r.__block=!t.incrementalPrepareRender,this._pipe(e,r)},t.prototype.performDataProcessorTasks=function(t,e){this._performStageTasks(this._dataProcessorHandlers,t,e,{block:!0})},t.prototype.performVisualTasks=function(t,e,n){this._performStageTasks(this._visualHandlers,t,e,n)},t.prototype._performStageTasks=function(t,e,n,i){i=i||{};var r=!1,o=this;function a(t,e){return t.setDirty&&(!t.dirtyMap||t.dirtyMap.get(e.__pipeline.id))}E(t,(function(t,s){if(!i.visualType||i.visualType===t.visualType){var l=o._stageTaskMap.get(t.uid),u=l.seriesTaskMap,h=l.overallTask;if(h){var c,p=h.agentStubMap;p.each((function(t){a(i,t)&&(t.dirty(),c=!0)})),c&&h.dirty(),o.updatePayload(h,n);var d=o.getPerformArgs(h,i.block);p.each((function(t){t.perform(d)})),h.perform(d)&&(r=!0)}else u&&u.each((function(s,l){a(i,s)&&s.dirty();var u=o.getPerformArgs(s,i.block);u.skip=!t.performRawSeries&&e.isSeriesFiltered(s.context.model),o.updatePayload(s,n),s.perform(u)&&(r=!0)}))}})),this.unfinished=r||this.unfinished},t.prototype.performSeriesTasks=function(t){var e;t.eachSeries((function(t){e=t.dataTask.perform()||e})),this.unfinished=e||this.unfinished},t.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)}))},t.prototype.updatePayload=function(t,e){"remain"!==e&&(t.context.payload=e)},t.prototype._createSeriesStageTask=function(t,e,n,i){var r=this,o=e.seriesTaskMap,a=e.seriesTaskMap=yt(),s=t.seriesType,l=t.getTargetSeries;function u(e){var s=e.uid,l=a.set(s,o&&o.get(s)||wf({plan:ay,reset:sy,count:hy}));l.context={model:e,ecModel:n,api:i,useClearVisual:t.isVisual&&!t.isLayout,plan:t.plan,reset:t.reset,scheduler:r},r._pipe(e,l)}t.createOnAllSeries?n.eachRawSeries(u):s?n.eachRawSeriesByType(s,u):l&&l(n,i).each(u)},t.prototype._createOverallStageTask=function(t,e,n,i){var r=this,o=e.overallTask=e.overallTask||wf({reset:ny});o.context={ecModel:n,api:i,overallReset:t.overallReset,scheduler:r};var a=o.agentStubMap,s=o.agentStubMap=yt(),l=t.seriesType,u=t.getTargetSeries,h=!0,c=!1,p="";function d(t){var e=t.uid,n=s.set(e,a&&a.get(e)||(c=!0,wf({reset:iy,onDirty:oy})));n.context={model:t,overallProgress:h},n.agent=o,n.__block=h,r._pipe(t,n)}lt(!t.createOnAllSeries,p),l?n.eachRawSeriesByType(l,d):u?u(n,i).each(d):(h=!1,E(n.getSeries(),d)),c&&o.dirty()},t.prototype._pipe=function(t,e){var n=t.uid,i=this._pipelineMap.get(n);!i.head&&(i.head=e),i.tail&&i.tail.pipe(e),i.tail=e,e.__idxInPipeline=i.count++,e.__pipeline=i},t.wrapStageHandler=function(t,e){return X(t)&&(t={overallReset:t,seriesType:cy(t)}),t.uid=Ac("stageHandler"),e&&(t.visualType=e),t},t}();function ny(t){t.overallReset(t.ecModel,t.api,t.payload)}function iy(t){return t.overallProgress&&ry}function ry(){this.agent.dirty(),this.getDownstream().dirty()}function oy(){this.agent&&this.agent.dirty()}function ay(t){return t.plan?t.plan(t.model,t.ecModel,t.api,t.payload):null}function sy(t){t.useClearVisual&&t.data.clearAllVisual();var e=t.resetDefines=To(t.reset(t.model,t.ecModel,t.api,t.payload));return e.length>1?z(e,(function(t,e){return uy(e)})):ly}var ly=uy(0);function uy(t){return function(e,n){var i=n.data,r=n.resetDefines[t];if(r&&r.dataEach)for(var o=e.start;o0&&h===r.length-u.length){var c=r.slice(0,h);"data"!==c&&(e.mainType=c,e[u.toLowerCase()]=t,s=!0)}}a.hasOwnProperty(r)&&(n[r]=t,s=!0),s||(i[r]=t)}))}return{cptQuery:e,dataQuery:n,otherQuery:i}},t.prototype.filter=function(t,e){var n=this.eventInfo;if(!n)return!0;var i=n.targetEl,r=n.packedEvent,o=n.model,a=n.view;if(!o||!a)return!0;var s=e.cptQuery,l=e.dataQuery;return u(s,o,"mainType")&&u(s,o,"subType")&&u(s,o,"index","componentIndex")&&u(s,o,"name")&&u(s,o,"id")&&u(l,r,"name")&&u(l,r,"dataIndex")&&u(l,r,"dataType")&&(!a.filterForExposedEvent||a.filterForExposedEvent(t,e.otherQuery,i,r));function u(t,e,n,i){return null==t[n]||e[i||n]===t[n]}},t.prototype.afterTrigger=function(){this.eventInfo=null},t}(),My=["symbol","symbolSize","symbolRotate","symbolOffset"],Iy=My.concat(["symbolKeepAspect"]),Ty={createOnAllSeries:!0,performRawSeries:!0,reset:function(t,e){var n=t.getData();if(t.legendIcon&&n.setVisual("legendIcon",t.legendIcon),t.hasSymbolVisual){for(var i={},r={},o=!1,a=0;a=0&&jy(l)?l:.5,t.createRadialGradient(a,s,0,a,s,l)}(t,e,n):function(t,e,n){var i=null==e.x?0:e.x,r=null==e.x2?1:e.x2,o=null==e.y?0:e.y,a=null==e.y2?0:e.y2;return e.global||(i=i*n.width+n.x,r=r*n.width+n.x,o=o*n.height+n.y,a=a*n.height+n.y),i=jy(i)?i:0,r=jy(r)?r:1,o=jy(o)?o:0,a=jy(a)?a:0,t.createLinearGradient(i,o,r,a)}(t,e,n),r=e.colorStops,o=0;o0&&(e=i.lineDash,n=i.lineWidth,e&&"solid"!==e&&n>0?"dashed"===e?[4*n,2*n]:"dotted"===e?[n]:j(e)?[e]:Y(e)?e:null:null),o=i.lineDashOffset;if(r){var a=i.strokeNoScale&&t.getLineScale?t.getLineScale():1;a&&1!==a&&(r=z(r,(function(t){return t/a})),o/=a)}return[r,o]}var Qy=new hs(!0);function tv(t){var e=t.stroke;return!(null==e||"none"===e||!(t.lineWidth>0))}function ev(t){return"string"==typeof t&&"none"!==t}function nv(t){var e=t.fill;return null!=e&&"none"!==e}function iv(t,e){if(null!=e.fillOpacity&&1!==e.fillOpacity){var n=t.globalAlpha;t.globalAlpha=e.fillOpacity*e.opacity,t.fill(),t.globalAlpha=n}else t.fill()}function rv(t,e){if(null!=e.strokeOpacity&&1!==e.strokeOpacity){var n=t.globalAlpha;t.globalAlpha=e.strokeOpacity*e.opacity,t.stroke(),t.globalAlpha=n}else t.stroke()}function ov(t,e,n){var i=la(e.image,e.__image,n);if(ha(i)){var r=t.createPattern(i,e.repeat||"repeat");if("function"==typeof DOMMatrix&&r&&r.setTransform){var o=new DOMMatrix;o.translateSelf(e.x||0,e.y||0),o.rotateSelf(0,0,(e.rotation||0)*wt),o.scaleSelf(e.scaleX||1,e.scaleY||1),r.setTransform(o)}return r}}var av=["shadowBlur","shadowOffsetX","shadowOffsetY"],sv=[["lineCap","butt"],["lineJoin","miter"],["miterLimit",10]];function lv(t,e,n,i,r){var o=!1;if(!i&&e===(n=n||{}))return!1;if(i||e.opacity!==n.opacity){cv(t,r),o=!0;var a=Math.max(Math.min(e.opacity,1),0);t.globalAlpha=isNaN(a)?Ma.opacity:a}(i||e.blend!==n.blend)&&(o||(cv(t,r),o=!0),t.globalCompositeOperation=e.blend||Ma.blend);for(var s=0;s0&&t.unfinished);t.unfinished||this._zr.flush()}}},e.prototype.getDom=function(){return this._dom},e.prototype.getId=function(){return this.id},e.prototype.getZr=function(){return this._zr},e.prototype.isSSR=function(){return this._ssr},e.prototype.setOption=function(t,e,n){if(!this[Dv])if(this._disposed)om(this.id);else{var i,r,o;if(q(e)&&(n=e.lazyUpdate,i=e.silent,r=e.replaceMerge,o=e.transition,e=e.notMerge),this[Dv]=!0,!this._model||e){var a=new Md(this._api),s=this._theme,l=this._model=new gd;l.scheduler=this._scheduler,l.ssr=this._ssr,l.init(null,null,null,s,this._locale,a)}this._model.setOption(t,{replaceMerge:r},um);var u={seriesTransition:o,optionChanged:!0};if(n)this[Av]={silent:i,updateParams:u},this[Dv]=!1,this.getZr().wakeUp();else{try{Ev(this),Bv.update.call(this,null,u)}catch(t){throw this[Av]=null,this[Dv]=!1,t}this._ssr||this._zr.flush(),this[Av]=null,this[Dv]=!1,Hv.call(this,i),Yv.call(this,i)}}},e.prototype.setTheme=function(){bo()},e.prototype.getModel=function(){return this._model},e.prototype.getOption=function(){return this._model&&this._model.getOption()},e.prototype.getWidth=function(){return this._zr.getWidth()},e.prototype.getHeight=function(){return this._zr.getHeight()},e.prototype.getDevicePixelRatio=function(){return this._zr.painter.dpr||r.hasGlobalWindow&&window.devicePixelRatio||1},e.prototype.getRenderedCanvas=function(t){return this.renderToCanvas(t)},e.prototype.renderToCanvas=function(t){t=t||{};var e=this._zr.painter;return e.getRenderedCanvas({backgroundColor:t.backgroundColor||this._model.get("backgroundColor"),pixelRatio:t.pixelRatio||this.getDevicePixelRatio()})},e.prototype.renderToSVGString=function(t){t=t||{};var e=this._zr.painter;return e.renderToString({useViewBox:t.useViewBox})},e.prototype.getSvgDataURL=function(){if(r.svgSupported){var t=this._zr;return E(t.storage.getDisplayList(),(function(t){t.stopAnimation(null,!0)})),t.painter.toDataURL()}},e.prototype.getDataURL=function(t){if(!this._disposed){var e=(t=t||{}).excludeComponents,n=this._model,i=[],r=this;E(e,(function(t){n.eachComponent({mainType:t},(function(t){var e=r._componentsMap[t.__viewId];e.group.ignore||(i.push(e),e.group.ignore=!0)}))}));var o="svg"===this._zr.painter.getType()?this.getSvgDataURL():this.renderToCanvas(t).toDataURL("image/"+(t&&t.type||"png"));return E(i,(function(t){t.group.ignore=!1})),o}om(this.id)},e.prototype.getConnectedDataURL=function(t){if(!this._disposed){var e="svg"===t.type,n=this.group,i=Math.min,r=Math.max,o=1/0;if(fm[n]){var a=o,s=o,l=-1/0,u=-1/0,c=[],p=t&&t.pixelRatio||this.getDevicePixelRatio();E(dm,(function(o,h){if(o.group===n){var p=e?o.getZr().painter.getSvgDom().innerHTML:o.renderToCanvas(T(t)),d=o.getDom().getBoundingClientRect();a=i(d.left,a),s=i(d.top,s),l=r(d.right,l),u=r(d.bottom,u),c.push({dom:p,left:d.left,top:d.top})}}));var d=(l*=p)-(a*=p),f=(u*=p)-(s*=p),g=h.createCanvas(),y=Yr(g,{renderer:e?"svg":"canvas"});if(y.resize({width:d,height:f}),e){var v="";return E(c,(function(t){var e=t.left-a,n=t.top-s;v+=''+t.dom+""})),y.painter.getSvgRoot().innerHTML=v,t.connectedBackgroundColor&&y.painter.setBackgroundColor(t.connectedBackgroundColor),y.refreshImmediately(),y.painter.toDataURL()}return t.connectedBackgroundColor&&y.add(new Ws({shape:{x:0,y:0,width:d,height:f},style:{fill:t.connectedBackgroundColor}})),E(c,(function(t){var e=new Ns({style:{x:t.left*p-a,y:t.top*p-s,image:t.dom}});y.add(e)})),y.refreshImmediately(),g.toDataURL("image/"+(t&&t.type||"png"))}return this.getDataURL(t)}om(this.id)},e.prototype.convertToPixel=function(t,e){return Fv(this,"convertToPixel",t,e)},e.prototype.convertFromPixel=function(t,e){return Fv(this,"convertFromPixel",t,e)},e.prototype.containPixel=function(t,e){var n;if(!this._disposed)return E(Fo(this._model,t),(function(t,i){i.indexOf("Models")>=0&&E(t,(function(t){var r=t.coordinateSystem;if(r&&r.containPoint)n=n||!!r.containPoint(e);else if("seriesModels"===i){var o=this._chartsMap[t.__viewId];o&&o.containPoint&&(n=n||o.containPoint(e,t))}else 0}),this)}),this),!!n;om(this.id)},e.prototype.getVisual=function(t,e){var n=Fo(this._model,t,{defaultMainType:"series"}),i=n.seriesModel;var r=i.getData(),o=n.hasOwnProperty("dataIndexInside")?n.dataIndexInside:n.hasOwnProperty("dataIndex")?r.indexOfRawIndex(n.dataIndex):null;return null!=o?Dy(r,o,e):Ay(r,e)},e.prototype.getViewOfComponentModel=function(t){return this._componentsMap[t.__viewId]},e.prototype.getViewOfSeriesModel=function(t){return this._chartsMap[t.__viewId]},e.prototype._initEvents=function(){var t,e,n,i=this;E(rm,(function(t){var e=function(e){var n,r=i.getModel(),o=e.target,a="globalout"===t;if(a?n={}:o&&Oy(o,(function(t){var e=rl(t);if(e&&null!=e.dataIndex){var i=e.dataModel||r.getSeriesByIndex(e.seriesIndex);return n=i&&i.getDataParams(e.dataIndex,e.dataType,o)||{},!0}if(e.eventData)return n=A({},e.eventData),!0}),!0),n){var s=n.componentType,l=n.componentIndex;"markLine"!==s&&"markPoint"!==s&&"markArea"!==s||(s="series",l=n.seriesIndex);var u=s&&null!=l&&r.getComponent(s,l),h=u&&i["series"===u.mainType?"_chartsMap":"_componentsMap"][u.__viewId];0,n.event=e,n.type=t,i._$eventProcessor.eventInfo={targetEl:o,packedEvent:n,model:u,view:h},i.trigger(t,n)}};e.zrEventfulCallAtLast=!0,i._zr.on(t,e,i)})),E(sm,(function(t,e){i._messageCenter.on(e,(function(t){this.trigger(e,t)}),i)})),E(["selectchanged"],(function(t){i._messageCenter.on(t,(function(e){this.trigger(t,e)}),i)})),t=this._messageCenter,e=this,n=this._api,t.on("selectchanged",(function(t){var i=n.getModel();t.isFromClick?(Py("map","selectchanged",e,i,t),Py("pie","selectchanged",e,i,t)):"select"===t.fromAction?(Py("map","selected",e,i,t),Py("pie","selected",e,i,t)):"unselect"===t.fromAction&&(Py("map","unselected",e,i,t),Py("pie","unselected",e,i,t))}))},e.prototype.isDisposed=function(){return this._disposed},e.prototype.clear=function(){this._disposed?om(this.id):this.setOption({series:[]},!0)},e.prototype.dispose=function(){if(this._disposed)om(this.id);else{this._disposed=!0,this.getDom()&&Xo(this.getDom(),vm,"");var t=this,e=t._api,n=t._model;E(t._componentsViews,(function(t){t.dispose(n,e)})),E(t._chartsViews,(function(t){t.dispose(n,e)})),t._zr.dispose(),t._dom=t._model=t._chartsMap=t._componentsMap=t._chartsViews=t._componentsViews=t._scheduler=t._api=t._zr=t._throttledZrFlush=t._theme=t._coordSysMgr=t._messageCenter=null,delete dm[t.id]}},e.prototype.resize=function(t){if(!this[Dv])if(this._disposed)om(this.id);else{this._zr.resize(t);var e=this._model;if(this._loadingFX&&this._loadingFX.resize(),e){var n=e.resetOption("media"),i=t&&t.silent;this[Av]&&(null==i&&(i=this[Av].silent),n=!0,this[Av]=null),this[Dv]=!0;try{n&&Ev(this),Bv.update.call(this,{type:"resize",animation:A({duration:0},t&&t.animation)})}catch(t){throw this[Dv]=!1,t}this[Dv]=!1,Hv.call(this,i),Yv.call(this,i)}}},e.prototype.showLoading=function(t,e){if(this._disposed)om(this.id);else if(q(t)&&(e=t,t=""),t=t||"default",this.hideLoading(),pm[t]){var n=pm[t](this._api,e),i=this._zr;this._loadingFX=n,i.add(n)}},e.prototype.hideLoading=function(){this._disposed?om(this.id):(this._loadingFX&&this._zr.remove(this._loadingFX),this._loadingFX=null)},e.prototype.makeActionFromEvent=function(t){var e=A({},t);return e.type=sm[t.type],e},e.prototype.dispatchAction=function(t,e){if(this._disposed)om(this.id);else if(q(e)||(e={silent:!!e}),am[t.type]&&this._model)if(this[Dv])this._pendingActions.push(t);else{var n=e.silent;Wv.call(this,t,n);var i=e.flush;i?this._zr.flush():!1!==i&&r.browser.weChat&&this._throttledZrFlush(),Hv.call(this,n),Yv.call(this,n)}},e.prototype.updateLabelLayout=function(){wv.trigger("series:layoutlabels",this._model,this._api,{updatedSeries:[]})},e.prototype.appendData=function(t){if(this._disposed)om(this.id);else{var e=t.seriesIndex,n=this.getModel().getSeriesByIndex(e);0,n.appendData(t),this._scheduler.unfinished=!0,this.getZr().wakeUp()}},e.internalField=function(){function t(t){t.clearColorPalette(),t.eachSeries((function(t){t.clearColorPalette()}))}function e(t){for(var e=[],n=t.currentStates,i=0;i0?{duration:o,delay:i.get("delay"),easing:i.get("easing")}:null;n.eachRendered((function(t){if(t.states&&t.states.emphasis){if(xh(t))return;if(t instanceof ks&&function(t){var e=ll(t);e.normalFill=t.style.fill,e.normalStroke=t.style.stroke;var n=t.states.select||{};e.selectFill=n.style&&n.style.fill||null,e.selectStroke=n.style&&n.style.stroke||null}(t),t.__dirty){var n=t.prevStates;n&&t.useStates(n)}if(r){t.stateTransition=a;var i=t.getTextContent(),o=t.getTextGuideLine();i&&(i.stateTransition=a),o&&(o.stateTransition=a)}t.__dirty&&e(t)}}))}Ev=function(t){var e=t._scheduler;e.restorePipelines(t._model),e.prepareStageTasks(),zv(t,!0),zv(t,!1),e.plan()},zv=function(t,e){for(var n=t._model,i=t._scheduler,r=e?t._componentsViews:t._chartsViews,o=e?t._componentsMap:t._chartsMap,a=t._zr,s=t._api,l=0;le.get("hoverLayerThreshold")&&!r.node&&!r.worker&&e.eachSeries((function(e){if(!e.preventUsingHoverLayer){var n=t._chartsMap[e.__viewId];n.__alive&&n.eachRendered((function(t){t.states.emphasis&&(t.states.emphasis.hoverLayer=!0)}))}}))}(t,e),wv.trigger("series:afterupdate",e,n,l)},Jv=function(t){t[kv]=!0,t.getZr().wakeUp()},Qv=function(t){t[kv]&&(t.getZr().storage.traverse((function(t){xh(t)||e(t)})),t[kv]=!1)},Kv=function(t){return new(function(e){function i(){return null!==e&&e.apply(this,arguments)||this}return n(i,e),i.prototype.getCoordinateSystems=function(){return t._coordSysMgr.getCoordinateSystems()},i.prototype.getComponentByElement=function(e){for(;e;){var n=e.__ecComponentInfo;if(null!=n)return t._model.getComponent(n.mainType,n.index);e=e.parent}},i.prototype.enterEmphasis=function(e,n){Ol(e,n),Jv(t)},i.prototype.leaveEmphasis=function(e,n){Rl(e,n),Jv(t)},i.prototype.enterBlur=function(e){Nl(e),Jv(t)},i.prototype.leaveBlur=function(e){El(e),Jv(t)},i.prototype.enterSelect=function(e){zl(e),Jv(t)},i.prototype.leaveSelect=function(e){Vl(e),Jv(t)},i.prototype.getModel=function(){return t.getModel()},i.prototype.getViewOfComponentModel=function(e){return t.getViewOfComponentModel(e)},i.prototype.getViewOfSeriesModel=function(e){return t.getViewOfSeriesModel(e)},i}(_d))(t)},$v=function(t){function e(t,e){for(var n=0;n=0)){Lm.push(n);var o=ey.wrapStageHandler(n,r);o.__prio=e,o.__raw=n,t.push(o)}}function Om(t,e){pm[t]=e}function Rm(t,e,n){var i=Mv("registerMap");i&&i(t,e,n)}var Nm=function(t){var e=(t=T(t)).type,n="";e||wo(n);var i=e.split(":");2!==i.length&&wo(n);var r=!1;"echarts"===i[0]&&(e=i[1],r=!0),t.__isBuiltIn=r,Vf.set(e,t)};km(Iv,Kg),km(Tv,Jg),km(Tv,Qg),km(Iv,Ty),km(Tv,Cy),km(7e3,(function(t,e){t.eachRawSeries((function(n){if(!t.isSeriesFiltered(n)){var i=n.getData();i.hasItemVisual()&&i.each((function(t){var n=i.getItemVisual(t,"decal");n&&(i.ensureUniqueItemVisual(t,"style").decal=mv(n,e))}));var r=i.getVisual("decal");if(r)i.getVisual("style").decal=mv(r,e)}}))})),wm(Xd),Sm(900,(function(t){var e=yt();t.eachSeries((function(t){var n=t.get("stack");if(n){var i=e.get(n)||e.set(n,[]),r=t.getData(),o={stackResultDimension:r.getCalculationInfo("stackResultDimension"),stackedOverDimension:r.getCalculationInfo("stackedOverDimension"),stackedDimension:r.getCalculationInfo("stackedDimension"),stackedByDimension:r.getCalculationInfo("stackedByDimension"),isStackedByIndex:r.getCalculationInfo("isStackedByIndex"),data:r,seriesModel:t};if(!o.stackedDimension||!o.isStackedByIndex&&!o.stackedByDimension)return;i.length&&r.setCalculationInfo("stackedOnSeries",i[i.length-1].seriesModel),i.push(o)}})),e.each(Ud)})),Om("default",(function(t,e){k(e=e||{},{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 n=new Br,i=new Ws({style:{fill:e.maskColor},zlevel:e.zlevel,z:1e4});n.add(i);var r,o=new Xs({style:{text:e.text,fill:e.textColor,fontSize:e.fontSize,fontWeight:e.fontWeight,fontStyle:e.fontStyle,fontFamily:e.fontFamily},zlevel:e.zlevel,z:10001}),a=new Ws({style:{fill:"none"},textContent:o,textConfig:{position:"right",distance:10},zlevel:e.zlevel,z:10001});return n.add(a),e.showSpinner&&((r=new nh({shape:{startAngle:-ty/2,endAngle:-ty/2+.1,r:e.spinnerRadius},style:{stroke:e.color,lineCap:"round",lineWidth:e.lineWidth},zlevel:e.zlevel,z:10001})).animateShape(!0).when(1e3,{endAngle:3*ty/2}).start("circularInOut"),r.animateShape(!0).when(1e3,{startAngle:3*ty/2}).delay(300).start("circularInOut"),n.add(r)),n.resize=function(){var n=o.getBoundingRect().width,s=e.showSpinner?e.spinnerRadius:0,l=(t.getWidth()-2*s-(e.showSpinner&&n?10:0)-n)/2-(e.showSpinner&&n?0:5+n/2)+(e.showSpinner?0:n/2)+(n?0:s),u=t.getHeight()/2;e.showSpinner&&r.setShape({cx:l,cy:u}),a.setShape({x:l-s,y:u-s,width:2*s,height:2*s}),i.setShape({x:0,y:0,width:t.getWidth(),height:t.getHeight()})},n.resize(),n})),Cm({type:dl,event:dl,update:dl},bt),Cm({type:fl,event:fl,update:fl},bt),Cm({type:gl,event:gl,update:gl},bt),Cm({type:yl,event:yl,update:yl},bt),Cm({type:vl,event:vl,update:vl},bt),bm("light",vy),bm("dark",wy);var Em=[],zm={registerPreprocessor:wm,registerProcessor:Sm,registerPostInit:Mm,registerPostUpdate:Im,registerUpdateLifecycle:Tm,registerAction:Cm,registerCoordinateSystem:Dm,registerLayout:Am,registerVisual:km,registerTransform:Nm,registerLoading:Om,registerMap:Rm,registerImpl:function(t,e){Sv[t]=e},PRIORITY:Cv,ComponentModel:zp,ComponentView:Ag,SeriesModel:bg,ChartView:Og,registerComponentModel:function(t){zp.registerClass(t)},registerComponentView:function(t){Ag.registerClass(t)},registerSeriesModel:function(t){bg.registerClass(t)},registerChartView:function(t){Og.registerClass(t)},registerSubTypeDefaulter:function(t,e){zp.registerSubTypeDefaulter(t,e)},registerPainter:function(t,e){Xr(t,e)}};function Vm(t){Y(t)?E(t,(function(t){Vm(t)})):P(Em,t)>=0||(Em.push(t),X(t)&&(t={install:t}),t.install(zm))}function Bm(t){return null==t?0:t.length||1}function Fm(t){return t}var Gm=function(){function t(t,e,n,i,r,o){this._old=t,this._new=e,this._oldKeyGetter=n||Fm,this._newKeyGetter=i||Fm,this.context=r,this._diffModeMultiple="multiple"===o}return t.prototype.add=function(t){return this._add=t,this},t.prototype.update=function(t){return this._update=t,this},t.prototype.updateManyToOne=function(t){return this._updateManyToOne=t,this},t.prototype.updateOneToMany=function(t){return this._updateOneToMany=t,this},t.prototype.updateManyToMany=function(t){return this._updateManyToMany=t,this},t.prototype.remove=function(t){return this._remove=t,this},t.prototype.execute=function(){this[this._diffModeMultiple?"_executeMultiple":"_executeOneToOne"]()},t.prototype._executeOneToOne=function(){var t=this._old,e=this._new,n={},i=new Array(t.length),r=new Array(e.length);this._initIndexMap(t,null,i,"_oldKeyGetter"),this._initIndexMap(e,n,r,"_newKeyGetter");for(var o=0;o1){var u=s.shift();1===s.length&&(n[a]=s[0]),this._update&&this._update(u,o)}else 1===l?(n[a]=null,this._update&&this._update(s,o)):this._remove&&this._remove(o)}this._performRestAdd(r,n)},t.prototype._executeMultiple=function(){var t=this._old,e=this._new,n={},i={},r=[],o=[];this._initIndexMap(t,n,r,"_oldKeyGetter"),this._initIndexMap(e,i,o,"_newKeyGetter");for(var a=0;a1&&1===c)this._updateManyToOne&&this._updateManyToOne(u,l),i[s]=null;else if(1===h&&c>1)this._updateOneToMany&&this._updateOneToMany(u,l),i[s]=null;else if(1===h&&1===c)this._update&&this._update(u,l),i[s]=null;else if(h>1&&c>1)this._updateManyToMany&&this._updateManyToMany(u,l),i[s]=null;else if(h>1)for(var p=0;p1)for(var a=0;a30}var Qm,tx,ex,nx,ix,rx,ox,ax=q,sx=z,lx="undefined"==typeof Int32Array?Array:Int32Array,ux=["hasItemOption","_nameList","_idList","_invertedIndicesMap","_dimSummary","userOutput","_rawData","_dimValueGetter","_nameDimIdx","_idDimIdx","_nameRepeatCount"],hx=["_approximateExtent"],cx=function(){function t(t,e){var n;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","minmaxDownSample","lttbDownSample","map"],this.CHANGABLE_METHODS=["filterSelf","selectRange"],this.DOWNSAMPLE_METHODS=["downSample","minmaxDownSample","lttbDownSample"];var i=!1;qm(t)?(n=t.dimensions,this._dimOmitted=t.isDimensionOmitted(),this._schema=t):(i=!0,n=t),n=n||["x","y"];for(var r={},o=[],a={},s=!1,l={},u=0;u=e)){var n=this._store.getProvider();this._updateOrdinalMeta();var i=this._nameList,r=this._idList;if(n.getSource().sourceFormat===Wp&&!n.pure)for(var o=[],a=t;a0},t.prototype.ensureUniqueItemVisual=function(t,e){var n=this._itemVisuals,i=n[t];i||(i=n[t]={});var r=i[e];return null==r&&(Y(r=this.getVisual(e))?r=r.slice():ax(r)&&(r=A({},r)),i[e]=r),r},t.prototype.setItemVisual=function(t,e,n){var i=this._itemVisuals[t]||{};this._itemVisuals[t]=i,ax(e)?A(i,e):i[e]=n},t.prototype.clearAllVisual=function(){this._visual={},this._itemVisuals=[]},t.prototype.setLayout=function(t,e){ax(t)?A(this._layout,t):this._layout[t]=e},t.prototype.getLayout=function(t){return this._layout[t]},t.prototype.getItemLayout=function(t){return this._itemLayouts[t]},t.prototype.setItemLayout=function(t,e,n){this._itemLayouts[t]=n?A(this._itemLayouts[t]||{},e):e},t.prototype.clearItemLayouts=function(){this._itemLayouts.length=0},t.prototype.setItemGraphicEl=function(t,e){var n=this.hostModel&&this.hostModel.seriesIndex;ol(n,this.dataType,t,e),this._graphicEls[t]=e},t.prototype.getItemGraphicEl=function(t){return this._graphicEls[t]},t.prototype.eachItemGraphicEl=function(t,e){E(this._graphicEls,(function(n,i){n&&t&&t.call(e,n,i)}))},t.prototype.cloneShallow=function(e){return e||(e=new t(this._schema?this._schema:sx(this.dimensions,this._getDimInfo,this),this.hostModel)),ix(e,this),e._store=this._store,e},t.prototype.wrapMethod=function(t,e){var n=this[t];X(n)&&(this.__wrappedMethods=this.__wrappedMethods||[],this.__wrappedMethods.push(t),this[t]=function(){var t=n.apply(this,arguments);return e.apply(this,[t].concat(at(arguments)))})},t.internalField=(Qm=function(t){var e=t._invertedIndicesMap;E(e,(function(n,i){var r=t._dimInfos[i],o=r.ordinalMeta,a=t._store;if(o){n=e[i]=new lx(o.categories.length);for(var s=0;s1&&(s+="__ec__"+u),i[e]=s}})),t}();function px(t,e){Qd(t)||(t=ef(t));var n=(e=e||{}).coordDimensions||[],i=e.dimensionsDefine||t.dimensionsDefine||[],r=yt(),o=[],a=function(t,e,n,i){var r=Math.max(t.dimensionsDetectedCount||1,e.length,n.length,i||0);return E(e,(function(t){var e;q(t)&&(e=t.dimsDef)&&(r=Math.max(r,e.length))})),r}(t,n,i,e.dimensionsCount),s=e.canOmitUnusedDimensions&&Jm(a),l=i===t.dimensionsDefine,u=l?$m(t):Km(i),h=e.encodeDefine;!h&&e.encodeDefaulter&&(h=e.encodeDefaulter(t,a));for(var c=yt(h),p=new Xf(a),d=0;d0&&(i.name=r+(o-1)),o++,e.set(r,o)}}(o),new jm({source:t,dimensions:o,fullDimensionCount:a,dimensionOmitted:s})}function dx(t,e,n){if(n||e.hasKey(t)){for(var i=0;e.hasKey(t+i);)i++;t+=i}return e.set(t,!0),t}var fx=function(t){this.coordSysDims=[],this.axisMap=yt(),this.categoryAxisMap=yt(),this.coordSysName=t};var gx={cartesian2d:function(t,e,n,i){var r=t.getReferringComponents("xAxis",Wo).models[0],o=t.getReferringComponents("yAxis",Wo).models[0];e.coordSysDims=["x","y"],n.set("x",r),n.set("y",o),yx(r)&&(i.set("x",r),e.firstCategoryDimIndex=0),yx(o)&&(i.set("y",o),null==e.firstCategoryDimIndex&&(e.firstCategoryDimIndex=1))},singleAxis:function(t,e,n,i){var r=t.getReferringComponents("singleAxis",Wo).models[0];e.coordSysDims=["single"],n.set("single",r),yx(r)&&(i.set("single",r),e.firstCategoryDimIndex=0)},polar:function(t,e,n,i){var r=t.getReferringComponents("polar",Wo).models[0],o=r.findAxisModel("radiusAxis"),a=r.findAxisModel("angleAxis");e.coordSysDims=["radius","angle"],n.set("radius",o),n.set("angle",a),yx(o)&&(i.set("radius",o),e.firstCategoryDimIndex=0),yx(a)&&(i.set("angle",a),null==e.firstCategoryDimIndex&&(e.firstCategoryDimIndex=1))},geo:function(t,e,n,i){e.coordSysDims=["lng","lat"]},parallel:function(t,e,n,i){var r=t.ecModel,o=r.getComponent("parallel",t.get("parallelIndex")),a=e.coordSysDims=o.dimensions.slice();E(o.parallelAxisIndex,(function(t,o){var s=r.getComponent("parallelAxis",t),l=a[o];n.set(l,s),yx(s)&&(i.set(l,s),null==e.firstCategoryDimIndex&&(e.firstCategoryDimIndex=o))}))}};function yx(t){return"category"===t.get("type")}function vx(t,e,n){var i,r,o,a=(n=n||{}).byIndex,s=n.stackedCoordDimension;!function(t){return!qm(t.schema)}(e)?(r=e.schema,i=r.dimensions,o=e.store):i=e;var l,u,h,c,p=!(!t||!t.get("stack"));if(E(i,(function(t,e){U(t)&&(i[e]=t={name:t}),p&&!t.isExtraCoord&&(a||l||!t.ordinalMeta||(l=t),u||"ordinal"===t.type||"time"===t.type||s&&s!==t.coordDim||(u=t))})),!u||a||l||(a=!0),u){h="__\0ecstackresult_"+t.id,c="__\0ecstackedover_"+t.id,l&&(l.createInvertedIndices=!0);var d=u.coordDim,f=u.type,g=0;E(i,(function(t){t.coordDim===d&&g++}));var y={name:h,coordDim:d,coordDimIndex:g,type:f,isExtraCoord:!0,isCalculationCoord:!0,storeDimIndex:i.length},v={name:c,coordDim:c,coordDimIndex:g+1,type:f,isExtraCoord:!0,isCalculationCoord:!0,storeDimIndex:i.length+1};r?(o&&(y.storeDimIndex=o.ensureCalculationDimension(c,f),v.storeDimIndex=o.ensureCalculationDimension(h,f)),r.appendCalculationDimension(y),r.appendCalculationDimension(v)):(i.push(y),i.push(v))}return{stackedDimension:u&&u.name,stackedByDimension:l&&l.name,isStackedByIndex:a,stackedOverDimension:c,stackResultDimension:h}}function mx(t,e){return!!e&&e===t.getCalculationInfo("stackedDimension")}function xx(t,e){return mx(t,e)?t.getCalculationInfo("stackResultDimension"):e}function _x(t,e,n){n=n||{};var i,r=e.getSourceManager(),o=!1;t?(o=!0,i=ef(t)):o=(i=r.getSource()).sourceFormat===Wp;var a=function(t){var e=t.get("coordinateSystem"),n=new fx(e),i=gx[e];if(i)return i(t,n,n.axisMap,n.categoryAxisMap),n}(e),s=function(t,e){var n,i=t.get("coordinateSystem"),r=wd.get(i);return e&&e.coordSysDims&&(n=z(e.coordSysDims,(function(t){var n={name:t},i=e.axisMap.get(t);if(i){var r=i.get("type");n.type=Ym(r)}return n}))),n||(n=r&&(r.getDimensionsInfo?r.getDimensionsInfo():r.dimensions.slice())||["x","y"]),n}(e,a),l=n.useEncodeDefaulter,u=X(l)?l:l?H(td,s,e):null,h=px(i,{coordDimensions:s,generateCoord:n.generateCoord,encodeDefine:e.getEncode(),encodeDefaulter:u,canOmitUnusedDimensions:!o}),c=function(t,e,n){var i,r;return n&&E(t,(function(t,o){var a=t.coordDim,s=n.categoryAxisMap.get(a);s&&(null==i&&(i=o),t.ordinalMeta=s.getOrdinalMeta(),e&&(t.createInvertedIndices=!0)),null!=t.otherDims.itemName&&(r=!0)})),r||null==i||(t[i].otherDims.itemName=0),i}(h.dimensions,n.createInvertedIndices,a),p=o?null:r.getSharedDataStore(h),d=vx(e,{schema:h,store:p}),f=new cx(h,e);f.setCalculationInfo(d);var g=null!=c&&function(t){if(t.sourceFormat===Wp){var e=function(t){var e=0;for(;ee[1]&&(e[1]=t[1])},t.prototype.unionExtentFromData=function(t,e){this.unionExtent(t.getApproximateExtent(e))},t.prototype.getExtent=function(){return this._extent.slice()},t.prototype.setExtent=function(t,e){var n=this._extent;isNaN(t)||(n[0]=t),isNaN(e)||(n[1]=e)},t.prototype.isInExtentRange=function(t){return this._extent[0]<=t&&this._extent[1]>=t},t.prototype.isBlank=function(){return this._isBlank},t.prototype.setBlank=function(t){this._isBlank=t},t}();na(bx);var Sx=0,Mx=function(){function t(t){this.categories=t.categories||[],this._needCollect=t.needCollect,this._deduplication=t.deduplication,this.uid=++Sx}return t.createByAxisModel=function(e){var n=e.option,i=n.data,r=i&&z(i,Ix);return new t({categories:r,needCollect:!r,deduplication:!1!==n.dedplication})},t.prototype.getOrdinal=function(t){return this._getOrCreateMap().get(t)},t.prototype.parseAndCollect=function(t){var e,n=this._needCollect;if(!U(t)&&!n)return t;if(n&&!this._deduplication)return e=this.categories.length,this.categories[e]=t,e;var i=this._getOrCreateMap();return null==(e=i.get(t))&&(n?(e=this.categories.length,this.categories[e]=t,i.set(t,e)):e=NaN),e},t.prototype._getOrCreateMap=function(){return this._map||(this._map=yt(this.categories))},t}();function Ix(t){return q(t)&&null!=t.value?t.value:t+""}function Tx(t){return"interval"===t.type||"log"===t.type}function Cx(t,e,n,i){var r={},o=t[1]-t[0],a=r.interval=po(o/e,!0);null!=n&&ai&&(a=r.interval=i);var s=r.intervalPrecision=Ax(a);return function(t,e){!isFinite(t[0])&&(t[0]=e[0]),!isFinite(t[1])&&(t[1]=e[1]),kx(t,0,e),kx(t,1,e),t[0]>t[1]&&(t[0]=t[1])}(r.niceTickExtent=[Jr(Math.ceil(t[0]/a)*a,s),Jr(Math.floor(t[1]/a)*a,s)],t),r}function Dx(t){var e=Math.pow(10,co(t)),n=t/e;return n?2===n?n=3:3===n?n=5:n*=2:n=1,Jr(n*e)}function Ax(t){return to(t)+2}function kx(t,e,n){t[e]=Math.max(Math.min(t[e],n[1]),n[0])}function Lx(t,e){return t>=e[0]&&t<=e[1]}function Px(t,e){return e[1]===e[0]?.5:(t-e[0])/(e[1]-e[0])}function Ox(t,e){return t*(e[1]-e[0])+e[0]}var Rx=function(t){function e(e){var n=t.call(this,e)||this;n.type="ordinal";var i=n.getSetting("ordinalMeta");return i||(i=new Mx({})),Y(i)&&(i=new Mx({categories:z(i,(function(t){return q(t)?t.value:t}))})),n._ordinalMeta=i,n._extent=n.getSetting("extent")||[0,i.categories.length-1],n}return n(e,t),e.prototype.parse=function(t){return null==t?NaN:U(t)?this._ordinalMeta.getOrdinal(t):Math.round(t)},e.prototype.contain=function(t){return Lx(t=this.parse(t),this._extent)&&null!=this._ordinalMeta.categories[t]},e.prototype.normalize=function(t){return Px(t=this._getTickNumber(this.parse(t)),this._extent)},e.prototype.scale=function(t){return t=Math.round(Ox(t,this._extent)),this.getRawOrdinalNumber(t)},e.prototype.getTicks=function(){for(var t=[],e=this._extent,n=e[0];n<=e[1];)t.push({value:n}),n++;return t},e.prototype.getMinorTicks=function(t){},e.prototype.setSortInfo=function(t){if(null!=t){for(var e=t.ordinalNumbers,n=this._ordinalNumbersByTick=[],i=this._ticksByOrdinalNumber=[],r=0,o=this._ordinalMeta.categories.length,a=Math.min(o,e.length);r=0&&t=0&&t=t},e.prototype.getOrdinalMeta=function(){return this._ordinalMeta},e.prototype.calcNiceTicks=function(){},e.prototype.calcNiceExtent=function(){},e.type="ordinal",e}(bx);bx.registerClass(Rx);var Nx=Jr,Ex=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.type="interval",e._interval=0,e._intervalPrecision=2,e}return n(e,t),e.prototype.parse=function(t){return t},e.prototype.contain=function(t){return Lx(t,this._extent)},e.prototype.normalize=function(t){return Px(t,this._extent)},e.prototype.scale=function(t){return Ox(t,this._extent)},e.prototype.setExtent=function(t,e){var n=this._extent;isNaN(t)||(n[0]=parseFloat(t)),isNaN(e)||(n[1]=parseFloat(e))},e.prototype.unionExtent=function(t){var e=this._extent;t[0]e[1]&&(e[1]=t[1]),this.setExtent(e[0],e[1])},e.prototype.getInterval=function(){return this._interval},e.prototype.setInterval=function(t){this._interval=t,this._niceExtent=this._extent.slice(),this._intervalPrecision=Ax(t)},e.prototype.getTicks=function(t){var e=this._interval,n=this._extent,i=this._niceExtent,r=this._intervalPrecision,o=[];if(!e)return o;n[0]1e4)return[];var s=o.length?o[o.length-1].value:i[1];return n[1]>s&&(t?o.push({value:Nx(s+e,r)}):o.push({value:n[1]})),o},e.prototype.getMinorTicks=function(t){for(var e=this.getTicks(!0),n=[],i=this.getExtent(),r=1;ri[0]&&h0&&(o=null===o?s:Math.min(o,s))}n[i]=o}}return n}(t),n=[];return E(t,(function(t){var i,r=t.coordinateSystem.getBaseAxis(),o=r.getExtent();if("category"===r.type)i=r.getBandWidth();else if("value"===r.type||"time"===r.type){var a=r.dim+"_"+r.index,s=e[a],l=Math.abs(o[1]-o[0]),u=r.scale.getExtent(),h=Math.abs(u[1]-u[0]);i=s?l/h*s:l}else{var c=t.getData();i=Math.abs(o[1]-o[0])/c.count()}var p=$r(t.get("barWidth"),i),d=$r(t.get("barMaxWidth"),i),f=$r(t.get("barMinWidth")||(qx(t)?.5:1),i),g=t.get("barGap"),y=t.get("barCategoryGap");n.push({bandWidth:i,barWidth:p,barMaxWidth:d,barMinWidth:f,barGap:g,barCategoryGap:y,axisKey:Wx(r),stackId:Gx(t)})})),Xx(n)}function Xx(t){var e={};E(t,(function(t,n){var i=t.axisKey,r=t.bandWidth,o=e[i]||{bandWidth:r,remainedWidth:r,autoWidthCount:0,categoryGap:null,gap:"20%",stacks:{}},a=o.stacks;e[i]=o;var s=t.stackId;a[s]||o.autoWidthCount++,a[s]=a[s]||{width:0,maxWidth:0};var l=t.barWidth;l&&!a[s].width&&(a[s].width=l,l=Math.min(o.remainedWidth,l),o.remainedWidth-=l);var u=t.barMaxWidth;u&&(a[s].maxWidth=u);var h=t.barMinWidth;h&&(a[s].minWidth=h);var c=t.barGap;null!=c&&(o.gap=c);var p=t.barCategoryGap;null!=p&&(o.categoryGap=p)}));var n={};return E(e,(function(t,e){n[e]={};var i=t.stacks,r=t.bandWidth,o=t.categoryGap;if(null==o){var a=G(i).length;o=Math.max(35-4*a,15)+"%"}var s=$r(o,r),l=$r(t.gap,1),u=t.remainedWidth,h=t.autoWidthCount,c=(u-s)/(h+(h-1)*l);c=Math.max(c,0),E(i,(function(t){var e=t.maxWidth,n=t.minWidth;if(t.width){i=t.width;e&&(i=Math.min(i,e)),n&&(i=Math.max(i,n)),t.width=i,u-=i+l*i,h--}else{var i=c;e&&ei&&(i=n),i!==c&&(t.width=i,u-=i+l*i,h--)}})),c=(u-s)/(h+(h-1)*l),c=Math.max(c,0);var p,d=0;E(i,(function(t,e){t.width||(t.width=c),p=t,d+=t.width*(1+l)})),p&&(d-=p.width*l);var f=-d/2;E(i,(function(t,i){n[e][i]=n[e][i]||{bandWidth:r,offset:f,width:t.width},f+=t.width*(1+l)}))})),n}function Ux(t,e){var n=Hx(t,e),i=Yx(n);E(n,(function(t){var e=t.getData(),n=t.coordinateSystem.getBaseAxis(),r=Gx(t),o=i[Wx(n)][r],a=o.offset,s=o.width;e.setLayout({bandWidth:o.bandWidth,offset:a,size:s})}))}function Zx(t){return{seriesType:t,plan:kg(),reset:function(t){if(jx(t)){var e=t.getData(),n=t.coordinateSystem,i=n.getBaseAxis(),r=n.getOtherAxis(i),o=e.getDimensionIndex(e.mapDimension(r.dim)),a=e.getDimensionIndex(e.mapDimension(i.dim)),s=t.get("showBackground",!0),l=e.mapDimension(r.dim),u=e.getCalculationInfo("stackResultDimension"),h=mx(e,l)&&!!e.getCalculationInfo("stackedOnSeries"),c=r.isHorizontal(),p=function(t,e){var n=e.model.get("startValue");n||(n=0);return e.toGlobalCoord(e.dataToCoord("log"===e.type?n>0?n:1:n))}(0,r),d=qx(t),f=t.get("barMinHeight")||0,g=u&&e.getDimensionIndex(u),y=e.getLayout("size"),v=e.getLayout("offset");return{progress:function(t,e){for(var i,r=t.count,l=d&&Bx(3*r),u=d&&s&&Bx(3*r),m=d&&Bx(r),x=n.master.getRect(),_=c?x.width:x.height,b=e.getStore(),w=0;null!=(i=t.next());){var S=b.get(h?g:o,i),M=b.get(a,i),I=p,T=void 0;h&&(T=+S-b.get(o,i));var C=void 0,D=void 0,A=void 0,k=void 0;if(c){var L=n.dataToPoint([S,M]);if(h)I=n.dataToPoint([T,M])[0];C=I,D=L[1]+v,A=L[0]-I,k=y,Math.abs(A)0)for(var s=0;s=0;--s)if(l[u]){o=l[u];break}o=o||a.none}if(Y(o)){var h=null==t.level?0:t.level>=0?t.level:o.length+t.level;o=o[h=Math.min(h,o.length-1)]}}return Jc(new Date(t.value),o,r,i)}(t,e,n,this.getSetting("locale"),i)},e.prototype.getTicks=function(){var t=this._interval,e=this._extent,n=[];if(!t)return n;n.push({value:e[0],level:0});var i=this.getSetting("useUTC"),r=function(t,e,n,i){var r=1e4,o=jc,a=0;function s(t,e,n,r,o,a,s){for(var l=new Date(e),u=e,h=l[r]();u1&&0===u&&o.unshift({value:o[0].value-p})}}for(u=0;u=i[0]&&v<=i[1]&&c++)}var m=(i[1]-i[0])/e;if(c>1.5*m&&p>m/1.5)break;if(u.push(g),c>m||t===o[d])break}h=[]}}0;var x=B(z(u,(function(t){return B(t,(function(t){return t.value>=i[0]&&t.value<=i[1]&&!t.notAdd}))})),(function(t){return t.length>0})),_=[],b=x.length-1;for(d=0;dn&&(this._approxInterval=n);var o=$x.length,a=Math.min(function(t,e,n,i){for(;n>>1;t[r][1]16?16:t>7.5?7:t>3.5?4:t>1.5?2:1}function Qx(t){return(t/=2592e6)>6?6:t>3?3:t>2?2:1}function t_(t){return(t/=Gc)>12?12:t>6?6:t>3.5?4:t>2?2:1}function e_(t,e){return(t/=e?Fc:Bc)>30?30:t>20?20:t>15?15:t>10?10:t>5?5:t>2?2:1}function n_(t){return po(t,!0)}function i_(t,e,n){var i=new Date(t);switch(Kc(e)){case"year":case"month":i[up(n)](0);case"day":i[hp(n)](1);case"hour":i[cp(n)](0);case"minute":i[pp(n)](0);case"second":i[dp(n)](0),i[fp(n)](0)}return i.getTime()}bx.registerClass(Kx);var r_=bx.prototype,o_=Ex.prototype,a_=Jr,s_=Math.floor,l_=Math.ceil,u_=Math.pow,h_=Math.log,c_=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.type="log",e.base=10,e._originalScale=new Ex,e._interval=0,e}return n(e,t),e.prototype.getTicks=function(t){var e=this._originalScale,n=this._extent,i=e.getExtent();return z(o_.getTicks.call(this,t),(function(t){var e=t.value,r=Jr(u_(this.base,e));return r=e===n[0]&&this._fixMin?d_(r,i[0]):r,{value:r=e===n[1]&&this._fixMax?d_(r,i[1]):r}}),this)},e.prototype.setExtent=function(t,e){var n=h_(this.base);t=h_(Math.max(0,t))/n,e=h_(Math.max(0,e))/n,o_.setExtent.call(this,t,e)},e.prototype.getExtent=function(){var t=this.base,e=r_.getExtent.call(this);e[0]=u_(t,e[0]),e[1]=u_(t,e[1]);var n=this._originalScale.getExtent();return this._fixMin&&(e[0]=d_(e[0],n[0])),this._fixMax&&(e[1]=d_(e[1],n[1])),e},e.prototype.unionExtent=function(t){this._originalScale.unionExtent(t);var e=this.base;t[0]=h_(t[0])/h_(e),t[1]=h_(t[1])/h_(e),r_.unionExtent.call(this,t)},e.prototype.unionExtentFromData=function(t,e){this.unionExtent(t.getApproximateExtent(e))},e.prototype.calcNiceTicks=function(t){t=t||10;var e=this._extent,n=e[1]-e[0];if(!(n===1/0||n<=0)){var i=ho(n);for(t/n*i<=.5&&(i*=10);!isNaN(i)&&Math.abs(i)<1&&Math.abs(i)>0;)i*=10;var r=[Jr(l_(e[0]/i)*i),Jr(s_(e[1]/i)*i)];this._interval=i,this._niceExtent=r}},e.prototype.calcNiceExtent=function(t){o_.calcNiceExtent.call(this,t),this._fixMin=t.fixMin,this._fixMax=t.fixMax},e.prototype.parse=function(t){return t},e.prototype.contain=function(t){return Lx(t=h_(t)/h_(this.base),this._extent)},e.prototype.normalize=function(t){return Px(t=h_(t)/h_(this.base),this._extent)},e.prototype.scale=function(t){return t=Ox(t,this._extent),u_(this.base,t)},e.type="log",e}(bx),p_=c_.prototype;function d_(t,e){return a_(t,to(e))}p_.getMinorTicks=o_.getMinorTicks,p_.getLabel=o_.getLabel,bx.registerClass(c_);var f_=function(){function t(t,e,n){this._prepareParams(t,e,n)}return t.prototype._prepareParams=function(t,e,n){n[1]0&&s>0&&!l&&(a=0),a<0&&s<0&&!u&&(s=0));var c=this._determinedMin,p=this._determinedMax;return null!=c&&(a=c,l=!0),null!=p&&(s=p,u=!0),{min:a,max:s,minFixed:l,maxFixed:u,isBlank:h}},t.prototype.modifyDataMinMax=function(t,e){this[y_[t]]=e},t.prototype.setDeterminedMinMax=function(t,e){var n=g_[t];this[n]=e},t.prototype.freeze=function(){this.frozen=!0},t}(),g_={min:"_determinedMin",max:"_determinedMax"},y_={min:"_dataMin",max:"_dataMax"};function v_(t,e,n){var i=t.rawExtentInfo;return i||(i=new f_(t,e,n),t.rawExtentInfo=i,i)}function m_(t,e){return null==e?null:nt(e)?NaN:t.parse(e)}function x_(t,e){var n=t.type,i=v_(t,e,t.getExtent()).calculate();t.setBlank(i.isBlank);var r=i.min,o=i.max,a=e.ecModel;if(a&&"time"===n){var s=Hx("bar",a),l=!1;if(E(s,(function(t){l=l||t.getBaseAxis()===e.axis})),l){var u=Yx(s),h=function(t,e,n,i){var r=n.axis.getExtent(),o=Math.abs(r[1]-r[0]),a=function(t,e,n){if(t&&e){var i=t[Wx(e)];return null!=i&&null!=n?i[Gx(n)]:i}}(i,n.axis);if(void 0===a)return{min:t,max:e};var s=1/0;E(a,(function(t){s=Math.min(t.offset,s)}));var l=-1/0;E(a,(function(t){l=Math.max(t.offset+t.width,l)})),s=Math.abs(s),l=Math.abs(l);var u=s+l,h=e-t,c=h/(1-(s+l)/o)-h;return e+=c*(l/u),t-=c*(s/u),{min:t,max:e}}(r,o,e,u);r=h.min,o=h.max}}return{extent:[r,o],fixMin:i.minFixed,fixMax:i.maxFixed}}function __(t,e){var n=e,i=x_(t,n),r=i.extent,o=n.get("splitNumber");t instanceof c_&&(t.base=n.get("logBase"));var a=t.type,s=n.get("interval"),l="interval"===a||"time"===a;t.setExtent(r[0],r[1]),t.calcNiceExtent({splitNumber:o,fixMin:i.fixMin,fixMax:i.fixMax,minInterval:l?n.get("minInterval"):null,maxInterval:l?n.get("maxInterval"):null}),null!=s&&t.setInterval&&t.setInterval(s)}function b_(t,e){if(e=e||t.get("type"))switch(e){case"category":return new Rx({ordinalMeta:t.getOrdinalMeta?t.getOrdinalMeta():t.getCategories(),extent:[1/0,-1/0]});case"time":return new Kx({locale:t.ecModel.getLocaleModel(),useUTC:t.ecModel.get("useUTC")});default:return new(bx.getClass(e)||Ex)}}function w_(t){var e,n,i=t.getLabelModel().get("formatter"),r="category"===t.type?t.scale.getExtent()[0]:null;return"time"===t.scale.type?(n=i,function(e,i){return t.scale.getFormattedLabel(e,i,n)}):U(i)?function(e){return function(n){var i=t.scale.getLabel(n);return e.replace("{value}",null!=i?i:"")}}(i):X(i)?(e=i,function(n,i){return null!=r&&(i=n.value-r),e(S_(t,n),i,null!=n.level?{level:n.level}:null)}):function(e){return t.scale.getLabel(e)}}function S_(t,e){return"category"===t.type?t.scale.getLabel(e):e.value}function M_(t,e){var n=e*Math.PI/180,i=t.width,r=t.height,o=i*Math.abs(Math.cos(n))+Math.abs(r*Math.sin(n)),a=i*Math.abs(Math.sin(n))+Math.abs(r*Math.cos(n));return new ze(t.x,t.y,o,a)}function I_(t){var e=t.get("interval");return null==e?"auto":e}function T_(t){return"category"===t.type&&0===I_(t.getLabelModel())}function C_(t,e){var n={};return E(t.mapDimensionsAll(e),(function(e){n[xx(t,e)]=!0})),G(n)}var D_=function(){function t(){}return t.prototype.getNeedCrossZero=function(){return!this.option.scale},t.prototype.getCoordSysModel=function(){},t}();var A_={isDimensionStacked:mx,enableDataStack:vx,getStackedDimension:xx};var k_=Object.freeze({__proto__:null,createList:function(t){return _x(null,t)},getLayoutRect:kp,dataStack:A_,createScale:function(t,e){var n=e;e instanceof Cc||(n=new Cc(e));var i=b_(n);return i.setExtent(t[0],t[1]),__(i,n),i},mixinAxisModelCommonMethods:function(t){R(t,D_)},getECData:rl,createTextStyle:function(t,e){return oc(t,null,null,"normal"!==(e=e||{}).state)},createDimensions:function(t,e){return px(t,e).dimensions},createSymbol:Xy,enableHoverEmphasis:Ul});function L_(t,e){return Math.abs(t-e)<1e-8}function P_(t,e,n){var i=0,r=t[0];if(!r)return!1;for(var o=1;on&&(t=r,n=a)}if(t)return function(t){for(var e=0,n=0,i=0,r=t.length,o=t[r-1][0],a=t[r-1][1],s=0;s>1^-(1&s),l=l>>1^-(1&l),r=s+=r,o=l+=o,i.push([s/n,l/n])}return i}function H_(t,e){return z(B((t=function(t){if(!t.UTF8Encoding)return t;var e=t,n=e.UTF8Scale;return null==n&&(n=1024),E(e.features,(function(t){var e=t.geometry,i=e.encodeOffsets,r=e.coordinates;if(i)switch(e.type){case"LineString":e.coordinates=W_(r,i,n);break;case"Polygon":case"MultiLineString":G_(r,i,n);break;case"MultiPolygon":E(r,(function(t,e){return G_(t,i[e],n)}))}})),e.UTF8Encoding=!1,e}(t)).features,(function(t){return t.geometry&&t.properties&&t.geometry.coordinates.length>0})),(function(t){var n=t.properties,i=t.geometry,r=[];switch(i.type){case"Polygon":var o=i.coordinates;r.push(new z_(o[0],o.slice(1)));break;case"MultiPolygon":E(i.coordinates,(function(t){t[0]&&r.push(new z_(t[0],t.slice(1)))}));break;case"LineString":r.push(new V_([i.coordinates]));break;case"MultiLineString":r.push(new V_(i.coordinates))}var a=new B_(n[e||"name"],r,n.cp);return a.properties=n,a}))}var Y_=Object.freeze({__proto__:null,linearMap:Kr,round:Jr,asc:Qr,getPrecision:to,getPrecisionSafe:eo,getPixelPrecision:no,getPercentWithPrecision:function(t,e,n){return t[e]&&io(t,n)[e]||0},MAX_SAFE_INTEGER:oo,remRadian:ao,isRadianAroundZero:so,parseDate:uo,quantity:ho,quantityExponent:co,nice:po,quantile:fo,reformIntervals:go,isNumeric:vo,numericToNumber:yo}),X_=Object.freeze({__proto__:null,parse:uo,format:Jc}),U_=Object.freeze({__proto__:null,extendShape:Ch,extendPath:Ah,makePath:Ph,makeImage:Oh,mergePath:Nh,resizePath:Eh,createIcon:Uh,updateProps:vh,initProps:mh,getTransform:Bh,clipPointsByRect:Yh,clipRectByRect:Xh,registerShape:kh,getShapeClass:Lh,Group:Br,Image:Ns,Text:Xs,Circle:Su,Ellipse:Iu,Sector:Fu,Ring:Wu,Polygon:Xu,Polyline:Zu,Rect:Ws,Line:Ku,BezierCurve:th,Arc:nh,IncrementalDisplayable:dh,CompoundPath:ih,LinearGradient:oh,RadialGradient:ah,BoundingRect:ze}),Z_=Object.freeze({__proto__:null,addCommas:gp,toCamelCase:yp,normalizeCssArray:vp,encodeHTML:re,formatTpl:bp,getTooltipMarker:wp,formatTime:function(t,e,n){"week"!==t&&"month"!==t&&"quarter"!==t&&"half-year"!==t&&"year"!==t||(t="MM-dd\nyyyy");var i=uo(e),r=n?"getUTC":"get",o=i[r+"FullYear"](),a=i[r+"Month"]()+1,s=i[r+"Date"](),l=i[r+"Hours"](),u=i[r+"Minutes"](),h=i[r+"Seconds"](),c=i[r+"Milliseconds"]();return t=t.replace("MM",qc(a,2)).replace("M",a).replace("yyyy",o).replace("yy",qc(o%100+"",2)).replace("dd",qc(s,2)).replace("d",s).replace("hh",qc(l,2)).replace("h",l).replace("mm",qc(u,2)).replace("m",u).replace("ss",qc(h,2)).replace("s",h).replace("SSS",qc(c,3))},capitalFirst:function(t){return t?t.charAt(0).toUpperCase()+t.substr(1):t},truncateText:function(t,e,n,i,r){var o={};return pa(o,t,e,n,i,r),o.text},getTextRect:function(t,e,n,i,r,o,a,s){return new Xs({style:{text:t,font:e,align:n,verticalAlign:i,padding:r,rich:o,overflow:a?"truncate":null,lineHeight:s}}).getBoundingRect()}}),j_=Object.freeze({__proto__:null,map:z,each:E,indexOf:P,inherits:O,reduce:V,filter:B,bind:W,curry:H,isArray:Y,isString:U,isObject:q,isFunction:X,extend:A,defaults:k,clone:T,merge:C}),q_=Vo();function K_(t,e){var n=z(e,(function(e){return t.scale.parse(e)}));return"time"===t.type&&n.length>0&&(n.sort(),n.unshift(n[0]),n.push(n[n.length-1])),n}function $_(t){var e=t.getLabelModel().get("customValues");if(e){var n=w_(t),i=t.scale.getExtent();return{labels:z(B(K_(t,e),(function(t){return t>=i[0]&&t<=i[1]})),(function(e){var i={value:e};return{formattedLabel:n(i),rawLabel:t.scale.getLabel(i),tickValue:e}}))}}return"category"===t.type?function(t){var e=t.getLabelModel(),n=Q_(t,e);return!e.get("show")||t.scale.isBlank()?{labels:[],labelCategoryInterval:n.labelCategoryInterval}:n}(t):function(t){var e=t.scale.getTicks(),n=w_(t);return{labels:z(e,(function(e,i){return{level:e.level,formattedLabel:n(e,i),rawLabel:t.scale.getLabel(e),tickValue:e.value}}))}}(t)}function J_(t,e){var n=t.getTickModel().get("customValues");if(n){var i=t.scale.getExtent();return{ticks:B(K_(t,n),(function(t){return t>=i[0]&&t<=i[1]}))}}return"category"===t.type?function(t,e){var n,i,r=tb(t,"ticks"),o=I_(e),a=eb(r,o);if(a)return a;e.get("show")&&!t.scale.isBlank()||(n=[]);if(X(o))n=rb(t,o,!0);else if("auto"===o){var s=Q_(t,t.getLabelModel());i=s.labelCategoryInterval,n=z(s.labels,(function(t){return t.tickValue}))}else n=ib(t,i=o,!0);return nb(r,o,{ticks:n,tickCategoryInterval:i})}(t,e):{ticks:z(t.scale.getTicks(),(function(t){return t.value}))}}function Q_(t,e){var n,i,r=tb(t,"labels"),o=I_(e),a=eb(r,o);return a||(X(o)?n=rb(t,o):(i="auto"===o?function(t){var e=q_(t).autoInterval;return null!=e?e:q_(t).autoInterval=t.calculateCategoryInterval()}(t):o,n=ib(t,i)),nb(r,o,{labels:n,labelCategoryInterval:i}))}function tb(t,e){return q_(t)[e]||(q_(t)[e]=[])}function eb(t,e){for(var n=0;n1&&h/l>2&&(u=Math.round(Math.ceil(u/l)*l));var c=T_(t),p=a.get("showMinLabel")||c,d=a.get("showMaxLabel")||c;p&&u!==o[0]&&g(o[0]);for(var f=u;f<=o[1];f+=l)g(f);function g(t){var e={value:t};s.push(n?t:{formattedLabel:i(e),rawLabel:r.getLabel(e),tickValue:t})}return d&&f-l!==o[1]&&g(o[1]),s}function rb(t,e,n){var i=t.scale,r=w_(t),o=[];return E(i.getTicks(),(function(t){var a=i.getLabel(t),s=t.value;e(t.value,a)&&o.push(n?s:{formattedLabel:r(t),rawLabel:a,tickValue:s})})),o}var ob=[0,1],ab=function(){function t(t,e,n){this.onBand=!1,this.inverse=!1,this.dim=t,this.scale=e,this._extent=n||[0,0]}return t.prototype.contain=function(t){var e=this._extent,n=Math.min(e[0],e[1]),i=Math.max(e[0],e[1]);return t>=n&&t<=i},t.prototype.containData=function(t){return this.scale.contain(t)},t.prototype.getExtent=function(){return this._extent.slice()},t.prototype.getPixelPrecision=function(t){return no(t||this.scale.getExtent(),this._extent)},t.prototype.setExtent=function(t,e){var n=this._extent;n[0]=t,n[1]=e},t.prototype.dataToCoord=function(t,e){var n=this._extent,i=this.scale;return t=i.normalize(t),this.onBand&&"ordinal"===i.type&&sb(n=n.slice(),i.count()),Kr(t,ob,n,e)},t.prototype.coordToData=function(t,e){var n=this._extent,i=this.scale;this.onBand&&"ordinal"===i.type&&sb(n=n.slice(),i.count());var r=Kr(t,n,ob,e);return this.scale.scale(r)},t.prototype.pointToData=function(t,e){},t.prototype.getTicksCoords=function(t){var e=(t=t||{}).tickModel||this.getTickModel(),n=z(J_(this,e).ticks,(function(t){return{coord:this.dataToCoord("ordinal"===this.scale.type?this.scale.getRawOrdinalNumber(t):t),tickValue:t}}),this);return function(t,e,n,i){var r=e.length;if(!t.onBand||n||!r)return;var o,a,s=t.getExtent();if(1===r)e[0].coord=s[0],o=e[1]={coord:s[1],tickValue:e[0].tickValue};else{var l=e[r-1].tickValue-e[0].tickValue,u=(e[r-1].coord-e[0].coord)/l;E(e,(function(t){t.coord-=u/2}));var h=t.scale.getExtent();a=1+h[1]-e[r-1].tickValue,o={coord:e[r-1].coord+u*a,tickValue:h[1]+1},e.push(o)}var c=s[0]>s[1];p(e[0].coord,s[0])&&(i?e[0].coord=s[0]:e.shift());i&&p(s[0],e[0].coord)&&e.unshift({coord:s[0]});p(s[1],o.coord)&&(i?o.coord=s[1]:e.pop());i&&p(o.coord,s[1])&&e.push({coord:s[1]});function p(t,e){return t=Jr(t),e=Jr(e),c?t>e:t0&&t<100||(t=5),z(this.scale.getMinorTicks(t),(function(t){return z(t,(function(t){return{coord:this.dataToCoord(t),tickValue:t}}),this)}),this)},t.prototype.getViewLabels=function(){return $_(this).labels},t.prototype.getLabelModel=function(){return this.model.getModel("axisLabel")},t.prototype.getTickModel=function(){return this.model.getModel("axisTick")},t.prototype.getBandWidth=function(){var t=this._extent,e=this.scale.getExtent(),n=e[1]-e[0]+(this.onBand?1:0);0===n&&(n=1);var i=Math.abs(t[1]-t[0]);return Math.abs(i)/n},t.prototype.calculateCategoryInterval=function(){return function(t){var e=function(t){var e=t.getLabelModel();return{axisRotate:t.getRotate?t.getRotate():t.isHorizontal&&!t.isHorizontal()?90:0,labelRotate:e.get("rotate")||0,font:e.getFont()}}(t),n=w_(t),i=(e.axisRotate-e.labelRotate)/180*Math.PI,r=t.scale,o=r.getExtent(),a=r.count();if(o[1]-o[0]<1)return 0;var s=1;a>40&&(s=Math.max(1,Math.floor(a/40)));for(var l=o[0],u=t.dataToCoord(l+1)-t.dataToCoord(l),h=Math.abs(u*Math.cos(i)),c=Math.abs(u*Math.sin(i)),p=0,d=0;l<=o[1];l+=s){var f,g,y=Sr(n({value:l}),e.font,"center","top");f=1.3*y.width,g=1.3*y.height,p=Math.max(p,f,7),d=Math.max(d,g,7)}var v=p/h,m=d/c;isNaN(v)&&(v=1/0),isNaN(m)&&(m=1/0);var x=Math.max(0,Math.floor(Math.min(v,m))),_=q_(t.model),b=t.getExtent(),w=_.lastAutoInterval,S=_.lastTickCount;return null!=w&&null!=S&&Math.abs(w-x)<=1&&Math.abs(S-a)<=1&&w>x&&_.axisExtent0===b[0]&&_.axisExtent1===b[1]?x=w:(_.lastTickCount=a,_.lastAutoInterval=x,_.axisExtent0=b[0],_.axisExtent1=b[1]),x}(this)},t}();function sb(t,e){var n=(t[1]-t[0])/e/2;t[0]+=n,t[1]-=n}var lb=2*Math.PI,ub=hs.CMD,hb=["top","right","bottom","left"];function cb(t,e,n,i,r){var o=n.width,a=n.height;switch(t){case"top":i.set(n.x+o/2,n.y-e),r.set(0,-1);break;case"bottom":i.set(n.x+o/2,n.y+a+e),r.set(0,1);break;case"left":i.set(n.x-e,n.y+a/2),r.set(-1,0);break;case"right":i.set(n.x+o+e,n.y+a/2),r.set(1,0)}}function pb(t,e,n,i,r,o,a,s,l){a-=t,s-=e;var u=Math.sqrt(a*a+s*s),h=(a/=u)*n+t,c=(s/=u)*n+e;if(Math.abs(i-r)%lb<1e-4)return l[0]=h,l[1]=c,u-n;if(o){var p=i;i=gs(r),r=gs(p)}else i=gs(i),r=gs(r);i>r&&(r+=lb);var d=Math.atan2(s,a);if(d<0&&(d+=lb),d>=i&&d<=r||d+lb>=i&&d+lb<=r)return l[0]=h,l[1]=c,u-n;var f=n*Math.cos(i)+t,g=n*Math.sin(i)+e,y=n*Math.cos(r)+t,v=n*Math.sin(r)+e,m=(f-a)*(f-a)+(g-s)*(g-s),x=(y-a)*(y-a)+(v-s)*(v-s);return m0){e=e/180*Math.PI,mb.fromArray(t[0]),xb.fromArray(t[1]),_b.fromArray(t[2]),De.sub(bb,mb,xb),De.sub(wb,_b,xb);var n=bb.len(),i=wb.len();if(!(n<.001||i<.001)){bb.scale(1/n),wb.scale(1/i);var r=bb.dot(wb);if(Math.cos(e)1&&De.copy(Ib,_b),Ib.toArray(t[1])}}}}function Cb(t,e,n){if(n<=180&&n>0){n=n/180*Math.PI,mb.fromArray(t[0]),xb.fromArray(t[1]),_b.fromArray(t[2]),De.sub(bb,xb,mb),De.sub(wb,_b,xb);var i=bb.len(),r=wb.len();if(!(i<.001||r<.001))if(bb.scale(1/i),wb.scale(1/r),bb.dot(e)=a)De.copy(Ib,_b);else{Ib.scaleAndAdd(wb,o/Math.tan(Math.PI/2-s));var l=_b.x!==xb.x?(Ib.x-xb.x)/(_b.x-xb.x):(Ib.y-xb.y)/(_b.y-xb.y);if(isNaN(l))return;l<0?De.copy(Ib,xb):l>1&&De.copy(Ib,_b)}Ib.toArray(t[1])}}}function Db(t,e,n,i){var r="normal"===n,o=r?t:t.ensureState(n);o.ignore=e;var a=i.get("smooth");a&&!0===a&&(a=.3),o.shape=o.shape||{},a>0&&(o.shape.smooth=a);var s=i.getModel("lineStyle").getLineStyle();r?t.useStyle(s):o.style=s}function Ab(t,e){var n=e.smooth,i=e.points;if(i)if(t.moveTo(i[0][0],i[0][1]),n>0&&i.length>=3){var r=Vt(i[0],i[1]),o=Vt(i[1],i[2]);if(!r||!o)return t.lineTo(i[1][0],i[1][1]),void t.lineTo(i[2][0],i[2][1]);var a=Math.min(r,o)*n,s=Gt([],i[1],i[0],a/r),l=Gt([],i[1],i[2],a/o),u=Gt([],s,l,.5);t.bezierCurveTo(s[0],s[1],s[0],s[1],u[0],u[1]),t.bezierCurveTo(l[0],l[1],l[0],l[1],i[2][0],i[2][1])}else for(var h=1;h0&&o&&_(-h/a,0,a);var f,g,y=t[0],v=t[a-1];return m(),f<0&&b(-f,.8),g<0&&b(g,.8),m(),x(f,g,1),x(g,f,-1),m(),f<0&&w(-f),g<0&&w(g),u}function m(){f=y.rect[e]-i,g=r-v.rect[e]-v.rect[n]}function x(t,e,n){if(t<0){var i=Math.min(e,-t);if(i>0){_(i*n,0,a);var r=i+t;r<0&&b(-r*n,1)}else b(-t*n,1)}}function _(n,i,r){0!==n&&(u=!0);for(var o=i;o0)for(l=0;l0;l--){_(-(o[l-1]*c),l,a)}}}function w(t){var e=t<0?-1:1;t=Math.abs(t);for(var n=Math.ceil(t/(a-1)),i=0;i0?_(n,0,i+1):_(-n,a-i-1,a),(t-=n)<=0)return}}function Rb(t,e,n,i){return Ob(t,"y","height",e,n,i)}function Nb(t){var e=[];t.sort((function(t,e){return e.priority-t.priority}));var n=new ze(0,0,0,0);function i(t){if(!t.ignore){var e=t.ensureState("emphasis");null==e.ignore&&(e.ignore=!1)}t.ignore=!0}for(var r=0;r=0&&n.attr(d.oldLayoutSelect),P(u,"emphasis")>=0&&n.attr(d.oldLayoutEmphasis)),vh(n,s,e,a)}else if(n.attr(s),!pc(n).valueAnimation){var h=rt(n.style.opacity,1);n.style.opacity=0,mh(n,{style:{opacity:h}},e,a)}if(d.oldLayout=s,n.states.select){var c=d.oldLayoutSelect={};Wb(c,s,Hb),Wb(c,n.states.select,Hb)}if(n.states.emphasis){var p=d.oldLayoutEmphasis={};Wb(p,s,Hb),Wb(p,n.states.emphasis,Hb)}fc(n,a,l,e,e)}if(i&&!i.ignore&&!i.invisible){r=(d=Gb(i)).oldLayout;var d,f={points:i.shape.points};r?(i.attr({shape:r}),vh(i,{shape:f},e)):(i.setShape(f),i.style.strokePercent=0,mh(i,{style:{strokePercent:1}},e)),d.oldLayout=f}},t}(),Xb=Vo();var Ub=Math.sin,Zb=Math.cos,jb=Math.PI,qb=2*Math.PI,Kb=180/jb,$b=function(){function t(){}return t.prototype.reset=function(t){this._start=!0,this._d=[],this._str="",this._p=Math.pow(10,t||4)},t.prototype.moveTo=function(t,e){this._add("M",t,e)},t.prototype.lineTo=function(t,e){this._add("L",t,e)},t.prototype.bezierCurveTo=function(t,e,n,i,r,o){this._add("C",t,e,n,i,r,o)},t.prototype.quadraticCurveTo=function(t,e,n,i){this._add("Q",t,e,n,i)},t.prototype.arc=function(t,e,n,i,r,o){this.ellipse(t,e,n,n,0,i,r,o)},t.prototype.ellipse=function(t,e,n,i,r,o,a,s){var l=a-o,u=!s,h=Math.abs(l),c=pi(h-qb)||(u?l>=qb:-l>=qb),p=l>0?l%qb:l%qb+qb,d=!1;d=!!c||!pi(h)&&p>=jb==!!u;var f=t+n*Zb(o),g=e+i*Ub(o);this._start&&this._add("M",f,g);var y=Math.round(r*Kb);if(c){var v=1/this._p,m=(u?1:-1)*(qb-v);this._add("A",n,i,y,1,+u,t+n*Zb(o+m),e+i*Ub(o+m)),v>.01&&this._add("A",n,i,y,0,+u,f,g)}else{var x=t+n*Zb(a),_=e+i*Ub(a);this._add("A",n,i,y,+d,+u,x,_)}},t.prototype.rect=function(t,e,n,i){this._add("M",t,e),this._add("l",n,0),this._add("l",0,i),this._add("l",-n,0),this._add("Z")},t.prototype.closePath=function(){this._d.length>0&&this._add("Z")},t.prototype._add=function(t,e,n,i,r,o,a,s,l){for(var u=[],h=this._p,c=1;c"}(r,o)+("style"!==r?re(a):a||"")+(i?""+n+z(i,(function(e){return t(e)})).join(n)+n:"")+("")}(t)}function uw(t){return{zrId:t,shadowCache:{},patternCache:{},gradientCache:{},clipPathCache:{},defs:{},cssNodes:{},cssAnims:{},cssStyleCache:{},cssAnimIdx:0,shadowIdx:0,gradientIdx:0,patternIdx:0,clipPathIdx:0}}function hw(t,e,n,i){return sw("svg","root",{width:t,height:e,xmlns:iw,"xmlns:xlink":rw,version:"1.1",baseProfile:"full",viewBox:!!i&&"0 0 "+t+" "+e},n)}var cw=0;function pw(){return cw++}var dw={cubicIn:"0.32,0,0.67,0",cubicOut:"0.33,1,0.68,1",cubicInOut:"0.65,0,0.35,1",quadraticIn:"0.11,0,0.5,0",quadraticOut:"0.5,1,0.89,1",quadraticInOut:"0.45,0,0.55,1",quarticIn:"0.5,0,0.75,0",quarticOut:"0.25,1,0.5,1",quarticInOut:"0.76,0,0.24,1",quinticIn:"0.64,0,0.78,0",quinticOut:"0.22,1,0.36,1",quinticInOut:"0.83,0,0.17,1",sinusoidalIn:"0.12,0,0.39,0",sinusoidalOut:"0.61,1,0.88,1",sinusoidalInOut:"0.37,0,0.63,1",exponentialIn:"0.7,0,0.84,0",exponentialOut:"0.16,1,0.3,1",exponentialInOut:"0.87,0,0.13,1",circularIn:"0.55,0,1,0.45",circularOut:"0,0.55,0.45,1",circularInOut:"0.85,0,0.15,1"},fw="transform-origin";function gw(t,e,n){var i=A({},t.shape);A(i,e),t.buildPath(n,i);var r=new $b;return r.reset(wi(t)),n.rebuildPath(r,1),r.generateStr(),r.getStr()}function yw(t,e){var n=e.originX,i=e.originY;(n||i)&&(t[fw]=n+"px "+i+"px")}var vw={fill:"fill",opacity:"opacity",lineWidth:"stroke-width",lineDashOffset:"stroke-dashoffset"};function mw(t,e){var n=e.zrId+"-ani-"+e.cssAnimIdx++;return e.cssAnims[n]=t,n}function xw(t){return U(t)?dw[t]?"cubic-bezier("+dw[t]+")":Pn(t)?t:"":""}function _w(t,e,n,i){var r=t.animators,o=r.length,a=[];if(t instanceof ih){var s=function(t,e,n){var i,r,o=t.shape.paths,a={};if(E(o,(function(t){var e=uw(n.zrId);e.animation=!0,_w(t,{},e,!0);var o=e.cssAnims,s=e.cssNodes,l=G(o),u=l.length;if(u){var h=o[r=l[u-1]];for(var c in h){var p=h[c];a[c]=a[c]||{d:""},a[c].d+=p.d||""}for(var d in s){var f=s[d].animation;f.indexOf(r)>=0&&(i=f)}}})),i){e.d=!1;var s=mw(a,n);return i.replace(r,s)}}(t,e,n);if(s)a.push(s);else if(!o)return}else if(!o)return;for(var l={},u=0;u0})).length)return mw(h,n)+" "+r[0]+" both"}for(var y in l){(s=g(l[y]))&&a.push(s)}if(a.length){var v=n.zrId+"-cls-"+pw();n.cssNodes["."+v]={animation:a.join(",")},e.class=v}}function bw(t,e,n,i){var r=JSON.stringify(t),o=n.cssStyleCache[r];o||(o=n.zrId+"-cls-"+pw(),n.cssStyleCache[r]=o,n.cssNodes["."+o+(i?":hover":"")]=t),e.class=e.class?e.class+" "+o:o}var ww=Math.round;function Sw(t){return t&&U(t.src)}function Mw(t){return t&&X(t.toDataURL)}function Iw(t,e,n,i){nw((function(r,o){var a="fill"===r||"stroke"===r;a&&_i(o)?Ew(e,t,r,i):a&&vi(o)?zw(n,t,r,i):t[r]=o,a&&i.ssr&&"none"===o&&(t["pointer-events"]="visible")}),e,n,!1),function(t,e,n){var i=t.style;if(function(t){return t&&(t.shadowBlur||t.shadowOffsetX||t.shadowOffsetY)}(i)){var r=function(t){var e=t.style,n=t.getGlobalScale();return[e.shadowColor,(e.shadowBlur||0).toFixed(2),(e.shadowOffsetX||0).toFixed(2),(e.shadowOffsetY||0).toFixed(2),n[0],n[1]].join(",")}(t),o=n.shadowCache,a=o[r];if(!a){var s=t.getGlobalScale(),l=s[0],u=s[1];if(!l||!u)return;var h=i.shadowOffsetX||0,c=i.shadowOffsetY||0,p=i.shadowBlur,d=hi(i.shadowColor),f=d.opacity,g=d.color,y=p/2/l+" "+p/2/u;a=n.zrId+"-s"+n.shadowIdx++,n.defs[a]=sw("filter",a,{id:a,x:"-100%",y:"-100%",width:"300%",height:"300%"},[sw("feDropShadow","",{dx:h/l,dy:c/u,stdDeviation:y,"flood-color":g,"flood-opacity":f})]),o[r]=a}e.filter=bi(a)}}(n,t,i)}function Tw(t,e){var n=Ur(e);n&&(n.each((function(e,n){null!=e&&(t[(ow+n).toLowerCase()]=e+"")})),e.isSilent()&&(t[ow+"silent"]="true"))}function Cw(t){return pi(t[0]-1)&&pi(t[1])&&pi(t[2])&&pi(t[3]-1)}function Dw(t,e,n){if(e&&(!function(t){return pi(t[4])&&pi(t[5])}(e)||!Cw(e))){var i=n?10:1e4;t.transform=Cw(e)?"translate("+ww(e[4]*i)/i+" "+ww(e[5]*i)/i+")":function(t){return"matrix("+di(t[0])+","+di(t[1])+","+di(t[2])+","+di(t[3])+","+fi(t[4])+","+fi(t[5])+")"}(e)}}function Aw(t,e,n){for(var i=t.points,r=[],o=0;o=0&&a||o;s&&(r=si(s))}var l=i.lineWidth;l&&(l/=!i.strokeNoScale&&t.transform?t.transform[0]:1);var u={cursor:"pointer"};r&&(u.fill=r),i.stroke&&(u.stroke=i.stroke),l&&(u["stroke-width"]=l),bw(u,e,n,!0)}}(t,o,e),sw(s,t.id+"",o)}function Nw(t,e){return t instanceof ks?Rw(t,e):t instanceof Ns?function(t,e){var n=t.style,i=n.image;if(i&&!U(i)&&(Sw(i)?i=i.src:Mw(i)&&(i=i.toDataURL())),i){var r=n.x||0,o=n.y||0,a={href:i,width:n.width,height:n.height};return r&&(a.x=r),o&&(a.y=o),Dw(a,t.transform),Iw(a,n,t,e),Tw(a,t),e.animation&&_w(t,a,e),sw("image",t.id+"",a)}}(t,e):t instanceof Ps?function(t,e){var n=t.style,i=n.text;if(null!=i&&(i+=""),i&&!isNaN(n.x)&&!isNaN(n.y)){var r=n.font||a,s=n.x||0,l=function(t,e,n){return"top"===n?t+=e/2:"bottom"===n&&(t-=e/2),t}(n.y||0,Tr(r),n.textBaseline),u={"dominant-baseline":"central","text-anchor":gi[n.textAlign]||n.textAlign};if($s(n)){var h="",c=n.fontStyle,p=qs(n.fontSize);if(!parseFloat(p))return;var d=n.fontFamily||o,f=n.fontWeight;h+="font-size:"+p+";font-family:"+d+";",c&&"normal"!==c&&(h+="font-style:"+c+";"),f&&"normal"!==f&&(h+="font-weight:"+f+";"),u.style=h}else u.style="font: "+r;return i.match(/\s/)&&(u["xml:space"]="preserve"),s&&(u.x=s),l&&(u.y=l),Dw(u,t.transform),Iw(u,n,t,e),Tw(u,t),e.animation&&_w(t,u,e),sw("text",t.id+"",u,void 0,i)}}(t,e):void 0}function Ew(t,e,n,i){var r,o=t[n],a={gradientUnits:o.global?"userSpaceOnUse":"objectBoundingBox"};if(mi(o))r="linearGradient",a.x1=o.x,a.y1=o.y,a.x2=o.x2,a.y2=o.y2;else{if(!xi(o))return void 0;r="radialGradient",a.cx=rt(o.x,.5),a.cy=rt(o.y,.5),a.r=rt(o.r,.5)}for(var s=o.colorStops,l=[],u=0,h=s.length;ul?Jw(t,null==n[c+1]?null:n[c+1].elm,n,s,c):Qw(t,e,a,l))}(n,i,r):jw(r)?(jw(t.text)&&Xw(n,""),Jw(n,null,r,0,r.length-1)):jw(i)?Qw(n,i,0,i.length-1):jw(t.text)&&Xw(n,""):t.text!==e.text&&(jw(i)&&Qw(n,i,0,i.length-1),Xw(n,e.text)))}var nS=0,iS=function(){function t(t,e,n){if(this.type="svg",this.refreshHover=rS("refreshHover"),this.configLayer=rS("configLayer"),this.storage=e,this._opts=n=A({},n),this.root=t,this._id="zr"+nS++,this._oldVNode=hw(n.width,n.height),t&&!n.ssr){var i=this._viewport=document.createElement("div");i.style.cssText="position:relative;overflow:hidden";var r=this._svgDom=this._oldVNode.elm=aw("svg");tS(null,this._oldVNode),i.appendChild(r),t.appendChild(i)}this.resize(n.width,n.height)}return t.prototype.getType=function(){return this.type},t.prototype.getViewportRoot=function(){return this._viewport},t.prototype.getViewportRootOffset=function(){var t=this.getViewportRoot();if(t)return{offsetLeft:t.offsetLeft||0,offsetTop:t.offsetTop||0}},t.prototype.getSvgDom=function(){return this._svgDom},t.prototype.refresh=function(){if(this.root){var t=this.renderToVNode({willUpdate:!0});t.attrs.style="position:absolute;left:0;top:0;user-select:none",function(t,e){if(Kw(t,e))eS(t,e);else{var n=t.elm,i=Hw(n);$w(e),null!==i&&(Fw(i,e.elm,Yw(n)),Qw(i,[t],0,0))}}(this._oldVNode,t),this._oldVNode=t}},t.prototype.renderOneToVNode=function(t){return Nw(t,uw(this._id))},t.prototype.renderToVNode=function(t){t=t||{};var e=this.storage.getDisplayList(!0),n=this._width,i=this._height,r=uw(this._id);r.animation=t.animation,r.willUpdate=t.willUpdate,r.compress=t.compress,r.emphasis=t.emphasis,r.ssr=this._opts.ssr;var o=[],a=this._bgVNode=function(t,e,n,i){var r;if(n&&"none"!==n)if(r=sw("rect","bg",{width:t,height:e,x:"0",y:"0"}),_i(n))Ew({fill:n},r.attrs,"fill",i);else if(vi(n))zw({style:{fill:n},dirty:bt,getBoundingRect:function(){return{width:t,height:e}}},r.attrs,"fill",i);else{var o=hi(n),a=o.color,s=o.opacity;r.attrs.fill=a,s<1&&(r.attrs["fill-opacity"]=s)}return r}(n,i,this._backgroundColor,r);a&&o.push(a);var s=t.compress?null:this._mainVNode=sw("g","main",{},[]);this._paintList(e,r,s?s.children:o),s&&o.push(s);var l=z(G(r.defs),(function(t){return r.defs[t]}));if(l.length&&o.push(sw("defs","defs",{},l)),t.animation){var u=function(t,e,n){var i=(n=n||{}).newline?"\n":"",r=" {"+i,o=i+"}",a=z(G(t),(function(e){return e+r+z(G(t[e]),(function(n){return n+":"+t[e][n]+";"})).join(i)+o})).join(i),s=z(G(e),(function(t){return"@keyframes "+t+r+z(G(e[t]),(function(n){return n+r+z(G(e[t][n]),(function(i){var r=e[t][n][i];return"d"===i&&(r='path("'+r+'")'),i+":"+r+";"})).join(i)+o})).join(i)+o})).join(i);return a||s?[""].join(i):""}(r.cssNodes,r.cssAnims,{newline:!0});if(u){var h=sw("style","stl",{},[],u);o.push(h)}}return hw(n,i,o,t.useViewBox)},t.prototype.renderToString=function(t){return t=t||{},lw(this.renderToVNode({animation:rt(t.cssAnimation,!0),emphasis:rt(t.cssEmphasis,!0),willUpdate:!1,compress:!0,useViewBox:rt(t.useViewBox,!0)}),{newline:!0})},t.prototype.setBackgroundColor=function(t){this._backgroundColor=t},t.prototype.getSvgRoot=function(){return this._mainVNode&&this._mainVNode.elm},t.prototype._paintList=function(t,e,n){for(var i,r,o=t.length,a=[],s=0,l=0,u=0;u=0&&(!c||!r||c[f]!==r[f]);f--);for(var g=d-1;g>f;g--)i=a[--s-1];for(var y=f+1;y=a)}}for(var h=this.__startIndex;h15)break}n.prevElClipPaths&&u.restore()};if(p)if(0===p.length)s=l.__endIndex;else for(var _=d.dpr,b=0;b0&&t>i[0]){for(s=0;st);s++);a=n[i[s]]}if(i.splice(s+1,0,t),n[t]=e,!e.virtual)if(a){var l=a.dom;l.nextSibling?o.insertBefore(e.dom,l.nextSibling):o.appendChild(e.dom)}else o.firstChild?o.insertBefore(e.dom,o.firstChild):o.appendChild(e.dom);e.painter||(e.painter=this)}},t.prototype.eachLayer=function(t,e){for(var n=this._zlevelList,i=0;i0?uS:0),this._needsManuallyCompositing),u.__builtin__||I("ZLevel "+l+" has been used by unkown layer "+u.id),u!==o&&(u.__used=!0,u.__startIndex!==r&&(u.__dirty=!0),u.__startIndex=r,u.incremental?u.__drawIndex=-1:u.__drawIndex=r,e(r),o=u),1&s.__dirty&&!s.__inHover&&(u.__dirty=!0,u.incremental&&u.__drawIndex<0&&(u.__drawIndex=r))}e(r),this.eachBuiltinLayer((function(t,e){!t.__used&&t.getElementCount()>0&&(t.__dirty=!0,t.__startIndex=t.__endIndex=t.__drawIndex=0),t.__dirty&&t.__drawIndex<0&&(t.__drawIndex=t.__startIndex)}))},t.prototype.clear=function(){return this.eachBuiltinLayer(this._clearLayer),this},t.prototype._clearLayer=function(t){t.clear()},t.prototype.setBackgroundColor=function(t){this._backgroundColor=t,E(this._layers,(function(t){t.setUnpainted()}))},t.prototype.configLayer=function(t,e){if(e){var n=this._layerConfig;n[t]?C(n[t],e,!0):n[t]=e;for(var i=0;i-1&&(s.style.stroke=s.style.fill,s.style.fill="#fff",s.style.lineWidth=2),e},e.type="series.line",e.dependencies=["grid","polar"],e.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},e}(bg);function pS(t,e){var n=t.mapDimensionsAll("defaultedLabel"),i=n.length;if(1===i){var r=mf(t,e,n[0]);return null!=r?r+"":null}if(i){for(var o=[],a=0;a=0&&i.push(e[o])}return i.join(" ")}var fS=function(t){function e(e,n,i,r){var o=t.call(this)||this;return o.updateData(e,n,i,r),o}return n(e,t),e.prototype._createSymbol=function(t,e,n,i,r){this.removeAll();var o=Xy(t,-1,-1,2,2,null,r);o.attr({z2:100,culling:!0,scaleX:i[0]/2,scaleY:i[1]/2}),o.drift=gS,this._symbolType=t,this.add(o)},e.prototype.stopSymbolAnimation=function(t){this.childAt(0).stopAnimation(null,t)},e.prototype.getSymbolType=function(){return this._symbolType},e.prototype.getSymbolPath=function(){return this.childAt(0)},e.prototype.highlight=function(){Ol(this.childAt(0))},e.prototype.downplay=function(){Rl(this.childAt(0))},e.prototype.setZ=function(t,e){var n=this.childAt(0);n.zlevel=t,n.z=e},e.prototype.setDraggable=function(t,e){var n=this.childAt(0);n.draggable=t,n.cursor=!e&&t?"move":n.cursor},e.prototype.updateData=function(t,n,i,r){this.silent=!1;var o=t.getItemVisual(n,"symbol")||"circle",a=t.hostModel,s=e.getSymbolSize(t,n),l=o!==this._symbolType,u=r&&r.disableAnimation;if(l){var h=t.getItemVisual(n,"symbolKeepAspect");this._createSymbol(o,t,n,s,h)}else{(p=this.childAt(0)).silent=!1;var c={scaleX:s[0]/2,scaleY:s[1]/2};u?p.attr(c):vh(p,c,a,n),Sh(p)}if(this._updateCommon(t,n,s,i,r),l){var p=this.childAt(0);if(!u){c={scaleX:this._sizeX,scaleY:this._sizeY,style:{opacity:p.style.opacity}};p.scaleX=p.scaleY=0,p.style.opacity=0,mh(p,c,a,n)}}u&&this.childAt(0).stopAnimation("leave")},e.prototype._updateCommon=function(t,e,n,i,r){var o,a,s,l,u,h,c,p,d,f=this.childAt(0),g=t.hostModel;if(i&&(o=i.emphasisItemStyle,a=i.blurItemStyle,s=i.selectItemStyle,l=i.focus,u=i.blurScope,c=i.labelStatesModels,p=i.hoverScale,d=i.cursorStyle,h=i.emphasisDisabled),!i||t.hasItemOption){var y=i&&i.itemModel?i.itemModel:t.getItemModel(e),v=y.getModel("emphasis");o=v.getModel("itemStyle").getItemStyle(),s=y.getModel(["select","itemStyle"]).getItemStyle(),a=y.getModel(["blur","itemStyle"]).getItemStyle(),l=v.get("focus"),u=v.get("blurScope"),h=v.get("disabled"),c=rc(y),p=v.getShallow("scale"),d=y.getShallow("cursor")}var m=t.getItemVisual(e,"symbolRotate");f.attr("rotation",(m||0)*Math.PI/180||0);var x=Zy(t.getItemVisual(e,"symbolOffset"),n);x&&(f.x=x[0],f.y=x[1]),d&&f.attr("cursor",d);var _=t.getItemVisual(e,"style"),b=_.fill;if(f instanceof Ns){var w=f.style;f.useStyle(A({image:w.image,x:w.x,y:w.y,width:w.width,height:w.height},_))}else f.__isEmptyBrush?f.useStyle(A({},_)):f.useStyle(_),f.style.decal=null,f.setColor(b,r&&r.symbolInnerColor),f.style.strokeNoScale=!0;var S=t.getItemVisual(e,"liftZ"),M=this._z2;null!=S?null==M&&(this._z2=f.z2,f.z2+=S):null!=M&&(f.z2=M,this._z2=null);var I=r&&r.useNameLabel;ic(f,c,{labelFetcher:g,labelDataIndex:e,defaultText:function(e){return I?t.getName(e):pS(t,e)},inheritColor:b,defaultOpacity:_.opacity}),this._sizeX=n[0]/2,this._sizeY=n[1]/2;var T=f.ensureState("emphasis");T.style=o,f.ensureState("select").style=s,f.ensureState("blur").style=a;var C=null==p||!0===p?Math.max(1.1,3/this._sizeY):isFinite(p)&&p>0?+p:1;T.scaleX=this._sizeX*C,T.scaleY=this._sizeY*C,this.setSymbolScale(1),Zl(this,l,u,h)},e.prototype.setSymbolScale=function(t){this.scaleX=this.scaleY=t},e.prototype.fadeOut=function(t,e,n){var i=this.childAt(0),r=rl(this).dataIndex,o=n&&n.animation;if(this.silent=i.silent=!0,n&&n.fadeLabel){var a=i.getTextContent();a&&_h(a,{style:{opacity:0}},e,{dataIndex:r,removeOpt:o,cb:function(){i.removeTextContent()}})}else i.removeTextContent();_h(i,{style:{opacity:0},scaleX:0,scaleY:0},e,{dataIndex:r,cb:t,removeOpt:o})},e.getSymbolSize=function(t,e){return Uy(t.getItemVisual(e,"symbolSize"))},e}(Br);function gS(t,e){this.parent.drift(t,e)}function yS(t,e,n,i){return e&&!isNaN(e[0])&&!isNaN(e[1])&&!(i.isIgnore&&i.isIgnore(n))&&!(i.clipShape&&!i.clipShape.contain(e[0],e[1]))&&"none"!==t.getItemVisual(n,"symbol")}function vS(t){return null==t||q(t)||(t={isIgnore:t}),t||{}}function mS(t){var e=t.hostModel,n=e.getModel("emphasis");return{emphasisItemStyle:n.getModel("itemStyle").getItemStyle(),blurItemStyle:e.getModel(["blur","itemStyle"]).getItemStyle(),selectItemStyle:e.getModel(["select","itemStyle"]).getItemStyle(),focus:n.get("focus"),blurScope:n.get("blurScope"),emphasisDisabled:n.get("disabled"),hoverScale:n.get("scale"),labelStatesModels:rc(e),cursorStyle:e.get("cursor")}}var xS=function(){function t(t){this.group=new Br,this._SymbolCtor=t||fS}return t.prototype.updateData=function(t,e){this._progressiveEls=null,e=vS(e);var n=this.group,i=t.hostModel,r=this._data,o=this._SymbolCtor,a=e.disableAnimation,s=mS(t),l={disableAnimation:a},u=e.getSymbolPoint||function(e){return t.getItemLayout(e)};r||n.removeAll(),t.diff(r).add((function(i){var r=u(i);if(yS(t,r,i,e)){var a=new o(t,i,s,l);a.setPosition(r),t.setItemGraphicEl(i,a),n.add(a)}})).update((function(h,c){var p=r.getItemGraphicEl(c),d=u(h);if(yS(t,d,h,e)){var f=t.getItemVisual(h,"symbol")||"circle",g=p&&p.getSymbolType&&p.getSymbolType();if(!p||g&&g!==f)n.remove(p),(p=new o(t,h,s,l)).setPosition(d);else{p.updateData(t,h,s,l);var y={x:d[0],y:d[1]};a?p.attr(y):vh(p,y,i)}n.add(p),t.setItemGraphicEl(h,p)}else n.remove(p)})).remove((function(t){var e=r.getItemGraphicEl(t);e&&e.fadeOut((function(){n.remove(e)}),i)})).execute(),this._getSymbolPoint=u,this._data=t},t.prototype.updateLayout=function(){var t=this,e=this._data;e&&e.eachItemGraphicEl((function(e,n){var i=t._getSymbolPoint(n);e.setPosition(i),e.markRedraw()}))},t.prototype.incrementalPrepareUpdate=function(t){this._seriesScope=mS(t),this._data=null,this.group.removeAll()},t.prototype.incrementalUpdate=function(t,e,n){function i(t){t.isGroup||(t.incremental=!0,t.ensureState("emphasis").hoverLayer=!0)}this._progressiveEls=[],n=vS(n);for(var r=t.start;r0?n=i[0]:i[1]<0&&(n=i[1]);return n}(r,n),a=i.dim,s=r.dim,l=e.mapDimension(s),u=e.mapDimension(a),h="x"===s||"radius"===s?1:0,c=z(t.dimensions,(function(t){return e.mapDimension(t)})),p=!1,d=e.getCalculationInfo("stackResultDimension");return mx(e,c[0])&&(p=!0,c[0]=d),mx(e,c[1])&&(p=!0,c[1]=d),{dataDimsForPoint:c,valueStart:o,valueAxisDim:s,baseAxisDim:a,stacked:!!p,valueDim:l,baseDim:u,baseDataOffset:h,stackedOverDimension:e.getCalculationInfo("stackedOverDimension")}}function bS(t,e,n,i){var r=NaN;t.stacked&&(r=n.get(n.getCalculationInfo("stackedOverDimension"),i)),isNaN(r)&&(r=t.valueStart);var o=t.baseDataOffset,a=[];return a[o]=n.get(t.baseDim,i),a[1-o]=r,e.dataToPoint(a)}var wS=Math.min,SS=Math.max;function MS(t,e){return isNaN(t)||isNaN(e)}function IS(t,e,n,i,r,o,a,s,l){for(var u,h,c,p,d,f,g=n,y=0;y=r||g<0)break;if(MS(v,m)){if(l){g+=o;continue}break}if(g===n)t[o>0?"moveTo":"lineTo"](v,m),c=v,p=m;else{var x=v-u,_=m-h;if(x*x+_*_<.5){g+=o;continue}if(a>0){for(var b=g+o,w=e[2*b],S=e[2*b+1];w===v&&S===m&&y=i||MS(w,S))d=v,f=m;else{T=w-u,C=S-h;var k=v-u,L=w-v,P=m-h,O=S-m,R=void 0,N=void 0;if("x"===s){var E=T>0?1:-1;d=v-E*(R=Math.abs(k))*a,f=m,D=v+E*(N=Math.abs(L))*a,A=m}else if("y"===s){var z=C>0?1:-1;d=v,f=m-z*(R=Math.abs(P))*a,D=v,A=m+z*(N=Math.abs(O))*a}else R=Math.sqrt(k*k+P*P),d=v-T*a*(1-(I=(N=Math.sqrt(L*L+O*O))/(N+R))),f=m-C*a*(1-I),A=m+C*a*I,D=wS(D=v+T*a*I,SS(w,v)),A=wS(A,SS(S,m)),D=SS(D,wS(w,v)),f=m-(C=(A=SS(A,wS(S,m)))-m)*R/N,d=wS(d=v-(T=D-v)*R/N,SS(u,v)),f=wS(f,SS(h,m)),D=v+(T=v-(d=SS(d,wS(u,v))))*N/R,A=m+(C=m-(f=SS(f,wS(h,m))))*N/R}t.bezierCurveTo(c,p,d,f,v,m),c=D,p=A}else t.lineTo(v,m)}u=v,h=m,g+=o}return y}var TS=function(){this.smooth=0,this.smoothConstraint=!0},CS=function(t){function e(e){var n=t.call(this,e)||this;return n.type="ec-polyline",n}return n(e,t),e.prototype.getDefaultStyle=function(){return{stroke:"#000",fill:null}},e.prototype.getDefaultShape=function(){return new TS},e.prototype.buildPath=function(t,e){var n=e.points,i=0,r=n.length/2;if(e.connectNulls){for(;r>0&&MS(n[2*r-2],n[2*r-1]);r--);for(;i=0){var y=a?(h-i)*g+i:(u-n)*g+n;return a?[t,y]:[y,t]}n=u,i=h;break;case o.C:u=r[l++],h=r[l++],c=r[l++],p=r[l++],d=r[l++],f=r[l++];var v=a?_n(n,u,c,d,t,s):_n(i,h,p,f,t,s);if(v>0)for(var m=0;m=0){y=a?mn(i,h,p,f,x):mn(n,u,c,d,x);return a?[t,y]:[y,t]}}n=d,i=f}}},e}(ks),DS=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e}(TS),AS=function(t){function e(e){var n=t.call(this,e)||this;return n.type="ec-polygon",n}return n(e,t),e.prototype.getDefaultShape=function(){return new DS},e.prototype.buildPath=function(t,e){var n=e.points,i=e.stackedOnPoints,r=0,o=n.length/2,a=e.smoothMonotone;if(e.connectNulls){for(;o>0&&MS(n[2*o-2],n[2*o-1]);o--);for(;r=0;a--){var s=t.getDimensionInfo(i[a].dimension);if("x"===(r=s&&s.coordDim)||"y"===r){o=i[a];break}}if(o){var l=e.getAxis(r),u=z(o.stops,(function(t){return{coord:l.toGlobalCoord(l.dataToCoord(t.value)),color:t.color}})),h=u.length,c=o.outerColors.slice();h&&u[0].coord>u[h-1].coord&&(u.reverse(),c.reverse());var p=function(t,e){var n,i,r=[],o=t.length;function a(t,e,n){var i=t.coord;return{coord:n,color:ti((n-i)/(e.coord-i),[t.color,e.color])}}for(var s=0;se){i?r.push(a(i,l,e)):n&&r.push(a(n,l,0),a(n,l,e));break}n&&(r.push(a(n,l,0)),n=null),r.push(l),i=l}}return r}(u,"x"===r?n.getWidth():n.getHeight()),d=p.length;if(!d&&h)return u[0].coord<0?c[1]?c[1]:u[h-1].color:c[0]?c[0]:u[0].color;var f=p[0].coord-10,g=p[d-1].coord+10,y=g-f;if(y<.001)return"transparent";E(p,(function(t){t.offset=(t.coord-f)/y})),p.push({offset:d?p[d-1].offset:.5,color:c[1]||"transparent"}),p.unshift({offset:d?p[0].offset:.5,color:c[0]||"transparent"});var v=new oh(0,0,0,0,p,!0);return v[r]=f,v[r+"2"]=g,v}}}function FS(t,e,n){var i=t.get("showAllSymbol"),r="auto"===i;if(!i||r){var o=n.getAxesByScale("ordinal")[0];if(o&&(!r||!function(t,e){var n=t.getExtent(),i=Math.abs(n[1]-n[0])/t.scale.count();isNaN(i)&&(i=0);for(var r=e.count(),o=Math.max(1,Math.round(r/5)),a=0;ai)return!1;return!0}(o,e))){var a=e.mapDimension(o.dim),s={};return E(o.getViewLabels(),(function(t){var e=o.scale.getRawOrdinalNumber(t.tickValue);s[e]=1})),function(t){return!s.hasOwnProperty(e.get(a,t))}}}}function GS(t,e){return[t[2*e],t[2*e+1]]}function WS(t){if(t.get(["endLabel","show"]))return!0;for(var e=0;e0&&"bolder"===t.get(["emphasis","lineStyle","width"]))&&(p.getState("emphasis").style.lineWidth=+p.style.lineWidth+1);rl(p).seriesIndex=t.seriesIndex,Zl(p,A,L,P);var O=zS(t.get("smooth")),R=t.get("smoothMonotone");if(p.setShape({smooth:O,smoothMonotone:R,connectNulls:b}),d){var N=o.getCalculationInfo("stackedOnSeries"),E=0;d.useStyle(k(s.getAreaStyle(),{fill:T,opacity:.7,lineJoin:"bevel",decal:o.getVisual("style").decal})),N&&(E=zS(N.get("smooth"))),d.setShape({smooth:O,stackedOnSmooth:E,smoothMonotone:R,connectNulls:b}),$l(d,t,"areaStyle"),rl(d).seriesIndex=t.seriesIndex,Zl(d,A,L,P)}var z=this._changePolyState;o.eachItemGraphicEl((function(t){t&&(t.onHoverStateChange=z)})),this._polyline.onHoverStateChange=z,this._data=o,this._coordSys=i,this._stackedOnPoints=x,this._points=l,this._step=I,this._valueOrigin=v,t.get("triggerLineEvent")&&(this.packEventData(t,p),d&&this.packEventData(t,d))},e.prototype.packEventData=function(t,e){rl(e).eventData={componentType:"series",componentSubType:"line",componentIndex:t.componentIndex,seriesIndex:t.seriesIndex,seriesName:t.name,seriesType:"line"}},e.prototype.highlight=function(t,e,n,i){var r=t.getData(),o=zo(r,i);if(this._changePolyState("emphasis"),!(o instanceof Array)&&null!=o&&o>=0){var a=r.getLayout("points"),s=r.getItemGraphicEl(o);if(!s){var l=a[2*o],u=a[2*o+1];if(isNaN(l)||isNaN(u))return;if(this._clipShapeForSymbol&&!this._clipShapeForSymbol.contain(l,u))return;var h=t.get("zlevel")||0,c=t.get("z")||0;(s=new fS(r,o)).x=l,s.y=u,s.setZ(h,c);var p=s.getSymbolPath().getTextContent();p&&(p.zlevel=h,p.z=c,p.z2=this._polyline.z2+1),s.__temp=!0,r.setItemGraphicEl(o,s),s.stopSymbolAnimation(!0),this.group.add(s)}s.highlight()}else Og.prototype.highlight.call(this,t,e,n,i)},e.prototype.downplay=function(t,e,n,i){var r=t.getData(),o=zo(r,i);if(this._changePolyState("normal"),null!=o&&o>=0){var a=r.getItemGraphicEl(o);a&&(a.__temp?(r.setItemGraphicEl(o,null),this.group.remove(a)):a.downplay())}else Og.prototype.downplay.call(this,t,e,n,i)},e.prototype._changePolyState=function(t){var e=this._polygon;Dl(this._polyline,t),e&&Dl(e,t)},e.prototype._newPolyline=function(t){var e=this._polyline;return e&&this._lineGroup.remove(e),e=new CS({shape:{points:t},segmentIgnoreThreshold:2,z2:10}),this._lineGroup.add(e),this._polyline=e,e},e.prototype._newPolygon=function(t,e){var n=this._polygon;return n&&this._lineGroup.remove(n),n=new AS({shape:{points:t,stackedOnPoints:e},segmentIgnoreThreshold:2}),this._lineGroup.add(n),this._polygon=n,n},e.prototype._initSymbolLabelAnimation=function(t,e,n){var i,r,o=e.getBaseAxis(),a=o.inverse;"cartesian2d"===e.type?(i=o.isHorizontal(),r=!1):"polar"===e.type&&(i="angle"===o.dim,r=!0);var s=t.hostModel,l=s.get("animationDuration");X(l)&&(l=l(null));var u=s.get("animationDelay")||0,h=X(u)?u(null):u;t.eachItemGraphicEl((function(t,o){var s=t;if(s){var c=[t.x,t.y],p=void 0,d=void 0,f=void 0;if(n)if(r){var g=n,y=e.pointToCoord(c);i?(p=g.startAngle,d=g.endAngle,f=-y[1]/180*Math.PI):(p=g.r0,d=g.r,f=y[0])}else{var v=n;i?(p=v.x,d=v.x+v.width,f=t.x):(p=v.y+v.height,d=v.y,f=t.y)}var m=d===p?0:(f-p)/(d-p);a&&(m=1-m);var x=X(u)?u(o):l*m+h,_=s.getSymbolPath(),b=_.getTextContent();s.attr({scaleX:0,scaleY:0}),s.animateTo({scaleX:1,scaleY:1},{duration:200,setToFinal:!0,delay:x}),b&&b.animateFrom({style:{opacity:0}},{duration:300,delay:x}),_.disableLabelAnimation=!0}}))},e.prototype._initOrUpdateEndLabel=function(t,e,n){var i=t.getModel("endLabel");if(WS(t)){var r=t.getData(),o=this._polyline,a=r.getLayout("points");if(!a)return o.removeTextContent(),void(this._endLabel=null);var s=this._endLabel;s||((s=this._endLabel=new Xs({z2:200})).ignoreClip=!0,o.setTextContent(this._endLabel),o.disableLabelAnimation=!0);var l=function(t){for(var e,n,i=t.length/2;i>0&&(e=t[2*i-2],n=t[2*i-1],isNaN(e)||isNaN(n));i--);return i-1}(a);l>=0&&(ic(o,rc(t,"endLabel"),{inheritColor:n,labelFetcher:t,labelDataIndex:l,defaultText:function(t,e,n){return null!=n?dS(r,n):pS(r,t)},enableTextSetter:!0},function(t,e){var n=e.getBaseAxis(),i=n.isHorizontal(),r=n.inverse,o=i?r?"right":"left":"center",a=i?"middle":r?"top":"bottom";return{normal:{align:t.get("align")||o,verticalAlign:t.get("verticalAlign")||a}}}(i,e)),o.textConfig.position=null)}else this._endLabel&&(this._polyline.removeTextContent(),this._endLabel=null)},e.prototype._endLabelOnDuring=function(t,e,n,i,r,o,a){var s=this._endLabel,l=this._polyline;if(s){t<1&&null==i.originalX&&(i.originalX=s.x,i.originalY=s.y);var u=n.getLayout("points"),h=n.hostModel,c=h.get("connectNulls"),p=o.get("precision"),d=o.get("distance")||0,f=a.getBaseAxis(),g=f.isHorizontal(),y=f.inverse,v=e.shape,m=y?g?v.x:v.y+v.height:g?v.x+v.width:v.y,x=(g?d:0)*(y?-1:1),_=(g?0:-d)*(y?-1:1),b=g?"x":"y",w=function(t,e,n){for(var i,r,o=t.length/2,a="x"===n?0:1,s=0,l=-1,u=0;u=e||i>=e&&r<=e){l=u;break}s=u,i=r}else i=r;return{range:[s,l],t:(e-i)/(r-i)}}(u,m,b),S=w.range,M=S[1]-S[0],I=void 0;if(M>=1){if(M>1&&!c){var T=GS(u,S[0]);s.attr({x:T[0]+x,y:T[1]+_}),r&&(I=h.getRawValue(S[0]))}else{(T=l.getPointOn(m,b))&&s.attr({x:T[0]+x,y:T[1]+_});var C=h.getRawValue(S[0]),D=h.getRawValue(S[1]);r&&(I=Zo(n,p,C,D,w.t))}i.lastFrameIndex=S[0]}else{var A=1===t||i.lastFrameIndex>0?S[0]:0;T=GS(u,A);r&&(I=h.getRawValue(A)),s.attr({x:T[0]+x,y:T[1]+_})}if(r){var k=pc(s);"function"==typeof k.setLabelText&&k.setLabelText(I)}}},e.prototype._doUpdateAnimation=function(t,e,n,i,r,o,a){var s=this._polyline,l=this._polygon,u=t.hostModel,h=function(t,e,n,i,r,o,a,s){for(var l=function(t,e){var n=[];return e.diff(t).add((function(t){n.push({cmd:"+",idx:t})})).update((function(t,e){n.push({cmd:"=",idx:e,idx1:t})})).remove((function(t){n.push({cmd:"-",idx:t})})).execute(),n}(t,e),u=[],h=[],c=[],p=[],d=[],f=[],g=[],y=_S(r,e,a),v=t.getLayout("points")||[],m=e.getLayout("points")||[],x=0;x3e3||l&&ES(p,f)>3e3)return s.stopAnimation(),s.setShape({points:d}),void(l&&(l.stopAnimation(),l.setShape({points:d,stackedOnPoints:f})));s.shape.__points=h.current,s.shape.points=c;var g={shape:{points:d}};h.current!==c&&(g.shape.__points=h.next),s.stopAnimation(),vh(s,g,u),l&&(l.setShape({points:c,stackedOnPoints:p}),l.stopAnimation(),vh(l,{shape:{stackedOnPoints:f}},u),s.shape.points!==l.shape.points&&(l.shape.points=s.shape.points));for(var y=[],v=h.status,m=0;me&&(e=t[n]);return isFinite(e)?e:NaN},min:function(t){for(var e=1/0,n=0;n10&&"cartesian2d"===o.type&&r){var s=o.getBaseAxis(),l=o.getOtherAxis(s),u=s.getExtent(),h=n.getDevicePixelRatio(),c=Math.abs(u[1]-u[0])*(h||1),p=Math.round(a/c);if(isFinite(p)&&p>1){"lttb"===r?t.setData(i.lttbDownSample(i.mapDimension(l.dim),1/p)):"minmax"===r&&t.setData(i.minmaxDownSample(i.mapDimension(l.dim),1/p));var d=void 0;U(r)?d=US[r]:X(r)&&(d=r),d&&t.setData(i.downSample(i.mapDimension(l.dim),1/p,d,ZS))}}}}}var qS=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.getInitialData=function(t,e){return _x(null,this,{useEncodeDefaulter:!0})},e.prototype.getMarkerPosition=function(t,e,n){var i=this.coordinateSystem;if(i&&i.clampData){var r=i.clampData(t),o=i.dataToPoint(r);if(n)E(i.getAxes(),(function(t,n){if("category"===t.type&&null!=e){var i=t.getTicksCoords(),a=t.getTickModel().get("alignWithLabel"),s=r[n],l="x1"===e[n]||"y1"===e[n];if(l&&!a&&(s+=1),i.length<2)return;if(2===i.length)return void(o[n]=t.toGlobalCoord(t.getExtent()[l?1:0]));for(var u=void 0,h=void 0,c=1,p=0;ps){h=(d+u)/2;break}1===p&&(c=f-i[0].tickValue)}null==h&&(u?u&&(h=i[i.length-1].coord):h=i[0].coord),o[n]=t.toGlobalCoord(h)}}));else{var a=this.getData(),s=a.getLayout("offset"),l=a.getLayout("size"),u=i.getBaseAxis().isHorizontal()?0:1;o[u]+=s+l/2}return o}return[NaN,NaN]},e.type="series.__base_bar__",e.defaultOption={z:2,coordinateSystem:"cartesian2d",legendHoverLink:!0,barMinHeight:0,barMinAngle:0,large:!1,largeThreshold:400,progressive:3e3,progressiveChunkMode:"mod"},e}(bg);bg.registerClass(qS);var KS=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.getInitialData=function(){return _x(null,this,{useEncodeDefaulter:!0,createInvertedIndices:!!this.get("realtimeSort",!0)||null})},e.prototype.getProgressive=function(){return!!this.get("large")&&this.get("progressive")},e.prototype.getProgressiveThreshold=function(){var t=this.get("progressiveThreshold"),e=this.get("largeThreshold");return e>t&&(t=e),t},e.prototype.brushSelector=function(t,e,n){return n.rect(e.getItemLayout(t))},e.type="series.bar",e.dependencies=["grid","polar"],e.defaultOption=kc(qS.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}),e}(qS),$S=function(){this.cx=0,this.cy=0,this.r0=0,this.r=0,this.startAngle=0,this.endAngle=2*Math.PI,this.clockwise=!0},JS=function(t){function e(e){var n=t.call(this,e)||this;return n.type="sausage",n}return n(e,t),e.prototype.getDefaultShape=function(){return new $S},e.prototype.buildPath=function(t,e){var n=e.cx,i=e.cy,r=Math.max(e.r0||0,0),o=Math.max(e.r,0),a=.5*(o-r),s=r+a,l=e.startAngle,u=e.endAngle,h=e.clockwise,c=2*Math.PI,p=h?u-lo)return!0;o=u}return!1},e.prototype._isOrderDifferentInView=function(t,e){for(var n=e.scale,i=n.getExtent(),r=Math.max(0,i[0]),o=Math.min(i[1],n.getOrdinalMeta().categories.length-1);r<=o;++r)if(t.ordinalNumbers[r]!==n.getRawOrdinalNumber(r))return!0},e.prototype._updateSortWithinSameData=function(t,e,n,i){if(this._isOrderChangedWithinSameData(t,e,n)){var r=this._dataSort(t,n,e);this._isOrderDifferentInView(r,n)&&(this._removeOnRenderedListener(i),i.dispatchAction({type:"changeAxisOrder",componentType:n.dim+"Axis",axisId:n.index,sortInfo:r}))}},e.prototype._dispatchInitSort=function(t,e,n){var i=e.baseAxis,r=this._dataSort(t,i,(function(n){return t.get(t.mapDimension(e.otherAxis.dim),n)}));n.dispatchAction({type:"changeAxisOrder",componentType:i.dim+"Axis",isInitSort:!0,axisId:i.index,sortInfo:r})},e.prototype.remove=function(t,e){this._clear(this._model),this._removeOnRenderedListener(e)},e.prototype.dispose=function(t,e){this._removeOnRenderedListener(e)},e.prototype._removeOnRenderedListener=function(t){this._onRendered&&(t.getZr().off("rendered",this._onRendered),this._onRendered=null)},e.prototype._clear=function(t){var e=this.group,n=this._data;t&&t.isAnimationEnabled()&&n&&!this._isLargeDraw?(this._removeBackground(),this._backgroundEls=[],n.eachItemGraphicEl((function(e){wh(e,t,rl(e).dataIndex)}))):e.removeAll(),this._data=null,this._isFirstFrame=!0},e.prototype._removeBackground=function(){this.group.remove(this._backgroundGroup),this._backgroundGroup=null},e.type="bar",e}(Og),oM={cartesian2d:function(t,e){var n=e.width<0?-1:1,i=e.height<0?-1:1;n<0&&(e.x+=e.width,e.width=-e.width),i<0&&(e.y+=e.height,e.height=-e.height);var r=t.x+t.width,o=t.y+t.height,a=nM(e.x,t.x),s=iM(e.x+e.width,r),l=nM(e.y,t.y),u=iM(e.y+e.height,o),h=sr?s:a,e.y=c&&l>o?u:l,e.width=h?0:s-a,e.height=c?0:u-l,n<0&&(e.x+=e.width,e.width=-e.width),i<0&&(e.y+=e.height,e.height=-e.height),h||c},polar:function(t,e){var n=e.r0<=e.r?1:-1;if(n<0){var i=e.r;e.r=e.r0,e.r0=i}var r=iM(e.r,t.r),o=nM(e.r0,t.r0);e.r=r,e.r0=o;var a=r-o<0;if(n<0){i=e.r;e.r=e.r0,e.r0=i}return a}},aM={cartesian2d:function(t,e,n,i,r,o,a,s,l){var u=new Ws({shape:A({},i),z2:1});(u.__dataIndex=n,u.name="item",o)&&(u.shape[r?"height":"width"]=0);return u},polar:function(t,e,n,i,r,o,a,s,l){var u=!r&&l?JS:Fu,h=new u({shape:i,z2:1});h.name="item";var c,p,d=dM(r);if(h.calculateTextPosition=(c=d,p=({isRoundCap:u===JS}||{}).isRoundCap,function(t,e,n){var i=e.position;if(!i||i instanceof Array)return Dr(t,e,n);var r=c(i),o=null!=e.distance?e.distance:5,a=this.shape,s=a.cx,l=a.cy,u=a.r,h=a.r0,d=(u+h)/2,f=a.startAngle,g=a.endAngle,y=(f+g)/2,v=p?Math.abs(u-h)/2:0,m=Math.cos,x=Math.sin,_=s+u*m(f),b=l+u*x(f),w="left",S="top";switch(r){case"startArc":_=s+(h-o)*m(y),b=l+(h-o)*x(y),w="center",S="top";break;case"insideStartArc":_=s+(h+o)*m(y),b=l+(h+o)*x(y),w="center",S="bottom";break;case"startAngle":_=s+d*m(f)+QS(f,o+v,!1),b=l+d*x(f)+tM(f,o+v,!1),w="right",S="middle";break;case"insideStartAngle":_=s+d*m(f)+QS(f,-o+v,!1),b=l+d*x(f)+tM(f,-o+v,!1),w="left",S="middle";break;case"middle":_=s+d*m(y),b=l+d*x(y),w="center",S="middle";break;case"endArc":_=s+(u+o)*m(y),b=l+(u+o)*x(y),w="center",S="bottom";break;case"insideEndArc":_=s+(u-o)*m(y),b=l+(u-o)*x(y),w="center",S="top";break;case"endAngle":_=s+d*m(g)+QS(g,o+v,!0),b=l+d*x(g)+tM(g,o+v,!0),w="left",S="middle";break;case"insideEndAngle":_=s+d*m(g)+QS(g,-o+v,!0),b=l+d*x(g)+tM(g,-o+v,!0),w="right",S="middle";break;default:return Dr(t,e,n)}return(t=t||{}).x=_,t.y=b,t.align=w,t.verticalAlign=S,t}),o){var f=r?"r":"endAngle",g={};h.shape[f]=r?i.r0:i.startAngle,g[f]=i[f],(s?vh:mh)(h,{shape:g},o)}return h}};function sM(t,e,n,i,r,o,a,s){var l,u;o?(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||(a?vh:mh)(n,{shape:l},e,r,null),(a?vh:mh)(n,{shape:u},e?t.baseAxis.model:null,r)}function lM(t,e){for(var n=0;n0?1:-1,a=i.height>0?1:-1;return{x:i.x+o*r/2,y:i.y+a*r/2,width:i.width-o*r,height:i.height-a*r}},polar:function(t,e,n){var i=t.getItemLayout(e);return{cx:i.cx,cy:i.cy,r0:i.r0,r:i.r,startAngle:i.startAngle,endAngle:i.endAngle,clockwise:i.clockwise}}};function dM(t){return function(t){var e=t?"Arc":"Angle";return function(t){switch(t){case"start":case"insideStart":case"end":case"insideEnd":return t+e;default:return t}}}(t)}function fM(t,e,n,i,r,o,a,s){var l=e.getItemVisual(n,"style");if(s){if(!o.get("roundCap")){var u=t.shape;A(u,eM(i.getModel("itemStyle"),u,!0)),t.setShape(u)}}else{var h=i.get(["itemStyle","borderRadius"])||0;t.setShape("r",h)}t.useStyle(l);var c=i.getShallow("cursor");c&&t.attr("cursor",c);var p=s?a?r.r>=r.r0?"endArc":"startArc":r.endAngle>=r.startAngle?"endAngle":"startAngle":a?r.height>=0?"bottom":"top":r.width>=0?"right":"left",d=rc(i);ic(t,d,{labelFetcher:o,labelDataIndex:n,defaultText:pS(o.getData(),n),inheritColor:l.fill,defaultOpacity:l.opacity,defaultOutsidePosition:p});var f=t.getTextContent();if(s&&f){var g=i.get(["label","position"]);t.textConfig.inside="middle"===g||null,function(t,e,n,i){if(j(i))t.setTextConfig({rotation:i});else if(Y(e))t.setTextConfig({rotation:0});else{var r,o=t.shape,a=o.clockwise?o.startAngle:o.endAngle,s=o.clockwise?o.endAngle:o.startAngle,l=(a+s)/2,u=n(e);switch(u){case"startArc":case"insideStartArc":case"middle":case"insideEndArc":case"endArc":r=l;break;case"startAngle":case"insideStartAngle":r=a;break;case"endAngle":case"insideEndAngle":r=s;break;default:return void t.setTextConfig({rotation:0})}var h=1.5*Math.PI-r;"middle"===u&&h>Math.PI/2&&h<1.5*Math.PI&&(h-=Math.PI),t.setTextConfig({rotation:h})}}(t,"outside"===g?p:g,dM(a),i.get(["label","rotate"]))}dc(f,d,o.getRawValue(n),(function(t){return dS(e,t)}));var y=i.getModel(["emphasis"]);Zl(t,y.get("focus"),y.get("blurScope"),y.get("disabled")),$l(t,i),function(t){return null!=t.startAngle&&null!=t.endAngle&&t.startAngle===t.endAngle}(r)&&(t.style.fill="none",t.style.stroke="none",E(t.states,(function(t){t.style&&(t.style.fill=t.style.stroke="none")})))}var gM=function(){},yM=function(t){function e(e){var n=t.call(this,e)||this;return n.type="largeBar",n}return n(e,t),e.prototype.getDefaultShape=function(){return new gM},e.prototype.buildPath=function(t,e){for(var n=e.points,i=this.baseDimIdx,r=1-this.baseDimIdx,o=[],a=[],s=this.barWidth,l=0;l=s[0]&&e<=s[0]+l[0]&&n>=s[1]&&n<=s[1]+l[1])return a[h]}return-1}(this,t.offsetX,t.offsetY);rl(this).dataIndex=e>=0?e:null}),30,!1);function xM(t,e,n){if(OS(n,"cartesian2d")){var i=e,r=n.getArea();return{x:t?i.x:r.x,y:t?r.y:i.y,width:t?i.width:r.width,height:t?r.height:i.height}}var o=e;return{cx:(r=n.getArea()).cx,cy:r.cy,r0:t?r.r0:o.r0,r:t?r.r:o.r,startAngle:t?o.startAngle:0,endAngle:t?o.endAngle:2*Math.PI}}var _M=2*Math.PI,bM=Math.PI/180;function wM(t,e){return kp(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()})}function SM(t,e){var n=wM(t,e),i=t.get("center"),r=t.get("radius");Y(r)||(r=[0,r]);var o,a,s=$r(n.width,e.getWidth()),l=$r(n.height,e.getHeight()),u=Math.min(s,l),h=$r(r[0],u/2),c=$r(r[1],u/2),p=t.coordinateSystem;if(p){var d=p.dataToPoint(i);o=d[0]||0,a=d[1]||0}else Y(i)||(i=[i,i]),o=$r(i[0],s)+n.x,a=$r(i[1],l)+n.y;return{cx:o,cy:a,r0:h,r:c}}function MM(t,e,n){e.eachSeriesByType(t,(function(t){var e=t.getData(),i=e.mapDimension("value"),r=wM(t,n),o=SM(t,n),a=o.cx,s=o.cy,l=o.r,u=o.r0,h=-t.get("startAngle")*bM,c=t.get("endAngle"),p=t.get("padAngle")*bM;c="auto"===c?h-_M:-c*bM;var d=t.get("minAngle")*bM+p,f=0;e.each(i,(function(t){!isNaN(t)&&f++}));var g=e.getSum(i),y=Math.PI/(g||f)*2,v=t.get("clockwise"),m=t.get("roseType"),x=t.get("stillShowZeroSum"),_=e.getDataExtent(i);_[0]=0;var b=v?1:-1,w=[h,c],S=b*p/2;us(w,!v),h=w[0],c=w[1];var M=IM(t);M.startAngle=h,M.endAngle=c,M.clockwise=v;var I=Math.abs(c-h),T=I,C=0,D=h;if(e.setLayout({viewRect:r,r:l}),e.each(i,(function(t,n){var i;if(isNaN(t))e.setItemLayout(n,{angle:NaN,startAngle:NaN,endAngle:NaN,clockwise:v,cx:a,cy:s,r0:u,r:m?NaN:l});else{(i="area"!==m?0===g&&x?y:t*y:I/f)i?h=o=D+b*i/2:(o=D+S,h=r-S),e.setItemLayout(n,{angle:i,startAngle:o,endAngle:h,clockwise:v,cx:a,cy:s,r0:u,r:m?Kr(t,_,[u,l]):l}),D=r}})),T<_M&&f)if(T<=.001){var A=I/f;e.each(i,(function(t,n){if(!isNaN(t)){var i=e.getItemLayout(n);i.angle=A;var r=0,o=0;An?a:o,h=Math.abs(l.label.y-n);if(h>=u.maxY){var c=l.label.x-e-l.len2*r,p=i+l.len,f=Math.abs(c)t.unconstrainedWidth?null:d:null;i.setStyle("width",f)}var g=i.getBoundingRect();o.width=g.width;var y=(i.style.margin||0)+2.1;o.height=g.height+y,o.y-=(o.height-c)/2}}}function kM(t){return"center"===t.position}function LM(t){var e,n,i=t.getData(),r=[],o=!1,a=(t.get("minShowLabelAngle")||0)*CM,s=i.getLayout("viewRect"),l=i.getLayout("r"),u=s.width,h=s.x,c=s.y,p=s.height;function d(t){t.ignore=!0}i.each((function(t){var s=i.getItemGraphicEl(t),c=s.shape,p=s.getTextContent(),f=s.getTextGuideLine(),g=i.getItemModel(t),y=g.getModel("label"),v=y.get("position")||g.get(["emphasis","label","position"]),m=y.get("distanceToLabelLine"),x=y.get("alignTo"),_=$r(y.get("edgeDistance"),u),b=y.get("bleedMargin"),w=g.getModel("labelLine"),S=w.get("length");S=$r(S,u);var M=w.get("length2");if(M=$r(M,u),Math.abs(c.endAngle-c.startAngle)0?"right":"left":k>0?"left":"right"}var B=Math.PI,F=0,G=y.get("rotate");if(j(G))F=G*(B/180);else if("center"===v)F=0;else if("radial"===G||!0===G){F=k<0?-A+B:-A}else if("tangential"===G&&"outside"!==v&&"outer"!==v){var W=Math.atan2(k,L);W<0&&(W=2*B+W),L>0&&(W=B+W),F=W-B}if(o=!!F,p.x=I,p.y=T,p.rotation=F,p.setStyle({verticalAlign:"middle"}),P){p.setStyle({align:D});var H=p.states.select;H&&(H.x+=p.x,H.y+=p.y)}else{var Y=p.getBoundingRect().clone();Y.applyTransform(p.getComputedTransform());var X=(p.style.margin||0)+2.1;Y.y-=X/2,Y.height+=X,r.push({label:p,labelLine:f,position:v,len:S,len2:M,minTurnAngle:w.get("minTurnAngle"),maxSurfaceAngle:w.get("maxSurfaceAngle"),surfaceNormal:new De(k,L),linePoints:C,textAlign:D,labelDistance:m,labelAlignTo:x,edgeDistance:_,bleedMargin:b,rect:Y,unconstrainedWidth:Y.width,labelStyleWidth:p.style.width})}s.setTextConfig({inside:P})}})),!o&&t.get("avoidLabelOverlap")&&function(t,e,n,i,r,o,a,s){for(var l=[],u=[],h=Number.MAX_VALUE,c=-Number.MAX_VALUE,p=0;p0){for(var l=o.getItemLayout(0),u=1;isNaN(l&&l.startAngle)&&u=n.r0}},e.type="pie",e}(Og);function RM(t,e,n){e=Y(e)&&{coordDimensions:e}||A({encodeDefine:t.getEncode()},e);var i=t.getSource(),r=px(i,e).dimensions,o=new cx(r,t);return o.initData(i,n),o}var NM=function(){function t(t,e){this._getDataWithEncodedVisual=t,this._getRawData=e}return t.prototype.getAllNames=function(){var t=this._getRawData();return t.mapArray(t.getName)},t.prototype.containName=function(t){return this._getRawData().indexOfName(t)>=0},t.prototype.indexOfName=function(t){return this._getDataWithEncodedVisual().indexOfName(t)},t.prototype.getItemVisual=function(t,e){return this._getDataWithEncodedVisual().getItemVisual(t,e)},t}(),EM=Vo(),zM=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.init=function(e){t.prototype.init.apply(this,arguments),this.legendVisualProvider=new NM(W(this.getData,this),W(this.getRawData,this)),this._defaultLabelLine(e)},e.prototype.mergeOption=function(){t.prototype.mergeOption.apply(this,arguments)},e.prototype.getInitialData=function(){return RM(this,{coordDimensions:["value"],encodeDefaulter:H(ed,this)})},e.prototype.getDataParams=function(e){var n=this.getData(),i=EM(n),r=i.seats;if(!r){var o=[];n.each(n.mapDimension("value"),(function(t){o.push(t)})),r=i.seats=io(o,n.hostModel.get("percentPrecision"))}var a=t.prototype.getDataParams.call(this,e);return a.percent=r[e]||0,a.$vars.push("percent"),a},e.prototype._defaultLabelLine=function(t){Co(t,"labelLine",["show"]);var e=t.labelLine,n=t.emphasis.labelLine;e.show=e.show&&t.label.show,n.show=n.show&&t.emphasis.label.show},e.type="series.pie",e.defaultOption={z:2,legendHoverLink:!0,colorBy:"data",center:["50%","50%"],radius:[0,"75%"],clockwise:!0,startAngle:90,endAngle:"auto",padAngle:0,minAngle:0,minShowLabelAngle:0,selectedOffset:10,percentPrecision:2,stillShowZeroSum:!0,left:0,top:0,right:0,bottom:0,width:null,height:null,label:{rotate:0,show:!0,overflow:"truncate",position:"outer",alignTo:"none",edgeDistance:"25%",bleedMargin:10,distanceToLabelLine:5},labelLine:{show:!0,length:15,length2:15,smooth:!1,minTurnAngle:90,maxSurfaceAngle:90,lineStyle:{width:1,type:"solid"}},itemStyle:{borderWidth:1,borderJoin:"round"},showEmptyCircle:!0,emptyCircleStyle:{color:"lightgray",opacity:1},labelLayout:{hideOverlap:!0},emphasis:{scale:!0,scaleSize:5},avoidLabelOverlap:!0,animationType:"expansion",animationDuration:1e3,animationTypeUpdate:"transition",animationEasingUpdate:"cubicInOut",animationDurationUpdate:500,animationEasing:"cubicInOut"},e}(bg);var VM=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.hasSymbolVisual=!0,n}return n(e,t),e.prototype.getInitialData=function(t,e){return _x(null,this,{useEncodeDefaulter:!0})},e.prototype.getProgressive=function(){var t=this.option.progressive;return null==t?this.option.large?5e3:this.get("progressive"):t},e.prototype.getProgressiveThreshold=function(){var t=this.option.progressiveThreshold;return null==t?this.option.large?1e4:this.get("progressiveThreshold"):t},e.prototype.brushSelector=function(t,e,n){return n.point(e.getItemLayout(t))},e.prototype.getZLevelKey=function(){return this.getData().count()>this.getProgressiveThreshold()?this.id:""},e.type="series.scatter",e.dependencies=["grid","polar","geo","singleAxis","calendar"],e.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"}},e}(bg),BM=function(){},FM=function(t){function e(e){var n=t.call(this,e)||this;return n._off=0,n.hoverDataIdx=-1,n}return n(e,t),e.prototype.getDefaultShape=function(){return new BM},e.prototype.reset=function(){this.notClear=!1,this._off=0},e.prototype.buildPath=function(t,e){var n,i=e.points,r=e.size,o=this.symbolProxy,a=o.shape,s=t.getContext?t.getContext():t,l=s&&r[0]<4,u=this.softClipShape;if(l)this._ctx=s;else{for(this._ctx=null,n=this._off;n=0;s--){var l=2*s,u=i[l]-o/2,h=i[l+1]-a/2;if(t>=u&&e>=h&&t<=u+o&&e<=h+a)return s}return-1},e.prototype.contain=function(t,e){var n=this.transformCoordToLocal(t,e),i=this.getBoundingRect();return t=n[0],e=n[1],i.contain(t,e)?(this.hoverDataIdx=this.findDataIndex(t,e))>=0:(this.hoverDataIdx=-1,!1)},e.prototype.getBoundingRect=function(){var t=this._rect;if(!t){for(var e=this.shape,n=e.points,i=e.size,r=i[0],o=i[1],a=1/0,s=1/0,l=-1/0,u=-1/0,h=0;h=0&&(l.dataIndex=n+(t.startIndex||0))}))},t.prototype.remove=function(){this._clear()},t.prototype._clear=function(){this._newAdded=[],this.group.removeAll()},t}(),WM=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){var i=t.getData();this._updateSymbolDraw(i,t).updateData(i,{clipShape:this._getClipShape(t)}),this._finished=!0},e.prototype.incrementalPrepareRender=function(t,e,n){var i=t.getData();this._updateSymbolDraw(i,t).incrementalPrepareUpdate(i),this._finished=!1},e.prototype.incrementalRender=function(t,e,n){this._symbolDraw.incrementalUpdate(t,e.getData(),{clipShape:this._getClipShape(e)}),this._finished=t.end===e.getData().count()},e.prototype.updateTransform=function(t,e,n){var i=t.getData();if(this.group.dirty(),!this._finished||i.count()>1e4)return{update:!0};var r=XS("").reset(t,e,n);r.progress&&r.progress({start:0,end:i.count(),count:i.count()},i),this._symbolDraw.updateLayout(i)},e.prototype.eachRendered=function(t){this._symbolDraw&&this._symbolDraw.eachRendered(t)},e.prototype._getClipShape=function(t){if(t.get("clip",!0)){var e=t.coordinateSystem;return e&&e.getArea&&e.getArea(.1)}},e.prototype._updateSymbolDraw=function(t,e){var n=this._symbolDraw,i=e.pipelineContext.large;return n&&i===this._isLargeDraw||(n&&n.remove(),n=this._symbolDraw=i?new GM:new xS,this._isLargeDraw=i,this.group.removeAll()),this.group.add(n.group),n},e.prototype.remove=function(t,e){this._symbolDraw&&this._symbolDraw.remove(!0),this._symbolDraw=null},e.prototype.dispose=function(){},e.type="scatter",e}(Og),HM=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.type="grid",e.dependencies=["xAxis","yAxis"],e.layoutMode="box",e.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"},e}(zp),YM=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.getCoordSysModel=function(){return this.getReferringComponents("grid",Wo).models[0]},e.type="cartesian2dAxis",e}(zp);R(YM,D_);var XM={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,showMinLine:!0,showMaxLine:!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)"]}}},UM=C({boundaryGap:!0,deduplication:null,splitLine:{show:!1},axisTick:{alignWithLabel:!1,interval:"auto"},axisLabel:{interval:"auto"}},XM),ZM=C({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}}},XM),jM={category:UM,value:ZM,time:C({splitNumber:6,axisLabel:{showMinLabel:!1,showMaxLabel:!1,rich:{primary:{fontWeight:"bold"}}},splitLine:{show:!1}},ZM),log:k({logBase:10},ZM)},qM={value:1,category:1,time:1,log:1};function KM(t,e,i,r){E(qM,(function(o,a){var s=C(C({},jM[a],!0),r,!0),l=function(t){function i(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e+"Axis."+a,n}return n(i,t),i.prototype.mergeDefaultAndTheme=function(t,e){var n=Pp(this),i=n?Rp(t):{};C(t,e.getTheme().get(a+"Axis")),C(t,this.getDefaultOption()),t.type=$M(t),n&&Op(t,i,n)},i.prototype.optionUpdated=function(){"category"===this.option.type&&(this.__ordinalMeta=Mx.createByAxisModel(this))},i.prototype.getCategories=function(t){var e=this.option;if("category"===e.type)return t?e.data:this.__ordinalMeta.categories},i.prototype.getOrdinalMeta=function(){return this.__ordinalMeta},i.type=e+"Axis."+a,i.defaultOption=s,i}(i);t.registerComponentModel(l)})),t.registerSubTypeDefaulter(e+"Axis",$M)}function $M(t){return t.type||(t.data?"category":"value")}var JM=function(){function t(t){this.type="cartesian",this._dimList=[],this._axes={},this.name=t||""}return t.prototype.getAxis=function(t){return this._axes[t]},t.prototype.getAxes=function(){return z(this._dimList,(function(t){return this._axes[t]}),this)},t.prototype.getAxesByScale=function(t){return t=t.toLowerCase(),B(this.getAxes(),(function(e){return e.scale.type===t}))},t.prototype.addAxis=function(t){var e=t.dim;this._axes[e]=t,this._dimList.push(e)},t}(),QM=["x","y"];function tI(t){return"interval"===t.type||"time"===t.type}var eI=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.type="cartesian2d",e.dimensions=QM,e}return n(e,t),e.prototype.calcAffineTransform=function(){this._transform=this._invTransform=null;var t=this.getAxis("x").scale,e=this.getAxis("y").scale;if(tI(t)&&tI(e)){var n=t.getExtent(),i=e.getExtent(),r=this.dataToPoint([n[0],i[0]]),o=this.dataToPoint([n[1],i[1]]),a=n[1]-n[0],s=i[1]-i[0];if(a&&s){var l=(o[0]-r[0])/a,u=(o[1]-r[1])/s,h=r[0]-n[0]*l,c=r[1]-i[0]*u,p=this._transform=[l,0,0,u,h,c];this._invTransform=Ie([],p)}}},e.prototype.getBaseAxis=function(){return this.getAxesByScale("ordinal")[0]||this.getAxesByScale("time")[0]||this.getAxis("x")},e.prototype.containPoint=function(t){var e=this.getAxis("x"),n=this.getAxis("y");return e.contain(e.toLocalCoord(t[0]))&&n.contain(n.toLocalCoord(t[1]))},e.prototype.containData=function(t){return this.getAxis("x").containData(t[0])&&this.getAxis("y").containData(t[1])},e.prototype.containZone=function(t,e){var n=this.dataToPoint(t),i=this.dataToPoint(e),r=this.getArea(),o=new ze(n[0],n[1],i[0]-n[0],i[1]-n[1]);return r.intersect(o)},e.prototype.dataToPoint=function(t,e,n){n=n||[];var i=t[0],r=t[1];if(this._transform&&null!=i&&isFinite(i)&&null!=r&&isFinite(r))return Wt(n,t,this._transform);var o=this.getAxis("x"),a=this.getAxis("y");return n[0]=o.toGlobalCoord(o.dataToCoord(i,e)),n[1]=a.toGlobalCoord(a.dataToCoord(r,e)),n},e.prototype.clampData=function(t,e){var n=this.getAxis("x").scale,i=this.getAxis("y").scale,r=n.getExtent(),o=i.getExtent(),a=n.parse(t[0]),s=i.parse(t[1]);return(e=e||[])[0]=Math.min(Math.max(Math.min(r[0],r[1]),a),Math.max(r[0],r[1])),e[1]=Math.min(Math.max(Math.min(o[0],o[1]),s),Math.max(o[0],o[1])),e},e.prototype.pointToData=function(t,e){var n=[];if(this._invTransform)return Wt(n,t,this._invTransform);var i=this.getAxis("x"),r=this.getAxis("y");return n[0]=i.coordToData(i.toLocalCoord(t[0]),e),n[1]=r.coordToData(r.toLocalCoord(t[1]),e),n},e.prototype.getOtherAxis=function(t){return this.getAxis("x"===t.dim?"y":"x")},e.prototype.getArea=function(t){t=t||0;var e=this.getAxis("x").getGlobalExtent(),n=this.getAxis("y").getGlobalExtent(),i=Math.min(e[0],e[1])-t,r=Math.min(n[0],n[1])-t,o=Math.max(e[0],e[1])-i+t,a=Math.max(n[0],n[1])-r+t;return new ze(i,r,o,a)},e}(JM),nI=function(t){function e(e,n,i,r,o){var a=t.call(this,e,n,i)||this;return a.index=0,a.type=r||"value",a.position=o||"bottom",a}return n(e,t),e.prototype.isHorizontal=function(){var t=this.position;return"top"===t||"bottom"===t},e.prototype.getGlobalExtent=function(t){var e=this.getExtent();return e[0]=this.toGlobalCoord(e[0]),e[1]=this.toGlobalCoord(e[1]),t&&e[0]>e[1]&&e.reverse(),e},e.prototype.pointToData=function(t,e){return this.coordToData(this.toLocalCoord(t["x"===this.dim?0:1]),e)},e.prototype.setCategorySortInfo=function(t){if("category"!==this.type)return!1;this.model.option.categorySortInfo=t,this.scale.setSortInfo(t)},e}(ab);function iI(t,e,n){n=n||{};var i=t.coordinateSystem,r=e.axis,o={},a=r.getAxesOnZeroOf()[0],s=r.position,l=a?"onZero":s,u=r.dim,h=i.getRect(),c=[h.x,h.x+h.width,h.y,h.y+h.height],p={left:0,right:1,top:0,bottom:1,onZero:2},d=e.get("offset")||0,f="x"===u?[c[2]-d,c[3]+d]:[c[0]-d,c[1]+d];if(a){var g=a.toGlobalCoord(a.dataToCoord(0));f[p.onZero]=Math.max(Math.min(g,f[1]),f[0])}o.position=["y"===u?f[p[l]]:c[0],"x"===u?f[p[l]]:c[3]],o.rotation=Math.PI/2*("x"===u?0:1);o.labelDirection=o.tickDirection=o.nameDirection={top:-1,bottom:1,left:-1,right:1}[s],o.labelOffset=a?f[p[s]]-f[p.onZero]:0,e.get(["axisTick","inside"])&&(o.tickDirection=-o.tickDirection),it(n.labelInside,e.get(["axisLabel","inside"]))&&(o.labelDirection=-o.labelDirection);var y=e.get(["axisLabel","rotate"]);return o.labelRotate="top"===l?-y:y,o.z2=1,o}function rI(t){return"cartesian2d"===t.get("coordinateSystem")}function oI(t){var e={xAxisModel:null,yAxisModel:null};return E(e,(function(n,i){var r=i.replace(/Model$/,""),o=t.getReferringComponents(r,Wo).models[0];e[i]=o})),e}var aI=Math.log;function sI(t,e,n){var i=Ex.prototype,r=i.getTicks.call(n),o=i.getTicks.call(n,!0),a=r.length-1,s=i.getInterval.call(n),l=x_(t,e),u=l.extent,h=l.fixMin,c=l.fixMax;if("log"===t.type){var p=aI(t.base);u=[aI(u[0])/p,aI(u[1])/p]}t.setExtent(u[0],u[1]),t.calcNiceExtent({splitNumber:a,fixMin:h,fixMax:c});var d=i.getExtent.call(t);h&&(u[0]=d[0]),c&&(u[1]=d[1]);var f=i.getInterval.call(t),g=u[0],y=u[1];if(h&&c)f=(y-g)/a;else if(h)for(y=u[0]+f*a;yu[0]&&isFinite(g)&&isFinite(u[0]);)f=Dx(f),g=u[1]-f*a;else{t.getTicks().length-1>a&&(f=Dx(f));var v=f*a;(g=Jr((y=Math.ceil(u[1]/f)*f)-v))<0&&u[0]>=0?(g=0,y=Jr(v)):y>0&&u[1]<=0&&(y=0,g=-Jr(v))}var m=(r[0].value-o[0].value)/s,x=(r[a].value-o[a].value)/s;i.setExtent.call(t,g+f*m,y+f*x),i.setInterval.call(t,f),(m||x)&&i.setNiceExtent.call(t,g+f,y-f)}var lI=function(){function t(t,e,n){this.type="grid",this._coordsMap={},this._coordsList=[],this._axesMap={},this._axesList=[],this.axisPointerEnabled=!0,this.dimensions=QM,this._initCartesian(t,e,n),this.model=t}return t.prototype.getRect=function(){return this._rect},t.prototype.update=function(t,e){var n=this._axesMap;function i(t){var e,n=G(t),i=n.length;if(i){for(var r=[],o=i-1;o>=0;o--){var a=t[+n[o]],s=a.model,l=a.scale;Tx(l)&&s.get("alignTicks")&&null==s.get("interval")?r.push(a):(__(l,s),Tx(l)&&(e=a))}r.length&&(e||__((e=r.pop()).scale,e.model),E(r,(function(t){sI(t.scale,t.model,e.scale)})))}}this._updateScale(t,this.model),i(n.x),i(n.y);var r={};E(n.x,(function(t){hI(n,"y",t,r)})),E(n.y,(function(t){hI(n,"x",t,r)})),this.resize(this.model,e)},t.prototype.resize=function(t,e,n){var i=t.getBoxLayoutParams(),r=!n&&t.get("containLabel"),o=kp(i,{width:e.getWidth(),height:e.getHeight()});this._rect=o;var a=this._axesList;function s(){E(a,(function(t){var e=t.isHorizontal(),n=e?[0,o.width]:[0,o.height],i=t.inverse?1:0;t.setExtent(n[i],n[1-i]),function(t,e){var n=t.getExtent(),i=n[0]+n[1];t.toGlobalCoord="x"===t.dim?function(t){return t+e}:function(t){return i-t+e},t.toLocalCoord="x"===t.dim?function(t){return t-e}:function(t){return i-t+e}}(t,e?o.x:o.y)}))}s(),r&&(E(a,(function(t){if(!t.model.get(["axisLabel","inside"])){var e=function(t){var e=t.model,n=t.scale;if(e.get(["axisLabel","show"])&&!n.isBlank()){var i,r,o=n.getExtent();r=n instanceof Rx?n.count():(i=n.getTicks()).length;var a,s=t.getLabelModel(),l=w_(t),u=1;r>40&&(u=Math.ceil(r/40));for(var h=0;h0&&i>0||n<0&&i<0)}(t)}var pI=Math.PI,dI=function(){function t(t,e){this.group=new Br,this.opt=e,this.axisModel=t,k(e,{labelOffset:0,nameDirection:1,tickDirection:1,labelDirection:1,silent:!0,handleAutoShown:function(){return!0}});var n=new Br({x:e.position[0],y:e.position[1],rotation:e.rotation});n.updateTransform(),this._transformGroup=n}return t.prototype.hasBuilder=function(t){return!!fI[t]},t.prototype.add=function(t){fI[t](this.opt,this.axisModel,this.group,this._transformGroup)},t.prototype.getGroup=function(){return this.group},t.innerTextLayout=function(t,e,n){var i,r,o=ao(e-t);return so(o)?(r=n>0?"top":"bottom",i="center"):so(o-pI)?(r=n>0?"bottom":"top",i="center"):(r="middle",i=o>0&&o0?"right":"left":n>0?"left":"right"),{rotation:o,textAlign:i,textVerticalAlign:r}},t.makeAxisEventDataBase=function(t){var e={componentType:t.mainType,componentIndex:t.componentIndex};return e[t.mainType+"Index"]=t.componentIndex,e},t.isLabelSilent=function(t){var e=t.get("tooltip");return t.get("silent")||!(t.get("triggerEvent")||e&&e.show)},t}(),fI={axisLine:function(t,e,n,i){var r=e.get(["axisLine","show"]);if("auto"===r&&t.handleAutoShown&&(r=t.handleAutoShown("axisLine")),r){var o=e.axis.getExtent(),a=i.transform,s=[o[0],0],l=[o[1],0],u=s[0]>l[0];a&&(Wt(s,s,a),Wt(l,l,a));var h=A({lineCap:"round"},e.getModel(["axisLine","lineStyle"]).getLineStyle()),c=new Ku({shape:{x1:s[0],y1:s[1],x2:l[0],y2:l[1]},style:h,strokeContainThreshold:t.strokeContainThreshold||5,silent:!0,z2:1});zh(c.shape,c.style.lineWidth),c.anid="line",n.add(c);var p=e.get(["axisLine","symbol"]);if(null!=p){var d=e.get(["axisLine","symbolSize"]);U(p)&&(p=[p,p]),(U(d)||j(d))&&(d=[d,d]);var f=Zy(e.get(["axisLine","symbolOffset"])||0,d),g=d[0],y=d[1];E([{rotate:t.rotation+Math.PI/2,offset:f[0],r:0},{rotate:t.rotation-Math.PI/2,offset:f[1],r:Math.sqrt((s[0]-l[0])*(s[0]-l[0])+(s[1]-l[1])*(s[1]-l[1]))}],(function(e,i){if("none"!==p[i]&&null!=p[i]){var r=Xy(p[i],-g/2,-y/2,g,y,h.stroke,!0),o=e.r+e.offset,a=u?l:s;r.attr({rotation:e.rotate,x:a[0]+o*Math.cos(t.rotation),y:a[1]-o*Math.sin(t.rotation),silent:!0,z2:11}),n.add(r)}}))}}},axisTickLabel:function(t,e,n,i){var r=function(t,e,n,i){var r=n.axis,o=n.getModel("axisTick"),a=o.get("show");"auto"===a&&i.handleAutoShown&&(a=i.handleAutoShown("axisTick"));if(!a||r.scale.isBlank())return;for(var s=o.getModel("lineStyle"),l=i.tickDirection*o.get("length"),u=mI(r.getTicksCoords(),e.transform,l,k(s.getLineStyle(),{stroke:n.get(["axisLine","lineStyle","color"])}),"ticks"),h=0;hc[1]?-1:1,d=["start"===s?c[0]-p*h:"end"===s?c[1]+p*h:(c[0]+c[1])/2,vI(s)?t.labelOffset+l*h:0],f=e.get("nameRotate");null!=f&&(f=f*pI/180),vI(s)?o=dI.innerTextLayout(t.rotation,null!=f?f:t.rotation,l):(o=function(t,e,n,i){var r,o,a=ao(n-t),s=i[0]>i[1],l="start"===e&&!s||"start"!==e&&s;so(a-pI/2)?(o=l?"bottom":"top",r="center"):so(a-1.5*pI)?(o=l?"top":"bottom",r="center"):(o="middle",r=a<1.5*pI&&a>pI/2?l?"left":"right":l?"right":"left");return{rotation:a,textAlign:r,textVerticalAlign:o}}(t.rotation,s,f||0,c),null!=(a=t.axisNameAvailableWidth)&&(a=Math.abs(a/Math.sin(o.rotation)),!isFinite(a)&&(a=null)));var g=u.getFont(),y=e.get("nameTruncate",!0)||{},v=y.ellipsis,m=it(t.nameTruncateMaxWidth,y.maxWidth,a),x=new Xs({x:d[0],y:d[1],rotation:o.rotation,silent:dI.isLabelSilent(e),style:oc(u,{text:r,font:g,overflow:"truncate",width:m,ellipsis:v,fill:u.getTextColor()||e.get(["axisLine","lineStyle","color"]),align:u.get("align")||o.textAlign,verticalAlign:u.get("verticalAlign")||o.textVerticalAlign}),z2:1});if(Kh({el:x,componentModel:e,itemName:r}),x.__fullText=r,x.anid="name",e.get("triggerEvent")){var _=dI.makeAxisEventDataBase(e);_.targetType="axisName",_.name=r,rl(x).eventData=_}i.add(x),x.updateTransform(),n.add(x),x.decomposeTransform()}}};function gI(t){t&&(t.ignore=!0)}function yI(t,e){var n=t&&t.getBoundingRect().clone(),i=e&&e.getBoundingRect().clone();if(n&&i){var r=xe([]);return Se(r,r,-t.rotation),n.applyTransform(be([],r,t.getLocalTransform())),i.applyTransform(be([],r,e.getLocalTransform())),n.intersect(i)}}function vI(t){return"middle"===t||"center"===t}function mI(t,e,n,i,r){for(var o=[],a=[],s=[],l=0;l=0||t===e}function bI(t){var e=wI(t);if(e){var n=e.axisPointerModel,i=e.axis.scale,r=n.option,o=n.get("status"),a=n.get("value");null!=a&&(a=i.parse(a));var s=SI(n);null==o&&(r.status=s?"show":"hide");var l=i.getExtent().slice();l[0]>l[1]&&l.reverse(),(null==a||a>l[1])&&(a=l[1]),a0&&!c.min?c.min=0:null!=c.min&&c.min<0&&!c.max&&(c.max=0);var p=a;null!=c.color&&(p=k({color:c.color},a));var d=C(T(c),{boundaryGap:t,splitNumber:e,scale:n,axisLine:i,axisTick:r,axisLabel:o,name:c.text,showName:s,nameLocation:"end",nameGap:u,nameTextStyle:p,triggerEvent:h},!1);if(U(l)){var f=d.name;d.name=l.replace("{value}",null!=f?f:"")}else X(l)&&(d.name=l(d.name,d));var g=new Cc(d,null,this.ecModel);return R(g,D_.prototype),g.mainType="radar",g.componentIndex=this.componentIndex,g}),this);this._indicatorModels=c},e.prototype.getIndicatorModels=function(){return this._indicatorModels},e.type="radar",e.defaultOption={z:0,center:["50%","50%"],radius:"75%",startAngle:90,axisName:{show:!0},boundaryGap:[0,0],splitNumber:5,axisNameGap:15,scale:!1,shape:"polygon",axisLine:C({lineStyle:{color:"#bbb"}},XI.axisLine),axisLabel:UI(XI.axisLabel,!1),axisTick:UI(XI.axisTick,!1),splitLine:UI(XI.splitLine,!0),splitArea:UI(XI.splitArea,!0),indicator:[]},e}(zp),jI=["axisLine","axisTickLabel","axisName"],qI=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){this.group.removeAll(),this._buildAxes(t),this._buildSplitLineAndArea(t)},e.prototype._buildAxes=function(t){var e=t.coordinateSystem;E(z(e.getIndicatorAxes(),(function(t){var n=t.model.get("showName")?t.name:"";return new dI(t.model,{axisName:n,position:[e.cx,e.cy],rotation:t.angle,labelDirection:-1,tickDirection:-1,nameDirection:1})})),(function(t){E(jI,t.add,t),this.group.add(t.getGroup())}),this)},e.prototype._buildSplitLineAndArea=function(t){var e=t.coordinateSystem,n=e.getIndicatorAxes();if(n.length){var i=t.get("shape"),r=t.getModel("splitLine"),o=t.getModel("splitArea"),a=r.getModel("lineStyle"),s=o.getModel("areaStyle"),l=r.get("show"),u=o.get("show"),h=a.get("color"),c=s.get("color"),p=Y(h)?h:[h],d=Y(c)?c:[c],f=[],g=[];if("circle"===i)for(var y=n[0].getTicksCoords(),v=e.cx,m=e.cy,x=0;x3?1.4:r>1?1.2:1.1;iT(this,"zoom","zoomOnMouseWheel",t,{scale:i>0?s:1/s,originX:o,originY:a,isAvailableBehavior:null})}if(n){var l=Math.abs(i);iT(this,"scrollMove","moveOnMouseWheel",t,{scrollDelta:(i>0?1:-1)*(l>3?.4:l>1?.15:.05),originX:o,originY:a,isAvailableBehavior:null})}}},e.prototype._pinchHandler=function(t){tT(this._zr,"globalPan")||iT(this,"zoom",null,t,{scale:t.pinchScale>1?1.1:1/1.1,originX:t.pinchX,originY:t.pinchY,isAvailableBehavior:null})},e}(jt);function iT(t,e,n,i,r){t.pointerChecker&&t.pointerChecker(i,r.originX,r.originY)&&(de(i.event),rT(t,e,n,i,r))}function rT(t,e,n,i,r){r.isAvailableBehavior=W(oT,null,n,i),t.trigger(e,r)}function oT(t,e,n){var i=n[t];return!t||i&&(!U(i)||e.event[i+"Key"])}function aT(t,e,n){var i=t.target;i.x+=e,i.y+=n,i.dirty()}function sT(t,e,n,i){var r=t.target,o=t.zoomLimit,a=t.zoom=t.zoom||1;if(a*=e,o){var s=o.min||0,l=o.max||1/0;a=Math.max(Math.min(l,a),s)}var u=a/t.zoom;t.zoom=a,r.x-=(n-r.x)*(u-1),r.y-=(i-r.y)*(u-1),r.scaleX*=u,r.scaleY*=u,r.dirty()}var lT,uT={axisPointer:1,tooltip:1,brush:1};function hT(t,e,n){var i=e.getComponentByElement(t.topTarget),r=i&&i.coordinateSystem;return i&&i!==n&&!uT.hasOwnProperty(i.mainType)&&r&&r.model!==n}function cT(t){U(t)&&(t=(new DOMParser).parseFromString(t,"text/xml"));var e=t;for(9===e.nodeType&&(e=e.firstChild);"svg"!==e.nodeName.toLowerCase()||1!==e.nodeType;)e=e.nextSibling;return e}var pT={fill:"fill",stroke:"stroke","stroke-width":"lineWidth",opacity:"opacity","fill-opacity":"fillOpacity","stroke-opacity":"strokeOpacity","stroke-dasharray":"lineDash","stroke-dashoffset":"lineDashOffset","stroke-linecap":"lineCap","stroke-linejoin":"lineJoin","stroke-miterlimit":"miterLimit","font-family":"fontFamily","font-size":"fontSize","font-style":"fontStyle","font-weight":"fontWeight","text-anchor":"textAlign",visibility:"visibility",display:"display"},dT=G(pT),fT={"alignment-baseline":"textBaseline","stop-color":"stopColor"},gT=G(fT),yT=function(){function t(){this._defs={},this._root=null}return t.prototype.parse=function(t,e){e=e||{};var n=cT(t);this._defsUsePending=[];var i=new Br;this._root=i;var r=[],o=n.getAttribute("viewBox")||"",a=parseFloat(n.getAttribute("width")||e.width),s=parseFloat(n.getAttribute("height")||e.height);isNaN(a)&&(a=null),isNaN(s)&&(s=null),wT(n,i,null,!0,!1);for(var l,u,h=n.firstChild;h;)this._parseNode(h,i,r,null,!1,!1),h=h.nextSibling;if(function(t,e){for(var n=0;n=4&&(l={x:parseFloat(c[0]||0),y:parseFloat(c[1]||0),width:parseFloat(c[2]),height:parseFloat(c[3])})}if(l&&null!=a&&null!=s&&(u=LT(l,{x:0,y:0,width:a,height:s}),!e.ignoreViewBox)){var p=i;(i=new Br).add(p),p.scaleX=p.scaleY=u.scale,p.x=u.x,p.y=u.y}return e.ignoreRootClip||null==a||null==s||i.setClipPath(new Ws({shape:{x:0,y:0,width:a,height:s}})),{root:i,width:a,height:s,viewBoxRect:l,viewBoxTransform:u,named:r}},t.prototype._parseNode=function(t,e,n,i,r,o){var a,s=t.nodeName.toLowerCase(),l=i;if("defs"===s&&(r=!0),"text"===s&&(o=!0),"defs"===s||"switch"===s)a=e;else{if(!r){var u=lT[s];if(u&&_t(lT,s)){a=u.call(this,t,e);var h=t.getAttribute("name");if(h){var c={name:h,namedFrom:null,svgNodeTagLower:s,el:a};n.push(c),"g"===s&&(l=c)}else i&&n.push({name:i.name,namedFrom:i,svgNodeTagLower:s,el:a});e.add(a)}}var p=vT[s];if(p&&_t(vT,s)){var d=p.call(this,t),f=t.getAttribute("id");f&&(this._defs[f]=d)}}if(a&&a.isGroup)for(var g=t.firstChild;g;)1===g.nodeType?this._parseNode(g,a,n,l,r,o):3===g.nodeType&&o&&this._parseText(g,a),g=g.nextSibling},t.prototype._parseText=function(t,e){var n=new Ps({style:{text:t.textContent},silent:!0,x:this._textX||0,y:this._textY||0});_T(e,n),wT(t,n,this._defsUsePending,!1,!1),function(t,e){var n=e.__selfStyle;if(n){var i=n.textBaseline,r=i;i&&"auto"!==i?"baseline"===i?r="alphabetic":"before-edge"===i||"text-before-edge"===i?r="top":"after-edge"===i||"text-after-edge"===i?r="bottom":"central"!==i&&"mathematical"!==i||(r="middle"):r="alphabetic",t.style.textBaseline=r}var o=e.__inheritedStyle;if(o){var a=o.textAlign,s=a;a&&("middle"===a&&(s="center"),t.style.textAlign=s)}}(n,e);var i=n.style,r=i.fontSize;r&&r<9&&(i.fontSize=9,n.scaleX*=r/9,n.scaleY*=r/9);var o=(i.fontSize||i.fontFamily)&&[i.fontStyle,i.fontWeight,(i.fontSize||12)+"px",i.fontFamily||"sans-serif"].join(" ");i.font=o;var a=n.getBoundingRect();return this._textX+=a.width,e.add(n),n},t.internalField=void(lT={g:function(t,e){var n=new Br;return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n},rect:function(t,e){var n=new Ws;return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n.setShape({x:parseFloat(t.getAttribute("x")||"0"),y:parseFloat(t.getAttribute("y")||"0"),width:parseFloat(t.getAttribute("width")||"0"),height:parseFloat(t.getAttribute("height")||"0")}),n.silent=!0,n},circle:function(t,e){var n=new Su;return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n.setShape({cx:parseFloat(t.getAttribute("cx")||"0"),cy:parseFloat(t.getAttribute("cy")||"0"),r:parseFloat(t.getAttribute("r")||"0")}),n.silent=!0,n},line:function(t,e){var n=new Ku;return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n.setShape({x1:parseFloat(t.getAttribute("x1")||"0"),y1:parseFloat(t.getAttribute("y1")||"0"),x2:parseFloat(t.getAttribute("x2")||"0"),y2:parseFloat(t.getAttribute("y2")||"0")}),n.silent=!0,n},ellipse:function(t,e){var n=new Iu;return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n.setShape({cx:parseFloat(t.getAttribute("cx")||"0"),cy:parseFloat(t.getAttribute("cy")||"0"),rx:parseFloat(t.getAttribute("rx")||"0"),ry:parseFloat(t.getAttribute("ry")||"0")}),n.silent=!0,n},polygon:function(t,e){var n,i=t.getAttribute("points");i&&(n=bT(i));var r=new Xu({shape:{points:n||[]},silent:!0});return _T(e,r),wT(t,r,this._defsUsePending,!1,!1),r},polyline:function(t,e){var n,i=t.getAttribute("points");i&&(n=bT(i));var r=new Zu({shape:{points:n||[]},silent:!0});return _T(e,r),wT(t,r,this._defsUsePending,!1,!1),r},image:function(t,e){var n=new Ns;return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n.setStyle({image:t.getAttribute("xlink:href")||t.getAttribute("href"),x:+t.getAttribute("x"),y:+t.getAttribute("y"),width:+t.getAttribute("width"),height:+t.getAttribute("height")}),n.silent=!0,n},text:function(t,e){var n=t.getAttribute("x")||"0",i=t.getAttribute("y")||"0",r=t.getAttribute("dx")||"0",o=t.getAttribute("dy")||"0";this._textX=parseFloat(n)+parseFloat(r),this._textY=parseFloat(i)+parseFloat(o);var a=new Br;return _T(e,a),wT(t,a,this._defsUsePending,!1,!0),a},tspan:function(t,e){var n=t.getAttribute("x"),i=t.getAttribute("y");null!=n&&(this._textX=parseFloat(n)),null!=i&&(this._textY=parseFloat(i));var r=t.getAttribute("dx")||"0",o=t.getAttribute("dy")||"0",a=new Br;return _T(e,a),wT(t,a,this._defsUsePending,!1,!0),this._textX+=parseFloat(r),this._textY+=parseFloat(o),a},path:function(t,e){var n=_u(t.getAttribute("d")||"");return _T(e,n),wT(t,n,this._defsUsePending,!1,!1),n.silent=!0,n}}),t}(),vT={lineargradient:function(t){var e=parseInt(t.getAttribute("x1")||"0",10),n=parseInt(t.getAttribute("y1")||"0",10),i=parseInt(t.getAttribute("x2")||"10",10),r=parseInt(t.getAttribute("y2")||"0",10),o=new oh(e,n,i,r);return mT(t,o),xT(t,o),o},radialgradient:function(t){var e=parseInt(t.getAttribute("cx")||"0",10),n=parseInt(t.getAttribute("cy")||"0",10),i=parseInt(t.getAttribute("r")||"0",10),r=new ah(e,n,i);return mT(t,r),xT(t,r),r}};function mT(t,e){"userSpaceOnUse"===t.getAttribute("gradientUnits")&&(e.global=!0)}function xT(t,e){for(var n=t.firstChild;n;){if(1===n.nodeType&&"stop"===n.nodeName.toLocaleLowerCase()){var i=n.getAttribute("offset"),r=void 0;r=i&&i.indexOf("%")>0?parseInt(i,10)/100:i?parseFloat(i):0;var o={};kT(n,o,o);var a=o.stopColor||n.getAttribute("stop-color")||"#000000";e.colorStops.push({offset:r,color:a})}n=n.nextSibling}}function _T(t,e){t&&t.__inheritedStyle&&(e.__inheritedStyle||(e.__inheritedStyle={}),k(e.__inheritedStyle,t.__inheritedStyle))}function bT(t){for(var e=TT(t),n=[],i=0;i0;o-=2){var a=i[o],s=i[o-1],l=TT(a);switch(r=r||[1,0,0,1,0,0],s){case"translate":we(r,r,[parseFloat(l[0]),parseFloat(l[1]||"0")]);break;case"scale":Me(r,r,[parseFloat(l[0]),parseFloat(l[1]||l[0])]);break;case"rotate":Se(r,r,-parseFloat(l[0])*DT,[parseFloat(l[1]||"0"),parseFloat(l[2]||"0")]);break;case"skewX":be(r,[1,0,Math.tan(parseFloat(l[0])*DT),1,0,0],r);break;case"skewY":be(r,[1,Math.tan(parseFloat(l[0])*DT),0,1,0,0],r);break;case"matrix":r[0]=parseFloat(l[0]),r[1]=parseFloat(l[1]),r[2]=parseFloat(l[2]),r[3]=parseFloat(l[3]),r[4]=parseFloat(l[4]),r[5]=parseFloat(l[5])}}e.setLocalTransform(r)}}(t,e),kT(t,a,s),i||function(t,e,n){for(var i=0;i0,f={api:n,geo:s,mapOrGeoModel:t,data:a,isVisualEncodedByVisualMap:d,isGeo:o,transformInfoRaw:c};"geoJSON"===s.resourceType?this._buildGeoJSON(f):"geoSVG"===s.resourceType&&this._buildSVG(f),this._updateController(t,e,n),this._updateMapSelectHandler(t,l,n,i)},t.prototype._buildGeoJSON=function(t){var e=this._regionsGroupByName=yt(),n=yt(),i=this._regionsGroup,r=t.transformInfoRaw,o=t.mapOrGeoModel,a=t.data,s=t.geo.projection,l=s&&s.stream;function u(t,e){return e&&(t=e(t)),t&&[t[0]*r.scaleX+r.x,t[1]*r.scaleY+r.y]}function h(t){for(var e=[],n=!l&&s&&s.project,i=0;i=0)&&(p=r);var d=a?{normal:{align:"center",verticalAlign:"middle"}}:null;ic(e,rc(i),{labelFetcher:p,labelDataIndex:c,defaultText:n},d);var f=e.getTextContent();if(f&&(JT(f).ignore=f.ignore,e.textConfig&&a)){var g=e.getBoundingRect().clone();e.textConfig.layoutRect=g,e.textConfig.position=[(a[0]-g.x)/g.width*100+"%",(a[1]-g.y)/g.height*100+"%"]}e.disableLabelAnimation=!0}else e.removeTextContent(),e.removeTextConfig(),e.disableLabelAnimation=null}function rC(t,e,n,i,r,o){t.data?t.data.setItemGraphicEl(o,e):rl(e).eventData={componentType:"geo",componentIndex:r.componentIndex,geoIndex:r.componentIndex,name:n,region:i&&i.option||{}}}function oC(t,e,n,i,r){t.data||Kh({el:e,componentModel:r,itemName:n,itemTooltipOption:i.get("tooltip")})}function aC(t,e,n,i,r){e.highDownSilentOnTouch=!!r.get("selectedMode");var o=i.getModel("emphasis"),a=o.get("focus");return Zl(e,a,o.get("blurScope"),o.get("disabled")),t.isGeo&&function(t,e,n){var i=rl(t);i.componentMainType=e.mainType,i.componentIndex=e.componentIndex,i.componentHighDownName=n}(e,r,n),a}function sC(t,e,n){var i,r=[];function o(){i=[]}function a(){i.length&&(r.push(i),i=[])}var s=e({polygonStart:o,polygonEnd:a,lineStart:o,lineEnd:a,point:function(t,e){isFinite(t)&&isFinite(e)&&i.push([t,e])},sphere:function(){}});return!n&&s.polygonStart(),E(t,(function(t){s.lineStart();for(var e=0;e-1&&(n.style.stroke=n.style.fill,n.style.fill="#fff",n.style.lineWidth=2),n},e.type="series.map",e.dependencies=["geo"],e.layoutMode="box",e.defaultOption={z:2,coordinateSystem:"geo",map:"",left:"center",top:"center",aspectScale:null,showLegendSymbol:!0,boundingCoords:null,center:null,zoom:1,scaleLimit:null,selectedMode:!0,label:{show:!1,color:"#000"},itemStyle:{borderWidth:.5,borderColor:"#444",areaColor:"#eee"},emphasis:{label:{show:!0,color:"rgb(100,0,0)"},itemStyle:{areaColor:"rgba(255,215,0,0.8)"}},select:{label:{show:!0,color:"rgb(100,0,0)"},itemStyle:{color:"rgba(255,215,0,0.8)"}},nameProperty:"name"},e}(bg);function hC(t){var e={};t.eachSeriesByType("map",(function(t){var n=t.getHostGeoModel(),i=n?"o"+n.id:"i"+t.getMapType();(e[i]=e[i]||[]).push(t)})),E(e,(function(t,e){for(var n,i,r,o=(n=z(t,(function(t){return t.getData()})),i=t[0].get("mapValueCalculation"),r={},E(n,(function(t){t.each(t.mapDimension("value"),(function(e,n){var i="ec-"+t.getName(n);r[i]=r[i]||[],isNaN(e)||r[i].push(e)}))})),n[0].map(n[0].mapDimension("value"),(function(t,e){for(var o="ec-"+n[0].getName(e),a=0,s=1/0,l=-1/0,u=r[o].length,h=0;h1?(d.width=p,d.height=p/x):(d.height=p,d.width=p*x),d.y=c[1]-d.height/2,d.x=c[0]-d.width/2;else{var b=t.getBoxLayoutParams();b.aspect=x,d=kp(b,{width:v,height:m})}this.setViewRect(d.x,d.y,d.width,d.height),this.setCenter(t.get("center"),e),this.setZoom(t.get("zoom"))}R(vC,dC);var _C=function(){function t(){this.dimensions=yC}return t.prototype.create=function(t,e){var n=[];function i(t){return{nameProperty:t.get("nameProperty"),aspectScale:t.get("aspectScale"),projection:t.get("projection")}}t.eachComponent("geo",(function(t,r){var o=t.get("map"),a=new vC(o+r,o,A({nameMap:t.get("nameMap")},i(t)));a.zoomLimit=t.get("scaleLimit"),n.push(a),t.coordinateSystem=a,a.model=t,a.resize=xC,a.resize(t,e)})),t.eachSeries((function(t){if("geo"===t.get("coordinateSystem")){var e=t.get("geoIndex")||0;t.coordinateSystem=n[e]}}));var r={};return t.eachSeriesByType("map",(function(t){if(!t.getHostGeoModel()){var e=t.getMapType();r[e]=r[e]||[],r[e].push(t)}})),E(r,(function(t,r){var o=z(t,(function(t){return t.get("nameMap")})),a=new vC(r,r,A({nameMap:D(o)},i(t[0])));a.zoomLimit=it.apply(null,z(t,(function(t){return t.get("scaleLimit")}))),n.push(a),a.resize=xC,a.resize(t[0],e),E(t,(function(t){t.coordinateSystem=a,function(t,e){E(e.get("geoCoord"),(function(e,n){t.addGeoCoord(n,e)}))}(a,t)}))})),n},t.prototype.getFilledRegions=function(t,e,n,i){for(var r=(t||[]).slice(),o=yt(),a=0;a=0;){var o=e[n];o.hierNode.prelim+=i,o.hierNode.modifier+=i,r+=o.hierNode.change,i+=o.hierNode.shift+r}}(t);var o=(n[0].hierNode.prelim+n[n.length-1].hierNode.prelim)/2;r?(t.hierNode.prelim=r.hierNode.prelim+e(t,r),t.hierNode.modifier=t.hierNode.prelim-o):t.hierNode.prelim=o}else r&&(t.hierNode.prelim=r.hierNode.prelim+e(t,r));t.parentNode.hierNode.defaultAncestor=function(t,e,n,i){if(e){for(var r=t,o=t,a=o.parentNode.children[0],s=e,l=r.hierNode.modifier,u=o.hierNode.modifier,h=a.hierNode.modifier,c=s.hierNode.modifier;s=PC(s),o=OC(o),s&&o;){r=PC(r),a=OC(a),r.hierNode.ancestor=t;var p=s.hierNode.prelim+c-o.hierNode.prelim-u+i(s,o);p>0&&(NC(RC(s,t,n),t,p),u+=p,l+=p),c+=s.hierNode.modifier,u+=o.hierNode.modifier,l+=r.hierNode.modifier,h+=a.hierNode.modifier}s&&!PC(r)&&(r.hierNode.thread=s,r.hierNode.modifier+=c-l),o&&!OC(a)&&(a.hierNode.thread=o,a.hierNode.modifier+=u-h,n=t)}return n}(t,r,t.parentNode.hierNode.defaultAncestor||i[0],e)}function AC(t){var e=t.hierNode.prelim+t.parentNode.hierNode.modifier;t.setLayout({x:e},!0),t.hierNode.modifier+=t.parentNode.hierNode.modifier}function kC(t){return arguments.length?t:EC}function LC(t,e){return t-=Math.PI/2,{x:e*Math.cos(t),y:e*Math.sin(t)}}function PC(t){var e=t.children;return e.length&&t.isExpand?e[e.length-1]:t.hierNode.thread}function OC(t){var e=t.children;return e.length&&t.isExpand?e[0]:t.hierNode.thread}function RC(t,e,n){return t.hierNode.ancestor.parentNode===e.parentNode?t.hierNode.ancestor:n}function NC(t,e,n){var i=n/(e.hierNode.i-t.hierNode.i);e.hierNode.change-=i,e.hierNode.shift+=n,e.hierNode.modifier+=n,e.hierNode.prelim+=n,t.hierNode.change+=i}function EC(t,e){return t.parentNode===e.parentNode?1:2}var zC=function(){this.parentPoint=[],this.childPoints=[]},VC=function(t){function e(e){return t.call(this,e)||this}return n(e,t),e.prototype.getDefaultStyle=function(){return{stroke:"#000",fill:null}},e.prototype.getDefaultShape=function(){return new zC},e.prototype.buildPath=function(t,e){var n=e.childPoints,i=n.length,r=e.parentPoint,o=n[0],a=n[i-1];if(1===i)return t.moveTo(r[0],r[1]),void t.lineTo(o[0],o[1]);var s=e.orient,l="TB"===s||"BT"===s?0:1,u=1-l,h=$r(e.forkPosition,1),c=[];c[l]=r[l],c[u]=r[u]+(a[u]-r[u])*h,t.moveTo(r[0],r[1]),t.lineTo(c[0],c[1]),t.moveTo(o[0],o[1]),c[l]=o[l],t.lineTo(c[0],c[1]),c[l]=a[l],t.lineTo(c[0],c[1]),t.lineTo(a[0],a[1]);for(var p=1;pm.x)||(_-=Math.PI);var S=b?"left":"right",M=s.getModel("label"),I=M.get("rotate"),T=I*(Math.PI/180),C=y.getTextContent();C&&(y.setTextConfig({position:M.get("position")||S,rotation:null==I?-_:T,origin:"center"}),C.setStyle("verticalAlign","middle"))}var D=s.get(["emphasis","focus"]),A="relative"===D?vt(a.getAncestorsIndices(),a.getDescendantIndices()):"ancestor"===D?a.getAncestorsIndices():"descendant"===D?a.getDescendantIndices():null;A&&(rl(n).focus=A),function(t,e,n,i,r,o,a,s){var l=e.getModel(),u=t.get("edgeShape"),h=t.get("layout"),c=t.getOrient(),p=t.get(["lineStyle","curveness"]),d=t.get("edgeForkPosition"),f=l.getModel("lineStyle").getLineStyle(),g=i.__edge;if("curve"===u)e.parentNode&&e.parentNode!==n&&(g||(g=i.__edge=new th({shape:XC(h,c,p,r,r)})),vh(g,{shape:XC(h,c,p,o,a)},t));else if("polyline"===u)if("orthogonal"===h){if(e!==n&&e.children&&0!==e.children.length&&!0===e.isExpand){for(var y=e.children,v=[],m=0;me&&(e=i.height)}this.height=e+1},t.prototype.getNodeById=function(t){if(this.getId()===t)return this;for(var e=0,n=this.children,i=n.length;e=0&&this.hostTree.data.setItemLayout(this.dataIndex,t,e)},t.prototype.getLayout=function(){return this.hostTree.data.getItemLayout(this.dataIndex)},t.prototype.getModel=function(t){if(!(this.dataIndex<0))return this.hostTree.data.getItemModel(this.dataIndex).getModel(t)},t.prototype.getLevelModel=function(){return(this.hostTree.levelModels||[])[this.depth]},t.prototype.setVisual=function(t,e){this.dataIndex>=0&&this.hostTree.data.setItemVisual(this.dataIndex,t,e)},t.prototype.getVisual=function(t){return this.hostTree.data.getItemVisual(this.dataIndex,t)},t.prototype.getRawIndex=function(){return this.hostTree.data.getRawIndex(this.dataIndex)},t.prototype.getId=function(){return this.hostTree.data.getId(this.dataIndex)},t.prototype.getChildIndex=function(){if(this.parentNode){for(var t=this.parentNode.children,e=0;e=0){var i=n.getData().tree.root,r=t.targetNode;if(U(r)&&(r=i.getNodeById(r)),r&&i.contains(r))return{node:r};var o=t.targetNodeId;if(null!=o&&(r=i.getNodeById(o)))return{node:r}}}function rD(t){for(var e=[];t;)(t=t.parentNode)&&e.push(t);return e.reverse()}function oD(t,e){return P(rD(t),e)>=0}function aD(t,e){for(var n=[];t;){var i=t.dataIndex;n.push({name:t.name,dataIndex:i,value:e.getRawValue(i)}),t=t.parentNode}return n.reverse(),n}var sD=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.hasSymbolVisual=!0,e.ignoreStyleOnData=!0,e}return n(e,t),e.prototype.getInitialData=function(t){var e={name:t.name,children:t.data},n=t.leaves||{},i=new Cc(n,this,this.ecModel),r=nD.createTree(e,this,(function(t){t.wrapMethod("getItemModel",(function(t,e){var n=r.getNodeByDataIndex(e);return n&&n.children.length&&n.isExpand||(t.parentModel=i),t}))}));var o=0;r.eachNode("preorder",(function(t){t.depth>o&&(o=t.depth)}));var a=t.expandAndCollapse&&t.initialTreeDepth>=0?t.initialTreeDepth:o;return r.root.eachNode("preorder",(function(t){var e=t.hostTree.data.getRawDataItem(t.dataIndex);t.isExpand=e&&null!=e.collapsed?!e.collapsed:t.depth<=a})),r.data},e.prototype.getOrient=function(){var t=this.get("orient");return"horizontal"===t?t="LR":"vertical"===t&&(t="TB"),t},e.prototype.setZoom=function(t){this.option.zoom=t},e.prototype.setCenter=function(t){this.option.center=t},e.prototype.formatTooltip=function(t,e,n){for(var i=this.getData().tree,r=i.root.children[0],o=i.getNodeByDataIndex(t),a=o.getValue(),s=o.name;o&&o!==r;)s=o.parentNode.name+"."+s,o=o.parentNode;return og("nameValue",{name:s,value:a,noValue:isNaN(a)||null==a})},e.prototype.getDataParams=function(e){var n=t.prototype.getDataParams.apply(this,arguments),i=this.getData().tree.getNodeByDataIndex(e);return n.treeAncestors=aD(i,this),n.collapsed=!i.isExpand,n},e.type="series.tree",e.layoutMode="box",e.defaultOption={z:2,coordinateSystem:"view",left:"12%",top:"12%",right:"12%",bottom:"12%",layout:"orthogonal",edgeShape:"curve",edgeForkPosition:"50%",roam:!1,nodeScaleRatio:.4,center:null,zoom:1,orient:"LR",symbol:"emptyCircle",symbolSize:7,expandAndCollapse:!0,initialTreeDepth:2,lineStyle:{color:"#ccc",width:1.5,curveness:.5},itemStyle:{color:"lightsteelblue",borderWidth:1.5},label:{show:!0},animationEasing:"linear",animationDuration:700,animationDurationUpdate:500},e}(bg);function lD(t,e){for(var n,i=[t];n=i.pop();)if(e(n),n.isExpand){var r=n.children;if(r.length)for(var o=r.length-1;o>=0;o--)i.push(r[o])}}function uD(t,e){t.eachSeriesByType("tree",(function(t){!function(t,e){var n=function(t,e){return kp(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()})}(t,e);t.layoutInfo=n;var i=t.get("layout"),r=0,o=0,a=null;"radial"===i?(r=2*Math.PI,o=Math.min(n.height,n.width)/2,a=kC((function(t,e){return(t.parentNode===e.parentNode?1:2)/t.depth}))):(r=n.width,o=n.height,a=kC());var s=t.getData().tree.root,l=s.children[0];if(l){!function(t){var e=t;e.hierNode={defaultAncestor:null,ancestor:e,prelim:0,modifier:0,change:0,shift:0,i:0,thread:null};for(var n,i,r=[e];n=r.pop();)if(i=n.children,n.isExpand&&i.length)for(var o=i.length-1;o>=0;o--){var a=i[o];a.hierNode={defaultAncestor:null,ancestor:a,prelim:0,modifier:0,change:0,shift:0,i:o,thread:null},r.push(a)}}(s),function(t,e,n){for(var i,r=[t],o=[];i=r.pop();)if(o.push(i),i.isExpand){var a=i.children;if(a.length)for(var s=0;sh.getLayout().x&&(h=t),t.depth>c.depth&&(c=t)}));var p=u===h?1:a(u,h)/2,d=p-u.getLayout().x,f=0,g=0,y=0,v=0;if("radial"===i)f=r/(h.getLayout().x+p+d),g=o/(c.depth-1||1),lD(l,(function(t){y=(t.getLayout().x+d)*f,v=(t.depth-1)*g;var e=LC(y,v);t.setLayout({x:e.x,y:e.y,rawX:y,rawY:v},!0)}));else{var m=t.getOrient();"RL"===m||"LR"===m?(g=o/(h.getLayout().x+p+d),f=r/(c.depth-1||1),lD(l,(function(t){v=(t.getLayout().x+d)*g,y="LR"===m?(t.depth-1)*f:r-(t.depth-1)*f,t.setLayout({x:y,y:v},!0)}))):"TB"!==m&&"BT"!==m||(f=r/(h.getLayout().x+p+d),g=o/(c.depth-1||1),lD(l,(function(t){y=(t.getLayout().x+d)*f,v="TB"===m?(t.depth-1)*g:o-(t.depth-1)*g,t.setLayout({x:y,y:v},!0)})))}}}(t,e)}))}function hD(t){t.eachSeriesByType("tree",(function(t){var e=t.getData();e.tree.eachNode((function(t){var n=t.getModel().getModel("itemStyle").getItemStyle();A(e.ensureUniqueItemVisual(t.dataIndex,"style"),n)}))}))}var cD=["treemapZoomToNode","treemapRender","treemapMove"];function pD(t){var e=t.getData().tree,n={};e.eachNode((function(e){for(var i=e;i&&i.depth>1;)i=i.parentNode;var r=pd(t.ecModel,i.name||i.dataIndex+"",n);e.setVisual("decal",r)}))}var dD=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.preventUsingHoverLayer=!0,n}return n(e,t),e.prototype.getInitialData=function(t,e){var n={name:t.name,children:t.data};fD(n);var i=t.levels||[],r=this.designatedVisualItemStyle={},o=new Cc({itemStyle:r},this,e);i=t.levels=function(t,e){var n,i,r=To(e.get("color")),o=To(e.get(["aria","decal","decals"]));if(!r)return;t=t||[],E(t,(function(t){var e=new Cc(t),r=e.get("color"),o=e.get("decal");(e.get(["itemStyle","color"])||r&&"none"!==r)&&(n=!0),(e.get(["itemStyle","decal"])||o&&"none"!==o)&&(i=!0)}));var a=t[0]||(t[0]={});n||(a.color=r.slice());!i&&o&&(a.decal=o.slice());return t}(i,e);var a=z(i||[],(function(t){return new Cc(t,o,e)}),this),s=nD.createTree(n,this,(function(t){t.wrapMethod("getItemModel",(function(t,e){var n=s.getNodeByDataIndex(e),i=n?a[n.depth]:null;return t.parentModel=i||o,t}))}));return s.data},e.prototype.optionUpdated=function(){this.resetViewRoot()},e.prototype.formatTooltip=function(t,e,n){var i=this.getData(),r=this.getRawValue(t);return og("nameValue",{name:i.getName(t),value:r})},e.prototype.getDataParams=function(e){var n=t.prototype.getDataParams.apply(this,arguments),i=this.getData().tree.getNodeByDataIndex(e);return n.treeAncestors=aD(i,this),n.treePathInfo=n.treeAncestors,n},e.prototype.setLayoutInfo=function(t){this.layoutInfo=this.layoutInfo||{},A(this.layoutInfo,t)},e.prototype.mapIdToIndex=function(t){var e=this._idIndexMap;e||(e=this._idIndexMap=yt(),this._idIndexMapCount=0);var n=e.get(t);return null==n&&e.set(t,n=this._idIndexMapCount++),n},e.prototype.getViewRoot=function(){return this._viewRoot},e.prototype.resetViewRoot=function(t){t?this._viewRoot=t:t=this._viewRoot;var e=this.getRawData().tree.root;t&&(t===e||e.contains(t))||(this._viewRoot=e)},e.prototype.enableAriaDecal=function(){pD(this)},e.type="series.treemap",e.layoutMode="box",e.defaultOption={progressive:0,left:"center",top:"middle",width:"80%",height:"80%",sort:!0,clipWindow:"origin",squareRatio:.5*(1+Math.sqrt(5)),leafDepth:null,drillDownIcon:"▶",zoomToNodeRatio:.1024,scaleLimit:null,roam:!0,nodeClick:"zoomToNode",animation:!0,animationDurationUpdate:900,animationEasing:"quinticInOut",breadcrumb:{show:!0,height:22,left:"center",top:"bottom",emptyItemWidth:25,itemStyle:{color:"rgba(0,0,0,0.7)",textStyle:{color:"#fff"}},emphasis:{itemStyle:{color:"rgba(0,0,0,0.9)"}}},label:{show:!0,distance:0,padding:5,position:"inside",color:"#fff",overflow:"truncate"},upperLabel:{show:!1,position:[0,"50%"],height:20,overflow:"truncate",verticalAlign:"middle"},itemStyle:{color:null,colorAlpha:null,colorSaturation:null,borderWidth:0,gapWidth:0,borderColor:"#fff",borderColorSaturation:null},emphasis:{upperLabel:{show:!0,position:[0,"50%"],overflow:"truncate",verticalAlign:"middle"}},visualDimension:0,visualMin:null,visualMax:null,color:[],colorAlpha:null,colorSaturation:null,colorMappingBy:"index",visibleMin:10,childrenVisibleMin:null,levels:[]},e}(bg);function fD(t){var e=0;E(t.children,(function(t){fD(t);var n=t.value;Y(n)&&(n=n[0]),e+=n}));var n=t.value;Y(n)&&(n=n[0]),(null==n||isNaN(n))&&(n=e),n<0&&(n=0),Y(t.value)?t.value[0]=n:t.value=n}var gD=function(){function t(t){this.group=new Br,t.add(this.group)}return t.prototype.render=function(t,e,n,i){var r=t.getModel("breadcrumb"),o=this.group;if(o.removeAll(),r.get("show")&&n){var a=r.getModel("itemStyle"),s=r.getModel("emphasis"),l=a.getModel("textStyle"),u=s.getModel(["itemStyle","textStyle"]),h={pos:{left:r.get("left"),right:r.get("right"),top:r.get("top"),bottom:r.get("bottom")},box:{width:e.getWidth(),height:e.getHeight()},emptyItemWidth:r.get("emptyItemWidth"),totalWidth:0,renderList:[]};this._prepare(n,h,l),this._renderContent(t,h,a,s,l,u,i),Lp(o,h.pos,h.box)}},t.prototype._prepare=function(t,e,n){for(var i=t;i;i=i.parentNode){var r=Ro(i.getModel().get("name"),""),o=n.getTextRect(r),a=Math.max(o.width+16,e.emptyItemWidth);e.totalWidth+=a+8,e.renderList.push({node:i,text:r,width:a})}},t.prototype._renderContent=function(t,e,n,i,r,o,a){for(var s,l,u,h,c,p,d,f,g,y=0,v=e.emptyItemWidth,m=t.get(["breadcrumb","height"]),x=(s=e.pos,l=e.box,h=l.width,c=l.height,p=$r(s.left,h),d=$r(s.top,c),f=$r(s.right,h),g=$r(s.bottom,c),(isNaN(p)||isNaN(parseFloat(s.left)))&&(p=0),(isNaN(f)||isNaN(parseFloat(s.right)))&&(f=h),(isNaN(d)||isNaN(parseFloat(s.top)))&&(d=0),(isNaN(g)||isNaN(parseFloat(s.bottom)))&&(g=c),u=vp(u||0),{width:Math.max(f-p-u[1]-u[3],0),height:Math.max(g-d-u[0]-u[2],0)}),_=e.totalWidth,b=e.renderList,w=i.getModel("itemStyle").getItemStyle(),S=b.length-1;S>=0;S--){var M=b[S],I=M.node,T=M.width,C=M.text;_>x.width&&(_-=T-v,T=v,C=null);var D=new Xu({shape:{points:yD(y,0,T,m,S===b.length-1,0===S)},style:k(n.getItemStyle(),{lineJoin:"bevel"}),textContent:new Xs({style:oc(r,{text:C})}),textConfig:{position:"inside"},z2:1e5,onclick:H(a,I)});D.disableLabelAnimation=!0,D.getTextContent().ensureState("emphasis").style=oc(o,{text:C}),D.ensureState("emphasis").style=w,Zl(D,i.get("focus"),i.get("blurScope"),i.get("disabled")),this.group.add(D),vD(D,t,I),y+=T+8}},t.prototype.remove=function(){this.group.removeAll()},t}();function yD(t,e,n,i,r,o){var a=[[r?t:t-5,e],[t+n,e],[t+n,e+i],[r?t:t-5,e+i]];return!o&&a.splice(2,0,[t+n+5,e+i/2]),!r&&a.push([t,e+i/2]),a}function vD(t,e,n){rl(t).eventData={componentType:"series",componentSubType:"treemap",componentIndex:e.componentIndex,seriesIndex:e.seriesIndex,seriesName:e.name,seriesType:"treemap",selfType:"breadcrumb",nodeData:{dataIndex:n&&n.dataIndex,name:n&&n.name},treePathInfo:n&&aD(n,e)}}var mD=function(){function t(){this._storage=[],this._elExistsMap={}}return t.prototype.add=function(t,e,n,i,r){return!this._elExistsMap[t.id]&&(this._elExistsMap[t.id]=!0,this._storage.push({el:t,target:e,duration:n,delay:i,easing:r}),!0)},t.prototype.finished=function(t){return this._finishedCallback=t,this},t.prototype.start=function(){for(var t=this,e=this._storage.length,n=function(){--e<=0&&(t._storage.length=0,t._elExistsMap={},t._finishedCallback&&t._finishedCallback())},i=0,r=this._storage.length;i3||Math.abs(t.dy)>3)){var e=this.seriesModel.getData().tree.root;if(!e)return;var n=e.getLayout();if(!n)return;this.api.dispatchAction({type:"treemapMove",from:this.uid,seriesId:this.seriesModel.id,rootRect:{x:n.x+t.dx,y:n.y+t.dy,width:n.width,height:n.height}})}},e.prototype._onZoom=function(t){var e=t.originX,n=t.originY,i=t.scale;if("animating"!==this._state){var r=this.seriesModel.getData().tree.root;if(!r)return;var o=r.getLayout();if(!o)return;var a,s=new ze(o.x,o.y,o.width,o.height),l=this._controllerHost;a=l.zoomLimit;var u=l.zoom=l.zoom||1;if(u*=i,a){var h=a.min||0,c=a.max||1/0;u=Math.max(Math.min(c,u),h)}var p=u/l.zoom;l.zoom=u;var d=this.seriesModel.layoutInfo,f=[1,0,0,1,0,0];we(f,f,[-(e-=d.x),-(n-=d.y)]),Me(f,f,[p,p]),we(f,f,[e,n]),s.applyTransform(f),this.api.dispatchAction({type:"treemapRender",from:this.uid,seriesId:this.seriesModel.id,rootRect:{x:s.x,y:s.y,width:s.width,height:s.height}})}},e.prototype._initEvents=function(t){var e=this;t.on("click",(function(t){if("ready"===e._state){var n=e.seriesModel.get("nodeClick",!0);if(n){var i=e.findTarget(t.offsetX,t.offsetY);if(i){var r=i.node;if(r.getLayout().isLeafRoot)e._rootToNode(i);else if("zoomToNode"===n)e._zoomToNode(i);else if("link"===n){var o=r.hostTree.data.getItemModel(r.dataIndex),a=o.get("link",!0),s=o.get("target",!0)||"blank";a&&Mp(a,s)}}}}}),this)},e.prototype._renderBreadcrumb=function(t,e,n){var i=this;n||(n=null!=t.get("leafDepth",!0)?{node:t.getViewRoot()}:this.findTarget(e.getWidth()/2,e.getHeight()/2))||(n={node:t.getData().tree.root}),(this._breadcrumb||(this._breadcrumb=new gD(this.group))).render(t,e,n.node,(function(e){"animating"!==i._state&&(oD(t.getViewRoot(),e)?i._rootToNode({node:e}):i._zoomToNode({node:e}))}))},e.prototype.remove=function(){this._clearController(),this._containerGroup&&this._containerGroup.removeAll(),this._storage={nodeGroup:[],background:[],content:[]},this._state="ready",this._breadcrumb&&this._breadcrumb.remove()},e.prototype.dispose=function(){this._clearController()},e.prototype._zoomToNode=function(t){this.api.dispatchAction({type:"treemapZoomToNode",from:this.uid,seriesId:this.seriesModel.id,targetNode:t.node})},e.prototype._rootToNode=function(t){this.api.dispatchAction({type:"treemapRootToNode",from:this.uid,seriesId:this.seriesModel.id,targetNode:t.node})},e.prototype.findTarget=function(t,e){var n;return this.seriesModel.getViewRoot().eachNode({attr:"viewChildren",order:"preorder"},(function(i){var r=this._storage.background[i.getRawIndex()];if(r){var o=r.transformCoordToLocal(t,e),a=r.shape;if(!(a.x<=o[0]&&o[0]<=a.x+a.width&&a.y<=o[1]&&o[1]<=a.y+a.height))return!1;n={node:i,offsetX:o[0],offsetY:o[1]}}}),this),n},e.type="treemap",e}(Og);var CD=E,DD=q,AD=-1,kD=function(){function t(e){var n=e.mappingMethod,i=e.type,r=this.option=T(e);this.type=i,this.mappingMethod=n,this._normalizeData=FD[n];var o=t.visualHandlers[i];this.applyVisual=o.applyVisual,this.getColorMapper=o.getColorMapper,this._normalizedToVisual=o._normalizedToVisual[n],"piecewise"===n?(LD(r),function(t){var e=t.pieceList;t.hasSpecialVisual=!1,E(e,(function(e,n){e.originIndex=n,null!=e.visual&&(t.hasSpecialVisual=!0)}))}(r)):"category"===n?r.categories?function(t){var e=t.categories,n=t.categoryMap={},i=t.visual;if(CD(e,(function(t,e){n[t]=e})),!Y(i)){var r=[];q(i)?CD(i,(function(t,e){var i=n[e];r[null!=i?i:AD]=t})):r[-1]=i,i=BD(t,r)}for(var o=e.length-1;o>=0;o--)null==i[o]&&(delete n[e[o]],e.pop())}(r):LD(r,!0):(lt("linear"!==n||r.dataExtent),LD(r))}return t.prototype.mapValueToVisual=function(t){var e=this._normalizeData(t);return this._normalizedToVisual(e,t)},t.prototype.getNormalizer=function(){return W(this._normalizeData,this)},t.listVisualTypes=function(){return G(t.visualHandlers)},t.isValidType=function(e){return t.visualHandlers.hasOwnProperty(e)},t.eachVisual=function(t,e,n){q(t)?E(t,e,n):e.call(n,t)},t.mapVisual=function(e,n,i){var r,o=Y(e)?[]:q(e)?{}:(r=!0,null);return t.eachVisual(e,(function(t,e){var a=n.call(i,t,e);r?o=a:o[e]=a})),o},t.retrieveVisuals=function(e){var n,i={};return e&&CD(t.visualHandlers,(function(t,r){e.hasOwnProperty(r)&&(i[r]=e[r],n=!0)})),n?i:null},t.prepareVisualTypes=function(t){if(Y(t))t=t.slice();else{if(!DD(t))return[];var e=[];CD(t,(function(t,n){e.push(n)})),t=e}return t.sort((function(t,e){return"color"===e&&"color"!==t&&0===t.indexOf("color")?1:-1})),t},t.dependsOn=function(t,e){return"color"===e?!(!t||0!==t.indexOf(e)):t===e},t.findPieceIndex=function(t,e,n){for(var i,r=1/0,o=0,a=e.length;ou[1]&&(u[1]=l);var h=e.get("colorMappingBy"),c={type:a.name,dataExtent:u,visual:a.range};"color"!==c.type||"index"!==h&&"id"!==h?c.mappingMethod="linear":(c.mappingMethod="category",c.loop=!0);var p=new kD(c);return WD(p).drColorMappingBy=h,p}(0,r,o,0,u,d);E(d,(function(t,e){if(t.depth>=n.length||t===n[t.depth]){var o=function(t,e,n,i,r,o){var a=A({},e);if(r){var s=r.type,l="color"===s&&WD(r).drColorMappingBy,u="index"===l?i:"id"===l?o.mapIdToIndex(n.getId()):n.getValue(t.get("visualDimension"));a[s]=r.mapValueToVisual(u)}return a}(r,u,t,e,f,i);YD(t,o,n,i)}}))}else s=XD(u),h.fill=s}}function XD(t){var e=UD(t,"color");if(e){var n=UD(t,"colorAlpha"),i=UD(t,"colorSaturation");return i&&(e=ni(e,null,null,i)),n&&(e=ii(e,n)),e}}function UD(t,e){var n=t[e];if(null!=n&&"none"!==n)return n}function ZD(t,e){var n=t.get(e);return Y(n)&&n.length?{name:e,range:n}:null}var jD=Math.max,qD=Math.min,KD=it,$D=E,JD=["itemStyle","borderWidth"],QD=["itemStyle","gapWidth"],tA=["upperLabel","show"],eA=["upperLabel","height"],nA={seriesType:"treemap",reset:function(t,e,n,i){var r=n.getWidth(),o=n.getHeight(),a=t.option,s=kp(t.getBoxLayoutParams(),{width:n.getWidth(),height:n.getHeight()}),l=a.size||[],u=$r(KD(s.width,l[0]),r),h=$r(KD(s.height,l[1]),o),c=i&&i.type,p=iD(i,["treemapZoomToNode","treemapRootToNode"],t),d="treemapRender"===c||"treemapMove"===c?i.rootRect:null,f=t.getViewRoot(),g=rD(f);if("treemapMove"!==c){var y="treemapZoomToNode"===c?function(t,e,n,i,r){var o,a=(e||{}).node,s=[i,r];if(!a||a===n)return s;var l=i*r,u=l*t.option.zoomToNodeRatio;for(;o=a.parentNode;){for(var h=0,c=o.children,p=0,d=c.length;poo&&(u=oo),a=o}ua[1]&&(a[1]=e)}))):a=[NaN,NaN];return{sum:i,dataExtent:a}}(e,a,s);if(0===u.sum)return t.viewChildren=[];if(u.sum=function(t,e,n,i,r){if(!i)return n;for(var o=t.get("visibleMin"),a=r.length,s=a,l=a-1;l>=0;l--){var u=r["asc"===i?a-l-1:l].getValue();u/n*ei&&(i=a));var l=t.area*t.area,u=e*e*n;return l?jD(u*i/l,l/(u*r)):1/0}function oA(t,e,n,i,r){var o=e===n.width?0:1,a=1-o,s=["x","y"],l=["width","height"],u=n[s[o]],h=e?t.area/e:0;(r||h>n[l[a]])&&(h=n[l[a]]);for(var c=0,p=t.length;ci&&(i=e);var o=i%2?i+2:i+3;r=[];for(var a=0;a0&&(m[0]=-m[0],m[1]=-m[1]);var _=v[0]<0?-1:1;if("start"!==i.__position&&"end"!==i.__position){var b=-Math.atan2(v[1],v[0]);u[0].8?"left":h[0]<-.8?"right":"center",p=h[1]>.8?"top":h[1]<-.8?"bottom":"middle";break;case"start":i.x=-h[0]*f+l[0],i.y=-h[1]*g+l[1],c=h[0]>.8?"right":h[0]<-.8?"left":"center",p=h[1]>.8?"bottom":h[1]<-.8?"top":"middle";break;case"insideStartTop":case"insideStart":case"insideStartBottom":i.x=f*_+l[0],i.y=l[1]+w,c=v[0]<0?"right":"left",i.originX=-f*_,i.originY=-w;break;case"insideMiddleTop":case"insideMiddle":case"insideMiddleBottom":case"middle":i.x=x[0],i.y=x[1]+w,c="center",i.originY=-w;break;case"insideEndTop":case"insideEnd":case"insideEndBottom":i.x=-f*_+u[0],i.y=u[1]+w,c=v[0]>=0?"right":"left",i.originX=f*_,i.originY=-w}i.scaleX=i.scaleY=r,i.setStyle({verticalAlign:i.__verticalAlign||p,align:i.__align||c})}}}function S(t,e){var n=t.__specifiedRotation;if(null==n){var i=a.tangentAt(e);t.attr("rotation",(1===e?-1:1)*Math.PI/2-Math.atan2(i[1],i[0]))}else t.attr("rotation",n)}},e}(Br),YA=function(){function t(t){this.group=new Br,this._LineCtor=t||HA}return t.prototype.updateData=function(t){var e=this;this._progressiveEls=null;var n=this,i=n.group,r=n._lineData;n._lineData=t,r||i.removeAll();var o=XA(t);t.diff(r).add((function(n){e._doAdd(t,n,o)})).update((function(n,i){e._doUpdate(r,t,i,n,o)})).remove((function(t){i.remove(r.getItemGraphicEl(t))})).execute()},t.prototype.updateLayout=function(){var t=this._lineData;t&&t.eachItemGraphicEl((function(e,n){e.updateLayout(t,n)}),this)},t.prototype.incrementalPrepareUpdate=function(t){this._seriesScope=XA(t),this._lineData=null,this.group.removeAll()},t.prototype.incrementalUpdate=function(t,e){function n(t){t.isGroup||function(t){return t.animators&&t.animators.length>0}(t)||(t.incremental=!0,t.ensureState("emphasis").hoverLayer=!0)}this._progressiveEls=[];for(var i=t.start;i=0?i+=u:i-=u:f>=0?i-=u:i+=u}return i}function ek(t,e){var n=[],i=Dn,r=[[],[],[]],o=[[],[]],a=[];e/=2,t.eachEdge((function(t,s){var l=t.getLayout(),u=t.getVisual("fromSymbol"),h=t.getVisual("toSymbol");l.__original||(l.__original=[Tt(l[0]),Tt(l[1])],l[2]&&l.__original.push(Tt(l[2])));var c=l.__original;if(null!=l[2]){if(It(r[0],c[0]),It(r[1],c[2]),It(r[2],c[1]),u&&"none"!==u){var p=SA(t.node1),d=tk(r,c[0],p*e);i(r[0][0],r[1][0],r[2][0],d,n),r[0][0]=n[3],r[1][0]=n[4],i(r[0][1],r[1][1],r[2][1],d,n),r[0][1]=n[3],r[1][1]=n[4]}if(h&&"none"!==h){p=SA(t.node2),d=tk(r,c[1],p*e);i(r[0][0],r[1][0],r[2][0],d,n),r[1][0]=n[1],r[2][0]=n[2],i(r[0][1],r[1][1],r[2][1],d,n),r[1][1]=n[1],r[2][1]=n[2]}It(l[0],r[0]),It(l[1],r[2]),It(l[2],r[1])}else{if(It(o[0],c[0]),It(o[1],c[1]),kt(a,o[1],o[0]),Et(a,a),u&&"none"!==u){p=SA(t.node1);At(o[0],o[0],a,p*e)}if(h&&"none"!==h){p=SA(t.node2);At(o[1],o[1],a,-p*e)}It(l[0],o[0]),It(l[1],o[1])}}))}function nk(t){return"view"===t.type}var ik=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(t,e){var n=new xS,i=new YA,r=this.group;this._controller=new nT(e.getZr()),this._controllerHost={target:r},r.add(n.group),r.add(i.group),this._symbolDraw=n,this._lineDraw=i,this._firstRender=!0},e.prototype.render=function(t,e,n){var i=this,r=t.coordinateSystem;this._model=t;var o=this._symbolDraw,a=this._lineDraw,s=this.group;if(nk(r)){var l={x:r.x,y:r.y,scaleX:r.scaleX,scaleY:r.scaleY};this._firstRender?s.attr(l):vh(s,l,t)}ek(t.getGraph(),wA(t));var u=t.getData();o.updateData(u);var h=t.getEdgeData();a.updateData(h),this._updateNodeAndLinkScale(),this._updateController(t,e,n),clearTimeout(this._layoutTimeout);var c=t.forceLayout,p=t.get(["force","layoutAnimation"]);c&&this._startForceLayoutIteration(c,p);var d=t.get("layout");u.graph.eachNode((function(e){var n=e.dataIndex,r=e.getGraphicEl(),o=e.getModel();if(r){r.off("drag").off("dragend");var a=o.get("draggable");a&&r.on("drag",(function(o){switch(d){case"force":c.warmUp(),!i._layouting&&i._startForceLayoutIteration(c,p),c.setFixed(n),u.setItemLayout(n,[r.x,r.y]);break;case"circular":u.setItemLayout(n,[r.x,r.y]),e.setLayout({fixed:!0},!0),TA(t,"symbolSize",e,[o.offsetX,o.offsetY]),i.updateLayout(t);break;default:u.setItemLayout(n,[r.x,r.y]),_A(t.getGraph(),t),i.updateLayout(t)}})).on("dragend",(function(){c&&c.setUnfixed(n)})),r.setDraggable(a,!!o.get("cursor")),"adjacency"===o.get(["emphasis","focus"])&&(rl(r).focus=e.getAdjacentDataIndices())}})),u.graph.eachEdge((function(t){var e=t.getGraphicEl(),n=t.getModel().get(["emphasis","focus"]);e&&"adjacency"===n&&(rl(e).focus={edge:[t.dataIndex],node:[t.node1.dataIndex,t.node2.dataIndex]})}));var f="circular"===t.get("layout")&&t.get(["circular","rotateLabel"]),g=u.getLayout("cx"),y=u.getLayout("cy");u.graph.eachNode((function(t){DA(t,f,g,y)})),this._firstRender=!1},e.prototype.dispose=function(){this.remove(),this._controller&&this._controller.dispose(),this._controllerHost=null},e.prototype._startForceLayoutIteration=function(t,e){var n=this;!function i(){t.step((function(t){n.updateLayout(n._model),(n._layouting=!t)&&(e?n._layoutTimeout=setTimeout(i,16):i())}))}()},e.prototype._updateController=function(t,e,n){var i=this,r=this._controller,o=this._controllerHost,a=this.group;r.setPointerChecker((function(e,i,r){var o=a.getBoundingRect();return o.applyTransform(a.transform),o.contain(i,r)&&!hT(e,n,t)})),nk(t.coordinateSystem)?(r.enable(t.get("roam")),o.zoomLimit=t.get("scaleLimit"),o.zoom=t.coordinateSystem.getZoom(),r.off("pan").off("zoom").on("pan",(function(e){aT(o,e.dx,e.dy),n.dispatchAction({seriesId:t.id,type:"graphRoam",dx:e.dx,dy:e.dy})})).on("zoom",(function(e){sT(o,e.scale,e.originX,e.originY),n.dispatchAction({seriesId:t.id,type:"graphRoam",zoom:e.scale,originX:e.originX,originY:e.originY}),i._updateNodeAndLinkScale(),ek(t.getGraph(),wA(t)),i._lineDraw.updateLayout(),n.updateLabelLayout()}))):r.disable()},e.prototype._updateNodeAndLinkScale=function(){var t=this._model,e=t.getData(),n=wA(t);e.eachItemGraphicEl((function(t,e){t&&t.setSymbolScale(n)}))},e.prototype.updateLayout=function(t){ek(t.getGraph(),wA(t)),this._symbolDraw.updateLayout(),this._lineDraw.updateLayout()},e.prototype.remove=function(){clearTimeout(this._layoutTimeout),this._layouting=!1,this._layoutTimeout=null,this._symbolDraw&&this._symbolDraw.remove(),this._lineDraw&&this._lineDraw.remove()},e.type="graph",e}(Og);function rk(t){return"_EC_"+t}var ok=function(){function t(t){this.type="graph",this.nodes=[],this.edges=[],this._nodesMap={},this._edgesMap={},this._directed=t||!1}return t.prototype.isDirected=function(){return this._directed},t.prototype.addNode=function(t,e){t=null==t?""+e:""+t;var n=this._nodesMap;if(!n[rk(t)]){var i=new ak(t,e);return i.hostGraph=this,this.nodes.push(i),n[rk(t)]=i,i}},t.prototype.getNodeByIndex=function(t){var e=this.data.getRawIndex(t);return this.nodes[e]},t.prototype.getNodeById=function(t){return this._nodesMap[rk(t)]},t.prototype.addEdge=function(t,e,n){var i=this._nodesMap,r=this._edgesMap;if(j(t)&&(t=this.nodes[t]),j(e)&&(e=this.nodes[e]),t instanceof ak||(t=i[rk(t)]),e instanceof ak||(e=i[rk(e)]),t&&e){var o=t.id+"-"+e.id,a=new sk(t,e,n);return a.hostGraph=this,this._directed&&(t.outEdges.push(a),e.inEdges.push(a)),t.edges.push(a),t!==e&&e.edges.push(a),this.edges.push(a),r[o]=a,a}},t.prototype.getEdgeByIndex=function(t){var e=this.edgeData.getRawIndex(t);return this.edges[e]},t.prototype.getEdge=function(t,e){t instanceof ak&&(t=t.id),e instanceof ak&&(e=e.id);var n=this._edgesMap;return this._directed?n[t+"-"+e]:n[t+"-"+e]||n[e+"-"+t]},t.prototype.eachNode=function(t,e){for(var n=this.nodes,i=n.length,r=0;r=0&&t.call(e,n[r],r)},t.prototype.eachEdge=function(t,e){for(var n=this.edges,i=n.length,r=0;r=0&&n[r].node1.dataIndex>=0&&n[r].node2.dataIndex>=0&&t.call(e,n[r],r)},t.prototype.breadthFirstTraverse=function(t,e,n,i){if(e instanceof ak||(e=this._nodesMap[rk(e)]),e){for(var r="out"===n?"outEdges":"in"===n?"inEdges":"edges",o=0;o=0&&n.node2.dataIndex>=0}));for(r=0,o=i.length;r=0&&this[t][e].setItemVisual(this.dataIndex,n,i)},getVisual:function(n){return this[t][e].getItemVisual(this.dataIndex,n)},setLayout:function(n,i){this.dataIndex>=0&&this[t][e].setItemLayout(this.dataIndex,n,i)},getLayout:function(){return this[t][e].getItemLayout(this.dataIndex)},getGraphicEl:function(){return this[t][e].getItemGraphicEl(this.dataIndex)},getRawIndex:function(){return this[t][e].getRawIndex(this.dataIndex)}}}function uk(t,e,n,i,r){for(var o=new ok(i),a=0;a "+p)),u++)}var d,f=n.get("coordinateSystem");if("cartesian2d"===f||"polar"===f)d=_x(t,n);else{var g=wd.get(f),y=g&&g.dimensions||[];P(y,"value")<0&&y.concat(["value"]);var v=px(t,{coordDimensions:y,encodeDefine:n.getEncode()}).dimensions;(d=new cx(v,n)).initData(t)}var m=new cx(["value"],n);return m.initData(l,s),r&&r(d,m),ZC({mainData:d,struct:o,structAttr:"graph",datas:{node:d,edge:m},datasAttr:{node:"data",edge:"edgeData"}}),o.update(),o}R(ak,lk("hostGraph","data")),R(sk,lk("hostGraph","edgeData"));var hk=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.hasSymbolVisual=!0,n}return n(e,t),e.prototype.init=function(e){t.prototype.init.apply(this,arguments);var n=this;function i(){return n._categoriesData}this.legendVisualProvider=new NM(i,i),this.fillDataTextStyle(e.edges||e.links),this._updateCategoriesData()},e.prototype.mergeOption=function(e){t.prototype.mergeOption.apply(this,arguments),this.fillDataTextStyle(e.edges||e.links),this._updateCategoriesData()},e.prototype.mergeDefaultAndTheme=function(e){t.prototype.mergeDefaultAndTheme.apply(this,arguments),Co(e,"edgeLabel",["show"])},e.prototype.getInitialData=function(t,e){var n,i=t.edges||t.links||[],r=t.data||t.nodes||[],o=this;if(r&&i){dA(n=this)&&(n.__curvenessList=[],n.__edgeMap={},fA(n));var a=uk(r,i,this,!0,(function(t,e){t.wrapMethod("getItemModel",(function(t){var e=o._categoriesModels[t.getShallow("category")];return e&&(e.parentModel=t.parentModel,t.parentModel=e),t}));var n=Cc.prototype.getModel;function i(t,e){var i=n.call(this,t,e);return i.resolveParentPath=r,i}function r(t){if(t&&("label"===t[0]||"label"===t[1])){var e=t.slice();return"label"===t[0]?e[0]="edgeLabel":"label"===t[1]&&(e[1]="edgeLabel"),e}return t}e.wrapMethod("getItemModel",(function(t){return t.resolveParentPath=r,t.getModel=i,t}))}));return E(a.edges,(function(t){!function(t,e,n,i){if(dA(n)){var r=gA(t,e,n),o=n.__edgeMap,a=o[yA(r)];o[r]&&!a?o[r].isForward=!0:a&&o[r]&&(a.isForward=!0,o[r].isForward=!1),o[r]=o[r]||[],o[r].push(i)}}(t.node1,t.node2,this,t.dataIndex)}),this),a.data}},e.prototype.getGraph=function(){return this.getData().graph},e.prototype.getEdgeData=function(){return this.getGraph().edgeData},e.prototype.getCategoriesData=function(){return this._categoriesData},e.prototype.formatTooltip=function(t,e,n){if("edge"===n){var i=this.getData(),r=this.getDataParams(t,n),o=i.graph.getEdgeByIndex(t),a=i.getName(o.node1.dataIndex),s=i.getName(o.node2.dataIndex),l=[];return null!=a&&l.push(a),null!=s&&l.push(s),og("nameValue",{name:l.join(" > "),value:r.value,noValue:null==r.value})}return vg({series:this,dataIndex:t,multipleSeries:e})},e.prototype._updateCategoriesData=function(){var t=z(this.option.categories||[],(function(t){return null!=t.value?t:A({value:0},t)})),e=new cx(["value"],this);e.initData(t),this._categoriesData=e,this._categoriesModels=e.mapArray((function(t){return e.getItemModel(t)}))},e.prototype.setZoom=function(t){this.option.zoom=t},e.prototype.setCenter=function(t){this.option.center=t},e.prototype.isAnimationEnabled=function(){return t.prototype.isAnimationEnabled.call(this)&&!("force"===this.get("layout")&&this.get(["force","layoutAnimation"]))},e.type="series.graph",e.dependencies=["grid","polar","geo","singleAxis","calendar"],e.defaultOption={z:2,coordinateSystem:"view",legendHoverLink:!0,layout:null,circular:{rotateLabel:!1},force:{initLayout:null,repulsion:[0,50],gravity:.1,friction:.6,edgeLength:30,layoutAnimation:!0},left:"center",top:"center",symbol:"circle",symbolSize:10,edgeSymbol:["none","none"],edgeSymbolSize:10,edgeLabel:{position:"middle",distance:5},draggable:!1,roam:!1,center:null,zoom:1,nodeScaleRatio:.6,label:{show:!1,formatter:"{b}"},itemStyle:{},lineStyle:{color:"#aaa",width:1,opacity:.5},emphasis:{scale:!0,label:{show:!0}},select:{itemStyle:{borderColor:"#212121"}}},e}(bg),ck={type:"graphRoam",event:"graphRoam",update:"none"};var pk=function(){this.angle=0,this.width=10,this.r=10,this.x=0,this.y=0},dk=function(t){function e(e){var n=t.call(this,e)||this;return n.type="pointer",n}return n(e,t),e.prototype.getDefaultShape=function(){return new pk},e.prototype.buildPath=function(t,e){var n=Math.cos,i=Math.sin,r=e.r,o=e.width,a=e.angle,s=e.x-n(a)*o*(o>=r/3?1:2),l=e.y-i(a)*o*(o>=r/3?1:2);a=e.angle-Math.PI/2,t.moveTo(s,l),t.lineTo(e.x+n(a)*o,e.y+i(a)*o),t.lineTo(e.x+n(e.angle)*r,e.y+i(e.angle)*r),t.lineTo(e.x-n(a)*o,e.y-i(a)*o),t.lineTo(s,l)},e}(ks);function fk(t,e){var n=null==t?"":t+"";return e&&(U(e)?n=e.replace("{value}",n):X(e)&&(n=e(t))),n}var gk=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){this.group.removeAll();var i=t.get(["axisLine","lineStyle","color"]),r=function(t,e){var n=t.get("center"),i=e.getWidth(),r=e.getHeight(),o=Math.min(i,r);return{cx:$r(n[0],e.getWidth()),cy:$r(n[1],e.getHeight()),r:$r(t.get("radius"),o/2)}}(t,n);this._renderMain(t,e,n,i,r),this._data=t.getData()},e.prototype.dispose=function(){},e.prototype._renderMain=function(t,e,n,i,r){var o=this.group,a=t.get("clockwise"),s=-t.get("startAngle")/180*Math.PI,l=-t.get("endAngle")/180*Math.PI,u=t.getModel("axisLine"),h=u.get("roundCap")?JS:Fu,c=u.get("show"),p=u.getModel("lineStyle"),d=p.get("width"),f=[s,l];us(f,!a);for(var g=(l=f[1])-(s=f[0]),y=s,v=[],m=0;c&&m=t&&(0===e?0:i[e-1][0])Math.PI/2&&(V+=Math.PI):"tangential"===z?V=-M-Math.PI/2:j(z)&&(V=z*Math.PI/180),0===V?c.add(new Xs({style:oc(x,{text:O,x:N,y:E,verticalAlign:h<-.8?"top":h>.8?"bottom":"middle",align:u<-.4?"left":u>.4?"right":"center"},{inheritColor:R}),silent:!0})):c.add(new Xs({style:oc(x,{text:O,x:N,y:E,verticalAlign:"middle",align:"center"},{inheritColor:R}),silent:!0,originX:N,originY:E,rotation:V}))}if(m.get("show")&&k!==_){P=(P=m.get("distance"))?P+l:l;for(var B=0;B<=b;B++){u=Math.cos(M),h=Math.sin(M);var F=new Ku({shape:{x1:u*(f-P)+p,y1:h*(f-P)+d,x2:u*(f-S-P)+p,y2:h*(f-S-P)+d},silent:!0,style:D});"auto"===D.stroke&&F.setStyle({stroke:i((k+B/b)/_)}),c.add(F),M+=T}M-=T}else M+=I}},e.prototype._renderPointer=function(t,e,n,i,r,o,a,s,l){var u=this.group,h=this._data,c=this._progressEls,p=[],d=t.get(["pointer","show"]),f=t.getModel("progress"),g=f.get("show"),y=t.getData(),v=y.mapDimension("value"),m=+t.get("min"),x=+t.get("max"),_=[m,x],b=[o,a];function w(e,n){var i,o=y.getItemModel(e).getModel("pointer"),a=$r(o.get("width"),r.r),s=$r(o.get("length"),r.r),l=t.get(["pointer","icon"]),u=o.get("offsetCenter"),h=$r(u[0],r.r),c=$r(u[1],r.r),p=o.get("keepAspect");return(i=l?Xy(l,h-a/2,c-s,a,s,null,p):new dk({shape:{angle:-Math.PI/2,width:a,r:s,x:h,y:c}})).rotation=-(n+Math.PI/2),i.x=r.cx,i.y=r.cy,i}function S(t,e){var n=f.get("roundCap")?JS:Fu,i=f.get("overlap"),a=i?f.get("width"):l/y.count(),u=i?r.r-a:r.r-(t+1)*a,h=i?r.r:r.r-t*a,c=new n({shape:{startAngle:o,endAngle:e,cx:r.cx,cy:r.cy,clockwise:s,r0:u,r:h}});return i&&(c.z2=Kr(y.get(v,t),[m,x],[100,0],!0)),c}(g||d)&&(y.diff(h).add((function(e){var n=y.get(v,e);if(d){var i=w(e,o);mh(i,{rotation:-((isNaN(+n)?b[0]:Kr(n,_,b,!0))+Math.PI/2)},t),u.add(i),y.setItemGraphicEl(e,i)}if(g){var r=S(e,o),a=f.get("clip");mh(r,{shape:{endAngle:Kr(n,_,b,a)}},t),u.add(r),ol(t.seriesIndex,y.dataType,e,r),p[e]=r}})).update((function(e,n){var i=y.get(v,e);if(d){var r=h.getItemGraphicEl(n),a=r?r.rotation:o,s=w(e,a);s.rotation=a,vh(s,{rotation:-((isNaN(+i)?b[0]:Kr(i,_,b,!0))+Math.PI/2)},t),u.add(s),y.setItemGraphicEl(e,s)}if(g){var l=c[n],m=S(e,l?l.shape.endAngle:o),x=f.get("clip");vh(m,{shape:{endAngle:Kr(i,_,b,x)}},t),u.add(m),ol(t.seriesIndex,y.dataType,e,m),p[e]=m}})).execute(),y.each((function(t){var e=y.getItemModel(t),n=e.getModel("emphasis"),r=n.get("focus"),o=n.get("blurScope"),a=n.get("disabled");if(d){var s=y.getItemGraphicEl(t),l=y.getItemVisual(t,"style"),u=l.fill;if(s instanceof Ns){var h=s.style;s.useStyle(A({image:h.image,x:h.x,y:h.y,width:h.width,height:h.height},l))}else s.useStyle(l),"pointer"!==s.type&&s.setColor(u);s.setStyle(e.getModel(["pointer","itemStyle"]).getItemStyle()),"auto"===s.style.fill&&s.setStyle("fill",i(Kr(y.get(v,t),_,[0,1],!0))),s.z2EmphasisLift=0,$l(s,e),Zl(s,r,o,a)}if(g){var c=p[t];c.useStyle(y.getItemVisual(t,"style")),c.setStyle(e.getModel(["progress","itemStyle"]).getItemStyle()),c.z2EmphasisLift=0,$l(c,e),Zl(c,r,o,a)}})),this._progressEls=p)},e.prototype._renderAnchor=function(t,e){var n=t.getModel("anchor");if(n.get("show")){var i=n.get("size"),r=n.get("icon"),o=n.get("offsetCenter"),a=n.get("keepAspect"),s=Xy(r,e.cx-i/2+$r(o[0],e.r),e.cy-i/2+$r(o[1],e.r),i,i,null,a);s.z2=n.get("showAbove")?1:0,s.setStyle(n.getModel("itemStyle").getItemStyle()),this.group.add(s)}},e.prototype._renderTitleAndDetail=function(t,e,n,i,r){var o=this,a=t.getData(),s=a.mapDimension("value"),l=+t.get("min"),u=+t.get("max"),h=new Br,c=[],p=[],d=t.isAnimationEnabled(),f=t.get(["pointer","showAbove"]);a.diff(this._data).add((function(t){c[t]=new Xs({silent:!0}),p[t]=new Xs({silent:!0})})).update((function(t,e){c[t]=o._titleEls[e],p[t]=o._detailEls[e]})).execute(),a.each((function(e){var n=a.getItemModel(e),o=a.get(s,e),g=new Br,y=i(Kr(o,[l,u],[0,1],!0)),v=n.getModel("title");if(v.get("show")){var m=v.get("offsetCenter"),x=r.cx+$r(m[0],r.r),_=r.cy+$r(m[1],r.r);(D=c[e]).attr({z2:f?0:2,style:oc(v,{x:x,y:_,text:a.getName(e),align:"center",verticalAlign:"middle"},{inheritColor:y})}),g.add(D)}var b=n.getModel("detail");if(b.get("show")){var w=b.get("offsetCenter"),S=r.cx+$r(w[0],r.r),M=r.cy+$r(w[1],r.r),I=$r(b.get("width"),r.r),T=$r(b.get("height"),r.r),C=t.get(["progress","show"])?a.getItemVisual(e,"style").fill:y,D=p[e],A=b.get("formatter");D.attr({z2:f?0:2,style:oc(b,{x:S,y:M,text:fk(o,A),width:isNaN(I)?null:I,height:isNaN(T)?null:T,align:"center",verticalAlign:"middle"},{inheritColor:C})}),dc(D,{normal:b},o,(function(t){return fk(t,A)})),d&&fc(D,e,a,t,{getFormattedLabel:function(t,e,n,i,r,a){return fk(a?a.interpolatedValue:o,A)}}),g.add(D)}h.add(g)})),this.group.add(h),this._titleEls=c,this._detailEls=p},e.type="gauge",e}(Og),yk=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.visualStyleAccessPath="itemStyle",n}return n(e,t),e.prototype.getInitialData=function(t,e){return RM(this,["value"])},e.type="series.gauge",e.defaultOption={z:2,colorBy:"data",center:["50%","50%"],legendHoverLink:!0,radius:"75%",startAngle:225,endAngle:-45,clockwise:!0,min:0,max:100,splitNumber:10,axisLine:{show:!0,roundCap:!1,lineStyle:{color:[[1,"#E6EBF8"]],width:10}},progress:{show:!1,overlap:!0,width:10,roundCap:!1,clip:!0},splitLine:{show:!0,length:10,distance:10,lineStyle:{color:"#63677A",width:3,type:"solid"}},axisTick:{show:!0,splitNumber:5,length:6,distance:10,lineStyle:{color:"#63677A",width:1,type:"solid"}},axisLabel:{show:!0,distance:15,color:"#464646",fontSize:12,rotate:0},pointer:{icon:null,offsetCenter:[0,0],show:!0,showAbove:!0,length:"60%",width:6,keepAspect:!1},anchor:{show:!1,showAbove:!1,size:6,icon:"circle",offsetCenter:[0,0],keepAspect:!1,itemStyle:{color:"#fff",borderWidth:0,borderColor:"#5470c6"}},title:{show:!0,offsetCenter:[0,"20%"],color:"#464646",fontSize:16,valueAnimation:!1},detail:{show:!0,backgroundColor:"rgba(0,0,0,0)",borderWidth:0,borderColor:"#ccc",width:100,height:null,padding:[5,10],offsetCenter:[0,"40%"],color:"#464646",fontSize:30,fontWeight:"bold",lineHeight:30,valueAnimation:!1}},e}(bg);var vk=["itemStyle","opacity"],mk=function(t){function e(e,n){var i=t.call(this)||this,r=i,o=new Zu,a=new Xs;return r.setTextContent(a),i.setTextGuideLine(o),i.updateData(e,n,!0),i}return n(e,t),e.prototype.updateData=function(t,e,n){var i=this,r=t.hostModel,o=t.getItemModel(e),a=t.getItemLayout(e),s=o.getModel("emphasis"),l=o.get(vk);l=null==l?1:l,n||Sh(i),i.useStyle(t.getItemVisual(e,"style")),i.style.lineJoin="round",n?(i.setShape({points:a.points}),i.style.opacity=0,mh(i,{style:{opacity:l}},r,e)):vh(i,{style:{opacity:l},shape:{points:a.points}},r,e),$l(i,o),this._updateLabel(t,e),Zl(this,s.get("focus"),s.get("blurScope"),s.get("disabled"))},e.prototype._updateLabel=function(t,e){var n=this,i=this.getTextGuideLine(),r=n.getTextContent(),o=t.hostModel,a=t.getItemModel(e),s=t.getItemLayout(e).label,l=t.getItemVisual(e,"style"),u=l.fill;ic(r,rc(a),{labelFetcher:t.hostModel,labelDataIndex:e,defaultOpacity:l.opacity,defaultText:t.getName(e)},{normal:{align:s.textAlign,verticalAlign:s.verticalAlign}}),n.setTextConfig({local:!0,inside:!!s.inside,insideStroke:u,outsideFill:u});var h=s.linePoints;i.setShape({points:h}),n.textGuideLineConfig={anchor:h?new De(h[0][0],h[0][1]):null},vh(r,{style:{x:s.x,y:s.y}},o,e),r.attr({rotation:s.rotation,originX:s.x,originY:s.y,z2:10}),kb(n,Lb(a),{stroke:u})},e}(Xu),xk=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.ignoreLabelLineUpdate=!0,n}return n(e,t),e.prototype.render=function(t,e,n){var i=t.getData(),r=this._data,o=this.group;i.diff(r).add((function(t){var e=new mk(i,t);i.setItemGraphicEl(t,e),o.add(e)})).update((function(t,e){var n=r.getItemGraphicEl(e);n.updateData(i,t),o.add(n),i.setItemGraphicEl(t,n)})).remove((function(e){wh(r.getItemGraphicEl(e),t,e)})).execute(),this._data=i},e.prototype.remove=function(){this.group.removeAll(),this._data=null},e.prototype.dispose=function(){},e.type="funnel",e}(Og),_k=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(e){t.prototype.init.apply(this,arguments),this.legendVisualProvider=new NM(W(this.getData,this),W(this.getRawData,this)),this._defaultLabelLine(e)},e.prototype.getInitialData=function(t,e){return RM(this,{coordDimensions:["value"],encodeDefaulter:H(ed,this)})},e.prototype._defaultLabelLine=function(t){Co(t,"labelLine",["show"]);var e=t.labelLine,n=t.emphasis.labelLine;e.show=e.show&&t.label.show,n.show=n.show&&t.emphasis.label.show},e.prototype.getDataParams=function(e){var n=this.getData(),i=t.prototype.getDataParams.call(this,e),r=n.mapDimension("value"),o=n.getSum(r);return i.percent=o?+(n.get(r,e)/o*100).toFixed(2):0,i.$vars.push("percent"),i},e.type="series.funnel",e.defaultOption={z:2,legendHoverLink:!0,colorBy:"data",left:80,top:60,right:80,bottom:60,minSize:"0%",maxSize:"100%",sort:"descending",orient:"vertical",gap:0,funnelAlign:"center",label:{show:!0,position:"outer"},labelLine:{show:!0,length:20,lineStyle:{width:1}},itemStyle:{borderColor:"#fff",borderWidth:1},emphasis:{label:{show:!0}},select:{itemStyle:{borderColor:"#212121"}}},e}(bg);function bk(t,e){t.eachSeriesByType("funnel",(function(t){var n=t.getData(),i=n.mapDimension("value"),r=t.get("sort"),o=function(t,e){return kp(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()})}(t,e),a=t.get("orient"),s=o.width,l=o.height,u=function(t,e){for(var n=t.mapDimension("value"),i=t.mapArray(n,(function(t){return t})),r=[],o="ascending"===e,a=0,s=t.count();a5)return;var i=this._model.coordinateSystem.getSlidedAxisExpandWindow([t.offsetX,t.offsetY]);"none"!==i.behavior&&this._dispatchExpand({axisExpandWindow:i.axisExpandWindow})}this._mouseDownPoint=null},mousemove:function(t){if(!this._mouseDownPoint&&Rk(this,"mousemove")){var e=this._model,n=e.coordinateSystem.getSlidedAxisExpandWindow([t.offsetX,t.offsetY]),i=n.behavior;"jump"===i&&this._throttledDispatchExpand.debounceNextCall(e.get("axisExpandDebounce")),this._throttledDispatchExpand("none"===i?null:{axisExpandWindow:n.axisExpandWindow,animation:"jump"===i?null:{duration:0}})}}};function Rk(t,e){var n=t._model;return n.get("axisExpandable")&&n.get("axisExpandTriggerOn")===e}var Nk=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(){t.prototype.init.apply(this,arguments),this.mergeOption({})},e.prototype.mergeOption=function(t){var e=this.option;t&&C(e,t,!0),this._initDimensions()},e.prototype.contains=function(t,e){var n=t.get("parallelIndex");return null!=n&&e.getComponent("parallel",n)===this},e.prototype.setAxisExpand=function(t){E(["axisExpandable","axisExpandCenter","axisExpandCount","axisExpandWidth","axisExpandWindow"],(function(e){t.hasOwnProperty(e)&&(this.option[e]=t[e])}),this)},e.prototype._initDimensions=function(){var t=this.dimensions=[],e=this.parallelAxisIndex=[];E(B(this.ecModel.queryComponents({mainType:"parallelAxis"}),(function(t){return(t.get("parallelIndex")||0)===this.componentIndex}),this),(function(n){t.push("dim"+n.get("dim")),e.push(n.componentIndex)}))},e.type="parallel",e.dependencies=["parallelAxis"],e.layoutMode="box",e.defaultOption={z:0,left:80,top:60,right:80,bottom:60,layout:"horizontal",axisExpandable:!1,axisExpandCenter:null,axisExpandCount:0,axisExpandWidth:50,axisExpandRate:17,axisExpandDebounce:50,axisExpandSlideTriggerArea:[-.15,.05,.4],axisExpandTriggerOn:"click",parallelAxisDefault:null},e}(zp),Ek=function(t){function e(e,n,i,r,o){var a=t.call(this,e,n,i)||this;return a.type=r||"value",a.axisIndex=o,a}return n(e,t),e.prototype.isHorizontal=function(){return"horizontal"!==this.coordinateSystem.getModel().get("layout")},e}(ab);function zk(t,e,n,i,r,o){t=t||0;var a=n[1]-n[0];if(null!=r&&(r=Bk(r,[0,a])),null!=o&&(o=Math.max(o,null!=r?r:0)),"all"===i){var s=Math.abs(e[1]-e[0]);s=Bk(s,[0,a]),r=o=Bk(s,[r,o]),i=0}e[0]=Bk(e[0],n),e[1]=Bk(e[1],n);var l=Vk(e,i);e[i]+=t;var u,h=r||0,c=n.slice();return l.sign<0?c[0]+=h:c[1]-=h,e[i]=Bk(e[i],c),u=Vk(e,i),null!=r&&(u.sign!==l.sign||u.spano&&(e[1-i]=e[i]+u.sign*o),e}function Vk(t,e){var n=t[e]-t[1-e];return{span:Math.abs(n),sign:n>0?-1:n<0?1:e?-1:1}}function Bk(t,e){return Math.min(null!=e[1]?e[1]:1/0,Math.max(null!=e[0]?e[0]:-1/0,t))}var Fk=E,Gk=Math.min,Wk=Math.max,Hk=Math.floor,Yk=Math.ceil,Xk=Jr,Uk=Math.PI,Zk=function(){function t(t,e,n){this.type="parallel",this._axesMap=yt(),this._axesLayout={},this.dimensions=t.dimensions,this._model=t,this._init(t,e,n)}return t.prototype._init=function(t,e,n){var i=t.dimensions,r=t.parallelAxisIndex;Fk(i,(function(t,n){var i=r[n],o=e.getComponent("parallelAxis",i),a=this._axesMap.set(t,new Ek(t,b_(o),[0,0],o.get("type"),i)),s="category"===a.type;a.onBand=s&&o.get("boundaryGap"),a.inverse=o.get("inverse"),o.axis=a,a.model=o,a.coordinateSystem=o.coordinateSystem=this}),this)},t.prototype.update=function(t,e){this._updateAxesFromSeries(this._model,t)},t.prototype.containPoint=function(t){var e=this._makeLayoutInfo(),n=e.axisBase,i=e.layoutBase,r=e.pixelDimIndex,o=t[1-r],a=t[r];return o>=n&&o<=n+e.axisLength&&a>=i&&a<=i+e.layoutLength},t.prototype.getModel=function(){return this._model},t.prototype._updateAxesFromSeries=function(t,e){e.eachSeries((function(n){if(t.contains(n,e)){var i=n.getData();Fk(this.dimensions,(function(t){var e=this._axesMap.get(t);e.scale.unionExtentFromData(i,i.mapDimension(t)),__(e.scale,e.model)}),this)}}),this)},t.prototype.resize=function(t,e){this._rect=kp(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()}),this._layoutAxes()},t.prototype.getRect=function(){return this._rect},t.prototype._makeLayoutInfo=function(){var t,e=this._model,n=this._rect,i=["x","y"],r=["width","height"],o=e.get("layout"),a="horizontal"===o?0:1,s=n[r[a]],l=[0,s],u=this.dimensions.length,h=jk(e.get("axisExpandWidth"),l),c=jk(e.get("axisExpandCount")||0,[0,u]),p=e.get("axisExpandable")&&u>3&&u>c&&c>1&&h>0&&s>0,d=e.get("axisExpandWindow");d?(t=jk(d[1]-d[0],l),d[1]=d[0]+t):(t=jk(h*(c-1),l),(d=[h*(e.get("axisExpandCenter")||Hk(u/2))-t/2])[1]=d[0]+t);var f=(s-t)/(u-c);f<3&&(f=0);var g=[Hk(Xk(d[0]/h,1))+1,Yk(Xk(d[1]/h,1))-1],y=f/h*d[0];return{layout:o,pixelDimIndex:a,layoutBase:n[i[a]],layoutLength:s,axisBase:n[i[1-a]],axisLength:n[r[1-a]],axisExpandable:p,axisExpandWidth:h,axisCollapseWidth:f,axisExpandWindow:d,axisCount:u,winInnerIndices:g,axisExpandWindow0Pos:y}},t.prototype._layoutAxes=function(){var t=this._rect,e=this._axesMap,n=this.dimensions,i=this._makeLayoutInfo(),r=i.layout;e.each((function(t){var e=[0,i.axisLength],n=t.inverse?1:0;t.setExtent(e[n],e[1-n])})),Fk(n,(function(e,n){var o=(i.axisExpandable?Kk:qk)(n,i),a={horizontal:{x:o.position,y:i.axisLength},vertical:{x:0,y:o.position}},s={horizontal:Uk/2,vertical:0},l=[a[r].x+t.x,a[r].y+t.y],u=s[r],h=[1,0,0,1,0,0];Se(h,h,u),we(h,h,l),this._axesLayout[e]={position:l,rotation:u,transform:h,axisNameAvailableWidth:o.axisNameAvailableWidth,axisLabelShow:o.axisLabelShow,nameTruncateMaxWidth:o.nameTruncateMaxWidth,tickDirection:1,labelDirection:1}}),this)},t.prototype.getAxis=function(t){return this._axesMap.get(t)},t.prototype.dataToPoint=function(t,e){return this.axisCoordToPoint(this._axesMap.get(e).dataToCoord(t),e)},t.prototype.eachActiveState=function(t,e,n,i){null==n&&(n=0),null==i&&(i=t.count());var r=this._axesMap,o=this.dimensions,a=[],s=[];E(o,(function(e){a.push(t.mapDimension(e)),s.push(r.get(e).model)}));for(var l=this.hasAxisBrushed(),u=n;ur*(1-h[0])?(l="jump",a=s-r*(1-h[2])):(a=s-r*h[1])>=0&&(a=s-r*(1-h[1]))<=0&&(a=0),(a*=e.axisExpandWidth/u)?zk(a,i,o,"all"):l="none";else{var p=i[1]-i[0];(i=[Wk(0,o[1]*s/p-p/2)])[1]=Gk(o[1],i[0]+p),i[0]=i[1]-p}return{axisExpandWindow:i,behavior:l}},t}();function jk(t,e){return Gk(Wk(t,e[0]),e[1])}function qk(t,e){var n=e.layoutLength/(e.axisCount-1);return{position:n*t,axisNameAvailableWidth:n,axisLabelShow:!0}}function Kk(t,e){var n,i,r=e.layoutLength,o=e.axisExpandWidth,a=e.axisCount,s=e.axisCollapseWidth,l=e.winInnerIndices,u=s,h=!1;return t=0;n--)Qr(e[n])},e.prototype.getActiveState=function(t){var e=this.activeIntervals;if(!e.length)return"normal";if(null==t||isNaN(+t))return"inactive";if(1===e.length){var n=e[0];if(n[0]<=t&&t<=n[1])return"active"}else for(var i=0,r=e.length;i6}(t)||o){if(a&&!o){"single"===s.brushMode&&vL(t);var l=T(s);l.brushType=RL(l.brushType,a),l.panelId=a===Qk?null:a.panelId,o=t._creatingCover=uL(t,l),t._covers.push(o)}if(o){var u=zL[RL(t._brushType,a)];o.__brushOption.range=u.getCreatingRange(kL(t,o,t._track)),i&&(hL(t,o),u.updateCommon(t,o)),cL(t,o),r={isEnd:i}}}else i&&"single"===s.brushMode&&s.removeOnClick&&gL(t,e,n)&&vL(t)&&(r={isEnd:i,removeOnClick:!0});return r}function RL(t,e){return"auto"===t?e.defaultBrushType:t}var NL={mousedown:function(t){if(this._dragging)EL(this,t);else if(!t.target||!t.target.draggable){LL(t);var e=this.group.transformCoordToLocal(t.offsetX,t.offsetY);this._creatingCover=null,(this._creatingPanel=gL(this,t,e))&&(this._dragging=!0,this._track=[e.slice()])}},mousemove:function(t){var e=t.offsetX,n=t.offsetY,i=this.group.transformCoordToLocal(e,n);if(function(t,e,n){if(t._brushType&&!function(t,e,n){var i=t._zr;return e<0||e>i.getWidth()||n<0||n>i.getHeight()}(t,e.offsetX,e.offsetY)){var i=t._zr,r=t._covers,o=gL(t,e,n);if(!t._dragging)for(var a=0;a=0&&(o[r[a].depth]=new Cc(r[a],this,e));var s=uk(i,n,this,!0,(function(t,e){t.wrapMethod("getItemModel",(function(t,e){var n=t.parentModel,i=n.getData().getItemLayout(e);if(i){var r=i.depth,o=n.levelModels[r];o&&(t.parentModel=o)}return t})),e.wrapMethod("getItemModel",(function(t,e){var n=t.parentModel,i=n.getGraph().getEdgeByIndex(e).node1.getLayout();if(i){var r=i.depth,o=n.levelModels[r];o&&(t.parentModel=o)}return t}))}));return s.data},e.prototype.setNodePosition=function(t,e){var n=(this.option.data||this.option.nodes)[t];n.localX=e[0],n.localY=e[1]},e.prototype.getGraph=function(){return this.getData().graph},e.prototype.getEdgeData=function(){return this.getGraph().edgeData},e.prototype.formatTooltip=function(t,e,n){function i(t){return isNaN(t)||null==t}if("edge"===n){var r=this.getDataParams(t,n),o=r.data,a=r.value;return og("nameValue",{name:o.source+" -- "+o.target,value:a,noValue:i(a)})}var s=this.getGraph().getNodeByIndex(t).getLayout().value,l=this.getDataParams(t,n).data.name;return og("nameValue",{name:null!=l?l+"":null,value:s,noValue:i(s)})},e.prototype.optionUpdated=function(){},e.prototype.getDataParams=function(e,n){var i=t.prototype.getDataParams.call(this,e,n);if(null==i.value&&"node"===n){var r=this.getGraph().getNodeByIndex(e).getLayout().value;i.value=r}return i},e.type="series.sankey",e.defaultOption={z:2,coordinateSystem:"view",left:"5%",top:"5%",right:"20%",bottom:"5%",orient:"horizontal",nodeWidth:20,nodeGap:8,draggable:!0,layoutIterations:32,label:{show:!0,position:"right",fontSize:12},edgeLabel:{show:!1,fontSize:12},levels:[],nodeAlign:"justify",lineStyle:{color:"#314656",opacity:.2,curveness:.5},emphasis:{label:{show:!0},lineStyle:{opacity:.5}},select:{itemStyle:{borderColor:"#212121"}},animationEasing:"linear",animationDuration:1e3},e}(bg);function QL(t,e){t.eachSeriesByType("sankey",(function(t){var n=t.get("nodeWidth"),i=t.get("nodeGap"),r=function(t,e){return kp(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()})}(t,e);t.layoutInfo=r;var o=r.width,a=r.height,s=t.getGraph(),l=s.nodes,u=s.edges;!function(t){E(t,(function(t){var e=uP(t.outEdges,lP),n=uP(t.inEdges,lP),i=t.getValue()||0,r=Math.max(e,n,i);t.setLayout({value:r},!0)}))}(l),function(t,e,n,i,r,o,a,s,l){(function(t,e,n,i,r,o,a){for(var s=[],l=[],u=[],h=[],c=0,p=0;p=0;v&&y.depth>d&&(d=y.depth),g.setLayout({depth:v?y.depth:c},!0),"vertical"===o?g.setLayout({dy:n},!0):g.setLayout({dx:n},!0);for(var m=0;mc-1?d:c-1;a&&"left"!==a&&function(t,e,n,i){if("right"===e){for(var r=[],o=t,a=0;o.length;){for(var s=0;s0;o--)nP(s,l*=.99,a),eP(s,r,n,i,a),hP(s,l,a),eP(s,r,n,i,a)}(t,e,o,r,i,a,s),function(t,e){var n="vertical"===e?"x":"y";E(t,(function(t){t.outEdges.sort((function(t,e){return t.node2.getLayout()[n]-e.node2.getLayout()[n]})),t.inEdges.sort((function(t,e){return t.node1.getLayout()[n]-e.node1.getLayout()[n]}))})),E(t,(function(t){var e=0,n=0;E(t.outEdges,(function(t){t.setLayout({sy:e},!0),e+=t.getLayout().dy})),E(t.inEdges,(function(t){t.setLayout({ty:n},!0),n+=t.getLayout().dy}))}))}(t,s)}(l,u,n,i,o,a,0!==B(l,(function(t){return 0===t.getLayout().value})).length?0:t.get("layoutIterations"),t.get("orient"),t.get("nodeAlign"))}))}function tP(t){var e=t.hostGraph.data.getRawDataItem(t.dataIndex);return null!=e.depth&&e.depth>=0}function eP(t,e,n,i,r){var o="vertical"===r?"x":"y";E(t,(function(t){var a,s,l;t.sort((function(t,e){return t.getLayout()[o]-e.getLayout()[o]}));for(var u=0,h=t.length,c="vertical"===r?"dx":"dy",p=0;p0&&(a=s.getLayout()[o]+l,"vertical"===r?s.setLayout({x:a},!0):s.setLayout({y:a},!0)),u=s.getLayout()[o]+s.getLayout()[c]+e;if((l=u-e-("vertical"===r?i:n))>0){a=s.getLayout()[o]-l,"vertical"===r?s.setLayout({x:a},!0):s.setLayout({y:a},!0),u=a;for(p=h-2;p>=0;--p)(l=(s=t[p]).getLayout()[o]+s.getLayout()[c]+e-u)>0&&(a=s.getLayout()[o]-l,"vertical"===r?s.setLayout({x:a},!0):s.setLayout({y:a},!0)),u=s.getLayout()[o]}}))}function nP(t,e,n){E(t.slice().reverse(),(function(t){E(t,(function(t){if(t.outEdges.length){var i=uP(t.outEdges,iP,n)/uP(t.outEdges,lP);if(isNaN(i)){var r=t.outEdges.length;i=r?uP(t.outEdges,rP,n)/r:0}if("vertical"===n){var o=t.getLayout().x+(i-sP(t,n))*e;t.setLayout({x:o},!0)}else{var a=t.getLayout().y+(i-sP(t,n))*e;t.setLayout({y:a},!0)}}}))}))}function iP(t,e){return sP(t.node2,e)*t.getValue()}function rP(t,e){return sP(t.node2,e)}function oP(t,e){return sP(t.node1,e)*t.getValue()}function aP(t,e){return sP(t.node1,e)}function sP(t,e){return"vertical"===e?t.getLayout().x+t.getLayout().dx/2:t.getLayout().y+t.getLayout().dy/2}function lP(t){return t.getValue()}function uP(t,e,n){for(var i=0,r=t.length,o=-1;++oo&&(o=e)})),E(n,(function(e){var n=new kD({type:"color",mappingMethod:"linear",dataExtent:[r,o],visual:t.get("color")}).mapValueToVisual(e.getLayout().value),i=e.getModel().get(["itemStyle","color"]);null!=i?(e.setVisual("color",i),e.setVisual("style",{fill:i})):(e.setVisual("color",n),e.setVisual("style",{fill:n}))}))}i.length&&E(i,(function(t){var e=t.getModel().get("lineStyle");t.setVisual("style",e)}))}))}var pP=function(){function t(){}return t.prototype._hasEncodeRule=function(t){var e=this.getEncode();return e&&null!=e.get(t)},t.prototype.getInitialData=function(t,e){var n,i,r=e.getComponent("xAxis",this.get("xAxisIndex")),o=e.getComponent("yAxis",this.get("yAxisIndex")),a=r.get("type"),s=o.get("type");"category"===a?(t.layout="horizontal",n=r.getOrdinalMeta(),i=!this._hasEncodeRule("x")):"category"===s?(t.layout="vertical",n=o.getOrdinalMeta(),i=!this._hasEncodeRule("y")):t.layout=t.layout||"horizontal";var l=["x","y"],u="horizontal"===t.layout?0:1,h=this._baseAxisDim=l[u],c=l[1-u],p=[r,o],d=p[u].get("type"),f=p[1-u].get("type"),g=t.data;if(g&&i){var y=[];E(g,(function(t,e){var n;Y(t)?(n=t.slice(),t.unshift(e)):Y(t.value)?((n=A({},t)).value=n.value.slice(),t.value.unshift(e)):n=t,y.push(n)})),t.data=y}var v=this.defaultValueDimensions,m=[{name:h,type:Ym(d),ordinalMeta:n,otherDims:{tooltip:!1,itemName:0},dimsDef:["base"]},{name:c,type:Ym(f),dimsDef:v.slice()}];return RM(this,{coordDimensions:m,dimensionsCount:v.length+1,encodeDefaulter:H(td,m,this)})},t.prototype.getBaseAxis=function(){var t=this._baseAxisDim;return this.ecModel.getComponent(t+"Axis",this.get(t+"AxisIndex")).axis},t}(),dP=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.defaultValueDimensions=[{name:"min",defaultTooltip:!0},{name:"Q1",defaultTooltip:!0},{name:"median",defaultTooltip:!0},{name:"Q3",defaultTooltip:!0},{name:"max",defaultTooltip:!0}],n.visualDrawType="stroke",n}return n(e,t),e.type="series.boxplot",e.dependencies=["xAxis","yAxis","grid"],e.defaultOption={z:2,coordinateSystem:"cartesian2d",legendHoverLink:!0,layout:null,boxWidth:[7,50],itemStyle:{color:"#fff",borderWidth:1},emphasis:{scale:!0,itemStyle:{borderWidth:2,shadowBlur:5,shadowOffsetX:1,shadowOffsetY:1,shadowColor:"rgba(0,0,0,0.2)"}},animationDuration:800},e}(bg);R(dP,pP,!0);var fP=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){var i=t.getData(),r=this.group,o=this._data;this._data||r.removeAll();var a="horizontal"===t.get("layout")?1:0;i.diff(o).add((function(t){if(i.hasValue(t)){var e=vP(i.getItemLayout(t),i,t,a,!0);i.setItemGraphicEl(t,e),r.add(e)}})).update((function(t,e){var n=o.getItemGraphicEl(e);if(i.hasValue(t)){var s=i.getItemLayout(t);n?(Sh(n),mP(s,n,i,t)):n=vP(s,i,t,a),r.add(n),i.setItemGraphicEl(t,n)}else r.remove(n)})).remove((function(t){var e=o.getItemGraphicEl(t);e&&r.remove(e)})).execute(),this._data=i},e.prototype.remove=function(t){var e=this.group,n=this._data;this._data=null,n&&n.eachItemGraphicEl((function(t){t&&e.remove(t)}))},e.type="boxplot",e}(Og),gP=function(){},yP=function(t){function e(e){var n=t.call(this,e)||this;return n.type="boxplotBoxPath",n}return n(e,t),e.prototype.getDefaultShape=function(){return new gP},e.prototype.buildPath=function(t,e){var n=e.points,i=0;for(t.moveTo(n[i][0],n[i][1]),i++;i<4;i++)t.lineTo(n[i][0],n[i][1]);for(t.closePath();ig){var _=[v,x];i.push(_)}}}return{boxData:n,outliers:i}}(e.getRawData(),t.config);return[{dimensions:["ItemName","Low","Q1","Q2","Q3","High"],data:i.boxData},{data:i.outliers}]}};var SP=["itemStyle","borderColor"],MP=["itemStyle","borderColor0"],IP=["itemStyle","borderColorDoji"],TP=["itemStyle","color"],CP=["itemStyle","color0"];function DP(t,e){return e.get(t>0?TP:CP)}function AP(t,e){return e.get(0===t?IP:t>0?SP:MP)}var kP={seriesType:"candlestick",plan:kg(),performRawSeries:!0,reset:function(t,e){if(!e.isSeriesFiltered(t))return!t.pipelineContext.large&&{progress:function(t,e){for(var n;null!=(n=t.next());){var i=e.getItemModel(n),r=e.getItemLayout(n).sign,o=i.getItemStyle();o.fill=DP(r,i),o.stroke=AP(r,i)||o.fill,A(e.ensureUniqueItemVisual(n,"style"),o)}}}}},LP=["color","borderColor"],PP=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){this.group.removeClipPath(),this._progressiveEls=null,this._updateDrawMode(t),this._isLargeDraw?this._renderLarge(t):this._renderNormal(t)},e.prototype.incrementalPrepareRender=function(t,e,n){this._clear(),this._updateDrawMode(t)},e.prototype.incrementalRender=function(t,e,n,i){this._progressiveEls=[],this._isLargeDraw?this._incrementalRenderLarge(t,e):this._incrementalRenderNormal(t,e)},e.prototype.eachRendered=function(t){Jh(this._progressiveEls||this.group,t)},e.prototype._updateDrawMode=function(t){var e=t.pipelineContext.large;null!=this._isLargeDraw&&e===this._isLargeDraw||(this._isLargeDraw=e,this._clear())},e.prototype._renderNormal=function(t){var e=t.getData(),n=this._data,i=this.group,r=e.getLayout("isSimpleBox"),o=t.get("clip",!0),a=t.coordinateSystem,s=a.getArea&&a.getArea();this._data||i.removeAll(),e.diff(n).add((function(n){if(e.hasValue(n)){var a=e.getItemLayout(n);if(o&&EP(s,a))return;var l=NP(a,n,!0);mh(l,{shape:{points:a.ends}},t,n),zP(l,e,n,r),i.add(l),e.setItemGraphicEl(n,l)}})).update((function(a,l){var u=n.getItemGraphicEl(l);if(e.hasValue(a)){var h=e.getItemLayout(a);o&&EP(s,h)?i.remove(u):(u?(vh(u,{shape:{points:h.ends}},t,a),Sh(u)):u=NP(h),zP(u,e,a,r),i.add(u),e.setItemGraphicEl(a,u))}else i.remove(u)})).remove((function(t){var e=n.getItemGraphicEl(t);e&&i.remove(e)})).execute(),this._data=e},e.prototype._renderLarge=function(t){this._clear(),GP(t,this.group);var e=t.get("clip",!0)?PS(t.coordinateSystem,!1,t):null;e?this.group.setClipPath(e):this.group.removeClipPath()},e.prototype._incrementalRenderNormal=function(t,e){for(var n,i=e.getData(),r=i.getLayout("isSimpleBox");null!=(n=t.next());){var o=NP(i.getItemLayout(n));zP(o,i,n,r),o.incremental=!0,this.group.add(o),this._progressiveEls.push(o)}},e.prototype._incrementalRenderLarge=function(t,e){GP(e,this.group,this._progressiveEls,!0)},e.prototype.remove=function(t){this._clear()},e.prototype._clear=function(){this.group.removeAll(),this._data=null},e.type="candlestick",e}(Og),OP=function(){},RP=function(t){function e(e){var n=t.call(this,e)||this;return n.type="normalCandlestickBox",n}return n(e,t),e.prototype.getDefaultShape=function(){return new OP},e.prototype.buildPath=function(t,e){var n=e.points;this.__simpleBox?(t.moveTo(n[4][0],n[4][1]),t.lineTo(n[6][0],n[6][1])):(t.moveTo(n[0][0],n[0][1]),t.lineTo(n[1][0],n[1][1]),t.lineTo(n[2][0],n[2][1]),t.lineTo(n[3][0],n[3][1]),t.closePath(),t.moveTo(n[4][0],n[4][1]),t.lineTo(n[5][0],n[5][1]),t.moveTo(n[6][0],n[6][1]),t.lineTo(n[7][0],n[7][1]))},e}(ks);function NP(t,e,n){var i=t.ends;return new RP({shape:{points:n?VP(i,t):i},z2:100})}function EP(t,e){for(var n=!0,i=0;id?x[1]:m[1],ends:w,brushRect:T(f,g,c)})}function M(t,n){var i=[];return i[0]=n,i[1]=t,isNaN(n)||isNaN(t)?[NaN,NaN]:e.dataToPoint(i)}function I(t,e,n){var r=e.slice(),o=e.slice();r[0]=Vh(r[0]+i/2,1,!1),o[0]=Vh(o[0]-i/2,1,!0),n?t.push(r,o):t.push(o,r)}function T(t,e,n){var r=M(t,n),o=M(e,n);return r[0]-=i/2,o[0]-=i/2,{x:r[0],y:r[1],width:i,height:o[1]-r[1]}}function C(t){return t[0]=Vh(t[0],1),t}}}}};function UP(t,e,n,i,r,o){return n>i?-1:n0?t.get(r,e-1)<=i?1:-1:1}function ZP(t,e){var n=e.rippleEffectColor||e.color;t.eachChild((function(t){t.attr({z:e.z,zlevel:e.zlevel,style:{stroke:"stroke"===e.brushType?n:null,fill:"fill"===e.brushType?n:null}})}))}var jP=function(t){function e(e,n){var i=t.call(this)||this,r=new fS(e,n),o=new Br;return i.add(r),i.add(o),i.updateData(e,n),i}return n(e,t),e.prototype.stopEffectAnimation=function(){this.childAt(1).removeAll()},e.prototype.startEffectAnimation=function(t){for(var e=t.symbolType,n=t.color,i=t.rippleNumber,r=this.childAt(1),o=0;o0&&(o=this._getLineLength(i)/l*1e3),o!==this._period||a!==this._loop||s!==this._roundTrip){i.stopAnimation();var h=void 0;h=X(u)?u(n):u,i.__t>0&&(h=-o*i.__t),this._animateSymbol(i,o,h,a,s)}this._period=o,this._loop=a,this._roundTrip=s}},e.prototype._animateSymbol=function(t,e,n,i,r){if(e>0){t.__t=0;var o=this,a=t.animate("",i).when(r?2*e:e,{__t:r?2:1}).delay(n).during((function(){o._updateSymbolPosition(t)}));i||a.done((function(){o.remove(t)})),a.start()}},e.prototype._getLineLength=function(t){return Vt(t.__p1,t.__cp1)+Vt(t.__cp1,t.__p2)},e.prototype._updateAnimationPoints=function(t,e){t.__p1=e[0],t.__p2=e[1],t.__cp1=e[2]||[(e[0][0]+e[1][0])/2,(e[0][1]+e[1][1])/2]},e.prototype.updateData=function(t,e,n){this.childAt(0).updateData(t,e,n),this._updateEffectSymbol(t,e)},e.prototype._updateSymbolPosition=function(t){var e=t.__p1,n=t.__p2,i=t.__cp1,r=t.__t<1?t.__t:2-t.__t,o=[t.x,t.y],a=o.slice(),s=In,l=Tn;o[0]=s(e[0],i[0],n[0],r),o[1]=s(e[1],i[1],n[1],r);var u=t.__t<1?l(e[0],i[0],n[0],r):l(n[0],i[0],e[0],1-r),h=t.__t<1?l(e[1],i[1],n[1],r):l(n[1],i[1],e[1],1-r);t.rotation=-Math.atan2(h,u)-Math.PI/2,"line"!==this._symbolType&&"rect"!==this._symbolType&&"roundRect"!==this._symbolType||(void 0!==t.__lastT&&t.__lastT=0&&!(i[o]<=e);o--);o=Math.min(o,r-2)}else{for(o=a;oe);o++);o=Math.min(o-1,r-2)}var s=(e-i[o])/(i[o+1]-i[o]),l=n[o],u=n[o+1];t.x=l[0]*(1-s)+s*u[0],t.y=l[1]*(1-s)+s*u[1];var h=t.__t<1?u[0]-l[0]:l[0]-u[0],c=t.__t<1?u[1]-l[1]:l[1]-u[1];t.rotation=-Math.atan2(c,h)-Math.PI/2,this._lastFrame=o,this._lastFramePercent=e,t.ignore=!1}},e}($P),tO=function(){this.polyline=!1,this.curveness=0,this.segs=[]},eO=function(t){function e(e){var n=t.call(this,e)||this;return n._off=0,n.hoverDataIdx=-1,n}return n(e,t),e.prototype.reset=function(){this.notClear=!1,this._off=0},e.prototype.getDefaultStyle=function(){return{stroke:"#000",fill:null}},e.prototype.getDefaultShape=function(){return new tO},e.prototype.buildPath=function(t,e){var n,i=e.segs,r=e.curveness;if(e.polyline)for(n=this._off;n0){t.moveTo(i[n++],i[n++]);for(var a=1;a0){var c=(s+u)/2-(l-h)*r,p=(l+h)/2-(u-s)*r;t.quadraticCurveTo(c,p,u,h)}else t.lineTo(u,h)}this.incremental&&(this._off=n,this.notClear=!0)},e.prototype.findDataIndex=function(t,e){var n=this.shape,i=n.segs,r=n.curveness,o=this.style.lineWidth;if(n.polyline)for(var a=0,s=0;s0)for(var u=i[s++],h=i[s++],c=1;c0){if(ds(u,h,(u+p)/2-(h-d)*r,(h+d)/2-(p-u)*r,p,d,o,t,e))return a}else if(cs(u,h,p,d,o,t,e))return a;a++}return-1},e.prototype.contain=function(t,e){var n=this.transformCoordToLocal(t,e),i=this.getBoundingRect();return t=n[0],e=n[1],i.contain(t,e)?(this.hoverDataIdx=this.findDataIndex(t,e))>=0:(this.hoverDataIdx=-1,!1)},e.prototype.getBoundingRect=function(){var t=this._rect;if(!t){for(var e=this.shape.segs,n=1/0,i=1/0,r=-1/0,o=-1/0,a=0;a0&&(o.dataIndex=n+t.__startIndex)}))},t.prototype._clear=function(){this._newAdded=[],this.group.removeAll()},t}(),iO={seriesType:"lines",plan:kg(),reset:function(t){var e=t.coordinateSystem;if(e){var n=t.get("polyline"),i=t.pipelineContext.large;return{progress:function(r,o){var a=[];if(i){var s=void 0,l=r.end-r.start;if(n){for(var u=0,h=r.start;h0&&(l||s.configLayer(o,{motionBlur:!0,lastFrameAlpha:Math.max(Math.min(a/10+.9,1),0)})),r.updateData(i);var u=t.get("clip",!0)&&PS(t.coordinateSystem,!1,t);u?this.group.setClipPath(u):this.group.removeClipPath(),this._lastZlevel=o,this._finished=!0},e.prototype.incrementalPrepareRender=function(t,e,n){var i=t.getData();this._updateLineDraw(i,t).incrementalPrepareUpdate(i),this._clearLayer(n),this._finished=!1},e.prototype.incrementalRender=function(t,e,n){this._lineDraw.incrementalUpdate(t,e.getData()),this._finished=t.end===e.getData().count()},e.prototype.eachRendered=function(t){this._lineDraw&&this._lineDraw.eachRendered(t)},e.prototype.updateTransform=function(t,e,n){var i=t.getData(),r=t.pipelineContext;if(!this._finished||r.large||r.progressiveRender)return{update:!0};var o=iO.reset(t,e,n);o.progress&&o.progress({start:0,end:i.count(),count:i.count()},i),this._lineDraw.updateLayout(),this._clearLayer(n)},e.prototype._updateLineDraw=function(t,e){var n=this._lineDraw,i=this._showEffect(e),r=!!e.get("polyline"),o=e.pipelineContext.large;return n&&i===this._hasEffet&&r===this._isPolyline&&o===this._isLargeDraw||(n&&n.remove(),n=this._lineDraw=o?new nO:new YA(r?i?QP:JP:i?$P:HA),this._hasEffet=i,this._isPolyline=r,this._isLargeDraw=o),this.group.add(n.group),n},e.prototype._showEffect=function(t){return!!t.get(["effect","show"])},e.prototype._clearLayer=function(t){var e=t.getZr();"svg"===e.painter.getType()||null==this._lastZlevel||e.painter.getLayer(this._lastZlevel).clear(!0)},e.prototype.remove=function(t,e){this._lineDraw&&this._lineDraw.remove(),this._lineDraw=null,this._clearLayer(e)},e.prototype.dispose=function(t,e){this.remove(t,e)},e.type="lines",e}(Og),oO="undefined"==typeof Uint32Array?Array:Uint32Array,aO="undefined"==typeof Float64Array?Array:Float64Array;function sO(t){var e=t.data;e&&e[0]&&e[0][0]&&e[0][0].coord&&(t.data=z(e,(function(t){var e={coords:[t[0].coord,t[1].coord]};return t[0].name&&(e.fromName=t[0].name),t[1].name&&(e.toName=t[1].name),D([e,t[0],t[1]])})))}var lO=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.visualStyleAccessPath="lineStyle",n.visualDrawType="stroke",n}return n(e,t),e.prototype.init=function(e){e.data=e.data||[],sO(e);var n=this._processFlatCoordsArray(e.data);this._flatCoords=n.flatCoords,this._flatCoordsOffset=n.flatCoordsOffset,n.flatCoords&&(e.data=new Float32Array(n.count)),t.prototype.init.apply(this,arguments)},e.prototype.mergeOption=function(e){if(sO(e),e.data){var n=this._processFlatCoordsArray(e.data);this._flatCoords=n.flatCoords,this._flatCoordsOffset=n.flatCoordsOffset,n.flatCoords&&(e.data=new Float32Array(n.count))}t.prototype.mergeOption.apply(this,arguments)},e.prototype.appendData=function(t){var e=this._processFlatCoordsArray(t.data);e.flatCoords&&(this._flatCoords?(this._flatCoords=vt(this._flatCoords,e.flatCoords),this._flatCoordsOffset=vt(this._flatCoordsOffset,e.flatCoordsOffset)):(this._flatCoords=e.flatCoords,this._flatCoordsOffset=e.flatCoordsOffset),t.data=new Float32Array(e.count)),this.getRawData().appendData(t.data)},e.prototype._getCoordsFromItemModel=function(t){var e=this.getData().getItemModel(t),n=e.option instanceof Array?e.option:e.getShallow("coords");return n},e.prototype.getLineCoordsCount=function(t){return this._flatCoordsOffset?this._flatCoordsOffset[2*t+1]:this._getCoordsFromItemModel(t).length},e.prototype.getLineCoords=function(t,e){if(this._flatCoordsOffset){for(var n=this._flatCoordsOffset[2*t],i=this._flatCoordsOffset[2*t+1],r=0;r ")})},e.prototype.preventIncremental=function(){return!!this.get(["effect","show"])},e.prototype.getProgressive=function(){var t=this.option.progressive;return null==t?this.option.large?1e4:this.get("progressive"):t},e.prototype.getProgressiveThreshold=function(){var t=this.option.progressiveThreshold;return null==t?this.option.large?2e4:this.get("progressiveThreshold"):t},e.prototype.getZLevelKey=function(){var t=this.getModel("effect"),e=t.get("trailLength");return this.getData().count()>this.getProgressiveThreshold()?this.id:t.get("show")&&e>0?e+"":""},e.type="series.lines",e.dependencies=["grid","polar","geo","calendar"],e.defaultOption={coordinateSystem:"geo",z:2,legendHoverLink:!0,xAxisIndex:0,yAxisIndex:0,symbol:["none","none"],symbolSize:[10,10],geoIndex:0,effect:{show:!1,period:4,constantSpeed:0,symbol:"circle",symbolSize:3,loop:!0,trailLength:.2},large:!1,largeThreshold:2e3,polyline:!1,clip:!0,label:{show:!1,position:"end"},lineStyle:{opacity:.5}},e}(bg);function uO(t){return t instanceof Array||(t=[t,t]),t}var hO={seriesType:"lines",reset:function(t){var e=uO(t.get("symbol")),n=uO(t.get("symbolSize")),i=t.getData();return i.setVisual("fromSymbol",e&&e[0]),i.setVisual("toSymbol",e&&e[1]),i.setVisual("fromSymbolSize",n&&n[0]),i.setVisual("toSymbolSize",n&&n[1]),{dataEach:i.hasItemOption?function(t,e){var n=t.getItemModel(e),i=uO(n.getShallow("symbol",!0)),r=uO(n.getShallow("symbolSize",!0));i[0]&&t.setItemVisual(e,"fromSymbol",i[0]),i[1]&&t.setItemVisual(e,"toSymbol",i[1]),r[0]&&t.setItemVisual(e,"fromSymbolSize",r[0]),r[1]&&t.setItemVisual(e,"toSymbolSize",r[1])}:null}}};var cO=function(){function t(){this.blurSize=30,this.pointSize=20,this.maxOpacity=1,this.minOpacity=0,this._gradientPixels={inRange:null,outOfRange:null};var t=h.createCanvas();this.canvas=t}return t.prototype.update=function(t,e,n,i,r,o){var a=this._getBrush(),s=this._getGradient(r,"inRange"),l=this._getGradient(r,"outOfRange"),u=this.pointSize+this.blurSize,h=this.canvas,c=h.getContext("2d"),p=t.length;h.width=e,h.height=n;for(var d=0;d0){var I=o(v)?s:l;v>0&&(v=v*S+w),x[_++]=I[M],x[_++]=I[M+1],x[_++]=I[M+2],x[_++]=I[M+3]*v*256}else _+=4}return c.putImageData(m,0,0),h},t.prototype._getBrush=function(){var t=this._brushCanvas||(this._brushCanvas=h.createCanvas()),e=this.pointSize+this.blurSize,n=2*e;t.width=n,t.height=n;var i=t.getContext("2d");return i.clearRect(0,0,n,n),i.shadowOffsetX=n,i.shadowBlur=this.blurSize,i.shadowColor="#000",i.beginPath(),i.arc(-e,e,this.pointSize,0,2*Math.PI,!0),i.closePath(),i.fill(),t},t.prototype._getGradient=function(t,e){for(var n=this._gradientPixels,i=n[e]||(n[e]=new Uint8ClampedArray(1024)),r=[0,0,0,0],o=0,a=0;a<256;a++)t[e](a/255,!0,r),i[o++]=r[0],i[o++]=r[1],i[o++]=r[2],i[o++]=r[3];return i},t}();function pO(t){var e=t.dimensions;return"lng"===e[0]&&"lat"===e[1]}var dO=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){var i;e.eachComponent("visualMap",(function(e){e.eachTargetSeries((function(n){n===t&&(i=e)}))})),this._progressiveEls=null,this.group.removeAll();var r=t.coordinateSystem;"cartesian2d"===r.type||"calendar"===r.type?this._renderOnCartesianAndCalendar(t,n,0,t.getData().count()):pO(r)&&this._renderOnGeo(r,t,i,n)},e.prototype.incrementalPrepareRender=function(t,e,n){this.group.removeAll()},e.prototype.incrementalRender=function(t,e,n,i){var r=e.coordinateSystem;r&&(pO(r)?this.render(e,n,i):(this._progressiveEls=[],this._renderOnCartesianAndCalendar(e,i,t.start,t.end,!0)))},e.prototype.eachRendered=function(t){Jh(this._progressiveEls||this.group,t)},e.prototype._renderOnCartesianAndCalendar=function(t,e,n,i,r){var o,a,s,l,u=t.coordinateSystem,h=OS(u,"cartesian2d");if(h){var c=u.getAxis("x"),p=u.getAxis("y");0,o=c.getBandWidth()+.5,a=p.getBandWidth()+.5,s=c.scale.getExtent(),l=p.scale.getExtent()}for(var d=this.group,f=t.getData(),g=t.getModel(["emphasis","itemStyle"]).getItemStyle(),y=t.getModel(["blur","itemStyle"]).getItemStyle(),v=t.getModel(["select","itemStyle"]).getItemStyle(),m=t.get(["itemStyle","borderRadius"]),x=rc(t),_=t.getModel("emphasis"),b=_.get("focus"),w=_.get("blurScope"),S=_.get("disabled"),M=h?[f.mapDimension("x"),f.mapDimension("y"),f.mapDimension("value")]:[f.mapDimension("time"),f.mapDimension("value")],I=n;Is[1]||Al[1])continue;var k=u.dataToPoint([D,A]);T=new Ws({shape:{x:k[0]-o/2,y:k[1]-a/2,width:o,height:a},style:C})}else{if(isNaN(f.get(M[1],I)))continue;T=new Ws({z2:1,shape:u.dataToRect([f.get(M[0],I)]).contentShape,style:C})}if(f.hasItemOption){var L=f.getItemModel(I),P=L.getModel("emphasis");g=P.getModel("itemStyle").getItemStyle(),y=L.getModel(["blur","itemStyle"]).getItemStyle(),v=L.getModel(["select","itemStyle"]).getItemStyle(),m=L.get(["itemStyle","borderRadius"]),b=P.get("focus"),w=P.get("blurScope"),S=P.get("disabled"),x=rc(L)}T.shape.r=m;var O=t.getRawValue(I),R="-";O&&null!=O[2]&&(R=O[2]+""),ic(T,x,{labelFetcher:t,labelDataIndex:I,defaultOpacity:C.opacity,defaultText:R}),T.ensureState("emphasis").style=g,T.ensureState("blur").style=y,T.ensureState("select").style=v,Zl(T,b,w,S),T.incremental=r,r&&(T.states.emphasis.hoverLayer=!0),d.add(T),f.setItemGraphicEl(I,T),this._progressiveEls&&this._progressiveEls.push(T)}},e.prototype._renderOnGeo=function(t,e,n,i){var r=n.targetVisuals.inRange,o=n.targetVisuals.outOfRange,a=e.getData(),s=this._hmLayer||this._hmLayer||new cO;s.blurSize=e.get("blurSize"),s.pointSize=e.get("pointSize"),s.minOpacity=e.get("minOpacity"),s.maxOpacity=e.get("maxOpacity");var l=t.getViewRect().clone(),u=t.getRoamTransform();l.applyTransform(u);var h=Math.max(l.x,0),c=Math.max(l.y,0),p=Math.min(l.width+l.x,i.getWidth()),d=Math.min(l.height+l.y,i.getHeight()),f=p-h,g=d-c,y=[a.mapDimension("lng"),a.mapDimension("lat"),a.mapDimension("value")],v=a.mapArray(y,(function(e,n,i){var r=t.dataToPoint([e,n]);return r[0]-=h,r[1]-=c,r.push(i),r})),m=n.getExtent(),x="visualMap.continuous"===n.type?function(t,e){var n=t[1]-t[0];return e=[(e[0]-t[0])/n,(e[1]-t[0])/n],function(t){return t>=e[0]&&t<=e[1]}}(m,n.option.range):function(t,e,n){var i=t[1]-t[0],r=(e=z(e,(function(e){return{interval:[(e.interval[0]-t[0])/i,(e.interval[1]-t[0])/i]}}))).length,o=0;return function(t){var i;for(i=o;i=0;i--){var a;if((a=e[i].interval)[0]<=t&&t<=a[1]){o=i;break}}return i>=0&&i=0?1:-1:o>0?1:-1}(n,o,r,i,c),function(t,e,n,i,r,o,a,s,l,u){var h,c=l.valueDim,p=l.categoryDim,d=Math.abs(n[p.wh]),f=t.getItemVisual(e,"symbolSize");h=Y(f)?f.slice():null==f?["100%","100%"]:[f,f];h[p.index]=$r(h[p.index],d),h[c.index]=$r(h[c.index],i?d:Math.abs(o)),u.symbolSize=h;var g=u.symbolScale=[h[0]/s,h[1]/s];g[c.index]*=(l.isHorizontal?-1:1)*a}(t,e,r,o,0,c.boundingLength,c.pxSign,u,i,c),function(t,e,n,i,r){var o=t.get(gO)||0;o&&(vO.attr({scaleX:e[0],scaleY:e[1],rotation:n}),vO.updateTransform(),o/=vO.getLineScale(),o*=e[i.valueDim.index]);r.valueLineWidth=o||0}(n,c.symbolScale,l,i,c);var p=c.symbolSize,d=Zy(n.get("symbolOffset"),p);return function(t,e,n,i,r,o,a,s,l,u,h,c){var p=h.categoryDim,d=h.valueDim,f=c.pxSign,g=Math.max(e[d.index]+s,0),y=g;if(i){var v=Math.abs(l),m=it(t.get("symbolMargin"),"15%")+"",x=!1;m.lastIndexOf("!")===m.length-1&&(x=!0,m=m.slice(0,m.length-1));var _=$r(m,e[d.index]),b=Math.max(g+2*_,0),w=x?0:2*_,S=vo(i),M=S?i:NO((v+w)/b);b=g+2*(_=(v-M*g)/2/(x?M:Math.max(M-1,1))),w=x?0:2*_,S||"fixed"===i||(M=u?NO((Math.abs(u)+w)/b):0),y=M*b-w,c.repeatTimes=M,c.symbolMargin=_}var I=f*(y/2),T=c.pathPosition=[];T[p.index]=n[p.wh]/2,T[d.index]="start"===a?I:"end"===a?l-I:l/2,o&&(T[0]+=o[0],T[1]+=o[1]);var C=c.bundlePosition=[];C[p.index]=n[p.xy],C[d.index]=n[d.xy];var D=c.barRectShape=A({},n);D[d.wh]=f*Math.max(Math.abs(n[d.wh]),Math.abs(T[d.index]+I)),D[p.wh]=n[p.wh];var k=c.clipShape={};k[p.xy]=-n[p.xy],k[p.wh]=h.ecSize[p.wh],k[d.xy]=0,k[d.wh]=n[d.wh]}(n,p,r,o,0,d,s,c.valueLineWidth,c.boundingLength,c.repeatCutLength,i,c),c}function _O(t,e){return t.toGlobalCoord(t.dataToCoord(t.scale.parse(e)))}function bO(t){var e=t.symbolPatternSize,n=Xy(t.symbolType,-e/2,-e/2,e,e);return n.attr({culling:!0}),"image"!==n.type&&n.setStyle({strokeNoScale:!0}),n}function wO(t,e,n,i){var r=t.__pictorialBundle,o=n.symbolSize,a=n.valueLineWidth,s=n.pathPosition,l=e.valueDim,u=n.repeatTimes||0,h=0,c=o[e.valueDim.index]+a+2*n.symbolMargin;for(PO(t,(function(t){t.__pictorialAnimationIndex=h,t.__pictorialRepeatTimes=u,h0:i<0)&&(r=u-1-t),e[l.index]=c*(r-u/2+.5)+s[l.index],{x:e[0],y:e[1],scaleX:n.symbolScale[0],scaleY:n.symbolScale[1],rotation:n.rotation}}}function SO(t,e,n,i){var r=t.__pictorialBundle,o=t.__pictorialMainPath;o?OO(o,null,{x:n.pathPosition[0],y:n.pathPosition[1],scaleX:n.symbolScale[0],scaleY:n.symbolScale[1],rotation:n.rotation},n,i):(o=t.__pictorialMainPath=bO(n),r.add(o),OO(o,{x:n.pathPosition[0],y:n.pathPosition[1],scaleX:0,scaleY:0,rotation:n.rotation},{scaleX:n.symbolScale[0],scaleY:n.symbolScale[1]},n,i))}function MO(t,e,n){var i=A({},e.barRectShape),r=t.__pictorialBarRect;r?OO(r,null,{shape:i},e,n):((r=t.__pictorialBarRect=new Ws({z2:2,shape:i,silent:!0,style:{stroke:"transparent",fill:"transparent",lineWidth:0}})).disableMorphing=!0,t.add(r))}function IO(t,e,n,i){if(n.symbolClip){var r=t.__pictorialClipPath,o=A({},n.clipShape),a=e.valueDim,s=n.animationModel,l=n.dataIndex;if(r)vh(r,{shape:o},s,l);else{o[a.wh]=0,r=new Ws({shape:o}),t.__pictorialBundle.setClipPath(r),t.__pictorialClipPath=r;var u={};u[a.wh]=n.clipShape[a.wh],Qh[i?"updateProps":"initProps"](r,{shape:u},s,l)}}}function TO(t,e){var n=t.getItemModel(e);return n.getAnimationDelayParams=CO,n.isAnimationEnabled=DO,n}function CO(t){return{index:t.__pictorialAnimationIndex,count:t.__pictorialRepeatTimes}}function DO(){return this.parentModel.isAnimationEnabled()&&!!this.getShallow("animation")}function AO(t,e,n,i){var r=new Br,o=new Br;return r.add(o),r.__pictorialBundle=o,o.x=n.bundlePosition[0],o.y=n.bundlePosition[1],n.symbolRepeat?wO(r,e,n):SO(r,0,n),MO(r,n,i),IO(r,e,n,i),r.__pictorialShapeStr=LO(t,n),r.__pictorialSymbolMeta=n,r}function kO(t,e,n,i){var r=i.__pictorialBarRect;r&&r.removeTextContent();var o=[];PO(i,(function(t){o.push(t)})),i.__pictorialMainPath&&o.push(i.__pictorialMainPath),i.__pictorialClipPath&&(n=null),E(o,(function(t){_h(t,{scaleX:0,scaleY:0},n,e,(function(){i.parent&&i.parent.remove(i)}))})),t.setItemGraphicEl(e,null)}function LO(t,e){return[t.getItemVisual(e.dataIndex,"symbol")||"none",!!e.symbolRepeat,!!e.symbolClip].join(":")}function PO(t,e,n){E(t.__pictorialBundle.children(),(function(i){i!==t.__pictorialBarRect&&e.call(n,i)}))}function OO(t,e,n,i,r,o){e&&t.attr(e),i.symbolClip&&!r?n&&t.attr(n):n&&Qh[r?"updateProps":"initProps"](t,n,i.animationModel,i.dataIndex,o)}function RO(t,e,n){var i=n.dataIndex,r=n.itemModel,o=r.getModel("emphasis"),a=o.getModel("itemStyle").getItemStyle(),s=r.getModel(["blur","itemStyle"]).getItemStyle(),l=r.getModel(["select","itemStyle"]).getItemStyle(),u=r.getShallow("cursor"),h=o.get("focus"),c=o.get("blurScope"),p=o.get("scale");PO(t,(function(t){if(t instanceof Ns){var e=t.style;t.useStyle(A({image:e.image,x:e.x,y:e.y,width:e.width,height:e.height},n.style))}else t.useStyle(n.style);var i=t.ensureState("emphasis");i.style=a,p&&(i.scaleX=1.1*t.scaleX,i.scaleY=1.1*t.scaleY),t.ensureState("blur").style=s,t.ensureState("select").style=l,u&&(t.cursor=u),t.z2=n.z2}));var d=e.valueDim.posDesc[+(n.boundingLength>0)],f=t.__pictorialBarRect;f.ignoreClip=!0,ic(f,rc(r),{labelFetcher:e.seriesModel,labelDataIndex:i,defaultText:pS(e.seriesModel.getData(),i),inheritColor:n.style.fill,defaultOpacity:n.style.opacity,defaultOutsidePosition:d}),Zl(t,h,c,o.get("disabled"))}function NO(t){var e=Math.round(t);return Math.abs(t-e)<1e-4?e:Math.ceil(t)}var EO=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.hasSymbolVisual=!0,n.defaultSymbol="roundRect",n}return n(e,t),e.prototype.getInitialData=function(e){return e.stack=null,t.prototype.getInitialData.apply(this,arguments)},e.type="series.pictorialBar",e.dependencies=["grid"],e.defaultOption=kc(qS.defaultOption,{symbol:"circle",symbolSize:null,symbolRotate:null,symbolPosition:null,symbolOffset:null,symbolMargin:null,symbolRepeat:!1,symbolRepeatDirection:"end",symbolClip:!1,symbolBoundingData:null,symbolPatternSize:400,barGap:"-100%",clip:!1,progressive:0,emphasis:{scale:!1},select:{itemStyle:{borderColor:"#212121"}}}),e}(qS);var zO=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n._layers=[],n}return n(e,t),e.prototype.render=function(t,e,n){var i=t.getData(),r=this,o=this.group,a=t.getLayerSeries(),s=i.getLayout("layoutInfo"),l=s.rect,u=s.boundaryGap;function h(t){return t.name}o.x=0,o.y=l.y+u[0];var c=new Gm(this._layersSeries||[],a,h,h),p=[];function d(e,n,s){var l=r._layers;if("remove"!==e){for(var u,h,c=[],d=[],f=a[n].indices,g=0;go&&(o=s),i.push(s)}for(var u=0;uo&&(o=c)}return{y0:r,max:o}}(l),h=u.y0,c=n/u.max,p=o.length,d=o[0].indices.length,f=0;fI&&!so(C-I)&&C0?(r.virtualPiece?r.virtualPiece.updateData(!1,i,t,e,n):(r.virtualPiece=new GO(i,t,e,n),l.add(r.virtualPiece)),o.piece.off("click"),r.virtualPiece.on("click",(function(t){r._rootToNode(o.parentNode)}))):r.virtualPiece&&(l.remove(r.virtualPiece),r.virtualPiece=null)}(a,s),this._initEvents(),this._oldChildren=h},e.prototype._initEvents=function(){var t=this;this.group.off("click"),this.group.on("click",(function(e){var n=!1;t.seriesModel.getViewRoot().eachNode((function(i){if(!n&&i.piece&&i.piece===e.target){var r=i.getModel().get("nodeClick");if("rootToNode"===r)t._rootToNode(i);else if("link"===r){var o=i.getModel(),a=o.get("link");if(a)Mp(a,o.get("target",!0)||"_blank")}n=!0}}))}))},e.prototype._rootToNode=function(t){t!==this.seriesModel.getViewRoot()&&this.api.dispatchAction({type:WO,from:this.uid,seriesId:this.seriesModel.id,targetNode:t})},e.prototype.containPoint=function(t,e){var n=e.getData().getItemLayout(0);if(n){var i=t[0]-n.cx,r=t[1]-n.cy,o=Math.sqrt(i*i+r*r);return o<=n.r&&o>=n.r0}},e.type="sunburst",e}(Og),XO=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.ignoreStyleOnData=!0,n}return n(e,t),e.prototype.getInitialData=function(t,e){var n={name:t.name,children:t.data};UO(n);var i=this._levelModels=z(t.levels||[],(function(t){return new Cc(t,this,e)}),this),r=nD.createTree(n,this,(function(t){t.wrapMethod("getItemModel",(function(t,e){var n=r.getNodeByDataIndex(e),o=i[n.depth];return o&&(t.parentModel=o),t}))}));return r.data},e.prototype.optionUpdated=function(){this.resetViewRoot()},e.prototype.getDataParams=function(e){var n=t.prototype.getDataParams.apply(this,arguments),i=this.getData().tree.getNodeByDataIndex(e);return n.treePathInfo=aD(i,this),n},e.prototype.getLevelModel=function(t){return this._levelModels&&this._levelModels[t.depth]},e.prototype.getViewRoot=function(){return this._viewRoot},e.prototype.resetViewRoot=function(t){t?this._viewRoot=t:t=this._viewRoot;var e=this.getRawData().tree.root;t&&(t===e||e.contains(t))||(this._viewRoot=e)},e.prototype.enableAriaDecal=function(){pD(this)},e.type="series.sunburst",e.defaultOption={z:2,center:["50%","50%"],radius:[0,"75%"],clockwise:!0,startAngle:90,minAngle:0,stillShowZeroSum:!0,nodeClick:"rootToNode",renderLabelForZeroData:!1,label:{rotate:"radial",show:!0,opacity:1,align:"center",position:"inside",distance:5,silent:!0},itemStyle:{borderWidth:1,borderColor:"white",borderType:"solid",shadowBlur:0,shadowColor:"rgba(0, 0, 0, 0.2)",shadowOffsetX:0,shadowOffsetY:0,opacity:1},emphasis:{focus:"descendant"},blur:{itemStyle:{opacity:.2},label:{opacity:.1}},animationType:"expansion",animationDuration:1e3,animationDurationUpdate:500,data:[],sort:"desc"},e}(bg);function UO(t){var e=0;E(t.children,(function(t){UO(t);var n=t.value;Y(n)&&(n=n[0]),e+=n}));var n=t.value;Y(n)&&(n=n[0]),(null==n||isNaN(n))&&(n=e),n<0&&(n=0),Y(t.value)?t.value[0]=n:t.value=n}var ZO=Math.PI/180;function jO(t,e,n){e.eachSeriesByType(t,(function(t){var e=t.get("center"),i=t.get("radius");Y(i)||(i=[0,i]),Y(e)||(e=[e,e]);var r=n.getWidth(),o=n.getHeight(),a=Math.min(r,o),s=$r(e[0],r),l=$r(e[1],o),u=$r(i[0],a/2),h=$r(i[1],a/2),c=-t.get("startAngle")*ZO,p=t.get("minAngle")*ZO,d=t.getData().tree.root,f=t.getViewRoot(),g=f.depth,y=t.get("sort");null!=y&&qO(f,y);var v=0;E(f.children,(function(t){!isNaN(t.getValue())&&v++}));var m=f.getValue(),x=Math.PI/(m||v)*2,_=f.depth>0,b=f.height-(_?-1:1),w=(h-u)/(b||1),S=t.get("clockwise"),M=t.get("stillShowZeroSum"),I=S?1:-1,T=function(e,n){if(e){var i=n;if(e!==d){var r=e.getValue(),o=0===m&&M?x:r*x;o1;)r=r.parentNode;var o=n.getColorFromPalette(r.name||r.dataIndex+"",e);return t.depth>1&&U(o)&&(o=$n(o,(t.depth-1)/(i-1)*.5)),o}(r,t,i.root.height)),A(n.ensureUniqueItemVisual(r.dataIndex,"style"),o)}))}))}var $O={color:"fill",borderColor:"stroke"},JO={symbol:1,symbolSize:1,symbolKeepAspect:1,legendIcon:1,visualMeta:1,liftZ:1,decal:1},QO=Vo(),tR=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.optionUpdated=function(){this.currentZLevel=this.get("zlevel",!0),this.currentZ=this.get("z",!0)},e.prototype.getInitialData=function(t,e){return _x(null,this)},e.prototype.getDataParams=function(e,n,i){var r=t.prototype.getDataParams.call(this,e,n);return i&&(r.info=QO(i).info),r},e.type="series.custom",e.dependencies=["grid","polar","geo","singleAxis","calendar"],e.defaultOption={coordinateSystem:"cartesian2d",z:2,legendHoverLink:!0,clip:!1},e}(bg);function eR(t,e){return e=e||[0,0],z(["x","y"],(function(n,i){var r=this.getAxis(n),o=e[i],a=t[i]/2;return"category"===r.type?r.getBandWidth():Math.abs(r.dataToCoord(o-a)-r.dataToCoord(o+a))}),this)}function nR(t,e){return e=e||[0,0],z([0,1],(function(n){var i=e[n],r=t[n]/2,o=[],a=[];return o[n]=i-r,a[n]=i+r,o[1-n]=a[1-n]=e[1-n],Math.abs(this.dataToPoint(o)[n]-this.dataToPoint(a)[n])}),this)}function iR(t,e){var n=this.getAxis(),i=e instanceof Array?e[0]:e,r=(t instanceof Array?t[0]:t)/2;return"category"===n.type?n.getBandWidth():Math.abs(n.dataToCoord(i-r)-n.dataToCoord(i+r))}function rR(t,e){return e=e||[0,0],z(["Radius","Angle"],(function(n,i){var r=this["get"+n+"Axis"](),o=e[i],a=t[i]/2,s="category"===r.type?r.getBandWidth():Math.abs(r.dataToCoord(o-a)-r.dataToCoord(o+a));return"Angle"===n&&(s=s*Math.PI/180),s}),this)}function oR(t,e,n,i){return t&&(t.legacy||!1!==t.legacy&&!n&&!i&&"tspan"!==e&&("text"===e||_t(t,"text")))}function aR(t,e,n){var i,r,o,a=t;if("text"===e)o=a;else{o={},_t(a,"text")&&(o.text=a.text),_t(a,"rich")&&(o.rich=a.rich),_t(a,"textFill")&&(o.fill=a.textFill),_t(a,"textStroke")&&(o.stroke=a.textStroke),_t(a,"fontFamily")&&(o.fontFamily=a.fontFamily),_t(a,"fontSize")&&(o.fontSize=a.fontSize),_t(a,"fontStyle")&&(o.fontStyle=a.fontStyle),_t(a,"fontWeight")&&(o.fontWeight=a.fontWeight),r={type:"text",style:o,silent:!0},i={};var s=_t(a,"textPosition");n?i.position=s?a.textPosition:"inside":s&&(i.position=a.textPosition),_t(a,"textPosition")&&(i.position=a.textPosition),_t(a,"textOffset")&&(i.offset=a.textOffset),_t(a,"textRotation")&&(i.rotation=a.textRotation),_t(a,"textDistance")&&(i.distance=a.textDistance)}return sR(o,t),E(o.rich,(function(t){sR(t,t)})),{textConfig:i,textContent:r}}function sR(t,e){e&&(e.font=e.textFont||e.font,_t(e,"textStrokeWidth")&&(t.lineWidth=e.textStrokeWidth),_t(e,"textAlign")&&(t.align=e.textAlign),_t(e,"textVerticalAlign")&&(t.verticalAlign=e.textVerticalAlign),_t(e,"textLineHeight")&&(t.lineHeight=e.textLineHeight),_t(e,"textWidth")&&(t.width=e.textWidth),_t(e,"textHeight")&&(t.height=e.textHeight),_t(e,"textBackgroundColor")&&(t.backgroundColor=e.textBackgroundColor),_t(e,"textPadding")&&(t.padding=e.textPadding),_t(e,"textBorderColor")&&(t.borderColor=e.textBorderColor),_t(e,"textBorderWidth")&&(t.borderWidth=e.textBorderWidth),_t(e,"textBorderRadius")&&(t.borderRadius=e.textBorderRadius),_t(e,"textBoxShadowColor")&&(t.shadowColor=e.textBoxShadowColor),_t(e,"textBoxShadowBlur")&&(t.shadowBlur=e.textBoxShadowBlur),_t(e,"textBoxShadowOffsetX")&&(t.shadowOffsetX=e.textBoxShadowOffsetX),_t(e,"textBoxShadowOffsetY")&&(t.shadowOffsetY=e.textBoxShadowOffsetY))}function lR(t,e,n){var i=t;i.textPosition=i.textPosition||n.position||"inside",null!=n.offset&&(i.textOffset=n.offset),null!=n.rotation&&(i.textRotation=n.rotation),null!=n.distance&&(i.textDistance=n.distance);var r=i.textPosition.indexOf("inside")>=0,o=t.fill||"#000";uR(i,e);var a=null==i.textFill;return r?a&&(i.textFill=n.insideFill||"#fff",!i.textStroke&&n.insideStroke&&(i.textStroke=n.insideStroke),!i.textStroke&&(i.textStroke=o),null==i.textStrokeWidth&&(i.textStrokeWidth=2)):(a&&(i.textFill=t.fill||n.outsideFill||"#000"),!i.textStroke&&n.outsideStroke&&(i.textStroke=n.outsideStroke)),i.text=e.text,i.rich=e.rich,E(e.rich,(function(t){uR(t,t)})),i}function uR(t,e){e&&(_t(e,"fill")&&(t.textFill=e.fill),_t(e,"stroke")&&(t.textStroke=e.fill),_t(e,"lineWidth")&&(t.textStrokeWidth=e.lineWidth),_t(e,"font")&&(t.font=e.font),_t(e,"fontStyle")&&(t.fontStyle=e.fontStyle),_t(e,"fontWeight")&&(t.fontWeight=e.fontWeight),_t(e,"fontSize")&&(t.fontSize=e.fontSize),_t(e,"fontFamily")&&(t.fontFamily=e.fontFamily),_t(e,"align")&&(t.textAlign=e.align),_t(e,"verticalAlign")&&(t.textVerticalAlign=e.verticalAlign),_t(e,"lineHeight")&&(t.textLineHeight=e.lineHeight),_t(e,"width")&&(t.textWidth=e.width),_t(e,"height")&&(t.textHeight=e.height),_t(e,"backgroundColor")&&(t.textBackgroundColor=e.backgroundColor),_t(e,"padding")&&(t.textPadding=e.padding),_t(e,"borderColor")&&(t.textBorderColor=e.borderColor),_t(e,"borderWidth")&&(t.textBorderWidth=e.borderWidth),_t(e,"borderRadius")&&(t.textBorderRadius=e.borderRadius),_t(e,"shadowColor")&&(t.textBoxShadowColor=e.shadowColor),_t(e,"shadowBlur")&&(t.textBoxShadowBlur=e.shadowBlur),_t(e,"shadowOffsetX")&&(t.textBoxShadowOffsetX=e.shadowOffsetX),_t(e,"shadowOffsetY")&&(t.textBoxShadowOffsetY=e.shadowOffsetY),_t(e,"textShadowColor")&&(t.textShadowColor=e.textShadowColor),_t(e,"textShadowBlur")&&(t.textShadowBlur=e.textShadowBlur),_t(e,"textShadowOffsetX")&&(t.textShadowOffsetX=e.textShadowOffsetX),_t(e,"textShadowOffsetY")&&(t.textShadowOffsetY=e.textShadowOffsetY))}var hR={position:["x","y"],scale:["scaleX","scaleY"],origin:["originX","originY"]},cR=G(hR),pR=(V(mr,(function(t,e){return t[e]=1,t}),{}),mr.join(", "),["","style","shape","extra"]),dR=Vo();function fR(t,e,n,i,r){var o=t+"Animation",a=gh(t,i,r)||{},s=dR(e).userDuring;return a.duration>0&&(a.during=s?W(bR,{el:e,userDuring:s}):null,a.setToFinal=!0,a.scope=t),A(a,n[o]),a}function gR(t,e,n,i){var r=(i=i||{}).dataIndex,o=i.isInit,a=i.clearStyle,s=n.isAnimationEnabled(),l=dR(t),u=e.style;l.userDuring=e.during;var h={},c={};if(function(t,e,n){for(var i=0;i=0)){var c=t.getAnimationStyleProps(),p=c?c.style:null;if(p){!r&&(r=i.style={});var d=G(n);for(u=0;u0&&t.animateFrom(p,d)}else!function(t,e,n,i,r){if(r){var o=fR("update",t,e,i,n);o.duration>0&&t.animateFrom(r,o)}}(t,e,r||0,n,h);yR(t,e),u?t.dirty():t.markRedraw()}function yR(t,e){for(var n=dR(t).leaveToProps,i=0;i=0){!o&&(o=i[t]={});var p=G(a);for(h=0;hi[1]&&i.reverse(),{coordSys:{type:"polar",cx:t.cx,cy:t.cy,r:i[1],r0:i[0]},api:{coord:function(i){var r=e.dataToRadius(i[0]),o=n.dataToAngle(i[1]),a=t.coordToPoint([r,o]);return a.push(r,o*Math.PI/180),a},size:W(rR,t)}}},calendar:function(t){var e=t.getRect(),n=t.getRangeInfo();return{coordSys:{type:"calendar",x:e.x,y:e.y,width:e.width,height:e.height,cellWidth:t.getCellWidth(),cellHeight:t.getCellHeight(),rangeInfo:{start:n.start,end:n.end,weeks:n.weeks,dayCount:n.allDay}},api:{coord:function(e,n){return t.dataToPoint(e,n)}}}}};function BR(t){return t instanceof ks}function FR(t){return t instanceof Da}var GR=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n,i){this._progressiveEls=null;var r=this._data,o=t.getData(),a=this.group,s=UR(t,o,e,n);r||a.removeAll(),o.diff(r).add((function(e){jR(n,null,e,s(e,i),t,a,o)})).remove((function(e){var n=r.getItemGraphicEl(e);n&&vR(n,QO(n).option,t)})).update((function(e,l){var u=r.getItemGraphicEl(l);jR(n,u,e,s(e,i),t,a,o)})).execute();var l=t.get("clip",!0)?PS(t.coordinateSystem,!1,t):null;l?a.setClipPath(l):a.removeClipPath(),this._data=o},e.prototype.incrementalPrepareRender=function(t,e,n){this.group.removeAll(),this._data=null},e.prototype.incrementalRender=function(t,e,n,i,r){var o=e.getData(),a=UR(e,o,n,i),s=this._progressiveEls=[];function l(t){t.isGroup||(t.incremental=!0,t.ensureState("emphasis").hoverLayer=!0)}for(var u=t.start;u=0?e.getStore().get(r,n):void 0}var o=e.get(i.name,n),a=i&&i.ordinalMeta;return a?a.categories[o]:o},styleEmphasis:function(n,i){0;null==i&&(i=s);var r=m(i,AR).getItemStyle(),o=x(i,AR),a=oc(o,null,null,!0,!0);a.text=o.getShallow("show")?ot(t.getFormattedLabel(i,AR),t.getFormattedLabel(i,kR),pS(e,i)):null;var l=ac(o,null,!0);return b(n,r),r=lR(r,a,l),n&&_(r,n),r.legacy=!0,r},visual:function(t,n){if(null==n&&(n=s),_t($O,t)){var i=e.getItemVisual(n,"style");return i?i[$O[t]]:null}if(_t(JO,t))return e.getItemVisual(n,t)},barLayout:function(t){if("cartesian2d"===o.type){return function(t){var e=[],n=t.axis,i="axis0";if("category"===n.type){for(var r=n.getBandWidth(),o=0;o=c;f--){var g=e.childAt(f);tN(e,g,r)}}(t,c,n,i,r),a>=0?o.replaceAt(c,a):o.add(c),c}function KR(t,e,n){var i,r=QO(t),o=e.type,a=e.shape,s=e.style;return n.isUniversalTransitionEnabled()||null!=o&&o!==r.customGraphicType||"path"===o&&((i=a)&&(_t(i,"pathData")||_t(i,"d")))&&rN(a)!==r.customPathData||"image"===o&&_t(s,"image")&&s.image!==r.customImagePath}function $R(t,e,n){var i=e?JR(t,e):t,r=e?QR(t,i,AR):t.style,o=t.type,a=i?i.textConfig:null,s=t.textContent,l=s?e?JR(s,e):s:null;if(r&&(n.isLegacy||oR(r,o,!!a,!!l))){n.isLegacy=!0;var u=aR(r,o,!e);!a&&u.textConfig&&(a=u.textConfig),!l&&u.textContent&&(l=u.textContent)}if(!e&&l){var h=l;!h.type&&(h.type="text")}var c=e?n[e]:n.normal;c.cfg=a,c.conOpt=l}function JR(t,e){return e?t?t[e]:null:t}function QR(t,e,n){var i=e&&e.style;return null==i&&n===AR&&t&&(i=t.styleEmphasis),i}function tN(t,e,n){e&&vR(e,QO(t).option,n)}function eN(t,e){var n=t&&t.name;return null!=n?n:"e\0\0"+e}function nN(t,e){var n=this.context,i=null!=t?n.newChildren[t]:null,r=null!=e?n.oldChildren[e]:null;qR(n.api,r,n.dataIndex,i,n.seriesModel,n.group)}function iN(t){var e=this.context,n=e.oldChildren[t];n&&vR(n,QO(n).option,e.seriesModel)}function rN(t){return t&&(t.pathData||t.d)}var oN=Vo(),aN=T,sN=W,lN=function(){function t(){this._dragging=!1,this.animationThreshold=15}return t.prototype.render=function(t,e,n,i){var r=e.get("value"),o=e.get("status");if(this._axisModel=t,this._axisPointerModel=e,this._api=n,i||this._lastValue!==r||this._lastStatus!==o){this._lastValue=r,this._lastStatus=o;var a=this._group,s=this._handle;if(!o||"hide"===o)return a&&a.hide(),void(s&&s.hide());a&&a.show(),s&&s.show();var l={};this.makeElOption(l,r,t,e,n);var u=l.graphicKey;u!==this._lastGraphicKey&&this.clear(n),this._lastGraphicKey=u;var h=this._moveAnimation=this.determineAnimation(t,e);if(a){var c=H(uN,e,h);this.updatePointerEl(a,l,c),this.updateLabelEl(a,l,c,e)}else a=this._group=new Br,this.createPointerEl(a,l,t,e),this.createLabelEl(a,l,t,e),n.getZr().add(a);dN(a,e,!0),this._renderHandle(r)}},t.prototype.remove=function(t){this.clear(t)},t.prototype.dispose=function(t){this.clear(t)},t.prototype.determineAnimation=function(t,e){var n=e.get("animation"),i=t.axis,r="category"===i.type,o=e.get("snap");if(!o&&!r)return!1;if("auto"===n||null==n){var a=this.animationThreshold;if(r&&i.getBandWidth()>a)return!0;if(o){var s=wI(t).seriesDataCount,l=i.getExtent();return Math.abs(l[0]-l[1])/s>a}return!1}return!0===n},t.prototype.makeElOption=function(t,e,n,i,r){},t.prototype.createPointerEl=function(t,e,n,i){var r=e.pointer;if(r){var o=oN(t).pointerEl=new Qh[r.type](aN(e.pointer));t.add(o)}},t.prototype.createLabelEl=function(t,e,n,i){if(e.label){var r=oN(t).labelEl=new Xs(aN(e.label));t.add(r),cN(r,i)}},t.prototype.updatePointerEl=function(t,e,n){var i=oN(t).pointerEl;i&&e.pointer&&(i.setStyle(e.pointer.style),n(i,{shape:e.pointer.shape}))},t.prototype.updateLabelEl=function(t,e,n,i){var r=oN(t).labelEl;r&&(r.setStyle(e.label.style),n(r,{x:e.label.x,y:e.label.y}),cN(r,i))},t.prototype._renderHandle=function(t){if(!this._dragging&&this.updateHandleTransform){var e,n=this._axisPointerModel,i=this._api.getZr(),r=this._handle,o=n.getModel("handle"),a=n.get("status");if(!o.get("show")||!a||"hide"===a)return r&&i.remove(r),void(this._handle=null);this._handle||(e=!0,r=this._handle=Uh(o.get("icon"),{cursor:"move",draggable:!0,onmousemove:function(t){de(t.event)},onmousedown:sN(this._onHandleDragMove,this,0,0),drift:sN(this._onHandleDragMove,this),ondragend:sN(this._onHandleDragEnd,this)}),i.add(r)),dN(r,n,!1),r.setStyle(o.getItemStyle(null,["color","borderColor","borderWidth","opacity","shadowColor","shadowBlur","shadowOffsetX","shadowOffsetY"]));var s=o.get("size");Y(s)||(s=[s,s]),r.scaleX=s[0]/2,r.scaleY=s[1]/2,Hg(this,"_doDispatchAxisPointer",o.get("throttle")||0,"fixRate"),this._moveHandleToValue(t,e)}},t.prototype._moveHandleToValue=function(t,e){uN(this._axisPointerModel,!e&&this._moveAnimation,this._handle,pN(this.getHandleTransform(t,this._axisModel,this._axisPointerModel)))},t.prototype._onHandleDragMove=function(t,e){var n=this._handle;if(n){this._dragging=!0;var i=this.updateHandleTransform(pN(n),[t,e],this._axisModel,this._axisPointerModel);this._payloadInfo=i,n.stopAnimation(),n.attr(pN(i)),oN(n).lastProp=null,this._doDispatchAxisPointer()}},t.prototype._doDispatchAxisPointer=function(){if(this._handle){var t=this._payloadInfo,e=this._axisModel;this._api.dispatchAction({type:"updateAxisPointer",x:t.cursorPoint[0],y:t.cursorPoint[1],tooltipOption:t.tooltipOption,axesInfo:[{axisDim:e.axis.dim,axisIndex:e.componentIndex}]})}},t.prototype._onHandleDragEnd=function(){if(this._dragging=!1,this._handle){var t=this._axisPointerModel.get("value");this._moveHandleToValue(t),this._api.dispatchAction({type:"hideTip"})}},t.prototype.clear=function(t){this._lastValue=null,this._lastStatus=null;var e=t.getZr(),n=this._group,i=this._handle;e&&n&&(this._lastGraphicKey=null,n&&e.remove(n),i&&e.remove(i),this._group=null,this._handle=null,this._payloadInfo=null),Yg(this,"_doDispatchAxisPointer")},t.prototype.doClear=function(){},t.prototype.buildLabel=function(t,e,n){return{x:t[n=n||0],y:t[1-n],width:e[n],height:e[1-n]}},t}();function uN(t,e,n,i){hN(oN(n).lastProp,i)||(oN(n).lastProp=i,e?vh(n,i,t):(n.stopAnimation(),n.attr(i)))}function hN(t,e){if(q(t)&&q(e)){var n=!0;return E(e,(function(e,i){n=n&&hN(t[i],e)})),!!n}return t===e}function cN(t,e){t[e.get(["label","show"])?"show":"hide"]()}function pN(t){return{x:t.x||0,y:t.y||0,rotation:t.rotation||0}}function dN(t,e,n){var i=e.get("z"),r=e.get("zlevel");t&&t.traverse((function(t){"group"!==t.type&&(null!=i&&(t.z=i),null!=r&&(t.zlevel=r),t.silent=n)}))}function fN(t){var e,n=t.get("type"),i=t.getModel(n+"Style");return"line"===n?(e=i.getLineStyle()).fill=null:"shadow"===n&&((e=i.getAreaStyle()).stroke=null),e}function gN(t,e,n,i,r){var o=yN(n.get("value"),e.axis,e.ecModel,n.get("seriesDataIndices"),{precision:n.get(["label","precision"]),formatter:n.get(["label","formatter"])}),a=n.getModel("label"),s=vp(a.get("padding")||0),l=a.getFont(),u=Sr(o,l),h=r.position,c=u.width+s[1]+s[3],p=u.height+s[0]+s[2],d=r.align;"right"===d&&(h[0]-=c),"center"===d&&(h[0]-=c/2);var f=r.verticalAlign;"bottom"===f&&(h[1]-=p),"middle"===f&&(h[1]-=p/2),function(t,e,n,i){var r=i.getWidth(),o=i.getHeight();t[0]=Math.min(t[0]+e,r)-e,t[1]=Math.min(t[1]+n,o)-n,t[0]=Math.max(t[0],0),t[1]=Math.max(t[1],0)}(h,c,p,i);var g=a.get("backgroundColor");g&&"auto"!==g||(g=e.get(["axisLine","lineStyle","color"])),t.label={x:h[0],y:h[1],style:oc(a,{text:o,font:l,fill:a.getTextColor(),padding:s,backgroundColor:g}),z2:10}}function yN(t,e,n,i,r){t=e.scale.parse(t);var o=e.scale.getLabel({value:t},{precision:r.precision}),a=r.formatter;if(a){var s={value:S_(e,{value:t}),axisDimension:e.dim,axisIndex:e.index,seriesData:[]};E(i,(function(t){var e=n.getSeriesByIndex(t.seriesIndex),i=t.dataIndexInside,r=e&&e.getDataParams(i);r&&s.seriesData.push(r)})),U(a)?o=a.replace("{value}",o):X(a)&&(o=a(s))}return o}function vN(t,e,n){var i=[1,0,0,1,0,0];return Se(i,i,n.rotation),we(i,i,n.position),Fh([t.dataToCoord(e),(n.labelOffset||0)+(n.labelDirection||1)*(n.labelMargin||0)],i)}function mN(t,e,n,i,r,o){var a=dI.innerTextLayout(n.rotation,0,n.labelDirection);n.labelMargin=r.get(["label","margin"]),gN(e,i,r,o,{position:vN(i.axis,t,n),align:a.textAlign,verticalAlign:a.textVerticalAlign})}function xN(t,e,n){return{x1:t[n=n||0],y1:t[1-n],x2:e[n],y2:e[1-n]}}function _N(t,e,n){return{x:t[n=n||0],y:t[1-n],width:e[n],height:e[1-n]}}function bN(t,e,n,i,r,o){return{cx:t,cy:e,r0:n,r:i,startAngle:r,endAngle:o,clockwise:!0}}var wN=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.makeElOption=function(t,e,n,i,r){var o=n.axis,a=o.grid,s=i.get("type"),l=SN(a,o).getOtherAxis(o).getGlobalExtent(),u=o.toGlobalCoord(o.dataToCoord(e,!0));if(s&&"none"!==s){var h=fN(i),c=MN[s](o,u,l);c.style=h,t.graphicKey=c.type,t.pointer=c}mN(e,t,iI(a.model,n),n,i,r)},e.prototype.getHandleTransform=function(t,e,n){var i=iI(e.axis.grid.model,e,{labelInside:!1});i.labelMargin=n.get(["handle","margin"]);var r=vN(e.axis,t,i);return{x:r[0],y:r[1],rotation:i.rotation+(i.labelDirection<0?Math.PI:0)}},e.prototype.updateHandleTransform=function(t,e,n,i){var r=n.axis,o=r.grid,a=r.getGlobalExtent(!0),s=SN(o,r).getOtherAxis(r).getGlobalExtent(),l="x"===r.dim?0:1,u=[t.x,t.y];u[l]+=e[l],u[l]=Math.min(a[1],u[l]),u[l]=Math.max(a[0],u[l]);var h=(s[1]+s[0])/2,c=[h,h];c[l]=u[l];return{x:u[0],y:u[1],rotation:t.rotation,cursorPoint:c,tooltipOption:[{verticalAlign:"middle"},{align:"center"}][l]}},e}(lN);function SN(t,e){var n={};return n[e.dim+"AxisIndex"]=e.index,t.getCartesian(n)}var MN={line:function(t,e,n){return{type:"Line",subPixelOptimize:!0,shape:xN([e,n[0]],[e,n[1]],IN(t))}},shadow:function(t,e,n){var i=Math.max(1,t.getBandWidth()),r=n[1]-n[0];return{type:"Rect",shape:_N([e-i/2,n[0]],[i,r],IN(t))}}};function IN(t){return"x"===t.dim?0:1}var TN=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="axisPointer",e.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}},e}(zp),CN=Vo(),DN=E;function AN(t,e,n){if(!r.node){var i=e.getZr();CN(i).records||(CN(i).records={}),function(t,e){if(CN(t).initialized)return;function n(n,i){t.on(n,(function(n){var r=function(t){var e={showTip:[],hideTip:[]},n=function(i){var r=e[i.type];r?r.push(i):(i.dispatchAction=n,t.dispatchAction(i))};return{dispatchAction:n,pendings:e}}(e);DN(CN(t).records,(function(t){t&&i(t,n,r.dispatchAction)})),function(t,e){var n,i=t.showTip.length,r=t.hideTip.length;i?n=t.showTip[i-1]:r&&(n=t.hideTip[r-1]);n&&(n.dispatchAction=null,e.dispatchAction(n))}(r.pendings,e)}))}CN(t).initialized=!0,n("click",H(LN,"click")),n("mousemove",H(LN,"mousemove")),n("globalout",kN)}(i,e),(CN(i).records[t]||(CN(i).records[t]={})).handler=n}}function kN(t,e,n){t.handler("leave",null,n)}function LN(t,e,n,i){e.handler(t,n,i)}function PN(t,e){if(!r.node){var n=e.getZr();(CN(n).records||{})[t]&&(CN(n).records[t]=null)}}var ON=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){var i=e.getComponent("tooltip"),r=t.get("triggerOn")||i&&i.get("triggerOn")||"mousemove|click";AN("axisPointer",n,(function(t,e,n){"none"!==r&&("leave"===t||r.indexOf(t)>=0)&&n({type:"updateAxisPointer",currTrigger:t,x:e&&e.offsetX,y:e&&e.offsetY})}))},e.prototype.remove=function(t,e){PN("axisPointer",e)},e.prototype.dispose=function(t,e){PN("axisPointer",e)},e.type="axisPointer",e}(Ag);function RN(t,e){var n,i=[],r=t.seriesIndex;if(null==r||!(n=e.getSeriesByIndex(r)))return{point:[]};var o=n.getData(),a=zo(o,t);if(null==a||a<0||Y(a))return{point:[]};var s=o.getItemGraphicEl(a),l=n.coordinateSystem;if(n.getTooltipPosition)i=n.getTooltipPosition(a)||[];else if(l&&l.dataToPoint)if(t.isStacked){var u=l.getBaseAxis(),h=l.getOtherAxis(u).dim,c=u.dim,p="x"===h||"radius"===h?1:0,d=o.mapDimension(c),f=[];f[p]=o.get(d,a),f[1-p]=o.get(o.getCalculationInfo("stackResultDimension"),a),i=l.dataToPoint(f)||[]}else i=l.dataToPoint(o.getValues(z(l.dimensions,(function(t){return o.mapDimension(t)})),a))||[];else if(s){var g=s.getBoundingRect().clone();g.applyTransform(s.transform),i=[g.x+g.width/2,g.y+g.height/2]}return{point:i,el:s}}var NN=Vo();function EN(t,e,n){var i=t.currTrigger,r=[t.x,t.y],o=t,a=t.dispatchAction||W(n.dispatchAction,n),s=e.getComponent("axisPointer").coordSysAxesInfo;if(s){GN(r)&&(r=RN({seriesIndex:o.seriesIndex,dataIndex:o.dataIndex},e).point);var l=GN(r),u=o.axesInfo,h=s.axesInfo,c="leave"===i||GN(r),p={},d={},f={list:[],map:{}},g={showPointer:H(VN,d),showTooltip:H(BN,f)};E(s.coordSysMap,(function(t,e){var n=l||t.containPoint(r);E(s.coordSysAxesInfo[e],(function(t,e){var i=t.axis,o=function(t,e){for(var n=0;n<(t||[]).length;n++){var i=t[n];if(e.axis.dim===i.axisDim&&e.axis.model.componentIndex===i.axisIndex)return i}}(u,t);if(!c&&n&&(!u||o)){var a=o&&o.value;null!=a||l||(a=i.pointToData(r)),null!=a&&zN(t,a,g,!1,p)}}))}));var y={};return E(h,(function(t,e){var n=t.linkGroup;n&&!d[e]&&E(n.axesInfo,(function(e,i){var r=d[i];if(e!==t&&r){var o=r.value;n.mapper&&(o=t.axis.scale.parse(n.mapper(o,FN(e),FN(t)))),y[t.key]=o}}))})),E(y,(function(t,e){zN(h[e],t,g,!0,p)})),function(t,e,n){var i=n.axesInfo=[];E(e,(function(e,n){var r=e.axisPointerModel.option,o=t[n];o?(!e.useHandle&&(r.status="show"),r.value=o.value,r.seriesDataIndices=(o.payloadBatch||[]).slice()):!e.useHandle&&(r.status="hide"),"show"===r.status&&i.push({axisDim:e.axis.dim,axisIndex:e.axis.model.componentIndex,value:r.value})}))}(d,h,p),function(t,e,n,i){if(GN(e)||!t.list.length)return void i({type:"hideTip"});var r=((t.list[0].dataByAxis[0]||{}).seriesDataIndices||[])[0]||{};i({type:"showTip",escapeConnect:!0,x:e[0],y:e[1],tooltipOption:n.tooltipOption,position:n.position,dataIndexInside:r.dataIndexInside,dataIndex:r.dataIndex,seriesIndex:r.seriesIndex,dataByCoordSys:t.list})}(f,r,t,a),function(t,e,n){var i=n.getZr(),r="axisPointerLastHighlights",o=NN(i)[r]||{},a=NN(i)[r]={};E(t,(function(t,e){var n=t.axisPointerModel.option;"show"===n.status&&t.triggerEmphasis&&E(n.seriesDataIndices,(function(t){var e=t.seriesIndex+" | "+t.dataIndex;a[e]=t}))}));var s=[],l=[];E(o,(function(t,e){!a[e]&&l.push(t)})),E(a,(function(t,e){!o[e]&&s.push(t)})),l.length&&n.dispatchAction({type:"downplay",escapeConnect:!0,notBlur:!0,batch:l}),s.length&&n.dispatchAction({type:"highlight",escapeConnect:!0,notBlur:!0,batch:s})}(h,0,n),p}}function zN(t,e,n,i,r){var o=t.axis;if(!o.scale.isBlank()&&o.containData(e))if(t.involveSeries){var a=function(t,e){var n=e.axis,i=n.dim,r=t,o=[],a=Number.MAX_VALUE,s=-1;return E(e.seriesModels,(function(e,l){var u,h,c=e.getData().mapDimensionsAll(i);if(e.getAxisTooltipData){var p=e.getAxisTooltipData(c,t,n);h=p.dataIndices,u=p.nestestValue}else{if(!(h=e.getData().indicesOfNearest(c[0],t,"category"===n.type?.5:null)).length)return;u=e.getData().get(c[0],h[0])}if(null!=u&&isFinite(u)){var d=t-u,f=Math.abs(d);f<=a&&((f=0&&s<0)&&(a=f,s=d,r=u,o.length=0),E(h,(function(t){o.push({seriesIndex:e.seriesIndex,dataIndexInside:t,dataIndex:e.getData().getRawIndex(t)})})))}})),{payloadBatch:o,snapToValue:r}}(e,t),s=a.payloadBatch,l=a.snapToValue;s[0]&&null==r.seriesIndex&&A(r,s[0]),!i&&t.snap&&o.containData(l)&&null!=l&&(e=l),n.showPointer(t,e,s),n.showTooltip(t,a,l)}else n.showPointer(t,e)}function VN(t,e,n,i){t[e.key]={value:n,payloadBatch:i}}function BN(t,e,n,i){var r=n.payloadBatch,o=e.axis,a=o.model,s=e.axisPointerModel;if(e.triggerTooltip&&r.length){var l=e.coordSys.model,u=MI(l),h=t.map[u];h||(h=t.map[u]={coordSysId:l.id,coordSysIndex:l.componentIndex,coordSysType:l.type,coordSysMainType:l.mainType,dataByAxis:[]},t.list.push(h)),h.dataByAxis.push({axisDim:o.dim,axisIndex:a.componentIndex,axisType:a.type,axisId:a.id,value:i,valueLabelOpt:{precision:s.get(["label","precision"]),formatter:s.get(["label","formatter"])},seriesDataIndices:r.slice()})}}function FN(t){var e=t.axis.model,n={},i=n.axisDim=t.axis.dim;return n.axisIndex=n[i+"AxisIndex"]=e.componentIndex,n.axisName=n[i+"AxisName"]=e.name,n.axisId=n[i+"AxisId"]=e.id,n}function GN(t){return!t||null==t[0]||isNaN(t[0])||null==t[1]||isNaN(t[1])}function WN(t){TI.registerAxisPointerClass("CartesianAxisPointer",wN),t.registerComponentModel(TN),t.registerComponentView(ON),t.registerPreprocessor((function(t){if(t){(!t.axisPointer||0===t.axisPointer.length)&&(t.axisPointer={});var e=t.axisPointer.link;e&&!Y(e)&&(t.axisPointer.link=[e])}})),t.registerProcessor(t.PRIORITY.PROCESSOR.STATISTIC,(function(t,e){t.getComponent("axisPointer").coordSysAxesInfo=xI(t,e)})),t.registerAction({type:"updateAxisPointer",event:"updateAxisPointer",update:":updateAxisPointer"},EN)}var HN=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.makeElOption=function(t,e,n,i,r){var o=n.axis;"angle"===o.dim&&(this.animationThreshold=Math.PI/18);var a=o.polar,s=a.getOtherAxis(o).getExtent(),l=o.dataToCoord(e),u=i.get("type");if(u&&"none"!==u){var h=fN(i),c=YN[u](o,a,l,s);c.style=h,t.graphicKey=c.type,t.pointer=c}var p=function(t,e,n,i,r){var o=e.axis,a=o.dataToCoord(t),s=i.getAngleAxis().getExtent()[0];s=s/180*Math.PI;var l,u,h,c=i.getRadiusAxis().getExtent();if("radius"===o.dim){var p=[1,0,0,1,0,0];Se(p,p,s),we(p,p,[i.cx,i.cy]),l=Fh([a,-r],p);var d=e.getModel("axisLabel").get("rotate")||0,f=dI.innerTextLayout(s,d*Math.PI/180,-1);u=f.textAlign,h=f.textVerticalAlign}else{var g=c[1];l=i.coordToPoint([g+r,a]);var y=i.cx,v=i.cy;u=Math.abs(l[0]-y)/g<.3?"center":l[0]>y?"left":"right",h=Math.abs(l[1]-v)/g<.3?"middle":l[1]>v?"top":"bottom"}return{position:l,align:u,verticalAlign:h}}(e,n,0,a,i.get(["label","margin"]));gN(t,n,i,r,p)},e}(lN);var YN={line:function(t,e,n,i){return"angle"===t.dim?{type:"Line",shape:xN(e.coordToPoint([i[0],n]),e.coordToPoint([i[1],n]))}:{type:"Circle",shape:{cx:e.cx,cy:e.cy,r:n}}},shadow:function(t,e,n,i){var r=Math.max(1,t.getBandWidth()),o=Math.PI/180;return"angle"===t.dim?{type:"Sector",shape:bN(e.cx,e.cy,i[0],i[1],(-n-r/2)*o,(r/2-n)*o)}:{type:"Sector",shape:bN(e.cx,e.cy,n-r/2,n+r/2,0,2*Math.PI)}}},XN=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.findAxisModel=function(t){var e;return this.ecModel.eachComponent(t,(function(t){t.getCoordSysModel()===this&&(e=t)}),this),e},e.type="polar",e.dependencies=["radiusAxis","angleAxis"],e.defaultOption={z:0,center:["50%","50%"],radius:"80%"},e}(zp),UN=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.getCoordSysModel=function(){return this.getReferringComponents("polar",Wo).models[0]},e.type="polarAxis",e}(zp);R(UN,D_);var ZN=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="angleAxis",e}(UN),jN=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="radiusAxis",e}(UN),qN=function(t){function e(e,n){return t.call(this,"radius",e,n)||this}return n(e,t),e.prototype.pointToData=function(t,e){return this.polar.pointToData(t,e)["radius"===this.dim?0:1]},e}(ab);qN.prototype.dataToRadius=ab.prototype.dataToCoord,qN.prototype.radiusToData=ab.prototype.coordToData;var KN=Vo(),$N=function(t){function e(e,n){return t.call(this,"angle",e,n||[0,360])||this}return n(e,t),e.prototype.pointToData=function(t,e){return this.polar.pointToData(t,e)["radius"===this.dim?0:1]},e.prototype.calculateCategoryInterval=function(){var t=this,e=t.getLabelModel(),n=t.scale,i=n.getExtent(),r=n.count();if(i[1]-i[0]<1)return 0;var o=i[0],a=t.dataToCoord(o+1)-t.dataToCoord(o),s=Math.abs(a),l=Sr(null==o?"":o+"",e.getFont(),"center","top"),u=Math.max(l.height,7)/s;isNaN(u)&&(u=1/0);var h=Math.max(0,Math.floor(u)),c=KN(t.model),p=c.lastAutoInterval,d=c.lastTickCount;return null!=p&&null!=d&&Math.abs(p-h)<=1&&Math.abs(d-r)<=1&&p>h?h=p:(c.lastTickCount=r,c.lastAutoInterval=h),h},e}(ab);$N.prototype.dataToAngle=ab.prototype.dataToCoord,$N.prototype.angleToData=ab.prototype.coordToData;var JN=["radius","angle"],QN=function(){function t(t){this.dimensions=JN,this.type="polar",this.cx=0,this.cy=0,this._radiusAxis=new qN,this._angleAxis=new $N,this.axisPointerEnabled=!0,this.name=t||"",this._radiusAxis.polar=this._angleAxis.polar=this}return t.prototype.containPoint=function(t){var e=this.pointToCoord(t);return this._radiusAxis.contain(e[0])&&this._angleAxis.contain(e[1])},t.prototype.containData=function(t){return this._radiusAxis.containData(t[0])&&this._angleAxis.containData(t[1])},t.prototype.getAxis=function(t){return this["_"+t+"Axis"]},t.prototype.getAxes=function(){return[this._radiusAxis,this._angleAxis]},t.prototype.getAxesByScale=function(t){var e=[],n=this._angleAxis,i=this._radiusAxis;return n.scale.type===t&&e.push(n),i.scale.type===t&&e.push(i),e},t.prototype.getAngleAxis=function(){return this._angleAxis},t.prototype.getRadiusAxis=function(){return this._radiusAxis},t.prototype.getOtherAxis=function(t){var e=this._angleAxis;return t===e?this._radiusAxis:e},t.prototype.getBaseAxis=function(){return this.getAxesByScale("ordinal")[0]||this.getAxesByScale("time")[0]||this.getAngleAxis()},t.prototype.getTooltipAxes=function(t){var e=null!=t&&"auto"!==t?this.getAxis(t):this.getBaseAxis();return{baseAxes:[e],otherAxes:[this.getOtherAxis(e)]}},t.prototype.dataToPoint=function(t,e){return this.coordToPoint([this._radiusAxis.dataToRadius(t[0],e),this._angleAxis.dataToAngle(t[1],e)])},t.prototype.pointToData=function(t,e){var n=this.pointToCoord(t);return[this._radiusAxis.radiusToData(n[0],e),this._angleAxis.angleToData(n[1],e)]},t.prototype.pointToCoord=function(t){var e=t[0]-this.cx,n=t[1]-this.cy,i=this.getAngleAxis(),r=i.getExtent(),o=Math.min(r[0],r[1]),a=Math.max(r[0],r[1]);i.inverse?o=a-360:a=o+360;var s=Math.sqrt(e*e+n*n);e/=s,n/=s;for(var l=Math.atan2(-n,e)/Math.PI*180,u=la;)l+=360*u;return[s,l]},t.prototype.coordToPoint=function(t){var e=t[0],n=t[1]/180*Math.PI;return[Math.cos(n)*e+this.cx,-Math.sin(n)*e+this.cy]},t.prototype.getArea=function(){var t=this.getAngleAxis(),e=this.getRadiusAxis().getExtent().slice();e[0]>e[1]&&e.reverse();var n=t.getExtent(),i=Math.PI/180,r=1e-4;return{cx:this.cx,cy:this.cy,r0:e[0],r:e[1],startAngle:-n[0]*i,endAngle:-n[1]*i,clockwise:t.inverse,contain:function(t,e){var n=t-this.cx,i=e-this.cy,o=n*n+i*i,a=this.r,s=this.r0;return a!==s&&o-r<=a*a&&o+r>=s*s}}},t.prototype.convertToPixel=function(t,e,n){return tE(e)===this?this.dataToPoint(n):null},t.prototype.convertFromPixel=function(t,e,n){return tE(e)===this?this.pointToData(n):null},t}();function tE(t){var e=t.seriesModel,n=t.polarModel;return n&&n.coordinateSystem||e&&e.coordinateSystem}function eE(t,e){var n=this,i=n.getAngleAxis(),r=n.getRadiusAxis();if(i.scale.setExtent(1/0,-1/0),r.scale.setExtent(1/0,-1/0),t.eachSeries((function(t){if(t.coordinateSystem===n){var e=t.getData();E(C_(e,"radius"),(function(t){r.scale.unionExtentFromData(e,t)})),E(C_(e,"angle"),(function(t){i.scale.unionExtentFromData(e,t)}))}})),__(i.scale,i.model),__(r.scale,r.model),"category"===i.type&&!i.onBand){var o=i.getExtent(),a=360/i.scale.count();i.inverse?o[1]+=a:o[1]-=a,i.setExtent(o[0],o[1])}}function nE(t,e){var n;if(t.type=e.get("type"),t.scale=b_(e),t.onBand=e.get("boundaryGap")&&"category"===t.type,t.inverse=e.get("inverse"),function(t){return"angleAxis"===t.mainType}(e)){t.inverse=t.inverse!==e.get("clockwise");var i=e.get("startAngle"),r=null!==(n=e.get("endAngle"))&&void 0!==n?n:i+(t.inverse?-360:360);t.setExtent(i,r)}e.axis=t,t.model=e}var iE={dimensions:JN,create:function(t,e){var n=[];return t.eachComponent("polar",(function(t,i){var r=new QN(i+"");r.update=eE;var o=r.getRadiusAxis(),a=r.getAngleAxis(),s=t.findAxisModel("radiusAxis"),l=t.findAxisModel("angleAxis");nE(o,s),nE(a,l),function(t,e,n){var i=e.get("center"),r=n.getWidth(),o=n.getHeight();t.cx=$r(i[0],r),t.cy=$r(i[1],o);var a=t.getRadiusAxis(),s=Math.min(r,o)/2,l=e.get("radius");null==l?l=[0,"100%"]:Y(l)||(l=[0,l]);var u=[$r(l[0],s),$r(l[1],s)];a.inverse?a.setExtent(u[1],u[0]):a.setExtent(u[0],u[1])}(r,t,e),n.push(r),t.coordinateSystem=r,r.model=t})),t.eachSeries((function(t){if("polar"===t.get("coordinateSystem")){var e=t.getReferringComponents("polar",Wo).models[0];0,t.coordinateSystem=e.coordinateSystem}})),n}},rE=["axisLine","axisLabel","axisTick","minorTick","splitLine","minorSplitLine","splitArea"];function oE(t,e,n){e[1]>e[0]&&(e=e.slice().reverse());var i=t.coordToPoint([e[0],n]),r=t.coordToPoint([e[1],n]);return{x1:i[0],y1:i[1],x2:r[0],y2:r[1]}}function aE(t){return t.getRadiusAxis().inverse?0:1}function sE(t){var e=t[0],n=t[t.length-1];e&&n&&Math.abs(Math.abs(e.coord-n.coord)-360)<1e-4&&t.pop()}var lE=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.axisPointerClass="PolarAxisPointer",n}return n(e,t),e.prototype.render=function(t,e){if(this.group.removeAll(),t.get("show")){var n=t.axis,i=n.polar,r=i.getRadiusAxis().getExtent(),o=n.getTicksCoords(),a=n.getMinorTicksCoords(),s=z(n.getViewLabels(),(function(t){t=T(t);var e=n.scale,i="ordinal"===e.type?e.getRawOrdinalNumber(t.tickValue):t.tickValue;return t.coord=n.dataToCoord(i),t}));sE(s),sE(o),E(rE,(function(e){!t.get([e,"show"])||n.scale.isBlank()&&"axisLine"!==e||uE[e](this.group,t,i,o,a,r,s)}),this)}},e.type="angleAxis",e}(TI),uE={axisLine:function(t,e,n,i,r,o){var a,s=e.getModel(["axisLine","lineStyle"]),l=n.getAngleAxis(),u=Math.PI/180,h=l.getExtent(),c=aE(n),p=c?0:1,d=360===Math.abs(h[1]-h[0])?"Circle":"Arc";(a=0===o[p]?new Qh[d]({shape:{cx:n.cx,cy:n.cy,r:o[c],startAngle:-h[0]*u,endAngle:-h[1]*u,clockwise:l.inverse},style:s.getLineStyle(),z2:1,silent:!0}):new Wu({shape:{cx:n.cx,cy:n.cy,r:o[c],r0:o[p]},style:s.getLineStyle(),z2:1,silent:!0})).style.fill=null,t.add(a)},axisTick:function(t,e,n,i,r,o){var a=e.getModel("axisTick"),s=(a.get("inside")?-1:1)*a.get("length"),l=o[aE(n)],u=z(i,(function(t){return new Ku({shape:oE(n,[l,l+s],t.coord)})}));t.add(Nh(u,{style:k(a.getModel("lineStyle").getLineStyle(),{stroke:e.get(["axisLine","lineStyle","color"])})}))},minorTick:function(t,e,n,i,r,o){if(r.length){for(var a=e.getModel("axisTick"),s=e.getModel("minorTick"),l=(a.get("inside")?-1:1)*s.get("length"),u=o[aE(n)],h=[],c=0;cf?"left":"right",v=Math.abs(d[1]-g)/p<.3?"middle":d[1]>g?"top":"bottom";if(s&&s[c]){var m=s[c];q(m)&&m.textStyle&&(a=new Cc(m.textStyle,l,l.ecModel))}var x=new Xs({silent:dI.isLabelSilent(e),style:oc(a,{x:d[0],y:d[1],fill:a.getTextColor()||e.get(["axisLine","lineStyle","color"]),text:i.formattedLabel,align:y,verticalAlign:v})});if(t.add(x),h){var _=dI.makeAxisEventDataBase(e);_.targetType="axisLabel",_.value=i.rawLabel,rl(x).eventData=_}}),this)},splitLine:function(t,e,n,i,r,o){var a=e.getModel("splitLine").getModel("lineStyle"),s=a.get("color"),l=0;s=s instanceof Array?s:[s];for(var u=[],h=0;h=0?"p":"n",C=b;m&&(i[s][I]||(i[s][I]={p:b,n:b}),C=i[s][I][T]);var D=void 0,A=void 0,k=void 0,L=void 0;if("radius"===c.dim){var P=c.dataToCoord(M)-b,O=o.dataToCoord(I);Math.abs(P)=L})}}}))}var vE={startAngle:90,clockwise:!0,splitNumber:12,axisLabel:{rotate:0}},mE={splitNumber:5},xE=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="polar",e}(Ag);function _E(t,e){e=e||{};var n=t.coordinateSystem,i=t.axis,r={},o=i.position,a=i.orient,s=n.getRect(),l=[s.x,s.x+s.width,s.y,s.y+s.height],u={horizontal:{top:l[2],bottom:l[3]},vertical:{left:l[0],right:l[1]}};r.position=["vertical"===a?u.vertical[o]:l[0],"horizontal"===a?u.horizontal[o]:l[3]];r.rotation=Math.PI/2*{horizontal:0,vertical:1}[a];r.labelDirection=r.tickDirection=r.nameDirection={top:-1,bottom:1,right:1,left:-1}[o],t.get(["axisTick","inside"])&&(r.tickDirection=-r.tickDirection),it(e.labelInside,t.get(["axisLabel","inside"]))&&(r.labelDirection=-r.labelDirection);var h=e.rotate;return null==h&&(h=t.get(["axisLabel","rotate"])),r.labelRotation="top"===o?-h:h,r.z2=1,r}var bE=["axisLine","axisTickLabel","axisName"],wE=["splitArea","splitLine"],SE=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.axisPointerClass="SingleAxisPointer",n}return n(e,t),e.prototype.render=function(e,n,i,r){var o=this.group;o.removeAll();var a=this._axisGroup;this._axisGroup=new Br;var s=_E(e),l=new dI(e,s);E(bE,l.add,l),o.add(this._axisGroup),o.add(l.getGroup()),E(wE,(function(t){e.get([t,"show"])&&ME[t](this,this.group,this._axisGroup,e)}),this),Hh(a,this._axisGroup,e),t.prototype.render.call(this,e,n,i,r)},e.prototype.remove=function(){AI(this)},e.type="singleAxis",e}(TI),ME={splitLine:function(t,e,n,i){var r=i.axis;if(!r.scale.isBlank()){var o=i.getModel("splitLine"),a=o.getModel("lineStyle"),s=a.get("color");s=s instanceof Array?s:[s];for(var l=a.get("width"),u=i.coordinateSystem.getRect(),h=r.isHorizontal(),c=[],p=0,d=r.getTicksCoords({tickModel:o}),f=[],g=[],y=0;y=e.y&&t[1]<=e.y+e.height:n.contain(n.toLocalCoord(t[1]))&&t[0]>=e.y&&t[0]<=e.y+e.height},t.prototype.pointToData=function(t){var e=this.getAxis();return[e.coordToData(e.toLocalCoord(t["horizontal"===e.orient?0:1]))]},t.prototype.dataToPoint=function(t){var e=this.getAxis(),n=this.getRect(),i=[],r="horizontal"===e.orient?0:1;return t instanceof Array&&(t=t[0]),i[r]=e.toGlobalCoord(e.dataToCoord(+t)),i[1-r]=0===r?n.y+n.height/2:n.x+n.width/2,i},t.prototype.convertToPixel=function(t,e,n){return AE(e)===this?this.dataToPoint(n):null},t.prototype.convertFromPixel=function(t,e,n){return AE(e)===this?this.pointToData(n):null},t}();function AE(t){var e=t.seriesModel,n=t.singleAxisModel;return n&&n.coordinateSystem||e&&e.coordinateSystem}var kE={create:function(t,e){var n=[];return t.eachComponent("singleAxis",(function(i,r){var o=new DE(i,t,e);o.name="single_"+r,o.resize(i,e),i.coordinateSystem=o,n.push(o)})),t.eachSeries((function(t){if("singleAxis"===t.get("coordinateSystem")){var e=t.getReferringComponents("singleAxis",Wo).models[0];t.coordinateSystem=e&&e.coordinateSystem}})),n},dimensions:CE},LE=["x","y"],PE=["width","height"],OE=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.makeElOption=function(t,e,n,i,r){var o=n.axis,a=o.coordinateSystem,s=EE(a,1-NE(o)),l=a.dataToPoint(e)[0],u=i.get("type");if(u&&"none"!==u){var h=fN(i),c=RE[u](o,l,s);c.style=h,t.graphicKey=c.type,t.pointer=c}mN(e,t,_E(n),n,i,r)},e.prototype.getHandleTransform=function(t,e,n){var i=_E(e,{labelInside:!1});i.labelMargin=n.get(["handle","margin"]);var r=vN(e.axis,t,i);return{x:r[0],y:r[1],rotation:i.rotation+(i.labelDirection<0?Math.PI:0)}},e.prototype.updateHandleTransform=function(t,e,n,i){var r=n.axis,o=r.coordinateSystem,a=NE(r),s=EE(o,a),l=[t.x,t.y];l[a]+=e[a],l[a]=Math.min(s[1],l[a]),l[a]=Math.max(s[0],l[a]);var u=EE(o,1-a),h=(u[1]+u[0])/2,c=[h,h];return c[a]=l[a],{x:l[0],y:l[1],rotation:t.rotation,cursorPoint:c,tooltipOption:{verticalAlign:"middle"}}},e}(lN),RE={line:function(t,e,n){return{type:"Line",subPixelOptimize:!0,shape:xN([e,n[0]],[e,n[1]],NE(t))}},shadow:function(t,e,n){var i=t.getBandWidth(),r=n[1]-n[0];return{type:"Rect",shape:_N([e-i/2,n[0]],[i,r],NE(t))}}};function NE(t){return t.isHorizontal()?0:1}function EE(t,e){var n=t.getRect();return[n[LE[e]],n[LE[e]]+n[PE[e]]]}var zE=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="single",e}(Ag);var VE=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(e,n,i){var r=Rp(e);t.prototype.init.apply(this,arguments),BE(e,r)},e.prototype.mergeOption=function(e){t.prototype.mergeOption.apply(this,arguments),BE(this.option,e)},e.prototype.getCellSize=function(){return this.option.cellSize},e.type="calendar",e.defaultOption={z:2,left:80,top:60,cellSize:20,orient:"horizontal",splitLine:{show:!0,lineStyle:{color:"#000",width:1,type:"solid"}},itemStyle:{color:"#fff",borderWidth:1,borderColor:"#ccc"},dayLabel:{show:!0,firstDay:0,position:"start",margin:"50%",color:"#000"},monthLabel:{show:!0,position:"start",margin:5,align:"center",formatter:null,color:"#000"},yearLabel:{show:!0,position:null,margin:30,formatter:null,color:"#ccc",fontFamily:"sans-serif",fontWeight:"bolder",fontSize:20}},e}(zp);function BE(t,e){var n,i=t.cellSize;1===(n=Y(i)?i:t.cellSize=[i,i]).length&&(n[1]=n[0]);var r=z([0,1],(function(t){return function(t,e){return null!=t[Cp[e][0]]||null!=t[Cp[e][1]]&&null!=t[Cp[e][2]]}(e,t)&&(n[t]="auto"),null!=n[t]&&"auto"!==n[t]}));Op(t,e,{type:"box",ignoreSize:r})}var FE=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){var i=this.group;i.removeAll();var r=t.coordinateSystem,o=r.getRangeInfo(),a=r.getOrient(),s=e.getLocaleModel();this._renderDayRect(t,o,i),this._renderLines(t,o,a,i),this._renderYearText(t,o,a,i),this._renderMonthText(t,s,a,i),this._renderWeekText(t,s,o,a,i)},e.prototype._renderDayRect=function(t,e,n){for(var i=t.coordinateSystem,r=t.getModel("itemStyle").getItemStyle(),o=i.getCellWidth(),a=i.getCellHeight(),s=e.start.time;s<=e.end.time;s=i.getNextNDay(s,1).time){var l=i.dataToRect([s],!1).tl,u=new Ws({shape:{x:l[0],y:l[1],width:o,height:a},cursor:"default",style:r});n.add(u)}},e.prototype._renderLines=function(t,e,n,i){var r=this,o=t.coordinateSystem,a=t.getModel(["splitLine","lineStyle"]).getLineStyle(),s=t.get(["splitLine","show"]),l=a.lineWidth;this._tlpoints=[],this._blpoints=[],this._firstDayOfMonth=[],this._firstDayPoints=[];for(var u=e.start,h=0;u.time<=e.end.time;h++){p(u.formatedDate),0===h&&(u=o.getDateInfo(e.start.y+"-"+e.start.m));var c=u.date;c.setMonth(c.getMonth()+1),u=o.getDateInfo(c)}function p(e){r._firstDayOfMonth.push(o.getDateInfo(e)),r._firstDayPoints.push(o.dataToRect([e],!1).tl);var l=r._getLinePointsOfOneWeek(t,e,n);r._tlpoints.push(l[0]),r._blpoints.push(l[l.length-1]),s&&r._drawSplitline(l,a,i)}p(o.getNextNDay(e.end.time,1).formatedDate),s&&this._drawSplitline(r._getEdgesPoints(r._tlpoints,l,n),a,i),s&&this._drawSplitline(r._getEdgesPoints(r._blpoints,l,n),a,i)},e.prototype._getEdgesPoints=function(t,e,n){var i=[t[0].slice(),t[t.length-1].slice()],r="horizontal"===n?0:1;return i[0][r]=i[0][r]-e/2,i[1][r]=i[1][r]+e/2,i},e.prototype._drawSplitline=function(t,e,n){var i=new Zu({z2:20,shape:{points:t},style:e});n.add(i)},e.prototype._getLinePointsOfOneWeek=function(t,e,n){for(var i=t.coordinateSystem,r=i.getDateInfo(e),o=[],a=0;a<7;a++){var s=i.getNextNDay(r.time,a),l=i.dataToRect([s.time],!1);o[2*s.day]=l.tl,o[2*s.day+1]=l["horizontal"===n?"bl":"tr"]}return o},e.prototype._formatterLabel=function(t,e){return U(t)&&t?(n=t,E(e,(function(t,e){n=n.replace("{"+e+"}",i?re(t):t)})),n):X(t)?t(e):e.nameMap;var n,i},e.prototype._yearTextPositionControl=function(t,e,n,i,r){var o=e[0],a=e[1],s=["center","bottom"];"bottom"===i?(a+=r,s=["center","top"]):"left"===i?o-=r:"right"===i?(o+=r,s=["center","top"]):a-=r;var l=0;return"left"!==i&&"right"!==i||(l=Math.PI/2),{rotation:l,x:o,y:a,style:{align:s[0],verticalAlign:s[1]}}},e.prototype._renderYearText=function(t,e,n,i){var r=t.getModel("yearLabel");if(r.get("show")){var o=r.get("margin"),a=r.get("position");a||(a="horizontal"!==n?"top":"left");var s=[this._tlpoints[this._tlpoints.length-1],this._blpoints[0]],l=(s[0][0]+s[1][0])/2,u=(s[0][1]+s[1][1])/2,h="horizontal"===n?0:1,c={top:[l,s[h][1]],bottom:[l,s[1-h][1]],left:[s[1-h][0],u],right:[s[h][0],u]},p=e.start.y;+e.end.y>+e.start.y&&(p=p+"-"+e.end.y);var d=r.get("formatter"),f={start:e.start.y,end:e.end.y,nameMap:p},g=this._formatterLabel(d,f),y=new Xs({z2:30,style:oc(r,{text:g}),silent:r.get("silent")});y.attr(this._yearTextPositionControl(y,c[a],n,a,o)),i.add(y)}},e.prototype._monthTextPositionControl=function(t,e,n,i,r){var o="left",a="top",s=t[0],l=t[1];return"horizontal"===n?(l+=r,e&&(o="center"),"start"===i&&(a="bottom")):(s+=r,e&&(a="middle"),"start"===i&&(o="right")),{x:s,y:l,align:o,verticalAlign:a}},e.prototype._renderMonthText=function(t,e,n,i){var r=t.getModel("monthLabel");if(r.get("show")){var o=r.get("nameMap"),a=r.get("margin"),s=r.get("position"),l=r.get("align"),u=[this._tlpoints,this._blpoints];o&&!U(o)||(o&&(e=Vc(o)||e),o=e.get(["time","monthAbbr"])||[]);var h="start"===s?0:1,c="horizontal"===n?0:1;a="start"===s?-a:a;for(var p="center"===l,d=r.get("silent"),f=0;f=i.start.time&&n.timea.end.time&&t.reverse(),t},t.prototype._getRangeInfo=function(t){var e,n=[this.getDateInfo(t[0]),this.getDateInfo(t[1])];n[0].time>n[1].time&&(e=!0,n.reverse());var i=Math.floor(n[1].time/GE)-Math.floor(n[0].time/GE)+1,r=new Date(n[0].time),o=r.getDate(),a=n[1].date.getDate();r.setDate(o+i-1);var s=r.getDate();if(s!==a)for(var l=r.getTime()-n[1].time>0?1:-1;(s=r.getDate())!==a&&(r.getTime()-n[1].time)*l>0;)i-=l,r.setDate(s-l);var u=Math.floor((i+n[0].day+6)/7),h=e?1-u:u-1;return e&&n.reverse(),{range:[n[0].formatedDate,n[1].formatedDate],start:n[0],end:n[1],allDay:i,weeks:u,nthWeek:h,fweek:n[0].day,lweek:n[1].day}},t.prototype._getDateByWeeksAndDay=function(t,e,n){var i=this._getRangeInfo(n);if(t>i.weeks||0===t&&ei.lweek)return null;var r=7*(t-1)-i.fweek+e,o=new Date(i.start.time);return o.setDate(+i.start.d+r),this.getDateInfo(o)},t.create=function(e,n){var i=[];return e.eachComponent("calendar",(function(r){var o=new t(r,e,n);i.push(o),r.coordinateSystem=o})),e.eachSeries((function(t){"calendar"===t.get("coordinateSystem")&&(t.coordinateSystem=i[t.get("calendarIndex")||0])})),i},t.dimensions=["time","value"],t}();function HE(t){var e=t.calendarModel,n=t.seriesModel;return e?e.coordinateSystem:n?n.coordinateSystem:null}function YE(t,e){var n;return E(e,(function(e){null!=t[e]&&"auto"!==t[e]&&(n=!0)})),n}var XE=["transition","enterFrom","leaveTo"],UE=XE.concat(["enterAnimation","updateAnimation","leaveAnimation"]);function ZE(t,e,n){if(n&&(!t[n]&&e[n]&&(t[n]={}),t=t[n],e=e[n]),t&&e)for(var i=n?XE:UE,r=0;r=0;l--){var p,d,f;if(f=null!=(d=Ro((p=n[l]).id,null))?r.get(d):null){var g=f.parent,y=(c=KE(g),{}),v=Lp(f,p,g===i?{width:o,height:a}:{width:c.width,height:c.height},null,{hv:p.hv,boundingMode:p.bounding},y);if(!KE(f).isNew&&v){for(var m=p.transition,x={},_=0;_=0)?x[b]=w:f[b]=w}vh(f,x,t,0)}else f.attr(y)}}},e.prototype._clear=function(){var t=this,e=this._elMap;e.each((function(n){tz(n,KE(n).option,e,t._lastGraphicModel)})),this._elMap=yt()},e.prototype.dispose=function(){this._clear()},e.type="graphic",e}(Ag);function JE(t){var e=_t(qE,t)?qE[t]:Lh(t);var n=new e({});return KE(n).type=t,n}function QE(t,e,n,i){var r=JE(n);return e.add(r),i.set(t,r),KE(r).id=t,KE(r).isNew=!0,r}function tz(t,e,n,i){t&&t.parent&&("group"===t.type&&t.traverse((function(t){tz(t,e,n,i)})),vR(t,e,i),n.removeKey(KE(t).id))}function ez(t,e,n,i){t.isGroup||E([["cursor",Da.prototype.cursor],["zlevel",i||0],["z",n||0],["z2",0]],(function(n){var i=n[0];_t(e,i)?t[i]=rt(e[i],n[1]):null==t[i]&&(t[i]=n[1])})),E(G(e),(function(n){if(0===n.indexOf("on")){var i=e[n];t[n]=X(i)?i:null}})),_t(e,"draggable")&&(t.draggable=e.draggable),null!=e.name&&(t.name=e.name),null!=e.id&&(t.id=e.id)}var nz=["x","y","radius","angle","single"],iz=["cartesian2d","polar","singleAxis"];function rz(t){return t+"Axis"}function oz(t,e){var n,i=yt(),r=[],o=yt();t.eachComponent({mainType:"dataZoom",query:e},(function(t){o.get(t.uid)||s(t)}));do{n=!1,t.eachComponent("dataZoom",a)}while(n);function a(t){!o.get(t.uid)&&function(t){var e=!1;return t.eachTargetAxis((function(t,n){var r=i.get(t);r&&r[n]&&(e=!0)})),e}(t)&&(s(t),n=!0)}function s(t){o.set(t.uid,!0),r.push(t),t.eachTargetAxis((function(t,e){(i.get(t)||i.set(t,[]))[e]=!0}))}return r}function az(t){var e=t.ecModel,n={infoList:[],infoMap:yt()};return t.eachTargetAxis((function(t,i){var r=e.getComponent(rz(t),i);if(r){var o=r.getCoordSysModel();if(o){var a=o.uid,s=n.infoMap.get(a);s||(s={model:o,axisModels:[]},n.infoList.push(s),n.infoMap.set(a,s)),s.axisModels.push(r)}}})),n}var sz=function(){function t(){this.indexList=[],this.indexMap=[]}return t.prototype.add=function(t){this.indexMap[t]||(this.indexList.push(t),this.indexMap[t]=!0)},t}(),lz=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n._autoThrottle=!0,n._noTarget=!0,n._rangePropMode=["percent","percent"],n}return n(e,t),e.prototype.init=function(t,e,n){var i=uz(t);this.settledOption=i,this.mergeDefaultAndTheme(t,n),this._doInit(i)},e.prototype.mergeOption=function(t){var e=uz(t);C(this.option,t,!0),C(this.settledOption,e,!0),this._doInit(e)},e.prototype._doInit=function(t){var e=this.option;this._setDefaultThrottle(t),this._updateRangeUse(t);var n=this.settledOption;E([["start","startValue"],["end","endValue"]],(function(t,i){"value"===this._rangePropMode[i]&&(e[t[0]]=n[t[0]]=null)}),this),this._resetTarget()},e.prototype._resetTarget=function(){var t=this.get("orient",!0),e=this._targetAxisInfoMap=yt();this._fillSpecifiedTargetAxis(e)?this._orient=t||this._makeAutoOrientByTargetAxis():(this._orient=t||"horizontal",this._fillAutoTargetAxisByOrient(e,this._orient)),this._noTarget=!0,e.each((function(t){t.indexList.length&&(this._noTarget=!1)}),this)},e.prototype._fillSpecifiedTargetAxis=function(t){var e=!1;return E(nz,(function(n){var i=this.getReferringComponents(rz(n),Ho);if(i.specified){e=!0;var r=new sz;E(i.models,(function(t){r.add(t.componentIndex)})),t.set(n,r)}}),this),e},e.prototype._fillAutoTargetAxisByOrient=function(t,e){var n=this.ecModel,i=!0;if(i){var r="vertical"===e?"y":"x";o(n.findComponents({mainType:r+"Axis"}),r)}i&&o(n.findComponents({mainType:"singleAxis",filter:function(t){return t.get("orient",!0)===e}}),"single");function o(e,n){var r=e[0];if(r){var o=new sz;if(o.add(r.componentIndex),t.set(n,o),i=!1,"x"===n||"y"===n){var a=r.getReferringComponents("grid",Wo).models[0];a&&E(e,(function(t){r.componentIndex!==t.componentIndex&&a===t.getReferringComponents("grid",Wo).models[0]&&o.add(t.componentIndex)}))}}}i&&E(nz,(function(e){if(i){var r=n.findComponents({mainType:rz(e),filter:function(t){return"category"===t.get("type",!0)}});if(r[0]){var o=new sz;o.add(r[0].componentIndex),t.set(e,o),i=!1}}}),this)},e.prototype._makeAutoOrientByTargetAxis=function(){var t;return this.eachTargetAxis((function(e){!t&&(t=e)}),this),"y"===t?"vertical":"horizontal"},e.prototype._setDefaultThrottle=function(t){if(t.hasOwnProperty("throttle")&&(this._autoThrottle=!1),this._autoThrottle){var e=this.ecModel.option;this.option.throttle=e.animation&&e.animationDurationUpdate>0?100:20}},e.prototype._updateRangeUse=function(t){var e=this._rangePropMode,n=this.get("rangeMode");E([["start","startValue"],["end","endValue"]],(function(i,r){var o=null!=t[i[0]],a=null!=t[i[1]];o&&!a?e[r]="percent":!o&&a?e[r]="value":n?e[r]=n[r]:o&&(e[r]="percent")}))},e.prototype.noTarget=function(){return this._noTarget},e.prototype.getFirstTargetAxisModel=function(){var t;return this.eachTargetAxis((function(e,n){null==t&&(t=this.ecModel.getComponent(rz(e),n))}),this),t},e.prototype.eachTargetAxis=function(t,e){this._targetAxisInfoMap.each((function(n,i){E(n.indexList,(function(n){t.call(e,i,n)}))}))},e.prototype.getAxisProxy=function(t,e){var n=this.getAxisModel(t,e);if(n)return n.__dzAxisProxy},e.prototype.getAxisModel=function(t,e){var n=this._targetAxisInfoMap.get(t);if(n&&n.indexMap[e])return this.ecModel.getComponent(rz(t),e)},e.prototype.setRawRange=function(t){var e=this.option,n=this.settledOption;E([["start","startValue"],["end","endValue"]],(function(i){null==t[i[0]]&&null==t[i[1]]||(e[i[0]]=n[i[0]]=t[i[0]],e[i[1]]=n[i[1]]=t[i[1]])}),this),this._updateRangeUse(t)},e.prototype.setCalculatedRange=function(t){var e=this.option;E(["start","startValue","end","endValue"],(function(n){e[n]=t[n]}))},e.prototype.getPercentRange=function(){var t=this.findRepresentativeAxisProxy();if(t)return t.getDataPercentWindow()},e.prototype.getValueRange=function(t,e){if(null!=t||null!=e)return this.getAxisProxy(t,e).getDataValueWindow();var n=this.findRepresentativeAxisProxy();return n?n.getDataValueWindow():void 0},e.prototype.findRepresentativeAxisProxy=function(t){if(t)return t.__dzAxisProxy;for(var e,n=this._targetAxisInfoMap.keys(),i=0;i=0}(e)){var n=rz(this._dimName),i=e.getReferringComponents(n,Wo).models[0];i&&this._axisIndex===i.componentIndex&&t.push(e)}}),this),t},t.prototype.getAxisModel=function(){return this.ecModel.getComponent(this._dimName+"Axis",this._axisIndex)},t.prototype.getMinMaxSpan=function(){return T(this._minMaxSpan)},t.prototype.calculateDataWindow=function(t){var e,n=this._dataExtent,i=this.getAxisModel().axis.scale,r=this._dataZoomModel.getRangePropMode(),o=[0,100],a=[],s=[];dz(["start","end"],(function(l,u){var h=t[l],c=t[l+"Value"];"percent"===r[u]?(null==h&&(h=o[u]),c=i.parse(Kr(h,o,n))):(e=!0,h=Kr(c=null==c?n[u]:i.parse(c),n,o)),s[u]=null==c||isNaN(c)?n[u]:c,a[u]=null==h||isNaN(h)?o[u]:h})),fz(s),fz(a);var l=this._minMaxSpan;function u(t,e,n,r,o){var a=o?"Span":"ValueSpan";zk(0,t,n,"all",l["min"+a],l["max"+a]);for(var s=0;s<2;s++)e[s]=Kr(t[s],n,r,!0),o&&(e[s]=i.parse(e[s]))}return e?u(s,a,n,o,!1):u(a,s,o,n,!0),{valueWindow:s,percentWindow:a}},t.prototype.reset=function(t){if(t===this._dataZoomModel){var e=this.getTargetSeriesModels();this._dataExtent=function(t,e,n){var i=[1/0,-1/0];dz(n,(function(t){!function(t,e,n){e&&E(C_(e,n),(function(n){var i=e.getApproximateExtent(n);i[0]t[1]&&(t[1]=i[1])}))}(i,t.getData(),e)}));var r=t.getAxisModel(),o=v_(r.axis.scale,r,i).calculate();return[o.min,o.max]}(this,this._dimName,e),this._updateMinMaxSpan();var n=this.calculateDataWindow(t.settledOption);this._valueWindow=n.valueWindow,this._percentWindow=n.percentWindow,this._setAxisModel()}},t.prototype.filterData=function(t,e){if(t===this._dataZoomModel){var n=this._dimName,i=this.getTargetSeriesModels(),r=t.get("filterMode"),o=this._valueWindow;"none"!==r&&dz(i,(function(t){var e=t.getData(),i=e.mapDimensionsAll(n);if(i.length){if("weakFilter"===r){var a=e.getStore(),s=z(i,(function(t){return e.getDimensionIndex(t)}),e);e.filterSelf((function(t){for(var e,n,r,l=0;lo[1];if(h&&!c&&!p)return!0;h&&(r=!0),c&&(e=!0),p&&(n=!0)}return r&&e&&n}))}else dz(i,(function(n){if("empty"===r)t.setData(e=e.map(n,(function(t){return function(t){return t>=o[0]&&t<=o[1]}(t)?t:NaN})));else{var i={};i[n]=o,e.selectRange(i)}}));dz(i,(function(t){e.setApproximateExtent(o,t)}))}}))}},t.prototype._updateMinMaxSpan=function(){var t=this._minMaxSpan={},e=this._dataZoomModel,n=this._dataExtent;dz(["min","max"],(function(i){var r=e.get(i+"Span"),o=e.get(i+"ValueSpan");null!=o&&(o=this.getAxisModel().axis.scale.parse(o)),null!=o?r=Kr(n[0]+o,n,[0,100],!0):null!=r&&(o=Kr(r,[0,100],n,!0)-n[0]),t[i+"Span"]=r,t[i+"ValueSpan"]=o}),this)},t.prototype._setAxisModel=function(){var t=this.getAxisModel(),e=this._percentWindow,n=this._valueWindow;if(e){var i=no(n,[0,500]);i=Math.min(i,20);var r=t.axis.scale.rawExtentInfo;0!==e[0]&&r.setDeterminedMinMax("min",+n[0].toFixed(i)),100!==e[1]&&r.setDeterminedMinMax("max",+n[1].toFixed(i)),r.freeze()}},t}();var yz={getTargetSeries:function(t){function e(e){t.eachComponent("dataZoom",(function(n){n.eachTargetAxis((function(i,r){var o=t.getComponent(rz(i),r);e(i,r,o,n)}))}))}e((function(t,e,n,i){n.__dzAxisProxy=null}));var n=[];e((function(e,i,r,o){r.__dzAxisProxy||(r.__dzAxisProxy=new gz(e,i,o,t),n.push(r.__dzAxisProxy))}));var i=yt();return E(n,(function(t){E(t.getTargetSeriesModels(),(function(t){i.set(t.uid,t)}))})),i},overallReset:function(t,e){t.eachComponent("dataZoom",(function(t){t.eachTargetAxis((function(e,n){t.getAxisProxy(e,n).reset(t)})),t.eachTargetAxis((function(n,i){t.getAxisProxy(n,i).filterData(t,e)}))})),t.eachComponent("dataZoom",(function(t){var e=t.findRepresentativeAxisProxy();if(e){var n=e.getDataPercentWindow(),i=e.getDataValueWindow();t.setCalculatedRange({start:n[0],end:n[1],startValue:i[0],endValue:i[1]})}}))}};var vz=!1;function mz(t){vz||(vz=!0,t.registerProcessor(t.PRIORITY.PROCESSOR.FILTER,yz),function(t){t.registerAction("dataZoom",(function(t,e){E(oz(e,t),(function(e){e.setRawRange({start:t.start,end:t.end,startValue:t.startValue,endValue:t.endValue})}))}))}(t),t.registerSubTypeDefaulter("dataZoom",(function(){return"slider"})))}function xz(t){t.registerComponentModel(hz),t.registerComponentView(pz),mz(t)}var _z=function(){},bz={};function wz(t,e){bz[t]=e}function Sz(t){return bz[t]}var Mz=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.optionUpdated=function(){t.prototype.optionUpdated.apply(this,arguments);var e=this.ecModel;E(this.option.feature,(function(t,n){var i=Sz(n);i&&(i.getDefaultOption&&(i.defaultOption=i.getDefaultOption(e)),C(t,i.defaultOption))}))},e.type="toolbox",e.layoutMode={type:"box",ignoreSize:!0},e.defaultOption={show:!0,z:6,orient:"horizontal",left:"right",top:"top",backgroundColor:"transparent",borderColor:"#ccc",borderRadius:0,borderWidth:0,padding:5,itemSize:15,itemGap:8,showTitle:!0,iconStyle:{borderColor:"#666",color:"none"},emphasis:{iconStyle:{borderColor:"#3E98C5"}},tooltip:{show:!1,position:"bottom"}},e}(zp);function Iz(t,e){var n=vp(e.get("padding")),i=e.getItemStyle(["color","opacity"]);return i.fill=e.get("backgroundColor"),t=new Ws({shape:{x:t.x-n[3],y:t.y-n[0],width:t.width+n[1]+n[3],height:t.height+n[0]+n[2],r:e.get("borderRadius")},style:i,silent:!0,z2:-1})}var Tz=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.render=function(t,e,n,i){var r=this.group;if(r.removeAll(),t.get("show")){var o=+t.get("itemSize"),a="vertical"===t.get("orient"),s=t.get("feature")||{},l=this._features||(this._features={}),u=[];E(s,(function(t,e){u.push(e)})),new Gm(this._featureNames||[],u).add(h).update(h).remove(H(h,null)).execute(),this._featureNames=u,function(t,e,n){var i=e.getBoxLayoutParams(),r=e.get("padding"),o={width:n.getWidth(),height:n.getHeight()},a=kp(i,o,r);Ap(e.get("orient"),t,e.get("itemGap"),a.width,a.height),Lp(t,i,o,r)}(r,t,n),r.add(Iz(r.getBoundingRect(),t)),a||r.eachChild((function(t){var e=t.__title,i=t.ensureState("emphasis"),a=i.textConfig||(i.textConfig={}),s=t.getTextContent(),l=s&&s.ensureState("emphasis");if(l&&!X(l)&&e){var u=l.style||(l.style={}),h=Sr(e,Xs.makeFont(u)),c=t.x+r.x,p=!1;t.y+r.y+o+h.height>n.getHeight()&&(a.position="top",p=!0);var d=p?-5-h.height:o+10;c+h.width/2>n.getWidth()?(a.position=["100%",d],u.align="right"):c-h.width/2<0&&(a.position=[0,d],u.align="left")}}))}function h(h,c){var p,d=u[h],f=u[c],g=s[d],y=new Cc(g,t,t.ecModel);if(i&&null!=i.newTitle&&i.featureName===d&&(g.title=i.newTitle),d&&!f){if(function(t){return 0===t.indexOf("my")}(d))p={onclick:y.option.onclick,featureName:d};else{var v=Sz(d);if(!v)return;p=new v}l[d]=p}else if(!(p=l[f]))return;p.uid=Ac("toolbox-feature"),p.model=y,p.ecModel=e,p.api=n;var m=p instanceof _z;d||!f?!y.get("show")||m&&p.unusable?m&&p.remove&&p.remove(e,n):(!function(i,s,l){var u,h,c=i.getModel("iconStyle"),p=i.getModel(["emphasis","iconStyle"]),d=s instanceof _z&&s.getIcons?s.getIcons():i.get("icon"),f=i.get("title")||{};U(d)?(u={})[l]=d:u=d;U(f)?(h={})[l]=f:h=f;var g=i.iconPaths={};E(u,(function(l,u){var d=Uh(l,{},{x:-o/2,y:-o/2,width:o,height:o});d.setStyle(c.getItemStyle()),d.ensureState("emphasis").style=p.getItemStyle();var f=new Xs({style:{text:h[u],align:p.get("textAlign"),borderRadius:p.get("textBorderRadius"),padding:p.get("textPadding"),fill:null,font:cc({fontStyle:p.get("textFontStyle"),fontFamily:p.get("textFontFamily"),fontSize:p.get("textFontSize"),fontWeight:p.get("textFontWeight")},e)},ignore:!0});d.setTextContent(f),Kh({el:d,componentModel:t,itemName:u,formatterParamsExtra:{title:h[u]}}),d.__title=h[u],d.on("mouseover",(function(){var e=p.getItemStyle(),i=a?null==t.get("right")&&"right"!==t.get("left")?"right":"left":null==t.get("bottom")&&"bottom"!==t.get("top")?"bottom":"top";f.setStyle({fill:p.get("textFill")||e.fill||e.stroke||"#000",backgroundColor:p.get("textBackgroundColor")}),d.setTextConfig({position:p.get("textPosition")||i}),f.ignore=!t.get("showTitle"),n.enterEmphasis(this)})).on("mouseout",(function(){"emphasis"!==i.get(["iconStatus",u])&&n.leaveEmphasis(this),f.hide()})),("emphasis"===i.get(["iconStatus",u])?Ol:Rl)(d),r.add(d),d.on("click",W(s.onclick,s,e,n,u)),g[u]=d}))}(y,p,d),y.setIconStatus=function(t,e){var n=this.option,i=this.iconPaths;n.iconStatus=n.iconStatus||{},n.iconStatus[t]=e,i[t]&&("emphasis"===e?Ol:Rl)(i[t])},p instanceof _z&&p.render&&p.render(y,e,n,i)):m&&p.dispose&&p.dispose(e,n)}},e.prototype.updateView=function(t,e,n,i){E(this._features,(function(t){t instanceof _z&&t.updateView&&t.updateView(t.model,e,n,i)}))},e.prototype.remove=function(t,e){E(this._features,(function(n){n instanceof _z&&n.remove&&n.remove(t,e)})),this.group.removeAll()},e.prototype.dispose=function(t,e){E(this._features,(function(n){n instanceof _z&&n.dispose&&n.dispose(t,e)}))},e.type="toolbox",e}(Ag);var Cz=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.onclick=function(t,e){var n=this.model,i=n.get("name")||t.get("title.0.text")||"echarts",o="svg"===e.getZr().painter.getType(),a=o?"svg":n.get("type",!0)||"png",s=e.getConnectedDataURL({type:a,backgroundColor:n.get("backgroundColor",!0)||t.get("backgroundColor")||"#fff",connectedBackgroundColor:n.get("connectedBackgroundColor"),excludeComponents:n.get("excludeComponents"),pixelRatio:n.get("pixelRatio")}),l=r.browser;if("function"!=typeof MouseEvent||!l.newEdge&&(l.ie||l.edge))if(window.navigator.msSaveOrOpenBlob||o){var u=s.split(","),h=u[0].indexOf("base64")>-1,c=o?decodeURIComponent(u[1]):u[1];h&&(c=window.atob(c));var p=i+"."+a;if(window.navigator.msSaveOrOpenBlob){for(var d=c.length,f=new Uint8Array(d);d--;)f[d]=c.charCodeAt(d);var g=new Blob([f]);window.navigator.msSaveOrOpenBlob(g,p)}else{var y=document.createElement("iframe");document.body.appendChild(y);var v=y.contentWindow,m=v.document;m.open("image/svg+xml","replace"),m.write(c),m.close(),v.focus(),m.execCommand("SaveAs",!0,p),document.body.removeChild(y)}}else{var x=n.get("lang"),_='',b=window.open();b.document.write(_),b.document.title=i}else{var w=document.createElement("a");w.download=i+"."+a,w.target="_blank",w.href=s;var S=new MouseEvent("click",{view:document.defaultView,bubbles:!0,cancelable:!1});w.dispatchEvent(S)}},e.getDefaultOption=function(t){return{show:!0,icon:"M4.7,22.9L29.3,45.5L54.7,23.4M4.6,43.6L4.6,58L53.8,58L53.8,43.6M29.2,45.1L29.2,0",title:t.getLocaleModel().get(["toolbox","saveAsImage","title"]),type:"png",connectedBackgroundColor:"#fff",name:"",excludeComponents:["toolbox"],lang:t.getLocaleModel().get(["toolbox","saveAsImage","lang"])}},e}(_z),Dz="__ec_magicType_stack__",Az=[["line","bar"],["stack"]],kz=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.getIcons=function(){var t=this.model,e=t.get("icon"),n={};return E(t.get("type"),(function(t){e[t]&&(n[t]=e[t])})),n},e.getDefaultOption=function(t){return{show:!0,type:[],icon:{line:"M4.1,28.9h7.1l9.3-22l7.4,38l9.7-19.7l3,12.8h14.9M4.1,58h51.4",bar:"M6.7,22.9h10V48h-10V22.9zM24.9,13h10v35h-10V13zM43.2,2h10v46h-10V2zM3.1,58h53.7",stack:"M8.2,38.4l-8.4,4.1l30.6,15.3L60,42.5l-8.1-4.1l-21.5,11L8.2,38.4z M51.9,30l-8.1,4.2l-13.4,6.9l-13.9-6.9L8.2,30l-8.4,4.2l8.4,4.2l22.2,11l21.5-11l8.1-4.2L51.9,30z M51.9,21.7l-8.1,4.2L35.7,30l-5.3,2.8L24.9,30l-8.4-4.1l-8.3-4.2l-8.4,4.2L8.2,30l8.3,4.2l13.9,6.9l13.4-6.9l8.1-4.2l8.1-4.1L51.9,21.7zM30.4,2.2L-0.2,17.5l8.4,4.1l8.3,4.2l8.4,4.2l5.5,2.7l5.3-2.7l8.1-4.2l8.1-4.2l8.1-4.1L30.4,2.2z"},title:t.getLocaleModel().get(["toolbox","magicType","title"]),option:{},seriesIndex:{}}},e.prototype.onclick=function(t,e,n){var i=this.model,r=i.get(["seriesIndex",n]);if(Lz[n]){var o,a={series:[]};E(Az,(function(t){P(t,n)>=0&&E(t,(function(t){i.setIconStatus(t,"normal")}))})),i.setIconStatus(n,"emphasis"),t.eachComponent({mainType:"series",query:null==r?null:{seriesIndex:r}},(function(t){var e=t.subType,r=t.id,o=Lz[n](e,r,t,i);o&&(k(o,t.option),a.series.push(o));var s=t.coordinateSystem;if(s&&"cartesian2d"===s.type&&("line"===n||"bar"===n)){var l=s.getAxesByScale("ordinal")[0];if(l){var u=l.dim+"Axis",h=t.getReferringComponents(u,Wo).models[0].componentIndex;a[u]=a[u]||[];for(var c=0;c<=h;c++)a[u][h]=a[u][h]||{};a[u][h].boundaryGap="bar"===n}}}));var s=n;"stack"===n&&(o=C({stack:i.option.title.tiled,tiled:i.option.title.stack},i.option.title),"emphasis"!==i.get(["iconStatus",n])&&(s="tiled")),e.dispatchAction({type:"changeMagicType",currentType:s,newOption:a,newTitle:o,featureName:"magicType"})}},e}(_z),Lz={line:function(t,e,n,i){if("bar"===t)return C({id:e,type:"line",data:n.get("data"),stack:n.get("stack"),markPoint:n.get("markPoint"),markLine:n.get("markLine")},i.get(["option","line"])||{},!0)},bar:function(t,e,n,i){if("line"===t)return C({id:e,type:"bar",data:n.get("data"),stack:n.get("stack"),markPoint:n.get("markPoint"),markLine:n.get("markLine")},i.get(["option","bar"])||{},!0)},stack:function(t,e,n,i){var r=n.get("stack")===Dz;if("line"===t||"bar"===t)return i.setIconStatus("stack",r?"normal":"emphasis"),C({id:e,stack:r?"":Dz},i.get(["option","stack"])||{},!0)}};Cm({type:"changeMagicType",event:"magicTypeChanged",update:"prepareAndUpdate"},(function(t,e){e.mergeOption(t.newOption)}));var Pz=new Array(60).join("-"),Oz="\t";function Rz(t){return t.replace(/^\s\s*/,"").replace(/\s\s*$/,"")}var Nz=new RegExp("[\t]+","g");function Ez(t,e){var n=t.split(new RegExp("\n*"+Pz+"\n*","g")),i={series:[]};return E(n,(function(t,n){if(function(t){if(t.slice(0,t.indexOf("\n")).indexOf(Oz)>=0)return!0}(t)){var r=function(t){for(var e=t.split(/\n+/g),n=[],i=z(Rz(e.shift()).split(Nz),(function(t){return{name:t,data:[]}})),r=0;r=0)&&t(r,i._targetInfoList)}))}return t.prototype.setOutputRanges=function(t,e){return this.matchOutputRanges(t,e,(function(t,e,n){if((t.coordRanges||(t.coordRanges=[])).push(e),!t.coordRange){t.coordRange=e;var i=Kz[t.brushType](0,n,e);t.__rangeOffset={offset:Jz[t.brushType](i.values,t.range,[1,1]),xyMinMax:i.xyMinMax}}})),t},t.prototype.matchOutputRanges=function(t,e,n){E(t,(function(t){var i=this.findTargetInfo(t,e);i&&!0!==i&&E(i.coordSyses,(function(i){var r=Kz[t.brushType](1,i,t.range,!0);n(t,r.values,i,e)}))}),this)},t.prototype.setInputRanges=function(t,e){E(t,(function(t){var n,i,r,o,a,s=this.findTargetInfo(t,e);if(t.range=t.range||[],s&&!0!==s){t.panelId=s.panelId;var l=Kz[t.brushType](0,s.coordSys,t.coordRange),u=t.__rangeOffset;t.range=u?Jz[t.brushType](l.values,u.offset,(n=l.xyMinMax,i=u.xyMinMax,r=tV(n),o=tV(i),a=[r[0]/o[0],r[1]/o[1]],isNaN(a[0])&&(a[0]=1),isNaN(a[1])&&(a[1]=1),a)):l.values}}),this)},t.prototype.makePanelOpts=function(t,e){return z(this._targetInfoList,(function(n){var i=n.getPanelRect();return{panelId:n.panelId,defaultBrushType:e?e(n):null,clipPath:BL(i),isTargetByCursor:GL(i,t,n.coordSysModel),getLinearBrushOtherExtent:FL(i)}}))},t.prototype.controlSeries=function(t,e,n){var i=this.findTargetInfo(t,n);return!0===i||i&&P(i.coordSyses,e.coordinateSystem)>=0},t.prototype.findTargetInfo=function(t,e){for(var n=this._targetInfoList,i=Uz(e,t),r=0;rt[1]&&t.reverse(),t}function Uz(t,e){return Fo(t,e,{includeMainTypes:Hz})}var Zz={grid:function(t,e){var n=t.xAxisModels,i=t.yAxisModels,r=t.gridModels,o=yt(),a={},s={};(n||i||r)&&(E(n,(function(t){var e=t.axis.grid.model;o.set(e.id,e),a[e.id]=!0})),E(i,(function(t){var e=t.axis.grid.model;o.set(e.id,e),s[e.id]=!0})),E(r,(function(t){o.set(t.id,t),a[t.id]=!0,s[t.id]=!0})),o.each((function(t){var r=t.coordinateSystem,o=[];E(r.getCartesians(),(function(t,e){(P(n,t.getAxis("x").model)>=0||P(i,t.getAxis("y").model)>=0)&&o.push(t)})),e.push({panelId:"grid--"+t.id,gridModel:t,coordSysModel:t,coordSys:o[0],coordSyses:o,getPanelRect:qz.grid,xAxisDeclared:a[t.id],yAxisDeclared:s[t.id]})})))},geo:function(t,e){E(t.geoModels,(function(t){var n=t.coordinateSystem;e.push({panelId:"geo--"+t.id,geoModel:t,coordSysModel:t,coordSys:n,coordSyses:[n],getPanelRect:qz.geo})}))}},jz=[function(t,e){var n=t.xAxisModel,i=t.yAxisModel,r=t.gridModel;return!r&&n&&(r=n.axis.grid.model),!r&&i&&(r=i.axis.grid.model),r&&r===e.gridModel},function(t,e){var n=t.geoModel;return n&&n===e.geoModel}],qz={grid:function(){return this.coordSys.master.getRect().clone()},geo:function(){var t=this.coordSys,e=t.getBoundingRect().clone();return e.applyTransform(Bh(t)),e}},Kz={lineX:H($z,0),lineY:H($z,1),rect:function(t,e,n,i){var r=t?e.pointToData([n[0][0],n[1][0]],i):e.dataToPoint([n[0][0],n[1][0]],i),o=t?e.pointToData([n[0][1],n[1][1]],i):e.dataToPoint([n[0][1],n[1][1]],i),a=[Xz([r[0],o[0]]),Xz([r[1],o[1]])];return{values:a,xyMinMax:a}},polygon:function(t,e,n,i){var r=[[1/0,-1/0],[1/0,-1/0]];return{values:z(n,(function(n){var o=t?e.pointToData(n,i):e.dataToPoint(n,i);return r[0][0]=Math.min(r[0][0],o[0]),r[1][0]=Math.min(r[1][0],o[1]),r[0][1]=Math.max(r[0][1],o[0]),r[1][1]=Math.max(r[1][1],o[1]),o})),xyMinMax:r}}};function $z(t,e,n,i){var r=n.getAxis(["x","y"][t]),o=Xz(z([0,1],(function(t){return e?r.coordToData(r.toLocalCoord(i[t]),!0):r.toGlobalCoord(r.dataToCoord(i[t]))}))),a=[];return a[t]=o,a[1-t]=[NaN,NaN],{values:o,xyMinMax:a}}var Jz={lineX:H(Qz,0),lineY:H(Qz,1),rect:function(t,e,n){return[[t[0][0]-n[0]*e[0][0],t[0][1]-n[0]*e[0][1]],[t[1][0]-n[1]*e[1][0],t[1][1]-n[1]*e[1][1]]]},polygon:function(t,e,n){return z(t,(function(t,i){return[t[0]-n[0]*e[i][0],t[1]-n[1]*e[i][1]]}))}};function Qz(t,e,n,i){return[e[0]-i[t]*n[0],e[1]-i[t]*n[1]]}function tV(t){return t?[t[0][1]-t[0][0],t[1][1]-t[1][0]]:[NaN,NaN]}var eV,nV,iV=E,rV=Io+"toolbox-dataZoom_",oV=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.render=function(t,e,n,i){this._brushController||(this._brushController=new lL(n.getZr()),this._brushController.on("brush",W(this._onBrush,this)).mount()),function(t,e,n,i,r){var o=n._isZoomActive;i&&"takeGlobalCursor"===i.type&&(o="dataZoomSelect"===i.key&&i.dataZoomSelectActive);n._isZoomActive=o,t.setIconStatus("zoom",o?"emphasis":"normal");var a=new Yz(sV(t),e,{include:["grid"]}),s=a.makePanelOpts(r,(function(t){return t.xAxisDeclared&&!t.yAxisDeclared?"lineX":!t.xAxisDeclared&&t.yAxisDeclared?"lineY":"rect"}));n._brushController.setPanels(s).enableBrush(!(!o||!s.length)&&{brushType:"auto",brushStyle:t.getModel("brushStyle").getItemStyle()})}(t,e,this,i,n),function(t,e){t.setIconStatus("back",function(t){return Gz(t).length}(e)>1?"emphasis":"normal")}(t,e)},e.prototype.onclick=function(t,e,n){aV[n].call(this)},e.prototype.remove=function(t,e){this._brushController&&this._brushController.unmount()},e.prototype.dispose=function(t,e){this._brushController&&this._brushController.dispose()},e.prototype._onBrush=function(t){var e=t.areas;if(t.isEnd&&e.length){var n={},i=this.ecModel;this._brushController.updateCovers([]),new Yz(sV(this.model),i,{include:["grid"]}).matchOutputRanges(e,i,(function(t,e,n){if("cartesian2d"===n.type){var i=t.brushType;"rect"===i?(r("x",n,e[0]),r("y",n,e[1])):r({lineX:"x",lineY:"y"}[i],n,e)}})),function(t,e){var n=Gz(t);Bz(e,(function(e,i){for(var r=n.length-1;r>=0&&!n[r][i];r--);if(r<0){var o=t.queryComponents({mainType:"dataZoom",subType:"select",id:i})[0];if(o){var a=o.getPercentRange();n[0][i]={dataZoomId:i,start:a[0],end:a[1]}}}})),n.push(e)}(i,n),this._dispatchZoomAction(n)}function r(t,e,r){var o=e.getAxis(t),a=o.model,s=function(t,e,n){var i;return n.eachComponent({mainType:"dataZoom",subType:"select"},(function(n){n.getAxisModel(t,e.componentIndex)&&(i=n)})),i}(t,a,i),l=s.findRepresentativeAxisProxy(a).getMinMaxSpan();null==l.minValueSpan&&null==l.maxValueSpan||(r=zk(0,r.slice(),o.scale.getExtent(),0,l.minValueSpan,l.maxValueSpan)),s&&(n[s.id]={dataZoomId:s.id,startValue:r[0],endValue:r[1]})}},e.prototype._dispatchZoomAction=function(t){var e=[];iV(t,(function(t,n){e.push(T(t))})),e.length&&this.api.dispatchAction({type:"dataZoom",from:this.uid,batch:e})},e.getDefaultOption=function(t){return{show:!0,filterMode:"filter",icon:{zoom:"M0,13.5h26.9 M13.5,26.9V0 M32.1,13.5H58V58H13.5 V32.1",back:"M22,1.4L9.9,13.5l12.3,12.3 M10.3,13.5H54.9v44.6 H10.3v-26"},title:t.getLocaleModel().get(["toolbox","dataZoom","title"]),brushStyle:{borderWidth:0,color:"rgba(210,219,238,0.2)"}}},e}(_z),aV={zoom:function(){var t=!this._isZoomActive;this.api.dispatchAction({type:"takeGlobalCursor",key:"dataZoomSelect",dataZoomSelectActive:t})},back:function(){this._dispatchZoomAction(function(t){var e=Gz(t),n=e[e.length-1];e.length>1&&e.pop();var i={};return Bz(n,(function(t,n){for(var r=e.length-1;r>=0;r--)if(t=e[r][n]){i[n]=t;break}})),i}(this.ecModel))}};function sV(t){var e={xAxisIndex:t.get("xAxisIndex",!0),yAxisIndex:t.get("yAxisIndex",!0),xAxisId:t.get("xAxisId",!0),yAxisId:t.get("yAxisId",!0)};return null==e.xAxisIndex&&null==e.xAxisId&&(e.xAxisIndex="all"),null==e.yAxisIndex&&null==e.yAxisId&&(e.yAxisIndex="all"),e}eV="dataZoom",nV=function(t){var e=t.getComponent("toolbox",0),n=["feature","dataZoom"];if(e&&null!=e.get(n)){var i=e.getModel(n),r=[],o=Fo(t,sV(i));return iV(o.xAxisModels,(function(t){return a(t,"xAxis","xAxisIndex")})),iV(o.yAxisModels,(function(t){return a(t,"yAxis","yAxisIndex")})),r}function a(t,e,n){var o=t.componentIndex,a={type:"select",$fromToolbox:!0,filterMode:i.get("filterMode",!0)||"filter",id:rV+e+o};a[n]=o,r.push(a)}},lt(null==od.get(eV)&&nV),od.set(eV,nV);var lV=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="tooltip",e.dependencies=["axisPointer"],e.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}},e}(zp);function uV(t){var e=t.get("confine");return null!=e?!!e:"richText"===t.get("renderMode")}function hV(t){if(r.domSupported)for(var e=document.documentElement.style,n=0,i=t.length;n-1?(u+="top:50%",h+="translateY(-50%) rotate("+(a="left"===s?-225:-45)+"deg)"):(u+="left:50%",h+="translateX(-50%) rotate("+(a="top"===s?225:45)+"deg)");var c=a*Math.PI/180,p=l+r,d=p*Math.abs(Math.cos(c))+p*Math.abs(Math.sin(c)),f=e+" solid "+r+"px;";return'
'}(n,i,r)),U(t))o.innerHTML=t+a;else if(t){o.innerHTML="",Y(t)||(t=[t]);for(var s=0;s=0?this._tryShow(n,i):"leave"===e&&this._hide(i))}),this))},e.prototype._keepShow=function(){var t=this._tooltipModel,e=this._ecModel,n=this._api,i=t.get("triggerOn");if(null!=this._lastX&&null!=this._lastY&&"none"!==i&&"click"!==i){var r=this;clearTimeout(this._refreshUpdateTimeout),this._refreshUpdateTimeout=setTimeout((function(){!n.isDisposed()&&r.manuallyShowTip(t,e,n,{x:r._lastX,y:r._lastY,dataByCoordSys:r._lastDataByCoordSys})}))}},e.prototype.manuallyShowTip=function(t,e,n,i){if(i.from!==this.uid&&!r.node&&n.getDom()){var o=CV(i,n);this._ticket="";var a=i.dataByCoordSys,s=function(t,e,n){var i=Go(t).queryOptionMap,r=i.keys()[0];if(!r||"series"===r)return;var o=Yo(e,r,i.get(r),{useDefault:!1,enableAll:!1,enableNone:!1}),a=o.models[0];if(!a)return;var s,l=n.getViewOfComponentModel(a);if(l.group.traverse((function(e){var n=rl(e).tooltipConfig;if(n&&n.name===t.name)return s=e,!0})),s)return{componentMainType:r,componentIndex:a.componentIndex,el:s}}(i,e,n);if(s){var l=s.el.getBoundingRect().clone();l.applyTransform(s.el.transform),this._tryShow({offsetX:l.x+l.width/2,offsetY:l.y+l.height/2,target:s.el,position:i.position,positionDefault:"bottom"},o)}else if(i.tooltip&&null!=i.x&&null!=i.y){var u=MV;u.x=i.x,u.y=i.y,u.update(),rl(u).tooltipConfig={name:null,option:i.tooltip},this._tryShow({offsetX:i.x,offsetY:i.y,target:u},o)}else if(a)this._tryShow({offsetX:i.x,offsetY:i.y,position:i.position,dataByCoordSys:a,tooltipOption:i.tooltipOption},o);else if(null!=i.seriesIndex){if(this._manuallyAxisShowTip(t,e,n,i))return;var h=RN(i,e),c=h.point[0],p=h.point[1];null!=c&&null!=p&&this._tryShow({offsetX:c,offsetY:p,target:h.el,position:i.position,positionDefault:"bottom"},o)}else null!=i.x&&null!=i.y&&(n.dispatchAction({type:"updateAxisPointer",x:i.x,y:i.y}),this._tryShow({offsetX:i.x,offsetY:i.y,position:i.position,target:n.getZr().findHover(i.x,i.y).target},o))}},e.prototype.manuallyHideTip=function(t,e,n,i){var r=this._tooltipContent;this._tooltipModel&&r.hideLater(this._tooltipModel.get("hideDelay")),this._lastX=this._lastY=this._lastDataByCoordSys=null,i.from!==this.uid&&this._hide(CV(i,n))},e.prototype._manuallyAxisShowTip=function(t,e,n,i){var r=i.seriesIndex,o=i.dataIndex,a=e.getComponent("axisPointer").coordSysAxesInfo;if(null!=r&&null!=o&&null!=a){var s=e.getSeriesByIndex(r);if(s)if("axis"===TV([s.getData().getItemModel(o),s,(s.coordinateSystem||{}).model],this._tooltipModel).get("trigger"))return n.dispatchAction({type:"updateAxisPointer",seriesIndex:r,dataIndex:o,position:i.position}),!0}},e.prototype._tryShow=function(t,e){var n=t.target;if(this._tooltipModel){this._lastX=t.offsetX,this._lastY=t.offsetY;var i=t.dataByCoordSys;if(i&&i.length)this._showAxisTooltip(i,t);else if(n){var r,o;if("legend"===rl(n).ssrType)return;this._lastDataByCoordSys=null,Oy(n,(function(t){return null!=rl(t).dataIndex?(r=t,!0):null!=rl(t).tooltipConfig?(o=t,!0):void 0}),!0),r?this._showSeriesItemTooltip(t,r,e):o?this._showComponentItemTooltip(t,o,e):this._hide(e)}else this._lastDataByCoordSys=null,this._hide(e)}},e.prototype._showOrMove=function(t,e){var n=t.get("showDelay");e=W(e,this),clearTimeout(this._showTimout),n>0?this._showTimout=setTimeout(e,n):e()},e.prototype._showAxisTooltip=function(t,e){var n=this._ecModel,i=this._tooltipModel,r=[e.offsetX,e.offsetY],o=TV([e.tooltipOption],i),a=this._renderMode,s=[],l=og("section",{blocks:[],noHeader:!0}),u=[],h=new yg;E(t,(function(t){E(t.dataByAxis,(function(t){var e=n.getComponent(t.axisDim+"Axis",t.axisIndex),r=t.value;if(e&&null!=r){var o=yN(r,e.axis,n,t.seriesDataIndices,t.valueLabelOpt),c=og("section",{header:o,noHeader:!ut(o),sortBlocks:!0,blocks:[]});l.blocks.push(c),E(t.seriesDataIndices,(function(l){var p=n.getSeriesByIndex(l.seriesIndex),d=l.dataIndexInside,f=p.getDataParams(d);if(!(f.dataIndex<0)){f.axisDim=t.axisDim,f.axisIndex=t.axisIndex,f.axisType=t.axisType,f.axisId=t.axisId,f.axisValue=S_(e.axis,{value:r}),f.axisValueLabel=o,f.marker=h.makeTooltipMarker("item",Sp(f.color),a);var g=bf(p.formatTooltip(d,!0,null)),y=g.frag;if(y){var v=TV([p],i).get("valueFormatter");c.blocks.push(v?A({valueFormatter:v},y):y)}g.text&&u.push(g.text),s.push(f)}}))}}))})),l.blocks.reverse(),u.reverse();var c=e.position,p=o.get("order"),d=cg(l,h,a,p,n.get("useUTC"),o.get("textStyle"));d&&u.unshift(d);var f="richText"===a?"\n\n":"
",g=u.join(f);this._showOrMove(o,(function(){this._updateContentNotChangedOnAxis(t,s)?this._updatePosition(o,c,r[0],r[1],this._tooltipContent,s):this._showTooltipContent(o,g,s,Math.random()+"",r[0],r[1],c,null,h)}))},e.prototype._showSeriesItemTooltip=function(t,e,n){var i=this._ecModel,r=rl(e),o=r.seriesIndex,a=i.getSeriesByIndex(o),s=r.dataModel||a,l=r.dataIndex,u=r.dataType,h=s.getData(u),c=this._renderMode,p=t.positionDefault,d=TV([h.getItemModel(l),s,a&&(a.coordinateSystem||{}).model],this._tooltipModel,p?{position:p}:null),f=d.get("trigger");if(null==f||"item"===f){var g=s.getDataParams(l,u),y=new yg;g.marker=y.makeTooltipMarker("item",Sp(g.color),c);var v=bf(s.formatTooltip(l,!1,u)),m=d.get("order"),x=d.get("valueFormatter"),_=v.frag,b=_?cg(x?A({valueFormatter:x},_):_,y,c,m,i.get("useUTC"),d.get("textStyle")):v.text,w="item_"+s.name+"_"+l;this._showOrMove(d,(function(){this._showTooltipContent(d,b,g,w,t.offsetX,t.offsetY,t.position,t.target,y)})),n({type:"showTip",dataIndexInside:l,dataIndex:h.getRawIndex(l),seriesIndex:o,from:this.uid})}},e.prototype._showComponentItemTooltip=function(t,e,n){var i="html"===this._renderMode,r=rl(e),o=r.tooltipConfig.option||{},a=o.encodeHTMLContent;if(U(o)){o={content:o,formatter:o},a=!0}a&&i&&o.content&&((o=T(o)).content=re(o.content));var s=[o],l=this._ecModel.getComponent(r.componentMainType,r.componentIndex);l&&s.push(l),s.push({formatter:o.content});var u=t.positionDefault,h=TV(s,this._tooltipModel,u?{position:u}:null),c=h.get("content"),p=Math.random()+"",d=new yg;this._showOrMove(h,(function(){var n=T(h.get("formatterParams")||{});this._showTooltipContent(h,c,n,p,t.offsetX,t.offsetY,t.position,e,d)})),n({type:"showTip",from:this.uid})},e.prototype._showTooltipContent=function(t,e,n,i,r,o,a,s,l){if(this._ticket="",t.get("showContent")&&t.get("show")){var u=this._tooltipContent;u.setEnterable(t.get("enterable"));var h=t.get("formatter");a=a||t.get("position");var c=e,p=this._getNearestPoint([r,o],n,t.get("trigger"),t.get("borderColor")).color;if(h)if(U(h)){var d=t.ecModel.get("useUTC"),f=Y(n)?n[0]:n;c=h,f&&f.axisType&&f.axisType.indexOf("time")>=0&&(c=Jc(f.axisValue,c,d)),c=bp(c,n,!0)}else if(X(h)){var g=W((function(e,i){e===this._ticket&&(u.setContent(i,l,t,p,a),this._updatePosition(t,a,r,o,u,n,s))}),this);this._ticket=i,c=h(n,i,g)}else c=h;u.setContent(c,l,t,p,a),u.show(t,p),this._updatePosition(t,a,r,o,u,n,s)}},e.prototype._getNearestPoint=function(t,e,n,i){return"axis"===n||Y(e)?{color:i||("html"===this._renderMode?"#fff":"none")}:Y(e)?void 0:{color:i||e.color||e.borderColor}},e.prototype._updatePosition=function(t,e,n,i,r,o,a){var s=this._api.getWidth(),l=this._api.getHeight();e=e||t.get("position");var u=r.getSize(),h=t.get("align"),c=t.get("verticalAlign"),p=a&&a.getBoundingRect().clone();if(a&&p.applyTransform(a.transform),X(e)&&(e=e([n,i],o,r.el,p,{viewSize:[s,l],contentSize:u.slice()})),Y(e))n=$r(e[0],s),i=$r(e[1],l);else if(q(e)){var d=e;d.width=u[0],d.height=u[1];var f=kp(d,{width:s,height:l});n=f.x,i=f.y,h=null,c=null}else if(U(e)&&a){var g=function(t,e,n,i){var r=n[0],o=n[1],a=Math.ceil(Math.SQRT2*i)+8,s=0,l=0,u=e.width,h=e.height;switch(t){case"inside":s=e.x+u/2-r/2,l=e.y+h/2-o/2;break;case"top":s=e.x+u/2-r/2,l=e.y-o-a;break;case"bottom":s=e.x+u/2-r/2,l=e.y+h+a;break;case"left":s=e.x-r-a,l=e.y+h/2-o/2;break;case"right":s=e.x+u+a,l=e.y+h/2-o/2}return[s,l]}(e,p,u,t.get("borderWidth"));n=g[0],i=g[1]}else{g=function(t,e,n,i,r,o,a){var s=n.getSize(),l=s[0],u=s[1];null!=o&&(t+l+o+2>i?t-=l+o:t+=o);null!=a&&(e+u+a>r?e-=u+a:e+=a);return[t,e]}(n,i,r,s,l,h?null:20,c?null:20);n=g[0],i=g[1]}if(h&&(n-=DV(h)?u[0]/2:"right"===h?u[0]:0),c&&(i-=DV(c)?u[1]/2:"bottom"===c?u[1]:0),uV(t)){g=function(t,e,n,i,r){var o=n.getSize(),a=o[0],s=o[1];return t=Math.min(t+a,i)-a,e=Math.min(e+s,r)-s,t=Math.max(t,0),e=Math.max(e,0),[t,e]}(n,i,r,s,l);n=g[0],i=g[1]}r.moveTo(n,i)},e.prototype._updateContentNotChangedOnAxis=function(t,e){var n=this._lastDataByCoordSys,i=this._cbParamsList,r=!!n&&n.length===t.length;return r&&E(n,(function(n,o){var a=n.dataByAxis||[],s=(t[o]||{}).dataByAxis||[];(r=r&&a.length===s.length)&&E(a,(function(t,n){var o=s[n]||{},a=t.seriesDataIndices||[],l=o.seriesDataIndices||[];(r=r&&t.value===o.value&&t.axisType===o.axisType&&t.axisId===o.axisId&&a.length===l.length)&&E(a,(function(t,e){var n=l[e];r=r&&t.seriesIndex===n.seriesIndex&&t.dataIndex===n.dataIndex})),i&&E(t.seriesDataIndices,(function(t){var n=t.seriesIndex,o=e[n],a=i[n];o&&a&&a.data!==o.data&&(r=!1)}))}))})),this._lastDataByCoordSys=t,this._cbParamsList=e,!!r},e.prototype._hide=function(t){this._lastDataByCoordSys=null,t({type:"hideTip",from:this.uid})},e.prototype.dispose=function(t,e){!r.node&&e.getDom()&&(Yg(this,"_updatePosition"),this._tooltipContent.dispose(),PN("itemTooltip",e))},e.type="tooltip",e}(Ag);function TV(t,e,n){var i,r=e.ecModel;n?(i=new Cc(n,r,r),i=new Cc(e.option,i,r)):i=e;for(var o=t.length-1;o>=0;o--){var a=t[o];a&&(a instanceof Cc&&(a=a.get("tooltip",!0)),U(a)&&(a={formatter:a}),a&&(i=new Cc(a,i,r)))}return i}function CV(t,e){return t.dispatchAction||W(e.dispatchAction,e)}function DV(t){return"center"===t||"middle"===t}var AV=["rect","polygon","keep","clear"];function kV(t,e){var n=To(t?t.brush:[]);if(n.length){var i=[];E(n,(function(t){var e=t.hasOwnProperty("toolbox")?t.toolbox:[];e instanceof Array&&(i=i.concat(e))}));var r=t&&t.toolbox;Y(r)&&(r=r[0]),r||(r={feature:{}},t.toolbox=[r]);var o=r.feature||(r.feature={}),a=o.brush||(o.brush={}),s=a.type||(a.type=[]);s.push.apply(s,i),function(t){var e={};E(t,(function(t){e[t]=1})),t.length=0,E(e,(function(e,n){t.push(n)}))}(s),e&&!s.length&&s.push.apply(s,AV)}}var LV=E;function PV(t){if(t)for(var e in t)if(t.hasOwnProperty(e))return!0}function OV(t,e,n){var i={};return LV(e,(function(e){var r,o=i[e]=((r=function(){}).prototype.__hidden=r.prototype,new r);LV(t[e],(function(t,i){if(kD.isValidType(i)){var r={type:i,visual:t};n&&n(r,e),o[i]=new kD(r),"opacity"===i&&((r=T(r)).type="colorAlpha",o.__hidden.__alphaForOpacity=new kD(r))}}))})),i}function RV(t,e,n){var i;E(n,(function(t){e.hasOwnProperty(t)&&PV(e[t])&&(i=!0)})),i&&E(n,(function(n){e.hasOwnProperty(n)&&PV(e[n])?t[n]=T(e[n]):delete t[n]}))}var NV={lineX:EV(0),lineY:EV(1),rect:{point:function(t,e,n){return t&&n.boundingRect.contain(t[0],t[1])},rect:function(t,e,n){return t&&n.boundingRect.intersect(t)}},polygon:{point:function(t,e,n){return t&&n.boundingRect.contain(t[0],t[1])&&P_(n.range,t[0],t[1])},rect:function(t,e,n){var i=n.range;if(!t||i.length<=1)return!1;var r=t.x,o=t.y,a=t.width,s=t.height,l=i[0];return!!(P_(i,r,o)||P_(i,r+a,o)||P_(i,r,o+s)||P_(i,r+a,o+s)||ze.create(t).contain(l[0],l[1])||Zh(r,o,r+a,o,i)||Zh(r,o,r,o+s,i)||Zh(r+a,o,r+a,o+s,i)||Zh(r,o+s,r+a,o+s,i))||void 0}}};function EV(t){var e=["x","y"],n=["width","height"];return{point:function(e,n,i){if(e){var r=i.range;return zV(e[t],r)}},rect:function(i,r,o){if(i){var a=o.range,s=[i[e[t]],i[e[t]]+i[n[t]]];return s[1]e[0][1]&&(e[0][1]=o[0]),o[1]e[1][1]&&(e[1][1]=o[1])}return e&&UV(e)}};function UV(t){return new ze(t[0][0],t[1][0],t[0][1]-t[0][0],t[1][1]-t[1][0])}var ZV=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(t,e){this.ecModel=t,this.api=e,this.model,(this._brushController=new lL(e.getZr())).on("brush",W(this._onBrush,this)).mount()},e.prototype.render=function(t,e,n,i){this.model=t,this._updateController(t,e,n,i)},e.prototype.updateTransform=function(t,e,n,i){GV(e),this._updateController(t,e,n,i)},e.prototype.updateVisual=function(t,e,n,i){this.updateTransform(t,e,n,i)},e.prototype.updateView=function(t,e,n,i){this._updateController(t,e,n,i)},e.prototype._updateController=function(t,e,n,i){(!i||i.$from!==t.id)&&this._brushController.setPanels(t.brushTargetManager.makePanelOpts(n)).enableBrush(t.brushOption).updateCovers(t.areas.slice())},e.prototype.dispose=function(){this._brushController.dispose()},e.prototype._onBrush=function(t){var e=this.model.id,n=this.model.brushTargetManager.setOutputRanges(t.areas,this.ecModel);(!t.isEnd||t.removeOnClick)&&this.api.dispatchAction({type:"brush",brushId:e,areas:T(n),$from:e}),t.isEnd&&this.api.dispatchAction({type:"brushEnd",brushId:e,areas:T(n),$from:e})},e.type="brush",e}(Ag),jV=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.areas=[],n.brushOption={},n}return n(e,t),e.prototype.optionUpdated=function(t,e){var n=this.option;!e&&RV(n,t,["inBrush","outOfBrush"]);var i=n.inBrush=n.inBrush||{};n.outOfBrush=n.outOfBrush||{color:"#ddd"},i.hasOwnProperty("liftZ")||(i.liftZ=5)},e.prototype.setAreas=function(t){t&&(this.areas=z(t,(function(t){return qV(this.option,t)}),this))},e.prototype.setBrushOption=function(t){this.brushOption=qV(this.option,t),this.brushType=this.brushOption.brushType},e.type="brush",e.dependencies=["geo","grid","xAxis","yAxis","parallel","series"],e.defaultOption={seriesIndex:"all",brushType:"rect",brushMode:"single",transformable:!0,brushStyle:{borderWidth:1,color:"rgba(210,219,238,0.3)",borderColor:"#D2DBEE"},throttleType:"fixRate",throttleDelay:0,removeOnClick:!0,z:1e4},e}(zp);function qV(t,e){return C({brushType:t.brushType,brushMode:t.brushMode,transformable:t.transformable,brushStyle:new Cc(t.brushStyle).getItemStyle(),removeOnClick:t.removeOnClick,z:t.z},e,!0)}var KV=["rect","polygon","lineX","lineY","keep","clear"],$V=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return n(e,t),e.prototype.render=function(t,e,n){var i,r,o;e.eachComponent({mainType:"brush"},(function(t){i=t.brushType,r=t.brushOption.brushMode||"single",o=o||!!t.areas.length})),this._brushType=i,this._brushMode=r,E(t.get("type",!0),(function(e){t.setIconStatus(e,("keep"===e?"multiple"===r:"clear"===e?o:e===i)?"emphasis":"normal")}))},e.prototype.updateView=function(t,e,n){this.render(t,e,n)},e.prototype.getIcons=function(){var t=this.model,e=t.get("icon",!0),n={};return E(t.get("type",!0),(function(t){e[t]&&(n[t]=e[t])})),n},e.prototype.onclick=function(t,e,n){var i=this._brushType,r=this._brushMode;"clear"===n?(e.dispatchAction({type:"axisAreaSelect",intervals:[]}),e.dispatchAction({type:"brush",command:"clear",areas:[]})):e.dispatchAction({type:"takeGlobalCursor",key:"brush",brushOption:{brushType:"keep"===n?i:i!==n&&n,brushMode:"keep"===n?"multiple"===r?"single":"multiple":r}})},e.getDefaultOption=function(t){return{show:!0,type:KV.slice(),icon:{rect:"M7.3,34.7 M0.4,10V-0.2h9.8 M89.6,10V-0.2h-9.8 M0.4,60v10.2h9.8 M89.6,60v10.2h-9.8 M12.3,22.4V10.5h13.1 M33.6,10.5h7.8 M49.1,10.5h7.8 M77.5,22.4V10.5h-13 M12.3,31.1v8.2 M77.7,31.1v8.2 M12.3,47.6v11.9h13.1 M33.6,59.5h7.6 M49.1,59.5 h7.7 M77.5,47.6v11.9h-13",polygon:"M55.2,34.9c1.7,0,3.1,1.4,3.1,3.1s-1.4,3.1-3.1,3.1 s-3.1-1.4-3.1-3.1S53.5,34.9,55.2,34.9z M50.4,51c1.7,0,3.1,1.4,3.1,3.1c0,1.7-1.4,3.1-3.1,3.1c-1.7,0-3.1-1.4-3.1-3.1 C47.3,52.4,48.7,51,50.4,51z M55.6,37.1l1.5-7.8 M60.1,13.5l1.6-8.7l-7.8,4 M59,19l-1,5.3 M24,16.1l6.4,4.9l6.4-3.3 M48.5,11.6 l-5.9,3.1 M19.1,12.8L9.7,5.1l1.1,7.7 M13.4,29.8l1,7.3l6.6,1.6 M11.6,18.4l1,6.1 M32.8,41.9 M26.6,40.4 M27.3,40.2l6.1,1.6 M49.9,52.1l-5.6-7.6l-4.9-1.2",lineX:"M15.2,30 M19.7,15.6V1.9H29 M34.8,1.9H40.4 M55.3,15.6V1.9H45.9 M19.7,44.4V58.1H29 M34.8,58.1H40.4 M55.3,44.4 V58.1H45.9 M12.5,20.3l-9.4,9.6l9.6,9.8 M3.1,29.9h16.5 M62.5,20.3l9.4,9.6L62.3,39.7 M71.9,29.9H55.4",lineY:"M38.8,7.7 M52.7,12h13.2v9 M65.9,26.6V32 M52.7,46.3h13.2v-9 M24.9,12H11.8v9 M11.8,26.6V32 M24.9,46.3H11.8v-9 M48.2,5.1l-9.3-9l-9.4,9.2 M38.9-3.9V12 M48.2,53.3l-9.3,9l-9.4-9.2 M38.9,62.3V46.4",keep:"M4,10.5V1h10.3 M20.7,1h6.1 M33,1h6.1 M55.4,10.5V1H45.2 M4,17.3v6.6 M55.6,17.3v6.6 M4,30.5V40h10.3 M20.7,40 h6.1 M33,40h6.1 M55.4,30.5V40H45.2 M21,18.9h62.9v48.6H21V18.9z",clear:"M22,14.7l30.9,31 M52.9,14.7L22,45.7 M4.7,16.8V4.2h13.1 M26,4.2h7.8 M41.6,4.2h7.8 M70.3,16.8V4.2H57.2 M4.7,25.9v8.6 M70.3,25.9v8.6 M4.7,43.2v12.6h13.1 M26,55.8h7.8 M41.6,55.8h7.8 M70.3,43.2v12.6H57.2"},title:t.getLocaleModel().get(["toolbox","brush","title"])}},e}(_z);var JV=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.layoutMode={type:"box",ignoreSize:!0},n}return n(e,t),e.type="title",e.defaultOption={z:6,show:!0,text:"",target:"blank",subtext:"",subtarget:"blank",left:0,top:0,backgroundColor:"rgba(0,0,0,0)",borderColor:"#ccc",borderWidth:0,padding:5,itemGap:10,textStyle:{fontSize:18,fontWeight:"bold",color:"#464646"},subtextStyle:{fontSize:12,color:"#6E7079"}},e}(zp),QV=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.render=function(t,e,n){if(this.group.removeAll(),t.get("show")){var i=this.group,r=t.getModel("textStyle"),o=t.getModel("subtextStyle"),a=t.get("textAlign"),s=rt(t.get("textBaseline"),t.get("textVerticalAlign")),l=new Xs({style:oc(r,{text:t.get("text"),fill:r.getTextColor()},{disableBox:!0}),z2:10}),u=l.getBoundingRect(),h=t.get("subtext"),c=new Xs({style:oc(o,{text:h,fill:o.getTextColor(),y:u.height+t.get("itemGap"),verticalAlign:"top"},{disableBox:!0}),z2:10}),p=t.get("link"),d=t.get("sublink"),f=t.get("triggerEvent",!0);l.silent=!p&&!f,c.silent=!d&&!f,p&&l.on("click",(function(){Mp(p,"_"+t.get("target"))})),d&&c.on("click",(function(){Mp(d,"_"+t.get("subtarget"))})),rl(l).eventData=rl(c).eventData=f?{componentType:"title",componentIndex:t.componentIndex}:null,i.add(l),h&&i.add(c);var g=i.getBoundingRect(),y=t.getBoxLayoutParams();y.width=g.width,y.height=g.height;var v=kp(y,{width:n.getWidth(),height:n.getHeight()},t.get("padding"));a||("middle"===(a=t.get("left")||t.get("right"))&&(a="center"),"right"===a?v.x+=v.width:"center"===a&&(v.x+=v.width/2)),s||("center"===(s=t.get("top")||t.get("bottom"))&&(s="middle"),"bottom"===s?v.y+=v.height:"middle"===s&&(v.y+=v.height/2),s=s||"top"),i.x=v.x,i.y=v.y,i.markRedraw();var m={align:a,verticalAlign:s};l.setStyle(m),c.setStyle(m),g=i.getBoundingRect();var x=v.margin,_=t.getItemStyle(["color","opacity"]);_.fill=t.get("backgroundColor");var b=new Ws({shape:{x:g.x-x[3],y:g.y-x[0],width:g.width+x[1]+x[3],height:g.height+x[0]+x[2],r:t.get("borderRadius")},style:_,subPixelOptimize:!0,silent:!0});i.add(b)}},e.type="title",e}(Ag);var tB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.layoutMode="box",n}return n(e,t),e.prototype.init=function(t,e,n){this.mergeDefaultAndTheme(t,n),this._initData()},e.prototype.mergeOption=function(e){t.prototype.mergeOption.apply(this,arguments),this._initData()},e.prototype.setCurrentIndex=function(t){null==t&&(t=this.option.currentIndex);var e=this._data.count();this.option.loop?t=(t%e+e)%e:(t>=e&&(t=e-1),t<0&&(t=0)),this.option.currentIndex=t},e.prototype.getCurrentIndex=function(){return this.option.currentIndex},e.prototype.isIndexMax=function(){return this.getCurrentIndex()>=this._data.count()-1},e.prototype.setPlayState=function(t){this.option.autoPlay=!!t},e.prototype.getPlayState=function(){return!!this.option.autoPlay},e.prototype._initData=function(){var t,e=this.option,n=e.data||[],i=e.axisType,r=this._names=[];"category"===i?(t=[],E(n,(function(e,n){var i,o=Ro(Ao(e),"");q(e)?(i=T(e)).value=n:i=n,t.push(i),r.push(o)}))):t=n;var o={category:"ordinal",time:"time",value:"number"}[i]||"number";(this._data=new cx([{name:"value",type:o}],this)).initData(t,r)},e.prototype.getData=function(){return this._data},e.prototype.getCategories=function(){if("category"===this.get("axisType"))return this._names.slice()},e.type="timeline",e.defaultOption={z:4,show:!0,axisType:"time",realtime:!0,left:"20%",top:null,right:"20%",bottom:0,width:null,height:40,padding:5,controlPosition:"left",autoPlay:!1,rewind:!1,loop:!0,playInterval:2e3,currentIndex:0,itemStyle:{},label:{color:"#000"},data:[]},e}(zp),eB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="timeline.slider",e.defaultOption=kc(tB.defaultOption,{backgroundColor:"rgba(0,0,0,0)",borderColor:"#ccc",borderWidth:0,orient:"horizontal",inverse:!1,tooltip:{trigger:"item"},symbol:"circle",symbolSize:12,lineStyle:{show:!0,width:2,color:"#DAE1F5"},label:{position:"auto",show:!0,interval:"auto",rotate:0,color:"#A4B1D7"},itemStyle:{color:"#A4B1D7",borderWidth:1},checkpointStyle:{symbol:"circle",symbolSize:15,color:"#316bf3",borderColor:"#fff",borderWidth:2,shadowBlur:2,shadowOffsetX:1,shadowOffsetY:1,shadowColor:"rgba(0, 0, 0, 0.3)",animation:!0,animationDuration:300,animationEasing:"quinticInOut"},controlStyle:{show:!0,showPlayBtn:!0,showPrevBtn:!0,showNextBtn:!0,itemSize:24,itemGap:12,position:"left",playIcon:"path://M31.6,53C17.5,53,6,41.5,6,27.4S17.5,1.8,31.6,1.8C45.7,1.8,57.2,13.3,57.2,27.4S45.7,53,31.6,53z M31.6,3.3 C18.4,3.3,7.5,14.1,7.5,27.4c0,13.3,10.8,24.1,24.1,24.1C44.9,51.5,55.7,40.7,55.7,27.4C55.7,14.1,44.9,3.3,31.6,3.3z M24.9,21.3 c0-2.2,1.6-3.1,3.5-2l10.5,6.1c1.899,1.1,1.899,2.9,0,4l-10.5,6.1c-1.9,1.1-3.5,0.2-3.5-2V21.3z",stopIcon:"path://M30.9,53.2C16.8,53.2,5.3,41.7,5.3,27.6S16.8,2,30.9,2C45,2,56.4,13.5,56.4,27.6S45,53.2,30.9,53.2z M30.9,3.5C17.6,3.5,6.8,14.4,6.8,27.6c0,13.3,10.8,24.1,24.101,24.1C44.2,51.7,55,40.9,55,27.6C54.9,14.4,44.1,3.5,30.9,3.5z M36.9,35.8c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H36c0.5,0,0.9,0.4,0.9,1V35.8z M27.8,35.8 c0,0.601-0.4,1-0.9,1h-1.3c-0.5,0-0.9-0.399-0.9-1V19.5c0-0.6,0.4-1,0.9-1H27c0.5,0,0.9,0.4,0.9,1L27.8,35.8L27.8,35.8z",nextIcon:"M2,18.5A1.52,1.52,0,0,1,.92,18a1.49,1.49,0,0,1,0-2.12L7.81,9.36,1,3.11A1.5,1.5,0,1,1,3,.89l8,7.34a1.48,1.48,0,0,1,.49,1.09,1.51,1.51,0,0,1-.46,1.1L3,18.08A1.5,1.5,0,0,1,2,18.5Z",prevIcon:"M10,.5A1.52,1.52,0,0,1,11.08,1a1.49,1.49,0,0,1,0,2.12L4.19,9.64,11,15.89a1.5,1.5,0,1,1-2,2.22L1,10.77A1.48,1.48,0,0,1,.5,9.68,1.51,1.51,0,0,1,1,8.58L9,.92A1.5,1.5,0,0,1,10,.5Z",prevBtnSize:18,nextBtnSize:18,color:"#A4B1D7",borderColor:"#A4B1D7",borderWidth:1},emphasis:{label:{show:!0,color:"#6f778d"},itemStyle:{color:"#316BF3"},controlStyle:{color:"#316BF3",borderColor:"#316BF3",borderWidth:2}},progress:{lineStyle:{color:"#316BF3"},itemStyle:{color:"#316BF3"},label:{color:"#6f778d"}},data:[]}),e}(tB);R(eB,_f.prototype);var nB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="timeline",e}(Ag),iB=function(t){function e(e,n,i,r){var o=t.call(this,e,n,i)||this;return o.type=r||"value",o}return n(e,t),e.prototype.getLabelModel=function(){return this.model.getModel("label")},e.prototype.isHorizontal=function(){return"horizontal"===this.model.get("orient")},e}(ab),rB=Math.PI,oB=Vo(),aB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(t,e){this.api=e},e.prototype.render=function(t,e,n){if(this.model=t,this.api=n,this.ecModel=e,this.group.removeAll(),t.get("show",!0)){var i=this._layout(t,n),r=this._createGroup("_mainGroup"),o=this._createGroup("_labelGroup"),a=this._axis=this._createAxis(i,t);t.formatTooltip=function(t){return og("nameValue",{noName:!0,value:a.scale.getLabel({value:t})})},E(["AxisLine","AxisTick","Control","CurrentPointer"],(function(e){this["_render"+e](i,r,a,t)}),this),this._renderAxisLabel(i,o,a,t),this._position(i,t)}this._doPlayStop(),this._updateTicksStatus()},e.prototype.remove=function(){this._clearTimer(),this.group.removeAll()},e.prototype.dispose=function(){this._clearTimer()},e.prototype._layout=function(t,e){var n,i,r,o,a=t.get(["label","position"]),s=t.get("orient"),l=function(t,e){return kp(t.getBoxLayoutParams(),{width:e.getWidth(),height:e.getHeight()},t.get("padding"))}(t,e),u={horizontal:"center",vertical:(n=null==a||"auto"===a?"horizontal"===s?l.y+l.height/2=0||"+"===n?"left":"right"},h={horizontal:n>=0||"+"===n?"top":"bottom",vertical:"middle"},c={horizontal:0,vertical:rB/2},p="vertical"===s?l.height:l.width,d=t.getModel("controlStyle"),f=d.get("show",!0),g=f?d.get("itemSize"):0,y=f?d.get("itemGap"):0,v=g+y,m=t.get(["label","rotate"])||0;m=m*rB/180;var x=d.get("position",!0),_=f&&d.get("showPlayBtn",!0),b=f&&d.get("showPrevBtn",!0),w=f&&d.get("showNextBtn",!0),S=0,M=p;"left"===x||"bottom"===x?(_&&(i=[0,0],S+=v),b&&(r=[S,0],S+=v),w&&(o=[M-g,0],M-=v)):(_&&(i=[M-g,0],M-=v),b&&(r=[0,0],S+=v),w&&(o=[M-g,0],M-=v));var I=[S,M];return t.get("inverse")&&I.reverse(),{viewRect:l,mainLength:p,orient:s,rotation:c[s],labelRotation:m,labelPosOpt:n,labelAlign:t.get(["label","align"])||u[s],labelBaseline:t.get(["label","verticalAlign"])||t.get(["label","baseline"])||h[s],playPosition:i,prevBtnPosition:r,nextBtnPosition:o,axisExtent:I,controlSize:g,controlGap:y}},e.prototype._position=function(t,e){var n=this._mainGroup,i=this._labelGroup,r=t.viewRect;if("vertical"===t.orient){var o=[1,0,0,1,0,0],a=r.x,s=r.y+r.height;we(o,o,[-a,-s]),Se(o,o,-rB/2),we(o,o,[a,s]),(r=r.clone()).applyTransform(o)}var l=y(r),u=y(n.getBoundingRect()),h=y(i.getBoundingRect()),c=[n.x,n.y],p=[i.x,i.y];p[0]=c[0]=l[0][0];var d,f=t.labelPosOpt;null==f||U(f)?(v(c,u,l,1,d="+"===f?0:1),v(p,h,l,1,1-d)):(v(c,u,l,1,d=f>=0?0:1),p[1]=c[1]+f);function g(t){t.originX=l[0][0]-t.x,t.originY=l[1][0]-t.y}function y(t){return[[t.x,t.x+t.width],[t.y,t.y+t.height]]}function v(t,e,n,i,r){t[i]+=n[i][r]-e[i][r]}n.setPosition(c),i.setPosition(p),n.rotation=i.rotation=t.rotation,g(n),g(i)},e.prototype._createAxis=function(t,e){var n=e.getData(),i=e.get("axisType"),r=function(t,e){if(e=e||t.get("type"),e)switch(e){case"category":return new Rx({ordinalMeta:t.getCategories(),extent:[1/0,-1/0]});case"time":return new Kx({locale:t.ecModel.getLocaleModel(),useUTC:t.ecModel.get("useUTC")});default:return new Ex}}(e,i);r.getTicks=function(){return n.mapArray(["value"],(function(t){return{value:t}}))};var o=n.getDataExtent("value");r.setExtent(o[0],o[1]),r.calcNiceTicks();var a=new iB("value",r,t.axisExtent,i);return a.model=e,a},e.prototype._createGroup=function(t){var e=this[t]=new Br;return this.group.add(e),e},e.prototype._renderAxisLine=function(t,e,n,i){var r=n.getExtent();if(i.get(["lineStyle","show"])){var o=new Ku({shape:{x1:r[0],y1:0,x2:r[1],y2:0},style:A({lineCap:"round"},i.getModel("lineStyle").getLineStyle()),silent:!0,z2:1});e.add(o);var a=this._progressLine=new Ku({shape:{x1:r[0],x2:this._currentPointer?this._currentPointer.x:r[0],y1:0,y2:0},style:k({lineCap:"round",lineWidth:o.style.lineWidth},i.getModel(["progress","lineStyle"]).getLineStyle()),silent:!0,z2:1});e.add(a)}},e.prototype._renderAxisTick=function(t,e,n,i){var r=this,o=i.getData(),a=n.scale.getTicks();this._tickSymbols=[],E(a,(function(t){var a=n.dataToCoord(t.value),s=o.getItemModel(t.value),l=s.getModel("itemStyle"),u=s.getModel(["emphasis","itemStyle"]),h=s.getModel(["progress","itemStyle"]),c={x:a,y:0,onclick:W(r._changeTimeline,r,t.value)},p=sB(s,l,e,c);p.ensureState("emphasis").style=u.getItemStyle(),p.ensureState("progress").style=h.getItemStyle(),Ul(p);var d=rl(p);s.get("tooltip")?(d.dataIndex=t.value,d.dataModel=i):d.dataIndex=d.dataModel=null,r._tickSymbols.push(p)}))},e.prototype._renderAxisLabel=function(t,e,n,i){var r=this;if(n.getLabelModel().get("show")){var o=i.getData(),a=n.getViewLabels();this._tickLabels=[],E(a,(function(i){var a=i.tickValue,s=o.getItemModel(a),l=s.getModel("label"),u=s.getModel(["emphasis","label"]),h=s.getModel(["progress","label"]),c=n.dataToCoord(i.tickValue),p=new Xs({x:c,y:0,rotation:t.labelRotation-t.rotation,onclick:W(r._changeTimeline,r,a),silent:!1,style:oc(l,{text:i.formattedLabel,align:t.labelAlign,verticalAlign:t.labelBaseline})});p.ensureState("emphasis").style=oc(u),p.ensureState("progress").style=oc(h),e.add(p),Ul(p),oB(p).dataIndex=a,r._tickLabels.push(p)}))}},e.prototype._renderControl=function(t,e,n,i){var r=t.controlSize,o=t.rotation,a=i.getModel("controlStyle").getItemStyle(),s=i.getModel(["emphasis","controlStyle"]).getItemStyle(),l=i.getPlayState(),u=i.get("inverse",!0);function h(t,n,l,u){if(t){var h=Cr(rt(i.get(["controlStyle",n+"BtnSize"]),r),r),c=function(t,e,n,i){var r=i.style,o=Uh(t.get(["controlStyle",e]),i||{},new ze(n[0],n[1],n[2],n[3]));r&&o.setStyle(r);return o}(i,n+"Icon",[0,-h/2,h,h],{x:t[0],y:t[1],originX:r/2,originY:0,rotation:u?-o:0,rectHover:!0,style:a,onclick:l});c.ensureState("emphasis").style=s,e.add(c),Ul(c)}}h(t.nextBtnPosition,"next",W(this._changeTimeline,this,u?"-":"+")),h(t.prevBtnPosition,"prev",W(this._changeTimeline,this,u?"+":"-")),h(t.playPosition,l?"stop":"play",W(this._handlePlayClick,this,!l),!0)},e.prototype._renderCurrentPointer=function(t,e,n,i){var r=i.getData(),o=i.getCurrentIndex(),a=r.getItemModel(o).getModel("checkpointStyle"),s=this,l={onCreate:function(t){t.draggable=!0,t.drift=W(s._handlePointerDrag,s),t.ondragend=W(s._handlePointerDragend,s),lB(t,s._progressLine,o,n,i,!0)},onUpdate:function(t){lB(t,s._progressLine,o,n,i)}};this._currentPointer=sB(a,a,this._mainGroup,{},this._currentPointer,l)},e.prototype._handlePlayClick=function(t){this._clearTimer(),this.api.dispatchAction({type:"timelinePlayChange",playState:t,from:this.uid})},e.prototype._handlePointerDrag=function(t,e,n){this._clearTimer(),this._pointerChangeTimeline([n.offsetX,n.offsetY])},e.prototype._handlePointerDragend=function(t){this._pointerChangeTimeline([t.offsetX,t.offsetY],!0)},e.prototype._pointerChangeTimeline=function(t,e){var n=this._toAxisCoord(t)[0],i=Qr(this._axis.getExtent().slice());n>i[1]&&(n=i[1]),n=0&&(a[o]=+a[o].toFixed(c)),[a,h]}var xB={min:H(mB,"min"),max:H(mB,"max"),average:H(mB,"average"),median:H(mB,"median")};function _B(t,e){if(e){var n=t.getData(),i=t.coordinateSystem,r=i&&i.dimensions;if(!function(t){return!isNaN(parseFloat(t.x))&&!isNaN(parseFloat(t.y))}(e)&&!Y(e.coord)&&Y(r)){var o=bB(e,n,i,t);if((e=T(e)).type&&xB[e.type]&&o.baseAxis&&o.valueAxis){var a=P(r,o.baseAxis.dim),s=P(r,o.valueAxis.dim),l=xB[e.type](n,o.baseDataDim,o.valueDataDim,a,s);e.coord=l[0],e.value=l[1]}else e.coord=[null!=e.xAxis?e.xAxis:e.radiusAxis,null!=e.yAxis?e.yAxis:e.angleAxis]}if(null!=e.coord&&Y(r))for(var u=e.coord,h=0;h<2;h++)xB[u[h]]&&(u[h]=MB(n,n.mapDimension(r[h]),u[h]));else e.coord=[];return e}}function bB(t,e,n,i){var r={};return null!=t.valueIndex||null!=t.valueDim?(r.valueDataDim=null!=t.valueIndex?e.getDimension(t.valueIndex):t.valueDim,r.valueAxis=n.getAxis(function(t,e){var n=t.getData().getDimensionInfo(e);return n&&n.coordDim}(i,r.valueDataDim)),r.baseAxis=n.getOtherAxis(r.valueAxis),r.baseDataDim=e.mapDimension(r.baseAxis.dim)):(r.baseAxis=i.getBaseAxis(),r.valueAxis=n.getOtherAxis(r.baseAxis),r.baseDataDim=e.mapDimension(r.baseAxis.dim),r.valueDataDim=e.mapDimension(r.valueAxis.dim)),r}function wB(t,e){return!(t&&t.containData&&e.coord&&!vB(e))||t.containData(e.coord)}function SB(t,e){return t?function(t,n,i,r){return If(r<2?t.coord&&t.coord[r]:t.value,e[r])}:function(t,n,i,r){return If(t.value,e[r])}}function MB(t,e,n){if("average"===n){var i=0,r=0;return t.each(e,(function(t,e){isNaN(t)||(i+=t,r++)})),i/r}return"median"===n?t.getMedian(e):t.getDataExtent(e)["max"===n?1:0]}var IB=Vo(),TB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.init=function(){this.markerGroupMap=yt()},e.prototype.render=function(t,e,n){var i=this,r=this.markerGroupMap;r.each((function(t){IB(t).keep=!1})),e.eachSeries((function(t){var r=gB.getMarkerModelFromSeries(t,i.type);r&&i.renderSeries(t,r,e,n)})),r.each((function(t){!IB(t).keep&&i.group.remove(t.group)}))},e.prototype.markKeep=function(t){IB(t).keep=!0},e.prototype.toggleBlurSeries=function(t,e){var n=this;E(t,(function(t){var i=gB.getMarkerModelFromSeries(t,n.type);i&&i.getData().eachItemGraphicEl((function(t){t&&(e?Nl(t):El(t))}))}))},e.type="marker",e}(Ag);function CB(t,e,n){var i=e.coordinateSystem;t.each((function(r){var o,a=t.getItemModel(r),s=$r(a.get("x"),n.getWidth()),l=$r(a.get("y"),n.getHeight());if(isNaN(s)||isNaN(l)){if(e.getMarkerPosition)o=e.getMarkerPosition(t.getValues(t.dimensions,r));else if(i){var u=t.get(i.dimensions[0],r),h=t.get(i.dimensions[1],r);o=i.dataToPoint([u,h])}}else o=[s,l];isNaN(s)||(o[0]=s),isNaN(l)||(o[1]=l),t.setItemLayout(r,o)}))}var DB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.updateTransform=function(t,e,n){e.eachSeries((function(t){var e=gB.getMarkerModelFromSeries(t,"markPoint");e&&(CB(e.getData(),t,n),this.markerGroupMap.get(t.id).updateLayout())}),this)},e.prototype.renderSeries=function(t,e,n,i){var r=t.coordinateSystem,o=t.id,a=t.getData(),s=this.markerGroupMap,l=s.get(o)||s.set(o,new xS),u=function(t,e,n){var i;i=t?z(t&&t.dimensions,(function(t){return A(A({},e.getData().getDimensionInfo(e.getData().mapDimension(t))||{}),{name:t,ordinalMeta:null})})):[{name:"value",type:"float"}];var r=new cx(i,n),o=z(n.get("data"),H(_B,e));t&&(o=B(o,H(wB,t)));var a=SB(!!t,i);return r.initData(o,null,a),r}(r,t,e);e.setData(u),CB(e.getData(),t,i),u.each((function(t){var n=u.getItemModel(t),i=n.getShallow("symbol"),r=n.getShallow("symbolSize"),o=n.getShallow("symbolRotate"),s=n.getShallow("symbolOffset"),l=n.getShallow("symbolKeepAspect");if(X(i)||X(r)||X(o)||X(s)){var h=e.getRawValue(t),c=e.getDataParams(t);X(i)&&(i=i(h,c)),X(r)&&(r=r(h,c)),X(o)&&(o=o(h,c)),X(s)&&(s=s(h,c))}var p=n.getModel("itemStyle").getItemStyle(),d=Ay(a,"color");p.fill||(p.fill=d),u.setItemVisual(t,{symbol:i,symbolSize:r,symbolRotate:o,symbolOffset:s,symbolKeepAspect:l,style:p})})),l.updateData(u),this.group.add(l.group),u.eachItemGraphicEl((function(t){t.traverse((function(t){rl(t).dataModel=e}))})),this.markKeep(l),l.group.silent=e.get("silent")||t.get("silent")},e.type="markPoint",e}(TB);var AB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.createMarkerModelFromSeries=function(t,n,i){return new e(t,n,i)},e.type="markLine",e.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"},e}(gB),kB=Vo(),LB=function(t,e,n,i){var r,o=t.getData();if(Y(i))r=i;else{var a=i.type;if("min"===a||"max"===a||"average"===a||"median"===a||null!=i.xAxis||null!=i.yAxis){var s=void 0,l=void 0;if(null!=i.yAxis||null!=i.xAxis)s=e.getAxis(null!=i.yAxis?"y":"x"),l=it(i.yAxis,i.xAxis);else{var u=bB(i,o,e,t);s=u.valueAxis,l=MB(o,xx(o,u.valueDataDim),a)}var h="x"===s.dim?0:1,c=1-h,p=T(i),d={coord:[]};p.type=null,p.coord=[],p.coord[c]=-1/0,d.coord[c]=1/0;var f=n.get("precision");f>=0&&j(l)&&(l=+l.toFixed(Math.min(f,20))),p.coord[h]=d.coord[h]=l,r=[p,d,{type:a,valueIndex:i.valueIndex,value:l}]}else r=[]}var g=[_B(t,r[0]),_B(t,r[1]),A({},r[2])];return g[2].type=g[2].type||null,C(g[2],g[0]),C(g[2],g[1]),g};function PB(t){return!isNaN(t)&&!isFinite(t)}function OB(t,e,n,i){var r=1-t,o=i.dimensions[t];return PB(e[r])&&PB(n[r])&&e[t]===n[t]&&i.getAxis(o).containData(e[t])}function RB(t,e){if("cartesian2d"===t.type){var n=e[0].coord,i=e[1].coord;if(n&&i&&(OB(1,n,i,t)||OB(0,n,i,t)))return!0}return wB(t,e[0])&&wB(t,e[1])}function NB(t,e,n,i,r){var o,a=i.coordinateSystem,s=t.getItemModel(e),l=$r(s.get("x"),r.getWidth()),u=$r(s.get("y"),r.getHeight());if(isNaN(l)||isNaN(u)){if(i.getMarkerPosition)o=i.getMarkerPosition(t.getValues(t.dimensions,e));else{var h=a.dimensions,c=t.get(h[0],e),p=t.get(h[1],e);o=a.dataToPoint([c,p])}if(OS(a,"cartesian2d")){var d=a.getAxis("x"),f=a.getAxis("y");h=a.dimensions;PB(t.get(h[0],e))?o[0]=d.toGlobalCoord(d.getExtent()[n?0:1]):PB(t.get(h[1],e))&&(o[1]=f.toGlobalCoord(f.getExtent()[n?0:1]))}isNaN(l)||(o[0]=l),isNaN(u)||(o[1]=u)}else o=[l,u];t.setItemLayout(e,o)}var EB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.updateTransform=function(t,e,n){e.eachSeries((function(t){var e=gB.getMarkerModelFromSeries(t,"markLine");if(e){var i=e.getData(),r=kB(e).from,o=kB(e).to;r.each((function(e){NB(r,e,!0,t,n),NB(o,e,!1,t,n)})),i.each((function(t){i.setItemLayout(t,[r.getItemLayout(t),o.getItemLayout(t)])})),this.markerGroupMap.get(t.id).updateLayout()}}),this)},e.prototype.renderSeries=function(t,e,n,i){var r=t.coordinateSystem,o=t.id,a=t.getData(),s=this.markerGroupMap,l=s.get(o)||s.set(o,new YA);this.group.add(l.group);var u=function(t,e,n){var i;i=t?z(t&&t.dimensions,(function(t){return A(A({},e.getData().getDimensionInfo(e.getData().mapDimension(t))||{}),{name:t,ordinalMeta:null})})):[{name:"value",type:"float"}];var r=new cx(i,n),o=new cx(i,n),a=new cx([],n),s=z(n.get("data"),H(LB,e,t,n));t&&(s=B(s,H(RB,t)));var l=SB(!!t,i);return r.initData(z(s,(function(t){return t[0]})),null,l),o.initData(z(s,(function(t){return t[1]})),null,l),a.initData(z(s,(function(t){return t[2]}))),a.hasItemOption=!0,{from:r,to:o,line:a}}(r,t,e),h=u.from,c=u.to,p=u.line;kB(e).from=h,kB(e).to=c,e.setData(p);var d=e.get("symbol"),f=e.get("symbolSize"),g=e.get("symbolRotate"),y=e.get("symbolOffset");function v(e,n,r){var o=e.getItemModel(n);NB(e,n,r,t,i);var s=o.getModel("itemStyle").getItemStyle();null==s.fill&&(s.fill=Ay(a,"color")),e.setItemVisual(n,{symbolKeepAspect:o.get("symbolKeepAspect"),symbolOffset:rt(o.get("symbolOffset",!0),y[r?0:1]),symbolRotate:rt(o.get("symbolRotate",!0),g[r?0:1]),symbolSize:rt(o.get("symbolSize"),f[r?0:1]),symbol:rt(o.get("symbol",!0),d[r?0:1]),style:s})}Y(d)||(d=[d,d]),Y(f)||(f=[f,f]),Y(g)||(g=[g,g]),Y(y)||(y=[y,y]),u.from.each((function(t){v(h,t,!0),v(c,t,!1)})),p.each((function(t){var e=p.getItemModel(t).getModel("lineStyle").getLineStyle();p.setItemLayout(t,[h.getItemLayout(t),c.getItemLayout(t)]),null==e.stroke&&(e.stroke=h.getItemVisual(t,"style").fill),p.setItemVisual(t,{fromSymbolKeepAspect:h.getItemVisual(t,"symbolKeepAspect"),fromSymbolOffset:h.getItemVisual(t,"symbolOffset"),fromSymbolRotate:h.getItemVisual(t,"symbolRotate"),fromSymbolSize:h.getItemVisual(t,"symbolSize"),fromSymbol:h.getItemVisual(t,"symbol"),toSymbolKeepAspect:c.getItemVisual(t,"symbolKeepAspect"),toSymbolOffset:c.getItemVisual(t,"symbolOffset"),toSymbolRotate:c.getItemVisual(t,"symbolRotate"),toSymbolSize:c.getItemVisual(t,"symbolSize"),toSymbol:c.getItemVisual(t,"symbol"),style:e})})),l.updateData(p),u.line.eachItemGraphicEl((function(t){rl(t).dataModel=e,t.traverse((function(t){rl(t).dataModel=e}))})),this.markKeep(l),l.group.silent=e.get("silent")||t.get("silent")},e.type="markLine",e}(TB);var zB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.createMarkerModelFromSeries=function(t,n,i){return new e(t,n,i)},e.type="markArea",e.defaultOption={z:1,tooltip:{trigger:"item"},animation:!1,label:{show:!0,position:"top"},itemStyle:{borderWidth:0},emphasis:{label:{show:!0,position:"top"}}},e}(gB),VB=Vo(),BB=function(t,e,n,i){var r=i[0],o=i[1];if(r&&o){var a=_B(t,r),s=_B(t,o),l=a.coord,u=s.coord;l[0]=it(l[0],-1/0),l[1]=it(l[1],-1/0),u[0]=it(u[0],1/0),u[1]=it(u[1],1/0);var h=D([{},a,s]);return h.coord=[a.coord,s.coord],h.x0=a.x,h.y0=a.y,h.x1=s.x,h.y1=s.y,h}};function FB(t){return!isNaN(t)&&!isFinite(t)}function GB(t,e,n,i){var r=1-t;return FB(e[r])&&FB(n[r])}function WB(t,e){var n=e.coord[0],i=e.coord[1],r={coord:n,x:e.x0,y:e.y0},o={coord:i,x:e.x1,y:e.y1};return OS(t,"cartesian2d")?!(!n||!i||!GB(1,n,i)&&!GB(0,n,i))||function(t,e,n){return!(t&&t.containZone&&e.coord&&n.coord&&!vB(e)&&!vB(n))||t.containZone(e.coord,n.coord)}(t,r,o):wB(t,r)||wB(t,o)}function HB(t,e,n,i,r){var o,a=i.coordinateSystem,s=t.getItemModel(e),l=$r(s.get(n[0]),r.getWidth()),u=$r(s.get(n[1]),r.getHeight());if(isNaN(l)||isNaN(u)){if(i.getMarkerPosition){var h=t.getValues(["x0","y0"],e),c=t.getValues(["x1","y1"],e),p=a.clampData(h),d=a.clampData(c),f=[];"x0"===n[0]?f[0]=p[0]>d[0]?c[0]:h[0]:f[0]=p[0]>d[0]?h[0]:c[0],"y0"===n[1]?f[1]=p[1]>d[1]?c[1]:h[1]:f[1]=p[1]>d[1]?h[1]:c[1],o=i.getMarkerPosition(f,n,!0)}else{var g=[m=t.get(n[0],e),x=t.get(n[1],e)];a.clampData&&a.clampData(g,g),o=a.dataToPoint(g,!0)}if(OS(a,"cartesian2d")){var y=a.getAxis("x"),v=a.getAxis("y"),m=t.get(n[0],e),x=t.get(n[1],e);FB(m)?o[0]=y.toGlobalCoord(y.getExtent()["x0"===n[0]?0:1]):FB(x)&&(o[1]=v.toGlobalCoord(v.getExtent()["y0"===n[1]?0:1]))}isNaN(l)||(o[0]=l),isNaN(u)||(o[1]=u)}else o=[l,u];return o}var YB=[["x0","y0"],["x1","y0"],["x1","y1"],["x0","y1"]],XB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.updateTransform=function(t,e,n){e.eachSeries((function(t){var e=gB.getMarkerModelFromSeries(t,"markArea");if(e){var i=e.getData();i.each((function(e){var r=z(YB,(function(r){return HB(i,e,r,t,n)}));i.setItemLayout(e,r),i.getItemGraphicEl(e).setShape("points",r)}))}}),this)},e.prototype.renderSeries=function(t,e,n,i){var r=t.coordinateSystem,o=t.id,a=t.getData(),s=this.markerGroupMap,l=s.get(o)||s.set(o,{group:new Br});this.group.add(l.group),this.markKeep(l);var u=function(t,e,n){var i,r,o=["x0","y0","x1","y1"];if(t){var a=z(t&&t.dimensions,(function(t){var n=e.getData();return A(A({},n.getDimensionInfo(n.mapDimension(t))||{}),{name:t,ordinalMeta:null})}));r=z(o,(function(t,e){return{name:t,type:a[e%2].type}})),i=new cx(r,n)}else i=new cx(r=[{name:"value",type:"float"}],n);var s=z(n.get("data"),H(BB,e,t,n));t&&(s=B(s,H(WB,t)));var l=t?function(t,e,n,i){return If(t.coord[Math.floor(i/2)][i%2],r[i])}:function(t,e,n,i){return If(t.value,r[i])};return i.initData(s,null,l),i.hasItemOption=!0,i}(r,t,e);e.setData(u),u.each((function(e){var n=z(YB,(function(n){return HB(u,e,n,t,i)})),o=r.getAxis("x").scale,s=r.getAxis("y").scale,l=o.getExtent(),h=s.getExtent(),c=[o.parse(u.get("x0",e)),o.parse(u.get("x1",e))],p=[s.parse(u.get("y0",e)),s.parse(u.get("y1",e))];Qr(c),Qr(p);var d=!!(l[0]>c[1]||l[1]p[1]||h[1]=0},e.prototype.getOrient=function(){return"vertical"===this.get("orient")?{index:1,name:"vertical"}:{index:0,name:"horizontal"}},e.type="legend.plain",e.dependencies=["series"],e.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}},e}(zp),ZB=H,jB=E,qB=Br,KB=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.newlineDisabled=!1,n}return n(e,t),e.prototype.init=function(){this.group.add(this._contentGroup=new qB),this.group.add(this._selectorGroup=new qB),this._isFirstRender=!0},e.prototype.getContentGroup=function(){return this._contentGroup},e.prototype.getSelectorGroup=function(){return this._selectorGroup},e.prototype.render=function(t,e,n){var i=this._isFirstRender;if(this._isFirstRender=!1,this.resetInner(),t.get("show",!0)){var r=t.get("align"),o=t.get("orient");r&&"auto"!==r||(r="right"===t.get("left")&&"vertical"===o?"right":"left");var a=t.get("selector",!0),s=t.get("selectorPosition",!0);!a||s&&"auto"!==s||(s="horizontal"===o?"end":"start"),this.renderInner(r,t,e,n,a,o,s);var l=t.getBoxLayoutParams(),u={width:n.getWidth(),height:n.getHeight()},h=t.get("padding"),c=kp(l,u,h),p=this.layoutInner(t,r,c,i,a,s),d=kp(k({width:p.width,height:p.height},l),u,h);this.group.x=d.x-p.x,this.group.y=d.y-p.y,this.group.markRedraw(),this.group.add(this._backgroundEl=Iz(p,t))}},e.prototype.resetInner=function(){this.getContentGroup().removeAll(),this._backgroundEl&&this.group.remove(this._backgroundEl),this.getSelectorGroup().removeAll()},e.prototype.renderInner=function(t,e,n,i,r,o,a){var s=this.getContentGroup(),l=yt(),u=e.get("selectedMode"),h=[];n.eachRawSeries((function(t){!t.get("legendHoverLink")&&h.push(t.id)})),jB(e.getData(),(function(r,o){var a=r.get("name");if(!this.newlineDisabled&&(""===a||"\n"===a)){var c=new qB;return c.newline=!0,void s.add(c)}var p=n.getSeriesByName(a)[0];if(!l.get(a)){if(p){var d=p.getData(),f=d.getVisual("legendLineStyle")||{},g=d.getVisual("legendIcon"),y=d.getVisual("style"),v=this._createItem(p,a,o,r,e,t,f,y,g,u,i);v.on("click",ZB($B,a,null,i,h)).on("mouseover",ZB(QB,p.name,null,i,h)).on("mouseout",ZB(tF,p.name,null,i,h)),n.ssr&&v.eachChild((function(t){var e=rl(t);e.seriesIndex=p.seriesIndex,e.dataIndex=o,e.ssrType="legend"})),l.set(a,!0)}else n.eachRawSeries((function(s){if(!l.get(a)&&s.legendVisualProvider){var c=s.legendVisualProvider;if(!c.containName(a))return;var p=c.indexOfName(a),d=c.getItemVisual(p,"style"),f=c.getItemVisual(p,"legendIcon"),g=qn(d.fill);g&&0===g[3]&&(g[3]=.2,d=A(A({},d),{fill:ri(g,"rgba")}));var y=this._createItem(s,a,o,r,e,t,{},d,f,u,i);y.on("click",ZB($B,null,a,i,h)).on("mouseover",ZB(QB,null,a,i,h)).on("mouseout",ZB(tF,null,a,i,h)),n.ssr&&y.eachChild((function(t){var e=rl(t);e.seriesIndex=s.seriesIndex,e.dataIndex=o,e.ssrType="legend"})),l.set(a,!0)}}),this);0}}),this),r&&this._createSelector(r,e,i,o,a)},e.prototype._createSelector=function(t,e,n,i,r){var o=this.getSelectorGroup();jB(t,(function(t){var i=t.type,r=new Xs({style:{x:0,y:0,align:"center",verticalAlign:"middle"},onclick:function(){n.dispatchAction({type:"all"===i?"legendAllSelect":"legendInverseSelect",legendId:e.id})}});o.add(r),ic(r,{normal:e.getModel("selectorLabel"),emphasis:e.getModel(["emphasis","selectorLabel"])},{defaultText:t.title}),Ul(r)}))},e.prototype._createItem=function(t,e,n,i,r,o,a,s,l,u,h){var c=t.visualDrawType,p=r.get("itemWidth"),d=r.get("itemHeight"),f=r.isSelected(e),g=i.get("symbolRotate"),y=i.get("symbolKeepAspect"),v=i.get("icon"),m=function(t,e,n,i,r,o,a){function s(t,e){"auto"===t.lineWidth&&(t.lineWidth=e.lineWidth>0?2:0),jB(t,(function(n,i){"inherit"===t[i]&&(t[i]=e[i])}))}var l=e.getModel("itemStyle"),u=l.getItemStyle(),h=0===t.lastIndexOf("empty",0)?"fill":"stroke",c=l.getShallow("decal");u.decal=c&&"inherit"!==c?mv(c,a):i.decal,"inherit"===u.fill&&(u.fill=i[r]);"inherit"===u.stroke&&(u.stroke=i[h]);"inherit"===u.opacity&&(u.opacity=("fill"===r?i:n).opacity);s(u,i);var p=e.getModel("lineStyle"),d=p.getLineStyle();if(s(d,n),"auto"===u.fill&&(u.fill=i.fill),"auto"===u.stroke&&(u.stroke=i.fill),"auto"===d.stroke&&(d.stroke=i.fill),!o){var f=e.get("inactiveBorderWidth"),g=u[h];u.lineWidth="auto"===f?i.lineWidth>0&&g?2:0:u.lineWidth,u.fill=e.get("inactiveColor"),u.stroke=e.get("inactiveBorderColor"),d.stroke=p.get("inactiveColor"),d.lineWidth=p.get("inactiveWidth")}return{itemStyle:u,lineStyle:d}}(l=v||l||"roundRect",i,a,s,c,f,h),x=new qB,_=i.getModel("textStyle");if(!X(t.getLegendIcon)||v&&"inherit"!==v){var b="inherit"===v&&t.getData().getVisual("symbol")?"inherit"===g?t.getData().getVisual("symbolRotate"):g:0;x.add(function(t){var e=t.icon||"roundRect",n=Xy(e,0,0,t.itemWidth,t.itemHeight,t.itemStyle.fill,t.symbolKeepAspect);n.setStyle(t.itemStyle),n.rotation=(t.iconRotate||0)*Math.PI/180,n.setOrigin([t.itemWidth/2,t.itemHeight/2]),e.indexOf("empty")>-1&&(n.style.stroke=n.style.fill,n.style.fill="#fff",n.style.lineWidth=2);return n}({itemWidth:p,itemHeight:d,icon:l,iconRotate:b,itemStyle:m.itemStyle,lineStyle:m.lineStyle,symbolKeepAspect:y}))}else x.add(t.getLegendIcon({itemWidth:p,itemHeight:d,icon:l,iconRotate:g,itemStyle:m.itemStyle,lineStyle:m.lineStyle,symbolKeepAspect:y}));var w="left"===o?p+5:-5,S=o,M=r.get("formatter"),I=e;U(M)&&M?I=M.replace("{name}",null!=e?e:""):X(M)&&(I=M(e));var T=f?_.getTextColor():i.get("inactiveColor");x.add(new Xs({style:oc(_,{text:I,x:w,y:d/2,fill:T,align:S,verticalAlign:"middle"},{inheritColor:T})}));var C=new Ws({shape:x.getBoundingRect(),style:{fill:"transparent"}}),D=i.getModel("tooltip");return D.get("show")&&Kh({el:C,componentModel:r,itemName:e,itemTooltipOption:D.option}),x.add(C),x.eachChild((function(t){t.silent=!0})),C.silent=!u,this.getContentGroup().add(x),Ul(x),x.__legendDataIndex=n,x},e.prototype.layoutInner=function(t,e,n,i,r,o){var a=this.getContentGroup(),s=this.getSelectorGroup();Ap(t.get("orient"),a,t.get("itemGap"),n.width,n.height);var l=a.getBoundingRect(),u=[-l.x,-l.y];if(s.markRedraw(),a.markRedraw(),r){Ap("horizontal",s,t.get("selectorItemGap",!0));var h=s.getBoundingRect(),c=[-h.x,-h.y],p=t.get("selectorButtonGap",!0),d=t.getOrient().index,f=0===d?"width":"height",g=0===d?"height":"width",y=0===d?"y":"x";"end"===o?c[d]+=l[f]+p:u[d]+=h[f]+p,c[1-d]+=l[g]/2-h[g]/2,s.x=c[0],s.y=c[1],a.x=u[0],a.y=u[1];var v={x:0,y:0};return v[f]=l[f]+p+h[f],v[g]=Math.max(l[g],h[g]),v[y]=Math.min(0,h[y]+c[1-d]),v}return a.x=u[0],a.y=u[1],this.group.getBoundingRect()},e.prototype.remove=function(){this.getContentGroup().removeAll(),this._isFirstRender=!0},e.type="legend.plain",e}(Ag);function $B(t,e,n,i){tF(t,e,n,i),n.dispatchAction({type:"legendToggleSelect",name:null!=t?t:e}),QB(t,e,n,i)}function JB(t){for(var e,n=t.getZr().storage.getDisplayList(),i=0,r=n.length;in[r],f=[-c.x,-c.y];e||(f[i]=l[s]);var g=[0,0],y=[-p.x,-p.y],v=rt(t.get("pageButtonGap",!0),t.get("itemGap",!0));d&&("end"===t.get("pageButtonPosition",!0)?y[i]+=n[r]-p[r]:g[i]+=p[r]+v);y[1-i]+=c[o]/2-p[o]/2,l.setPosition(f),u.setPosition(g),h.setPosition(y);var m={x:0,y:0};if(m[r]=d?n[r]:c[r],m[o]=Math.max(c[o],p[o]),m[a]=Math.min(0,p[a]+y[1-i]),u.__rectSize=n[r],d){var x={x:0,y:0};x[r]=Math.max(n[r]-p[r]-v,0),x[o]=m[o],u.setClipPath(new Ws({shape:x})),u.__rectSize=x[r]}else h.eachChild((function(t){t.attr({invisible:!0,silent:!0})}));var _=this._getPageInfo(t);return null!=_.pageIndex&&vh(l,{x:_.contentPosition[0],y:_.contentPosition[1]},d?t:null),this._updatePageInfoView(t,_),m},e.prototype._pageGo=function(t,e,n){var i=this._getPageInfo(e)[t];null!=i&&n.dispatchAction({type:"legendScroll",scrollDataIndex:i,legendId:e.id})},e.prototype._updatePageInfoView=function(t,e){var n=this._controllerGroup;E(["pagePrev","pageNext"],(function(i){var r=null!=e[i+"DataIndex"],o=n.childOfName(i);o&&(o.setStyle("fill",r?t.get("pageIconColor",!0):t.get("pageIconInactiveColor",!0)),o.cursor=r?"pointer":"default")}));var i=n.childOfName("pageText"),r=t.get("pageFormatter"),o=e.pageIndex,a=null!=o?o+1:0,s=e.pageCount;i&&r&&i.setStyle("text",U(r)?r.replace("{current}",null==a?"":a+"").replace("{total}",null==s?"":s+""):r({current:a,total:s}))},e.prototype._getPageInfo=function(t){var e=t.get("scrollDataIndex",!0),n=this.getContentGroup(),i=this._containerGroup.__rectSize,r=t.getOrient().index,o=lF[r],a=uF[r],s=this._findTargetItemIndex(e),l=n.children(),u=l[s],h=l.length,c=h?1:0,p={contentPosition:[n.x,n.y],pageCount:c,pageIndex:c-1,pagePrevDataIndex:null,pageNextDataIndex:null};if(!u)return p;var d=m(u);p.contentPosition[r]=-d.s;for(var f=s+1,g=d,y=d,v=null;f<=h;++f)(!(v=m(l[f]))&&y.e>g.s+i||v&&!x(v,g.s))&&(g=y.i>g.i?y:v)&&(null==p.pageNextDataIndex&&(p.pageNextDataIndex=g.i),++p.pageCount),y=v;for(f=s-1,g=d,y=d,v=null;f>=-1;--f)(v=m(l[f]))&&x(y,v.s)||!(g.i=e&&t.s<=e+i}},e.prototype._findTargetItemIndex=function(t){return this._showController?(this.getContentGroup().eachChild((function(i,r){var o=i.__legendDataIndex;null==n&&null!=o&&(n=r),o===t&&(e=r)})),null!=e?e:n):0;var e,n},e.type="legend.scroll",e}(KB);function cF(t){Vm(rF),t.registerComponentModel(oF),t.registerComponentView(hF),function(t){t.registerAction("legendScroll","legendscroll",(function(t,e){var n=t.scrollDataIndex;null!=n&&e.eachComponent({mainType:"legend",subType:"scroll",query:t},(function(t){t.setScrollDataIndex(n)}))}))}(t)}var pF=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="dataZoom.inside",e.defaultOption=kc(lz.defaultOption,{disabled:!1,zoomLock:!1,zoomOnMouseWheel:!0,moveOnMouseMove:!0,moveOnMouseWheel:!1,preventDefaultMouseMove:!0}),e}(lz),dF=Vo();function fF(t,e,n){dF(t).coordSysRecordMap.each((function(t){var i=t.dataZoomInfoMap.get(e.uid);i&&(i.getRange=n)}))}function gF(t,e){if(e){t.removeKey(e.model.uid);var n=e.controller;n&&n.dispose()}}function yF(t,e){t.isDisposed()||t.dispatchAction({type:"dataZoom",animation:{easing:"cubicOut",duration:100},batch:e})}function vF(t,e,n,i){return t.coordinateSystem.containPoint([n,i])}function mF(t){t.registerProcessor(t.PRIORITY.PROCESSOR.FILTER,(function(t,e){var n=dF(e),i=n.coordSysRecordMap||(n.coordSysRecordMap=yt());i.each((function(t){t.dataZoomInfoMap=null})),t.eachComponent({mainType:"dataZoom",subType:"inside"},(function(t){E(az(t).infoList,(function(n){var r=n.model.uid,o=i.get(r)||i.set(r,function(t,e){var n={model:e,containsPoint:H(vF,e),dispatchAction:H(yF,t),dataZoomInfoMap:null,controller:null},i=n.controller=new nT(t.getZr());return E(["pan","zoom","scrollMove"],(function(t){i.on(t,(function(e){var i=[];n.dataZoomInfoMap.each((function(r){if(e.isAvailableBehavior(r.model.option)){var o=(r.getRange||{})[t],a=o&&o(r.dzReferCoordSysInfo,n.model.mainType,n.controller,e);!r.model.get("disabled",!0)&&a&&i.push({dataZoomId:r.model.id,start:a[0],end:a[1]})}})),i.length&&n.dispatchAction(i)}))})),n}(e,n.model));(o.dataZoomInfoMap||(o.dataZoomInfoMap=yt())).set(t.uid,{dzReferCoordSysInfo:n,model:t,getRange:null})}))})),i.each((function(t){var e,n=t.controller,r=t.dataZoomInfoMap;if(r){var o=r.keys()[0];null!=o&&(e=r.get(o))}if(e){var a=function(t){var e,n="type_",i={type_true:2,type_move:1,type_false:0,type_undefined:-1},r=!0;return t.each((function(t){var o=t.model,a=!o.get("disabled",!0)&&(!o.get("zoomLock",!0)||"move");i[n+a]>i[n+e]&&(e=a),r=r&&o.get("preventDefaultMouseMove",!0)})),{controlType:e,opt:{zoomOnMouseWheel:!0,moveOnMouseMove:!0,moveOnMouseWheel:!0,preventDefaultMouseMove:!!r}}}(r);n.enable(a.controlType,a.opt),n.setPointerChecker(t.containsPoint),Hg(t,"dispatchAction",e.model.get("throttle",!0),"fixRate")}else gF(i,t)}))}))}var xF=function(t){function e(){var e=null!==t&&t.apply(this,arguments)||this;return e.type="dataZoom.inside",e}return n(e,t),e.prototype.render=function(e,n,i){t.prototype.render.apply(this,arguments),e.noTarget()?this._clear():(this.range=e.getPercentRange(),fF(i,e,{pan:W(_F.pan,this),zoom:W(_F.zoom,this),scrollMove:W(_F.scrollMove,this)}))},e.prototype.dispose=function(){this._clear(),t.prototype.dispose.apply(this,arguments)},e.prototype._clear=function(){!function(t,e){for(var n=dF(t).coordSysRecordMap,i=n.keys(),r=0;r0?s.pixelStart+s.pixelLength-s.pixel:s.pixel-s.pixelStart)/s.pixelLength*(o[1]-o[0])+o[0],u=Math.max(1/i.scale,0);o[0]=(o[0]-l)*u+l,o[1]=(o[1]-l)*u+l;var h=this.dataZoomModel.findRepresentativeAxisProxy().getMinMaxSpan();return zk(0,o,[0,100],0,h.minSpan,h.maxSpan),this.range=o,r[0]!==o[0]||r[1]!==o[1]?o:void 0}},pan:bF((function(t,e,n,i,r,o){var a=wF[i]([o.oldX,o.oldY],[o.newX,o.newY],e,r,n);return a.signal*(t[1]-t[0])*a.pixel/a.pixelLength})),scrollMove:bF((function(t,e,n,i,r,o){return wF[i]([0,0],[o.scrollDelta,o.scrollDelta],e,r,n).signal*(t[1]-t[0])*o.scrollDelta}))};function bF(t){return function(e,n,i,r){var o=this.range,a=o.slice(),s=e.axisModels[0];if(s)return zk(t(a,s,e,n,i,r),a,[0,100],"all"),this.range=a,o[0]!==a[0]||o[1]!==a[1]?a:void 0}}var wF={grid:function(t,e,n,i,r){var o=n.axis,a={},s=r.model.coordinateSystem.getRect();return t=t||[0,0],"x"===o.dim?(a.pixel=e[0]-t[0],a.pixelLength=s.width,a.pixelStart=s.x,a.signal=o.inverse?1:-1):(a.pixel=e[1]-t[1],a.pixelLength=s.height,a.pixelStart=s.y,a.signal=o.inverse?-1:1),a},polar:function(t,e,n,i,r){var o=n.axis,a={},s=r.model.coordinateSystem,l=s.getRadiusAxis().getExtent(),u=s.getAngleAxis().getExtent();return t=t?s.pointToCoord(t):[0,0],e=s.pointToCoord(e),"radiusAxis"===n.mainType?(a.pixel=e[0]-t[0],a.pixelLength=l[1]-l[0],a.pixelStart=l[0],a.signal=o.inverse?1:-1):(a.pixel=e[1]-t[1],a.pixelLength=u[1]-u[0],a.pixelStart=u[0],a.signal=o.inverse?-1:1),a},singleAxis:function(t,e,n,i,r){var o=n.axis,a=r.model.coordinateSystem.getRect(),s={};return t=t||[0,0],"horizontal"===o.orient?(s.pixel=e[0]-t[0],s.pixelLength=a.width,s.pixelStart=a.x,s.signal=o.inverse?1:-1):(s.pixel=e[1]-t[1],s.pixelLength=a.height,s.pixelStart=a.y,s.signal=o.inverse?-1:1),s}};function SF(t){mz(t),t.registerComponentModel(pF),t.registerComponentView(xF),mF(t)}var MF=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.type="dataZoom.slider",e.layoutMode="box",e.defaultOption=kc(lz.defaultOption,{show:!0,right:"ph",top:"ph",width:"ph",height:"ph",left:null,bottom:null,borderColor:"#d2dbee",borderRadius:3,backgroundColor:"rgba(47,69,84,0)",dataBackground:{lineStyle:{color:"#d2dbee",width:.5},areaStyle:{color:"#d2dbee",opacity:.2}},selectedDataBackground:{lineStyle:{color:"#8fb0f7",width:.5},areaStyle:{color:"#8fb0f7",opacity:.2}},fillerColor:"rgba(135,175,274,0.2)",handleIcon:"path://M-9.35,34.56V42m0-40V9.5m-2,0h4a2,2,0,0,1,2,2v21a2,2,0,0,1-2,2h-4a2,2,0,0,1-2-2v-21A2,2,0,0,1-11.35,9.5Z",handleSize:"100%",handleStyle:{color:"#fff",borderColor:"#ACB8D1"},moveHandleSize:7,moveHandleIcon:"path://M-320.9-50L-320.9-50c18.1,0,27.1,9,27.1,27.1V85.7c0,18.1-9,27.1-27.1,27.1l0,0c-18.1,0-27.1-9-27.1-27.1V-22.9C-348-41-339-50-320.9-50z M-212.3-50L-212.3-50c18.1,0,27.1,9,27.1,27.1V85.7c0,18.1-9,27.1-27.1,27.1l0,0c-18.1,0-27.1-9-27.1-27.1V-22.9C-239.4-41-230.4-50-212.3-50z M-103.7-50L-103.7-50c18.1,0,27.1,9,27.1,27.1V85.7c0,18.1-9,27.1-27.1,27.1l0,0c-18.1,0-27.1-9-27.1-27.1V-22.9C-130.9-41-121.8-50-103.7-50z",moveHandleStyle:{color:"#D2DBEE",opacity:.7},showDetail:!0,showDataShadow:"auto",realtime:!0,zoomLock:!1,textStyle:{color:"#6E7079"},brushSelect:!0,brushStyle:{color:"rgba(135,175,274,0.15)"},emphasis:{handleLabel:{show:!0},handleStyle:{borderColor:"#8FB0F7"},moveHandleStyle:{color:"#8FB0F7"}}}),e}(lz),IF=Ws,TF="horizontal",CF="vertical",DF=["line","bar","candlestick","scatter"],AF={easing:"cubicOut",duration:100,delay:0},kF=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n._displayables={},n}return n(e,t),e.prototype.init=function(t,e){this.api=e,this._onBrush=W(this._onBrush,this),this._onBrushEnd=W(this._onBrushEnd,this)},e.prototype.render=function(e,n,i,r){if(t.prototype.render.apply(this,arguments),Hg(this,"_dispatchZoomAction",e.get("throttle"),"fixRate"),this._orient=e.getOrient(),!1!==e.get("show")){if(e.noTarget())return this._clear(),void this.group.removeAll();r&&"dataZoom"===r.type&&r.from===this.uid||this._buildView(),this._updateView()}else this.group.removeAll()},e.prototype.dispose=function(){this._clear(),t.prototype.dispose.apply(this,arguments)},e.prototype._clear=function(){Yg(this,"_dispatchZoomAction");var t=this.api.getZr();t.off("mousemove",this._onBrush),t.off("mouseup",this._onBrushEnd)},e.prototype._buildView=function(){var t=this.group;t.removeAll(),this._brushing=!1,this._displayables.brushRect=null,this._resetLocation(),this._resetInterval();var e=this._displayables.sliderGroup=new Br;this._renderBackground(),this._renderHandle(),this._renderDataShadow(),t.add(e),this._positionGroup()},e.prototype._resetLocation=function(){var t=this.dataZoomModel,e=this.api,n=t.get("brushSelect")?7:0,i=this._findCoordRect(),r={width:e.getWidth(),height:e.getHeight()},o=this._orient===TF?{right:r.width-i.x-i.width,top:r.height-30-7-n,width:i.width,height:30}:{right:7,top:i.y,width:30,height:i.height},a=Rp(t.option);E(["right","top","width","height"],(function(t){"ph"===a[t]&&(a[t]=o[t])}));var s=kp(a,r);this._location={x:s.x,y:s.y},this._size=[s.width,s.height],this._orient===CF&&this._size.reverse()},e.prototype._positionGroup=function(){var t=this.group,e=this._location,n=this._orient,i=this.dataZoomModel.getFirstTargetAxisModel(),r=i&&i.get("inverse"),o=this._displayables.sliderGroup,a=(this._dataShadowInfo||{}).otherAxisInverse;o.attr(n!==TF||r?n===TF&&r?{scaleY:a?1:-1,scaleX:-1}:n!==CF||r?{scaleY:a?-1:1,scaleX:-1,rotation:Math.PI/2}:{scaleY:a?-1:1,scaleX:1,rotation:Math.PI/2}:{scaleY:a?1:-1,scaleX:1});var s=t.getBoundingRect([o]);t.x=e.x-s.x,t.y=e.y-s.y,t.markRedraw()},e.prototype._getViewExtent=function(){return[0,this._size[0]]},e.prototype._renderBackground=function(){var t=this.dataZoomModel,e=this._size,n=this._displayables.sliderGroup,i=t.get("brushSelect");n.add(new IF({silent:!0,shape:{x:0,y:0,width:e[0],height:e[1]},style:{fill:t.get("backgroundColor")},z2:-40}));var r=new IF({shape:{x:0,y:0,width:e[0],height:e[1]},style:{fill:"transparent"},z2:0,onclick:W(this._onClickPanel,this)}),o=this.api.getZr();i?(r.on("mousedown",this._onBrushStart,this),r.cursor="crosshair",o.on("mousemove",this._onBrush),o.on("mouseup",this._onBrushEnd)):(o.off("mousemove",this._onBrush),o.off("mouseup",this._onBrushEnd)),n.add(r)},e.prototype._renderDataShadow=function(){var t=this._dataShadowInfo=this._prepareDataShadowInfo();if(this._displayables.dataShadowSegs=[],t){var e=this._size,n=this._shadowSize||[],i=t.series,r=i.getRawData(),o=i.getShadowDim&&i.getShadowDim(),a=o&&r.getDimensionInfo(o)?i.getShadowDim():t.otherDim;if(null!=a){var s=this._shadowPolygonPts,l=this._shadowPolylinePts;if(r!==this._shadowData||a!==this._shadowDim||e[0]!==n[0]||e[1]!==n[1]){var u=r.getDataExtent(a),h=.3*(u[1]-u[0]);u=[u[0]-h,u[1]+h];var c,p=[0,e[1]],d=[0,e[0]],f=[[e[0],0],[0,0]],g=[],y=d[1]/(r.count()-1),v=0,m=Math.round(r.count()/e[0]);r.each([a],(function(t,e){if(m>0&&e%m)v+=y;else{var n=null==t||isNaN(t)||""===t,i=n?0:Kr(t,u,p,!0);n&&!c&&e?(f.push([f[f.length-1][0],0]),g.push([g[g.length-1][0],0])):!n&&c&&(f.push([v,0]),g.push([v,0])),f.push([v,i]),g.push([v,i]),v+=y,c=n}})),s=this._shadowPolygonPts=f,l=this._shadowPolylinePts=g}this._shadowData=r,this._shadowDim=a,this._shadowSize=[e[0],e[1]];for(var x=this.dataZoomModel,_=0;_<3;_++){var b=w(1===_);this._displayables.sliderGroup.add(b),this._displayables.dataShadowSegs.push(b)}}}function w(t){var e=x.getModel(t?"selectedDataBackground":"dataBackground"),n=new Br,i=new Xu({shape:{points:s},segmentIgnoreThreshold:1,style:e.getModel("areaStyle").getAreaStyle(),silent:!0,z2:-20}),r=new Zu({shape:{points:l},segmentIgnoreThreshold:1,style:e.getModel("lineStyle").getLineStyle(),silent:!0,z2:-19});return n.add(i),n.add(r),n}},e.prototype._prepareDataShadowInfo=function(){var t=this.dataZoomModel,e=t.get("showDataShadow");if(!1!==e){var n,i=this.ecModel;return t.eachTargetAxis((function(r,o){E(t.getAxisProxy(r,o).getTargetSeriesModels(),(function(t){if(!(n||!0!==e&&P(DF,t.get("type"))<0)){var a,s=i.getComponent(rz(r),o).axis,l=function(t){var e={x:"y",y:"x",radius:"angle",angle:"radius"};return e[t]}(r),u=t.coordinateSystem;null!=l&&u.getOtherAxis&&(a=u.getOtherAxis(s).inverse),l=t.getData().mapDimension(l),n={thisAxis:s,series:t,thisDim:r,otherDim:l,otherAxisInverse:a}}}),this)}),this),n}},e.prototype._renderHandle=function(){var t=this.group,e=this._displayables,n=e.handles=[null,null],i=e.handleLabels=[null,null],r=this._displayables.sliderGroup,o=this._size,a=this.dataZoomModel,s=this.api,l=a.get("borderRadius")||0,u=a.get("brushSelect"),h=e.filler=new IF({silent:u,style:{fill:a.get("fillerColor")},textConfig:{position:"inside"}});r.add(h),r.add(new IF({silent:!0,subPixelOptimize:!0,shape:{x:0,y:0,width:o[0],height:o[1],r:l},style:{stroke:a.get("dataBackgroundColor")||a.get("borderColor"),lineWidth:1,fill:"rgba(0,0,0,0)"}})),E([0,1],(function(e){var o=a.get("handleIcon");!Wy[o]&&o.indexOf("path://")<0&&o.indexOf("image://")<0&&(o="path://"+o);var s=Xy(o,-1,0,2,2,null,!0);s.attr({cursor:LF(this._orient),draggable:!0,drift:W(this._onDragMove,this,e),ondragend:W(this._onDragEnd,this),onmouseover:W(this._showDataInfo,this,!0),onmouseout:W(this._showDataInfo,this,!1),z2:5});var l=s.getBoundingRect(),u=a.get("handleSize");this._handleHeight=$r(u,this._size[1]),this._handleWidth=l.width/l.height*this._handleHeight,s.setStyle(a.getModel("handleStyle").getItemStyle()),s.style.strokeNoScale=!0,s.rectHover=!0,s.ensureState("emphasis").style=a.getModel(["emphasis","handleStyle"]).getItemStyle(),Ul(s);var h=a.get("handleColor");null!=h&&(s.style.fill=h),r.add(n[e]=s);var c=a.getModel("textStyle"),p=(a.get("handleLabel")||{}).show||!1;t.add(i[e]=new Xs({silent:!0,invisible:!p,style:oc(c,{x:0,y:0,text:"",verticalAlign:"middle",align:"center",fill:c.getTextColor(),font:c.getFont()}),z2:10}))}),this);var c=h;if(u){var p=$r(a.get("moveHandleSize"),o[1]),d=e.moveHandle=new Ws({style:a.getModel("moveHandleStyle").getItemStyle(),silent:!0,shape:{r:[0,0,2,2],y:o[1]-.5,height:p}}),f=.8*p,g=e.moveHandleIcon=Xy(a.get("moveHandleIcon"),-f/2,-f/2,f,f,"#fff",!0);g.silent=!0,g.y=o[1]+p/2-.5,d.ensureState("emphasis").style=a.getModel(["emphasis","moveHandleStyle"]).getItemStyle();var y=Math.min(o[1]/2,Math.max(p,10));(c=e.moveZone=new Ws({invisible:!0,shape:{y:o[1]-y,height:p+y}})).on("mouseover",(function(){s.enterEmphasis(d)})).on("mouseout",(function(){s.leaveEmphasis(d)})),r.add(d),r.add(g),r.add(c)}c.attr({draggable:!0,cursor:LF(this._orient),drift:W(this._onDragMove,this,"all"),ondragstart:W(this._showDataInfo,this,!0),ondragend:W(this._onDragEnd,this),onmouseover:W(this._showDataInfo,this,!0),onmouseout:W(this._showDataInfo,this,!1)})},e.prototype._resetInterval=function(){var t=this._range=this.dataZoomModel.getPercentRange(),e=this._getViewExtent();this._handleEnds=[Kr(t[0],[0,100],e,!0),Kr(t[1],[0,100],e,!0)]},e.prototype._updateInterval=function(t,e){var n=this.dataZoomModel,i=this._handleEnds,r=this._getViewExtent(),o=n.findRepresentativeAxisProxy().getMinMaxSpan(),a=[0,100];zk(e,i,r,n.get("zoomLock")?"all":t,null!=o.minSpan?Kr(o.minSpan,a,r,!0):null,null!=o.maxSpan?Kr(o.maxSpan,a,r,!0):null);var s=this._range,l=this._range=Qr([Kr(i[0],r,a,!0),Kr(i[1],r,a,!0)]);return!s||s[0]!==l[0]||s[1]!==l[1]},e.prototype._updateView=function(t){var e=this._displayables,n=this._handleEnds,i=Qr(n.slice()),r=this._size;E([0,1],(function(t){var i=e.handles[t],o=this._handleHeight;i.attr({scaleX:o/2,scaleY:o/2,x:n[t]+(t?-1:1),y:r[1]/2-o/2})}),this),e.filler.setShape({x:i[0],y:0,width:i[1]-i[0],height:r[1]});var o={x:i[0],width:i[1]-i[0]};e.moveHandle&&(e.moveHandle.setShape(o),e.moveZone.setShape(o),e.moveZone.getBoundingRect(),e.moveHandleIcon&&e.moveHandleIcon.attr("x",o.x+o.width/2));for(var a=e.dataShadowSegs,s=[0,i[0],i[1],r[0]],l=0;le[0]||n[1]<0||n[1]>e[1])){var i=this._handleEnds,r=(i[0]+i[1])/2,o=this._updateInterval("all",n[0]-r);this._updateView(),o&&this._dispatchZoomAction(!1)}},e.prototype._onBrushStart=function(t){var e=t.offsetX,n=t.offsetY;this._brushStart=new De(e,n),this._brushing=!0,this._brushStartTime=+new Date},e.prototype._onBrushEnd=function(t){if(this._brushing){var e=this._displayables.brushRect;if(this._brushing=!1,e){e.attr("ignore",!0);var n=e.shape;if(!(+new Date-this._brushStartTime<200&&Math.abs(n.width)<5)){var i=this._getViewExtent(),r=[0,100];this._range=Qr([Kr(n.x,i,r,!0),Kr(n.x+n.width,i,r,!0)]),this._handleEnds=[n.x,n.x+n.width],this._updateView(),this._dispatchZoomAction(!1)}}}},e.prototype._onBrush=function(t){this._brushing&&(de(t.event),this._updateBrushRect(t.offsetX,t.offsetY))},e.prototype._updateBrushRect=function(t,e){var n=this._displayables,i=this.dataZoomModel,r=n.brushRect;r||(r=n.brushRect=new IF({silent:!0,style:i.getModel("brushStyle").getItemStyle()}),n.sliderGroup.add(r)),r.attr("ignore",!1);var o=this._brushStart,a=this._displayables.sliderGroup,s=a.transformCoordToLocal(t,e),l=a.transformCoordToLocal(o.x,o.y),u=this._size;s[0]=Math.max(Math.min(u[0],s[0]),0),r.setShape({x:l[0],y:0,width:s[0]-l[0],height:u[1]})},e.prototype._dispatchZoomAction=function(t){var e=this._range;this.api.dispatchAction({type:"dataZoom",from:this.uid,dataZoomId:this.dataZoomModel.id,animation:t?AF:null,start:e[0],end:e[1]})},e.prototype._findCoordRect=function(){var t,e=az(this.dataZoomModel).infoList;if(!t&&e.length){var n=e[0].model.coordinateSystem;t=n.getRect&&n.getRect()}if(!t){var i=this.api.getWidth(),r=this.api.getHeight();t={x:.2*i,y:.2*r,width:.6*i,height:.6*r}}return t},e.type="dataZoom.slider",e}(cz);function LF(t){return"vertical"===t?"ns-resize":"ew-resize"}function PF(t){t.registerComponentModel(MF),t.registerComponentView(kF),mz(t)}var OF=function(t,e,n){var i=T((RF[t]||{})[e]);return n&&Y(i)?i[i.length-1]:i},RF={color:{active:["#006edd","#e0ffff"],inactive:["rgba(0,0,0,0)"]},colorHue:{active:[0,360],inactive:[0,0]},colorSaturation:{active:[.3,1],inactive:[0,0]},colorLightness:{active:[.9,.5],inactive:[0,0]},colorAlpha:{active:[.3,1],inactive:[0,0]},opacity:{active:[.3,1],inactive:[0,0]},symbol:{active:["circle","roundRect","diamond"],inactive:["none"]},symbolSize:{active:[10,50],inactive:[0,0]}},NF=kD.mapVisual,EF=kD.eachVisual,zF=Y,VF=E,BF=Qr,FF=Kr,GF=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n.stateList=["inRange","outOfRange"],n.replacableOptionKeys=["inRange","outOfRange","target","controller","color"],n.layoutMode={type:"box",ignoreSize:!0},n.dataBound=[-1/0,1/0],n.targetVisuals={},n.controllerVisuals={},n}return n(e,t),e.prototype.init=function(t,e,n){this.mergeDefaultAndTheme(t,n)},e.prototype.optionUpdated=function(t,e){var n=this.option;!e&&RV(n,t,this.replacableOptionKeys),this.textStyleModel=this.getModel("textStyle"),this.resetItemSize(),this.completeVisualOption()},e.prototype.resetVisual=function(t){var e=this.stateList;t=W(t,this),this.controllerVisuals=OV(this.option.controller,e,t),this.targetVisuals=OV(this.option.target,e,t)},e.prototype.getItemSymbol=function(){return null},e.prototype.getTargetSeriesIndices=function(){var t=this.option.seriesIndex,e=[];return null==t||"all"===t?this.ecModel.eachSeries((function(t,n){e.push(n)})):e=To(t),e},e.prototype.eachTargetSeries=function(t,e){E(this.getTargetSeriesIndices(),(function(n){var i=this.ecModel.getSeriesByIndex(n);i&&t.call(e,i)}),this)},e.prototype.isTargetSeries=function(t){var e=!1;return this.eachTargetSeries((function(n){n===t&&(e=!0)})),e},e.prototype.formatValueText=function(t,e,n){var i,r=this.option,o=r.precision,a=this.dataBound,s=r.formatter;n=n||["<",">"],Y(t)&&(t=t.slice(),i=!0);var l=e?t:i?[u(t[0]),u(t[1])]:u(t);return U(s)?s.replace("{value}",i?l[0]:l).replace("{value2}",i?l[1]:l):X(s)?i?s(t[0],t[1]):s(t):i?t[0]===a[0]?n[0]+" "+l[1]:t[1]===a[1]?n[1]+" "+l[0]:l[0]+" - "+l[1]:l;function u(t){return t===a[0]?"min":t===a[1]?"max":(+t).toFixed(Math.min(o,20))}},e.prototype.resetExtent=function(){var t=this.option,e=BF([t.min,t.max]);this._dataExtent=e},e.prototype.getDataDimensionIndex=function(t){var e=this.option.dimension;if(null!=e)return t.getDimensionIndex(e);for(var n=t.dimensions,i=n.length-1;i>=0;i--){var r=n[i],o=t.getDimensionInfo(r);if(!o.isCalculationCoord)return o.storeDimIndex}},e.prototype.getExtent=function(){return this._dataExtent.slice()},e.prototype.completeVisualOption=function(){var t=this.ecModel,e=this.option,n={inRange:e.inRange,outOfRange:e.outOfRange},i=e.target||(e.target={}),r=e.controller||(e.controller={});C(i,n),C(r,n);var o=this.isCategory();function a(n){zF(e.color)&&!n.inRange&&(n.inRange={color:e.color.slice().reverse()}),n.inRange=n.inRange||{color:t.get("gradientColor")}}a.call(this,i),a.call(this,r),function(t,e,n){var i=t[e],r=t[n];i&&!r&&(r=t[n]={},VF(i,(function(t,e){if(kD.isValidType(e)){var n=OF(e,"inactive",o);null!=n&&(r[e]=n,"color"!==e||r.hasOwnProperty("opacity")||r.hasOwnProperty("colorAlpha")||(r.opacity=[0,0]))}})))}.call(this,i,"inRange","outOfRange"),function(t){var e=(t.inRange||{}).symbol||(t.outOfRange||{}).symbol,n=(t.inRange||{}).symbolSize||(t.outOfRange||{}).symbolSize,i=this.get("inactiveColor"),r=this.getItemSymbol()||"roundRect";VF(this.stateList,(function(a){var s=this.itemSize,l=t[a];l||(l=t[a]={color:o?i:[i]}),null==l.symbol&&(l.symbol=e&&T(e)||(o?r:[r])),null==l.symbolSize&&(l.symbolSize=n&&T(n)||(o?s[0]:[s[0],s[0]])),l.symbol=NF(l.symbol,(function(t){return"none"===t?r:t}));var u=l.symbolSize;if(null!=u){var h=-1/0;EF(u,(function(t){t>h&&(h=t)})),l.symbolSize=NF(u,(function(t){return FF(t,[0,h],[0,s[0]],!0)}))}}),this)}.call(this,r)},e.prototype.resetItemSize=function(){this.itemSize=[parseFloat(this.get("itemWidth")),parseFloat(this.get("itemHeight"))]},e.prototype.isCategory=function(){return!!this.option.categories},e.prototype.setSelected=function(t){},e.prototype.getSelected=function(){return null},e.prototype.getValueState=function(t){return null},e.prototype.getVisualMeta=function(t){return null},e.type="visualMap",e.dependencies=["series"],e.defaultOption={show:!0,z:4,seriesIndex:"all",min:0,max:200,left:0,right:null,top:null,bottom:0,itemWidth:null,itemHeight:null,inverse:!1,orient:"vertical",backgroundColor:"rgba(0,0,0,0)",borderColor:"#ccc",contentColor:"#5793f3",inactiveColor:"#aaa",borderWidth:0,padding:5,textGap:10,precision:0,textStyle:{color:"#333"}},e}(zp),WF=[20,140],HF=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.optionUpdated=function(e,n){t.prototype.optionUpdated.apply(this,arguments),this.resetExtent(),this.resetVisual((function(t){t.mappingMethod="linear",t.dataExtent=this.getExtent()})),this._resetRange()},e.prototype.resetItemSize=function(){t.prototype.resetItemSize.apply(this,arguments);var e=this.itemSize;(null==e[0]||isNaN(e[0]))&&(e[0]=WF[0]),(null==e[1]||isNaN(e[1]))&&(e[1]=WF[1])},e.prototype._resetRange=function(){var t=this.getExtent(),e=this.option.range;!e||e.auto?(t.auto=1,this.option.range=t):Y(e)&&(e[0]>e[1]&&e.reverse(),e[0]=Math.max(e[0],t[0]),e[1]=Math.min(e[1],t[1]))},e.prototype.completeVisualOption=function(){t.prototype.completeVisualOption.apply(this,arguments),E(this.stateList,(function(t){var e=this.option.controller[t].symbolSize;e&&e[0]!==e[1]&&(e[0]=e[1]/3)}),this)},e.prototype.setSelected=function(t){this.option.range=t.slice(),this._resetRange()},e.prototype.getSelected=function(){var t=this.getExtent(),e=Qr((this.get("range")||[]).slice());return e[0]>t[1]&&(e[0]=t[1]),e[1]>t[1]&&(e[1]=t[1]),e[0]=n[1]||t<=e[1])?"inRange":"outOfRange"},e.prototype.findTargetDataIndices=function(t){var e=[];return this.eachTargetSeries((function(n){var i=[],r=n.getData();r.each(this.getDataDimensionIndex(r),(function(e,n){t[0]<=e&&e<=t[1]&&i.push(n)}),this),e.push({seriesId:n.id,dataIndex:i})}),this),e},e.prototype.getVisualMeta=function(t){var e=YF(this,"outOfRange",this.getExtent()),n=YF(this,"inRange",this.option.range.slice()),i=[];function r(e,n){i.push({value:e,color:t(e,n)})}for(var o=0,a=0,s=n.length,l=e.length;at[1])break;n.push({color:this.getControllerVisual(o,"color",e),offset:r/100})}return n.push({color:this.getControllerVisual(t[1],"color",e),offset:1}),n},e.prototype._createBarPoints=function(t,e){var n=this.visualMapModel.itemSize;return[[n[0]-e[0],t[0]],[n[0],t[0]],[n[0],t[1]],[n[0]-e[1],t[1]]]},e.prototype._createBarGroup=function(t){var e=this._orient,n=this.visualMapModel.get("inverse");return new Br("horizontal"!==e||n?"horizontal"===e&&n?{scaleX:"bottom"===t?-1:1,rotation:-Math.PI/2}:"vertical"!==e||n?{scaleX:"left"===t?1:-1}:{scaleX:"left"===t?1:-1,scaleY:-1}:{scaleX:"bottom"===t?1:-1,rotation:Math.PI/2})},e.prototype._updateHandle=function(t,e){if(this._useHandle){var n=this._shapes,i=this.visualMapModel,r=n.handleThumbs,o=n.handleLabels,a=i.itemSize,s=i.getExtent(),l=this._applyTransform("left",n.mainGroup);KF([0,1],(function(u){var h=r[u];h.setStyle("fill",e.handlesColor[u]),h.y=t[u];var c=qF(t[u],[0,a[1]],s,!0),p=this.getControllerVisual(c,"symbolSize");h.scaleX=h.scaleY=p/a[0],h.x=a[0]-p/2;var d=Fh(n.handleLabelPoints[u],Bh(h,this.group));if("horizontal"===this._orient){var f="left"===l||"top"===l?(a[0]-p)/2:(a[0]-p)/-2;d[1]+=f}o[u].setStyle({x:d[0],y:d[1],text:i.formatValueText(this._dataInterval[u]),verticalAlign:"middle",align:"vertical"===this._orient?this._applyTransform("left",n.mainGroup):"center"})}),this)}},e.prototype._showIndicator=function(t,e,n,i){var r=this.visualMapModel,o=r.getExtent(),a=r.itemSize,s=[0,a[1]],l=this._shapes,u=l.indicator;if(u){u.attr("invisible",!1);var h=this.getControllerVisual(t,"color",{convertOpacityToAlpha:!0}),c=this.getControllerVisual(t,"symbolSize"),p=qF(t,o,s,!0),d=a[0]-c/2,f={x:u.x,y:u.y};u.y=p,u.x=d;var g=Fh(l.indicatorLabelPoint,Bh(u,this.group)),y=l.indicatorLabel;y.attr("invisible",!1);var v=this._applyTransform("left",l.mainGroup),m="horizontal"===this._orient;y.setStyle({text:(n||"")+r.formatValueText(e),verticalAlign:m?v:"middle",align:m?"center":v});var x={x:d,y:p,style:{fill:h}},_={style:{x:g[0],y:g[1]}};if(r.ecModel.isAnimationEnabled()&&!this._firstShowIndicator){var b={duration:100,easing:"cubicInOut",additive:!0};u.x=f.x,u.y=f.y,u.animateTo(x,b),y.animateTo(_,b)}else u.attr(x),y.attr(_);this._firstShowIndicator=!1;var w=this._shapes.handleLabels;if(w)for(var S=0;Sr[1]&&(u[1]=1/0),e&&(u[0]===-1/0?this._showIndicator(l,u[1],"< ",a):u[1]===1/0?this._showIndicator(l,u[0],"> ",a):this._showIndicator(l,l,"≈ ",a));var h=this._hoverLinkDataIndices,c=[];(e||eG(n))&&(c=this._hoverLinkDataIndices=n.findTargetDataIndices(u));var p=function(t,e){var n={},i={};return r(t||[],n),r(e||[],i,n),[o(n),o(i)];function r(t,e,n){for(var i=0,r=t.length;i=0&&(r.dimension=o,i.push(r))}})),t.getData().setVisual("visualMeta",i)}}];function aG(t,e,n,i){for(var r=e.targetVisuals[i],o=kD.prepareVisualTypes(r),a={color:Ay(t.getData(),"color")},s=0,l=o.length;s0:t.splitNumber>0)&&!t.calculable?"piecewise":"continuous"})),t.registerAction(iG,rG),E(oG,(function(e){t.registerVisual(t.PRIORITY.VISUAL.COMPONENT,e)})),t.registerPreprocessor(lG))}function pG(t){t.registerComponentModel(HF),t.registerComponentView(QF),cG(t)}var dG=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n._pieceList=[],n}return n(e,t),e.prototype.optionUpdated=function(e,n){t.prototype.optionUpdated.apply(this,arguments),this.resetExtent();var i=this._mode=this._determineMode();this._pieceList=[],fG[this._mode].call(this,this._pieceList),this._resetSelected(e,n);var r=this.option.categories;this.resetVisual((function(t,e){"categories"===i?(t.mappingMethod="category",t.categories=T(r)):(t.dataExtent=this.getExtent(),t.mappingMethod="piecewise",t.pieceList=z(this._pieceList,(function(t){return t=T(t),"inRange"!==e&&(t.visual=null),t})))}))},e.prototype.completeVisualOption=function(){var e=this.option,n={},i=kD.listVisualTypes(),r=this.isCategory();function o(t,e,n){return t&&t[e]&&t[e].hasOwnProperty(n)}E(e.pieces,(function(t){E(i,(function(e){t.hasOwnProperty(e)&&(n[e]=1)}))})),E(n,(function(t,n){var i=!1;E(this.stateList,(function(t){i=i||o(e,t,n)||o(e.target,t,n)}),this),!i&&E(this.stateList,(function(t){(e[t]||(e[t]={}))[n]=OF(n,"inRange"===t?"active":"inactive",r)}))}),this),t.prototype.completeVisualOption.apply(this,arguments)},e.prototype._resetSelected=function(t,e){var n=this.option,i=this._pieceList,r=(e?n:t).selected||{};if(n.selected=r,E(i,(function(t,e){var n=this.getSelectedMapKey(t);r.hasOwnProperty(n)||(r[n]=!0)}),this),"single"===n.selectedMode){var o=!1;E(i,(function(t,e){var n=this.getSelectedMapKey(t);r[n]&&(o?r[n]=!1:o=!0)}),this)}},e.prototype.getItemSymbol=function(){return this.get("itemSymbol")},e.prototype.getSelectedMapKey=function(t){return"categories"===this._mode?t.value+"":t.index+""},e.prototype.getPieceList=function(){return this._pieceList},e.prototype._determineMode=function(){var t=this.option;return t.pieces&&t.pieces.length>0?"pieces":this.option.categories?"categories":"splitNumber"},e.prototype.setSelected=function(t){this.option.selected=T(t)},e.prototype.getValueState=function(t){var e=kD.findPieceIndex(t,this._pieceList);return null!=e&&this.option.selected[this.getSelectedMapKey(this._pieceList[e])]?"inRange":"outOfRange"},e.prototype.findTargetDataIndices=function(t){var e=[],n=this._pieceList;return this.eachTargetSeries((function(i){var r=[],o=i.getData();o.each(this.getDataDimensionIndex(o),(function(e,i){kD.findPieceIndex(e,n)===t&&r.push(i)}),this),e.push({seriesId:i.id,dataIndex:r})}),this),e},e.prototype.getRepresentValue=function(t){var e;if(this.isCategory())e=t.value;else if(null!=t.value)e=t.value;else{var n=t.interval||[];e=n[0]===-1/0&&n[1]===1/0?0:(n[0]+n[1])/2}return e},e.prototype.getVisualMeta=function(t){if(!this.isCategory()){var e=[],n=["",""],i=this,r=this._pieceList.slice();if(r.length){var o=r[0].interval[0];o!==-1/0&&r.unshift({interval:[-1/0,o]}),(o=r[r.length-1].interval[1])!==1/0&&r.push({interval:[o,1/0]})}else r.push({interval:[-1/0,1/0]});var a=-1/0;return E(r,(function(t){var e=t.interval;e&&(e[0]>a&&s([a,e[0]],"outOfRange"),s(e.slice()),a=e[1])}),this),{stops:e,outerColors:n}}function s(r,o){var a=i.getRepresentValue({interval:r});o||(o=i.getValueState(a));var s=t(a,o);r[0]===-1/0?n[0]=s:r[1]===1/0?n[1]=s:e.push({value:r[0],color:s},{value:r[1],color:s})}},e.type="visualMap.piecewise",e.defaultOption=kc(GF.defaultOption,{selected:null,minOpen:!1,maxOpen:!1,align:"auto",itemWidth:20,itemHeight:14,itemSymbol:"roundRect",pieces:null,categories:null,splitNumber:5,selectedMode:"multiple",itemGap:10,hoverLink:!0}),e}(GF),fG={splitNumber:function(t){var e=this.option,n=Math.min(e.precision,20),i=this.getExtent(),r=e.splitNumber;r=Math.max(parseInt(r,10),1),e.splitNumber=r;for(var o=(i[1]-i[0])/r;+o.toFixed(n)!==o&&n<5;)n++;e.precision=n,o=+o.toFixed(n),e.minOpen&&t.push({interval:[-1/0,i[0]],close:[0,0]});for(var a=0,s=i[0];a","≥"][e[0]]];t.text=t.text||this.formatValueText(null!=t.value?t.value:t.interval,!1,n)}),this)}};function gG(t,e){var n=t.inverse;("vertical"===t.orient?!n:n)&&e.reverse()}var yG=function(t){function e(){var n=null!==t&&t.apply(this,arguments)||this;return n.type=e.type,n}return n(e,t),e.prototype.doRender=function(){var t=this.group;t.removeAll();var e=this.visualMapModel,n=e.get("textGap"),i=e.textStyleModel,r=i.getFont(),o=i.getTextColor(),a=this._getItemAlign(),s=e.itemSize,l=this._getViewData(),u=l.endsText,h=it(e.get("showLabel",!0),!u),c=!e.get("selectedMode");u&&this._renderEndsText(t,u[0],s,h,a),E(l.viewPieceList,(function(i){var l=i.piece,u=new Br;u.onclick=W(this._onItemClick,this,l),this._enableHoverLink(u,i.indexInModelPieceList);var p=e.getRepresentValue(l);if(this._createItemSymbol(u,p,[0,0,s[0],s[1]],c),h){var d=this.visualMapModel.getValueState(p);u.add(new Xs({style:{x:"right"===a?-n:s[0]+n,y:s[1]/2,text:l.text,verticalAlign:"middle",align:a,font:r,fill:o,opacity:"outOfRange"===d?.5:1},silent:c}))}t.add(u)}),this),u&&this._renderEndsText(t,u[1],s,h,a),Ap(e.get("orient"),t,e.get("itemGap")),this.renderBackground(t),this.positionGroup(t)},e.prototype._enableHoverLink=function(t,e){var n=this;t.on("mouseover",(function(){return i("highlight")})).on("mouseout",(function(){return i("downplay")}));var i=function(t){var i=n.visualMapModel;i.option.hoverLink&&n.api.dispatchAction({type:t,batch:jF(i.findTargetDataIndices(e),i)})}},e.prototype._getItemAlign=function(){var t=this.visualMapModel,e=t.option;if("vertical"===e.orient)return ZF(t,this.api,t.itemSize);var n=e.align;return n&&"auto"!==n||(n="left"),n},e.prototype._renderEndsText=function(t,e,n,i,r){if(e){var o=new Br,a=this.visualMapModel.textStyleModel;o.add(new Xs({style:oc(a,{x:i?"right"===r?n[0]:0:n[0]/2,y:n[1]/2,verticalAlign:"middle",align:i?r:"center",text:e})})),t.add(o)}},e.prototype._getViewData=function(){var t=this.visualMapModel,e=z(t.getPieceList(),(function(t,e){return{piece:t,indexInModelPieceList:e}})),n=t.get("text"),i=t.get("orient"),r=t.get("inverse");return("horizontal"===i?r:!r)?e.reverse():n&&(n=n.slice().reverse()),{viewPieceList:e,endsText:n}},e.prototype._createItemSymbol=function(t,e,n,i){var r=Xy(this.getControllerVisual(e,"symbol"),n[0],n[1],n[2],n[3],this.getControllerVisual(e,"color"));r.silent=i,t.add(r)},e.prototype._onItemClick=function(t){var e=this.visualMapModel,n=e.option,i=n.selectedMode;if(i){var r=T(n.selected),o=e.getSelectedMapKey(t);"single"===i||!0===i?(r[o]=!0,E(r,(function(t,e){r[e]=e===o}))):r[o]=!r[o],this.api.dispatchAction({type:"selectDataRange",from:this.uid,visualMapId:this.visualMapModel.id,selected:r})}},e.type="visualMap.piecewise",e}(XF);function vG(t){t.registerComponentModel(dG),t.registerComponentView(yG),cG(t)}var mG={label:{enabled:!0},decal:{show:!1}},xG=Vo(),_G={};function bG(t,e){var n=t.getModel("aria");if(n.get("enabled")){var i=T(mG);C(i.label,t.getLocaleModel().get("aria"),!1),C(n.option,i,!1),function(){if(n.getModel("decal").get("show")){var e=yt();t.eachSeries((function(t){if(!t.isColorBySeries()){var n=e.get(t.type);n||(n={},e.set(t.type,n)),xG(t).scope=n}})),t.eachRawSeries((function(e){if(!t.isSeriesFiltered(e))if(X(e.enableAriaDecal))e.enableAriaDecal();else{var n=e.getData();if(e.isColorBySeries()){var i=pd(e.ecModel,e.name,_G,t.getSeriesCount()),r=n.getVisual("decal");n.setVisual("decal",u(r,i))}else{var o=e.getRawData(),a={},s=xG(e).scope;n.each((function(t){var e=n.getRawIndex(t);a[e]=t}));var l=o.count();o.each((function(t){var i=a[t],r=o.getName(t)||t+"",h=pd(e.ecModel,r,s,l),c=n.getItemVisual(i,"decal");n.setItemVisual(i,"decal",u(c,h))}))}}function u(t,e){var n=t?A(A({},e),t):e;return n.dirty=!0,n}}))}}(),function(){var i=e.getZr().dom;if(!i)return;var o=t.getLocaleModel().get("aria"),a=n.getModel("label");if(a.option=k(a.option,o),!a.get("enabled"))return;if(i.setAttribute("role","img"),a.get("description"))return void i.setAttribute("aria-label",a.get("description"));var s,l=t.getSeriesCount(),u=a.get(["data","maxCount"])||10,h=a.get(["series","maxCount"])||10,c=Math.min(l,h);if(l<1)return;var p=function(){var e=t.get("title");e&&e.length&&(e=e[0]);return e&&e.text}();s=p?r(a.get(["general","withTitle"]),{title:p}):a.get(["general","withoutTitle"]);var d=[];s+=r(l>1?a.get(["series","multiple","prefix"]):a.get(["series","single","prefix"]),{seriesCount:l}),t.eachSeries((function(e,n){if(n1?a.get(["series","multiple",o]):a.get(["series","single",o]),{seriesId:e.seriesIndex,seriesName:e.get("name"),seriesType:(_=e.subType,b=t.getLocaleModel().get(["series","typeNames"]),b[_]||b.chart)});var s=e.getData();if(s.count()>u)i+=r(a.get(["data","partialData"]),{displayCnt:u});else i+=a.get(["data","allData"]);for(var h=a.get(["data","separator","middle"]),p=a.get(["data","separator","end"]),f=a.get(["data","excludeDimensionId"]),g=[],y=0;y":"gt",">=":"gte","=":"eq","!=":"ne","<>":"ne"},MG=function(){function t(t){if(null==(this._condVal=U(t)?new RegExp(t):et(t)?t:null)){var e="";0,wo(e)}}return t.prototype.evaluate=function(t){var e=typeof t;return U(e)?this._condVal.test(t):!!j(e)&&this._condVal.test(t+"")},t}(),IG=function(){function t(){}return t.prototype.evaluate=function(){return this.value},t}(),TG=function(){function t(){}return t.prototype.evaluate=function(){for(var t=this.children,e=0;e2&&l.push(e),e=[t,n]}function f(t,n,i,r){BG(t,i)&&BG(n,r)||e.push(t,n,i,r,i,r)}function g(t,n,i,r,o,a){var s=Math.abs(n-t),l=4*Math.tan(s/4)/3,u=nM:C2&&l.push(e),l}function GG(t,e,n,i,r,o,a,s,l,u){if(BG(t,n)&&BG(e,i)&&BG(r,a)&&BG(o,s))l.push(a,s);else{var h=2/u,c=h*h,p=a-t,d=s-e,f=Math.sqrt(p*p+d*d);p/=f,d/=f;var g=n-t,y=i-e,v=r-a,m=o-s,x=g*g+y*y,_=v*v+m*m;if(x=0&&_-w*w=0)l.push(a,s);else{var S=[],M=[];wn(t,n,r,a,.5,S),wn(e,i,o,s,.5,M),GG(S[0],M[0],S[1],M[1],S[2],M[2],S[3],M[3],l,u),GG(S[4],M[4],S[5],M[5],S[6],M[6],S[7],M[7],l,u)}}}}function WG(t,e,n){var i=t[e],r=t[1-e],o=Math.abs(i/r),a=Math.ceil(Math.sqrt(o*n)),s=Math.floor(n/a);0===s&&(s=1,a=n);for(var l=[],u=0;u0)for(u=0;uMath.abs(u),c=WG([l,u],h?0:1,e),p=(h?s:u)/c.length,d=0;d1?null:new De(d*l+t,d*u+e)}function UG(t,e,n){var i=new De;De.sub(i,n,e),i.normalize();var r=new De;return De.sub(r,t,e),r.dot(i)}function ZG(t,e){var n=t[t.length-1];n&&n[0]===e[0]&&n[1]===e[1]||t.push(e)}function jG(t){var e=t.points,n=[],i=[];Ba(e,n,i);var r=new ze(n[0],n[1],i[0]-n[0],i[1]-n[1]),o=r.width,a=r.height,s=r.x,l=r.y,u=new De,h=new De;return o>a?(u.x=h.x=s+o/2,u.y=l,h.y=l+a):(u.y=h.y=l+a/2,u.x=s,h.x=s+o),function(t,e,n){for(var i=t.length,r=[],o=0;or,a=WG([i,r],o?0:1,e),s=o?"width":"height",l=o?"height":"width",u=o?"x":"y",h=o?"y":"x",c=t[s]/a.length,p=0;p0)for(var b=i/n,w=-i/2;w<=i/2;w+=b){var S=Math.sin(w),M=Math.cos(w),I=0;for(x=0;x0;l/=2){var u=0,h=0;(t&l)>0&&(u=1),(e&l)>0&&(h=1),s+=l*l*(3*u^h),0===h&&(1===u&&(t=l-1-t,e=l-1-e),a=t,t=e,e=a)}return s}function cW(t){var e=1/0,n=1/0,i=-1/0,r=-1/0,o=z(t,(function(t){var o=t.getBoundingRect(),a=t.getComputedTransform(),s=o.x+o.width/2+(a?a[4]:0),l=o.y+o.height/2+(a?a[5]:0);return e=Math.min(s,e),n=Math.min(l,n),i=Math.max(s,i),r=Math.max(l,r),[s,l]}));return z(o,(function(o,a){return{cp:o,z:hW(o[0],o[1],e,n,i,r),path:t[a]}})).sort((function(t,e){return t.z-e.z})).map((function(t){return t.path}))}function pW(t){return $G(t.path,t.count)}function dW(t){return Y(t[0])}function fW(t,e){for(var n=[],i=t.length,r=0;r=0;r--)if(!n[r].many.length){var l=n[s].many;if(l.length<=1){if(!s)return n;s=0}o=l.length;var u=Math.ceil(o/2);n[r].many=l.slice(u,o),n[s].many=l.slice(0,u),s++}return n}var gW={clone:function(t){for(var e=[],n=1-Math.pow(1-t.path.style.opacity,1/t.count),i=0;i0){var s,l,u=i.getModel("universalTransition").get("delay"),h=Object.assign({setToFinal:!0},a);dW(t)&&(s=t,l=e),dW(e)&&(s=e,l=t);for(var c=s?s===t:t.length>e.length,p=s?fW(l,s):fW(c?e:t,[c?t:e]),d=0,f=0;f1e4))for(var r=n.getIndices(),o=0;o0&&i.group.traverse((function(t){t instanceof ks&&!t.animators.length&&t.animateFrom({style:{opacity:0}},r)}))}))}function TW(t){var e=t.getModel("universalTransition").get("seriesKey");return e||t.id}function CW(t){return Y(t)?t.sort().join(","):t}function DW(t){if(t.hostModel)return t.hostModel.getModel("universalTransition").get("divideShape")}function AW(t,e){for(var n=0;n=0&&r.push({dataGroupId:e.oldDataGroupIds[n],data:e.oldData[n],divide:DW(e.oldData[n]),groupIdDim:t.dimension})})),E(To(t.to),(function(t){var i=AW(n.updatedSeries,t);if(i>=0){var r=n.updatedSeries[i].getData();o.push({dataGroupId:e.oldDataGroupIds[i],data:r,divide:DW(r),groupIdDim:t.dimension})}})),r.length>0&&o.length>0&&IW(r,o,i)}(t,i,n,e)}));else{var o=function(t,e){var n=yt(),i=yt(),r=yt();return E(t.oldSeries,(function(e,n){var o=t.oldDataGroupIds[n],a=t.oldData[n],s=TW(e),l=CW(s);i.set(l,{dataGroupId:o,data:a}),Y(s)&&E(s,(function(t){r.set(t,{key:l,dataGroupId:o,data:a})}))})),E(e.updatedSeries,(function(t){if(t.isUniversalTransitionEnabled()&&t.isAnimationEnabled()){var e=t.get("dataGroupId"),o=t.getData(),a=TW(t),s=CW(a),l=i.get(s);if(l)n.set(s,{oldSeries:[{dataGroupId:l.dataGroupId,divide:DW(l.data),data:l.data}],newSeries:[{dataGroupId:e,divide:DW(o),data:o}]});else if(Y(a)){var u=[];E(a,(function(t){var e=i.get(t);e.data&&u.push({dataGroupId:e.dataGroupId,divide:DW(e.data),data:e.data})})),u.length&&n.set(s,{oldSeries:u,newSeries:[{dataGroupId:e,data:o,divide:DW(o)}]})}else{var h=r.get(a);if(h){var c=n.get(h.key);c||(c={oldSeries:[{dataGroupId:h.dataGroupId,data:h.data,divide:DW(h.data)}],newSeries:[]},n.set(h.key,c)),c.newSeries.push({dataGroupId:e,data:o,divide:DW(o)})}}}})),n}(i,n);E(o.keys(),(function(t){var n=o.get(t);IW(n.oldSeries,n.newSeries,e)}))}E(n.updatedSeries,(function(t){t[_g]&&(t[_g]=!1)}))}for(var a=t.getSeries(),s=i.oldSeries=[],l=i.oldDataGroupIds=[],u=i.oldData=[],h=0;h +
+

核心业绩指标

+

2024年度 / 单位:人民币

+
+
+ 营业收入 + 23.4亿 + +18.2% YoY +
+
+ 净利润 + 5.8亿 + +22.5% YoY +
+
+ 毛利率 + 42.3% + +2.1pp +
+
+ ROE + 16.8% + -0.5pp +
+
+
+ +``` + +```css +.kpi-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr)); + gap: clamp(0.75rem, 2vw, 1.5rem); + margin-top: clamp(1rem, 3vh, 2rem); +} + +.kpi-card { + background: var(--card-bg, rgba(255, 255, 255, 0.05)); + border: 1px solid var(--border-color, rgba(0, 0, 0, 0.08)); + border-radius: clamp(6px, 1vw, 12px); + padding: clamp(0.75rem, 2vw, 1.5rem); + display: flex; + flex-direction: column; + gap: clamp(0.25rem, 0.5vh, 0.5rem); +} + +.kpi-label { + font-size: clamp(0.65rem, 1vw, 0.85rem); + color: var(--text-secondary); + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.kpi-value { + font-size: clamp(1.5rem, 3.5vw, 2.5rem); + font-weight: 700; + font-family: var(--font-display); + color: var(--text-primary); + line-height: 1.1; +} + +.kpi-trend { + font-size: clamp(0.6rem, 0.9vw, 0.8rem); + font-weight: 500; +} + +.kpi-trend.positive { color: var(--color-positive, #16a34a); } +.kpi-trend.negative { color: var(--color-negative, #dc2626); } +.kpi-trend.neutral { color: var(--text-secondary); } + +/* A股惯例:涨为红、跌为绿。如需切换,覆盖以下变量 */ +/* --color-positive: #dc2626; --color-negative: #16a34a; */ +``` + +### KPI 计数动画 + +```javascript +class KPICounter { + constructor(el) { + this.el = el; + this.target = parseFloat(el.dataset.count) || 0; + this.duration = 1200; + } + + animate() { + const start = performance.now(); + const step = (now) => { + const progress = Math.min((now - start) / this.duration, 1); + const eased = 1 - Math.pow(1 - progress, 3); // ease-out-cubic + const current = this.target * eased; + this.el.textContent = formatCN(current); + if (progress < 1) requestAnimationFrame(step); + }; + requestAnimationFrame(step); + } +} + +// 在 IntersectionObserver 回调中触发 +entry.target.querySelectorAll('.kpi-value[data-count]').forEach(el => { + new KPICounter(el).animate(); +}); +``` + +--- + +## 2. Data Table (数据表格) + +适用于:财务数据对比、同业比较、历史趋势 + +```html +
+
+

财务数据摘要

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
指标2022A2023A2024A2025E
营业收入(亿)156.3189.7234.0278.5
净利润(亿)38.247.558.069.2
毛利率(%)39.140.842.343.5
EPS(元)2.152.683.273.90
PE(倍)28.524.321.117.7
+
+

数据来源:公司年报、券商一致预期 | E = 预测值

+
+
+``` + +```css +.table-wrapper { + overflow-x: auto; + margin-top: clamp(0.75rem, 2vh, 1.5rem); + -webkit-overflow-scrolling: touch; +} + +.data-table { + width: 100%; + border-collapse: collapse; + font-size: clamp(0.7rem, 1.2vw, 0.95rem); + font-family: var(--font-body); +} + +.data-table th { + font-size: clamp(0.6rem, 1vw, 0.8rem); + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--text-secondary); + padding: clamp(0.4rem, 1vh, 0.75rem) clamp(0.5rem, 1.5vw, 1rem); + border-bottom: 2px solid var(--border-color, rgba(0, 0, 0, 0.15)); + text-align: left; +} + +.data-table th.col-num, +.data-table td.num { + text-align: right; + font-variant-numeric: tabular-nums; +} + +.data-table td { + padding: clamp(0.35rem, 0.8vh, 0.6rem) clamp(0.5rem, 1.5vw, 1rem); + border-bottom: 1px solid var(--border-color, rgba(0, 0, 0, 0.06)); + color: var(--text-primary); +} + +.data-table tbody tr:hover { + background: var(--row-hover, rgba(0, 0, 0, 0.02)); +} + +.data-table .highlight { + color: var(--accent); + font-weight: 600; +} + +.data-table .separator td { + border-top: 2px solid var(--border-color, rgba(0, 0, 0, 0.1)); +} + +.table-note { + font-size: clamp(0.55rem, 0.8vw, 0.7rem); + color: var(--text-secondary); + margin-top: clamp(0.5rem, 1vh, 0.75rem); + opacity: 0.7; +} + +/* 深色主题表格适配 */ +@media (prefers-color-scheme: dark) { + .data-table th { border-bottom-color: rgba(255, 255, 255, 0.15); } + .data-table td { border-bottom-color: rgba(255, 255, 255, 0.06); } + .data-table tbody tr:hover { background: rgba(255, 255, 255, 0.03); } +} +``` + +### 内容密度规范 + +| 表格类型 | 最大行数 | 最大列数 | +|----------|---------|---------| +| 财务摘要 | 6-8 行 | 5-6 列 | +| 同业对比 | 4-6 行 | 6-7 列 | +| 估值对比 | 5-6 行 | 4-5 列 | + +**超出限制时拆分为多个 slide,不要压缩字号。** + +--- + +## 3. Timeline (时间线) + +适用于:公司发展历程、项目里程碑、政策演变 + +```html +
+
+

发展里程碑

+
+
+ 2018 +
+
+

成立与首轮融资

+

完成A轮融资2亿元,核心团队组建完成

+
+
+
+ 2020 +
+
+

产品商业化

+

首款产品上市,当年营收突破5000万

+
+
+
+ 2023 +
+
+

IPO上市

+

科创板上市,市值突破100亿

+
+
+
+ 2025E +
+
+

全球化布局

+

海外营收占比目标达30%

+
+
+
+
+
+``` + +```css +.timeline { + display: flex; + flex-direction: column; + gap: clamp(0.5rem, 1.5vh, 1.25rem); + margin-top: clamp(0.75rem, 2vh, 1.5rem); + padding-left: clamp(3rem, 8vw, 6rem); + position: relative; +} + +/* 纵轴线 */ +.timeline::before { + content: ''; + position: absolute; + left: clamp(1.2rem, 3.5vw, 2.5rem); + top: 0; + bottom: 0; + width: 2px; + background: var(--border-color, rgba(0, 0, 0, 0.12)); +} + +.timeline-item { + position: relative; + display: flex; + align-items: flex-start; + gap: clamp(0.5rem, 1.5vw, 1rem); +} + +.timeline-date { + position: absolute; + left: calc(-1 * clamp(3rem, 8vw, 6rem)); + width: clamp(2.5rem, 7vw, 5rem); + font-size: clamp(0.65rem, 1vw, 0.85rem); + font-weight: 700; + color: var(--accent); + text-align: right; + padding-top: 0.15em; +} + +.timeline-dot { + position: absolute; + left: calc(-1 * clamp(3rem, 8vw, 6rem) + clamp(2.7rem, 7.3vw, 5.3rem)); + width: clamp(8px, 1vw, 12px); + height: clamp(8px, 1vw, 12px); + border-radius: 50%; + background: var(--accent); + border: 2px solid var(--bg-primary, #fff); + box-shadow: 0 0 0 2px var(--accent); + flex-shrink: 0; + margin-top: 0.3em; +} + +.timeline-dot.active { + box-shadow: 0 0 0 2px var(--accent), 0 0 0 5px rgba(var(--accent-rgb, 37, 99, 235), 0.2); +} + +.timeline-content h4 { + font-size: clamp(0.8rem, 1.3vw, 1.05rem); + font-weight: 600; + color: var(--text-primary); + margin-bottom: clamp(0.15rem, 0.3vh, 0.3rem); +} + +.timeline-content p { + font-size: clamp(0.65rem, 1vw, 0.85rem); + color: var(--text-secondary); + line-height: 1.4; +} + +/* 时间线最多 4-5 个节点 */ +``` + +--- + +## 4. Comparison (对比分析) + +适用于:可比公司、方案对比、产品差异 + +```html +
+
+

可比公司估值对比

+
+ +
+

可比A

+
+
PE (TTM)25.1x
+
PB4.2x
+
ROE16.5%
+
营收增速+15.8%
+
+
+
+

可比B

+
+
PE (TTM)18.7x
+
PB2.9x
+
ROE15.1%
+
营收增速+11.2%
+
+
+
+
+
+``` + +```css +.comparison-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); + gap: clamp(0.75rem, 2vw, 1.5rem); + margin-top: clamp(0.75rem, 2vh, 1.5rem); +} + +.comp-card { + background: var(--card-bg, rgba(0, 0, 0, 0.02)); + border: 1px solid var(--border-color, rgba(0, 0, 0, 0.08)); + border-radius: clamp(6px, 1vw, 12px); + padding: clamp(0.75rem, 2vw, 1.5rem); +} + +.comp-card.featured { + border-color: var(--accent); + border-width: 2px; + background: var(--card-bg-featured, rgba(var(--accent-rgb, 37, 99, 235), 0.04)); +} + +.comp-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: clamp(0.5rem, 1vh, 0.75rem); + padding-bottom: clamp(0.4rem, 0.8vh, 0.6rem); + border-bottom: 1px solid var(--border-color, rgba(0, 0, 0, 0.08)); +} + +.comp-header h3 { + font-size: clamp(0.85rem, 1.3vw, 1.1rem); + font-weight: 700; + color: var(--text-primary); +} + +.comp-tag { + font-size: clamp(0.5rem, 0.7vw, 0.65rem); + background: var(--accent); + color: var(--bg-primary, #fff); + padding: 0.15em 0.5em; + border-radius: 3px; + font-weight: 500; +} + +.comp-row { + display: flex; + justify-content: space-between; + align-items: center; + padding: clamp(0.25rem, 0.5vh, 0.4rem) 0; + font-size: clamp(0.65rem, 1vw, 0.85rem); +} + +.comp-row span { color: var(--text-secondary); } +.comp-row strong { + color: var(--text-primary); + font-variant-numeric: tabular-nums; +} + +/* 最多 3 列对比卡片,每卡片 4-5 行指标 */ +``` + +--- + +## 5. Chart + Text Split (图文分栏) + +适用于:数据解读、趋势分析配说明 + +```html +
+
+
+
+

营收持续高增长

+
    +
  • 收入增速 23.4%,连续4年保持20%+增长
  • +
  • 核心产品市占率提升至 18.5%
  • +
  • 海外业务贡献 12% 增量
  • +
+
+
+
+
+
+
+
+``` + +```css +.split-layout { + display: grid; + grid-template-columns: 1fr 1fr; + gap: clamp(1rem, 3vw, 2.5rem); + align-items: center; + height: 100%; +} + +.split-text h2 { + font-size: clamp(1.2rem, 2.8vw, 2rem); + margin-bottom: clamp(0.5rem, 1.5vh, 1rem); +} + +.insight-list { + list-style: none; + padding: 0; + display: flex; + flex-direction: column; + gap: clamp(0.4rem, 1vh, 0.75rem); +} + +.insight-list li { + font-size: clamp(0.75rem, 1.2vw, 1rem); + line-height: 1.5; + color: var(--text-secondary); + padding-left: clamp(0.75rem, 1.5vw, 1.25rem); + position: relative; +} + +.insight-list li::before { + content: ''; + position: absolute; + left: 0; + top: 0.55em; + width: clamp(4px, 0.5vw, 6px); + height: clamp(4px, 0.5vw, 6px); + border-radius: 50%; + background: var(--accent); +} + +.insight-list li strong { + color: var(--text-primary); + font-weight: 600; +} + +/* 窄屏堆叠 */ +@media (max-width: 768px) { + .split-layout { + grid-template-columns: 1fr; + } +} +``` + +--- + +## 布局选择指南 + +| 页面用途 | 推荐布局 | 最大内容量 | +|----------|---------|-----------| +| 业绩概览 | KPI Dashboard | 4-6 个指标卡片 | +| 财务数据 | Data Table | 8 行 x 6 列 | +| 发展历程 | Timeline | 4-5 个节点 | +| 同业对比 | Comparison | 3 列 x 5 行指标 | +| 趋势解读 | Chart + Text Split | 1 图 + 3-4 条要点 | +| 收入拆解 | Chart (全幅) | 1 个图表 + 标题 | +| 投资亮点 | KPI + 简述 | 3-4 个亮点 | + +**内容超限时拆分为多个 slide。绝对不要缩小字号或减少间距来容纳更多内容。** diff --git a/fund-slides/references/html-template.md b/fund-slides/references/html-template.md new file mode 100644 index 0000000..4d9f6e8 --- /dev/null +++ b/fund-slides/references/html-template.md @@ -0,0 +1,417 @@ +# HTML Presentation Template + +Reference architecture for generating slide presentations. Every presentation follows this structure. + +## Base HTML Structure + +```html + + + + + + Presentation Title + + + + + + + + + + + +
+ + + + + +
+

Presentation Title

+

Subtitle or author

+
+ +
+
+

Slide Title

+

Content...

+
+
+ + + + + + +``` + +## Required JavaScript Features + +Every presentation must include: + +1. **SlidePresentation Class** — Main controller with: + - Keyboard navigation (arrows, space, page up/down) + - Touch/swipe support + - Mouse wheel navigation + - Progress bar updates + - Navigation dots + +2. **Intersection Observer** — For scroll-triggered animations: + - Add `.visible` class when slides enter viewport + - Trigger CSS transitions efficiently + +3. **Optional Enhancements** (match to chosen style): + - Custom cursor with trail + - Particle system background (canvas) + - Parallax effects + - 3D tilt on hover + - Magnetic buttons + - Counter animations + +4. **Inline Editing** (only if user opted in during Phase 1 — skip entirely if they said No): + - Edit toggle button (hidden by default, revealed via hover hotzone or `E` key) + - Auto-save to localStorage + - Export/save file functionality + - See "Inline Editing Implementation" section below + +## Inline Editing Implementation (Opt-In Only) + +**If the user chose "No" for inline editing in Phase 1, do NOT generate any edit-related HTML, CSS, or JS.** + +**Do NOT use CSS `~` sibling selector for hover-based show/hide.** The CSS-only approach (`edit-hotzone:hover ~ .edit-toggle`) fails because `pointer-events: none` on the toggle button breaks the hover chain: user hovers hotzone -> button becomes visible -> mouse moves toward button -> leaves hotzone -> button disappears before click. + +**Required approach: JS-based hover with 400ms delay timeout.** + +HTML: +```html +
+ +``` + +CSS (visibility controlled by JS classes only): +```css +/* Do NOT use CSS ~ sibling selector for this! + pointer-events: none breaks the hover chain. + Must use JS with delay timeout. */ +.edit-hotzone { + position: fixed; top: 0; left: 0; + width: 80px; height: 80px; + z-index: 10000; + cursor: pointer; +} +.edit-toggle { + opacity: 0; + pointer-events: none; + transition: opacity 0.3s ease; + z-index: 10001; +} +.edit-toggle.show, +.edit-toggle.active { + opacity: 1; + pointer-events: auto; +} +``` + +JS (three interaction methods): +```javascript +// 1. Click handler on the toggle button +document.getElementById('editToggle').addEventListener('click', () => { + editor.toggleEditMode(); +}); + +// 2. Hotzone hover with 400ms grace period +const hotzone = document.querySelector('.edit-hotzone'); +const editToggle = document.getElementById('editToggle'); +let hideTimeout = null; + +hotzone.addEventListener('mouseenter', () => { + clearTimeout(hideTimeout); + editToggle.classList.add('show'); +}); +hotzone.addEventListener('mouseleave', () => { + hideTimeout = setTimeout(() => { + if (!editor.isActive) editToggle.classList.remove('show'); + }, 400); +}); +editToggle.addEventListener('mouseenter', () => { + clearTimeout(hideTimeout); +}); +editToggle.addEventListener('mouseleave', () => { + hideTimeout = setTimeout(() => { + if (!editor.isActive) editToggle.classList.remove('show'); + }, 400); +}); + +// 3. Hotzone direct click +hotzone.addEventListener('click', () => { + editor.toggleEditMode(); +}); + +// 4. Keyboard shortcut (E key, skip when editing text) +document.addEventListener('keydown', (e) => { + if ((e.key === 'e' || e.key === 'E') && !e.target.getAttribute('contenteditable')) { + editor.toggleEditMode(); + } +}); +``` + +## Image Pipeline (Skip If No Images) + +If user chose "No images" in Phase 1, skip this entirely. If images were provided, process them before generating HTML. + +**Dependency:** `pip install Pillow` + +### Image Processing + +```python +from PIL import Image, ImageDraw + +# Circular crop (for logos on modern/clean styles) +def crop_circle(input_path, output_path): + img = Image.open(input_path).convert('RGBA') + w, h = img.size + size = min(w, h) + left, top = (w - size) // 2, (h - size) // 2 + img = img.crop((left, top, left + size, top + size)) + mask = Image.new('L', (size, size), 0) + ImageDraw.Draw(mask).ellipse([0, 0, size, size], fill=255) + img.putalpha(mask) + img.save(output_path, 'PNG') + +# Resize (for oversized images that inflate HTML) +def resize_max(input_path, output_path, max_dim=1200): + img = Image.open(input_path) + img.thumbnail((max_dim, max_dim), Image.LANCZOS) + img.save(output_path, quality=85) +``` + +| Situation | Operation | +|-----------|-----------| +| Square logo on rounded aesthetic | `crop_circle()` | +| Image > 1MB | `resize_max(max_dim=1200)` | +| Wrong aspect ratio | Manual crop with `img.crop()` | + +Save processed images with `_processed` suffix. Never overwrite originals. + +### Image Placement + +**Use direct file paths** (not base64) — presentations are viewed locally: + +```html + +Screenshot +``` + +```css +.slide-image { + max-width: 100%; + max-height: min(50vh, 400px); + object-fit: contain; + border-radius: 8px; +} +.slide-image.screenshot { + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); +} +.slide-image.logo { + max-height: min(30vh, 200px); +} +``` + +**Adapt border/shadow colors to match the chosen style's accent.** Never repeat the same image on multiple slides (except logos on title + closing). + +**Placement patterns:** Logo centered on title slide. Screenshots in two-column layouts with text. Full-bleed images as slide backgrounds with text overlay (use sparingly). + +--- + +## Financial Data Integration + +When the presentation includes financial data (charts, KPIs, tables), add these utilities: + +### Chinese Number Formatting (Required for Financial Slides) + +```javascript +/* Include in +``` + +Chart containers must init on slide visibility. See [financial-charts.md](financial-charts.md) for complete configuration reference. + +### Trend Indicators (CSS Only, No Emoji) + +```css +/* Up/down arrows as CSS pseudo-elements — never use emoji */ +.trend-up::before { + content: ''; + display: inline-block; + width: 0; height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-bottom: 6px solid var(--color-positive, #dc2626); + margin-right: 0.3em; + vertical-align: middle; +} +.trend-down::before { + content: ''; + display: inline-block; + width: 0; height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 6px solid var(--color-negative, #16a34a); + margin-right: 0.3em; + vertical-align: middle; +} +.trend-flat::before { + content: '--'; + color: var(--text-secondary); + margin-right: 0.3em; +} +``` + +--- + +## Code Quality + +**Comments:** Every section needs clear comments explaining what it does and how to modify it. + +**Accessibility:** +- Semantic HTML (`
`, `