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

Loading an external SVG file. #29

Open
Salitehkat opened this issue Jul 7, 2018 · 30 comments
Open

Loading an external SVG file. #29

Salitehkat opened this issue Jul 7, 2018 · 30 comments
Labels

Comments

@Salitehkat
Copy link

Salitehkat commented Jul 7, 2018

Hi,
Is it possible to load in "rect" an external SVG file instead of an image? (cross fingers..)
Ive been looking some examples, like this one. [https://github.com//issues/27]

and tried to change it to and svg file instead but no success.

Thanks lots in advance for any help.

@Salitehkat
Copy link
Author

For anyone please refer here:

here

@iangilman
Copy link
Member

Did you get it to work using the CodePen example? That example uses the Snap library to help out, but presumably it's possible without an extra library if you want.

Anyway, the basic idea is you open up the external SVG and pull elements out of it and drop them into the SVG attached to the OpenSeadragon viewer.

@Salitehkat
Copy link
Author

I found the Snap library and did the work. It took me ages to understand the positioning and size of the svg but im on the way. Thanks !

@iangilman
Copy link
Member

Glad to hear it's working out :)

@vortice3D
Copy link

vortice3D commented Jul 11, 2018

Hi Salitehkat.

Could you please explain more in deep how have you made to have the referred Codepen working?

Even resolving the CORS issue (downloading and playing it all from a local HTTP server) and with not console errors, it still doesn't show any SVG at all for me.

Best regards.

@vortice3D
Copy link

vortice3D commented Jul 11, 2018

Hi again Salitehkat:

Forgive me my last comment. I've finally succedeed to have it working (only a mistake with paths).

BTW, Any advice about your statement: "It took me ages to understand the positioning and size of the svg"?

Best regards.

@Salitehkat
Copy link
Author

Hi, honestly didnt finish understanding it completely. Sometimes it works, sometimes it doesnt. What ive been concluding is that if your svg file measures 300px width, you have to put the same width in the viewer part

var viewer = OpenSeadragon({ id: "contentDiv", prefixUrl: "//openseadragon.github.io/openseadragon/images/", tileSources: [{ tileSource: tileSource, width: 300 }] });

This will show the svg same size as your viewport (like 1:1).

ps: My page is 100% width.

Finally ive seen that some svg grabbed form the internet work much better. MIne sometimes show, sometimes they dont, and the positions are not clear. So I have to check well about making proper svg.

here is a guideline that helps.

Im still experimenting. Ill post each success (if any ;).

suerte!

@vortice3D
Copy link

vortice3D commented Jul 11, 2018

Hi Salitehkat; and thank you very much for your support.

At the moment I've been able to show basic SVGs but, as you say, other more complicated files (with symbols) are not shown completely. This is strange because if I drop that SVG file directly on the browser (FF, Chrome, IE,...) it is shown flawless (?).

Other aspect of this developing is that I'd prefer not to use any third parties SVG lib, and implement the functionality with my own vanilla JavaScript; but well, when I have all this working with Snap, will be the time to deal with it.

Thanks for your time.

P.S. BTW, the guideline you are mentioning is a very good reference.

@iangilman
Copy link
Member

One thing to note about that codepen is that it's assuming there's just a single element at the top of the SVG that needs copying over (a g). In reality, some SVGs have a lot of elements that aren't grouped into a g, or maybe there are a bunch of groups or whatever.

Another thing to keep in mind is the SVG has its own idea for how big it should be drawn (i.e. the coordinates of all of its elements). You may need to wrap the whole thing in a transform to adjust it as you need.

@vortice3D
Copy link

vortice3D commented Jul 13, 2018

Ok, Ian:

Now I have all working and w/o the help of any third party lib, as I prefer The loading mechanism is a standard Ajax procedure and I can position and scale all with the help of a syntax like this:
g.setAttribute("transform", "translate(0.4,0.3)scale(0.0025)");

The truth is that in all this process of having the SVG (g blocks indeed) embedded fine, the use of FF Document Inspector was of a great help.

However, a strange think happens, and I'd like to ask you about it: the SVG is only shown briefly (of course with a correct style, position and size) and then immediately hidden behind (I suppose as I can´t see it) the OSD image.

Do you have an idea of what can be happening here with the SVG element? I'm tried to set z-index to a large value (i.e. 9999) w/o any different behavior.

Thanks for your time.

P.S. BTW I'm using also a standard OSD overlay (in order to show a focus rect styled via CSS), which is shown w/o problem over the image.

@vortice3D
Copy link

vortice3D commented Jul 13, 2018

Hi again:

Please, forgive my last comment.

The apparent "hiding" of SVG elements was only a temporal visualization effect.

The SVG elements seems to be shown first, at the center of the still-not-shown image (where I have my viewport focused) and then re-positioned (transform applied) to their final coordinates.

In my case that coordinates where at the top of the image and out of my view.

@vortice3D
Copy link

vortice3D commented Jul 13, 2018

And again here:

Well, to complete my last comment, doing the things in a proper way, that is, waiting to have the image loaded before loading the SVGs, by means of:

_viewer.addHandler('open', function() { ... _loadSVG(...); ... }

avoids the "phantom" effect.

My fault.

Thanks for your time.

@iangilman
Copy link
Member

Fantastic! Glad to hear you're getting it figured out. Looks like you were able to sort it all out :)

I wonder if you might be able to share some of the knowledge you've gained doing this... I don't know if it would be a blog post or some sample code or a plugin, but I'm guessing you're not the only one who would like to be able to add SVG like this!

@vortice3D
Copy link

Ok Ian, as soon as I have all the modules working together I'll try to follow your recommendation.

Well, I feel like I've kidnapped this Salitehkat 's thread for my own purposes. In that case I wanted to apologize.

Best regards.

@iangilman
Copy link
Member

Sounds good, and no worries as far as I'm concerned... I hope @Salitehkat doesn't mind. :)

@Salitehkat
Copy link
Author

Of course, and more of course not. Never.

@Salitehkat
Copy link
Author

Hi,
After testing with D3 and Snap, my question is: is it posible to load an external SVG without using any extra library but only using the OSD svgOverlay? (no snap, no d3). I am trying to find examples but didnt succeed. If its posible, is there any code example ?
I am trying to minimize as much as posible the resources.

Thank you very much.

@vortice3D
Copy link

Hi Salitehkat:

If you don't need any high-level functionality from a specific library, you can do it all with vanilla JavaScript.

Loading is done the standard ajax way, and all the rest is not very complicated.

I'll be able to be more specific tomorrow evening, as I will be in front of my computer (not my phone like now) then.

Best regards.

@Salitehkat
Copy link
Author

Thanks! It would be a super help.
Danke again.

@vortice3D
Copy link

vortice3D commented Jul 27, 2018

Well, as introduced in other threads of this forum, you can load the SVG in the classic ajax-way:

function _loadSVG(path, callback) {
		var xhr = new XMLHttpRequest();
		xhr.onload = function(e) {
			try {
				if (xhr.readyState == 4 && xhr.status == 200) {
					callback(xhr.responseXML.documentElement);
				}
			} catch(e) {
				console.log(e);
			}
		};
		//
		xhr.open("GET", path, true);
		xhr.overrideMimeType("text/xml");
		xhr.responseType = "document";
		xhr.send();
	}

Then, you only need to process the data retrieved in the best way, depending of your source SVG structure or the use you want to do of it in your own code.

This way, for the processing of a simple SVG file with a top-level group (g) element:

_loadSVG(path, function(data) {
				var g = data.getElementById("group-identifier");
				_osdSVG.node().appendChild(g);
				//
				...
			});

Where of course the group-identifier string must be changed for your own SVG group tag ID name.

If you want to implement a more sophisticated processing of the SVG file, when it is for example a multi-layered SVG (a layer is actually a group), you could do:

_loadSVG(path, function(data) {
				_osdSVG.node().appendChild(data.getElementsByTagName("defs")[0]);
				//
				var g=document.createElementNS("http://www.w3.org/2000/svg", "g");
				g.id="0461005"; //of course here goes whatever you prefer
				g.appendChild(data.getElementById("layer1"));
				g.appendChild(data.getElementById("layer2"));
				g.appendChild(data.getElementById("layer3"));
				g.appendChild(data.getElementById("layer4"));
				_osdSVG.node().appendChild(g);
...
});

I hope this helps you a bit.

Best regards.

P.S: Excuse me for the lack of indentation in the code blocks. Ian said me to use ``` in order to fix it but using it that way shows all my post formatted as code (?)

@iangilman
Copy link
Member

@vortice3D Thank you for sharing this! I've fixed your code formatting... You just need to add the ``` around each block. You can edit your comment to see how I did it. I didn't fix the indents, but you could do that (just shift them back a bit). :)

@Salitehkat
Copy link
Author

Wow, thanks! im still trying to figure how it works. I am super basics in this language, actually quite illiterate. Ill be testing today and send back a feedback. Thanks a lot for your time. !

@Salitehkat
Copy link
Author

Hi vortice3D, sorry to disturb. Please can you show me a full example (for level -20 of understanding?). I tried this weekend but its all so new that I couldnt adapt the code you provided and load the svg. Sorry so much for my low level and thanks for your time.

@Salitehkat
Copy link
Author

Hi, testing I get this error:

ReferenceError: _osdSVG is not defined

Where do I have to define _osdSVG?

thanks so much again.

@Salitehkat
Copy link
Author

FINALLY!!

`var overlay = viewer.svgOverlay();

			var path = "images/svg.svg";

			
						function _loadSVG(path, callback) {
				var xhr = new XMLHttpRequest();
				xhr.onload = function(e) {
					try {
						if (xhr.readyState == 4 && xhr.status == 200) {
							callback(xhr.responseXML.documentElement);
						}
					} catch(e) {
						console.log(e);
					}
				};
				//
				xhr.open("GET", path, true);
				xhr.overrideMimeType("text/xml");
				xhr.responseType = "document";
				xhr.send();
			}

			
		_loadSVG(path, function(data) {
			var g = data.getElementById("elements");

			
			overlay.node().appendChild(g);
			
	
			
		});

`

Thankuuu!

@vortice3D
Copy link

Hi, Salitehkat:

I'd like to apologize for not responding your last request, but I've been out of the city for holidays.

Luckily, I can see you have been able to solve it yourself.

Best regards.

@Salitehkat
Copy link
Author

Yes ;) many thanks for providing the code.
enjoy holidays.

