Select symbol definition path - paperjs

I need to view the segments and handles of the path that defines a SymbolItem. It is a related issue to this one but in reverse (I want the behavior displayed on that jsfiddle).
As per the following example, I can view the bounding box of the SymbolItem, but I cannot select the path itself in order to view its segments/handles. What am I missing?
function onMouseDown(event) {
project.activeLayer.selected = false;
// Check whether there is something on that position already. If there isn't:
// Add a circle centered around the position of the mouse:
if (event.item === null) {
var circle = new Path.Circle(new Point(0, 0), 10);
circle.fillColor = '#' + Math.floor(Math.random() * 16777215).toString(16);
var circleSymbol = new SymbolDefinition(circle);
multiply(circleSymbol, event.point);
}
// If there is an item at that position, select the item.
else {
event.item.selected = true;
}
}
function multiply(item, location) {
for (var i = 0; i < 10; i++) {
var next = item.place(location);
next.position.x = next.position.x + 20 * i;
}
}

Using SymbolDefinition/SymbolItem prevent you from changing properties of each symbol items.
The only thing you can do in this case is select all symbols which share a common definition.
To achieve what you want, you have to use Path directly.
Here is a sketch showing the solution.
function onMouseDown(event) {
project.activeLayer.selected = false;
if (event.item === null) {
var circle = new Path.Circle(new Point(0, 0), 10);
circle.fillColor = Color.random();
// just pass the circle instead of making a symbol definition
multiply(circle, event.point);
}
else {
event.item.selected = true;
}
}
function multiply(item, location) {
for (var i = 0; i < 10; i++) {
// use passed item for first iteration, then use a clone
var next = i === 0 ? item : item.clone();
next.position = location + [20 * i, 0];
}
}

Related

Paning the bubbles

is there a way of paning the bubble in the current view when there are regions which are outside the mapview?
E.g. https://dev2.gruppenunterkuenfte.de/nordrhein-westfalen__r187.html?vs=1
You can click on a bubble at the edge and you see them outside.
Using google: https://www.gruppenunterkuenfte.de/nordrhein-westfalen__r187.html?vs=1
will pan automatically in the full view ...
Regards
Chris
Might not be available out of the box, but something as follows could be done to check when opening the bubble and move the map center.
var checkBubble = function(evt) {
setTimeout(function() {
if(infoBubble && infoBubble.getState() == "open"){
var border = 50;
var objRect = infoBubble.getContentElement().parentElement.getBoundingClientRect();
var objStyleRight = Math.abs(parseInt(infoBubble.getContentElement().parentElement.style.right));
objStyleRight = objStyleRight ? objStyleRight : 0;
var mapRect = map.getElement().getBoundingClientRect();
var shiftX = 0;
var shiftY = 0;
// check, if infobubble isn't too far to up
if ((objRect.top-border) < mapRect.top) {
shiftY = (mapRect.top - (objRect.top-border));
}
// check, if infobubble isn't too far to the left
var objLeft = (objRect.left - objStyleRight);
if ((objLeft-border) < mapRect.left) {
shiftX = (mapRect.left - (objLeft-border));
} // check, if infobubble isn't too far to the right
else if ((objRect.right+border) > mapRect.right) {
shiftX = -(objRect.right - (mapRect.right-border));
}
if ((shiftX == 0) && (shiftY == 0)) {
return;
}
var currScreenCenter = map.geoToScreen(map.getCenter());
var newY = (currScreenCenter.y - shiftY);
var newX = (currScreenCenter.x - shiftX);
var newGeoCenter = map.screenToGeo(newX, newY);
map.setCenter(newGeoCenter, true);
}
}, 20);
}
map.addEventListener("mapviewchange",checkBubble);
Thanks a lot works great! I extend to the case that the bubble is outside at the bottom:
...
// check, if infobubble isn't too far to up
if ((objRect.top-border) < mapRect.top) {
shiftY = (mapRect.top - (objRect.top-border));
} else {
if ((objRect.bottom+border) > mapRect.bottom) {
shiftY = -(objRect.bottom - (mapRect.bottom-border));
}
}
...
Regards
Chris

