diff --git a/.storybook/public/testdata/sample.czml b/.storybook/public/testdata/sample.czml new file mode 100644 index 000000000..b83f02263 --- /dev/null +++ b/.storybook/public/testdata/sample.czml @@ -0,0 +1,55 @@ +[ + { + "id": "document", + "name": "Japan", + "version": "1.0" + }, + { + "id": "1", + "name": "Sendai city", + "description": "This is Sendai city of Miyagi prefecture.", + "position": { + "cartographicDegrees": [ + 140.87636805791237, + 38.26835288549171, + 0 + ] + }, + "point": { + "color": { "rgba": [255, 0, 255, 255] }, + "pixelSize": 100 + } + }, + { + "id": "2", + "name": "Fukushima city", + "description": "This is Fukushima city of Fukushima prefecture.", + "position": { + "cartographicDegrees": [ + 140.47334452422348, + 37.76702444930477, + 0 + ] + }, + "point": { + "color": { "rgba": [0, 255, 255, 255] }, + "pixelSize": 100 + } + }, + { + "id": "3", + "name": "Tokyo", + "description": "This is Tokyo prefecture.", + "position": { + "cartographicDegrees": [ + 139.6904487961309, + 35.685394553171434, + 0 + ] + }, + "point": { + "color": { "rgba": [255, 255, 0, 255] }, + "pixelSize": 100 + } + } +] \ No newline at end of file diff --git a/.storybook/public/testdata/sample.gltf b/.storybook/public/testdata/sample.gltf new file mode 100644 index 000000000..e7d915e19 --- /dev/null +++ b/.storybook/public/testdata/sample.gltf @@ -0,0 +1,70 @@ + { + "scene": 0, + "scenes" : [ + { + "nodes" : [ 0 ] + } + ], + + "nodes" : [ + { + "mesh" : 0 + } + ], + + "meshes" : [ + { + "primitives" : [ { + "attributes" : { + "POSITION" : 1 + }, + "indices" : 0 + } ] + } + ], + + "buffers" : [ + { + "uri" : "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=", + "byteLength" : 44 + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteOffset" : 0, + "byteLength" : 6, + "target" : 34963 + }, + { + "buffer" : 0, + "byteOffset" : 8, + "byteLength" : 36, + "target" : 34962 + } + ], + "accessors" : [ + { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 3, + "type" : "SCALAR", + "max" : [ 2 ], + "min" : [ 0 ] + }, + { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 3, + "type" : "VEC3", + "max" : [ 1.0, 1.0, 0.0 ], + "min" : [ 0.0, 0.0, 0.0 ] + } + ], + + "asset" : { + "version" : "2.0" + } +} diff --git a/src/core/engines/Cesium/Feature/Model/index.stories.tsx b/src/core/engines/Cesium/Feature/Model/index.stories.tsx new file mode 100644 index 000000000..178bfa95b --- /dev/null +++ b/src/core/engines/Cesium/Feature/Model/index.stories.tsx @@ -0,0 +1,49 @@ +import { Meta, Story } from "@storybook/react"; + +import { engine } from "../../"; +import Component, { Props } from "../../../../Map"; + +export default { + title: "core/engines/Cesium/Feature/Model", + component: Component, + parameters: { actions: { argTypesRegex: "^on.*" } }, +} as Meta; + +const Template: Story = args => ; + +export const Default = Template.bind([]); +Default.args = { + engine: "cesium", + engines: { + cesium: engine, + }, + ready: true, + layers: [ + { + id: "l", + type: "simple", + data: { + type: "geojson", + value: { + type: "Feature", + geometry: { + type: "Point", + coordinates: [0, 0, 1000], + }, + }, + }, + model: { + url: "/BoxAnimated.glb", + scale: 1000000, + }, + }, + ], + property: { + tiles: [ + { + id: "default", + tile_type: "default", + }, + ], + }, +}; diff --git a/src/core/engines/Cesium/Feature/Model/index.tsx b/src/core/engines/Cesium/Feature/Model/index.tsx index a873753ea..8adee43f8 100644 --- a/src/core/engines/Cesium/Feature/Model/index.tsx +++ b/src/core/engines/Cesium/Feature/Model/index.tsx @@ -28,6 +28,7 @@ export default function Model({ id, isVisible, property, geometry, layer, featur const { model, + url, heightReference: hr, heading, pitch, @@ -69,7 +70,7 @@ export default function Model({ id, isVisible, property, geometry, layer, featur const modelLightColor = useMemo(() => toColor(lightColor), [lightColor]); const modelSilhouetteColor = useMemo(() => toColor(silhouetteColor), [silhouetteColor]); - return !isVisible || !model || !position ? null : ( + return !isVisible || (!model && !url) || !position ? null : ( = args => ; + +export const Default = Template.bind([]); +Default.args = { + engine: "cesium", + engines: { + cesium: engine, + }, + ready: true, + layers: [ + { + id: "l", + type: "simple", + data: { + type: "czml", + url: "/testdata/sample.czml", + }, + resource: {}, + }, + ], + property: { + tiles: [ + { + id: "default", + tile_type: "default", + }, + ], + }, +}; diff --git a/src/core/engines/Cesium/Feature/Resource/index.tsx b/src/core/engines/Cesium/Feature/Resource/index.tsx index 933b39af6..eeffcf6c3 100644 --- a/src/core/engines/Cesium/Feature/Resource/index.tsx +++ b/src/core/engines/Cesium/Feature/Resource/index.tsx @@ -1,11 +1,11 @@ import { useMemo } from "react"; import { KmlDataSource, CzmlDataSource, GeoJsonDataSource } from "resium"; -import type { LegacyResourceAppearance } from "../../.."; -import { type FeatureComponentConfig, type FeatureProps } from "../utils"; +import type { ResourceAppearance } from "../../.."; +import { extractSimpleLayerData, type FeatureComponentConfig, type FeatureProps } from "../utils"; export type Props = FeatureProps; -export type Property = LegacyResourceAppearance; +export type Property = ResourceAppearance; const types: Record = { kml: "kml", geojson: "geojson", @@ -18,8 +18,15 @@ const comps = { geojson: GeoJsonDataSource, }; -export default function Resource({ isVisible, property }: Props) { - const { url, type, clampToGround } = property ?? {}; +export default function Resource({ isVisible, property, layer }: Props) { + const { clampToGround } = property ?? {}; + const [type, url] = useMemo((): [ResourceAppearance["type"], string | undefined] => { + const data = extractSimpleLayerData(layer); + const type = property?.type; + const url = property?.url; + return [type ?? (data?.type as ResourceAppearance["type"]), url ?? data?.url]; + }, [property, layer]); + const ext = useMemo( () => (!type || type === "auto" ? url?.match(/\.([a-z]+?)(?:\?.*?)?$/) : undefined), [type, url], @@ -29,7 +36,9 @@ export default function Resource({ isVisible, property }: Props) { if (!isVisible || !Component || !url) return null; - return ; + return ; } -export const config: FeatureComponentConfig = {}; +export const config: FeatureComponentConfig = { + noFeature: true, +}; diff --git a/src/core/engines/Cesium/Feature/index.tsx b/src/core/engines/Cesium/Feature/index.tsx index a1f0c45ca..4e7381330 100644 --- a/src/core/engines/Cesium/Feature/index.tsx +++ b/src/core/engines/Cesium/Feature/index.tsx @@ -24,7 +24,7 @@ const components: Record (Object.keys(components) as (keyof AppearanceTypes)[]).map(k => { const [C, config] = components[k] ?? []; - if ( - !C || - (f && !f[k]) || - !layer[k] || - (config.noLayer && !f) || - (config.noFeature && f) - ) { + if (!C || (f && !f[k]) || (config.noLayer && !f) || (config.noFeature && f)) { return null; } diff --git a/src/core/engines/Cesium/Feature/utils.tsx b/src/core/engines/Cesium/Feature/utils.tsx index fa86d92c7..ff46faf99 100644 --- a/src/core/engines/Cesium/Feature/utils.tsx +++ b/src/core/engines/Cesium/Feature/utils.tsx @@ -10,6 +10,8 @@ import { } from "react"; import { type CesiumComponentRef, Entity } from "resium"; +import { Data } from "@reearth/core/mantle"; + import type { ComputedFeature, ComputedLayer, FeatureComponentProps, Geometry } from "../.."; export type FeatureProps

= { @@ -110,3 +112,10 @@ const tagObj: { [k in keyof Tag]: 1 } = { const tagKeys = Object.keys(tagObj) as (keyof Tag)[]; const tagKey = "__reearth_tag"; + +export const extractSimpleLayerData = (layer: ComputedLayer | undefined): Data | void => { + if (layer?.layer.type !== "simple") { + return; + } + return layer.layer.data; +}; diff --git a/src/core/engines/Cesium/index.tsx b/src/core/engines/Cesium/index.tsx index 4c4a4f926..c16e2265c 100644 --- a/src/core/engines/Cesium/index.tsx +++ b/src/core/engines/Cesium/index.tsx @@ -192,5 +192,5 @@ export const engine: Engine = { component: Component, featureComponent: Feature, clusterComponent: Cluster, - // delegatedDataTypes: ["3dtiles", "czml"], + delegatedDataTypes: ["czml"], }; diff --git a/src/core/engines/index.ts b/src/core/engines/index.ts index b7a4d5b85..28f95e0da 100644 --- a/src/core/engines/index.ts +++ b/src/core/engines/index.ts @@ -29,5 +29,5 @@ export type { MarkerAppearance, ModelAppearance, LegacyPhotooverlayAppearance, - LegacyResourceAppearance, + ResourceAppearance, } from "../mantle"; diff --git a/src/core/mantle/compat/backward.test.ts b/src/core/mantle/compat/backward.test.ts index 8238d30ac..5aca41cd8 100644 --- a/src/core/mantle/compat/backward.test.ts +++ b/src/core/mantle/compat/backward.test.ts @@ -340,12 +340,12 @@ test("3dtiles", () => { }); }); -test("legacy_resource", () => { +test("resource", () => { expect( getCompat({ id: "xxx", type: "simple", - legacy_resource: { + resource: { url: "xxx", aaaa: 1, }, diff --git a/src/core/mantle/compat/backward.ts b/src/core/mantle/compat/backward.ts index bd4bce1ec..9b48a5991 100644 --- a/src/core/mantle/compat/backward.ts +++ b/src/core/mantle/compat/backward.ts @@ -168,11 +168,11 @@ export function getCompat(l: Layer | undefined): LayerCompat | undefined { : {}), }, }; - } else if ("legacy_resource" in l) { + } else if ("resource" in l) { extensionId = "resource"; property = { default: { - ...(l as any).legacy_resource, + ...(l as any).resource, }, }; } diff --git a/src/core/mantle/compat/forward.test.ts b/src/core/mantle/compat/forward.test.ts index 99fadb530..db469f08b 100644 --- a/src/core/mantle/compat/forward.test.ts +++ b/src/core/mantle/compat/forward.test.ts @@ -472,7 +472,7 @@ test("resource", () => { id: "x", type: "simple", visible: true, - legacy_resource: { + resource: { url: "xxx", hoge: "red", }, diff --git a/src/core/mantle/compat/forward.ts b/src/core/mantle/compat/forward.ts index b7462927a..d544384d2 100644 --- a/src/core/mantle/compat/forward.ts +++ b/src/core/mantle/compat/forward.ts @@ -193,7 +193,7 @@ function convertLegacyLayerItem(l: LegacyLayer): LayerSimple | undefined { }; } } else if (l.extensionId === "resource") { - appearance = "legacy_resource"; + appearance = "resource"; } const property = appearance diff --git a/src/core/mantle/types/appearance.ts b/src/core/mantle/types/appearance.ts index 1d339920d..60ac5a383 100644 --- a/src/core/mantle/types/appearance.ts +++ b/src/core/mantle/types/appearance.ts @@ -23,7 +23,7 @@ export type AppearanceTypes = { ellipsoid: EllipsoidAppearance; box: BoxAppearance; photooverlay: LegacyPhotooverlayAppearance; - legacy_resource: LegacyResourceAppearance; + resource: ResourceAppearance; }; export type MarkerAppearance = { @@ -85,7 +85,9 @@ export type EllipsoidAppearance = { }; export type ModelAppearance = { + // For compat model?: string; + url?: string; heightReference?: "none" | "clamp" | "relative"; heading?: number; pitch?: number; @@ -133,7 +135,7 @@ export type LegacyPhotooverlayAppearance = { photoOverlayDescription?: string; }; -export type LegacyResourceAppearance = { +export type ResourceAppearance = { url?: string; type?: "geojson" | "kml" | "czml" | "auto"; clampToGround?: boolean; @@ -177,7 +179,7 @@ export const appearanceKeyObj: { [k in keyof AppearanceTypes]: 1 } = { "3dtiles": 1, box: 1, photooverlay: 1, - legacy_resource: 1, + resource: 1, }; export const appearanceKeys = objKeys(appearanceKeyObj); diff --git a/src/core/mantle/types/index.ts b/src/core/mantle/types/index.ts index 8d9b0904f..fe66f5b14 100644 --- a/src/core/mantle/types/index.ts +++ b/src/core/mantle/types/index.ts @@ -74,7 +74,7 @@ export type DataRange = { z: number; }; -export type DataType = "geojson" | "3dtiles" | "csv"; +export type DataType = "geojson" | "3dtiles" | "czml" | "csv"; // Feature