How to get a stage calculation to resize an image w/r/t c - apache-flex

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.

Related

Circle mask acts like rectangle

I'm trying to draw an object masked with a circle, but the mask applied is more like a circle's bounding rectangle
I tried using circle drawn with drawCircle method:
private function squareToRound(ability:MovieClip):MovieClip
{
var container:MovieClip = new MovieClip();
var newAbility:MovieClip = ability;
var newMask:MovieClip = new MovieClip();
newAbility.width = 43;
newAbility.height = 43;
newMask.x = newAbility.x + newAbility.width / 2;
newMask.y = newAbility.y + newAbility.height / 2;
container.addChild(newAbility);
newMask.graphics.beginFill();
newMask.graphics.drawCircle(0, 0, 8);
newMask.graphics.endFill();
container.addChild(newMask);
newAbility.mask = newMask;
return container;
}
... and as an asset from SWF:
private function squareToRound(ability:MovieClip):MovieClip
{
var container:MovieClip = new MovieClip();
var newAbility:MovieClip = ability;
var newMask:MovieClip = new CircleAbilityMask();
newAbility.width = 43;
newAbility.height = 43;
newMask.x = newAbility.x + newAbility.width / 2;
newMask.y = newAbility.y + newAbility.height / 2;
container.addChild(newAbility);
container.addChild(newMask);
newAbility.mask = newMask;
return container;
}
The results are equal.
I checked what the mask looks like by commenting "newAbility.mask = newMask;" line
This should be resolved in the current OpenFL release:
https://github.com/openfl/openfl/blob/develop/CHANGELOG.md#650-11102017
You can also use Cairo (on native platforms) or Canvas (on HTML5) for smoother/better masking support:
openfl test html5 -Dcanvas
openfl test windows -Dcairo
These are also used when you bitmapData.draw, sprite.cacheAsBitmap = true or other APIs that trigger a software render rather than GL.

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;
},

d3js: Use view port center for zooming focal point

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.

Flex 4.5 mobile Resize textarea with animation on soft keyboard activate event?

I'm using Flex 4.5.1 with AIR 2.7 (and Flash Builder 4.5.1) to build an app for the Blackberry Playbook.
The app has a large textarea that needs to be resized when the soft keyboard shows up. I am able to hook into the soft keyboard events and do things there.
Now, I want to resize the textarea to fit the remaining part of the screen when the keyboard shows up. I know the current and destination size and want to use a smooth animation to show the textarea resizing. (I can't already set the height and can see the textarea being correctly resized in the keyboard_activating event - but I want to do it through an animation). I've tried using the Animate class, the spark.effects.Move class and none of them seem to work in this case. They seem to run the animation but the screen does not get refreshed!
I don't want to use the built-in resizeAppForKeyboard property on the ViewNavigatorApplication. I have set to 'none' in the app descriptor so that part of it is fine.
Any ideas / thoughts? Is my approach correct at all? How would one go about resizing the textarea using an animation in the keyboard activating event? My code looks like:
In the main view (onCreationComplete event): (txNote is the textarea in question)
txNote.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, function(e:SoftKeyboardEvent):void {
toggleEditMode(true);
});
txNote.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, function(e:SoftKeyboardEvent):void {
toggleEditMode(false);
});
private function toggleEditMode(keyboardActivated:Boolean):void {
trace("toggle edit: " + editMode + ", kb activating: " + keyboardActivated + ", txNote height = " + txNote.height);
editMode = keyboardActivated;
//we handle resize manually, because we want a nice animation happening and we want to resize only the text area - nothing else.
var y:Number = editMode ? -38 : 0;
var height:Number = editMode ? 218 : 455;
txNote.moveAndSize(y, height);
}
The code in txNote.moveAndSize:
public function moveAndSize(newY:Number, newHeight:Number):void {
//parent group uses BasicLayout
//(this.parent as Group).autoLayout = false;
//resizePath.valueFrom = this.height;
//resizePath.valueTo = newHeight;
//movePath.valueFrom = this.y;
//movePath.valueTo = newY;
//resizeEffect.heightFrom = this.height;
//resizeEffect.heightTo = height;
this.top = newY;
moveEffect.xFrom = this.x;
moveEffect.xTo = this.x;
moveEffect.yFrom = this.y;
moveEffect.yTo = newY;
moveEffect.end();
moveEffect.play([ this ]);
//this.move(x, newY);
//animate.play([ this ]);
//this.height = height;
//this.y = y;
//setLayoutBoundsSize(width, height);
//setLayoutBoundsPosition(x, y);
}
The moveEffect / movePath / animate various things I tried are set up in the txNote constructor as follows:
public class NotesArea extends TextArea {
// private var animate:Animate;
// private var movePath:SimpleMotionPath;
// private var resizePath:SimpleMotionPath;
private var moveEffect:Move;
// private var resizeEffect:Resize;
public function NotesArea() {
super();
// animate = new Animate();
// var paths:Vector.<MotionPath> = new Vector.<MotionPath>();
// movePath = new SimpleMotionPath("top");
// resizePath = new SimpleMotionPath("height");
// paths.push(movePath);
//paths.push(resizePath);
// animate.duration = 300;
// animate.motionPaths = paths;
// animate.addEventListener(EffectEvent.EFFECT_UPDATE, function(e:EffectEvent):void {
// trace("y = " + y);
// invalidateDisplayList();
// });
// animate.addEventListener(EffectEvent.EFFECT_END, function(e:EffectEvent):void {
// trace("EFFECT ended: y = " + y);
// });
moveEffect = new Move();
moveEffect.duration = 250;
moveEffect.repeatCount = 1;
moveEffect.addEventListener(EffectEvent.EFFECT_END, function (e:EffectEvent):void {
//(this.parent as Group).autoLayout = true;
trace("move effect ran. y = " + y + ", top = " + top);
});
//this.setStyle("moveEffect", moveEffect);
//
// resizeEffect = new Resize();
// resizeEffect.duration = 250;
// this.setStyle("resizeEffect", resizeEffect);
}
}
yourTextField.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_DEACTIVATE, onActivating);
yourTextField.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATING, onActivating);
yourTextField.addEventListener(SoftKeyboardEvent.SOFT_KEYBOARD_ACTIVATE, onActivating);
// in the event listener to the textField IE :
private function onActivating(event:SoftKeyboardEvent):void
{
//listen to the event; make your move here.
}

Center window component

I have create a window component but it will randomly position whether I open its window, x and y positions will only offset the elements, not window. How do I position it to the center of the screen?
Flex 4 (AS3):
private function openDoc():void {
if (newWindow != null) newWindow.close();
newWindow = new docwin();
newWindow.width = 500;
newWindow.height = 320;
newWindow.type = "normal";
newWindow.systemChrome = "standard";
newWindow.transparent = false;
newWindow.setStyle("showFlexChrome", true);
newWindow.showStatusBar = false;
newWindow.minimizable = false;
newWindow.maximizable = false;
newWindow.resizable = false;
newWindow.open();
}
Try this:
newWindow.x = Math.ceil((Capabilities.screenResolutionX - newWindow.width) / 2);
newWindow.y = Math.ceil((Capabilities.screenResolutionY - newWindow.height) / 2);
You can use layout property of window like horizontalCentre and verticalCentre use contstraint based layout scheme
You have to position the new window with reference to stageWidth and stageHeight properties.
Assuming the origin of your new window is top left, the new location of the the windows will be:
(Stage.stageWidth - newWindow.width)/2, (Stage.stageHeight - newWindow.height)/2;

Resources