Parsing Entities in Cesium - kml

I have around 7k-8k placemarks in KML. I have to parse through each of the placemarks in cesium by importing the KML file. I have tried parsing through EntityCollection.values array but since not all the entities are placemarks, I find no other way of parsing through all placemark entities in Cesium.
I would like to know the following:
How are entities grouped in EntityCollection.values?
Is there any other way to access all placemark entities which are created when a KML file is imported?
I have tried to parse through the EntityCollection.values array and found out that only after an unspecified number of entities do the placemarks come.

When Cesium KmlDataSource loads a KML source, it flattens out the structure of the KML features such that Containers (Documents and Folders) and Placemarks are all added to an Entity Collection as an array in the order they appear in the source KML. All except the root-level container are populated in the array.
Here is an example to load a KML source into Cesium and iterate over the entities.
var url = "mykml.kml"; // source KML file path or URL
viewer.dataSources
.add(Cesium.KmlDataSource.load(url))
.then(
function (kmlData) {
parseElements(kmlData.entities)
}
);
function parseElements(entities) {
var e;
var pointCount = 0;
var values = entities.values;
console.dir(values); // debug the array
for (var i = 0; i < values.length; i++) {
e = values[i];
if (Cesium.defined(e.position)) {
// Placemark with Point geometry
pointCount++;
}
else if (Cesium.defined(e.polyline)) {
// Placemark with LineString geometry
}
else if (Cesium.defined(e.polygon)) {
// Placemark with Polygon geometry
}
// check for other conditions
}
console.log(pointCount); // dump # of point placemarks
viewer.flyTo(entities);
}
If the source KML has ExtendedData then you can access this extended data via the entity's kml property which is a KmlFeatureData object.
Example:
<Placemark>
...
<ExtendedData>
<Data name="holeNumber">
<value>1</value>
</Data>
<Data name="holeYardage">
<value>234</value>
</Data>
<Data name="holePar">
<value>4</value>
</Data>
</ExtendedData>
</Placemark>
If var "e" is an entity created from the KML above then the code snippet below will output value=234.
var data = e.kml.extendedData;
if (Cesium.defined(data)) {
console.log("value=", data.holeYardage.value);
}

Related

Why is svg generated by MathJax.js different than the svg generated by MathJax-node

I am writing an web app that saves html to onenote. In order to save math formulas, I plan to convert math formulas to svg by MathJax.js and then convert svg to png, because the html/css supported in onenote api is limited.
But it seems the svg generated by MathJax.js in browser is not a valid svg. I tested it with a simple math formula: $$a^2 + b^2 = c^2$$ (demo code) and copy the svg to jsfiddle and it displays nothing.
Then I tried to write a MathJax-node demo and copy the svg to jsfiddle again, it looks good. Here is my demo code, it's almost the same as the GitHub repo demo:
// a simple TeX-input example
const fs = require('fs')
var mjAPI = require("mathjax-node");
mjAPI.config({
MathJax: {
// traditional MathJax configuration
}
});
mjAPI.start();
var yourMath = String.raw`a^2 + b^2 = c^2`
mjAPI.typeset({
math: yourMath,
format: "TeX", // or "inline-TeX", "MathML"
svg: true, // or svg:true, or html:true
}, function (data) {
if (!data.errors) {console.log(data.svg)}
// will produce:
// <math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
// <mi>E</mi>
// <mo>=</mo>
// <mi>m</mi>
// <msup>
// <mi>c</mi>
// <mn>2</mn>
// </msup>
// </math>
fs.writeFile('math.txt', data.svg, (error) => {
console.log(error)
})
});
I also tested two svg with cloudconvert, it's the same result. Why are the two svg different? Do I miss something?
The difference is due to a specific setting: useGlobalCache
By default, MathJax (docs) sets this to true while mathjax-node (docs) sets this to false.
On the server MathJax-node does not have any document context and produces self-contained SVGs. On the client, MathJax has a full document context and thus can re-use the SVG paths across equations.

svg convert to canvas - can't generate multi pages pdf

