I used https://github.com/Autodesk-Forge/viewer-react-express-headless as a starting point for my Forge React application and I modified viewer = new Autodesk.Viewing.Viewer3D(viewerElement, {}); to viewer = new Autodesk.Viewing.Private.GuiViewer3D(viewerElement, {}); to change it back from a headless to a classic viewer.
I can load my model but it appears without edges and when I go to Settings -> Performance -> Display edges it is off by default, and when I try to set it back the edges stay invisible.
From my non wokring viewer:
When I try the same operation with the same model loaded on Autodesk Viewer it works as expected and I can toggle the visibility of the edges.
From the Autodesk Viewer
I found another seemingly related question on stackoverflow, but I tried viewer.js?v=v4.2, viewer.js?v=v5.0 and viewer.js?v=v6.3.1 and I still have the invisible edges issue.
I also posted a Github Issue
Thank you for your help.
Alexis
ok, if you are creating the viewer instance via
Autodesk.Viewing.Private.GuiViewer3D directly, rather than the
Autodesk.Viewing.ViewingApplication, then there is a magic configuration parameter that you will need to apply when initializing the Forge viewer, so that the lines will appear...
To fix it, an extra option
isAEC: true must be passed into the
modelOptions in your code, see below:
var modelOptions = {
placementTransform: mat,
globalOffset:{x:0,y:0,z:0},
sharedPropertyDbPath: doc.getPropertyDbPath(),
isAEC: true //!<<< Here is the missing line
};
viewer.loadModel(svfUrl, modelOptions, onLoadModelSuccess, onLoadModelError);
Related
Background:
I'm currently integrating HERE maps into our web-based application. I'm trying both - HERE provided Javascript API and Leaflet at the same time to find the best approach for our use-case.
While JavaScript API provided by HERE maps is OK, rendering wise Leaflet performs much better when using raster tiles.
Issue:
It would be fine by me to use raster tiles + leaflet, but our application also needs to display traffic incidents data.
Traffic incident data is provided by HERE in JSON and XML formats (Documentation link, Example JSON). They provide [Z]/[X]/[Y], quadkey, prox, bbox, or corridor filters which can be used to retrieve filtered data set.
I've tried using [Z]/[X]/[Y] addressing with custom L.TileLayer implementation which loads appropriate JSON, converts it to GeoJSON and displays GeoJSON on map. However that approach is very inefficient and significant performance drop is visible.
Question:
Maybe anyone has already solved this issue and could share any insights on how the HERE traffic incidents could be shown on Leaflet map without encountering performance issues?
I created the following script, which works without any performance issues:
var fg = L.featureGroup().addTo(map);
function loadTraffic(data) {
fg.clearLayers();
var d = data.TRAFFICITEMS.TRAFFICITEM.map((r) => {
var latlngs = [];
if (r.LOCATION.GEOLOC) {
if (r.LOCATION.GEOLOC.ORIGIN) {
latlngs.push(L.latLng(r.LOCATION.GEOLOC.ORIGIN.LATITUDE, r.LOCATION.GEOLOC.ORIGIN.LONGITUDE));
}
if (r.LOCATION.GEOLOC.TO) {
if (L.Util.isArray(r.LOCATION.GEOLOC.TO)) {
r.LOCATION.GEOLOC.TO.forEach((latlng) => {
latlngs.push(L.latLng(latlng.LATITUDE, latlng.LONGITUDE));
})
} else {
latlngs.push(L.latLng(r.LOCATION.GEOLOC.TO.LATITUDE, r.LOCATION.GEOLOC.TO.LONGITUDE));
}
}
}
var desc = r.TRAFFICITEMDESCRIPTION.find(x => x.TYPE === "short_desc").content;
return {
latlngs,
desc
}
})
console.log(d);
d.forEach((road)=>{
L.polyline(road.latlngs,{color: 'red'}).addTo(fg).bindPopup(road.desc);
});
map.fitBounds(fg.getBounds())
}
If this script is not working for you, please share your json file.
Ok, so I've found a solution for this task. Apparently I was on a good path, I only needed to optimize my implementation.
What I had to do to achieve appropriate performance is:
Create custom CircleMarker extension which would draw custom icon on canvas
Create JS worker which would fetch the data from a given URL, transform it to GeoJSON and return GeoJSON to it's listener
Create custom GridLayer implementation, which, in fetchTile function, creates worker instance, passes it a link with appropriate [Z]/[X]/[Y] coordinates already set, adds listener, which listens for worker's done event and returns empty tile
On worker's done event, custom GridLayer implementation creates GeoJSON layer, adds it to the dictionary with coordinates as a key and, if zoom level is still the same - adds that layer to the map
Add zoomend observer on a map, which removes any layers that does not match current zoom level from the map
Now the map is definitely usable and works way faster than original HERE JS API.
P.S. Sorry, but I can't share the implementation itself due to our company policies.
While it is easy enough to get firstPaint times from dev tools, is there a way to get the timing from JS?
Yes, this is part of the paint timing API.
You probably want the timing for first-contentful-paint, which you can get using:
const paintTimings = performance.getEntriesByType('paint');
const fmp = paintTimings.find(({ name }) => name === "first-contentful-paint");
enter code here
console.log(`First contentful paint at ${fmp.startTime}ms`);
Recently new browser APIs like PerformanceObserver and PerformancePaintTiming have made it easier to retrieve First Contentful Paint (FCP) by Javascript.
I made a JavaScript library called Perfume.js which works with few lines of code
const perfume = new Perfume({
firstContentfulPaint: true
});
// ⚡️ Perfume.js: First Contentful Paint 2029.00 ms
I realize you asked about First Paint (FP) but would suggest using First Contentful Paint (FCP) instead.
The primary difference between the two metrics is FP marks the point
when the browser renders anything that is visually different from what
was on the screen prior to navigation. By contrast, FCP is the point
when the browser renders the first bit of content from the DOM, which
may be text, an image, SVG, or even a canvas element.
if(typeof(PerformanceObserver)!=='undefined'){ //if browser is supporting
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log(entry.entryType);
console.log(entry.startTime);
console.log(entry.duration);
}
});
observer.observe({entryTypes: ['paint']});
}
this will help you just paste this code in starting of your js app before everything else.
I'm working on a problem where I want to display data in a dashboard both as a chart (via perak:c3) and in a table (via aslagle:reactive-table). My issue is that the data is pulled from a collection in MongoDB, and it's format is instantly amenable to plotting via c3, but needs to be transformed into a local collection to be used by the reactive-table package, as suggested in this answer to a previous question.
When I change the dataset to be displayed I want the chart to be updated, and the table also. This requires changing the values in the local collection, however, which slows things down and so rather than the chart being smoothly redrawn, there is a freeze on the page, and then the new data is displayed.
I have created a sample project on GitHub here so the problem can be replicated easily. If you run the app and select a dataset in your browser you will see exactly what I mean
To see the reactive behaviour I want to preserve in the chart go to client/templates/dashboard/dashboard.html and simply comment out the table template {{> dashboardTable}}
and now change the dataset to see how the chart is smoothly redrawn. Essentially I am trying to ensure both templates dashboardChart and dashboardTable render independently of one another.
UPDATE
Following Michael Floyd's suggestion of using a timeout helped a bit
Meteor.setTimeout(function(){createLocalCollection(data)},200);
but although the chart gets smoothly drawn, when the table finishes being filled, the chart is drawn again. It looks like it jumps to some intermediate state that I can't understand. Here is a video showing what I mean.
I'm adding this as a separate answer because it's a completely different approach.
Use the onRendered callback in d3 to invoke the local collection update.
Where you have:
chart = c3.generate({
bindto: '#dataset-chart',
in dashboard_chart.js, add:
chart = c3.generate({
onrendered: createLocalCollection(),
bindto: '#dataset-chart',
Of course you need to remove createLocalCollection(data) from your event handler.
To avoid having to pass the data context through the onrendered handler in d3 also update your createLocalCollection function to use the reactive variable datasetID that you defined earlier to establish the current dataset:
var createLocalCollection = function() {
var values = My_First_Collection.find({datasetID: datasetID.get()}).fetch();
var tempDoc = {};
local.remove({});
tempDoc = {};
for (var i in values[0].value) {
tempDoc.value = values[0].value[i];
tempDoc.date = values[0].date[i];
local.insert(tempDoc);
}
};
Using this method you let D3 tell you when the chart rendering is done and then your table can start getting populated. The result is an instantaneous chart update followed by the table updating. No mucking with timeouts either.
Remember that js is single threaded. You have two things to and they are going to happen sequentially. What you can do is defer the code that is updating the local collection using Meteor.setTimeout(). This will allow the chart to update first and then your table can update second. I've seen this before where you run a function that updates the DOM (in your case d3 is updating the svg canvas) but the actual screen update gets stuck behind long running js.
I tried this specifically and chart performance was fine.
Meteor.setTimeout(function(){createLocalCollection(data)},500);
Cutting the interval down to 100 allowed the chart to update but then the menu didn't fade out completely until the local collection finished updating.
One thing that I've used with tables and local collections is to only update the local collection document when the corresponding non-local document is being rendered on screen (assuming there's a 1:1 relationship between the original data and the transformed version). This allows the reactive table to load lazily.
I am using the heatmap.js library from pa7 in github successfully to make some heatmap
http://www.patrick-wied.at/static/heatmapjs/example-heatmap-leaflet.html
But when I updated the heatmap with additional data or new data points, the leaflet library does not really update with the additional data points. There seems to be no method that can used for redraw. I dont know if someone has already solved this problem, thats why I am asking to see. Here is the simple portion of my additional script:
ndata=[{lat: 13.59, lon:-17.05, value: 11},{lat: 33.08, lon:-103.24, value: 19}]
testData.data.push.apply(ndata)
layer.addData(testData.data);
There is no errors in the console of Google chrome or no exceptions.
Thanks
There is a redraw method in the layer:
var heatmapLayer = L.TileLayer.heatMap();
// add layer to map
heatmapLayer.redraw()
Having said this, in the latest version, the heatmap layer automatically redraws when you set the data (see https://github.com/pa7/heatmap.js/blob/d09c4e99852b4849e2b4d4f12976a9fce0327ca5/src/heatmap-leaflet.js#L112).
I need good examples and best practices on program architecture.
I'm trying to build a JS UI for an app that works with Google.Maps. In the 1st draft, user should be able to draw geometric shapes on the map in a way similar to G.M. Then the shapes are sent through AJAX and the response is displayed.
Problem is that the code got complicated just with polygons editing.
Inspired by Joel's "Duct-tape Programmer", I tried to sketch a straightforward code that makes actions and switches event handlers, to avoid big if-else trees. "New poly" button creates an observer for map.onclick, changes event handlers for other buttons or hides them, and hides itself, etc.
The downside of this approach is that data handling code is mixed with interface. A code that creates a div container to display the data on the new polygon stands next to the code that deals w/ G.M or w/ the shape data. If I want to revise the UI, I'll need to process the WHOLE app.
I could review it later and move this UI-generating code elsewhere, but then came my lead programmer. He instead insisted on "messaging" approach: a simple event system where objects subscribe to events and fire them. Interface code can be perfectly isolated from data handling and talking to G.M, but now each listener has to double-check if this message is to it.
For example, clicking on a poly on a map must highlight it and start editing. But not if another poly is being drawn. So, some are-you-talking-to-ME?-code is necessary everywhere.
I'll appreciate good examples of UI architecture approaches.
The event handling idea suggested to you is a good approach.
Here's some more ideas:
Make the shape drawing thing a component
The shape drawing component sends events to other code, to react to stuff like "editing" or "clicked"
This component could also handle the editing part - It sends "clicked" event to controller, controllers tells the component to go into edit mode
While in edit mode the component would not send normal "clicked" events until the editing was closed, avoiding your problem of having to check
In general, it's a good idea to have a "view" layer which simply deals with displaying the data and sending events about user actions on that data (ie. clicks, etc.) to a "controller" layer, which then decides what to do - for example it could decide to change the view into editing mode.
I don't know if this is beside the point. But I use this as a temple for all my javascript projects.
(function () {
var window = this,
$ = jQuery,
controller,
view,
model;
controller = {
addEventForMenu : function () {
// Add event function for menu
}
};
view = {
content : {
doStuff : function () {
}
},
menu : {
openMenuItem : function () {
}
}
};
model = {
data : {
makeJson : function () {
// make json of string
},
doAjax : function () {
},
handleResponse : function () {
}
}
}
$.extend(true, $.view, view);
})();
The good thing here is that it's only the view object that is extended to the DOM, the rest is kept inside the anonymous scope.
Also in bug project i create on of these files for each part ie, map.js, content.js, editor.js
If you just mind the naming of your methods in the view object you can have as many files as you like during development. When the project is set in to a production environment I just make it one file and minify it.
..fredrik
In short publisher-subscriber paradigm works well to make geometric shapes. First make command-line which primitive is base polygon publisher publishes. Canvas object seems obvious here to paint, usual method repaint() for updating the client view (eventdriven programming normally in C you can review eg opengl or glut eventdriven graphics), combined with the so-so gmap API I too use, publisher-subscriber pattern or factory are good design patterns whatever graphics implementation. tricky gmaps specific thing is latitude and longitude switch places in the array between json and persistence layer, there's no serverside reverse geocoding yet, naming is kinda inconsistent, and for multilingua apps names both change relative user human language and are doubled (Paris in Text, Paris in France...),. Look if you like my going implementation, registers geographic names and spatial coordinated relative user with geoip worldwide
function wAdd(response){
map.clearOverlays();
if(!response||response.Status.code!=200){
}
else{
try{
place=response.Placemark[0];
point=new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
marker=new GMarker(point);
map.addOverlay(marker);
marker.openInfoWindowHtml('<a href="/li?lat='+place.Point.coordinates[1]+'&lon='+place.Point.coordinates[0]+'&cc='+place.AddressDetails.Country.CountryNameCode+'">'+place.AddressDetails.Country.AdministrativeArea.Locality.LocalityName+'<span id="wr2"></span> '+ nads( place.Point.coordinates[1],place.Point.coordinates[0] )+' ' +'<img src="http://geoip.wtanaka.com/flag/'+place.AddressDetails.Country.CountryNameCode.toLowerCase()+'.gif">');
}
catch(e){
try{
place=response.Placemark[0];
point=new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
marker=new GMarker(point);
map.addOverlay(marker);
marker.openInfoWindowHtml('<a href="/li?lat='+place.Point.coordinates[1]+'&lon='+place.Point.coordinates[0]+'&cc='+place.AddressDetails.Country.CountryNameCode+'">'+place.AddressDetails.Country.AdministrativeArea.AdministrativeAreaName+'<span id="wr2"></span> '+ nads( place.Point.coordinates[1],place.Point.coordinates[0] )+' ' +'<img src="http://geoip.wtanaka.com/flag/'+place.AddressDetails.Country.CountryNameCode.toLowerCase()+'.gif">');
}
catch(e){
try {
place=response.Placemark[0];
point=new GLatLng(place.Point.coordinates[1],place.Point.coordinates[0]);
marker=new GMarker(point);
map.addOverlay(marker);
marker.openInfoWindowHtml('<a href="/li?lat='+place.Point.coordinates[1]+'&lon='+place.Point.coordinates[0]+'&cc='+place.AddressDetails.Country.CountryNameCode+'">'+place.AddressDetails.Country.CountryName+'<span id="wr2"></span> '+ nads( place.Point.coordinates[1],place.Point.coordinates[0] )+' ' +'<img src="http://geoip.wtanaka.com/flag/'+place.AddressDetails.Country.CountryNameCode.toLowerCase()+'.gif">');
}
catch(e){
place=response.Placemark[0];
marker=new GMarker(point);
map.addOverlay(marker);
marker.openInfoWindowHtml(''+place.address+'');
}
} }
}map.addOverlay(geoXml);
}
i would recommend having few object variables containing the state (0, drawing, editing, ... any other required) - this would help you deciding whether to allow event handling or just bury it if for example drawing is done and clicking on editable polygone happens.
as for the UI - I am not sure if your question is aimed at you - developing the script or at the user as you are mixing two things here.
keep in mind that for a user everything should be as simple as possible: if he is editing, don't allow him to draw. if he is drawing, don't allow him to edit (overlapping of polygons could occur). however - allow user quickly to switch from editing (e.g. right click?) to drawing - or in other words cancel the current state.
The first thing I would do is create a service that wraps over the google API. This is so that later if you need to change mapping services (windows maps or yahoo maps). Then you can put a facade over the google service. Then you might want to put some wrappers over your service and split it up into a view(output) and model(input) and manage this with controllers/presenters. Check into Model View Controller / Model View Presenter / Presenter First / Humble Dialog on Wikipedia. It should discuss the seperation that your looking for. Also Martin Fowler web page goes into presentation patterns. You should check out my old blog ugly-lisp-code. I have references to event driven/event messaging.
If you have a one-to-one pub/sub just store an event-handler(closure/lambda/first-order-function) in the object that is going to fire the event.
If you have a one-to-many pub/sub then you will need a more complex object to store your closures.
LOL! Right now I've been looking at this same exact issue. I'm going to be writing about using a presenter-first in JavaScript on my blog. A bare bones start on presenter and model.
[edit] you might want to check out this stackoverflow question. One of the answer has a link to separating concerns into MVC. The link is on A List Apart.