@peter.prib/renderengine 0.2.5 → 0.2.6

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.
Files changed (33) hide show
  1. package/README.md +215 -213
  2. package/REFERENCE.md +94 -6
  3. package/dist/renderengine-workspace.umd.js +3254 -2089
  4. package/dist/renderengine.umd.js +3016 -2086
  5. package/examples/data-model.html +324 -0
  6. package/package.json +70 -68
  7. package/src/charting/CheckboxTreeSelector.js +373 -304
  8. package/src/charting/DiagramEditor.js +48 -6
  9. package/src/charting/DiagramTypeRegistry.js +5 -1
  10. package/src/charting/archimate/ArchimateCanvasEditor.js +825 -815
  11. package/src/charting/archimate/ArchimateElementTemplate.js +208 -195
  12. package/src/charting/datamodel/DataModel.js +299 -0
  13. package/src/charting/datamodel/DataModelContext.js +108 -0
  14. package/src/charting/datamodel/DataModelPerspective.js +84 -0
  15. package/src/charting/datamodel/LevelMapping.js +38 -0
  16. package/src/charting/datamodel/LevelSchema.js +41 -0
  17. package/src/charting/datamodel/index.js +5 -0
  18. package/src/charting/diagrams/DataModelDiagram.js +160 -86
  19. package/src/charting/diagrams/DataModelRelationshipStrategy.js +86 -38
  20. package/src/charting/diagrams/nesting.js +31 -0
  21. package/src/charting/modelTree/ModelTree.js +202 -164
  22. package/src/charting/modelTree/ModelTreePanel.js +36 -3
  23. package/src/charting/modelTree/TreeViewMode.js +131 -110
  24. package/src/charting/modelTree/modes/FlatTreeMode.js +32 -46
  25. package/src/charting/modelTree/modes/LayerGroupedTreeMode.js +47 -62
  26. package/src/charting/modelTree/modes/TypeGroupedTreeMode.js +46 -60
  27. package/src/datamodel.js +132 -122
  28. package/src/diagramCatalog.js +35 -30
  29. package/src/index.js +6 -1
  30. package/src/workspace/index.js +1 -0
  31. package/src/workspace/parts/ArchimateCanvasPart.js +5 -2
  32. package/src/workspace/parts/ChartPart.js +6 -1
  33. package/src/workspace/parts/DataModelPart.js +234 -0