How to normal-scale using threejs to make objects 'thicker' or 'thinner'

I'm trying to figure out how to extrude an already loaded .obj object to make it "thicker". I think I'm looking for a way to scale my object not from its anchor point but scaling it by each polygon normal.
A classic example would be to take a "ring" object. If you scale it up with just the normal scale methods it just gets bigger from the center but I want the ring to become thicker/thinner. Its called a 'normal scale' in cinema 4d.
Here's some example code of what I currently have, and which isn't giving me the expected result.
var objLoader = new THREE.OBJLoader();
var material = new THREE.MeshLambertMaterial({color:'yellow', shading:THREE.FlatShading});
objLoader.load('objects/gun/M1911.obj', function (obj) {
obj.traverse(function (child) {
if (child instanceof THREE.Mesh) {
child.geometry.computeVertexNormals();
child.material = material;
}
});
obj.material = material;
obj.scale.set(7, 7, 7);
scene.add(obj);
});
scaleGeo: function (geo, ratio) {
for (var i = 0; i < geo.faces.length; i++) {
var faceI = geo.faces[i];
var vertexArr = [faceI.a, faceI.b, faceI.c];
for (var j = 0; j < vertexArr.length; j++) {
var vertexJ = geo.vertices[vertexArr[j]];
var normalJ = faceI.vertexNormals[j];
if (vertexJ.hasScale) continue;
vertexJ.x += normalJ.x * ratio;
vertexJ.y += normalJ.y * ratio;
vertexJ.z += normalJ.z * ratio;
vertexJ.hasScale = true;
}
}
return geo;
},

creating a Placemarks that can be hidden

I have been trying to create a Placemark that I can hide and show (like turning visibility on and off) on demand (on click)... I am using this to make the placemark:
function placemark(lat, long, name, url, iconsrc){
var placemark = ge.createPlacemark(name);
ge.getFeatures().appendChild(placemark);
placemark.setName(name);
// Create style map for placemark
var icon = ge.createIcon('');
if(iconsrc == "0")
icon.setHref('http://maps.google.com/mapfiles/kml/paddle/red-circle.png');
else{
icon.setHref(iconsrc);
}
var style = ge.createStyle('');
style.getIconStyle().setIcon(icon);
if(iconsrc != "0")
style.getIconStyle().setScale(2.5);
placemark.setStyleSelector(style);
// Create point
var point = ge.createPoint('');
point.setLatitude(lat);
point.setLongitude(long);
//point.setAltitudeMode(1500);
placemark.setGeometry(point);
google.earth.addEventListener(placemark, 'click', function(event) {
// Prevent the default balloon from popping up.
event.preventDefault();
var balloon = ge.createHtmlStringBalloon('');
balloon.setFeature(placemark); // optional
balloon.setContentString(
'<iframe src="'+ url +'" frameborder="0"></iframe>');
ge.setBalloon(balloon);
});
}
I have tried everything... from this:
function hidePlacemark(name){
var children = ge.getFeatures().getChildNodes();
for(var i = 0; i < children.getLength(); i++) {
var child = children.item(i);
if(child.getType() == 'KmlPlacemark') {
if(child.getId()== name)
child.setVisibility(false);
}
}
}
to using this ge.getFeatures().removeChild(child);
can anyone point me to the right direction on creating a function that will allow me to turn the visibility on/off on demand please.
Your hidePlacemark function is missing some {} in your final IF statement
if(child.getId()== name)
you have
function hidePlacemark(name){
var children = ge.getFeatures().getChildNodes();
for(var i = 0; i < children.getLength(); i++) {
var child = children.item(i);
if(child.getType() == 'KmlPlacemark') {
if(child.getId()== name)
child.setVisibility(false);
}
}
}
make it
function hidePlacemark(name){
var children = ge.getFeatures().getChildNodes();
for(var i = 0; i < children.getLength(); i++) {
var child = children.item(i);
if(child.getType() == 'KmlPlacemark') {
if(child.getId()== name) {
child.setVisibility(false);
}
}
}
}
HOWEVER ------- you are better off doing this as it is much faster as you don't need to loop through ALL your placemarks
function hidePlacemark(name) {
var placemark = ge.getElementById(name);
placemark.setVisibility(false);
}
I think the plain ge.getFeatures().removeChild(placemark); works.
I played with this GooglePlayground, and just added the following code to line 8 (that is empty in this GooglePlayground Sample):
addSampleButton('Hide Placemark', function(){
ge.getFeatures().removeChild(placemark);
});
Clicking the button Hide Placemark hides the placemark like a charm here. Any chances your problem is somewhere else in your code?

