mpetroff / pannellum

Pannellum is a lightweight, free, and open source panorama viewer for the web.
https://pannellum.org/
MIT License
4.22k stars 718 forks source link

Use in Angular2? #508

Closed johnathandinh closed 6 years ago

johnathandinh commented 6 years ago

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.

mpetroff commented 6 years ago

I've never used Angular, but maybe someone else can help.

khanhvu161188 commented 6 years ago

@johnathandinh

  1. in angular-cli.json add vendor/pannellum/pannellum.js in "scripts" add vendor/pannellum/pannellum.css in "styles"
  2. in component: add declare var pannellum: any; and use like normal
    pannellum.viewer('panoramaContainer', {
      "type": "equirectangular",
      "panorama": photourl,
      "autoLoad": true,
      "compass": true
    });
johnathandinh commented 6 years ago

@khanhvu161188 So if I add it to the vendors, it won't get instantiated in the background on load?

Khurshid11 commented 6 years ago

@khanhvu161188 Thanks, it works perfectly for me.

mpetroff commented 6 years ago

Since this seems to be resolved, I'm closing the issue.

esanya commented 5 years ago

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

alegroSandermann commented 4 years ago

Hi, I would also know how to use it in angular 8. Can't get it work.

johnathandinh commented 4 years ago

@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()
  }
}
alegroSandermann commented 4 years ago

If I implement this I get the message: Property 'nativeWindow' does not exist on type 'Window & typeof globalThis'.

johnathandinh commented 4 years ago

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.

alegroSandermann commented 4 years ago

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

johnathandinh commented 4 years ago

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

What does not work specifically? Please share a snippet.

Right, I've removed that also from the snippet. Are you still seeing that?

alegroSandermann commented 4 years ago

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)

johnathandinh commented 4 years ago

Oh, you still have to init pannellum.

  1. in angular-cli.json add vendor/pannellum/pannellum.js in "scripts" add vendor/pannellum/pannellum.css in "styles"
  2. in component: add declare var pannellum: any; and use like normal
 pannellum.viewer('panoramaContainer', {
      "type": "equirectangular",
      "panorama": photourl,
      "autoLoad": true,
      "compass": true
    });
alegroSandermann commented 4 years ago

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.

jakubmank commented 4 years ago

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

saifkhan-786 commented 3 years ago

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``

saifkhan-786 commented 3 years ago

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``

almiavicas commented 3 years ago

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.

TheTrueTrooper commented 10 months ago

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.

  1. First install with
    npm i pannellum 
  2. Include the CSS one of three ways. I recommend the angular.json way or the first. Try to include it as early as possible if you want to override in components. angular.json:
    "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.

  3. Import the script. You can similarly do it multiple ways like above. I recommend angular,json since you really only need it to run once. But if you import to get lazy loading as I have done bellow that is fine.
    "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.

  4. Then define some type interfaces. here is a rough I did. I don't really want to be responsible for maintaining this and it is a bit roughed for the moment. But if a community would develop a definitely typed that would be great! You can copy and paste it into a file for now. Its really just the imports and some interface definitions for working with the JavaScript in typescript. Most of the comments and interfaces were scraped from the docs anyway,
    
    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