Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript/Angular implementation #34

Open
daanvanrobays opened this issue May 28, 2019 · 10 comments
Open

Typescript/Angular implementation #34

daanvanrobays opened this issue May 28, 2019 · 10 comments

Comments

@daanvanrobays
Copy link

Hello,

I am developing an angular application that uses openseadragon viewer and I'd like to place some svg overlays on this viewer.
However, I am having trouble getting the svg-overlay package initialized into the openseaviewer.

I've installed both npm packages and am importing them as shown below.

import * as OpenSeadragon from 'openseadragon';
import * as OsdSvgOverlay from 'svg-overlay';

this.openSeadragonViewer = OpenSeadragon({
     id: "openSeadragonContainer",
     ...
});

var overlay = this.openSeadragonViewer.svgOverlay();

After this code executes it throws an error saying that '.svgOverlay is not a function'.
I've also tried declaring them in another way

declare var OsdSvgOverlay: any;

But this throws the same error.

Is there something I am doing wrong here? Or can anyone who succesfully added this in a typescript / angular project share their expertise?

Thanks in advance!

@daanvanrobays daanvanrobays changed the title typescript implementation Typescript/Angular implementation May 28, 2019
@iangilman
Copy link
Member

I don't think there is an npm package for the svg-overlay:

https://www.npmjs.com/package/svg-overlay

Did you not get an error when you tried to install it?

At any rate, you may need to do some work to make it function with import. I'm actually not entirely sure how plugins should work in that kind of environment.

@daanvanrobays
Copy link
Author

daanvanrobays commented May 29, 2019

I referenced the package straight from github using the following:

"svg-overlay": "github:openseadragon/svg-overlay"

I eventually got it working by adding the file to my vendor.ts and writing this inside the openseadragon-svg-overlay.js file:

function OsdSvgOverlay( viewer ) {
    return new OsdSvgOverlay.Overlay( viewer );
}

and the import

import * as OsdSvgOverlay from '../../../../../wwwroot/lib/osd-svg-overlay/openseadragon-svg-overlay.js';

@iangilman
Copy link
Member

Good to know! Is there anything we can do to the plugin to make that process easier for the next person?

@gerstej9
Copy link

gerstej9 commented Jun 3, 2022

Have there been any updates on this in relation to React? I have been attempting to replicate this solution with a React/typescript app to be able to utilize the svg-overlay function with no luck. Any suggestions @iangilman or @daanvanrobays?

@iangilman
Copy link
Member

No updates as far as I'm aware of. What issues are you encountering? Are you getting any errors? Can you tell which part is working?

@gerstej9
Copy link

gerstej9 commented Jun 6, 2022

Thank you for the prompt response @iangilman! I had been trying to replicate the work done by daan and finally was able to get things working in React utilizing his suggestions. Below is how I setup the svg-overlay plugin within my repo.

// OpenSeadragon SVG Overlay plugin 0.0.5

var $ = window.OpenSeadragon;

if (!$) {
    $ = require('openseadragon');
    if (!$) {
        throw new Error('OpenSeadragon is missing.');
    }
}

var svgNS = 'http://www.w3.org/2000/svg';

// ----------
$.Viewer.prototype.svgOverlay = function () {
    if (this._svgOverlayInfo) {
        return this._svgOverlayInfo;
    }

    this._svgOverlayInfo = new Overlay(this);
    return this._svgOverlayInfo;
};

// ----------
var Overlay = function (viewer) {
    var self = this;

    this._viewer = viewer;
    this._containerWidth = 0;
    this._containerHeight = 0;

    this._svg = document.createElementNS(svgNS, 'svg');
    this._svg.style.position = 'absolute';
    this._svg.style.left = 0;
    this._svg.style.top = 0;
    this._svg.style.width = '100%';
    this._svg.style.height = '100%';
    this._viewer.canvas.appendChild(this._svg);

    this._node = document.createElementNS(svgNS, 'g');
    this._svg.appendChild(this._node);

    this._viewer.addHandler('animation', function () {
        self.resize();
    });

    this._viewer.addHandler('open', function () {
        self.resize();
    });

    this._viewer.addHandler('rotate', function (evt) {
        self.resize();
    });

    this._viewer.addHandler('flip', function () {
        self.resize();
    });

    this._viewer.addHandler('resize', function () {
        self.resize();
    });

    this.resize();
};

// ----------
Overlay.prototype = {
    // ----------
    node: function () {
        return this._node;
    },

    // ----------
    resize: function () {
        if (this._containerWidth !== this._viewer.container.clientWidth) {
            this._containerWidth = this._viewer.container.clientWidth;
            this._svg.setAttribute('width', this._containerWidth);
        }

        if (this._containerHeight !== this._viewer.container.clientHeight) {
            this._containerHeight = this._viewer.container.clientHeight;
            this._svg.setAttribute('height', this._containerHeight);
        }

        var p = this._viewer.viewport.pixelFromPoint(new $.Point(0, 0), true);
        var zoom = this._viewer.viewport.getZoom(true);
        var rotation = this._viewer.viewport.getRotation();
        var flipped = this._viewer.viewport.getFlip();
        // TODO: Expose an accessor for _containerInnerSize in the OSD API so we don't have to use the private variable.
        var containerSizeX = this._viewer.viewport._containerInnerSize.x;
        var scaleX = containerSizeX * zoom;
        var scaleY = scaleX;

        if (flipped) {
            // Makes the x component of the scale negative to flip the svg
            scaleX = -scaleX;
            // Translates svg back into the correct coordinates when the x scale is made negative.
            p.x = -p.x + containerSizeX;
        }

        this._node.setAttribute(
            'transform',
            'translate(' + p.x + ',' + p.y + ') scale(' + scaleX + ',' + scaleY + ') rotate(' + rotation + ')'
        );
    },
    // ----------
    onClick: function (node, handler) {
        // TODO: Fast click for mobile browsers

        new $.MouseTracker({
            element: node,
            clickHandler: handler,
        }).setTracking(true);
    },
};

export const OsdSvgOverlay = (viewer) => {
    return new Overlay(viewer);
};

I then import const { OsdSvgOverlay } = require('../../../utils/openseadragon/openseadragon-svg-overlay');

and call the function by passing in viewer const overlay = OsdSvgOverlay(viewer);

from there I can treat it the same as if it const overlay = viewer.svgOverlay()

Thanks again for the prompt response!

@iangilman
Copy link
Member

Looks great! Do you think it might be possible to update this repository to support this modality but also still support the "old fashioned" loading technique? I don't have a lot of experience with creating code that supports both, but surely people do it!

@gerstej9
Copy link

TBH I am not really sure how to go about doing that but if it would be helpful I would be more than happy to add a PR that adds a file of the overlay plugin configured in the way daan did it that I copied and then update the README with a section on implementation utilizing the new plugin. I don't know if that would be helpful or not but unfortunately that is probably the limit of what I would be able to do to help enhance the functionality.

@iangilman
Copy link
Member

I wouldn't want a duplicate copy of the code, since it would be harder to maintain, but I suppose one option would be to introduce a build step that spits out two copies of the code, each with the right "framing" elements. I wonder if that's how people generally do it?

No rush on this... Even having this conversation here is helpful to people! If you do run across any information on how to support both modalities, please let me know. And, of course, if you do have energy around implementing it, please do! We just need to make sure we're doing it cleanly :)

@gerstej9
Copy link

Yeah I hear you loud and clean on the "clean" approach. I'll definitely think through it and see if I can come up with anything!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants