Closed johnathandinh closed 6 years ago
I've never used Angular, but maybe someone else can help.
@johnathandinh
angular-cli.json
add vendor/pannellum/pannellum.js
in "scripts"
add vendor/pannellum/pannellum.css
in "styles"declare var pannellum: any;
and use like normal
pannellum.viewer('panoramaContainer', {
"type": "equirectangular",
"panorama": photourl,
"autoLoad": true,
"compass": true
});
@khanhvu161188 So if I add it to the vendors, it won't get instantiated in the background on load?
@khanhvu161188 Thanks, it works perfectly for me.
Since this seems to be resolved, I'm closing the issue.
Hi,
I would like to integrate pannellum into an angular6 app. I did: -cd myangular projekt root -npm i pannellum
This adds pannellum into package.json, but not into angular.json (there is no angular-cli.json now).
With the setup above, the pannellum integration does not work.
import * as pannelllum from pannellum works, but I'm not sure how could I instantiate some pannellum object to work with (viewer)...
Could you help? Thx, Regards Sandor
Hi, I would also know how to use it in angular 8. Can't get it work.
@esanya @alegroSandermann Implemented into a pano.component.ts like so.....
@Component({
selector: 'ng-pano',
templateUrl: './pano.component.html',
})
export class PanoComponent implements OnInit, OnChanges, OnDestroy {
private pano
ngOnInit() {
this.pano = window.pannellum.viewer(element, config)
}
ngOnChanges(changes) {
// Couldn't get Pannellum to update the image without destroying, I don't remember why.
this.pano.destroy()
this.pano = window.pannellum.viewer(element, config)
}
ngOnDestroy() {
this.pano.destroy()
}
}
If I implement this I get the message: Property 'nativeWindow' does not exist on type 'Window & typeof globalThis'.
If I implement this I get the message: Property 'nativeWindow' does not exist on type 'Window & typeof globalThis'.
Sorry, nativeWindow
should not exist. I've edited it out of my snippet. Have you initiated pannellum
in the component? That needs to be declared to exist in your window
scope.
I did declare var window: any;
after the import. This eliminates the error but it does also not work
And what I have seen, the import import * as pannellum from 'pannellum/build/pannellum.js';
has never been used
I did
declare var window: any;
after the import. This eliminates the error but it does also not work And what I have seen, the importimport * as pannellum from 'pannellum/build/pannellum.js';
has never been used
What does not work specifically? Please share a snippet.
Right, I've removed that also from the snippet. Are you still seeing that?
This is my component ts file: `import { Component, OnInit, OnChanges, OnDestroy } from '@angular/core';
declare var window: any;
@Component({ selector: 'app-landingpage', templateUrl: './landingpage.component.html', styleUrls: ['./landingpage.component.css'] })
export class LandingpageComponent implements OnInit, OnChanges, OnDestroy { private pano;
constructor() { }
ngOnInit() { this.pano = window.pannellum.viewer('panoramaContainer', { "type": "equirectangular", "panorama": "https://pannellum.org/images/alma.jpg" }); }
ngOnChanges(changes) { // Couldn't get Pannellum to update the image without destroying, I don't remember why. this.pano.destroy() this.pano = window.pannellum.viewer('panoramaContainer', { "type": "equirectangular", "panorama": "https://pannellum.org/images/alma.jpg" }); }
ngOnDestroy() { this.pano.destroy() }
}`
The console says:
ERROR TypeError: Cannot read property 'viewer' of undefined at LandingpageComponent.ngOnInit (landingpage.component.ts:20) at checkAndUpdateDirectiveInline (core.js:31910) at checkAndUpdateNodeInline (core.js:44367) at checkAndUpdateNode (core.js:44306) at debugCheckAndUpdateNode (core.js:45328) at debugCheckDirectivesFn (core.js:45271) at Object.eval [as updateDirectives] (LandingpageComponent_Host.ngfactory.js? [sm]:1) at Object.debugUpdateDirectives [as updateDirectives] (core.js:45259) at checkAndUpdateView (core.js:44271) at callViewAction (core.js:44637)
Oh, you still have to init pannellum.
- in
angular-cli.json
addvendor/pannellum/pannellum.js
in "scripts" addvendor/pannellum/pannellum.css
in "styles"- in component: add
declare var pannellum: any;
and use like normalpannellum.viewer('panoramaContainer', { "type": "equirectangular", "panorama": photourl, "autoLoad": true, "compass": true });
I have no angular-cli.json, just an angular.json
I added the script and css but get the same error message at the console.
I have no angular-cli.json, just an angular.json
I added the script and css but get the same error message at the console.
From Angular 6 version angular-cli.json has been replaced with angular.json
Hi I have successfully used it in Angular 11
step 1 install npm i pannellum
step 2 add "./node_modules/pannellum/build/pannellum.js" inside script in angular.json
step 3 add "./node_modules/pannellum/build/pannellum.css" inside styles in angular.json
step 4 declare var pannellum: any; in your component
step 5 pannellum.viewer('panoramaContainer', {
"type": "equirectangular",
"panorama": "../assets/Willpearson-004.jpg",
"autoLoad": true,
"compass": true
}); in your component.
step 6
"<div id="panoramaContainer"></div>"
in html template
and add css #panoramaContainer {
width: 600px;
height: 400px;
}
its done``
I have no angular-cli.json, just an angular.json I added the script and css but get the same error message at the console.
From Angular 6 version angular-cli.json has been replaced with angular.json
Hi I have successfully used it in Angular 11 step 1 install npm i pannellum step 2 add "./node_modules/pannellum/build/pannellum.js" inside script in angular.json step 3 add "./node_modules/pannellum/build/pannellum.css" inside styles in angular.json step 4 declare var pannellum: any; in your component step 5 pannellum.viewer('panoramaContainer', { "type": "equirectangular", "panorama": "../assets/Willpearson-004.jpg", "autoLoad": true, "compass": true }); in your component. step 6 "
" in html template and add css #panoramaContainer { width: 600px; height: 400px; }its done``
declare var pannellum: any;
is necessary for angular v11. You should include this line of code in your components, just after your imports.
The comments from @khanhvu161188 and @saifkhan-786 explain everything you need to make it work.
I'm using angular 17 and I still use the Cli all the time (like to build)? -\(' - ' )/-
I suggest a reusable component over injection since there is a requirement of some html and it is globally available (The factories are instanced on window already. When the code is imported the javascript makes a single factory object that is stored globally on the window once or at least when you import. It is also kind of important to destroy the instanced viewer later to avoid issue or suffer the dreaded memory leak. Reusable components with ngAfterViewInit make it easy!).
I mean If you are using type script why not leverage the type script with a type def? Yes sure 'any' will quick and dirty do it for you, so that is an option, but you will get 0 intelligence and 0 type checking. You can define some type interfaces.
npm i pannellum
"styles": [
"./node_modules/pannellum/src/css/pannellum.css", //add this line to wherever you set your styles.
"./node_modules/leaflet/dist/leaflet.css",
"src/custom-theme.scss",
"src/styles.scss"
],
scss or similar equivalent (pick either the root styles.scss or an appropriate level for you):
@import '~pannellum/src/css/pannellum.css';
Additionally you can include it in the html, but to integrate it I think its a bad option.
"scripts": [
"./node_modules/pannellum/src/js/libpannellum",
"./node_modules/pannellum/src/js/pannellum"
],
Imports to .ts files:
import 'pannellum/src/js/libpannellum' //this could go in the component as well
import 'pannellum/src/js/pannellum'
additionally you can include it in the html, but to integrate it I think its a bad option.
import 'pannellum/src/js/libpannellum'//as above's option 2
import 'pannellum/src/js/pannellum'//as above's option 2
/* possible Viewer config values for type of viewer / export type PannellumPanoramaType = 'equirectangular' | 'cube' | 'multires';
/* utility enum for PannellumPanoramaType / export enum PannellumPanoramaTypeEnum { 'equirectangular', 'cube', 'multires' }
/* Calues that may be used for configuration. / export type PannellumCrossOrigin = 'anonymous' | 'use-credentials' ;
/** events that you may specify in API
export type PannellumEquirectangularConfig = PannellumSharedConfig & { / If a string is passed, it sets the URL to the equirectangular panorama image. This is relative to basePath if it is set, else it is relative to the location of pannellum.htm. An absolute URL can also be used. Alternatively, an already loaded image can be passed. */ panorama: string /* Sets the panorama's horizontal angle of view, in degrees. Defaults to 360. This is used if the equirectangular image does not cover a full 360 degrees in the horizontal. / haov?: number / Sets the panorama's vertical angle of view, in degrees. Defaults to 180. This is used if the equirectangular image does not cover a full 180 degrees in the vertical. */ vaov?: number / Sets the vertical offset of the center of the equirectangular image from the horizon, in degrees. Defaults to 0. This is used if vaov is less than 180 and the equirectangular image is not cropped symmetrically. */ vOffset?: number /* If set to true, any embedded Photo Sphere XMP data will be ignored; else, said data will override any existing settings. Defaults to false. / ignoreGPanoXMP?: boolean / Currently, only equirectangular dynamic content is supported. The panorama source is considered dynamic when this is set to true. Defaults to false. This should be set to true for video. */ dynamic?: boolean /* Currently, only equirectangular dynamic content is supported. The panorama source is considered dynamic when this is set to true. Defaults to false. This should be set to true for video. / dynamicUpdate?: boolean /* This specifies the panorama Type. it will need to be equirectangular in this config type, For cube please switch to PannellumCubeMapConfig and for multires please switch to PannellumMultiresConfig/ type: 'equirectangular' }
export type PannellumCubeMapConfig = PannellumSharedConfig & { /* This is an array of URLs for the six cube faces in the order front, right, back, left, up, down. These are relative to basePath if it is set, else they are relative to the location of pannellum.htm. Absolute URLs can also be used. Partial cubemap images may be specified by giving null instead of a URL. / cubeMap: string[] /* This specifies the panorama Type. it will need to be equirectangular in this config type, For equirectangular please switch to PannellumEquirectangularConfig and for multires please switch to PannellumMultiresConfig/ type: 'cube' }
export type PannellumMultiresConfig = PannellumSharedConfig & { / This is the base path of the URLs for the multiresolution tiles. It is relative to the regular basePath option if it is defined, else it is relative to the location of pannellum.htm. An absolute URL can also be used. */ basePath: string /* This is a format string for the location of the multiresolution tiles, relative to multiRes.basePath, which is relative to basePath. Format parameters are %l for the zoom level, %s for the cube face, %x for the x index, and %y for the y index. For each tile, .extension is appended. / path: string / This is a format string for the location of the fallback tiles for the CSS 3D transform-based renderer if the WebGL renderer is not supported, relative to multiRes.basePath, which is relative to basePath. The only format parameter is %s, for the cube face. For each face, .extension is appended. */ fallback: string / Specifies the tiles' file extension. Do not include the '.'. */ extension: string /* This specifies the size in pixels of each image tile. / tileResolution: number / This specifies the maximum zoom level. */ maxLevel: number / This specifies the size in pixels of the full resolution cube faces the image tiles were created from. */ cubeResolution: number /* Specifies the spherical-harmonic-transform-based preview hash. This is rendered instead of the background color before the base set of cube faces are loaded. / shtHash?: string / Specifies a equirectangular preview thumbnail to be rendered instead of the background color or SHT hash before the base set of cube faces are loaded. This image can either be specified as a Base64-encoded string or as an object that can be directly uploaded to a WebGL texture, e.g., ImageData, ImageBitmap, HTMLImageElement, HTMLCanvasElement objects. If a Base64-encoded string is used, the image size should be kept small, since it needs to be loaded with the configuration parameters. */ equirectangularThumbnail?: ImageData | ImageBitmap | HTMLCanvasElement /* This specifies the panorama Type. it will need to be equirectangular in this config type, For cube please switch to PannellumCubeMapConfig and for equirectangular please switch to PannellumEquirectangularConfig/ type: 'multires' }
export type PannellumSharedConfig = { / This specifies the panorama type. Can be equirectangular, cubemap, or multires. Defaults to equirectangular */ type: PannellumPanoramaType /* If set, the value is displayed as the panorama's title. If no title is desired, don't set this parameter. / title?: string / If set, the value is displayed as the panorama's author. If no author is desired, don't set this parameter. */ author?: string / If set, the displayed author text is hyperlinked to this URL. If no author URL is desired, don't set this parameter. The author parameter must also be set for this parameter to have an effect. */ authorURL?: string /* Allows user-facing strings to be changed / translated. See defaultConfig.strings definition in pannellum.js for more details. / strings?: PannellumStringsDictionary / This specifies a base path to load the images from. */ basePath?: string / If set to true, device orientation control will be used when the panorama is loaded, if the device supports it. If false, device orientation control needs to be activated by pressing a button. Defaults to false. Note that a secure HTTPS connection is required for device orientation access in most browsers. Additionally, this feature does not work in combination with autoLoad: true in most browsers, since a user interaction is required to prompt for permission. */ autoLoad?: boolean /* Setting this parameter causes the panorama to automatically rotate when loaded. The value specifies the rotation speed in degrees per second. Positive is counter-clockwise, and negative is clockwise. / autoRotate?: boolean / Sets the delay, in milliseconds, to start automatically rotating the panorama after user activity ceases. This parameter only has an effect if the autoRotate parameter is set. Before starting rotation, the viewer is panned to the initial pitch. */ autoRotateInactivityDelay?: number / Sets the delay, in milliseconds, to stop automatically rotating the panorama after it is loaded. This parameter only has an effect if the autoRotate parameter is set. */ autoRotateStopDelay?: number /* If set to true, device orientation control will be used when the panorama is loaded, if the device supports it. If false, device orientation control needs to be activated by pressing a button. Defaults to false. Note that a secure HTTPS connection is required for device orientation access in most browsers. Additionally, this feature does not work in combination with autoLoad: true in most browsers, since a user interaction is required to prompt for permission. / orientationOnByDefault?: boolean / If set to false, the zoom controls will not be displayed. Defaults to true. */ showZoomCtrl?: boolean / If set to false, zooming with keyboard will be disabled. Defaults to true. */ keyboardZoom?: boolean /* If set to false, zooming with mouse wheel will be disabled. Defaults to true. Can also be set to fullscreenonly, in which case it is only enabled when the viewer is fullscreen. Can also be set to ctrl, in which case the ctrl key must be held down to zoom with the mouse wheel (except while the viewer is fullscreen); when the ctrl key is required for mouse wheel zooming, the use of ctrl / shift for zoom control is disabled. / mouseZoom?: boolean | 'fullscreenonly' / If set to false, the zoom to click location on double click function will be disabled. Defaults to true. */ doubleClickZoom?: boolean / If specified, the hotspot can moved using the mouse or by touch. */ draggable?: boolean /* If specified, the hotspot can moved using the mouse or by touch. / dragConfirm?: boolean | 'pitch' | 'yaw' | 'both' / Controls the "friction" that slows down the viewer motion after it is dragged and released. Higher values mean the motion stops faster. Should be set (0.0, 1.0]; defaults to 0.15. */ friction?: number / If set to true, keyboard controls are disabled. Defaults to false. */ disableKeyboardCtrl?: boolean /* If set to false, the fullscreen control will not be displayed. Defaults to true. The fullscreen button will only be displayed if the browser supports the fullscreen API. / showFullscreenCtrl?: boolean / If set to false, no controls are displayed. Defaults to true. */ showControls?: boolean / Adjusts panning speed from touch inputs. Defaults to 1. */ touchPanSpeedCoeffFactor?: number /* Specifies the yaw portion of the hot spot’s location, in degrees. / yaw?: number / Sets the panorama’s starting pitch position in degrees. Defaults to 0. */ pitch?: number / If set to false, one finger can be used to pan viewer. Defaults to false. Can also be set to pitch, yaw, or both. If set to pitch or both, two fingers need to be used to pan vertically (except while the viewer is fullscreen). If set to yaw or both, two fingers need to be used to pan horizontally (except while the viewer is fullscreen). */ hfov?: number /* Sets the minimum yaw the viewer edge can be at, in degrees. Defaults to -180, i.e. no limit. / minYaw?: number / Sets the maximum yaw the viewer edge can be at, in degrees. Defaults to 180, i.e. no limit. */ maxYaw?: number / Sets the minimum / maximum pitch the viewer edge can be at, in degrees. Defaults to undefined, so the viewer center can reach -90 / 90. */ minPitch?: number /* If set to true, prevent displaying out-of-range areas of a partial panorama by constraining the yaw and the field-of-view. Even at the corners and edges of the canvas only areas actually belonging to the image (i.e., within [minYaw, maxYaw] and [minPitch, maxPitch]) are shown, thus setting the backgroundColor option is not needed if this option is set. Defaults to false. / maxPitch?: number / Sets the minimum horizontal field of view, in degrees, that the viewer can be set to. Defaults to 50. Unless the multiResMinHfov parameter is set to true, the minHfov parameter is ignored for multires panoramas. */ minHfov?: number / Sets the maximum horizontal field of view, in degrees, that the viewer can be set to. Defaults to 120. Unless the multiResMinHfov parameter is set to true, the minHfov parameter is ignored for multires panoramas. */ maxHfov?: number /* When set to false, the minHfov parameter is ignored for multires panoramas; an automatically calculated minimum horizontal field of view is used instead. Defaults to false. / multiResMinHfov?: boolean / If true, a compass is displayed. Normally defaults to false; defaults to true if heading information is present in Photo Sphere XMP metadata. */ compass?: boolean / Set the offset, in degrees, of the center of the panorama from North. As this affects the compass, it only has an effect if compass is set to true. */ northOffset?: number /* Specifies a URL for a preview image to display before the panorama is loaded. / preview?: string / Specifies the title to be displayed while the load button is displayed. */ previewTitle?: string / Specifies the author to be displayed while the load button is displayed. */ previewAuthor?: string /* Specifies roll of image horizon, in degrees (for correcting non-leveled panoramas). / horizonPitch?: number / Specifies roll of image horizon, in degrees (for correcting non-leveled panoramas). */ horizonRoll?: number / (API required)This specifies a timing function to be used for animating movements such as when the lookAt method is called. The default timing function is easeInOutQuad. If a custom function is specified, it should take a number [0, 1] as its only argument and return a number [0, 1]. */ animationTimingFunction?: ((number: number)=>number) /* When true, HTML is escaped from configuration strings to help mitigate possible DOM XSS attacks. This is always true when using the standalone viewer since the configuration is provided via the URL; it defaults to false but can be set to true when using the API. / escapeHTML?: boolean / When true, target="_blank" is set on most hyperlinks to open them in new tabs. This is always true when using the standalone viewer since said viewer is often used in an
/* A key value pairing object. See strings on PannellumSharedConfig or PannellumEquirectangularConfig or PannellumCubeMapConfig or PannellumMultiresConfig/ export type PannellumStringsDictionary = { //* Key value pairing /
}
export type PannellumTour = { /* sets the default scene / default: PannellumDefaultScene /* sets the scene key value pairs / scenes: PannellumScenes }
export type PannellumDefaultScene = { / required the first scene id */ firstScene: string /* Sets default author. If set, the value is displayed as the panorama's author. If no author is desired, don't set this parameter. / author?: string / Sets default Specifies the fade duration, in milliseconds, when transitioning between scenes. Not defined by default. Only applicable for tours. Only works with WebGL renderer. */ sceneFadeDuration?: number }
/* A multi scene configuration allowing multiple scenes durring init / export type PannellumScenes = { /* Key value paring for SceneId to scene config / key: string: PannellumEquirectangularConfig | PannellumCubeMapConfig | PannellumMultiresConfig }
export type PannellumHotSpot = { / Specifies the pitch portion of the hot spot's location, in degrees. */ pitch: number /* Specifies the yaw portion of the hot spot's location, in degrees. / yaw: number / Specifies the type of the hot spot. Can be scene for scene links or info for information hot spots. A tour (Scene) configuration file is required for scene hot spots. */ type: "info" | "scene" / This specifies the text that is displayed when the user hovers over the hot spot. */ text: string /* If specified for an info hot spot, the hot spot links to the specified URL. Not applicable for scene hot spots. / URL?: string / Specifies URL's link attributes. If not set, the target attribute is set to _blank, to open link in new tab to avoid opening in viewer frame / page. */ attributes?: object / Specifies the ID of the scene to link to for scene hot spots. Not applicable for info hot spots. */ sceneId?: string /* Specifies the pitch of the target scene, in degrees. Can also be set to same, which uses the current pitch of the current scene as the initial pitch of the target scene. / targetPitch?: number / Specifies the yaw of the target scene, in degrees. Can also be set to same or sameAzimuth. These settings use the current yaw of the current scene as the initial yaw of the target scene; same uses the current yaw directly, while sameAzimuth takes into account the northOffset values of both scenes to maintain the same direction with regard to north. */ targetYaw?: number / Specifies the HFOV of the target scene, in degrees. Can also be set to same, which uses the current HFOV of the current scene as the initial HFOV of the target scene. */ targetHfov?: number /* Specifies hot spot ID, for use with API's removeHotSpot function. / id?: any / If specified, string is used as the CSS class for the hot spot instead of the default CSS classes. */ cssClass?: string / If createTooltipFunc is specified, this function is used to create the hot spot tooltip DOM instead of the default function. The contents of createTooltipArgs are passed to the function as arguments. */ createTooltipFunc?: ((createTooltipArgs: object)=> void) /* For use with createTooltipFunc. The contents of createTooltipArgs are passed to the createTooltipFunc function as arguments. / createTooltipArgs?: object / If clickHandlerFunc is specified, this function is added as an event handler for the hot spot's click, pointerup, and touchend events. The event object and the contents of clickHandlerArgs are passed to the function as arguments. */ clickHandlerFunc?: ((createArgs: object)=> void) / For use with createTooltipFunc. The event object and the contents of clickHandlerArgs are passed to the createTooltipFunc function as arguments. */ clickHandlerArgs?: object /* If specified, the hotspot can moved using the mouse or by touch. Defaults false / draggable?: boolean / If dragHandlerFunc is specified, this function is added as an event handler when dragging of the hotspot starts and ends. The event object and the contents of dragHandlerArgs are passed to the function as arguments. Possible types of the event object are: mousedown, pointerdown, touchend, pointerup, pointerleave, mouseup, and mouseleave. */ dragHandlerFunc?: ((createArgs: object)=> void) /* The event object and the contents of dragHandlerArgs are passed to the function dragHandlerFunc as arguments. / dragHandlerArgs?: object /* When true, the hot spot is scaled to match changes in the field of view, relative to the initial field of view. Note that this does not account for changes in local image scale that occur due to distortions within the viewport. If set to a number, a fixed scaling is applied relative to the default hot spot size. Defaults to false. / scale?: boolean }
export interface PannellumRender{ /**
Destroy renderer. */ destroy(): void }
export interface PannellumViewer { /**
@returns Viewer this */ off(type?: PannellumEventType, callback?: ((event: Event)=>void)): PannellumViewer /* destroys object for clean up / destroy(): void }
/**
Extended window with pannellum access added via interface */ interface Window { /**
/**
/**
4. Add it to the component. Here I'm giving an example of a rough reusable component. It's a rough init of my first component, It simply is for a simple single .jpg equirectangular. Feel free to remix it! Maybe kill it for a Tour version or Keep it and make another Tour version (idk), but it should be a good start point for the remix!
a. Component:
```typescript
import { AfterViewInit, Component, Input, OnDestroy } from '@angular/core';
import { PannellumCubeMapConfig, PannellumEquirectangularConfig, PannellumHotSpot, PannellumMultiresConfig, PannellumPanoramaType, PannellumPanoramaTypeEnum, PannellumViewer } from '../pannellum/pannellum';
@Component({ selector: 'pannellum-panorama', templateUrl: './pannellum-panorama.component.html', styleUrls: ['./pannellum-panorama.component.scss'] }) export class PannellumComponent implements AfterViewInit, OnDestroy { @Input() panoramaId: string = "panorama" @Input() panoramaSrc: string | null = null; @Input() panoramaType: PannellumPanoramaType = "equirectangular" @Input() options: PannellumEquirectangularConfig | PannellumCubeMapConfig | PannellumMultiresConfig | null = null; @Input() hotSpots: PannellumHotSpot[] | null = null;
private pannellumViewer: PannellumViewer | null = null
private ensureArray(array: any[] | null | undefined): any[] { return array ?? []; }
private initPanorama(): void { //Creating the viewer as per docs. I would recommend a function for this. note the options are set in another component as an input. //Note the viewer will not auto update, If you want to up date the viewers settings you would need to call destroy from api and then recall this function from an exposed function or a setter function as input or use provided API. For the purposes here I think that might complicate the how to and this is not a library just a how to, so I will leave more advanced features up to you. For instance you could provide support for PannellumTour types provided in the types above. this.pannellumViewer = globalThis.window.pannellum.viewer(this.panoramaId, { ...this.options, type: this.panoramaType, panorama: this.panoramaSrc, //fixes a bug with lib where the array not being set in config breaks api hotSpots: [...this.ensureArray(this.options?.hotSpots), ...this.ensureArray(this.hotSpots)] } as PannellumEquirectangularConfig) }
constructor() { }
//Make sure to wait for component to be initialized. Not sure why the other guy need to destroy, but I'm not having that issue. Just make sure it is after View init. If you may not have the html generated as of yet ngAfterViewInit(): void { this.initPanorama(); }
//Make sure to clean up on component destruction and a good example of the API use after initialized or NgInit's. This is actually important! ngOnDestroy(): void { if(this.pannellumViewer != null) { this.pannellumViewer.destroy(); } } }
b. scss (simply to get you started) you can remix this too (or you could just inline style it.)!:
```scss
::ng-deep .panorama-container { //::ng-deep and important ensure it is added, but ng- deep is deprecated so please find a better fix
width: 100% !important;
height: 500px !important;
}
::ng-deep .panorama-frame {
border: 2px solid black !important;
height: 100% !important;
}
::ng-deep #panorama {
height: 100% !important;
}
c. HTML Template:
<div class="panorama-container">
<div class="panorama-frame">
<div id="{{panoramaId}}"></div>
</div>
</div>
@Component({
selector: 'app-root',
standalone: false,
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'Your App';
//you should get intellisense help since you defined the types when working in an appropriate IDE! YAY! public options: as PannellumEquirectangularConfig= { compass: true, autoRotate: true } } as PannellumEquirectangularConfig; //cast to get rid of the error of not having type field included.
HTML template one line add:
```html
<!--options can be set as per the docs in the .components.ts and you can change the source to locally hosted files etc-->
<pannellum-panorama [panoramaSrc]="'https://pannellum.org/images/alma.jpg'" [options]="options"></pannellum-panorama>
After that I'm sure you have everything you need to get started with the docs and refine what I have here.
Has anyone tried to use this in Angular2 via dependency injection? Looking for guidance on how to lazy load it...
I am currently initializing the plugin through the Window object, via Window as a provider to NgModule. Unfortunately, this requires it to load on App start and not at time of call.