@@ -3244,8 +3244,10 @@ export class DiagramEditor {
3244
3244
  // Try template-based first (template diagram pattern)
3245
3245
  const ids = (this._dragState?.movers ?? [elementId]).filter(id => this.getTemplate(id));
3246
3246
  if (!ids.length || !this.history) return;
3247
- // Where they were dropped: into a shape that holds them, or out of their parent.
3247
+ // Where they were dropped: into a shape that holds them, or out of their parent;
3248
+ // a parent they stick out of grows to show them (worked out where they lie now).
3248
3249
  const nesting = this.nestingChanges(ids);
3250
+ const fits = this.fitNesting(nesting);
3249
3251
  // Put them back, then move them all (and nest them) as one undo step.
3250
3252
  for (const id of ids) {
3251
3253
  const t = this.getTemplate(id);
@@ -3255,6 +3257,7 @@ export class DiagramEditor {
3255
3257
  const steps = [
3256
3258
  ...ids.map(id => new MoveElementCommand(this, id, deltaX, deltaY)),
3257
3259
  ...nesting.map(({ childId, parentId }) => this.nestCommand(childId, parentId)).filter(Boolean),
3260
+ ...fits.map(({ id, bounds }) => new SetPropertiesCommand(this.getTemplate(id), bounds, 'Fit around nested')),
3258
3261
  ];
3259
3262
  this.history.execute(steps.length === 1 ? steps[0] : new CompositeCommand('Move', steps));
3260
3263
  this.render();
@@ -3264,11 +3267,15 @@ export class DiagramEditor {
3264
3267
 
3265
3268
  // ===== Nesting (a shape drawn inside another) =====
3266
3269
 
3270
+ /** The room kept around a nested shape when its parent grows to show it: the top leaves room for the parent's name. */
3271
+ static NEST_MARGIN = Object.freeze({ side: 12, top: 28 });
3272
+
3267
3273
  /**
3268
3274
  * After a move, as the shapes lie now: each moved shape that is not moving
3269
3275
  * with its parent, whose parent changes. Its new parent is the innermost
3270
- * shape not moved that wholly holds its box and `canHold` it; none (null)
3271
- * takes it out of the one it was in.
3276
+ * shape not moved that wholly holds its box and `canHold` it, else the
3277
+ * innermost one its centre was dropped on that `nestsOnDrop` it (fitNesting
3278
+ * then grows it); none (null) takes it out of the one it was in.
3272
3279
  * @param {Array<string>} movedIds
3273
3280
  * @returns {Array<{childId: string, parentId: (string|null), previousId: (string|null)}>}
3274
3281
  */
@@ -3283,15 +3290,50 @@ export class DiagramEditor {
3283
3290
  const child = this.getTemplate(childId);
3284
3291
  if (!child) continue;
3285
3292
  const inner = box(child);
3286
- const parent = [...this.templates.values()]
3287
- .filter(t => !moved.has(t.id) && t.visible !== false && this.canHold(t.id, childId) && holds(box(t), inner))
3288
- .sort((a, b) => a.width * a.height - b.width * b.height)[0];
3293
+ const candidates = [...this.templates.values()].filter(t => !moved.has(t.id) && t.visible !== false && this.canHold(t.id, childId));
3294
+ const smallest = (list) => list.sort((a, b) => a.width * a.height - b.width * b.height)[0];
3295
+ const onCentre = (t) => { const b = box(t); return b.left <= child.x && child.x <= b.right && b.top <= child.y && child.y <= b.bottom; };
3296
+ const parent = smallest(candidates.filter(t => holds(box(t), inner)))
3297
+ ?? smallest(candidates.filter(t => onCentre(t) && this.nestsOnDrop(t.id, childId)));
3289
3298
  const parentId = parent?.id ?? null;
3290
3299
  if (parentId !== previousId) changes.push({ childId, parentId, previousId });
3291
3300
  }
3292
3301
  return changes;
3293
3302
  }
3294
3303
 
3304
+ /**
3305
+ * What has to grow for some nesting changes (nestingChanges') to show each
3306
+ * child whole, as the shapes lie now: each new parent the child sticks out
3307
+ * of, then that parent's own parents in turn, each to hold the one inside
3308
+ * with NEST_MARGIN around it.
3309
+ * @returns {Array<{id: string, bounds: {x, y, width, height}}>} new centre and size, outermost last
3310
+ */
3311
+ fitNesting(changes) {
3312
+ const { side, top } = DiagramEditor.NEST_MARGIN;
3313
+ const bounds = new Map();
3314
+ const at = (id) => bounds.get(id) ?? (({ x, y, width, height }) => ({ x, y, width, height }))(this.getTemplate(id));
3315
+ for (const { childId, parentId } of changes) {
3316
+ let inner = at(childId);
3317
+ for (let outerId = parentId; outerId; outerId = this.parentOf(outerId)) {
3318
+ const outer = at(outerId);
3319
+ const left = Math.min(outer.x - outer.width / 2, inner.x - inner.width / 2 - side);
3320
+ const right = Math.max(outer.x + outer.width / 2, inner.x + inner.width / 2 + side);
3321
+ const upper = Math.min(outer.y - outer.height / 2, inner.y - inner.height / 2 - top);
3322
+ const lower = Math.max(outer.y + outer.height / 2, inner.y + inner.height / 2 + side);
3323
+ const grown = { x: (left + right) / 2, y: (upper + lower) / 2, width: right - left, height: lower - upper };
3324
+ if (grown.width === outer.width && grown.height === outer.height) break; // it already shows it
3325
+ bounds.set(outerId, grown);
3326
+ inner = grown;
3327
+ }
3328
+ }
3329
+ return [...bounds].map(([id, b]) => ({ id, bounds: b }));
3330
+ }
3331
+
3332
+ /** Whether a shape dropped on another (its centre on it, sticking out) nests there. Never here; a subclass says when. */
3333
+ nestsOnDrop(parentId, childId) {
3334
+ return false;
3335
+ }
3336
+
3295
3337
  /** The shape this one is drawn inside (nested in), or null. None here: a subclass with nesting says. */
3296
3338
  parentOf(templateId) {
3297
3339
  return null;
@@ -218,7 +218,7 @@ export const DIAGRAM_TYPES = {
218
218
  'enterprise-ontology': {
219
219
  name: 'Enterprise Ontology',
220
220
  group: 'Data',
221
- description: 'The universal concepts enterprise data models are built from: parties in roles enter arrangements governing resources; events change them, ledgers record their value; classification, place, time, measure and rule describe them',
221
+ description: 'The universal concepts enterprise data models are built from (after IBM IFW\'s data concepts): parties in roles enter arrangements for products and resources; events change them, ledgers record their value; business direction steers them; classification, place, time, measure and rule describe them',
222
222
  templates: [
223
223
  shape('party', 'Party', ActorTemplate, {},
224
224
  'A person or legal actor that can act or hold rights: person, organisation, government body. Every business process involves actors.'),
@@ -226,6 +226,8 @@ export const DIAGRAM_TYPES = {
226
226
  'The part a party (or resource) plays in a context: customer, supplier, employee, owner, custodian. A party has many roles, and they change over time.'),
227
227
  shape('arrangement', 'Arrangement', DocumentTemplate, { width: 130, height: 70, fillColor: C.yellow },
228
228
  'A formalised relationship between parties, or parties and resources: contract, agreement, subscription, membership, policy, lease. Business interactions are structured by agreements.'),
229
+ shape('product', 'Product', PackageTemplate, { width: 120, height: 70, fillColor: C.green },
230
+ 'What the business offers and sells, under terms: a plan, a policy, a loan, a service bundle. Not the things it holds (resources), but the offer made of them.'),
229
231
  shape('resource', 'Resource', BoxTemplate, { width: 110, height: 80, fillColor: C.blue },
230
232
  'A physical or digital thing of value or use: product, asset, document, file, device. Businesses manage things.'),
231
233
  shape('event', 'Event', EllipseTemplate, { width: 120, height: 60, fillColor: C.green },
@@ -240,6 +242,8 @@ export const DIAGRAM_TYPES = {
240
242
  'A point or interval in time: effective date, validity period, contract term, timestamp, posting date.'),
241
243
  shape('measure', 'Measure', RectangleTemplate, { width: 110, height: 40, fillColor: C.white },
242
244
  'A quantity with its unit: weight, price, balance, temperature, risk score, count. The basis of metrics, KPIs and ledgers.'),
245
+ shape('direction', 'Business Direction', StarTemplate, { width: 100, height: 90, fillColor: C.yellow },
246
+ 'Where the business means to go: goal, objective, strategy, plan, policy, and the targets that measure them. It shapes products, arrangements and rules.'),
243
247
  shape('rule', 'Rule', DiamondTemplate, { width: 100, height: 70, fillColor: C.red },
244
248
  'A condition that governs arrangements, events or resources: business rule, policy, validation, regulatory requirement, eligibility.'),
245
249
  note,