when you drag images you can control their moving with dragBoundFunc. Is there something similar when you scaling? I want to set an image area in "part of a stage" and when i setScale for this image and make it bigger, i don't want to see parts which is bigger than image area i've set before. is it possible? Here is my fiddle..
var stage = new Kinetic.Stage({
container : 'canvas',
width : 620,
height : 236
});
var layer = new Kinetic.Layer();
var leftImage = new Image();
leftImage.src = "http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg";
var leftImg = new Kinetic.Image({
x : stage.getWidth() - 480,
y : stage.getHeight() - 126,
image : leftImage,
width : 190,
height : 124,
offset : [95, 62],
draggable : true,
dragBoundFunc: function(pos) {
var x=stage.getWidth() - 480;
var y=stage.getHeight() - 126;
var radius = 50;
var scale = radius/ Math.sqrt(Math.pow(pos.x - x, 2) + Math.pow(pos.y - y, 2));
if(scale < 1)
return {
y: Math.round((pos.y - y) * scale + y),
x: Math.round((pos.x - x) * scale + x)
};
else
return pos;
}
});
var rectLeft = new Kinetic.Rect({
x : 38,
y : 20,
width : 232,
height : 184,
stroke:'red',
listening:false
});
var rectRight = new Kinetic.Rect({
x : 350,
y : 20,
width : 232,
height : 184,
stroke:'green',
listening:false
});
layer.add(leftImg);
layer.add(rectLeft);
layer.add(rectRight);
stage.add(layer);
document.getElementById('larger').addEventListener('click', function() {
leftImg.setScale(leftImg.getScale().x + 1.5);
layer.draw();
}, false);
Sure.
You can clip your scaled image into a fixed area of the stage by wrapping your image in a group and setting the clip property of that group to your fixed area.
If you set the clip property on a group like this:
var group=new Kinetic.Group({
x:100,
y:100,
width: originalImageWidth,
height: originalImageHeight,
clip: [0,0,originalImageWidth,originalImageHeight]
});
Then the image you put in the group will be clipped to stage #100,100 and size == original image size.
If you later scale the image larger, the clipping area will act as a "viewport" into part of the larger image.
Related
I have been asked, using Konvajs, to work out an animation that will rotate a circle as if spinning on its central x-axis. So imagine a coin spinning on a table. The intention is to reveal some text on the circle. At the start the circle is fully visible as if from behind so no text visible, then it flips to reveal the text.
I have this code that does a rotation like a spinning wheel.
Can anyone give me a tween / animation approach that would achieve the spinning coin effect?
// the tween has to be created after the node has been added to the layer
var tween = new Konva.Tween({
node: group,
duration: 4,
rotation: 360,
easing: Konva.Easings.BackEaseOut
}
});
tween.play();
After some research it looks like a 3D spin requires heavier lifting which may not be available or work well on mobile.
A good second-best appears to be using scaleX and animating from 0 > 1.
group.scaleX(0);
var tween = new Konva.Tween({
node: group,
duration: .25,
scaleX: 1,
easing: Konva.Easings.EaseOut
});
Here is an example of the second-best version using scaleX() effect. Because of the need to calculate scaleX() and control visibility of the text so as to make it appear that the disc is solid, I moved away from a tween and over to an animation().
// Set up the canvas / stage
var s1 = new Konva.Stage({container: 'container1', width: 300, height: 200});
// Add a layer for line
var layer = new Konva.Layer({draggable: false});
s1.add(layer);
// just a plain JS object to keep common variables in hand.
var cfg = { w: 300, h: 200, r: 80, txtSize: 520};
var group = new Konva.Group();
var circle = new Konva.Circle({x: cfg.w/2, y: cfg.h/2, radius: cfg.r, fill: 'DodgerBlue', stroke: 'DeepPink', strokeWidth: 5})
group.add(circle)
var textValue = new Konva.Text({
id: "t1",
x: cfg.w/2,
y: cfg.h/2,
text: '',
fill: 'DeepPink ',
fontSize: cfg.txtSize
});
group.add(textValue);
textValue.offset({x: textValue.getWidth()/2, y: textValue.getHeight()/2});
layer.add(group)
// to spin a group about a point, set the offset to that point, then set the x & y to that point to !
var pos = group.getClientRect();
RotatePoint(group, {x: pos.x + pos.width/2, y: pos.y + pos.height/2});
// Everything is ready so draw the canvas objects set up so far.
s1.draw()
$('#st').on('click', function(){
group.scaleX(1);
var txt = $('#theText').val();
setValue(txt);
})
// set the offset for rotation to the given location and re-position the shape
function RotatePoint(shape, pos){ // where pos = {x: xpos, y: yPos}
var initialPos = shape.getAbsolutePosition();
var moveBy = {x: pos.x - initialPos.x, y: pos.y - initialPos.y};
// offset is relative to initial x,y of shape, so deduct x,y.
shape.offsetX(moveBy.x);
shape.offsetY(moveBy.y);
shape.x(initialPos.x + moveBy.x);
shape.y(initialPos.y + moveBy.y);
}
var setValue = function(newText){
// work out scaling to make text fit into the circle
var txt = this.layer.find('#t1')[0];
txt.text(newText).scale({x:1, y: 1})
var txtSize = txt.getClientRect();
var maxW = (cfg.r); // max allowed width of text
var txtScaleW = (txtSize.width > maxW ? ( maxW / txtSize.width) : 1);
var maxH = cfg.r; // max allowed height of text
var txtScaleH = (txtSize.height > maxH ? ( maxH / txtSize.height) : 1);
// finally decide which is the worst case and use that scaling
var txtScale = ( txtScaleW > txtScaleH ? txtScaleH : txtScaleW);
txt.scale({x: txtScale, y: txtScale});
txt.offset({x: txt.getWidth()/2, y: txt.getHeight()/2});
layer.draw()
}
// set initial text & spin !
setValue('BBB');
var anim, pos = 0, frameCnt = 0
if (anim) {anim.stop(); }
anim = new Konva.Animation(function(frame) {
frameCnt = frameCnt + 1;
if (frameCnt % 2 === 0){
pos = pos + .2
var scaleX = Math.sin(pos)
textValue.visible(scaleX < 0 ? false : true);
group.scaleX(scaleX);
if (pos % 360 === 0){ console.log('spin') }
}
}, layer);
anim.start();
div
{
float: left;
margin: 0 5px;
}
p
{
margin: 0 5px 5px 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/konva/2.5.1/konva.min.js"></script>
<div id='container1' style="width: 300px, height: 200px;"></div>
<div>
<p> <input type='text' id='theText' value='BBB' /> <button id='st'>Change text</button> </p>
</div>
I need to rotate the image 180 degrees, but when I add in the rotate code, the image becomes a square.
var moulding_matte_canvas_height = [],
canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d"),
width = 5.171363636363637,
opening_i = 0,
rotate = 180 * Math.PI / 180,
i = 2;
moulding_matte_canvas_height[0] = 225;
canvas.width = 285;
canvas.height = 335;
img = new Image();
img.src = 'http://www.asa.tframes.org:1881/system/components/compimg/80ac89fad42cf14561b641df241bf406/pattern';
function moulding_get_segment_width(img_width, opening_i)
{
return 175;
}
//
$(img).on("load", function() {
ctx.save();
ctx.translate(width, moulding_matte_canvas_height[opening_i]);
//ctx.rotate(rotate);
//ctx.rotate(Math.PI);
ctx.drawImage(img, 0, 0, moulding_get_segment_width(img.width, i), width);
ctx.restore();
//
});
$("#mattes").append(canvas); /*appending the canvas*/
http://fiddle.jshell.net/onpa628e/1/
(Whitespace is intentional due to other elements that will be drawn and the red next to the image is just for clarity)
Without rotate:
With rotate:
Expected:
Your image looks like a square, because it's only showing a tiny portion on the canvas. This happens because translate is only moving ~ 5px (your "width" variable) on the x axis.
Here's your example modified with a higher x value.
I have got some code for rotation of an image. But however, the center of rotation is not equal to the center of the image which is to be rotated.
I have set the center of an image but I don't know how to set the center of the rotation.
Following is the code :
// image code
var image = Titanium.UI.createImageView({
backgroundImage:'test.png',
width: 650,
height: 650,
center:{x:CenterX, y:CenterY},
align:'center'
});
//rotation code
image.addEventListener('touchstart', function(e){
var conv = e.source.convertPointToView({x: e.x, y:e.y}, win);
var newAngle = Math.atan2(conv.y - 500, 380 - conv.x)* -(180 / Math.PI);
diff = (newAngle - old);
});
image.addEventListener('touchmove', function(e){
var conv = e.source.convertPointToView({x: e.x, y:e.y}, win);
var newAngle = Math.atan2(conv.y - 500, 380 - conv.x)* -(180 / Math.PI);
current = (newAngle-diff);
var t = Ti.UI.create2DMatrix().rotate(current);
wheel.transform = t;
});
You have to set the animation / view anchorPoint, on iOS you have to set the Ti.UI.View's anchorPoint, on Android you have to set the Ti.UI.Animation's anchorPoint or in your case, since your using a Matrix, just set the anchorPoint of the Matrix on creation (for Android).
Here is what you do for iOS:
/* iOS */
var image = Titanium.UI.createImageView({
backgroundImage:'test.png',
width: 650,
height: 650,
anchorPoint: {0.5, 0.5}, // ANchor point is at the center
});
Or alternatively, on Android:
/* Android */
// Matrix, inside your event listener
image.addEventListener('touchmove', function(e){
var conv = e.source.convertPointToView({x: e.x, y:e.y}, win);
var newAngle = Math.atan2(conv.y - 500, 380 - conv.x)* -(180 / Math.PI);
current = (newAngle-diff);
// Note that I set the anchor point here.
var t = Ti.UI.create2DMatrix({anchorPoint: {0.5, 0.5}}).rotate(current);
wheel.transform = t;
});
How would you crop a small portion of a big image (e.g area of an imageview visible in a transparent frame) in appcelerator titanium for both iOS and android? imageAs** functions won't work as they aren't supported below android 3.0 . Here is my code:
var win=Ti.UI.createWindow({backgroundColor: 'white'})
var ImageView = Titanium.UI.createImageView({
width:200, height:200,
});
var cropView = Titanium.UI.createView({
width: 150,
height: 150,
borderColor: 'red',
borderWidth: 1,
zIndex: 1,
});
var button= Ti.UI.createButton({
bottom: 30,
width: 60,
title: 'OK',
zIndex: 1,
})
win.add(cropView)
Ti.Media.openPhotoGallery({
PhotoGalleryOptionsType : Ti.Media.MEDIA_TYPE_PHOTO,
success: function(e){
ImageView.image=e.media;
win.add(ImageView)
}, });
button.addEventListener('click',function(e)
{
// crop the visible area
})
I am using iOS 5 and android 2.2. Thanks for your help.
Add ImageView to cropView (rather than to win), position and size imageView so that the portion you want displayed is displayed (using negative values for left and top), and then call cropView.toImage(). You can use the resulting blob in a new image view, save it to a file, email it as an attachment, whatever you want.
Any portion of the image outside of its parents bounds will be cropped, leaving only the portion you specify.
I have done some small changes and now its all functional. Cheers!! :)
var win = Ti.UI.createWindow({
backgroundColor : 'white'
})
var orignal = Titanium.UI.createImageView({
width : Ti.UI.SIZE,
height : Ti.UI.SIZE,
left:5
});
var ImageView = Titanium.UI.createImageView({
width : 200,
height : 200
});
var cropView = Titanium.UI.createView({
top : 10,
width : 150,
height : 150,
borderColor : 'lime',
borderWidth : 1,
zIndex : 1,
left:150
});
var button = Ti.UI.createButton({
bottom : 30,
width : 60,
title : 'CROP',
zIndex : 1,
});
win.add(button);
Ti.Media.openPhotoGallery({
PhotoGalleryOptionsType : Ti.Media.MEDIA_TYPE_PHOTO,
success : function(e) {
ImageView.image = e.media;
orignal.image=e.media;
cropView.add(ImageView);
win.add(cropView);
win.add(orignal);
},
});
var CropedImageView = Titanium.UI.createImageView({
top : 200,
width : cropView.width,
height : cropView.height,
left:150
});
button.addEventListener('click', function(e) {
cropView.borderColor='transparent';
CropedImageView.image = cropView.toImage();
win.add(CropedImageView);
});
win.open();
I learnt some of this while my stay at Oodles Technologies.
Here's my contribution :
In this example you will see how to crop image in iOS Titanium.
To crop a image first create scroll view, define its maxZoomScale, minZoomScale.
maxZoomScale:-
Maximum Scaling factor of the scrollable region and its content.
minZoomScale:-
Minimum Scaling factor of the scrollable region and its content
maxZoomSale and minZoomScale we can adjust according to required.
then we have to add image view inside scrollview, then we can zoom in and zoom out image, to crop a image just need to click on crop button.
var window = Ti.UI.createWindow({
backgroundColor : 'white'
});
var scrollView = Ti.UI.createScrollView({
height : 260,
width : Ti.UI.FILL,
maxZoomScale : 4.0,
minZoomScale : 1.0,
zoomScale : 1.0,
});
window.add(scrollView);
var imageView = Ti.UI.createImageView({
height : scrollView.height,
width : scrollView.width,
backgroundColor : "transparent",
anchorPoint : {
x : 0.5,
y : 0.5
},
image : 'Default-568h#2x.png',
});
scrollView.add(imageView);
var button = Ti.UI.createButton({
top : 20,
title : 'Crop Button'
});
window.add(button);
button.addEventListener('click', function(e) {
button.hide();
var cropimage = scrollView.toImage();
var cropImageView = Ti.UI.createImageView({
top : 20,
height : 120,
width : 120,
image : cropimage
});
window.add(cropImageView);
});
window.open();
Here is my
APP.js
var win = Ti.UI.createWindow({
navBarHidden : true,
className : 'window',
backgroundColor : "#efefef"
});
var header = Ti.UI.createView({
height : 20,
width : 303,
top : 0,
backgroundColor : "#abc"
});
win.add(header);
var scroll = Ti.UI.createScrollView({
top : 44,
bottom : 44,
layout : 'vertical'
});
win.add(scroll);
header.addEventListener('click', function(evt) {
fetch_images();
});
win.open();
function fetch_images() {
var xhr = Ti.Network.createHTTPClient({
onload : function() {
myjson = JSON.parse(this.responseText);
for ( i = 0; i < myjson.length; i++) {
Ti.API.debug(i);
var look = new looks(myjson[i])
scroll.add(look);
}
},
onerror : function(e) {
Ti.API.debug("STATUS: " + this.status);
Ti.API.debug("TEXT: " + this.responseText);
Ti.API.debug("ERROR: " + e.error);
if (Titanium.Network.online) {
alert('No reponse from server.');
} else {
alert('Please Check your Internet connectivity.');
}
},
timeout : 5000
});
xhr.open('GET', 'http://xxxxxxx.com/xxxxxxx.json?api_token=xxxxxxxx');
xhr.send();
}
function looks(image_details) {
var look_container = Ti.UI.createView({
height : 325,
width : 303,
top : 10,
layout : 'horizontal',
backgroundColor : "#cac"
});
var look_image = i.UI.createImageView({
width : 303,
top : 0,
left : 0,
right : 0,
image : image_details.image_medium
});
look_container.add(look_image);
return look_container;
}
I am about to pull my hairs from my head.
Working with this for around last 4-5 hours.
Acc. to the code Image should be something like this
But it appears like this.
Any guess whats wrong !! Any help would be grateful ??
As per the code Image should be aligned to top (0px from top). But Image is always down the line in the view and dont stick to the top... ??
-------------------------EDIT---------------------------
I editted my code to check for static JPG images
and its same even for the Images in the resources directory
check this question developer.appcelerator.com/question
code
var win = Ti.UI.createWindow({
navBarHidden : true,
className : 'window',
backgroundColor : "#efefef"
});
var my_container = Ti.UI.createView({
height : 325,
width : 303,
top : 30,
backgroundColor : "#cac",
layout : "horizontal"
});
var my_image = Ti.UI.createImageView({
width : '100%',
top : 0,
left : 0,
right : 0,
image : 'hello.jpg'
});
my_container.add(my_image);
win.add(my_container);
my_container.addEventListener('click', function() {
my_image.top = my_image.top - 25;
})
win.addEventListener('click', function() {
my_image.top = my_image.top + 5;
})
win.open();
and image url for the image to be used.
The problem is not the layout properties, it is image scaling! Note first that you are passing a larger image than the view, so Titanium does some scaling under the sheets.
So when you define the width of that ImageView, if the image you pass is bigger than the view, Titanium scales it using its own mechanism, which obviously, is not what you want, since it has been causing you to tear your hair out the past few days. I believe they scale images from the bottom up, causing your weird problem.
To fix this, you need to take control of the image scaling from Titanium, and pass a new, resized image
To do this, we need to get the original height and width of the image, to preserve the aspect ratio, then figure out a new size, resize the image, and pass it to the imageView.
To get the height and width of the image you kind of have to hack around a bit, here is how I did it with SDK 2.1.1.GA:
Get Height and Width of a Blob / Image
// Load the image as a blob to get height information
var imageFile = Ti.Filesystem.getFile('hello.png');
var blobOfImage = imageFile.read();
// Put it in a imageView, since It wont let me get height from a blob for some reason
var imageView1 = Titanium.UI.createImageView({
image: blobOfImage,
width: 'auto',
height: 'auto',
});
// This is the important part, toImage this view and you get the height and width of this image
// For some reason we cant get this from a Blob in SDK 2.1.1.GA
var heightOfImage = imageView1.toImage().height;
var widthOfImage = imageView1.toImage().width;
Now we calculate the aspect ratio for the width (screen size for iPhone of 320).
Aspect Ratio
var aspectRatio = heightOfImage / widthOfImage;
And now we can create the new resized image in the imageview.
New Image!
var my_container = Ti.UI.createView({
height : 325,
width : 303,
top : 30,
backgroundColor : "#cac",
layout : "horizontal"
});
var my_image = Ti.UI.createImageView({
top : 0,
left : 0,
right : 0,
image : blobOfImage.imageAsResized(320, 320*aspectRatio) // Note the resize call to the image blob
});
Here is the final output :
So I guess the lesson is dont trust Titanium to scale your images for you.