@Salitehkat
Copy link
Author

Salitehkat commented Aug 21, 2018

Hi,
I have svg element animations happening as soon as the whole SVG is loaded, but its inconsistent because sometimes the svg loads after the animation functions are loaded (so i cant access the elements). Is there a way to stop any other function from running till the svg has been loaded completely? (not only after starting the loadSvg function but also the when the svg has completely loaded? No matter how many tryouts ive done I cant figure how.

var path = "images/svg.svg";
function _loadSVG(path, callback) {
var xhr = new XMLHttpRequest();
try {
if (xhr.readyState == 4 && xhr.status == 200) {
callback(xhr.responseXML.documentElement);
}
} catch(e) {
console.log(e);
}
};
xhr.open("GET", path, true);
xhr.overrideMimeType("text/xml");
xhr.responseType = "document";
xhr.send();
}
_loadSVG(path, function(data) {
var g = data.getElementById("elements");
overlay.node().appendChild(g);
});`

Thanks so much for any help or tip.

@vortice3D
Copy link

vortice3D commented Aug 21, 2018

Hi Salitehkat:

All you need to do is moving the code you want to be executed as soon as the SVG is loaded to the callback, this way:

_loadSVG(path, function(data) {
  var g = data.getElementById("elements");
  overlay.node().appendChild(g);
  //
  runRenderLoop();
});

where runrenderLoop launchs the render on a per-frame basis, i.e. renderFrame at 60FPS (if available):

function renderFrame(){
  updateThis();
  drawThis();
  //  
  updateThat();  
  drawThat();
  ...
}

function runRenderLoop(){
  var timer=window.setInterval(renderFrame,1000/60);
}

Best regards.

@Salitehkat
Copy link
Author

Merci!!!

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

No branches or pull requests

3 participants