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];
}
}
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;
},
We are trying to implement zoom buttons on top of a map created in D3 - essentially as it works on Google maps. The zoom event can be dispatched programmatically using
d3ZoomBehavior.scale(myNewScale);
d3ZoomBehavior.event(myContainer);
and the map will zoom using the current translation for the view. If using zoom buttons the focal point (zoom center) is no longer the translation but the center of the view port. For zoom using the scroll wheel we have the option of using zoom.center - but this apparently have no effect when dispatching your own event.
I'm confused as to how a calculate the next translation taking the new scaling factor and the view port center into account.
Given that I know the current scale, the next scale, the current translation and the dimensions of the map view port how do I calculate the next translation, so that the center of the view port do not change?
I've recently had to do the same thing, and I've got a working example up here http://bl.ocks.org/linssen/7352810. Essentially it uses a tween to smoothly zoom to the desired target scale as well as translating across by calculating the required difference after zooming to centre.
I've included the gist of it below, but it's probably worth looking at the working example to get the full effect.
html
<button id="zoom_in">+</button>
<button id="zoom_out">-</button>
js
var zoom = d3.behavior.zoom().scaleExtent([1, 8]).on("zoom", zoomed);
function zoomed() {
svg.attr("transform",
"translate(" + zoom.translate() + ")" +
"scale(" + zoom.scale() + ")"
);
}
function interpolateZoom (translate, scale) {
var self = this;
return d3.transition().duration(350).tween("zoom", function () {
var iTranslate = d3.interpolate(zoom.translate(), translate),
iScale = d3.interpolate(zoom.scale(), scale);
return function (t) {
zoom
.scale(iScale(t))
.translate(iTranslate(t));
zoomed();
};
});
}
function zoomClick() {
var clicked = d3.event.target,
direction = 1,
factor = 0.2,
target_zoom = 1,
center = [width / 2, height / 2],
extent = zoom.scaleExtent(),
translate = zoom.translate(),
translate0 = [],
l = [],
view = {x: translate[0], y: translate[1], k: zoom.scale()};
d3.event.preventDefault();
direction = (this.id === 'zoom_in') ? 1 : -1;
target_zoom = zoom.scale() * (1 + factor * direction);
if (target_zoom < extent[0] || target_zoom > extent[1]) { return false; }
translate0 = [(center[0] - view.x) / view.k, (center[1] - view.y) / view.k];
view.k = target_zoom;
l = [translate0[0] * view.k + view.x, translate0[1] * view.k + view.y];
view.x += center[0] - l[0];
view.y += center[1] - l[1];
interpolateZoom([view.x, view.y], view.k);
}
d3.selectAll('button').on('click', zoomClick);
A more succinct version of Wil's solution:
var vis = d3.select('.vis');
var zoom = d3.behavior.zoom()...
var width = .., height = ..;
function zoomByFactor(factor) {
var scale = zoom.scale();
var extent = zoom.scaleExtent();
var newScale = scale * factor;
if (extent[0] <= newScale && newScale <= extent[1]) {
var t = zoom.translate();
var c = [width / 2, height / 2];
zoom
.scale(newScale)
.translate(
[c[0] + (t[0] - c[0]) / scale * newScale,
c[1] + (t[1] - c[1]) / scale * newScale])
.event(vis.transition().duration(350));
}
};
function zoomIn() { zoomByFactor(1.2); }
function zoomOut() { zoomByFactor(0.8); }
I've found this to be quite difficult to do in practice. The approach I've taken here is to simply create a mouse event that triggers the zoom when the zoom buttons are used. This event is created at the center of the map.
Here's the relevant code:
.on("click", function() {
var evt = document.createEvent("MouseEvents");
evt.initMouseEvent(
'dblclick', // in DOMString typeArg,
true, // in boolean canBubbleArg,
true, // in boolean cancelableArg,
window,// in views::AbstractView viewArg,
120, // in long detailArg,
width/2, // in long screenXArg,
height/2, // in long screenYArg,
width/2, // in long clientXArg,
height/2, // in long clientYArg,
0, // in boolean ctrlKeyArg,
0, // in boolean altKeyArg,
(by > 0 ? 0 : 1), // in boolean shiftKeyArg,
0, // in boolean metaKeyArg,
0, // in unsigned short buttonArg,
null // in EventTarget relatedTargetArg
);
this.dispatchEvent(evt);
});
The whole thing is a bit of a hack, but it works in practice and I've found this much easier than to calculate the correct center for every offset/zoom.
I've found some excellent demos of how to mix together sound objects together for live playback. See the working example bellow...
But can it be done programmatically without any playback so I can just output the mixed file? Also I'll be adding some volume change info along the way so it'll need to be added in small chunks like how the play buffer works.
[Embed(source = "audio/track01.mp3")]
private var Track1:Class;
[Embed(source = "audio/track02.mp3")]
private var Track2:Class;
[Embed(source = "audio/track03.mp3")]
private var Track3:Class;
[Embed(source = "audio/track04.mp3")]
private var Track4:Class;[Embed(source = "AudioMixerFilter2.pbj",mimeType = "application/octet-stream")]
private var EmbedShader:Class;
private var shader:Shader = new Shader(new EmbedShader());
private var sound:Vector.<Sound> = new Vector.<Sound>();
private var bytes:Vector.<ByteArray> = new Vector.<ByteArray>();
private var sliders:Vector.<Number> = new Vector.<Number>();
private var sliderVol:int = 1;
private var BUFFER_SIZE:int = 0x800;
public var playback:Sound = new Sound();
public function startAudioMixer(event:FlexEvent):void{
sound.push(new Track1(), new Track2(), new Track3(), new Track4());
sliders.push(sliderVol,sliderVol,sliderVol,sliderVol);
playback.addEventListener(SampleDataEvent.SAMPLE_DATA, onSoundData);
playback.play();
}
private function onSoundData(event:SampleDataEvent):void {
for(var i:int = 0; i < sound.length; i++){
bytes[i] = new ByteArray();
bytes[i].length = BUFFER_SIZE * 4 * 2;
sound[i].extract(bytes[i], BUFFER_SIZE);
var volume:Number = 0;
bytes[i].position = 0;
for(var j:int = 0; j < BUFFER_SIZE; j++){
volume += Math.abs(bytes[i].readFloat());
volume += Math.abs(bytes[i].readFloat());
}
volume = (volume / (BUFFER_SIZE * .5)) * sliderVol; // SLIDER VOL WILL CHANGE
shader.data['track' + (i + 1)].width = BUFFER_SIZE / 1024;
shader.data['track' + (i + 1)].height = 512;
shader.data['track' + (i + 1)].input = bytes[i];
shader.data['vol' + (i + 1)].value = [sliders[i]];
}
var shaderJob:ShaderJob = new ShaderJob(shader,event.data,BUFFER_SIZE / 1024,512);
shaderJob.start(true);
}
Easiest way would be to just forget about the Pixel Bender stuff.
Once the Sounds are loaded, use an ENTER_FRAME that uses Sound.extract to get a smallish ByteArray from each Sound, then read through all four extracted ByteArrays doing some basic math to arrive at the 'mixed' values for the left & right signals. Write those values to the "final/mixed/output" ByteArray. Repeat the process each frame until you're at the end of the sounds. If the Sounds aren't all the identical length, you'll need to figure out how to handle that as well.
If you need to perform a mix where the amplitude of each track changes over time, it'd be a good challenge, but would take time to set up.
While you're at it, check out Andre Michelle's Tonfall project... It's a complex but great place to start with understanding the ins/outs of audio in AS3.
I am trying to center an image in the middle of the stage and scale it proportionally to the correct aspect ratio based on its loader's size when the image is loading.
In my main app runner I do:
private var rec:Rectangle = new Rectangle();
private var img:BitmapDisplay = new BitmapDisplay();
stage.addEventListener(Event.RESIZE, setRect);
img.imageURL = "some/path/to/image.jpg";
addChild(img);
private function setRect():void
{
var horz:Number = stage.stageWidth / 16;
var vert:Number = stage.y + stage.stageHeight / 16;
rec.x = horz;
rec.y = 80;
rec.width = stage.stageWidth - horz;
rec.height = stage.stageHeight - (vert * 2) - rec.y;
img.boundary = rec;
}
Then in my image (BitmapDisplay) class I have:
// sets the boundary of the image and resizes it
public function set boundary(rect:Rectangle):void
{
_imageBoundary = rect;
resizeImage();
}
private function resizeImage():void
{
var aspect:Number = _ldr.content.width / _ldr.content.height;
var cAspect:Number = _imageBoundary.width / _imageBoundary.height;
if (aspect <= cAspect)
{
_ldr.height = _imageBoundary.height;
_ldr.width = aspect * _ldr.height;
}
else
{
_ldr.width = _imageBoundary.width;
_ldr.height = _ldr.width / aspect;
}
var _pad:int = 7;
_ldr.x = (_imageBoundary.width - _ldr.width) / 2 + _imageBoundary.x - _pad;
_ldr.y = (_imageBoundary.height - _ldr.height) / 2 + _imageBoundary.y - _pad;
}
}
Is there something obvious keeping this from working right?
I want a 16th of the stage to be the bounds for the image and for the image to scale/resize based on this rect.
Thanks...
It turns out that this had more to do with the loader not being ready to be resized. There was some error checking in my code that needed to be reformatted, so now when the resize function gets called, it doesn't do anything until the loader is ready and the boundary is set.