I am hoping it is possible to create, say, a Paper.Path object that is not attached to a scope. The reason I need to do this is because I have a few parser classes who's job it is to generate geometry from a gerber file, they should not have any influence over the PaperScope's canvas. A simple separation of concerns.
For example: (this code won't work)
import paper, {Path, Point} from 'paperjs';
let path = new Path([new Point(100, 100), new Point(200, -50)]);
paper.addPath(path); <- this doesn't exist but you get the point.
There are no obvious ways to go about this, and the paperjs docs seem to tout this "clever scoping" as a feature, but it's really been a pain to work with...
You can setup Paper.js so that it doesn't insert newly created in the scene by default. You have to set paper.settings.insertItems = false when initializing your app (see the documentation).
If you want some items to be part of the scene and other not, you can have a finer control over whether they are inserted or not by passing an insert: true/false parameter to the constructor.
Here is a sketch demonstrating this behavior.
// Switch this to true to see the difference.
const INSERT = false;
const circle = new Path.Circle({
center: view.center,
radius: 50,
fillColor: 'orange',
insert: INSERT
})
Related
I'm using the aframe-particle-system-component, and was using .setAttribute() on the tick() function to update the particle system in real time, but it performed terribly, leading to almost instant memory-related crashes. Is there a way to directly access the maxAge, opacity, and enabled properties of the system? I'm assuming this is the best way to tackle this as the framework advises that .object3D is directly accessed for performance reasons. I would like to be able to access the particle system in a similar manner. Any help is appreciated.
tldr: here's an example with animated opacity, size, and some toggles. Switching max age seems to wait until all current particles are gone, though no word about it in the docs.
1. Gutting the particle system
The particle system is based on the ShaderParticleEngine, so modyfing it won't be that THREE.js'ish.
From what I can tell, the particle-system creates and stores SPE.Emitter's. You can access them here:
let particleSystem = this.el.component['particle-system']
let emitterGroup = particleSystem.particleGroup.emitters
Changing values - for example, if you have one emitter:
emitterGroup[0].disable() // disables the emitter
emitterGroup[0].opacity.value = 0.1 // sets the opacity
2. A job for a-frame custom components
I'd create a custom component - which will upon any change iterate through the emitter group and change the attributes:
AFRAME.registerComponent('particle-controller', {
schema: {
opacity: {default: 1}
},
init: function() {
let system = this.el.components['particle-system']
this.emitterGroup = system.particleGroup.emitters
},
update: function() {
this.setValueInEmitters(this.emitterGroup, 'opacity', this.data.opacity)
},
// may come in handy when changing more key-value pairs
setValueInEmitters(group, prop, value) {
for (let i = 0; i < group.length; i++) {
group[i].prop.value = value
}
}
})
The schema could be fed with key-value pairs or such to make the component more universal.
3. Why setAttribute is so heavy
Gathering from the source code, any change removes the old particle group and creates a new one from scratch.
On map using cluster layer to display the marker , on API call loading the data on reload i need to clear clustered marker in the map please help on this issue,normal marker to clear using current method (map.removeObjects(map.getObjects()) it working as excepted but i need remove default cluster marker
Please find the below code :
startClustering(map, data) {
// First we need to create an array of DataPoint objects,
// for the ClusterProvider
// tslint:disable-next-line:ter-prefer-arrow-callback
const dataPoints = data.map(function (item) {
console.log('item>>>>', item);
return new H.clustering.DataPoint(item.y, item.x);
});
const clusteredDataProvider = new H.clustering.Provider(dataPoints, {
clusteringOptions: {
// Maximum radius of the neighbourhood
eps: 1,
// minimum weight of points required to form a cluster
minWeight: 2,
},
});
// Create a layer tha will consume objects from our clustering provider
const clusteringLayer = new H.map.layer.ObjectLayer(clusteredDataProvider);
// To make objects from clustering provder visible,
// we need to add our layer to the map
map.addLayer(clusteringLayer);
}
i need to remove this cluster marker before call this funcation
The easiest approach will be to keep a reference to the cluster layer you wish to remove and then remove it by:
Given a reference called clusteringLayer:
map.removeLayer(clusteringLayer);
The other alternative of using map.getLayers() to retrieve all map layers and removing each layer via map.removerLayer(<layerRef>) might remove layers you do not wish to remove.
In my openlayers 5 (based on a angular 6 app), I am implementing a functionality where you search for something, query the db, the db brings back some geoJSON and I render this geoJSON data in a ol vector layer.
There are two different ways to search, so there are two different forms that bring back geoJSOn to the same ol vector.
Of course, before rendering the data, I have to clear out the layer.
This is my code
ngOnInit() {//initialize some params and the ol map
//bring results-as you type - pure angular
this.results = this.myForm.valueChanges.pipe(
switchMap( formdata => this.mapcmsService.searchName(formdata.name, formdata.cepDrop))
);//pipe
this.tilesource = new OlXYZ({
url:'http://tile.stamen.com/terrain/{z}/{x}/{y}.jpg'
});
this.tilelayer = new OlTileLayer({
source: this.tilesource
});
this.vectorsource = new VectorSource({});
this.vectorlayer = new VectorLayer({
source: this.vectorsource
});
this.view = new OlView({
center: OlProj.fromLonLat([6.661594, 50.433237]),
zoom: 2,
});
this.olmap = new OlMap({
target: 'map',
layers: [this.tilelayer,this.vectorlayer],
view: this.view,
projection: 'EPSG:3857'
});
const selectClick = new Select({
condition: click,
layers:[this.vectorlayer]
});
this.olmap.addInteraction(selectClick);
selectClick.on(
'select', ()=>{
const values = selectClick.getFeatures().item(0).values_;
this.getDetails(values.id);
}
);
} //closes ngOnInit
Outside the ngOnInit, after the initialization,there are the two different functions that bring geoJSON to the same ol vector layer. They basically do the same thing.
searchById(id){
this.map_loading = true;
this.myService.getById(id).subscribe((data) =>{
this.vectorsource.refresh();
this.vectorsource.clear();
const fff = (new GeoJSON()).readFeatures(data.data);
this.vectorsource.addFeatures(fff);
this.map_loading = false;
})
}//searchById
and
searchCategories(){
this.map_loading = true;
this.myService.categoriesSearch(this.categoriesForm.value).subscribe((data) =>{
this.vectorsource.refresh();
this.vectorsource.clear();
const fff = (new GeoJSON()).readFeatures(data.data);
this.vectorsource.addFeatures(fff);
this.map_loading = false;
})
}//searchCategories
The problem is that the ol vector source is not always cleared before new features are added. I search for something, features are rendered. I search again , and sometimes, the old features remain on the map, along with the new ones.
I did a silly move to add refresh with clean and nothing is fixed. This is not standard, eg every other search. This randomly happen and I dont have a clue how to debug it. Please advice
Thanks
Is there an unique id for each feature?
I had the same problem that features were loaded constantly. I used the bbox-strategy and every time I moved the map, it loaded all the features in the extent, even if they were already there.
I had to set an unique id in the data for my features, so OpenLayers can refer to the existing ones if you load new ones. This randomness maybe comes through the generated ids for the features, that are sometimes equal to the new ones and sometimes not.
Dont know if that faces your problem, it just flew into my brain while I read that.
I have a meteor template rendering a document comming out of mongo db.
Parts of the document are editable (they render as html input elements).
Now I need the data to flow back into the document (and into mongo),
What is the best way to do this ?
The answer is easy if I want to write back the value of doc.a :
doc = {a: "hello"}
it is less easy with : doc.a[0].z
doc = {a: [{z: "hello"}]}
because in order to do the update, the path must be remembered
in order to write the update statement.
Updating the whole document whenever a field changes looks simple,
but inefficient...
It is an extremely common use case, some frameworks (EmberJs) have
magical bindings that modifies the model whenever the widget's value
changes.
How is this done in meteor ?
As you point out, it would probably be inefficient to run a db update command whenever the input changes. This is especially true for draggable elements like sliders.
One thing you can do is separate the db query into a function, and then debounce it using underscore.js, like so (untested):
var debouncedUpdate = _.debounce(function(newObject) {
CollectionName.update({_id: newObject._id},newObject);
},300,true);
Template.objectInput.events({
'keydown #text-input': function(event) {
var newValue = $(this.find('#text-input')).val();
var self = this;
self.value = newValue;
debouncedUpdate(self);
},
});
I've a layout template with a left sidebar where I show information of Location passed entities as an array.
Also in this template, I show a object Map with all of this locations.
I want to do click on a Location of my sidebar and then on the same template show another object Map replacing the previous with information of this Location. Keeping the sidebar with the information and not doing new queries on the database.
How to achieve this?
Ajax? Conditional layout?
I read this article but I don't understand how to solved my problem: http://twig.sensiolabs.org/doc/recipes.html#overriding-a-template-that-also-extends-itself
PD: I'm using Twig template and Symfony2
You could have a separate template for printing object map and, as you guessed, this would have to be done using AJAX. You would pass the data you want to show on map (not id as you don't want to query database again) and the controller would return formatted HTML.
However, this seems to me a bit overkill. I would always consider doing JS (with optional framework) in order to swap the content of sidebar with Map object.
It really depends on which map API do you use. If it could be controlled via JS I would look no further. It it could not, well then, AJAX is your natural choice....
UPDATE:
OK, what you should do is create initial Map object that will be modified later on:
var theMap = null;
function initializeMap(){
var mapOptions = {
center: new google.maps.LatLng(some_latitude, some_longitude),
zoom: 8, // goes from 0 to 18
mapTypeId: google.maps.MapTypeId.ROADMAP
};
theMap = new google.maps.Map(document.getElementById("map_canvas"),mapOptions);
// you must have some element with ID = 'map_canvas'
}
some_latitude and some_longitude are fairly unimportant as you will most likely set new coordinates in a few moments.
Now assuming (but not crucial at all) that you use some of the JS frameworks (I prefer jQuery) you could bind click event to those location links:
var onlyMarker = null;
$('.location').click(function(){
var $t = $(this);
var newLatLang = new google.maps.LatLng($t.attr('data-lat') ,$t.attr('data-lng'));
if ( onlyMarker == null ) {
onlyMarker = new google.maps.Marker({
position: newLatLang
map: theMap,
title: $t.attr('title')
});
}else{
onlyMarker.setPosition(newLatLang);
}
});
Now, relying on HTML5's 'data-*' attibutes is not good idea in particular as if you use any other version lower you will most likely end-up with invalid markup. The workaround is to for link (<a>) to carry id/key to LatLng object, for example:
// initially generated from `AJAX` or in `Twig` loop
var allLatlangs = [
new google.maps.LatLngf(some_latitude, some_longitude),
new google.maps.LatLngf(some_latitude, some_longitude),
new google.maps.LatLngf(some_latitude, some_longitude),
];
$('.location').click(function(){
var id = $(this).attr('id');
var newLatLang = allLatLang(id);
//....
// everything else is the same
// ....
});
Don't forget to include Maps API with proper API key:
https://maps.googleapis.com/maps/api/js?key=API_KEY_HERE&sensor=true
In order to obtain valid API key follow this link: API KEY HOW-TO
This link basically covers key steps that I have described here so study it and it should all come together nicely.
Also, if you're unsure how to retrieve some things from Maps you should consult reference:
REFERENCE which has every method call described pretty good
Remember not to execute any of this code until everything is being loaded.
Hope this helped a bit :)