how to create an event after an event in Appcelerator Titanium - ios

I am trying to repurpose code to create a custom progress bar - but I am unable to understand how to make the final change.
The current implementation does the progress bar. What I would like is for the progress bar to update the text and then disappear on its own.
var win = Ti.UI.createWindow({
backgroundColor: 'white',
});
var label1 = Ti.UI.createLabel({
text: 'Working on it...',
textAlign:'center',
});
var track = Ti.UI.createView({
width: "60%", height: "20%",
borderRadius:40,
backgroundColor: 'red'
});
var progress = Ti.UI.createView({
borderRadius:40,
left: 0,
width: 5, height: "100%",
backgroundColor : "green"
});
track.add(progress);
track.add(label1);
win.add(track);
win.addEventListener('open', function () {
progress.animate({
width: "100%",
duration: 1000
});
});
win.open();
So when the final green progress is complete - I would like to
a. replace the "working on it" with "complete"
b. after 1000 ms - make the entire progress bar disappear.

No need to add Listener for complete event, you can add anonymous function in animate method itself
e.g
progress.animate({
width: "100%",
duration: 1000
},function(e){
label1.text = "complete";
win.remove(track);
});

You can use complete event listener of Animation object
// create the animation
var animation = Ti.UI.createAnimation({
width: "100%",
duration: 1000
});
animation.addEventListener("complete", function onAnimationComplete(e){
// YOUR CODE HERE
animation.removeEventListener("complete", onAnimationComplete);
});
progress.animate(animation);
More details Titanium.UI.Animation

Related

Vue-Konva: Is there a way to reorder layers on the fly?

So, I've been working with vue-konva and I have something like this:
<v-container>
<v-stage ref="stage">
<v-layer ref="baseImage">
<v-image>
</v-layer>
<v-layer ref="annotationLayer">
<v-rect ref="eventBox">
<v-rect ref="rubberBox">
<v-rect ref="annotationRect">
</v-layer>
</v-stage>
<v-container>
Currently there are some issues if I want to draw new boxes, when there are other annotationRects already on the image. Because they are technically above the eventBox and rubberbox, they are "blocking" these two layers when the cursor is above an existing annotationRect.
But, I don't want to just constantly have eventBox and rubberBox be on top of annotationRect because I need to be able to interact with annotationRect to move them, resize them ,etc.
Is there a way for me to reorder eventBox, rubberBox, and annotationRect, i.e. changing the order to (bottom to top) annotationRect-eventBox-rubberBox from the original eventBox-rubberBox-annotationRect and back, on the fly, for example when the vue component receives an event from another component?
You need to define your eventBox, rubberBox, and annotationRect inside order array in the state of your app. Then you can use v-for directive to render items from the array:
<template>
<div>
<v-stage ref="stage" :config="stageSize" #click="changeOrder">
<v-layer>
<v-text :config="{text: 'Click me to change order', fontSize: 15}"/>
<v-rect v-for="item in items" v-bind:key="item.id" :config="item"/>
</v-layer>
<v-layer ref="dragLayer"></v-layer>
</v-stage>
</div>
</template>
<script>
const width = window.innerWidth;
const height = window.innerHeight;
export default {
data() {
return {
stageSize: {
width: width,
height: height
},
items: [
{ id: 1, x: 10, y: 50, width: 100, height: 100, fill: "red" },
{ id: 2, x: 50, y: 70, width: 100, height: 100, fill: "blue" }
]
};
},
methods: {
changeOrder() {
const first = this.items[0];
// remove first item:
this.items.splice(0, 1);
// add it to the top:
this.items.push(first);
}
}
};
</script>
DEmo: https://codesandbox.io/s/vue-konva-list-render-l70vs?file=/src/App.vue

Konvajs shape stroke color lingers after change

