ea 0.3.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +3 -0
- data/TODO.complete/01-t-xref-parsing.md +91 -0
- data/TODO.complete/02-per-label-geometry.md +50 -0
- data/TODO.complete/03-object-properties-constraints.md +57 -0
- data/TODO.complete/04-operation-params.md +37 -0
- data/TODO.complete/05-pdata-flag-matrix.md +52 -0
- data/TODO.complete/06-emf-image-rendering.md +34 -0
- data/TODO.complete/07-auxiliary-tables.md +47 -0
- data/TODO.complete/10-mdg-stereotype-registry.md +40 -0
- data/TODO.complete/11-gml-xsd-generation.md +42 -0
- data/TODO.complete/13-shapescript-interpreter.md +28 -0
- data/TODO.complete/20-cli-diff.md +46 -0
- data/TODO.complete/21-cli-render.md +26 -0
- data/TODO.complete/22-cli-export.md +29 -0
- data/TODO.complete/23-cli-mdg.md +23 -0
- data/TODO.complete/30-headerlines-ocp-refactor.md +72 -0
- data/TODO.complete/31-public-send-cleanup.md +61 -0
- data/TODO.complete/32-spec-coverage.md +33 -0
- data/TODO.complete/33-blocked-parity-gaps.md +41 -0
- data/TODO.complete/36-stereotype-icon-wiring.md +32 -0
- data/TODO.complete/37-cli-lint.md +32 -0
- data/TODO.complete/38-cli-query.md +26 -0
- data/TODO.complete/39-cli-info.md +23 -0
- data/TODO.complete/40-ocl-evaluator.md +31 -0
- data/TODO.complete/41-round-trip-spec.md +18 -0
- data/TODO.complete/42-html-diff-report.md +18 -0
- data/TODO.complete/43-json-schema-export.md +20 -0
- data/TODO.complete/44-remaining-qea-tables.md +40 -0
- data/TODO.complete/45-shapescript-extensions.md +25 -0
- data/TODO.complete/46-xsd-consolidation.md +20 -0
- data/TODO.complete/47-headerlines-legacy-removal.md +20 -0
- data/TODO.complete/STATUS.md +109 -0
- data/TODO.diagrams/01-svg-measurement-harness.md +31 -0
- data/TODO.diagrams/01-xmi-extension-elements-parsing.md +67 -0
- data/TODO.diagrams/02-diagram-element-rich-model.md +61 -0
- data/TODO.diagrams/02-polygon-over-rendering.md +29 -0
- data/TODO.diagrams/03-ea-style-svg-emitter.md +70 -0
- data/TODO.diagrams/03-text-over-rendering.md +30 -0
- data/TODO.diagrams/04-connector-routing-from-soid-eoid.md +55 -0
- data/TODO.diagrams/04-rect-under-rendering.md +33 -0
- data/TODO.diagrams/05-canvas-dimension-parity.md +51 -0
- data/TODO.diagrams/05-marker-rendering-per-relationship-type.md +49 -0
- data/TODO.diagrams/06-connector-labels.md +49 -0
- data/TODO.diagrams/06-group-layering-parity.md +39 -0
- data/TODO.diagrams/07-canvas-size-and-viewbox.md +39 -0
- data/TODO.diagrams/07-text-content-fidelity.md +65 -0
- data/TODO.diagrams/08-qea-direct-pipeline.md +46 -0
- data/TODO.diagrams/08-visual-regression-harness.md +34 -0
- data/TODO.diagrams/09-cli-render-all-diagrams.md +25 -0
- data/TODO.diagrams/10-stereotype-color-config.md +29 -0
- data/TODO.diagrams/11-elkrb-auto-layout-integration.md +53 -0
- data/TODO.diagrams/12-connector-labels.md +40 -0
- data/TODO.diagrams/12-per-entity-svg-layer-ordering.md +24 -0
- data/TODO.diagrams/13-marker-polygon-vs-path-dispatch.md +20 -0
- data/TODO.diagrams/13-per-text-type-font-sizes.md +33 -0
- data/TODO.diagrams/14-center-header-text.md +33 -0
- data/TODO.diagrams/14-filter-diagram-frame-elements.md +18 -0
- data/TODO.diagrams/15-deep-dead-code-audit.md +47 -0
- data/TODO.diagrams/15-per-element-font-from-style.md +24 -0
- data/TODO.diagrams/16-canvas-marker-extent.md +30 -0
- data/TODO.diagrams/16-document-remaining-parity-gaps.md +91 -0
- data/TODO.diagrams/17-italic-abstract-classes.md +28 -0
- data/TODO.diagrams/17-remaining-parity-gaps.md +90 -0
- data/TODO.diagrams/18-canvas-from-image-bounds.md +20 -0
- data/TODO.diagrams/18-property-lookup-index.md +42 -0
- data/TODO.diagrams/19-connector-sx-sy-routing.md +27 -0
- data/TODO.diagrams/19-replace-respond-to-with-is-a.md +31 -0
- data/TODO.diagrams/20-split-labels-emitter.md +56 -0
- data/TODO.diagrams/20-visibility-glyph-font-encoding.md +27 -0
- data/TODO.diagrams/21-aggregation-navigability-arrow.md +21 -0
- data/TODO.diagrams/21-auto-generated-legend-block.md +65 -0
- data/TODO.diagrams/22-ghost-element-discriminator.md +57 -0
- data/TODO.diagrams/22-style-based-path-grouping.md +28 -0
- data/TODO.diagrams/23-marker-polygon-deduplication.md +47 -0
- data/TODO.diagrams/23-multiplicity-label-positioning.md +29 -0
- data/TODO.diagrams/24-marker-anchor-structural.md +35 -0
- data/TODO.diagrams/24-track-marker-anchors-structurally.md +66 -0
- data/TODO.diagrams/24-truncate-properties-to-fit-box.md +24 -0
- data/TODO.diagrams/26-phantom-general-parent-rendering.md +59 -0
- data/TODO.diagrams/27-path-grouping-mode-detection.md +43 -0
- data/TODO.diagrams/28-architecture-cleanup-batch.md +47 -0
- data/TODO.diagrams/30-decompose-elements-groups-for.md +52 -0
- data/TODO.diagrams/32-examples-coverage-batch.md +78 -0
- data/TODO.diagrams/36-instance-specification-model.md +42 -0
- data/TODO.diagrams/37-element-icon-decorations.md +41 -0
- data/TODO.diagrams/38-html-note-and-receptions.md +32 -0
- data/TODO.diagrams/39-property-stereotype-discriminator.md +40 -0
- data/TODO.diagrams/40-standalone-1-discriminator.md +38 -0
- data/TODO.diagrams/41-xmi-to-svg-pipeline.md +113 -0
- data/TODO.diagrams/42-close-all-parity-deltas.md +69 -0
- data/TODO.diagrams/43-marker-deduplication-strategy.md +54 -0
- data/TODO.diagrams/44-element-icon-decorations.md +34 -0
- data/TODO.diagrams/45-phantom-parent-class-boxes.md +40 -0
- data/TODO.diagrams/46-user-drawn-legend-swatches.md +44 -0
- data/TODO.diagrams/47-attribute-line-fidelity.md +72 -0
- data/TODO.diagrams/48-spec-coverage-critical-emitter-components.md +45 -0
- data/TODO.diagrams/49-spec-coverage-orchestrators.md +25 -0
- data/TODO.diagrams/50-examples-parity.md +85 -0
- data/TODO.diagrams/51-property-oy-gap-and-remaining-gaps.md +48 -0
- data/TODO.diagrams/52-marker-registration-architecture.md +89 -0
- data/TODO.diagrams/53-remaining-example-gaps.md +86 -0
- data/TODO.diagrams/54-display-name-nested-classes.md +40 -0
- data/TODO.diagrams/55-visibility-icon-discriminator.md +58 -0
- data/TODO.diagrams/56-package-contents-rendering.md +148 -0
- data/TODO.diagrams/57-instance-specification-model.md +100 -0
- data/TODO.diagrams/58-domain-model-note-text.md +67 -0
- data/TODO.diagrams/59-classes-arrow-discriminator.md +57 -0
- data/TODO.diagrams/60-testschema-association-marker.md +40 -0
- data/TODO.diagrams/61-legend-block-rendering.md +55 -0
- data/TODO.diagrams/61-plateau-parity-gaps.md +59 -0
- data/TODO.diagrams/62-ghost-element-rendering.md +56 -0
- data/TODO.diagrams/63-qualified-name-wrap.md +36 -0
- data/TODO.diagrams/64-property-stereotype-labels.md +22 -0
- data/TODO.diagrams/65-path-coordinate-frame.md +62 -0
- data/TODO.diagrams/67-path-coordinate-frame.md +62 -0
- data/TODO.diagrams/68-inherited-attributes.md +65 -0
- data/TODO.diagrams/69-package-anchor-conditional.md +29 -0
- data/TODO.diagrams/70-mdg-technology-support.md +68 -0
- data/TODO.diagrams/71-off-canvas-parent-ghost.md +45 -0
- data/TODO.diagrams/72-basic-attr-divider-paths.md +39 -0
- data/TODO.diagrams/73-plateau-polygon-gap.md +69 -0
- data/TODO.diagrams/74-plateau-rect-gap.md +22 -0
- data/TODO.diagrams/75-plateau-text-gap.md +39 -0
- data/TODO.diagrams/76-basic-poly-path-gaps.md +41 -0
- data/TODO.diagrams/77-basic-text-overrender.md +40 -0
- data/TODO.diagrams/78-headerlines-ocp-refactor.md +65 -0
- data/TODO.diagrams/79-architecture-backlog.md +65 -0
- data/TODO.diagrams/80-basic-triangle-polygons.md +51 -0
- data/TODO.diagrams/81-plateau-path-overrender.md +53 -0
- data/TODO.diagrams/82-appearance-canvas-offset.md +54 -0
- data/TODO.diagrams/83-3d-diagram-subtitle.md +58 -0
- data/TODO.diagrams/84-canvas-offset-mismatches.md +61 -0
- data/TODO.diagrams/85-phantom-property-overrender.md +95 -0
- data/TODO.diagrams/86-foreign-package-rule.md +62 -0
- data/TODO.diagrams/87-internal-tech-encryption.md +80 -0
- data/TODO.diagrams/EXAMPLES_STATUS.md +88 -0
- data/TODO.diagrams/README.md +69 -0
- data/TODO.diagrams/STATUS.md +73 -0
- data/TODO.fixup/01-default-grouped-paths.md +34 -0
- data/TODO.fixup/02-marker-consolidation-per-connector.md +20 -0
- data/TODO.fixup/03-diagram-font-inference.md +28 -0
- data/TODO.fixup/04-extract-bounds-calculator.md +25 -0
- data/TODO.fixup/05-marker-registry-ocp.md +32 -0
- data/TODO.fixup/06-connector-path-bend-routing.md +28 -0
- data/TODO.fixup/07-edge-attachment-formula.md +22 -0
- data/TODO.fixup/08-visual-diff-harness.md +28 -0
- data/TODO.fixup/09-extract-element-compartments.md +34 -0
- data/TODO.fixup/10-canvas-width-overshoot-fix.md +20 -0
- data/TODO.fixup/11-layer-sequencer-extraction.md +18 -0
- data/TODO.fixup/12-path-style-harmony.md +23 -0
- data/TODO.fixup/13-datatype-stereotype-fallback.md +28 -0
- data/TODO.fixup/14-ea-exe-reverse-engineering-notes.md +56 -0
- data/TODO.fixup/15-enumeration-literal-rendering.md +30 -0
- data/TODO.fixup/16-operation-compartment-rendering.md +42 -0
- data/TODO.fixup/17-path-count-calibration.md +27 -0
- data/TODO.fixup/18-polygon-count-calibration.md +32 -0
- data/TODO.fixup/19-rect-count-undershoot-investigation.md +40 -0
- data/TODO.fixup/20-stereotype-color-from-classifier.md +18 -0
- data/TODO.fixup/21-visibility-filter-for-properties.md +24 -0
- data/TODO.fixup/22-multiplicity-display-rule-calibration.md +25 -0
- data/TODO.fixup/23-diagram-frame-title-element.md +31 -0
- data/TODO.fixup/24-note-element-rendering.md +23 -0
- data/TODO.fixup/25-ea-exe-disassembly-findings.md +177 -0
- data/TODO.fixup/26-svg-renderer-architecture.md +78 -0
- data/TODO.fixup/27-svg-element-emitters-disassembly.md +135 -0
- data/TODO.fixup/28-geometry-parser-identification.md +57 -0
- data/TODO.fixup/29-qea-svg-xmi-triple-comparison.md +185 -0
- data/TODO.fixup/30-theme-system-stub.md +46 -0
- data/TODO.fixup/31-theme-value-object-registry.md +17 -0
- data/TODO.fixup/32-styleex-on-diagram-model.md +22 -0
- data/TODO.fixup/33-text-encoding-decimals-rotation.md +29 -0
- data/TODO.fixup/34-per-type-fill-via-theme.md +18 -0
- data/TODO.fixup/35-stroke-width-per-theme.md +7 -0
- data/TODO.fixup/36-qea-rect-coord-normalization.md +24 -0
- data/TODO.fixup/37-package-shape-rendering.md +22 -0
- data/TODO.fixup/38-note-element-rendering.md +15 -0
- data/TODO.fixup/39-styleex-flag-honoring.md +25 -0
- data/TODO.fixup/40-connector-dashed-lines.md +15 -0
- data/TODO.fixup/41-diagram-frame-showborder-detection.md +23 -0
- data/TODO.fixup/42-textrenderer-centralization.md +10 -0
- data/TODO.fixup/43-colorresolver-unification.md +24 -0
- data/TODO.fixup/44-theme-aware-textrenderer.md +17 -0
- data/TODO.fixup/45-theme-aware-fontresolver.md +22 -0
- data/TODO.fixup/46-style-parameterized-by-theme.md +21 -0
- data/TODO.fixup/47-canvas-frame-inset.md +19 -0
- data/TODO.fixup/48-background-rect-format.md +15 -0
- data/TODO.fixup/49-all-samples-integration-test.md +17 -0
- data/TODO.fixup/50-svg-emitter-architecture-docs.md +33 -0
- data/TODO.fixup/51-promote-theme-to-ea-namespace.md +28 -0
- data/TODO.fixup/52-theme-definition-integrated-fills.md +26 -0
- data/TODO.fixup/53-theme-registry-yaml-loading.md +50 -0
- data/TODO.fixup/54-diagram-theme-api.md +50 -0
- data/TODO.fixup/55-update-eaemitter-to-ea-theme.md +23 -0
- data/TODO.fixup/56-theme-yaml-files.md +65 -0
- data/TODO.fixup/57-theme-specs-and-integration.md +27 -0
- data/TODO.fixup/58-ea-entry-point-theme-autoload.md +20 -0
- data/TODO.fixup/59-thread-theme-through-all-renderers.md +29 -0
- data/TODO.fixup/60-cli-theme-option.md +22 -0
- data/TODO.fixup/61-theme-validation.md +28 -0
- data/TODO.fixup/62-theme-builder-dsl.md +31 -0
- data/TODO.fixup/63-theme-integration-rendering-spec.md +24 -0
- data/TODO.fixup/64-theme-writeback-styleex.md +21 -0
- data/TODO.fixup/65-remove-dead-eaemitter-theme-files.md +30 -0
- data/TODO.fixup/66-styleex-writeback.md +22 -0
- data/TODO.fixup/67-delete-dead-code.md +28 -0
- data/TODO.fixup/68-figure-parity-status.md +82 -0
- data/TODO.fixup/69-package-polygon-rendering.md +54 -0
- data/TODO.fixup/70-tagged-values-compartment.md +39 -0
- data/TODO.fixup/71-auto-detect-theme-from-xmi.md +37 -0
- data/TODO.fixup/72-sample-exports-as-regression-specs.md +37 -0
- data/TODO.fixup/73-delete-dead-transformations.md +14 -0
- data/TODO.fixup/74-delete-dead-diagram-renderers.md +18 -0
- data/TODO.fixup/75-visibility-legend-icons.md +23 -0
- data/TODO.fixup/76-plateau-text-undershoot.md +27 -0
- data/TODO.fixup/77-canvas-frame-margins.md +28 -0
- data/TODO.fixup/78-note-element-rendering.md +30 -0
- data/TODO.fixup/79-operation-compartment-rendering.md +27 -0
- data/TODO.fixup/80-tagged-value-stereotype-visibility.md +37 -0
- data/TODO.fixup/81-figure-parity-current-state.md +63 -0
- data/config/qea_schema.yml +356 -0
- data/config/stereotype_colors.yml +15 -0
- data/config/themes/119.yml +98 -0
- data/config/themes/default.yml +14 -0
- data/examples/exports/20251010_current_plateau_v5/UML_EA.DTD +6856 -0
- data/examples/exports/20251010_current_plateau_v5/model.xml +96709 -0
- data/examples/exports/ArcGISWorkspace_template/UML_EA.DTD +6856 -0
- data/examples/exports/ArcGISWorkspace_template/model.xml +1427 -0
- data/examples/exports/UmlModel_template/UML_EA.DTD +6856 -0
- data/examples/exports/UmlModel_template/model.xml +23 -0
- data/examples/exports/basic/UML_EA.DTD +6856 -0
- data/examples/exports/basic/model.xml +8039 -0
- data/examples/exports/simple/UML_EA.DTD +6856 -0
- data/examples/exports/simple/model.xml +585 -0
- data/examples/exports/simple_example/UML_EA.DTD +6856 -0
- data/examples/exports/simple_example/model.xml +23 -0
- data/examples/exports/test/UML_EA.DTD +6856 -0
- data/examples/exports/test/model.xml +1638 -0
- data/examples/qea/basic.qea +0 -0
- data/frontend/README.md +51 -0
- data/frontend/dist/app.iife.js +24 -0
- data/frontend/dist/style.css +1 -0
- data/frontend/index.html +26 -0
- data/frontend/package-lock.json +2359 -0
- data/frontend/package.json +26 -0
- data/frontend/src/App.vue +59 -0
- data/frontend/src/app.ts +8 -0
- data/frontend/src/components/AppHeader.vue +127 -0
- data/frontend/src/components/AppSidebar.vue +119 -0
- data/frontend/src/components/ClassDetails.vue +247 -0
- data/frontend/src/components/DiagramView.vue +79 -0
- data/frontend/src/components/PackageDetails.vue +92 -0
- data/frontend/src/components/PackageTreeNode.vue +64 -0
- data/frontend/src/components/SearchResults.vue +48 -0
- data/frontend/src/components/WelcomeView.vue +87 -0
- data/frontend/src/shims-vue.d.ts +5 -0
- data/frontend/src/stores/dataStore.ts +79 -0
- data/frontend/src/stores/uiStore.ts +167 -0
- data/frontend/src/styles/main.css +1566 -0
- data/frontend/src/types.ts +221 -0
- data/frontend/tests/e2e/__screenshots__/new-dark-mode.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-package-details.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-search-modal.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-sidebar-collapsed.png +0 -0
- data/frontend/tests/e2e/__screenshots__/new-welcome.png +0 -0
- data/frontend/tests/e2e/render.spec.ts +188 -0
- data/frontend/tsconfig.json +20 -0
- data/frontend/vite.config.ts +26 -0
- data/frontend/vitest.config.ts +8 -0
- data/lib/ea/cli/app.rb +62 -1
- data/lib/ea/cli/command/diagrams.rb +37 -28
- data/lib/ea/cli/command/diff.rb +46 -0
- data/lib/ea/cli/command/export.rb +80 -0
- data/lib/ea/cli/command/info.rb +75 -0
- data/lib/ea/cli/command/lint.rb +48 -0
- data/lib/ea/cli/command/mdg.rb +98 -0
- data/lib/ea/cli/command/query.rb +34 -0
- data/lib/ea/cli/command/render.rb +135 -0
- data/lib/ea/cli/command/svg.rb +43 -6
- data/lib/ea/cli/command.rb +7 -0
- data/lib/ea/diagram/display_config.rb +184 -0
- data/lib/ea/diagram.rb +4 -41
- data/lib/ea/diff/change.rb +30 -0
- data/lib/ea/diff/comparator.rb +82 -0
- data/lib/ea/diff/html_reporter.rb +91 -0
- data/lib/ea/diff.rb +15 -0
- data/lib/ea/export/json/generator.rb +42 -0
- data/lib/ea/export/json.rb +12 -0
- data/lib/ea/export/json_schema/generator.rb +77 -0
- data/lib/ea/export/json_schema.rb +12 -0
- data/lib/ea/export/plantuml/generator.rb +73 -0
- data/lib/ea/export/plantuml.rb +12 -0
- data/lib/ea/export/xmi/generator.rb +77 -0
- data/lib/ea/export/xmi.rb +11 -0
- data/lib/ea/export/xsd/class_mapping.rb +65 -0
- data/lib/ea/export/xsd/generator.rb +142 -0
- data/lib/ea/export/xsd/namespace_registry.rb +82 -0
- data/lib/ea/export/xsd.rb +19 -0
- data/lib/ea/export.rb +14 -0
- data/lib/ea/image/emf_renderer.rb +42 -0
- data/lib/ea/image.rb +12 -0
- data/lib/ea/lint/engine.rb +30 -0
- data/lib/ea/lint/lint_rule.rb +38 -0
- data/lib/ea/lint/offense.rb +18 -0
- data/lib/ea/lint/rules/cyclic_generalization.rb +62 -0
- data/lib/ea/lint/rules/duplicate_name.rb +28 -0
- data/lib/ea/lint/rules/missing_stereotype.rb +35 -0
- data/lib/ea/lint/rules/naming_convention.rb +44 -0
- data/lib/ea/lint/rules/orphan_element.rb +28 -0
- data/lib/ea/lint/rules.rb +14 -0
- data/lib/ea/lint.rb +13 -0
- data/lib/ea/mdg/document.rb +120 -0
- data/lib/ea/mdg/loader.rb +118 -0
- data/lib/ea/mdg/registry.rb +98 -0
- data/lib/ea/mdg/stereotype_alias_registry.rb +77 -0
- data/lib/ea/mdg/xml/applies_to.rb +18 -0
- data/lib/ea/mdg/xml/apply.rb +18 -0
- data/lib/ea/mdg/xml/content.rb +18 -0
- data/lib/ea/mdg/xml/documentation.rb +24 -0
- data/lib/ea/mdg/xml/stereotype.rb +28 -0
- data/lib/ea/mdg/xml/stereotypes.rb +18 -0
- data/lib/ea/mdg/xml/tag.rb +28 -0
- data/lib/ea/mdg/xml/tagged_values.rb +18 -0
- data/lib/ea/mdg/xml/technology.rb +28 -0
- data/lib/ea/mdg/xml/uml_profile.rb +22 -0
- data/lib/ea/mdg/xml/uml_profiles.rb +18 -0
- data/lib/ea/mdg/xml.rb +24 -0
- data/lib/ea/mdg.rb +25 -0
- data/lib/ea/model/classifier.rb +4 -0
- data/lib/ea/model/constraint.rb +24 -0
- data/lib/ea/model/diagram.rb +85 -0
- data/lib/ea/model/diagram_connector.rb +53 -1
- data/lib/ea/model/diagram_element.rb +44 -0
- data/lib/ea/model/document.rb +47 -2
- data/lib/ea/model/ghost_label.rb +32 -0
- data/lib/ea/model/instance_specification.rb +34 -0
- data/lib/ea/model/legend.rb +43 -0
- data/lib/ea/model/legend_item.rb +26 -0
- data/lib/ea/model/note.rb +28 -0
- data/lib/ea/model/operation.rb +2 -0
- data/lib/ea/model/property.rb +2 -0
- data/lib/ea/model/relationship.rb +2 -0
- data/lib/ea/model/signal.rb +14 -0
- data/lib/ea/model/slot.rb +19 -0
- data/lib/ea/model.rb +8 -0
- data/lib/ea/ocl/evaluator.rb +94 -0
- data/lib/ea/ocl/nodes.rb +30 -0
- data/lib/ea/ocl/parser.rb +133 -0
- data/lib/ea/ocl/unsupported_error.rb +7 -0
- data/lib/ea/ocl.rb +13 -0
- data/lib/ea/qea/factory/document_builder.rb +24 -10
- data/lib/ea/qea/factory/generalization_builder.rb +9 -11
- data/lib/ea/qea/infrastructure/table_reader.rb +9 -0
- data/lib/ea/qea/models/ea_author.rb +35 -0
- data/lib/ea/qea/models/ea_glossary.rb +34 -0
- data/lib/ea/qea/models/ea_image.rb +53 -0
- data/lib/ea/qea/models/ea_implement.rb +32 -0
- data/lib/ea/qea/models/ea_list.rb +42 -0
- data/lib/ea/qea/models/ea_object_effort.rb +34 -0
- data/lib/ea/qea/models/ea_object_problem.rb +37 -0
- data/lib/ea/qea/models/ea_object_require.rb +34 -0
- data/lib/ea/qea/models/ea_object_resource.rb +34 -0
- data/lib/ea/qea/models/ea_object_risk.rb +34 -0
- data/lib/ea/qea/models/ea_object_scenario.rb +34 -0
- data/lib/ea/qea/models/ea_object_test.rb +35 -0
- data/lib/ea/qea/models/ea_object_trx.rb +34 -0
- data/lib/ea/qea/models/ea_operation.rb +7 -0
- data/lib/ea/qea/models/ea_palette.rb +30 -0
- data/lib/ea/qea/models/ea_palette_item.rb +36 -0
- data/lib/ea/qea/models/ea_phase.rb +40 -0
- data/lib/ea/qea/models/ea_role_constraint.rb +32 -0
- data/lib/ea/qea/models/ea_secrypt.rb +34 -0
- data/lib/ea/qea/models/ea_version.rb +39 -0
- data/lib/ea/qea/models/ea_xref.rb +11 -1
- data/lib/ea/qea/models.rb +19 -0
- data/lib/ea/qea/services/database_loader.rb +22 -1
- data/lib/ea/query/builder.rb +108 -0
- data/lib/ea/query.rb +9 -0
- data/lib/ea/render/image_converter.rb +101 -0
- data/lib/ea/render.rb +10 -0
- data/lib/ea/shapescript/parser.rb +208 -0
- data/lib/ea/shapescript/renderer.rb +74 -0
- data/lib/ea/shapescript/shape.rb +34 -0
- data/lib/ea/shapescript.rb +24 -0
- data/lib/ea/sources/qea/adapter.rb +22 -5
- data/lib/ea/sources/qea/classifier_builder.rb +184 -7
- data/lib/ea/sources/qea/diagram_builder.rb +352 -24
- data/lib/ea/sources/qea/id_normalizer.rb +16 -1
- data/lib/ea/sources/qea/instance_builder.rb +113 -0
- data/lib/ea/sources/qea/legend_builder.rb +137 -0
- data/lib/ea/sources/qea/note_builder.rb +58 -0
- data/lib/ea/sources/qea/object_classifier_map.rb +6 -1
- data/lib/ea/sources/qea/operation_builder.rb +1 -0
- data/lib/ea/sources/qea/package_builder.rb +16 -0
- data/lib/ea/sources/qea/relationship_builder.rb +21 -5
- data/lib/ea/sources/qea/tagged_value_builder.rb +28 -9
- data/lib/ea/sources/qea/xref/legend_definition.rb +35 -0
- data/lib/ea/sources/qea/xref/parser.rb +150 -0
- data/lib/ea/sources/qea/xref/property_definition.rb +29 -0
- data/lib/ea/sources/qea/xref/record.rb +41 -0
- data/lib/ea/sources/qea/xref/stereotype_application.rb +37 -0
- data/lib/ea/sources/qea/xref.rb +27 -0
- data/lib/ea/sources/qea.rb +4 -0
- data/lib/ea/sources/xmi/adapter.rb +80 -2
- data/lib/ea/sources/xmi/annotation_builder.rb +1 -1
- data/lib/ea/sources/xmi/classifier_builder.rb +10 -1
- data/lib/ea/sources/xmi/diagram_builder.rb +242 -45
- data/lib/ea/sources/xmi/extension_elements.rb +74 -0
- data/lib/ea/sources/xmi/extension_geometry_parser.rb +124 -0
- data/lib/ea/sources/xmi/extension_style_parser.rb +91 -0
- data/lib/ea/sources/xmi/note_builder.rb +46 -0
- data/lib/ea/sources/xmi/property_builder.rb +9 -0
- data/lib/ea/sources/xmi/stereotype_builder.rb +54 -0
- data/lib/ea/sources/xmi/tag_builder.rb +45 -0
- data/lib/ea/sources/xmi/umldi_keyword_extractor.rb +87 -0
- data/lib/ea/sources/xmi.rb +7 -0
- data/lib/ea/spa/output/sharded_multi_file_strategy.rb +18 -3
- data/lib/ea/spa/output/single_file_strategy.rb +8 -2
- data/lib/ea/spa/output/strategy.rb +34 -0
- data/lib/ea/svg/connector_router.rb +134 -0
- data/lib/ea/svg/ea_emitter/background.rb +15 -0
- data/lib/ea/svg/ea_emitter/bounds_calculator.rb +142 -0
- data/lib/ea/svg/ea_emitter/canvas.rb +88 -0
- data/lib/ea/svg/ea_emitter/color_resolver.rb +56 -0
- data/lib/ea/svg/ea_emitter/compartment/attributes.rb +28 -0
- data/lib/ea/svg/ea_emitter/compartment/constraints.rb +30 -0
- data/lib/ea/svg/ea_emitter/compartment/enum_literals.rb +86 -0
- data/lib/ea/svg/ea_emitter/compartment/header.rb +32 -0
- data/lib/ea/svg/ea_emitter/compartment/header_divider.rb +57 -0
- data/lib/ea/svg/ea_emitter/compartment/instance_slots.rb +96 -0
- data/lib/ea/svg/ea_emitter/compartment/instance_underline.rb +67 -0
- data/lib/ea/svg/ea_emitter/compartment/note_body.rb +52 -0
- data/lib/ea/svg/ea_emitter/compartment/note_text.rb +102 -0
- data/lib/ea/svg/ea_emitter/compartment/operations.rb +38 -0
- data/lib/ea/svg/ea_emitter/compartment/package_contents.rb +72 -0
- data/lib/ea/svg/ea_emitter/compartment/package_from_parent.rb +136 -0
- data/lib/ea/svg/ea_emitter/compartment/shape.rb +82 -0
- data/lib/ea/svg/ea_emitter/compartment/tagged_values.rb +30 -0
- data/lib/ea/svg/ea_emitter/compartment.rb +58 -0
- data/lib/ea/svg/ea_emitter/connectors.rb +84 -0
- data/lib/ea/svg/ea_emitter/diagram_frame.rb +143 -0
- data/lib/ea/svg/ea_emitter/document.rb +35 -0
- data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +117 -0
- data/lib/ea/svg/ea_emitter/element/attribute_renderer.rb +119 -0
- data/lib/ea/svg/ea_emitter/element/bcol_decoder.rb +29 -0
- data/lib/ea/svg/ea_emitter/element/compartment_geometry.rb +113 -0
- data/lib/ea/svg/ea_emitter/element/constraint_renderer.rb +53 -0
- data/lib/ea/svg/ea_emitter/element/divider_renderer.rb +17 -0
- data/lib/ea/svg/ea_emitter/element/enumeration_literal_renderer.rb +34 -0
- data/lib/ea/svg/ea_emitter/element/filter.rb +44 -0
- data/lib/ea/svg/ea_emitter/element/hand_draw_shape_renderer.rb +77 -0
- data/lib/ea/svg/ea_emitter/element/header_line_pipeline.rb +43 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/instance_spec.rb +27 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/name.rb +76 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/parent_ghost.rb +25 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider/stereotype_label.rb +68 -0
- data/lib/ea/svg/ea_emitter/element/header_line_provider.rb +19 -0
- data/lib/ea/svg/ea_emitter/element/header_lines.rb +27 -0
- data/lib/ea/svg/ea_emitter/element/header_renderer.rb +48 -0
- data/lib/ea/svg/ea_emitter/element/icon_renderer.rb +109 -0
- data/lib/ea/svg/ea_emitter/element/legend_renderer.rb +177 -0
- data/lib/ea/svg/ea_emitter/element/note_shape_renderer.rb +112 -0
- data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +100 -0
- data/lib/ea/svg/ea_emitter/element/package_shape_renderer.rb +181 -0
- data/lib/ea/svg/ea_emitter/element/row_icon_renderer.rb +156 -0
- data/lib/ea/svg/ea_emitter/element/shape_renderer.rb +17 -0
- data/lib/ea/svg/ea_emitter/element/stereotype_icon_renderer.rb +82 -0
- data/lib/ea/svg/ea_emitter/element/tagged_value_renderer.rb +50 -0
- data/lib/ea/svg/ea_emitter/element/text_escape.rb +20 -0
- data/lib/ea/svg/ea_emitter/element.rb +37 -0
- data/lib/ea/svg/ea_emitter/elements.rb +357 -0
- data/lib/ea/svg/ea_emitter/font_resolver.rb +111 -0
- data/lib/ea/svg/ea_emitter/ghost_labels.rb +66 -0
- data/lib/ea/svg/ea_emitter/label/end_label.rb +266 -0
- data/lib/ea/svg/ea_emitter/label/midpoint_label.rb +101 -0
- data/lib/ea/svg/ea_emitter/label/registry.rb +50 -0
- data/lib/ea/svg/ea_emitter/label.rb +23 -0
- data/lib/ea/svg/ea_emitter/labels.rb +130 -0
- data/lib/ea/svg/ea_emitter/layer.rb +20 -0
- data/lib/ea/svg/ea_emitter/layer_sequencer.rb +93 -0
- data/lib/ea/svg/ea_emitter/marker/arrow_path.rb +52 -0
- data/lib/ea/svg/ea_emitter/marker/diamond.rb +57 -0
- data/lib/ea/svg/ea_emitter/marker/kind.rb +35 -0
- data/lib/ea/svg/ea_emitter/marker/open_triangle.rb +27 -0
- data/lib/ea/svg/ea_emitter/marker/package_import.rb +39 -0
- data/lib/ea/svg/ea_emitter/marker/plus.rb +40 -0
- data/lib/ea/svg/ea_emitter/marker/registry.rb +42 -0
- data/lib/ea/svg/ea_emitter/marker.rb +37 -0
- data/lib/ea/svg/ea_emitter/markers.rb +404 -0
- data/lib/ea/svg/ea_emitter/render_context.rb +52 -0
- data/lib/ea/svg/ea_emitter/style.rb +15 -0
- data/lib/ea/svg/ea_emitter/text_renderer.rb +92 -0
- data/lib/ea/svg/ea_emitter.rb +51 -0
- data/lib/ea/svg/parity/checker.rb +105 -0
- data/lib/ea/svg/parity/source.rb +59 -0
- data/lib/ea/svg/parity/suite.rb +113 -0
- data/lib/ea/svg/parity.rb +14 -0
- data/lib/ea/svg/stereotype_color_resolver.rb +50 -0
- data/lib/ea/svg.rb +4 -15
- data/lib/ea/theme/definition.rb +176 -0
- data/lib/ea/theme/loader.rb +125 -0
- data/lib/ea/theme/registry.rb +96 -0
- data/lib/ea/theme.rb +37 -0
- data/lib/ea/transformations.rb +5 -88
- data/lib/ea/version.rb +4 -1
- data/lib/ea.rb +14 -4
- data/lib/tasks/svg_bench.rake +87 -0
- data/lutaml-uml-0.5.1.gem +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes-list.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-1-themes.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-2-gradients.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-3-colors.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance-fonts.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-4-appearance.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-5-behavior.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram-6-sequence.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-1-diagram.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-2-objects.png +0 -0
- data/reference-docs/enterprise-architect-appearance-dialogs/appearance-3-links.png +0 -0
- metadata +473 -26
- data/lib/ea/diagram/configuration.rb +0 -379
- data/lib/ea/diagram/element_renderers/base_renderer.rb +0 -77
- data/lib/ea/diagram/element_renderers/class_renderer.rb +0 -323
- data/lib/ea/diagram/element_renderers/connector_renderer.rb +0 -41
- data/lib/ea/diagram/element_renderers/package_renderer.rb +0 -61
- data/lib/ea/diagram/element_renderers.rb +0 -43
- data/lib/ea/diagram/extractor.rb +0 -566
- data/lib/ea/diagram/layout_engine.rb +0 -170
- data/lib/ea/diagram/path_builder.rb +0 -202
- data/lib/ea/diagram/style_parser.rb +0 -42
- data/lib/ea/diagram/style_resolver.rb +0 -291
- data/lib/ea/diagram/svg_renderer.rb +0 -274
- data/lib/ea/diagram/util.rb +0 -73
- data/lib/ea/svg/bounds_calculator.rb +0 -74
- data/lib/ea/svg/connector_path.rb +0 -138
- data/lib/ea/svg/element_box.rb +0 -256
- data/lib/ea/svg/renderer.rb +0 -77
- data/lib/ea/svg/style_resolver.rb +0 -72
- data/lib/ea/transformations/configuration.rb +0 -333
- data/lib/ea/transformations/format_registry.rb +0 -366
- data/lib/ea/transformations/parsers/base_parser.rb +0 -482
- data/lib/ea/transformations/parsers/qea_parser.rb +0 -401
- data/lib/ea/transformations/parsers/xmi_parser.rb +0 -243
- data/lib/ea/transformations/transformation_engine.rb +0 -390
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
# Emits the diagram frame: outer border + name tab. EA renders
|
|
7
|
+
# every diagram with a 1px black border forming a rectangle
|
|
8
|
+
# inset 6px from the canvas edge, plus a "tab" polygon in the
|
|
9
|
+
# upper-left containing the diagram type + name text.
|
|
10
|
+
#
|
|
11
|
+
# Layout:
|
|
12
|
+
# ┌───┐
|
|
13
|
+
# │tab│──────────────────┐
|
|
14
|
+
# └───┘ │
|
|
15
|
+
# │
|
|
16
|
+
# (diagram contents) │
|
|
17
|
+
# │
|
|
18
|
+
# ┌──────────────────────┘
|
|
19
|
+
#
|
|
20
|
+
# Format observed in EA reference SVGs:
|
|
21
|
+
# <g style="...stroke-width:1;stroke-linecap:square;
|
|
22
|
+
# stroke-linejoin:miter; fill:#000000;
|
|
23
|
+
# fill-opacity:0.00; stroke:#000000;
|
|
24
|
+
# stroke-opacity:1.00">
|
|
25
|
+
# <path d="M 6 6 L 6 H-6 W-6 W-6 6 L 6 6"/>
|
|
26
|
+
# </g>
|
|
27
|
+
# <g style="...fill:#FFFFFF;...">
|
|
28
|
+
# <polygon points="6 26 X 26 X+13 12 X+13 6 6 6 6 26"/>
|
|
29
|
+
# </g>
|
|
30
|
+
# <g style="...">
|
|
31
|
+
# <text x="11" y="19" ...>class DiagramName</text>
|
|
32
|
+
# </g>
|
|
33
|
+
class DiagramFrame
|
|
34
|
+
attr_reader :canvas, :theme
|
|
35
|
+
|
|
36
|
+
def initialize(canvas:, theme: nil)
|
|
37
|
+
@canvas = canvas
|
|
38
|
+
@theme = theme || Ea::Theme::Registry.default
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def layers(diagram)
|
|
42
|
+
return [] if canvas.nil?
|
|
43
|
+
|
|
44
|
+
[
|
|
45
|
+
border_layer(canvas),
|
|
46
|
+
tab_layer(canvas, diagram),
|
|
47
|
+
tab_label_layer(canvas, diagram)
|
|
48
|
+
].compact
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def border_layer(canvas)
|
|
54
|
+
d = border_path_d(canvas)
|
|
55
|
+
body = %(<path d="#{d}" shape-rendering="auto"/>)
|
|
56
|
+
Layer.new(style_key: :frame_border, style: BORDER_STYLE, body: body)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def tab_layer(canvas, diagram)
|
|
60
|
+
points = tab_points(canvas, diagram)
|
|
61
|
+
body = %(<polygon points="#{points}" shape-rendering="auto" style="fill-rule:evenodd;"/>)
|
|
62
|
+
Layer.new(style_key: :frame_tab, style: TAB_STYLE, body: body)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def tab_label_layer(canvas, diagram)
|
|
66
|
+
label = tab_label(diagram)
|
|
67
|
+
return nil unless label
|
|
68
|
+
|
|
69
|
+
body = build_label_text(label)
|
|
70
|
+
Layer.new(style_key: :frame_label, style: LABEL_STYLE, body: body)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def border_path_d(canvas)
|
|
74
|
+
inset = theme.frame.inset
|
|
75
|
+
right = canvas.width - inset
|
|
76
|
+
bottom = canvas.height - inset
|
|
77
|
+
"M #{inset} #{inset} L #{inset} #{bottom} L #{right} #{bottom} L #{right} #{inset} L #{inset} #{inset}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def tab_points(canvas, diagram)
|
|
81
|
+
label_width = tab_label_width(diagram)
|
|
82
|
+
x1 = theme.frame.inset
|
|
83
|
+
x2 = x1 + label_width
|
|
84
|
+
x3 = x2 + theme.frame.tab_slant
|
|
85
|
+
top1 = theme.frame.inset
|
|
86
|
+
top2 = theme.frame.inset + theme.frame.tab_height
|
|
87
|
+
"#{x1} #{top2} #{x2} #{top2} #{x3} #{top1 + theme.frame.tab_height - theme.frame.tab_slant} #{x3} #{top1} #{x1} #{top1} #{x1} #{top2}"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def tab_label(diagram)
|
|
91
|
+
type = diagram_label_prefix(diagram)
|
|
92
|
+
return nil unless type
|
|
93
|
+
|
|
94
|
+
"#{type} #{diagram.name}"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def diagram_label_prefix(diagram)
|
|
98
|
+
case diagram.diagram_type&.downcase
|
|
99
|
+
when "logical" then "class"
|
|
100
|
+
when "package" then "pkg"
|
|
101
|
+
when "usecase" then "uc"
|
|
102
|
+
when "sequence" then "seq"
|
|
103
|
+
when "activity" then "act"
|
|
104
|
+
when "statechart" then "sm"
|
|
105
|
+
when "deployment" then "dep"
|
|
106
|
+
when "component" then "comp"
|
|
107
|
+
when "object" then "object"
|
|
108
|
+
when "custom", "conceptual" then nil
|
|
109
|
+
else diagram.diagram_type&.downcase
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def tab_label_width(diagram)
|
|
114
|
+
label = tab_label(diagram)
|
|
115
|
+
return theme.package.default_tab_width unless label
|
|
116
|
+
|
|
117
|
+
text_width = Ea::Svg::EaEmitter::TextRenderer.estimate_width(
|
|
118
|
+
label, theme.font_size || 7, theme.text_width_factor
|
|
119
|
+
).round
|
|
120
|
+
text_width + theme.frame.tab_padding
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def build_label_text(label)
|
|
124
|
+
TextRenderer.new(
|
|
125
|
+
content: label,
|
|
126
|
+
x: theme.frame.tab_label_x, y: theme.frame.tab_label_y,
|
|
127
|
+
family: theme.font_family || "Calibri",
|
|
128
|
+
size: theme.font_size || 7,
|
|
129
|
+
weight: theme.text_weight_bold,
|
|
130
|
+
size_unit: theme.font_size_unit,
|
|
131
|
+
fill: "#000000",
|
|
132
|
+
stroke_in_text: theme.stroke_in_text_color,
|
|
133
|
+
width_factor: theme.text_width_factor
|
|
134
|
+
).to_svg
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
BORDER_STYLE = "stroke-width:1;stroke-linecap:square;stroke-linejoin:miter; fill:#000000;fill-opacity:0.00; stroke:#000000; stroke-opacity:1.00"
|
|
138
|
+
TAB_STYLE = "stroke-width:1;stroke-linecap:square;stroke-linejoin:miter; fill:#FFFFFF;fill-opacity:1.00; stroke:#000000; stroke-opacity:1.00"
|
|
139
|
+
LABEL_STYLE = "stroke-width:1;stroke-linecap:square;stroke-linejoin:miter; fill:#000000;fill-opacity:1.00; stroke:#000000; stroke-opacity:0.00"
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
# Top-level orchestrator: emits a complete standalone SVG
|
|
7
|
+
# document matching EA's encoding. Bound computation and
|
|
8
|
+
# layer sequencing delegated to BoundsCalculator and
|
|
9
|
+
# LayerSequencer respectively (SRP).
|
|
10
|
+
class Document
|
|
11
|
+
BUILD_ID = "1624"
|
|
12
|
+
|
|
13
|
+
attr_reader :diagram, :model_index, :frame, :document
|
|
14
|
+
|
|
15
|
+
def initialize(diagram, model_index:, frame: true, document: nil, **_options)
|
|
16
|
+
@diagram = diagram
|
|
17
|
+
@model_index = model_index
|
|
18
|
+
@frame = frame
|
|
19
|
+
@document = document
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def render
|
|
23
|
+
canvas = Canvas.from(diagram, model_index: model_index)
|
|
24
|
+
layers = LayerSequencer.new(diagram, model_index: model_index,
|
|
25
|
+
canvas: canvas, frame: frame,
|
|
26
|
+
document: document)
|
|
27
|
+
.layers
|
|
28
|
+
.reject { |s| s.nil? || s.empty? }
|
|
29
|
+
|
|
30
|
+
%(<?xml version="1.0" encoding="UTF-8" standalone="no"?>\n<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">\n\n<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="#{canvas.width_cm}" height="#{canvas.height_cm}" viewBox="#{canvas.view_box}">\n<title></title>\n<desc>Created with Enterprise Architect (Build: #{BUILD_ID}) 2</desc>\n#{layers.join("\n")}\n</svg>)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Element
|
|
7
|
+
# Builds the text representation of a single property line
|
|
8
|
+
# for the attribute compartment. Encapsulates the four EA
|
|
9
|
+
# rendering rules:
|
|
10
|
+
#
|
|
11
|
+
# 1. Visibility marker (+, -, #, ~).
|
|
12
|
+
# 2. Namespace prefix on properties inherited from a
|
|
13
|
+
# classifier in a different package ("core::mimeType").
|
|
14
|
+
# 3. Primitive type name stripping ("xs::double" → "double").
|
|
15
|
+
# 4. Multiplicity shorthand ("[2..2]" → "[2]") and
|
|
16
|
+
# `{ordered}` modifier.
|
|
17
|
+
#
|
|
18
|
+
# Stateless: each call returns a fresh line String. Pass a
|
|
19
|
+
# `Lookup` to enable cross-classifier resolution (namespace
|
|
20
|
+
# prefix). Without a lookup, the line is rendered as-is
|
|
21
|
+
# (backwards-compatible).
|
|
22
|
+
class AttributeLineBuilder
|
|
23
|
+
# XSD primitive types whose namespace prefix EA drops in
|
|
24
|
+
# the rendered attribute line. The full set is not yet
|
|
25
|
+
# reverse-engineered — leave empty for now so we never
|
|
26
|
+
# wrongly strip a prefix. TODO-D 47 will populate this
|
|
27
|
+
# once verified per-diagram.
|
|
28
|
+
PRIMITIVE_TYPES = Set.new([]).freeze
|
|
29
|
+
|
|
30
|
+
attr_reader :property, :host, :lookup
|
|
31
|
+
|
|
32
|
+
# property - the Ea::Model::Property to render
|
|
33
|
+
# host - the Ea::Model::Classifier whose compartment
|
|
34
|
+
# we're rendering (determines "inherited" status)
|
|
35
|
+
# lookup - object responding to `#call(id) -> Classifier`
|
|
36
|
+
# used to resolve the property's declaring
|
|
37
|
+
# classifier (defaults to no lookup).
|
|
38
|
+
def initialize(property, host: nil, lookup: nil)
|
|
39
|
+
@property = property
|
|
40
|
+
@host = host
|
|
41
|
+
@lookup = lookup
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def to_s
|
|
45
|
+
parts = ["#{visibility_marker} "]
|
|
46
|
+
parts << namespaced_name
|
|
47
|
+
type_str = formatted_type
|
|
48
|
+
parts << ": #{type_str}" unless type_str.empty?
|
|
49
|
+
mult = multiplicity
|
|
50
|
+
parts << " #{mult}" unless mult.empty?
|
|
51
|
+
parts << " = #{property.default_value}" if property.default_value && !property.default_value.to_s.empty?
|
|
52
|
+
parts.join.rstrip
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def visibility_marker
|
|
58
|
+
case property.visibility
|
|
59
|
+
when "private" then "-"
|
|
60
|
+
when "protected" then "#"
|
|
61
|
+
when "package" then "~"
|
|
62
|
+
else "+"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Property name, prefixed with the declaring classifier's
|
|
67
|
+
# package name when the property is inherited from a
|
|
68
|
+
# different package than the host classifier.
|
|
69
|
+
def namespaced_name
|
|
70
|
+
prefix = inherited_namespace_prefix
|
|
71
|
+
base = property.name.to_s
|
|
72
|
+
prefix && !prefix.empty? ? "#{prefix}::#{base}" : base
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Returns the declaring classifier's package name when it
|
|
76
|
+
# differs from the host's package; nil otherwise.
|
|
77
|
+
def inherited_namespace_prefix
|
|
78
|
+
return nil unless host && lookup
|
|
79
|
+
return nil if property.owner_id.nil? || property.owner_id == host.id
|
|
80
|
+
|
|
81
|
+
owner = lookup.call(property.owner_id)
|
|
82
|
+
return nil unless owner.is_a?(Ea::Model::Classifier)
|
|
83
|
+
return nil if owner.package_id.nil?
|
|
84
|
+
return nil if owner.package_id == host.package_id
|
|
85
|
+
|
|
86
|
+
owner.package_name
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Format the type name. Primitive types from the PRIMITIVE_TYPES
|
|
90
|
+
# set render bare; everything else renders verbatim from the
|
|
91
|
+
# source. The source already provides the correct colon form
|
|
92
|
+
# (single for XSD, double for UML package qualifiers).
|
|
93
|
+
def formatted_type
|
|
94
|
+
raw = property.type_name.to_s
|
|
95
|
+
return "" if raw.empty?
|
|
96
|
+
|
|
97
|
+
simple = raw.split(":").last.to_s.split("::").last.to_s
|
|
98
|
+
PRIMITIVE_TYPES.member?(simple) ? simple : raw
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def multiplicity
|
|
102
|
+
lower = property.multiplicity_lower
|
|
103
|
+
upper = property.multiplicity_upper
|
|
104
|
+
return "" if lower.nil? && upper.nil?
|
|
105
|
+
return "" if lower == 1 && upper == 1
|
|
106
|
+
|
|
107
|
+
"[#{lower || 0}..#{bound_text(upper)}]"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def bound_text(value)
|
|
111
|
+
value == -1 ? "*" : value.to_s
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Element
|
|
7
|
+
# Emits the attribute compartment text `<g>`. Each attribute
|
|
8
|
+
# renders as TWO `<text>` elements (visibility marker +
|
|
9
|
+
# content) matching EA's encoding.
|
|
10
|
+
class AttributeRenderer
|
|
11
|
+
DEFAULT_VISIBILITY_X_OFFSET = 5
|
|
12
|
+
DEFAULT_CONTENT_X_OFFSET = 26
|
|
13
|
+
DEFAULT_FONT_UNIT = "pt"
|
|
14
|
+
|
|
15
|
+
def self.render(lines, bounds:, first_y:, family:,
|
|
16
|
+
size:, size_unit: DEFAULT_FONT_UNIT,
|
|
17
|
+
fill: "#000000",
|
|
18
|
+
visibility_x_offset: DEFAULT_VISIBILITY_X_OFFSET,
|
|
19
|
+
content_x_offset: DEFAULT_CONTENT_X_OFFSET)
|
|
20
|
+
line_h = size + 4
|
|
21
|
+
text_blocks = []
|
|
22
|
+
lines.each_with_index do |line, idx|
|
|
23
|
+
y = first_y + (idx * line_h)
|
|
24
|
+
visibility, rest = split_visibility(line)
|
|
25
|
+
if visibility
|
|
26
|
+
text_blocks << build_text(bounds.x + visibility_x_offset, y, visibility, family, size, size_unit, fill)
|
|
27
|
+
text_blocks << build_text(bounds.x + content_x_offset, y, rest, family, size, size_unit, fill)
|
|
28
|
+
else
|
|
29
|
+
text_blocks << build_text(bounds.x + visibility_x_offset, y, line.strip, family, size, size_unit, fill)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
group_style = "stroke-width:1;stroke-linecap:round;stroke-linejoin:bevel; fill:#{fill};fill-opacity:1.00; stroke:#000000; stroke-opacity:0.00"
|
|
33
|
+
%(<g style="#{group_style}">\n#{text_blocks.join("\n")}\n</g>)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Builds attribute display lines from classifier properties,
|
|
37
|
+
# hiding properties that are navigable association ends
|
|
38
|
+
# (those are rendered as connector lines).
|
|
39
|
+
#
|
|
40
|
+
# When a property carries a stereotype (e.g. «voidable»),
|
|
41
|
+
# EA renders the stereotype label as a separate line above
|
|
42
|
+
# the property's own line. We insert those labels here so
|
|
43
|
+
# the renderer's per-line spacing naturally places them.
|
|
44
|
+
#
|
|
45
|
+
# Pass a `lookup` (any callable returning a Classifier for
|
|
46
|
+
# an id) to enable inherited-property namespace prefixing.
|
|
47
|
+
def self.lines_for(classifier, lookup: nil)
|
|
48
|
+
props = displayable_properties(classifier)
|
|
49
|
+
return [] unless props
|
|
50
|
+
|
|
51
|
+
props.flat_map do |prop|
|
|
52
|
+
lines = []
|
|
53
|
+
stereotype = property_stereotype(prop)
|
|
54
|
+
lines << "«#{stereotype}»" if stereotype
|
|
55
|
+
lines << AttributeLineBuilder.new(prop, host: classifier,
|
|
56
|
+
lookup: lookup).to_s
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Internal helpers
|
|
61
|
+
|
|
62
|
+
def self.split_visibility(line)
|
|
63
|
+
stripped = line.strip
|
|
64
|
+
return [nil, stripped] unless stripped.match?(/^[-+~#]\s/)
|
|
65
|
+
|
|
66
|
+
visibility = "#{stripped[0]} "
|
|
67
|
+
rest = stripped[2..].to_s.strip
|
|
68
|
+
[visibility, rest]
|
|
69
|
+
end
|
|
70
|
+
private_class_method :split_visibility
|
|
71
|
+
|
|
72
|
+
def self.build_text(x, y, content, family, size, size_unit = DEFAULT_FONT_UNIT, fill = "#000000")
|
|
73
|
+
TextRenderer.new(content: content, x: x, y: y,
|
|
74
|
+
family: family, size: size, size_unit: size_unit, fill: fill).to_svg
|
|
75
|
+
end
|
|
76
|
+
private_class_method :build_text
|
|
77
|
+
|
|
78
|
+
def self.displayable_properties(classifier)
|
|
79
|
+
return nil unless classifier.properties
|
|
80
|
+
|
|
81
|
+
classifier.properties.reject(&:association_id)
|
|
82
|
+
end
|
|
83
|
+
private_class_method :displayable_properties
|
|
84
|
+
|
|
85
|
+
# Returns the first stereotype ref for a property, or nil.
|
|
86
|
+
# Used to emit «voidable» (and similar) labels above the
|
|
87
|
+
# property's own line.
|
|
88
|
+
def self.property_stereotype(property)
|
|
89
|
+
refs = property.stereotype_refs
|
|
90
|
+
return nil unless refs&.any?
|
|
91
|
+
|
|
92
|
+
refs.first.to_s
|
|
93
|
+
end
|
|
94
|
+
private_class_method :property_stereotype
|
|
95
|
+
|
|
96
|
+
# EA renders namespace separators as "::" (UML standard)
|
|
97
|
+
# even when the source XMI stores them as ":" (XML style).
|
|
98
|
+
def self.namespace_double_colon(type_name)
|
|
99
|
+
return nil if type_name.nil? || type_name.empty?
|
|
100
|
+
|
|
101
|
+
type_name.to_s.gsub(/([A-Za-z0-9_]):([A-Za-z])/, '\1::\2')
|
|
102
|
+
end
|
|
103
|
+
private_class_method :namespace_double_colon
|
|
104
|
+
|
|
105
|
+
def self.multiplicity_text(property)
|
|
106
|
+
lower = property.multiplicity_lower
|
|
107
|
+
upper = property.multiplicity_upper
|
|
108
|
+
return "" if lower.nil? && upper.nil?
|
|
109
|
+
return "" if lower == 1 && upper == 1
|
|
110
|
+
return "[#{upper == -1 ? "*" : upper}]" if lower == upper
|
|
111
|
+
|
|
112
|
+
"[#{lower || 0}..#{upper == -1 ? "*" : upper}]"
|
|
113
|
+
end
|
|
114
|
+
private_class_method :multiplicity_text
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Element
|
|
7
|
+
# Decodes EA's BGR-encoded BCol/LCol integers into "#RRGGBB"
|
|
8
|
+
# hex strings. EA stores color as a Win32 COLORREF: R in low
|
|
9
|
+
# byte, G in mid byte, B in high byte.
|
|
10
|
+
#
|
|
11
|
+
# Returns nil when bgr_int is nil OR equals -1 (EA's sentinel
|
|
12
|
+
# for "no color override" — callers fall through to a
|
|
13
|
+
# stereotype-derived default).
|
|
14
|
+
class BColDecoder
|
|
15
|
+
SENTINEL = -1
|
|
16
|
+
|
|
17
|
+
def self.to_hex(bgr_int)
|
|
18
|
+
return nil if bgr_int.nil? || bgr_int == SENTINEL
|
|
19
|
+
|
|
20
|
+
r = bgr_int & 0xff
|
|
21
|
+
g = (bgr_int >> 8) & 0xff
|
|
22
|
+
b = (bgr_int >> 16) & 0xff
|
|
23
|
+
format("#%02X%02X%02X", r, g, b)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Element
|
|
7
|
+
# Y-coordinate calculator for the compartments of an element
|
|
8
|
+
# box: header text, header divider, attribute rows, operation
|
|
9
|
+
# rows, enum literals, tagged-value rows.
|
|
10
|
+
#
|
|
11
|
+
# Owns its own coordinate math; the rest of Elements only
|
|
12
|
+
# reads `header_first_y`, `divider_y`, `attr_first_y`, etc.
|
|
13
|
+
# Construction takes the bounds, font size, line counts,
|
|
14
|
+
# and per-region offsets from the theme.
|
|
15
|
+
#
|
|
16
|
+
# Extracted from Elements.rb to keep each concern in one
|
|
17
|
+
# place (MECE). Element rendering reads these values;
|
|
18
|
+
# coordinate math changes don't ripple into rendering.
|
|
19
|
+
class CompartmentGeometry
|
|
20
|
+
attr_reader :bounds, :size, :header_lines_count,
|
|
21
|
+
:attr_lines_count, :op_lines_count,
|
|
22
|
+
:tagged_values_count,
|
|
23
|
+
:header_top_padding, :header_line_offset,
|
|
24
|
+
:divider_offset, :attr_line_offset,
|
|
25
|
+
:attr_first_offset
|
|
26
|
+
|
|
27
|
+
def initialize(bounds:, size:, header_lines_count:,
|
|
28
|
+
attr_lines_count:, op_lines_count:,
|
|
29
|
+
tagged_values_count:,
|
|
30
|
+
header_top_padding: 9,
|
|
31
|
+
header_line_offset: 6,
|
|
32
|
+
divider_offset: 8,
|
|
33
|
+
attr_line_offset: 4,
|
|
34
|
+
attr_first_offset: 7)
|
|
35
|
+
@bounds = bounds
|
|
36
|
+
@size = size
|
|
37
|
+
@header_lines_count = header_lines_count
|
|
38
|
+
@attr_lines_count = attr_lines_count
|
|
39
|
+
@op_lines_count = op_lines_count
|
|
40
|
+
@tagged_values_count = tagged_values_count
|
|
41
|
+
@header_top_padding = header_top_padding
|
|
42
|
+
@header_line_offset = header_line_offset
|
|
43
|
+
@divider_offset = divider_offset
|
|
44
|
+
@attr_line_offset = attr_line_offset
|
|
45
|
+
@attr_first_offset = attr_first_offset
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def header_first_y
|
|
49
|
+
bounds.y + size + (header_top_padding || 9)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Y of the divider line between header and the rest.
|
|
53
|
+
# Returns nil when there's no header content to separate
|
|
54
|
+
# from empty below-header content.
|
|
55
|
+
def divider_y
|
|
56
|
+
return nil if header_lines_count.zero?
|
|
57
|
+
|
|
58
|
+
header_first_y +
|
|
59
|
+
([header_lines_count, 1].max - 1) * (size + (header_line_offset || 6)) +
|
|
60
|
+
(divider_offset || 8)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def attr_first_y
|
|
64
|
+
return bounds.y + size + (header_top_padding || 9) + 12 unless divider_y
|
|
65
|
+
|
|
66
|
+
divider_y + size + (attr_first_offset || 7)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def attr_bottom_y
|
|
70
|
+
return attr_first_y unless attr_lines_count&.positive?
|
|
71
|
+
|
|
72
|
+
attr_first_y + (attr_lines_count - 1) * (size + (attr_line_offset || 4))
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def op_divider_y
|
|
76
|
+
attr_bottom_y + size + 5
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def op_first_y
|
|
80
|
+
return nil unless op_lines_count&.positive?
|
|
81
|
+
|
|
82
|
+
op_divider_y + size + 5
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def op_bottom_y
|
|
86
|
+
return op_divider_y unless op_lines_count&.positive?
|
|
87
|
+
|
|
88
|
+
op_first_y + (op_lines_count - 1) * (size + 4)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def enum_divider_y
|
|
92
|
+
op_bottom_y + size + 5
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def enum_literal_first_y
|
|
96
|
+
enum_divider_y + size + 5
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Tagged values appear after attributes (or after ops if
|
|
100
|
+
# present). EA does not emit a separate divider — the
|
|
101
|
+
# italic "tags" header marks the compartment.
|
|
102
|
+
def tagged_value_first_y
|
|
103
|
+
return nil unless tagged_values_count&.positive?
|
|
104
|
+
|
|
105
|
+
base = attr_bottom_y
|
|
106
|
+
base = op_bottom_y if op_lines_count&.positive?
|
|
107
|
+
base + size + 5
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Element
|
|
7
|
+
# Emits the constraints compartment text `<g>`. EA renders
|
|
8
|
+
# constraints as a sub-compartment with an italic "constraints"
|
|
9
|
+
# header followed by `{name}` lines:
|
|
10
|
+
#
|
|
11
|
+
# <text style="...font-style:italic;...">constraints</text>
|
|
12
|
+
# <text style="...font-style:normal;...">{pattern}</text>
|
|
13
|
+
class ConstraintRenderer
|
|
14
|
+
HEADER_TEXT = "constraints"
|
|
15
|
+
HEADER_X_OFFSET = 5
|
|
16
|
+
LINE_X_OFFSET = 5
|
|
17
|
+
|
|
18
|
+
def self.render(constraints, bounds:, first_y:, family:, size:,
|
|
19
|
+
fill: "#000000")
|
|
20
|
+
line_h = size + 4
|
|
21
|
+
text_blocks = []
|
|
22
|
+
text_blocks << build_text(
|
|
23
|
+
bounds.x + centered_x_offset(bounds, size), first_y,
|
|
24
|
+
HEADER_TEXT, family, size, fill, style: "italic"
|
|
25
|
+
)
|
|
26
|
+
constraints.each_with_index do |constraint, idx|
|
|
27
|
+
y = first_y + ((idx + 1) * line_h)
|
|
28
|
+
text_blocks << build_text(
|
|
29
|
+
bounds.x + LINE_X_OFFSET, y,
|
|
30
|
+
"{#{constraint.name}}", family, size, fill
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
%(<g style="#{Style::TEXT_GROUP}">\n#{text_blocks.join("\n")}\n</g>)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.build_text(x, y, content, family, size, fill, style: "normal")
|
|
37
|
+
TextRenderer.new(content: content, x: x, y: y,
|
|
38
|
+
family: family, size: size, fill: fill,
|
|
39
|
+
style: style).to_svg
|
|
40
|
+
end
|
|
41
|
+
private_class_method :build_text
|
|
42
|
+
|
|
43
|
+
def self.centered_x_offset(bounds, size)
|
|
44
|
+
text_width = HEADER_TEXT.length * (size / 2)
|
|
45
|
+
centered = (bounds.width / 2 - text_width / 2).floor
|
|
46
|
+
[HEADER_X_OFFSET, centered].max
|
|
47
|
+
end
|
|
48
|
+
private_class_method :centered_x_offset
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Element
|
|
7
|
+
# Emits the horizontal divider path between header and
|
|
8
|
+
# attribute compartments.
|
|
9
|
+
class DividerRenderer
|
|
10
|
+
def self.render(bounds, y:, stroke:, stroke_width:)
|
|
11
|
+
%(<g style="stroke-width:#{stroke_width};stroke-linecap:round;stroke-linejoin:bevel; fill:#000000;fill-opacity:0.00; stroke:#{stroke}; stroke-opacity:1.00">\n <path d="M #{Canvas.coord(bounds.x)} #{Canvas.coord(y)} L #{Canvas.coord(bounds.x + bounds.width)} #{Canvas.coord(y)}" shape-rendering="auto"/>\n</g>)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Svg
|
|
5
|
+
module EaEmitter
|
|
6
|
+
module Element
|
|
7
|
+
# Emits the enumeration literal compartment text `<g>`. Each
|
|
8
|
+
# literal appears as a separate text element matching EA's
|
|
9
|
+
# encoding:
|
|
10
|
+
#
|
|
11
|
+
# <text>literal_name</text>
|
|
12
|
+
#
|
|
13
|
+
# Rendered as a third compartment below the attribute
|
|
14
|
+
# compartment for Enumeration classifiers.
|
|
15
|
+
class EnumerationLiteralRenderer
|
|
16
|
+
def self.render(literals, bounds:, first_y:, family:, size:)
|
|
17
|
+
line_h = size + 4
|
|
18
|
+
text_blocks = literals.each_with_index.map do |literal, idx|
|
|
19
|
+
y = first_y + (idx * line_h)
|
|
20
|
+
build_text(bounds.x + 5, y, literal.name.to_s, family, size)
|
|
21
|
+
end
|
|
22
|
+
%(<g style="#{Style::TEXT_GROUP}">\n#{text_blocks.join("\n")}\n</g>)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.build_text(x, y, content, family, size)
|
|
26
|
+
TextRenderer.new(content: content, x: x, y: y,
|
|
27
|
+
family: family, size: size).to_svg
|
|
28
|
+
end
|
|
29
|
+
private_class_method :build_text
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|