App-Chart
view release on metacpan or search on metacpan
lib/App/Chart/Series.pm view on Meta::CPAN
# make page no more than twice upper,lower data range, so the
# data is not less than half the window
{ my ($l, $h) = $self->range ($lo, $hi);
if (defined $l) {
### series range: "$l to $h"
$page = min ($page, 2 * ($h - $l));
}
}
### shrink to use minimum half window: $page
# make page no smaller than last 1/2 of data, so that's visible
{ my ($l, $h) = $self->range (CORE::int (($lo + $hi) / 2), $hi);
if ($l) { $page = max ($page, $h - $l); }
}
### expand so last half data visible: $page
my ($l, $h);
my $accumulate = sub {
my ($value) = @_;
### accumulate: $value
if (! defined $value) { return 1; }
my $new_l = defined $l ? min ($value, $l) : $value;
my $new_h = defined $h ? max ($value, $h) : $value;
if ($new_h - $new_l <= $page) {
$l = $new_l;
$h = $new_h;
}
if (! defined $l) {
$l = $new_l;
$h = $new_l + $page;
}
return 0;
};
if ($latest) {
if (defined (my $quote_iso = $latest->{'quote_date'})) {
my $quote_t = $timebase->from_iso_floor ($quote_iso);
if ($quote_t >= $lo && $quote_t <= $hi) {
$accumulate->($latest->{'bid'});
$accumulate->($latest->{'offer'});
}
}
if (defined (my $last_iso = $latest->{'last_date'})) {
my $last_t = $timebase->from_iso_floor ($last_iso);
if ($last_t >= $lo && $last_t <= $hi) {
$accumulate->($latest->{'last'});
$accumulate->($latest->{'high'});
$accumulate->($latest->{'low'});
}
}
}
for (my $i = $hi; $i >= $lo; $i--) {
foreach my $value ($values->[$i], $highs->[$i], $lows->[$i]) {
$accumulate->($value);
}
}
my $extra = ($page - ($h - $l)) / 2;
$l -= $extra;
$h += $extra;
### initial range decided: "$l $h $self"
return ($l, $h);
}
# # don't go below `datatype-minimum' (if present), so long as
# # the actual data respects that minimum
# (and-let* ((minimum (datatype-minimum datatype))
# (actual-min (apply min-maybe lst-closes))
# ( (>= actual-min minimum)))
# (set! lower (max lower minimum)))
sub filled_low {
my ($self) = @_;
return $self->{'fill_low'};
}
sub filled_high {
my ($self) = @_;
return $self->{'fill_high'};
}
sub find_before {
my ($self, $before, $n) = @_;
### Series find_before(): "before=$before n=$n"
if ($n <= 0) { return $before; } # asking for no points before
my $values = $self->values_array;
my $chunk = $n;
my $i = $before - 1;
for (;;) {
$chunk *= 2;
my $pre = $i - $chunk;
$self->fill ($pre, $i);
for ( ; $i >= $pre; $i--) {
if ($i < 0) {
### not found, return 0
return 0;
}
if (defined $values->[$i]) {
$n--;
if ($n <= 0) {
### find_before() found: $i
return $i;
}
}
}
}
}
# return pos where there's a value somwhere $pos > $after, or $after if no more
sub find_after {
my ($self, $after, $n) = @_;
### Series find_after(): "$after n=".($n//'undef')
if ($n <= 0) { return $after; } # asking for no points after
my $values = $self->values_array;
my $hi = $self->hi;
my $chunk = $n;
my $i = $after + 1;
( run in 1.163 second using v1.01-cache-2.11-cpan-39bf76dae61 )