I'm trying to change the stroke color of a hexagon on mouseover, and then back to the original color on mouseout.
My problem is that, if I redraw only the hexagon after updating the stroke color, the previous color lingers around the edges of the stroke.
hexagon.on('mouseover', function(e) {
e.target.stroke('red');
e.target.draw();
});
hexagon.on('mouseout', function(e) {
e.target.stroke('gray');
e.target.draw();
});
Demo at https://codepen.io/jsgarvin/pen/dmRJXj
Here the original color is gray, and it changes to red on mouse over, but on mouse out it changes back to gray with a red dusting around all of the edges.
If I redraw the entire layer though, it seems to do what I expect, but in my particular use case I expect to have several thousand hexagons, among other things, on the layer, and that seems inefficient to redraw the entire layer if I just need to update one hexagon. Is there a more correct way to do this that I'm overlooking? Thanks!
You need to draw the layer.
hexagon.on('mouseover', function(e) {
e.target.stroke('red');
e.target.draw();
layer.draw(); // <<<<< THIS LINE IS THE FIX
});
I found this out as I was coding an alternative which I include below in the snippet. It uses a second shape and we show & hide the two so as to provide the mouseover effect. I can imagine that this will not be viable in all cases but it might help someone out so here is a working snippet.
Left hand is your example copied from your Pen with the fix included, the right is the shape switcher, just for fun.
var stage = new Konva.Stage({
container: 'container',
width: 400,
height: 150
});
var layer = new Konva.Layer();
stage.add(layer);
var c = layer.getCanvas();
var ctx = c.getContext();
var hexagon = new Konva.RegularPolygon({
x: 75,
y: 75,
radius: 55,
sides: 6,
stroke: 'gray',
strokeWidth: 10
});
hexagon.on('mouseover', function(e) {
e.target.stroke('red');
e.target.draw();
layer.draw(); // <<<<< THIS LINE IS THE FIX
});
hexagon.on('mouseout', function(e) {
e.target.stroke('gray');
e.target.draw();
layer.draw(); // <<<<< THIS LINE IS THE FIX
});
var hexagon2 = new Konva.RegularPolygon({
x: 250,
y: 75,
radius: 55,
sides: 6,
stroke: 'gray',
strokeWidth: 10
});
hexagon2.on('mouseover', function(e) {
e.target.visible(false);
hexagon3.visible(true);
layer.draw();
});
var hexagon3 = new Konva.RegularPolygon({
x: 250,
y: 75,
radius: 55,
sides: 6,
stroke: 'red',
strokeWidth: 10,
visible: false
});
hexagon3.on('mouseout', function(e) {
e.target.visible(false);
hexagon2.visible(true);
layer.draw();
});
layer.add(hexagon);
layer.add(hexagon2);
layer.add(hexagon3);
stage.draw();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.5/konva.min.js"></script>
<p>Left image is OP's version, right is shape-switching. Mouse-over the hexagons.</p>
<div id='container'></div>

Strange event bubbling issue in Titanium Appcelerator alloy project

