I'm trying to achieve this mosaic light show effect for my background view with the CAReplicatorLayer object:
https://downloops.com/stock-footage/mosaic-light-show-blue-illuminated-pixel-grid-looping-background/
Each tile/CALayer is a single image that was replicated horizontally & vertically. That part I have done.
It seems to me this task is broken into at least 4 separate parts:
Pick a random tile
Select a random range of color offset for the selected tile
Apply that color offset over a specified duration in seconds
If the random color offset exceeds a specific threshold then apply a glow effect with the color offset animation.
But I'm not actually sure this would be the correct algorithm.
My current code was taken from this tutorial:
https://www.swiftbysundell.com/articles/ca-gems-using-replicator-layers-in-swift/
Animations are not my strong suite & I don't actually know how to apply continuous/repeating animation on all tiles. Here is my current code:
#IBOutlet var animationView: UIView!
func cleanUpAnimationView() {
self.animationView.layer.removeAllAnimations()
self.animationView.layer.sublayers?.removeAll()
}
/// Start a background animation with a replicated pattern image in tiled formation.
func setupAnimationView(withPatternImage patternImage: UIImage, animate: Bool = true) {
// Tutorial: https://www.swiftbysundell.com/articles/ca-gems-using-replicator-layers-in-swift/
let imageSize = patternImage.size.halve
self.cleanUpAnimationView()
// Animate pattern image
let replicatorLayer = CAReplicatorLayer()
replicatorLayer.frame.size = self.animationView.frame.size
replicatorLayer.masksToBounds = true
self.animationView.layer.addSublayer(replicatorLayer)
// Give the replicator layer a sublayer to replicate
let imageLayer = CALayer()
imageLayer.contents = patternImage.cgImage
imageLayer.frame.size = imageSize
replicatorLayer.addSublayer(imageLayer)
// Tell the replicator layer how many copies (or instances) of the image needs to be rendered. But we won't see more than one since they are, per default, all rendered/stacked on top of each other.
let instanceCount = self.animationView.frame.width / imageSize.width
replicatorLayer.instanceCount = Int(ceil(instanceCount))
// Instance offsets & transforms is needed to move them
// 'CATransform3D' transform will be used on each instance: shifts them to the right & reduces the red & green color component of each instance's tint color.
// Shift each instance by the width of the image
replicatorLayer.instanceTransform = CATransform3DMakeTranslation(imageSize.width, 0, 0)
// Reduce the red & green color component of each instance, effectively making each copy more & more blue while horizontally repeating the gradient pattern
let colorOffset = -1 / Float(replicatorLayer.instanceCount)
replicatorLayer.instanceRedOffset = colorOffset
replicatorLayer.instanceGreenOffset = colorOffset
//replicatorLayer.instanceBlueOffset = colorOffset
//replicatorLayer.instanceColor = UIColor.random.cgColor
// Extend the original pattern to also repeat vertically using another tint color gradient
let verticalReplicatorLayer = CAReplicatorLayer()
verticalReplicatorLayer.frame.size = self.animationView.frame.size
verticalReplicatorLayer.masksToBounds = true
verticalReplicatorLayer.instanceBlueOffset = colorOffset
self.animationView.layer.addSublayer(verticalReplicatorLayer)
let verticalInstanceCount = self.animationView.frame.height / imageSize.height
verticalReplicatorLayer.instanceCount = Int(ceil(verticalInstanceCount))
verticalReplicatorLayer.instanceTransform = CATransform3DMakeTranslation(0, imageSize.height, 0)
verticalReplicatorLayer.addSublayer(replicatorLayer)
guard animate else { return }
// Set both the horizontal & vertical replicators to add a slight delay to all animations applied to the layer they're replicating
let delay = TimeInterval(0.1)
replicatorLayer.instanceDelay = delay
verticalReplicatorLayer.instanceDelay = delay
// This will make the image layer change color
let animColor = CABasicAnimation(keyPath: "instanceRedOffset")
animColor.duration = animationDuration
animColor.fromValue = verticalReplicatorLayer.instanceRedOffset
animColor.toValue = -1 / Float(Int.random(replicatorLayer.instanceCount-1))
animColor.autoreverses = true
animColor.repeatCount = .infinity
replicatorLayer.add(animColor, forKey: "colorshift")
let animColor1 = CABasicAnimation(keyPath: "instanceGreenOffset")
animColor1.duration = animationDuration
animColor1.fromValue = verticalReplicatorLayer.instanceGreenOffset
animColor1.toValue = -1 / Float(Int.random(replicatorLayer.instanceCount-1))
animColor1.autoreverses = true
animColor1.repeatCount = .infinity
replicatorLayer.add(animColor1, forKey: "colorshift1")
let animColor2 = CABasicAnimation(keyPath: "instanceBlueOffset")
animColor2.duration = animationDuration
animColor2.fromValue = verticalReplicatorLayer.instanceBlueOffset
animColor2.toValue = -1 / Float(Int.random(replicatorLayer.instanceCount-1))
animColor2.autoreverses = true
animColor2.repeatCount = .infinity
replicatorLayer.add(animColor2, forKey: "colorshift2")
}
let imageSize = patternImage.size.halve
and
animColor.toValue = -1 / Float(Int.random(replicatorLayer.instanceCount-1))
both generated errors.
I removed the halve and commented-out the animColor lines and the code runs and animates. I could not get ANY replicator layer to display or animate at all (not even the most basic apple or tutorial code) until I used your code. Thank you so much!
When I use a morph animation for a model, the model automatically turns into a hard edge. How should we avoid such changes?
let animation = CABasicAnimation(keyPath: "morpher.weights[0]")
animation.fromValue = 0.0
animation.toValue = 1.0
animation.autoreverses = true
animation.repeatCount = MAXFLOAT
animation.duration = 0.25
face.addAnimation(animation, forKey: nil)
here is the animation
There could be three potential problems causing your model to show hard edges at animation:
insufficient number of polygons in 3D models (low-poly models)
source and target models have different number of polygons
models have lamina faces, non-manifold geo, or non-planar faces
Supposedly, you may have all the listed problems at once or just one of them.
I am trying to make a Standard Deviation overlay using only the daily inputs, and have it overlay that info on any time frame chart. So, even if I look at an hourly chart, I will still see the daily deviations overlayed on the chart. I made one that changes with whatever time frame I am looking at. I started with another public one to make this:
study(title="Standard Deviation",shorttitle="SD",overlay=true)
length = input(20, minval=1)
src = input(open, title="Source")
sd = stdev(src, length)
piv=open
plotOpen = plot(piv,title="Open",color=black,trackprice=true,linewidth=2)
plotR05 = plot(piv+(0.5*sd),title="+0.5", color=red,trackprice=true,linewidth=2)
plotS05 = plot(piv-(0.5*sd),title="-0.5", color=red,trackprice=true,linewidth=2)
plotR10 = plot(piv+sd,title="1", color=blue,trackprice=true,linewidth=2)
plotS10 = plot(piv-sd,title="-1", color=blue,trackprice=true,linewidth=2)
plotR15 = plot(piv+(1.5*sd),title="+1.5", color=green,trackprice=true,linewidth=2)
plotS15 = plot(piv-(1.5*sd),title="-1.5", color=green,trackprice=true,linewidth=2)
plotR20 = plot(piv+(2*sd),title="+2", color=orange,trackprice=true,linewidth=2)
plotS20 = plot(piv-(2*sd),title="-2", color=orange,trackprice=true,linewidth=2)
I am trying to make a Standard Deviation overlay using only the daily inputs, and have it overlay that info on any time frame chart.
You can use TradingView's security() function for that. That function can load price data from any time frame and/or instrument, including the daily data from the current instrument.
With security() your code can thus calculate the daily standard deviation regardless of which time frame the script currently runs on.
For example:
study(title="Standard Deviation",shorttitle="SD",overlay=true)
length = input(20, minval=1)
src = input(open, title="Source")
// Load daily stddev
dailyStd = security(tickerid, "D", stddev(src, length))
piv=open
plotOpen = plot(piv,title="Open",color=black,trackprice=true,linewidth=2)
plotR05 = plot(piv+(0.5*dailyStd),title="+0.5", color=red,trackprice=true,linewidth=2)
plotS05 = plot(piv-(0.5*dailyStd),title="-0.5", color=red,trackprice=true,linewidth=2)
plotR10 = plot(piv+dailyStd,title="1", color=blue,trackprice=true,linewidth=2)
plotS10 = plot(piv-dailyStd,title="-1", color=blue,trackprice=true,linewidth=2)
plotR15 = plot(piv+(1.5*dailyStd),title="+1.5", color=green,trackprice=true,linewidth=2)
plotS15 = plot(piv-(1.5*dailyStd),title="-1.5", color=green,trackprice=true,linewidth=2)
plotR20 = plot(piv+(2*dailyStd),title="+2", color=orange,trackprice=true,linewidth=2)
plotS20 = plot(piv-(2*dailyStd),title="-2", color=orange,trackprice=true,linewidth=2)
Give it a try to see if this approach better serves your goal.
for version 5
//#version=5
indicator("Standart Deviation", shorttitle="SD", overlay=true)
length = input.int(30, minval=1)
src = input.source(open,"Source")
//load daily stdev
dailyStd = request.security(syminfo.tickerid,"D",ta.stdev(src,length))
piv=open
plotOpen = plot(piv,title="Open", color=color.white, trackprice = true, linewidth=2)
plotStdResistance = plot(piv+dailyStd,title="RESISTANCE",color=color.red,trackprice=true,linewidth=1)
plotStdSupport = plot(piv-dailyStd,title="SUPPORT", color=color.green, trackprice = true, linewidth=1)
I want to make Y-axis interval with a certain difference. Let's say the multiple of 100 or any fix value, currently it draws with their own interval.
I am sharing my formatting code here.
let leftAxis = chartView.leftAxis
leftAxis.valueFormatter = IntAxisValueFormatter()
leftAxis.granularityEnabled = true
leftAxis.granularity = 1
I am able to solve my challenge, I am adding my fix here. First I calculated the total range then divided them by interval diff and set the LabelCount.
let totalRange = maxY - minY
let interval = 100 //Let's say 100 in my case
leftAxis.setLabelCount(Int(totalRange/interval) + 1, force: true)
One way is you calculate scale value according to your data. And you can use following function to scale as you need. But exact with value difference I don't think it is possible.
self.lineChart.setScaleMinima(1.0, scaleY: 2.0)
In above value first parameter will zoom in horizontally while second will zoom vertically.
I have an image that I want to rotate 360° (clockwise) and then repeat and I'm having trouble hitting on the right way to do this. I can do this:
UIView.Animate(1, 0, UIViewAnimationOptions.Repeat,
() =>
{
LoadingImage.Transform = MonoTouch.CoreGraphics.CGAffineTransform.MakeRotation(-(float)(Math.PI));
},
() =>
{
});
Which rotates my image 180° and then snaps back to the start and repeats. So, I thought if I do something like 1.99 * PI, it would rotate almost all the way around and probably look ok. Unfortunately, the animation system is smart than that and will just rotate in the opposite direction instead!
So what's the right way to get an image to spin 360° continuously?
Update
With the help or Eric's comment, I've got to this:
CABasicAnimation rotationAnimation = new CABasicAnimation();
rotationAnimation.KeyPath = "transform.rotation.z";
rotationAnimation.To = new NSNumber(Math.PI * 2);
rotationAnimation.Duration = 1;
rotationAnimation.Cumulative = true;
rotationAnimation.RepeatCount = 10;
LoadingImage.Layer.AddAnimation(rotationAnimation, "rotationAnimation");
Which does spin 360°, 10 times in my example (see RepeatCount), but I don't see a way to tell it to repeat until I stop it. CABasicAnimation has a RepeatCount and a RepeatDuration, but doesn't seem to have a property to tell it to just keep repeating. I can set RepeatCount to some suitably high value that it'll keep spinning until the user has probably lost interest, but that doesn't seem like a great solution.
Looks like the solution adapted from the link Eric provided looks like the best choice:
CABasicAnimation rotationAnimation = new CABasicAnimation();
rotationAnimation.KeyPath = "transform.rotation.z";
rotationAnimation.To = new NSNumber(Math.PI * 2);
rotationAnimation.Duration = 1;
rotationAnimation.Cumulative = true;
rotationAnimation.RepeatCount = float.MaxValue;
LoadingImage.Layer.AddAnimation(rotationAnimation, "rotationAnimation");
Set RepeatCount to float.MaxValue to effectively keep it repeating forever (why a count is a float rather than an int remains a mystery).
Try animation.repeatCount = HUGE_VALF;
I think the reason repeat count is a float is to allow for partial cycles of an animation. Maybe you want a circle to animate by pulsing, but stop at the opposite end of where you started.