terriajs
Version:
Geospatial data visualization platform.
118 lines (102 loc) • 3.56 kB
text/typescript
import i18next from "i18next";
import { action, autorun, computed, runInAction, makeObservable } from "mobx";
import DeveloperError from "terriajs-cesium/Source/Core/DeveloperError";
import filterOutUndefined from "../../../Core/filterOutUndefined";
import isDefined from "../../../Core/isDefined";
import Result from "../../../Core/Result";
import CatalogMemberMixin from "../../../ModelMixins/CatalogMemberMixin";
import MappableMixin, { MapItem } from "../../../ModelMixins/MappableMixin";
import ModelReference from "../../../Traits/ModelReference";
import CompositeCatalogItemTraits from "../../../Traits/TraitsClasses/CompositeCatalogItemTraits";
import CommonStrata from "../../Definition/CommonStrata";
import CreateModel from "../../Definition/CreateModel";
import { ModelConstructorParameters } from "../../Definition/Model";
import { BaseModel } from "../../Definition/Model";
export default class CompositeCatalogItem extends MappableMixin(
CatalogMemberMixin(CreateModel(CompositeCatalogItemTraits))
) {
static readonly type = "composite";
private _visibilityDisposer = autorun(() => {
this.syncVisibilityToMembers();
});
constructor(...args: ModelConstructorParameters) {
super(...args);
makeObservable(this);
}
get type() {
return CompositeCatalogItem.type;
}
get typeName() {
return i18next.t("models.composite.name");
}
get memberModels(): ReadonlyArray<BaseModel> {
const members = this.members;
if (members === undefined) {
return [];
}
return filterOutUndefined(
members.map((id) =>
ModelReference.isRemoved(id)
? undefined
: this.terria.getModelById(BaseModel, id)
)
);
}
protected async forceLoadMetadata(): Promise<void> {
const members = this.memberModels.filter(CatalogMemberMixin.isMixedInto);
// Avoid calling loadX functions in a computed context
await Promise.resolve();
Result.combine(
await Promise.all(
members.map(async (model) => await model.loadMetadata())
),
"Failed to load composite catalog items metadata"
).throwIfError();
}
async forceLoadMapItems(): Promise<void> {
const members = this.memberModels.filter(MappableMixin.isMixedInto);
// Avoid calling loadX functions in a computed context
await Promise.resolve();
Result.combine(
await Promise.all(members.map((model) => model.loadMapItems())),
"Failed to load composite catalog items mapItems"
).throwIfError();
}
syncVisibilityToMembers() {
const { show } = this;
this.memberModels.forEach((model) => {
runInAction(() => {
model.setTrait(CommonStrata.underride, "show", show);
});
});
}
get mapItems() {
const result: MapItem[] = [];
this.memberModels.filter(MappableMixin.isMixedInto).forEach((model) => {
result.push(...model.mapItems);
});
return result;
}
add(stratumId: string, member: BaseModel) {
if (member.uniqueId === undefined) {
throw new DeveloperError(
"A model without a `uniqueId` cannot be added to a composite."
);
}
if (!isDefined(this.terria.getModelById(BaseModel, member.uniqueId))) {
this.terria.addModel(member);
}
const members = this.getTrait(stratumId, "members");
if (isDefined(members)) {
members.push(member.uniqueId);
} else {
this.setTrait(stratumId, "members", [member.uniqueId]);
}
}
dispose() {
super.dispose();
this._visibilityDisposer();
}
}