I am developing on iOS 9.2 SDK & Titannium SDK v5.1.2.GA.
In my iPad app; there is a product tab page, which has a "Discount" button. When you click it, a Popover with a TextField and Picker is shown like this:
The above is created on the fly. (not using a controller + view).
This works as intended. I wanted to extend this a little further by recording the given discount to a product in alloy.js in a global array variable called Alloy.Globals.ProductDiscounts = []; (so it can be used later).
The way I "capture" the new discount price is by listening to the "hide" event on the picker. Then update the global array.
For debugging purpose, I added a console log to make sure it's getting recorded correctly and then in the Appcelerator Studio console window, I started see this endless output like this:
I had to kill the simulator to stop this weird constant output of nulls.
This is my code so far, any idea why the console window is spazzing out? Also, why isn't my global array isn't getting set? or is it getting set, but I missed the actual console.log entry?
// Subscribe to line discount button click event
lineDiscountButton.addEventListener('click', function(e)
{
// Stop further events
e.cancelBubble = true;
// Create popover
var discountPopover = Titanium.UI.iPad.createPopover({
arrowDirection: Titanium.UI.iPad.POPOVER_ARROW_DIRECTION_RIGHT,
orignalPrice: e.source.orignalPrice,
priceButton: e.source.priceButton
});
var discountPopoverView = Titanium.UI.createView({
width: 250,
height: 210
});
// Create discount popover view wrapper
var discountPopoverViewWrapper = Titanium.UI.createView({
top: 10,
left: 10,
right: 10,
bottom: 10,
layout: 'vertical'
});
discountPopoverViewWrapper.add(Titanium.UI.createLabel({
top: 0,
left: 0,
color: '#5C5C5C',
font: {
fontSize: 12
},
text: 'Enter a new Price'
}));
discountPopoverViewWrapper.add(Titanium.UI.createView({
top: 0,
height: 1,
backgroundColor: '#0088CE',
width: '100%'
}));
var discountPrice = Titanium.UI.createTextField({
top: 0,
width: '100%',
height: Titanium.UI.SIZE,
hintText: discountPopover.orignalPrice,
value: discountPopover.orignalPrice,
backgroundColor: '#FFFFFF',
font: {
fontSize: 18,
fontWeight: 'bold'
},
color: '#5C5C5C'
});
discountPopoverViewWrapper.add(discountPrice);
discountPopoverViewWrapper.add(Titanium.UI.createLabel({
top: 10,
left: 0,
color: '#5C5C5C',
font: {
fontSize: 12
},
text: 'Or Select a Discount Percent'
}));
discountPopoverViewWrapper.add(Titanium.UI.createView({
top: 0,
height: 1,
backgroundColor: '#0088CE',
width: '100%'
}));
var discountPercentPicker = Titanium.UI.createPicker({
top: 0,
width: Titanium.UI.FILL,
height: 112
});
var discountPercentValues = [];
for (var i = 0; i <= 100; i++) {
discountPercentValues.push(Titanium.UI.createPickerRow({
title: i +'%'
}));
}
discountPercentPicker.add(discountPercentValues);
discountPercentPicker.addEventListener('change', function(e) {
if (parseInt(e.rowIndex) === 0) {
discountPrice.value = discountPopover.orignalPrice;
} else {
discountPrice.value = (discountPopover.orignalPrice - (discountPopover.orignalPrice * (parseInt(e.rowIndex) / 100))).toFixed(2);
}
});
discountPopoverViewWrapper.add(discountPercentPicker);
// Add discount popover view wrapper to view
discountPopoverView.add(discountPopoverViewWrapper);
// Set popover content view
discountPopover.contentView = discountPopoverView;
// Subscribe to popover hide event
discountPopover.addEventListener('hide', function(e) {
e.cancelBubble = true;
Alloy.Globals.ProductDiscounts[discountPopover.priceButton.sku] = parseFloat(discountPrice.value).toFixed(2);
Alloy.Globals.LiveBasketCollection.executeQuery("UPDATE live_basket SET Price = "+ discountPrice.value +" WHERE Sku = '"+ discountPopover.priceButton.sku +"'");
discountPopover.priceButton.price = Alloy.Globals.DeviceDefaults.CurrencySymbol + discountPrice.value;
discountPopover.priceButton.title = (discountPopover.priceButton.basketQuantity > 0 ? discountPopover.priceButton.basketQuantity +' x ' : '') + discountPopover.priceButton.price;
Titanium.App.fireEvent('redrawBasket');
discountPopover = discountPopoverView = discountPrice = discountPercentPicker = discountPercentValues = null;
console.log(Alloy.Globals.ProductDiscounts);
});
// Show popover
discountPopover.show({
view: lineDiscountButton,
animated: true
});
});
Just as a Question... Why are you cancelling bubbling.
without more of the code base I can only try and make a suggestion.
1) addeventlistener.
lineDiscountButton.addEventListener('click', setupData);
2) setupData
Function setupData(e) {
lineDiscountButton.removeEventListener('click', setupData);
Your code from the inline function.
}
Basically remove the event listener once activated, so add and remove as required.
I don't want to teach you to suck eggs, but to remove an event listener, you have to use exactly the same parameters as adding it. Thus inline function on event listeners are not ideal, although they work separating the code out into its own function is preferable.
Next Alloy globals.... Not good practice. I am guessing you want to have the data only for the duration of the running of the app, and not for future use.
If you need it for future use, you can store the data in properties.
Hope this helps
T.

Titanium, change TextField height with animation