I have 12 graphs and I want to generate pdf with 2 pages each page has 6 graphs.
However, when I convert svg to canvas, then the jspdf can only see part of both sub-dives.
$('#downloadx2').click(function() {
var svgElements = $("#body_id").find('svg');
//replace all svgs with a temp canvas
svgElements.each(function() {
var canvas, xml;
// canvg doesn't cope very well with em font sizes so find the calculated size in pixels and replace it in the element.
$.each($(this).find('[style*=em]'), function(index, el) {
$(this).css('font-size', getStylex(el, 'font-size'));
});
canvas = document.createElement("canvas");
canvas.className = "screenShotTempCanvas";
//convert SVG into a XML string
xml = (new XMLSerializer()).serializeToString(this);
// Removing the name space as IE throws an error
xml = xml.replace(/xmlns=\"http:\/\/www\.w3\.org\/2000\/svg\"/, '');
//draw the SVG onto a canvas
canvg(canvas, xml);
$(canvas).insertAfter(this);
//hide the SVG element
////this.className = "tempHide";
$(this).attr('class', 'tempHide');
$(this).hide();
});
var doc = new jsPDF("p", "mm");
var width = doc.internal.pageSize.width;
var height = doc.internal.pageSize.height;
html2canvas($("#div_pdf1"), {
onrendered: function(canvas) {
var imgData = canvas.toDataURL(
'image/png', 0.1);
doc.addImage(imgData, 'PNG', 5, 0, width, height/2,'','FAST');
doc.addPage();
}
});
html2canvas($("#div_pdf2"), {
onrendered: function(canvas2) {
var imgData2 = canvas2.toDataURL(
'image/png', 0.1);
doc.addImage(imgData2, 'PNG', 5, 0, width, height/2,'','FAST');
doc.save('.pdf');
}
});
});
<body id="body_id">
<div id="div_pdf1" >
<svg></svg>
<svg></svg>
<svg></svg>
</div>
<div id="div_pdf1" >
<svg></svg>
<svg></svg>
<svg></svg>
</div>
</body>
When I run this code, the generated pdf will view two pages with same canvas the first one (div_pdf1) div. So how to get both of them appearing in pdf as two pages.
You seem to be trying to run 2 parts in sequence but that's not how javascript works and actually runs your code.
No big deal, just a small misunderstanding between your mental model and the engine that executes the code.
A quick temporary debugging tool to see what's going on and verify that there is a discrepancy is to add console.log to key points and check the sequence of their printout once you run the code.
console.log('[1] just before: svgElements.each');
svgElements.each(function() {
console.log('[2] just after: svgElements.each');
And also around this part of the code:
console.log('[3] just before html2canvas-div_pdf1');
html2canvas($("#div_pdf1"), {
console.log('[4] just after html2canvas-div_pdf1');
Finally around this part of the code:
console.log('[5] just before html2canvas-div_pdf2');
html2canvas($("#div_pdf2"), {
console.log('[6] just after html2canvas-div_pdf2');
I suspect you'll see the code doesn't print the log lines in the order you think they will.
Next, you can try wrapping the 2 calls to html2canvas with one setTimeout function and force a delay in the execution of that code by an arbitrary amount of milliseconds.
Note that this is not the recommended final production quality solution but it will make the code output what you want.

Create xml file using SSJS

I want to create a xml file using SSJS on server. Is there a way to do so? Can anyone please give a sample code to create a xml file on server.
There are quite some ways. The seemingly easiest one is to create a string that looks like XML.
The next one would be the use of Java DOM classes. There is an article describing it.
Finally you can use SAX with a little helper class
Let us know how it goes.
Update: This would be my version of #Michael's code sample:
<?xml version="1.0" encoding="UTF-8"?>
<!-- XPage which is not rendered but returns data like XML, JSON, etc. -->
<!-- More: http://www.wissel.net/blog/d6plinks/shwl-7mgfbn -->
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
<xp:this.beforeRenderResponse><![CDATA[#{javascript:try {
var out = facesContext.getOutputStream();
var exCon = facesContext.getExternalContext();
var response = exCon.getResponse(); // get the response context
// set content type, e.g. ...
response.setContentType("text/xml");
// set caching option
response.setHeader("Cache-Control", "no-cache");
// write XML output ...
var result = new biz.taoconsulting.xmltools.SimpleXMLDoc();
result.setOut(out);
result.openTag("result");
result.dateTag("created", new java.util.Date());
result.addSimpleTag("Author",#UserName);
result.openTag("FruitList");
result.addComment("Stephan really likes the fruits example");
var attributes = new java.util.HashMap();
attributes.add("name","Durian");
attributes.add("color","white");
attributes.add("taste","Don't ask");
result.addEmptyTag("fruit",attributes);
result.closeDocument();
// close the output
exCon.responseComplete();
out.close();
} catch (e) {
print(e.toString());
}}]]>
</xp:this.beforeRenderResponse>
</xp:view>
Note the differences here:
I use the beforeRenderResponse event
Access to outputStream instead of writer (stream is not accessible in the afterRenderResponse event)
set the response complete to stop the page from further output, so you can simply type comments on the page what it does
use of the helper class
What seems a little odd when you read the source of the helper class: why not use the output stream in the constructor, so you won't miss it? - I would today add a second constructor with that, but the parameterless constructor allow me to define that class as a managed bean if I fancy that.
to "render" XML in a String as #Stefan suggested I would use the XAgent approach:
<?xml version="1.0" encoding="UTF-8"?>
<!-- XPage which is not rendered but returns data like XML, JSON, etc. -->
<!-- More: http://www.wissel.net/blog/d6plinks/shwl-7mgfbn -->
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
<xp:this.afterRenderResponse><![CDATA[#{javascript:try {
var writer = facesContext.getResponseWriter(), // get a writer object
response = facesContext.getExternalContext().getResponse(); // get the response context
// set content type, e.g. ...
response.setContentType("text/xml");
// set caching option
response.setHeader("Cache-Control", "no-cache");
// write XML output ...
writer.write(
'<?xml version="1.0"?>\n'
+ '<root>\n'
+ '<entity>Example Content</entity>\n'
+ '</root>\n'
);
// close the stream
writer.endDocument();
} catch (e) {
print(e.toString());
}}]]>
</xp:this.afterRenderResponse>
<xp:this.resources>
<xp:script src="/XBAN.jss" clientSide="false"></xp:script>
</xp:this.resources>
</xp:view>
Simply put his code into a newly created XPage and test it. Modify the lines in writer.write() to fit to your needs.

multiple d3 visualizations in one HTML document

I want to have multiple d3 visualizations in one document. My idea is to store some configuration such as url of the RESTful service along with the SVG tag attributes. On document load d3 would read in the attributes and load the data from the server and create the visualization. In this way I could edit / rearrange the document while keeping the visualizations intact.
My question is whether there is already a standardized way (best practice) of doing this? Or is there some plugin or something I could use?
change: I realized that I should mention that I want to create different documents with the same code. Consequently the document defines the content of the visualization (not the code).
A sample document with SVG attributes:
...
<head>
...
<svg width="200"... src="localhost:8000/rest/host1/cpu" type="os.line">...</svg>
<svg width="200"... src="localhost:8000/rest/host1/memory" type="os.bar">...</svg>
in the end I decided to move the configuration into paragraphs (integrates well with redactor):
<p class="plot" src="localhost:8000/rest/host1/cpu" type="os.line">...</p>
<p class="plot" src="localhost:8000/rest/host1/memory" type="os.bar">...</p>
... here is my code:
define(['lib/d3.v3.min'], function(ignore) {
var visualise = function(plugins) {
var _host = function(src) {
return src.split("/")[4];
};
var _plot = function(type) {
var parts = type.split(".", 2);
return plugins[parts[0]][parts[1]];
};
d3.selectAll("p.plot")
.each(function() {
var div = d3.select(this);
var plot = _plot(div.attr("type"));
var url = div.attr("src");
var host = _host(url);
d3.csv(url, function(data) {
div.call(plot, data, host);
});
});
};
return {visualise: visualise};
});
comments, improvements are more than welcome.
Why not just append each visualization to a different div?

How do I fill/stroke an SVG file on my website?

I Googled this issue for about 30 minutes and was surprised nobody has asked so maybe it's not possible.
I'm using this line to embed the SVG file that I made in AI (note that when I saved the SVG, I had no fill OR stroke on the paths):
<object type="image/svg+xml" data="example.svg" height=600px width=600px>Your browser does not support SVG</object>
This obviously comes up with no image because the SVG file has no fill or stroke.
I tried adding in
...fill=yellow>
or
...style="fill:yellow;">
but I'm not having any luck. Thanks!
Have a nice trick: Embed it as <img> and use javascript to convert it into inline <svg> with this code (that came from SO I think). Now you can manipulate this SVG object
CODE::
/*
* Replace all SVG images with inline SVG
*/
jQuery('img.svg').each(function(){
var $img = jQuery(this);
var imgID = $img.attr('id');
var imgClass = $img.attr('class');
var imgURL = $img.attr('src');
jQuery.get(imgURL, function(data) {
// Get the SVG tag, ignore the rest
var $svg = jQuery(data).find('svg');
// Add replaced image's ID to the new SVG
if(typeof imgID !== 'undefined') {
$svg = $svg.attr('id', imgID);
}
// Add replaced image's classes to the new SVG
if(typeof imgClass !== 'undefined') {
$svg = $svg.attr('class', imgClass+' replaced-svg');
}
// Remove any invalid XML tags as per http://validator.w3.org
$svg = $svg.removeAttr('xmlns:a');
// Replace image with new SVG
$img.replaceWith($svg);
});
});
Are you trying to add the fill or style on the object element? If so, that's not going to work. Those properties are not supported on the object element. You're going to have to add it into the SVG in the SVG file.

Resources