ResolvedScene constructor

ResolvedScene({
  1. required String documentId,
  2. required int revision,
  3. int textLayoutRevision = 0,
  4. String? defaultFontFamily,
  5. required List<ResolvedElement> elements,
  6. ResolvedScene? previous,
  7. List<ResolvedElement> hiddenElements = const [],
  8. FrameCollapseProjection? collapseProjection,
})

Implementation

factory ResolvedScene({
  required String documentId,
  required int revision,
  int textLayoutRevision = 0,
  String? defaultFontFamily,
  required List<ResolvedElement> elements,
  ResolvedScene? previous,
  List<ResolvedElement> hiddenElements = const [],
  FrameCollapseProjection? collapseProjection,
}) {
  final preservesOrder =
      previous != null &&
      previous.documentId == documentId &&
      previous.elements.length == elements.length &&
      Iterable.generate(elements.length).every(
        (index) =>
            previous._sourceElements[index].id == elements[index].id &&
            previous._sourceElements[index].zIndex == elements[index].zIndex,
      );
  // Compare source order with source order. Paint order may differ whenever
  // frames/connectors have different z-values. Retain the permutation only
  // after checking every identity and z-value; arbitrary callers cannot assert
  // that ordering is unchanged. Equal z-values keep their input order.
  final paintOrder = preservesOrder
      ? previous._paintOrder
      : _scenePaintOrder(
          elements,
          previous?.documentId == documentId ? previous : null,
        );
  final sorted = DiagramPersistentList<ResolvedElement>.snapshot(
    paintOrder.map((index) => elements[index]).toList(),
  );
  final changedIndexes = preservesOrder
      ? <int>[
          for (var index = 0; index < sorted.length; index += 1)
            if (!identical(previous.elements[index], sorted[index])) index,
        ]
      : null;
  final sameSources =
      previous != null &&
      previous._sourceElements.length == elements.length &&
      Iterable.generate(elements.length)
          .every((i) => previous._sourceElements[i].id == elements[i].id);
  final sourceChanges = sameSources
      ? [
          for (var i = 0; i < elements.length; i++)
            if (!identical(previous._sourceElements[i], elements[i])) i,
        ]
      : null;
  var boundsIndex = sameSources
      ? previous._boundsIndex
      : _SceneBounds.build(elements);
  if (sourceChanges != null) {
    for (final i in sourceChanges) {
      boundsIndex = boundsIndex!.replace(i, elements[i].bounds);
    }
  }
  // Identity/order is stable for ordinary edits. Retain only the index map:
  // lookups read this revision's sorted elements, so moving one element does
  // not copy an entire ID-to-element map or retain stale resolved objects.
  final elementIndexes = preservesOrder
      ? previous._elementIndexes
      : Map<String, int>.unmodifiable({
          for (var index = 0; index < sorted.length; index++)
            sorted[index].id: index,
        });
  return ResolvedScene._(
    elementIndexes,
    DiagramPersistentList<ResolvedElement>.snapshot(elements),
    paintOrder,
    documentId: documentId,
    revision: revision,
    textLayoutRevision: textLayoutRevision,
    defaultFontFamily: defaultFontFamily,
    elements: sorted,
    boundsIndex: boundsIndex,
    collapseProjection: collapseProjection,
    hiddenElements: DiagramPersistentList.snapshot(hiddenElements),
    hiddenIndexes: Map.unmodifiable({
      for (var i = 0; i < hiddenElements.length; i++) hiddenElements[i].id: i,
    }),
    spatialIndex: preservesOrder
        ? DiagramSpatialIndex.incremental(
            previous.spatialIndex,
            sorted,
            changedIndexes: changedIndexes,
          )
        : previous != null && previous.documentId == documentId
        ? DiagramSpatialIndex.incremental(
            previous.spatialIndex,
            sorted,
            changedIds: sourceChanges?.map((i) => elements[i].id),
          )
        : DiagramSpatialIndex(sorted),
  );
}