In Appcelerator Titanium (iOS project) I have a TextField with height:50. The TextField contains much more text but the fact that its height is set to 50 lets me use the TextField as a preview of the remaining text: under the TextField I have a button and when I tap this button I want to show the entire text, so I would like to animate the TextField from its current height to Ti.UI.SIZE. Is this possible? How? I noticed some iOS properties (eg. anchorPoint) but I could not understand if they can be useful in my case.
You need to use TextArea instead of TextField if you want multiple lines and word wrapping.
I've added the TextArea to a View so I can animate it to both expand and shrink it.
You can try something like this..
// Create the text area for multiple lines and word wrapping.
var messageField = Ti.UI.createTextArea({
backgroundColor: 'transparent',
color: 'black',
height: Ti.UI.SIZE, // Set here the height to SIZE and the view's height to the required one, ex. 50
textAlign: 'left',
value: 'This text should be displayed in more than one line in a text area, but that behavior is not supported by a text field, again, This text should be displayed in more than one line in a text area, but that behavior is not supported by a text field.',
verticalAlign: Ti.UI.TEXT_VERTICAL_ALIGNMENT_TOP,
width: '90%',
font: { fontSize: 20 }
});
// Add the text area to a view to be able to animate it
var view = Titanium.UI.createView({
height: 50, // Required height
top: 250,
width: '90%',
borderColor: 'black',
borderRadius: 10,
borderWidth: 2,
});
view.add(messageField);
// Create animation object
var animation = Titanium.UI.createAnimation();
animation.duration = 1000; // Set the time of animation, 1000 --> 1 second
var button = Ti.UI.createButton({
title: "Show More",
font: { fontSize: 18 },
width: 100,
top: 200
});
var isExpanded = false;
button.addEventListener('click', function() { // Event listener for your button
if(isExpanded) {
isExpanded = false;
animation.height = 50; // Set the animation height to 50 to shrink the view
view.animate(animation); // Start animating the view to the required height
button.title = "Show More";
} else {
isExpanded = true;
animation.height = Ti.UI.SIZE; // Set the animation height to SIZE to make it expand
view.animate(animation); // Start animating the view to the required height
button.title = "Show Less";
}
});
var win = Ti.UI.createWindow({
backgroundColor: 'white'
});
win.add(button);
win.add(view);
win.open();

Highcharts add an image to that chart with an onClick event attached to it

I have created a chart where I've added an image.
Now when I click this image I want to set the yAxis max to a specific point, and when I click it again to reset the yAxis to the original values.
This is the jsfiddle for it: http://jsfiddle.net/inadcod/TynwP/
I have managed to add the image, to add a click event to the image, but it's as far as I got.
Can anyone help me out with this? Thanks!
There are two ways to do what you want.
First way:
The problem is that it's not possible to update chart options and then redraw to get it updated, you have to destroy and then create it again like the following.
So, for this you can store your chart options into a var and then pass as parameter.
// inside options
load: function() {
this.renderer.image('http://inadcod.com/img/zoom.png', 70, 10, 28, 28)
.on('click', function() {
if(options.yAxis.max) {
delete options.yAxis.max; // return to default
} else {
options.yAxis.max = 25;
}
chart = new Highcharts.Chart(options);
})
.css({
cursor: 'pointer',
position: 'relative',
"margin-left": "-90px",
opacity: 0.75
}).attr({
id: 'myImage',
zIndex: -100
}).add();
}
Demo
Second way:
redraw isn't called if you just update axis data like the following.
chart.yAxis[0].max = 25;, that's why I suggested the way above.
But if you set chart.yAxis[0].isDisty = true; and call chart.redraw();, it will work. You can see my demo bellow.
// inside chart options
load: function() {
this.renderer.image('http://inadcod.com/img/zoom.png', 70, 10, 28, 28)
.on('click', function() {
var axis = chart.yAxis[0];
axis.max = 25;
axis.isDirty = true;
chart.redraw();
})
.css({
cursor: 'pointer',
position: 'relative',
"margin-left": "-90px",
opacity: 0.75
}).attr({
id: 'myImage', // your image id
zIndex: -100
}).add();
}
Demo

Resources