Flex AS3: ProgressBar doesn't move

I am a little stuck and need some advice/help.
I have a progress bar:
<mx:ProgressBar id="appProgress" mode="manual" width="300" label="{appProgressMsg}" minimum="0" maximum="100"/>
I have two listener functions, one sets the progress, and one sets the appProgressMsg:
public function incProgress(e:TEvent):void {
var p:uint = Math.floor(e.data.number / e.data.total * 100);
trace("Setting Perc." + p);
appProgress.setProgress(p, 100);
}
public function setApplicationProgressStep(e:TEvent):void {
trace("Setting step:" + e.data);
appProgressMsg = e.data;
}
I want to reuse this progress bar alot. And not necessarily for ProgressEvents, but when going through steps.
For instance, I loop over a bunch of database inserts, and want to undate the progress etc.
Here is a sample:
public function updateDatabase(result:Object):void {
var total:int = 0;
var i:int = 0;
var r:SQLResult;
trace("updateDatabase called.");
for each (var table:XML in this.queries.elements("table")) {
var key:String = table.attribute("name");
if (result[key]) {
send(TEvent.UpdateApplicationProgressStep, "Updating " + key);
i = 1;
total = result[key].length;
for each (var row:Object in result[key]) {
//now, we need to see if we already have this record.
send(TEvent.UpdateApplicationProgress, { number:i, total: total } );
r = this.query("select * from " + key + " where server_id = '" + row.id + "'");
if (r.data == null) {
//there is no entry with this id, make one.
this.query(table.insert, row);
} else {
//it exists, so let's update.
this.update(key, row);
}
i++;
}
}
}
}
Everything works fine.
That is, the listener functions are called and I get trace output like:
updateDatabase called.
Setting step:Updating project
Setting Perc 25
Setting Perc 50
Setting Perc 75
Setting Perc 100
The issue is, only the very last percent and step is shown. that is, when it's all done, the progress bar jumps to 100% and shows the last step label.
Does anyone know why this is?
Thanks in advance for any help,
Jason
The new code, which works awesomely I might add:
public function updateDatabase(result:Object, eindex:int = 0, sindex:int = 0 ):void {
var total:int = 0;
var i:int = 0;
var j:int;
var r:SQLResult;
var table:XML;
var key:String;
var elems:XMLList = this.queries.elements("table");
var startTime:int = getTimer();
var row:Object;
for (i = eindex; i < elems.length(); i++) {
table = elems[i];
key = table.attribute("name");
if (!result[key])
continue;
total = result[key].length;
send(TEvent.UpdateApplicationProgressStep, "Updating " + key);
for (j = sindex; j < result[key].length; j++) {
if (getTimer() - startTime > 100) {
setTimeout(updateDatabase, 100, result, i, j);
send(TEvent.UpdateApplicationProgress, { number:j, total: total } );
return;
}
row = result[key][j];
r = this.query("select * from " + key + " where server_id = '" + row.id + "'");
if (r.data == null) {
//there is no entry with this id, make one.
this.query(table.insert, row,false);
} else {
//it exists, so let's update.
this.update(key, row,false);
}
}
send(TEvent.UpdateApplicationProgress, { number:1, total: 1 } );
}
}
Flash is single threaded. The display will not update until your function returns. For this reason, you should never have any code that runs for longer than about 100ms (1/10th of a second), otherwise the UI (or even the entire browser) will appear to be locked up.
The general solution is to split up your work over multiple frames, here is some pseudo-code:
function doWork(arg1:Obj, arg2:Obj, start:int=0) {
var startTime = getTimer(); // store starting time
for(i=start; i<length; i++) {
if(getTimer() - startTime > 100) { // see if we've been working too long
trace("Current progress: "+(i/length * 100)+"%");
updateProgress( i / length );
setTimeout(doWork, 100, arg1, arg2, i); // schedule more work to be done
return; // stop current loop
}
trace("Working on item "+i);
// processing here
}
trace("All work done");
}
doWork(data1, data2); // start the work
Your pseudo-code works for updating the progress bar however in my case my "work" was copying of files from DVD to the appStorageDirectory which seem to reintroduce the same issue that your work around resolved - the progress bar now does not update
Here is my hack of your solution
function doWork(arg1:int, arg2:int, start:int=0) {
var startTime = getTimer(); // store starting time
for(var i:int=start; i<arg2; i++) {
if(getTimer() - startTime > 100 ) { // see if we've been working too long
trace("Current progress: "+(i/arg2 * 100)+"%");
setTimeout(doWork, 100, i, arg2, i); // schedule more work to be done
return; // stop current loop
}
trace("Working on item "+i);
dispatchEvent(new progressMadeEvent("incrementChange",i,arg2))
var dir:String = copyRes[i].nativePath.toString().split(OSSep).pop()
copyRes[i].copyTo(appStore.resolvePath(dir)) // copies dir from DVD to appStorageDir
}
trace("All work done");
}

