package ONO::Lib::DateTime::Clock;
################################################################################
# COPYRIGHT / LICENSE #
################################################################################
#
# This file is part of the ONO Software Project.
#
# Copyright (C) 2000-2025 Jos KIRPS [ www.kirps.com | jos_AT_kirps_DOT_com ]
# and The Joopita Project [ www.joopita.org | contact_AT_joopita_DOT_com ]
#
# This file, as well as other parts of the ONO Software Project or related
# elements, are FREE SOFTWARE available under the ARTISTIC LICENSE 2.0.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# For the full license, see /ono/osr/license/LICENSE.txt, or write to
# jos_AT_kirps_DOT_com or contact_AT_joopita_DOT_com.
#
################################################################################
# END OF COPYRIGHT / LICENSE, HERE COMES THE CODE ... #
################################################################################
use strict;
use ONO::Lib::DateTime::ToolBox;
use ONO::Lib::Code::RandomID;
###############################################################################
# standard text based clock
###############################################################################
sub clock {
my $switches = $_[1];
#: A Simple HTML clock
#:
#: -n no autostart
#: -S no seconds
my $ID = ONO::Lib::Code::RandomID->make;
my $jswitch;
if ($switches =~ /S/) {
$jswitch = 1;
}
my $clock = qq~<span id="clock_$ID">0:00:00</span>
<script>
onojs_getthedate('clock_$ID','$jswitch');
function startclock() {setInterval("onojs_getthedate('clock_$ID','$jswitch')",1000)}
</script>
~;
if ($switches !~ /n/) {
$clock .= qq~<script>startclock();</script>~;
}
}
###############################################################################
# animated train station clock (300px fixed for the moment)
###############################################################################
sub canvas_clock {
my (
$self,
$size,
$hour,
$min,
$sec,
$switches,
$colors,
$url,
) = @_;
#: HTML canvas clock
#:
#: -A don't animate
#: -b box around the clock (square, using background color)
#: -B box with border (only with -b)
#: -c use custom colors
#: -C close icon (only with -b, requires url)
#: -H no hour
#: -M no min
#: -r round edges (only with -b)
#: -s studio clock style
#: -S no sec
my $half = int($size/2); # 150
my $rela1 = $half - ($half/10) - ($half/30); # 130
my $rela2 = int($half/1.25); # 120
my $rela3 = int($half/1.36363636); # 110
my $rela4 = int($rela2/4*3.2); # 95
my @cols = (
'#fff', # background
'#d34', # border 1
'#812', # border 2
'#bbb', # steps
'#000', # hour
'#777', # min
'#c00', # secs
);
if ($switches =~ /c/) {
my $num;
foreach my $col (split(/:/,$colors)) {
if ($col =~ /[A-Za-z0-9]/) {
$cols[$num] = $col;
if ($cols[$num] !~ /#/) {
$cols[$num] = "#$cols[$num]";
}
}
$num++;
}
}
my $ID = ONO::Lib::Code::RandomID->make;
my ($ANIMATE,$HOUR,$MIN,$SEC);
if ($switches !~ /A/) {
$ANIMATE = qq~c2d$ID.restore();setTimeout(draw$ID,1000);~;
}
if ($switches !~ /H/) {
$HOUR = qq~c2d$ID.rotate(Math.PI/6*(hrs+(min/60)+(sec/3600)));
c2d$ID.strokeStyle = "$cols[4]";
c2d$ID.beginPath();
c2d$ID.moveTo(0,10);
c2d$ID.lineTo(0,-0.2*$size);
c2d$ID.stroke();
c2d$ID.restore();
c2d$ID.save();
~;
}
if ($switches !~ /M/) {
$MIN = qq~c2d$ID.rotate(Math.PI/30*(min+(sec/60)));
c2d$ID.strokeStyle = "$cols[5]";
c2d$ID.beginPath();
c2d$ID.moveTo(0,20);
c2d$ID.lineTo(0,-$rela3);
c2d$ID.stroke();
c2d$ID.restore();
c2d$ID.save();
~;
}
if ($switches !~ /S/) {
$SEC = qq~c2d$ID.lineWidth=3;
c2d$ID.rotate(Math.PI/30*sec);
c2d$ID.strokeStyle = "$cols[6]";
c2d$ID.beginPath();
c2d$ID.moveTo(0,20);
c2d$ID.lineTo(0,-$rela3);
c2d$ID.stroke();
c2d$ID.restore();~;
}
my $VAR_HOUR = "var hrs=now.getHours();";
my $VAR_MIN = "var min=now.getMinutes();";
my $VAR_SEC = "var sec=now.getSeconds();";
# warning: 'ne ""' is important here as times can be zero!
if ($hour ne "") {
$VAR_HOUR = "var hrs=$hour;";
}
if ($min ne "") {
$VAR_MIN = "var min=$min;";
}
if ($sec ne "") {
$VAR_SEC = "var sec=$sec;";
}
my ($RUN1,$RUN2) = ("","$MIN$HOUR$SEC");
my $DOTS = qq~if (i % 5 == 0) {
c2d$ID.lineWidth=($rela2/15);
sx=sang*$rela4;
sy=cang*-$rela4;
ex=sang*$rela2;
ey=cang*-$rela2;
nx=sang*($rela2/3*2);
ny=cang*-($rela2/3*2);
} else {
c2d$ID.lineWidth=2;
sx=sang*($rela2/1.09);
sy=cang*($rela2/1.09);
ex=sang*$rela2;
ey=cang*$rela2;
}
c2d$ID.beginPath();
c2d$ID.moveTo(sx,sy);
c2d$ID.lineTo(ex,ey);
c2d$ID.stroke();
~;
my $DOTS2;
if ($switches =~ /s/) {
($RUN1,$RUN2) = ("$MIN$HOUR$SEC","");
$DOTS = qq~c2d$ID.lineWidth=2;
sx=sang*($rela2/1.04);
sy=cang*($rela2/1.04);
ex=sang*($rela2/1.12);
ey=cang*($rela2/1.12);
fx=sang*($rela2/0.96);
fy=cang*($rela2/0.96);
c2d$ID.strokeStyle = '#000';
var col = '#110909';
if (i < sec+1) {
col = '$cols[3]';
}
c2d$ID.beginPath();
c2d$ID.arc(sx,sy,$size/110, 0, 2 * Math.PI);
c2d$ID.fillStyle = col;
c2d$ID.fill();
c2d$ID.stroke();
if (i%5 == 0) {
c2d$ID.beginPath();
c2d$ID.arc(ex,ey,$size/110, 0, 2 * Math.PI);
c2d$ID.fillStyle = '$cols[3]';
c2d$ID.fill();
c2d$ID.stroke();
}
~;
$DOTS2 = qq~for (y = 0; y <= 10; y++) {
for (x = 0; x <= 32; x++) {
if (x < 6 || (x > 7 && x < 14) || x == 16 || (x > 18 && x < 25) || x > 26) {
var act = 0;
var h1 = 0;
var h2 = hrs;
var m1 = 0;
var m2 = min;
if (hrs > 9) {h1 = hrs.toString().substr(0,1);h2 = hrs.toString().substr(1,1)}
if (min > 9) {m1 = min.toString().substr(0,1);m2 = min.toString().substr(1,1)}
if (x == 16 && sec%2 == 0 && (y == 3 || y == 7)) {act = 1}
// num 1
if (x < 6) {
if ((x > 0 && x < 5) && (y == 0 || y == 5 || y == 10)) {
act = 1;
if (y == 0 && h1 == 1) {act = 0}
if (y == 5 && (h1 == 0 || h1 == 1)) {act = 0}
if (y == 10 && h1 == 1) {act = 0}
}
if (x == 0 && y > 0 && y < 5) {act = 1;if (h1 == 1 || h1 == 2) {act = 0}}
if (x == 0 && y > 5 && y < 10) {act = 1;if (h1 == 1) {act = 0}}
if (x == 5 && y > 0 && y < 5) {act = 1}
if (x == 5 && y > 5 && y < 10) {act = 1;if (h1 == 2) {act = 0}}
}
// num 2
if (x > 7 && x < 14) {
if ((x > 8 && x < 13) && (y == 0 || y == 5 || y == 10)) {
act = 1;
if (y == 0 && (h2 == 1 || h2 == 4)) {act = 0}
if (y == 5 && (h2 == 0 || h2 == 1 || h2 == 7)) {act = 0}
if (y == 10 && (h2 == 1 || h2 == 4 || h2 == 7)) {act = 0}
}
if (x == 8 && y > 0 && y < 5) {act = 1;if (h2 == 1 || h2 == 2 || h2 == 3 || h2 == 7) {act = 0}}
if (x == 8 && y > 5 && y < 10) {act = 1;if (h2 == 1 || h2 == 3 || h2 == 4 || h2 == 5 || h2 == 7) {act = 0}}
if (x == 13 && y > 0 && y < 5) {act = 1;if (h2 == 5 || h2 == 6) {act = 0}}
if (x == 13 && y > 5 && y < 10) {act = 1;if (h2 == 2) {act = 0}}
}
// num 3
if (x > 18 && x < 25) {
if ((x > 19 && x < 24) && (y == 0 || y == 5 || y == 10)) {
act = 1;
if (y == 0 && (m1 == 1 || m1 == 4)) {act = 0}
if (y == 5 && (m1 == 0 || m1 == 1 || m1 == 7)) {act = 0}
if (y == 10 && (m1 == 1 || m1 == 4 || m1 == 7)) {act = 0}
}
if (x == 19 && y > 0 && y < 5) {act = 1;if (m1 == 1 || m1 == 2 || m1 == 3 || m1 == 7) {act = 0}}
if (x == 19 && y > 5 && y < 10) {act = 1;if (m1 == 1 || m1 == 3 || m1 == 4 || m1 == 5 || m1 == 7) {act = 0}}
if (x == 24 && y > 0 && y < 5) {act = 1;if (m1 == 5 || m1 == 6) {act = 0}}
if (x == 24 && y > 5 && y < 10) {act = 1;if (m1 == 2) {act = 0}}
}
// num 4
if (x > 26) {
if ((x > 27 && x < 32) && (y == 0 || y == 5 || y == 10)) {
act = 1;
if (y == 0 && (m2 == 1 || m2 == 4)) {act = 0}
if (y == 5 && (m2 == 0 || m2 == 1 || m2 == 7)) {act = 0}
if (y == 10 && (m2 == 1 || m2 == 4 || m2 == 7)) {act = 0}
}
if (x == 27 && y > 0 && y < 5) {act = 1;if (m2 == 1 || m2 == 2 || m2 == 3 || m2 == 7) {act = 0}}
if (x == 27 && y > 5 && y < 10) {act = 1;if (m2 == 1 || m2 == 3 || m2 == 4 || m2 == 5 || m2 == 7) {act = 0}}
if (x == 32 && y > 0 && y < 5) {act = 1;if (m2 == 5 || m2 == 6) {act = 0}}
if (x == 32 && y > 5 && y < 10) {act = 1;if (m2 == 2) {act = 0}}
}
var col = '#110909';
if (act == 1) {
col = '$cols[3]';
}
c2d$ID.beginPath();
c2d$ID.arc(0-($half/1.825)+($half*x/28)-($half*y/200),0-($half/5.8)+($half*y/28),$size/110, 0, 2 * Math.PI);
c2d$ID.fillStyle = col;
c2d$ID.fill();
c2d$ID.stroke();
}
}
}
~;
}
my $CLOCK = qq~<canvas id="ono_clock_$ID" width="$size" height="$size"></canvas>
<script>
draw$ID();
function draw$ID() {
var canvas = document.getElementById('ono_clock_$ID');
if (canvas.getContext) {
var c2d$ID=canvas.getContext('2d');
c2d$ID.clearRect(0,0,$size,$size);
var grad1=c2d$ID.createLinearGradient(0,0,$size,$size);
grad1.addColorStop(0,"$cols[1]");
grad1.addColorStop(1,"$cols[2]");
var grad2=c2d$ID.createLinearGradient(0,0,$size,$size);
grad2.addColorStop(0,"$cols[2]");
grad2.addColorStop(1,"$cols[1]");
c2d$ID.font="18px Arial";
c2d$ID.textBaseline="middle";
c2d$ID.textAlign="center";
c2d$ID.lineWidth=1;
c2d$ID.save();
c2d$ID.beginPath();
c2d$ID.arc($half, $half, $rela1, 0, 2 * Math.PI, false);
c2d$ID.fillStyle = '$cols[0]';
c2d$ID.fill();
c2d$ID.strokeStyle=grad1;
c2d$ID.lineWidth=1;
c2d$ID.beginPath();
c2d$ID.arc($half,$half,$rela1,0,Math.PI*2,true);
c2d$ID.shadowOffsetX=0;
c2d$ID.shadowOffsetY=0;
c2d$ID.shadowColor="rgba(0,0,0,0.6)";
c2d$ID.shadowBlur=6;
c2d$ID.stroke();
c2d$ID.restore();
c2d$ID.strokeStyle=grad2;
c2d$ID.lineWidth=5;
c2d$ID.beginPath();
c2d$ID.arc($half,$half,$rela1-1,0,Math.PI*2,true);
c2d$ID.stroke();
c2d$ID.strokeStyle="$cols[3]";
c2d$ID.save();
c2d$ID.translate($half,$half);
var now=new Date();
$VAR_HOUR
$VAR_MIN
$VAR_SEC
c2d$ID.lineWidth = 6;
c2d$ID.save();
$RUN1
for (i = 0; i <= 59; i++) {
ang = Math.PI/30*(i+30)*(-1);
sang = Math.sin(ang);
cang = Math.cos(ang);
$DOTS
}
$DOTS2
$RUN2
$ANIMATE
}
}
</script>
~;
if ($switches =~ /b/) {
my ($CLASS,$STYLE,$CLOSE);
if ($switches =~ /B/) {
$STYLE .= ";border:5px solid #333333";
}
if ($switches =~ /r/) {
$CLASS .= " radius10";
}
if ($switches =~ /C/) {
$CLOSE = qq~<a href="$url"><div class="abs" style="top:10px;right:10px"><img class="block24" src="/ono/osr/images/icons/crystal/32x32/ono/close.png" alt="close button"></div></a>~;
}
$CLOCK = qq~<div class="rel block$CLASS" style="background-color:$cols[0];width:${size}px;height:${size}px$STYLE">$CLOSE$CLOCK</div>~;
}
return $CLOCK;
}
###############################################################################
# countdown
###############################################################################
sub countdown {
my (
$self,
$year,
$mon,
$day,
$hour,
$min,
$sec,
$BLK_ref,
) = @_;
#: Countdown clock.
my %BLK = %$BLK_ref;
my (
$curr_sec,$curr_min,$curr_hour,
$curr_mday,$curr_mon,$curr_year,
$wday,$yday,$isdst
) = ONO::Lib::DateTime::ToolBox->get;
my $month_name = ONO::Lib::DateTime::ToolBox->month_name($mon);
my $TIMESTAMP = "$month_name $day, $year $hour:$min:$sec";
my ($TABS,%hide);
my @SIZE = (25,4,10,8);
if ($year eq $curr_year && $mon eq $curr_mon && $day eq $curr_mday) {
$hide{'d'} = " hide";
@SIZE = (33,6,15,12);
if ($hour eq $curr_hour) {
$hide{'h'} = " hide";
@SIZE = (50,8,20,16);
}
}
# <div class="rel bo" style="top:$SIZE[1]vw;height:$SIZE[2]vw"><div id="ono_countdown_$tp[0]" class="bold bo" style="font-size:$SIZE[3]vw"></div></div>
foreach my $tab ('d:days','h:hours','m:minutes','s:seconds') {
my @tp = split(/:/,$tab);
$TABS .= qq~<td id="ono_countdown_td_$tp[0]" class="w$SIZE[0] center$hide{$tp[0]}">
<div id="ono_countdown_box_$tp[0]" class="box_black radius10 rel">
<div id="ono_countdown_$tp[0]" class="bold" style="height:150px;font-size:1000%;line-height:100%"></div>
<div class="mb10">$BLK{$tp[1]}</div>
</div>
</td>
~;
}
return qq~<table class="wide_table">
<tr class="vtop">
$TABS
</tr>
</table>
<script>
var countDownDate = new Date("$TIMESTAMP").getTime();
var now = new Date().getTime();
var distance = countDownDate - now;
if (distance < 24*60*60*1000) {
onojs_class("ono_countdown_td_d",'hide');
onojs_class("ono_countdown_td_h",'w33 center');
onojs_class("ono_countdown_td_m",'w33 center');
onojs_class("ono_countdown_td_s",'w33 center');
}
if (distance < 60*60*1000) {
onojs_class("ono_countdown_td_h",'hide');
onojs_class("ono_countdown_td_m",'w50 center');
onojs_class("ono_countdown_td_s",'w50 center');
}
if (distance < 60*1000) {
onojs_class("ono_countdown_td_m",'hide');
onojs_class("ono_countdown_td_s",'w100 center');
}
var x = setInterval(function() {
var now = new Date().getTime();
var distance = countDownDate - now;
document.getElementById("ono_countdown_d").innerHTML = Math.floor(distance / (1000 * 60 * 60 * 24));
document.getElementById("ono_countdown_h").innerHTML = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
document.getElementById("ono_countdown_m").innerHTML = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
document.getElementById("ono_countdown_s").innerHTML = Math.floor((distance % (1000 * 60)) / 1000);
if (distance < 1000) {
clearInterval(x);
document.getElementById("ono_countdown_d").innerHTML = '0';
document.getElementById("ono_countdown_h").innerHTML = '0';
document.getElementById("ono_countdown_m").innerHTML = '0';
document.getElementById("ono_countdown_s").innerHTML = '0';
onojs_class("ono_countdown_box_d",'box_red radius10 rel');
onojs_class("ono_countdown_box_h",'box_red radius10 rel');
onojs_class("ono_countdown_box_m",'box_red radius10 rel');
onojs_class("ono_countdown_box_s",'box_red radius10 rel');
}
}, 1000);
</script>
~;
}
###############################################################################
# end of script
###############################################################################
1;
__END__