SVG internal url links and iframes on wirecloud - iframe

Wirecloud uses iframes to render the html of widgets. This seems to create problems for some advanced svg features that require references to internal definitions (see also this discussion).
The js code producing the svg works fine in single page app or django view.
There are no error messages.
The entire code is too big to post here, but the key relevant elements are:
var canvas = document.getElementById("canvas");
var svgns = "http://www.w3.org/2000/svg";
var svg = document.createElementNS(svgns, 'svg');
then a typical definition (for example a gradient):
var defs = document.createElementNS(svgns, "defs");
var linearGradient = document.createElementNS(svgns, "linearGradient");
and finally the use of the definition
arc.setAttribute('style', "fill:url(about:srcdoc#linearGradient);");
It is the reference (here to #linearGradient) that is not properly linked to when the svg object is created (when inspecting the created graphics the fill attribute is null)
Normally in svg you just use url(#reference). Have tried "about:blank" and "about:srcdoc" as workarounds as suggested elsewhere on SO but somehow they don't seem to work (chrome / firefox)
This seems to be an issue with svg / iframe (not wirecloud specific) but I have not tried to render the svg in iframe outside wirecloud to confirm this.
If there is no workaround this would limit the type of svg graphics that can be rendered within a wirecloud widget programmatically using javascript. Maybe some of the other ways of embedding svg would work (fetching it from the server) but its not optimal design for interactive widgets, or maybe an iframe alternative :-)

All the architecture of WireCloud is based on iframes. Those elements are used for providing the isolation between each of the widgets and operators and, currently, cannot be disabled. Moreover, the proposed alternative (webcomponents) is not matured enough to be a real alternative :(.
Anyway, WireCloud doesn't make use of the srcdoc attribute, so your problem rendering SVG images inside widgets should not be related to the linked question. The problem seems to be related to the use of the <base> element (which is injected by WireCloud into the HTML of the widget). See this answer for more details. We have created a ticket for analysing if we can remove the <base> element, but for now, you will have to use absolute URLs. E.g.:
var baseUrl = window.location.origin + window.location.pathname + window.location.search;
arc.setAttribute("fill", "url(" + baseUrl + "#MyGradient)");
This is the full code of my "SVG example widget":
var baseUrl = window.location.origin + window.location.pathname + window.location.search;
var svgns = "http://www.w3.org/2000/svg";
var svg = document.createElementNS(svgns, 'svg');
document.body.appendChild(svg);
var defs = document.createElementNS(svgns, "defs");
var linearGradient = document.createElementNS(svgns, "linearGradient");
linearGradient.setAttribute("id", "MyGradient");
defs.appendChild(linearGradient);
svg.appendChild(defs);
var stop = document.createElementNS(svgns, "stop");
stop.setAttribute("offset", "5%");
stop.setAttribute("stop-color", "green");
linearGradient.appendChild(stop);
stop = document.createElementNS(svgns, "stop");
stop.setAttribute("offset", "95%");
stop.setAttribute("stop-color", "gold");
linearGradient.appendChild(stop);
var rect = document.createElementNS(svgns, "rect");
rect.setAttribute("x", "10");
rect.setAttribute("y", "10");
rect.setAttribute("width", "100");
rect.setAttribute("height", "100");
rect.setAttribute("fill", "url(" + baseUrl + "#MyGradient)");

Related

openlayers-3 change external wms layer styles

Is it possible change the style of a external wms layer??
im trying to use this layer:
https://firms.modaps.eosdis.nasa.gov/wms/?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=fires24&width=400&height=250&BBOX=-26,34,35,82
with this code on openlayers3
var fill = new ol.style.Fill({color: 'GREEN'});
var stroke = new ol.style.Stroke({color: 'GREEN'});
var styles = [new ol.style.Style({
image: new ol.style.Circle({
fill: fill,
stroke: stroke,
radius: 5
})
})];
var fires = new ol.layer.Image({
name: 'fires',
source: new ol.source.ImageWMS({
url: 'https://firms.modaps.eosdis.nasa.gov/wms/',
params: {
'LAYERS': 'fires24',
'VERSION': '1.1.1'
}
}),
style: styles
});
the layer is displayed correctly but without my own styles.
Is it possible to do that or replace with a custom icon?
The WMS link you use is returning a PNG file, which I believe OpenLayers cannot style 'after the fact'. Once you've got it it's immutable - it's not 'data' but an image with transparency that is overlaid on top of your underlying map source.
There are some params you can pass into a wms call (as you've done) and the standard looks like it can support you passing styles into the call to the WMS server to get it to use those when rendering the image.
I've got a list of possible parameters from the geoserver website (a GIS server) - http://docs.geoserver.org/stable/en/user/services/wms/reference.html
Looking at that link it looks like sld or sld_body parameters may work. SLD is like OL styles but in XML. Details of these stylesheets are here - http://docs.geoserver.org/stable/en/user/styling/index.html#styling
I've had a go at this jsfiddle : https://jsfiddle.net/y7fj57dj/ but it's not working as such - it could either be my SLD (I'm not up to speed with it) or the NASA server doesn't know what to do with it/is ignoring it.
You may need to contact NASA server admins to confirm if you can style the WMS calls (support#earthdata.nasa.gov, retrieved by going to https://firms.modaps.eosdis.nasa.gov/wms/?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetCapabilities).

How to attach style when convert svg to image

All:
Right now, I want to draw a svg and style it with external style. Everything goes well until I try to down load it:
function chartExporter(svg){
// svg is a D3 object
svg.attr("version", 1.1)
.attr("xmlns", "http://www.w3.org/2000/svg");
var svgDOM = svg.node();
var html = svgDOM.outerHTML;
var imgsrc = 'data:image/svg+xml;base64,'+ btoa(html);
imgobj.src = imgsrc;
imgobj.onload = function(){
var a = document.createElement("a");
a.download = "sample.svg";
a.href = imgsrc;
a.click();
}
}
The problem here is: If I use D3 to add inline style or attributes, the svg downloaded seems good, but if I use external css file to include style, those styles can not be applied to svg when converted( it make sense, cos they are not in that html string), I wonder how to bring those style into svg?
Thanks

Set canvas element as background of a div element

We can use canvas for drawing custom shapes.
I need to draw my shape dynamically as a canvas item and place it for a div background item.
My pages generates run time and they aren't static html code so i can't use tricky methods.
What's your idea?
Regards
Looks like you searching for toDataURL().
UPD:
Here a usage exaple:
dataUrl = your_canvas.toDataURL();
your_div.style.background='url('+dataUrl+')'
Live demo on jsFiddle
Sounds like you need canvas2image: https://github.com/hongru/canvas2image
You can create a canvas and then get the contents as a png:
var canvas = document.createElement("canvas");
....do stuff here...
var img = Canvas2Image.convertToPNG(canvas, canvas.width, canvas.height);
Then all you need to do is use the png as a background image:
document.body.style.background = "url(" + img.src + ")";
Please correct me if any of this is wrong.

SVG to PNG with Embedded Style Sheet

I'm interested in creating a PNG from SVG. I followed the code given in:
https://developer.mozilla.org/en-US/docs/HTML/Canvas/Drawing_DOM_objects_into_a_canvas
But the image does not come out right due to styling from CSS. I made a local CSS file and do an import into the SVG, as described in:
How to apply a style to an embedded SVG?
But it does not appear to be using the style sheet. Any ideas why I would have this error?
Thanks.
Have a look at PhantomJS - You need to install it then either write your own script or run something along these lines:
phantomjs rasterize.js http://ariya.github.com/svg/tiger.svg tiger.png
You can also save to PDF, set Zoom setting, etc.
You could use html2canvas to generate a canvas from any dom element (including svg elements).
However, style definitions for svg elements defined in stylesheets are not applied to the generated canvas. This can be patched by adding style definitions to the svg elements before calling html2canvas.
Inspired on this article, I've created this:
function generateStyleDefs(svgDomElement) {
var styleDefs = "";
var sheets = document.styleSheets;
for (var i = 0; i < sheets.length; i++) {
var rules = sheets[i].cssRules;
for (var j = 0; j < rules.length; j++) {
var rule = rules[j];
if (rule.style) {
var selectorText = rule.selectorText;
var elems = svgDomElement.querySelectorAll(selectorText);
if (elems.length) {
styleDefs += selectorText + " { " + rule.style.cssText + " }\n";
}
}
}
}
var s = document.createElement('style');
s.setAttribute('type', 'text/css');
s.innerHTML = "<![CDATA[\n" + styleDefs + "\n]]>";
//somehow cdata section doesn't always work; you could use this instead:
//s.innerHTML = styleDefs;
var defs = document.createElement('defs');
defs.appendChild(s);
svgDomElement.insertBefore(defs, svgDomElement.firstChild);
}
// generate style definitions on the svg element(s)
generateStyleDefs(document.getElementById('svgElementId'));
// after generating the style defintions, call html2canvas
html2canvas(document.getElementById('idOfElement')).then(function(canvas) {
document.body.appendChild(canvas);
});
The example at
"How to apply a style to an embedded SVG?" as you mentioned should work. You need to define youObjectElement in this line of code when you test it.
var svgDoc = yourObjectElement.contentDocument;
try again.

Using Jcrop ,could not refresh preview pane correctly when changing image

I am trying to use Jcrop with preview pane in the page of changing avatar. However, after uploading new image file, when I call setImage to set the new image(with different width/height) and also set the attr of the preview image, the preview pane show up incorrectly. I use firebug the trace, it seems the img is still using the height, width of previous image. I modify the tutorial3 in the download package, simply adding a botton to change the image to see if the preview pane is correct or not. I seem to be the same error. Here below is the code for button click function.
Any solutions?
$('#img1').click(function(e) {
$('#preview').attr('src','demo_files/img50d5753eb067c.jpg');
jcrop_api.setImage('demo_files/img50d5753eb067c.jpg');
$('#target').Jcrop({
onChange: updatePreview,
onSelect: updatePreview,
aspectRatio: 1,
boxWidth: 450
},function(){
// Use the API to get the real image size
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
// Store the API in the jcrop_api variable
jcrop_api = this;
});
});
I see the same problem with yours in this topic Change an Image while using JCrop and the answer of AdmSteck in which is the best one.
Hope this help!
within the unminified version of the plugin "boundx and boundy" are declared as local variables that do not get updated outside of the setImage function. All you need to do is remove the 'var' for these two variables and make them global.
from line 328,
var boundx = $img.width(),
boundy = $img.height(),
$div = $('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({
position: 'relative',
backgroundColor: options.bgColor
}).insertAfter($origimg).append($img);
change to
boundx = $img.width();
boundy = $img.height();
var $div = $('<div />').width(boundx).height(boundy).addClass(cssClass('holder')).css({
position: 'relative',
backgroundColor: options.bgColor
}).insertAfter($origimg).append($img);

Resources