How to access children of children recursively?

I have a Canvas which has many components inside it and those again, have many components inside them.
getChildren() returns only the top level children. What is the best way to retrieve all the children (children of children of children and so on).
Well, I sorta know how to do this by iterating through the children, but the code is really messy. I'd prefer to use a nice recursive function. Has anyone written this before? Or is there a Util class to do this?
private function recuse(display : DisplayObjectContainer) : void {
if(display) {
for (var i : int = 0;i < _display.numChildren;i++) {
var child : DisplayObject = display.getChildAt(i);
trace(child.name);
if(child is DisplayObjectContainer) {
recuse(DisplayObjectContainer(child));
}
}
}
}
Try something likely (note you can return the lists recursively if you want to gather all the references to the top level iteration)
function inspect(object:DisplayObject):void
{
if(object is DisplayObjectContainer)
{
var casted:DisplayObjectContainer = object as DisplayObjectContainer
trace("DisplayObjectContainer ", casted.name)
for(var depth:int = 0; depth < casted.numChildren;depth++)
{
inspect(casted.getChildAt(depth))
}
}else{
trace("DisplayObject", object.name );
}
}
inspect(this)
function theCallbackFunction(obj:DisplayObject):void
{
trace(obj.name);
}
//Visit the children first.
//Deep most objects will be visited first and so on.
//stage is visited at the end.
//Uses recursion
function depthFirst(obj:DisplayObject, func:Function):void
{
if(!(obj instanceof DisplayObjectContainer))
{
func(obj);
return;
}
var p:DisplayObjectContainer = DisplayObjectContainer(obj);
var len:Number = p.numChildren;
for(var i:Number = 0; i < len; i++)
{
var child:DisplayObject = p.getChildAt(i);
depthFirst(child, func);
}
func(obj);
}
//Visit the siblings first.
//stage is visited first, then its children, then the grand children and so on
//No recursion.
function breadthFirst(obj:DisplayObject, func:Function):void
{
var q:Array = [];
q.push(obj);
var p:DisplayObjectContainer;
var i:Number, len:Number;
while(q.length != 0)
{
var child:DisplayObject = queue.shift();
func(child);
if(!(child instanceof DisplayObjectContainer))
continue;
p = DisplayObjectContainer(child);
len = p.numChildren;
for(i = 0; i < len; i++)
q.push(p.getChildAt(i));
}
}
depthFirst(this.stage, theCallbackFunction);
breadthFirst(this.stage, theCallbackFunction);

Resources