Build your custom canvas clock

Published on by Yousfi Benameur


this is clock i have already pointed in html5 canvas examples.
the canvas is a surface drawing as gdiplus or gdiplusX provide, but its available on a web navigator.all librairies are built in navigator.
Of course canvas is the speciality of javascript language(vfp cannot build dom objects as i shown in previous posts)
here i used a vfp ie browser (activeX) emulated as IE11.
In this clock can customize many parameters as
-color1,color2
-opacity (transparency 8-100%)-(between 0-8 there is bad effect when clock is animated ...i avoided).
-Graduations color
-Needles color
this can be animated (a web equivalent function setIntervel to vfp timer with interval=1000 millisecond or 1 sec.).
the canvas can captured here with 2 methods :
 -with windows utility snipping tool (manually)
 -with my personal method (i evoked it in html5 canvas posts).it use the web function datatoURl and parse this string
  to obtain a blob of image and apply strtofile vfp function +strconv(..,14) to decode it.This methode cpture the background canvas as transparent (no image back).
  
  the image is saved to a created "images" directory.
 -can add a text on clock or cut it. 
-can export the animated clock to IE com application,full ie navigator or firefox....(even chrome...edge..)
-can set a canvas background image (disc or type a valid web url image....even an animated gif works as well).
-can extract the full html code.
-this small workshop directed by VFP, can build dozens of diffrent clocks.
This sample shows how we can interact from vfp to web objects online

note: the vfp inputbox dont accept clipboard as CTRL+V,CTRL+C...it was an original bug of inputbox vfp function...must type url 
      solution:can replace inputbox by a custom modal form.
 - IE application have changed its behavior....then run vfp9 as administrator to avoid some errors...        


Click on code to select [then copy] -click outside to deselect


*1*
*updated on Monday 28 november 2016---added a clock clipped image background and make the canvas background image tiled to (100% ,100%).
*corrected also the vfp native inputbox bug .see below the class yinputbox.
*to cut the images background in the dialogs choose nothing as picture (cancel)

publi yform
yform=newObject("yclock")
yform.show
read events
retu
*
DEFINE CLASS yclock AS form
BorderStyle = 3  &&resizable
Height = 499
Width = 948
ShowWindow = 2
AutoCenter = .T.
Caption = "Customize your html5 canvas clock"
MaxButton = .T.
BackColor = RGB(212,210,208)
ysource = .F.
ybackg=.f.
ybackg1=.f.
Name = "Form1"

ADD OBJECT shape5 AS shape WITH ;
Top = 15, ;
Left = 19, ;
Height = 276, ;
Width = 169, ;
BackStyle = 0, ;
BorderWidth = 6, ;
Curvature = 15, ;
Enabled = .F., ;
Name = "Shape5"

ADD OBJECT yborder AS shape WITH ;
anchor=15,;
Top = 25, ;
Left = 270, ;
Height = 455, ;
Width = 660, ;
BackStyle = 1, ;
BorderStyle = 0, ;
BackColor = RGB(0,255,0), ;
Name = "yborder"

ADD OBJECT yshp AS shape WITH ;
Top = 12, ;
Left = 14, ;
Height = 276, ;
Width = 169, ;
BackStyle = 1, ;
BorderWidth = 2, ;
Curvature = 15, ;
Enabled = .F., ;
Name = "yshp"

ADD OBJECT olecontrol1 AS olecontrol WITH ;
oleclass="shell.explorer.2",;
anchor=15,;
Top = 31, ;
Left = 276, ;
Height = 442, ;
Width = 648, ;
Name = "Olecontrol1"

ADD OBJECT shape1 AS shape WITH ;
Top = 21, ;
Left = 102, ;
Height = 49, ;
Width = 49, ;
BorderStyle = 1, ;
BorderWidth = 0, ;
Curvature = 30, ;
MousePointer = 15, ;
BackColor = RGB(0,255,0), ;
Name = "Shape1"

ADD OBJECT shape2 AS shape WITH ;
Top = 82, ;
Left = 104, ;
Height = 49, ;
Width = 49, ;
BorderStyle = 1, ;
Curvature = 30, ;
MousePointer = 15, ;
BackColor = RGB(0,0,0), ;
Name = "Shape2"

ADD OBJECT label2 AS label WITH ;
AutoSize = .T., ;
FontBold = .T., ;
FontSize = 11, ;
BackStyle = 0, ;
Caption = "Color1", ;
Height = 20, ;
Left = 24, ;
Top = 36, ;
Width = 49, ;
ForeColor = RGB(255,0,0), ;
Name = "Label2"

ADD OBJECT label3 AS label WITH ;
AutoSize = .T., ;
FontBold = .T., ;
FontSize = 11, ;
BackStyle = 0, ;
Caption = "color2", ;
Height = 20, ;
Left = 24, ;
Top = 103, ;
Width = 46, ;
ForeColor = RGB(255,0,0), ;
Name = "Label3"

ADD OBJECT command1 AS commandbutton WITH ;
Top = 312, ;
Left = 12, ;
Height = 36, ;
Width = 96, ;
FontBold = .T., ;
FontSize = 10, ;
Caption = "Capture SNIP.", ;
MousePointer = 15, ;
SpecialEffect = 2, ;
BackColor = RGB(255,128,64), ;
Name = "Command1"

ADD OBJECT spinner1 AS spinner WITH ;
Height = 24, ;
Increment =   0.10, ;
KeyboardHighValue = 1, ;
KeyboardLowValue = 0, ;
Left = 108, ;
MousePointer = 15, ;
SpinnerHighValue =   1.00, ;
SpinnerLowValue =   0.80, ;
Top = 156, ;
Width = 61, ;
Value = 0.9, ;
Name = "Spinner1"

ADD OBJECT label1 AS label WITH ;
AutoSize = .T., ;
FontBold = .T., ;
FontSize = 11, ;
BackStyle = 0, ;
Caption = "Opacity", ;
Height = 20, ;
Left = 24, ;
Top = 160, ;
Width = 55, ;
ForeColor = RGB(255,0,0), ;
Name = "Label1"

ADD OBJECT check1 AS checkbox WITH ;
Top = 353, ;
Left = 6, ;
Height = 22, ;
Width = 155, ;
FontBold = .T., ;
FontSize = 12, ;
AutoSize = .T., ;
Alignment = 0, ;
BackStyle = 0, ;
Caption = "Draw graduations", ;
ForeColor = RGB(128,0,64), ;
Name = "Check1"

ADD OBJECT check2 AS checkbox WITH ;
Top = 395, ;
Left = 4, ;
Height = 22, ;
Width = 221, ;
FontBold = .T., ;
FontSize = 12, ;
AutoSize = .T., ;
Alignment = 0, ;
BackStyle = 0, ;
Caption = "Start /stop animation clock", ;
ForeColor = RGB(128,0,64), ;
Name = "Check2"

ADD OBJECT shape3 AS shape WITH ;
Top = 204, ;
Left = 139, ;
Height = 25, ;
Width = 24, ;
BackStyle = 1, ;
BorderStyle = 1, ;
BorderWidth = 0, ;
Curvature = 30, ;
MousePointer = 15, ;
BackColor = RGB(0,255,255), ;
Name = "Shape3"

ADD OBJECT label4 AS label WITH ;
AutoSize = .T., ;
FontBold = .T., ;
FontSize = 11, ;
WordWrap = .T., ;
BackStyle = 0, ;
Caption = "Graduations", ;
Height = 20, ;
Left = 24, ;
Top = 207, ;
Width = 87, ;
ForeColor = RGB(255,0,0), ;
Name = "Label4"

ADD OBJECT command2 AS commandbutton WITH ;
AutoSize = .T., ;
Top = 453, ;
Left = 37, ;
Height = 36, ;
Width = 67, ;
FontBold = .T., ;
FontSize = 12, ;
Caption = "Code", ;
MousePointer = 15, ;
SpecialEffect = 2, ;
BackColor = RGB(128,255,0), ;
Name = "Command2"

ADD OBJECT shape4 AS shape WITH ;
Top = 242, ;
Left = 139, ;
Height = 25, ;
Width = 24, ;
BackStyle = 1, ;
BorderStyle = 1, ;
BorderWidth = 0, ;
Curvature = 30, ;
MousePointer = 15, ;
BackColor = RGB(255,255,85), ;
Name = "Shape4"

ADD OBJECT label5 AS label WITH ;
AutoSize = .T., ;
FontBold = .T., ;
FontSize = 11, ;
WordWrap = .T., ;
BackStyle = 0, ;
Caption = "Hour/minutes", ;
Height = 20, ;
Left = 24, ;
Top = 245, ;
Width = 95, ;
ForeColor = RGB(255,0,0), ;
Name = "Label5"

ADD OBJECT command3 AS commandbutton WITH ;
Top = 313, ;
Left = 116, ;
Height = 36, ;
Width = 96, ;
FontBold = .T., ;
FontSize = 10, ;
Caption = "Capture VFP", ;
MousePointer = 15, ;
SpecialEffect = 2, ;
BackColor = RGB(128,255,0), ;
Name = "Command3"

ADD OBJECT combo1 AS combobox WITH ;
Height = 24, ;
Left = 120, ;
Top = 456, ;
Width = 100, ;
Name = "Combo1"

ADD OBJECT image1 AS image WITH ;
Picture = home(1)+"graphics\icons\win95\explorer.ico", ;
Height = 32, ;
Left = 219, ;
MousePointer = 15, ;
Top = 314, ;
Width = 32, ;
Name = "Image1"

ADD OBJECT label6 AS label WITH ;
AutoSize = .T., ;
FontBold = .T., ;
FontSize = 20, ;
BackStyle = 0, ;
Caption = "?", ;
Height = 35, ;
Left = 230, ;
MousePointer = 15, ;
Top = 451, ;
Width = 19, ;
ForeColor = RGB(0,255,0), ;
Name = "Label6"

ADD OBJECT spinner2 AS spinner WITH ;
Height = 24, ;
Increment =   0.10, ;
KeyboardHighValue = 1, ;
KeyboardLowValue = 0, ;
Left =192, ;
SpinnerHighValue =   1.00, ;
SpinnerLowValue =   0.00, ;
Top = 120+90, ;
Width = 72, ;
Value = 0.50, ;
mousepointer=15, ;
Name = "Spinner2"

ADD OBJECT check3 as  checkbox with;
Top = 264,;
Left = 204,;
Height = 18,;
Width = 47,;
FontBold = .T.,;
FontSize = 10,;
AutoSize = .T.,;
Alignment = 0,;
BackStyle = 0,;
Caption = "Text",;
ForeColor = RGB(255,0,0),;
Name = "Check3"


ADD OBJECT ybkg1 AS commandbutton with ;
AutoSize = .T.,;
Top = 119,;
Left = 191,;
Height = 27,;
Width = 76,;
FontBold = .T.,;
FontSize = 9,;
Caption = "Img Clock",;
MousePointer = 15,;
SpecialEffect = 2,;
ForeColor = RGB(255,255,255),;
BackColor = RGB(0,0,0),;
Name = "ybkg1"

PROCEDURE ybkg1.Click
local m.x,m.xpict
m.x=int(val(inputbox("Choose a disc image (1) or an a valid URL image(2)","","1")))
if !between(m.x,1,2)
m.x=1
endi
do case
case m.x=1
m.xpict=getpict()
*if empty(m.xpict) &&if empty : choose to  cut the image clock background
*return  .f.
*endi
thisform.ybackg1="file:///"+strtran(m.xpict,"\","/")

case m.x=2
local m.oo
m.oo=newObject("yinputbox")
oo.show(1)
*m.xpict=inputbox("Get the image URL","","https://www.colourbox.com/preview/7701131-textures.jpg")
*thisform.ybackg1=m.xpict
thisform.ybackg1=_screen.yurl
endcase
thisform.ybuild(thisform.yrgb(thisform.shape1.backcolor),thisform.yrgb(thisform.shape2.backcolor))
ENDPROC




PROCEDURE check3.InteractiveChange
thisform.ybuild(thisform.yrgb(thisform.shape1.backcolor),thisform.yrgb(thisform.shape2.backcolor))
ENDPROC

ADD OBJECT yimg  AS commandbutton with ;
Top = 154,;
Left = 190,;
Height = 32,;
Width = 75,;
FontBold = .T.,;
FontSize = 11,;
Caption = "Img Bkg",;
MousePointer = 15,;
SpecialEffect = 2,;
ForeColor = RGB(255,255,255),;
BackColor = RGB(0,0,0),;
Name = "YIMG"

PROCEDURE yimg.Click
local m.x,m.xpict
m.x=int(val(inputbox("Choose a disc image (1) or an a valid URL image(2)","","1")))
if !between(m.x,1,2)
m.x=1
endi
do case
case m.x=1
m.xpict=getpict()
*if empty(m.xpict) &&if empty cut the image background
*return  .f.
*endi
thisform.ybackg="file:///"+strtran(m.xpict,"\","/")

case m.x=2
*m.xpict=inputbox("Get the image URL","","https://www.colourbox.com/preview/1927275-old-brick-wall-texture.jpg")
thisform.ybackg=m.xpict
local m.oo
oo=newObject("yinputbox")
oo.show(1)
thisform.ybackg=_screen.yurl
endcase


thisform.ybuild(thisform.yrgb(thisform.shape1.backcolor),thisform.yrgb(thisform.shape2.backcolor))
ENDPROC



ADD OBJECT label7 AS label WITH ;
AutoSize = .T., ;
FontBold = .T., ;
FontSize = 11, ;
BackStyle = 0, ;
Caption = "Zoom 0-1", ;
Height = 20, ;
Left = 194, ;
Top = 110+80+4, ;
Width = 65, ;
ForeColor = RGB(255,0,0), ;
Name = "Label7"


PROCEDURE spinner2.InteractiveChange
thisform.ybuild(thisform.yrgb(thisform.shape1.backcolor),thisform.yrgb(thisform.shape2.backcolor))
ENDPROC


PROCEDURE ybuild
lparameters color1,color2      &&,color3
Local colCircle1,colCircle2,gradu,hmin,colText          &&can customize here these properties
colCircle1= color2    &&'#16b'   &&'black'  &&
gradu=thisform.yrgb(thisform.shape3.backcolor)   &&graduations color
hmin=thisform.yrgb(thisform.shape4.backcolor)            &&graduations color hours/minutes
colText='white'

if thisform.check3.value=1
text to m.mytext textmerge noshow
//draw text
ctx.save();
ctx.translate(x,y);
ctx.fillStyle = 'white';
ctx.font = (r*0.45/5)+"px serif";
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillText('Vfp rock',0,r*0.45);
ctx.restore();

endtext
else
m.mytext=""
endi

local m.ygraduations
text to m.ygraduations textmerge noshow
//draw index
ctx.save();
ctx.translate(x,y);
ctx.fillStyle = <<gradu>>                         //graduations+hours+minutes
for(var i=0;i<12;i++){
ctx.rotate(Math.PI/6);
ctx.fillRect(-r*0.04/2,-r*0.75,r*0.04,r*0.2);
}
ctx.restore();

ctx.save();          //petit cercle centre
ctx.translate(x,y);
ctx.beginPath();
ctx.fillStyle = 'red';
ctx.arc(0,0,r*0.02,0,Math.PI*2,false);
ctx.fill();
ctx.restore();
endtext
local m.xx,m.yy,m.zz
m.zz=iif(thisform.check2.value=1 ," setInterval('drawHands()',1000); ","")

m.xx= iif(thisform.check1.value=1,m.ygraduations,"")
text to m.yy textmerge noshow
//draw hour hand
ctx.save();
ctx.translate(x,y);
ctx.beginPath();
ctx.rotate((h/12+m/12/60)*2*Math.PI);
ctx.strokeStyle = <<hmin>>
ctx.lineWidth = r*0.02;
ctx.moveTo(0,0);
ctx.lineTo(0,-r*0.4);
ctx.stroke();
ctx.restore();

//draw minute hand
ctx.save();
ctx.translate(x,y);
ctx.rotate(m*2*Math.PI/60);
ctx.beginPath();
ctx.strokeStyle = <<hmin>>
ctx.lineWidth = r*0.02;
ctx.moveTo(0,0);
ctx.lineTo(0,-r*0.6);
ctx.stroke();
ctx.restore();

//draw second hand
ctx.save();
ctx.translate(x,y);
ctx.beginPath();
ctx.rotate(s*2*Math.PI/60);
ctx.strokeStyle = 'red';
ctx.lineWidth = r*0.01;
ctx.moveTo(0,r*0.1);
ctx.lineTo(0,-r*0.7);
ctx.stroke();
ctx.restore();
endtext
m.yy=iif(thisform.check1.value=1,m.yy,"")

TEXT to m.myvar textmerge noshow
<!DOCTYPE HTML>
<html>
<meta http-equiv="X-UA-Compatible" content="IE=11" >
<body  bgcolor="white"   leftmargin=0 topmargin=0 scroll="no"  oncontextmenu="return true;" onload="init();">
<canvas id="ycanvas" width="<<int(thisform.olecontrol1.width)>>"  height="<<int(thisform.olecontrol1.height)>>" style="background-color:white;background: url('<<thisform.ybackg>>');background-size:100% 100%;"></canvas>
<script>
function init(){
drawHands();
<<m.zz>>
}

function drawHands(){
var canvas = document.getElementById('ycanvas');

var ctx = canvas.getContext('2d');
var x=<<int(thisform.olecontrol1.width/2)>>
var y=<<int(thisform.olecontrol1.height/2)>>
var r=x*<<thisform.spinner2.value>>   //5;

var d = new Date();
var h = d.getHours();
var m = d.getMinutes();
var s = d.getSeconds();

ctx.clearRect(0,0,canvas.width,canvas.height);
//////////////////////
var thumbImg = document.createElement('img');
thumbImg.src = '<<thisform.ybackg1>>';   // https://www.colourbox.com/preview/7701131-textures.jpg';
thumbImg.onload = function() {
ctx.save();
// ctx.clearRect(0,0,2*x,2*y);
ctx.translate(x,y);
ctx.globalAlpha = 0.4;
ctx.beginPath();
ctx.arc(0, 0, r*0.8, 0, Math.PI * 2, true);
ctx.closePath();
ctx.clip();

ctx.drawImage(thumbImg, -0.8*r,-0.8*r,2*r*0.8, 2*r*0.8);

ctx.beginPath();
ctx.arc(0, 0, r*0.8, 0, Math.PI * 2, true);
ctx.clip();
ctx.closePath();
ctx.restore();
} ;
////////////////////////////////////////////

//draw background
ctx.save();
ctx.translate(x,y);
var grad = ctx.createLinearGradient(-r,r,r,-r);
grad.addColorStop(0,<<color1>>);
grad.addColorStop(0.5,<<color2>>);
grad.addColorStop(1,<<color1>>);
ctx.beginPath();
ctx.fillStyle = grad;
ctx.arc(0,0,r,0,Math.PI*2,false);
ctx.fill();

grad = ctx.createLinearGradient(-r,-r,r,r);
grad.addColorStop(0,<<color1>>);
grad.addColorStop(0.5,<<color2>>);
grad.addColorStop(1,<<color1>>);
ctx.beginPath();
ctx.fillStyle = grad;
ctx.arc(0,0,r*0.85,0,Math.PI*2,false);
ctx.fill();

ctx.beginPath();
ctx.fillStyle =<<color2>>                           //cercle 1
ctx.arc(0,0,r*0.8,0,Math.PI*2,false);
ctx.fill();

ctx.beginPath();
ctx.fillStyle = <<color2>>                           //petit cercle 2
ctx.arc(0,0,r*0.4,0,Math.PI*2,false);
ctx.fill();
ctx.restore();

<<m.mytext>>
<<m.xx>>
<<m.yy>>
}
</script>
</body>
</html>
ENDTEXT
m.lcdest=Addbs(Sys(2023))+"test.html"
Strtofile(m.myvar,m.lcdest)

thisform.olecontrol1.navigate(m.lcdest)
thisform.ysource=m.myvar
*modi comm (lcdest)
ENDPROC

PROCEDURE yrgb
lparameters xcol
Local RGBChr
m.RGBChr=left(BINTOC(xcol,'R'),3)
R=asc(substr(m.RGBChr,1,1)) && RED
G=asc(substr(m.RGBChr,2,1)) && GREEN
B=asc(substr(m.RGBChr,3,1)) && BLUE
return "'rgba("+trans(r,"999")+","+trans(g,"999")+","+trans(b,"999")+","+trans(thisform.spinner1.value,"999.99")+" )'"
ENDPROC

PROCEDURE Init
publi m.yrep
m.yrep=addbs(justpath(sys(16,1)))       &&if form :addbs(justpath(sys(1271,this)))
set defa to (yrep)
if !directory (m.yrep+"images")
md (m.yrep+"images")
endi
_screen.windowstate=1
thisform.ybackg="https://www.colourbox.com/preview/1927275-old-brick-wall-texture.jpg"
thisform.ybackg1="https://www.colourbox.com/preview/7701131-textures.jpg"

thisform.ybuild(thisform.yrgb(thisform.shape1.backcolor),thisform.yrgb(thisform.shape2.backcolor))
ENDPROC

PROCEDURE Load
Set Safe Off
declare integer BringWindowToTop in user32 integer
&&shellexecute
DECLARE INTEGER ShellExecute IN SHELL32.DLL INTEGER nWinHandle,;
STRING cOperation,;
STRING cFileName,;
STRING cParameters,;
STRING cDirectory,;
INTEGER nShowWindow
ENDPROC

Procedure resize
thisform.ybuild(thisform.yrgb(thisform.shape1.backcolor),thisform.yrgb(thisform.shape2.backcolor))
endproc

PROCEDURE yborder.Init

with this
.backcolor=0  &&can customize
.zorder(1)
endwith
ENDPROC

PROCEDURE olecontrol1.Init
this.silent=.t.
ENDPROC

PROCEDURE shape1.Click
local m.xcolor
m.xcolor=getcolor()
if !m.xcolor=-1
this.backcolor=m.xcolor
thisform.ybuild(thisform.yrgb(this.backcolor),thisform.yrgb(thisform.shape2.backcolor))
endi
ENDPROC

PROCEDURE shape2.Click
local m.xcolor
m.xcolor=getcolor()
if !m.xcolor=-1
this.backcolor=m.xcolor
thisform.ybuild(thisform.yrgb(thisform.shape1.backcolor),thisform.yrgb(this.backcolor))
endi
ENDPROC

PROCEDURE command1.Click
thisform.check2.value=0    &&stop clock if animated
thisform.check2.interactiveChange()
run/n snippingTool
ENDPROC

PROCEDURE spinner1.InteractiveChange
thisform.ybuild(thisform.yrgb(thisform.shape1.backcolor),thisform.yrgb(thisform.shape2.backcolor))
ENDPROC

PROCEDURE check1.InteractiveChange
thisform.ybuild(thisform.yrgb(thisform.shape1.backcolor),thisform.yrgb(thisform.shape2.backcolor))
if this.value=1
thisform.check2.enabled=.t.
else
thisform.check2.enabled=.f.
endi
ENDPROC

PROCEDURE check2.InteractiveChange
thisform.ybuild(thisform.yrgb(thisform.shape1.backcolor),thisform.yrgb(thisform.shape2.backcolor))
ENDPROC

PROCEDURE shape3.Click
local m.xcolor
m.xcolor=getcolor()
if !m.xcolor=-1
this.backcolor=m.xcolor
thisform.ybuild(thisform.yrgb(thisform.shape1.backcolor),thisform.yrgb(thisform.shape2.backcolor))
endi

PROCEDURE command2.Click
try
local m.lcdest
m.lcdest=addbs(sys(2023))+"ysource.txt"
strtofile(thisform.ysource,m.lcdest)
run/n notepad &lcdest
catch
endtry
ENDPROC

PROCEDURE shape4.Click
local m.xcolor
m.xcolor=getcolor()
if !m.xcolor=-1
this.backcolor=m.xcolor
thisform.ybuild(thisform.yrgb(thisform.shape1.backcolor),thisform.yrgb(thisform.shape2.backcolor))
endi
ENDPROC

PROCEDURE command3.Click
thisform.check2.value=0    &&stop clock if animated
thisform.check2.interactiveChange()

local m.dataURL
m.dataURL = thisform.olecontrol1.document.getElementById("ycanvas").toDataURL("image/png")
m.dataURL=strconv(strtran(m.dataURL,"data:image/png;base64,",""),14)

Local m.xx
m.xx="ycap_"+Ttoc(Datetime())
m.xx=Strtran(m.xx,"/","_")
m.xx=Strtran(m.xx,":","_")
m.xx=Strtran(m.xx,";","_")
m.xx=m.yrep+"images\"+m.xx+Sys(2015)+'.png'
strtofile(m.dataURL,m.xx)

*run/n explorer &xx
messagebox(m.xx +"........saved!",0+32+4096,'',1000)
ENDPROC

PROCEDURE combo1.Click
with thisform
.check1.value=1
.check2.value=1
.check1.interactiveChange()
.check2.interactiveChange()
endwith

local m.lcdest
m.lcdest=Addbs(Sys(2023))+"test.html"

do case
case this.value=1
local apie
apie=newObject("internetexplorer.application")
with apie
.navigate(m.lcdest)
try    &&run as admin
.menubar=0
.toolbar=0
.statusbar=0
bringwindowtotop(.hwnd)
catch
endtry
.visible=.t.
endwith

case this.value=2
result = ShellExecute(0, "open", "iexplore.exe",m.lcdest,"",1)

case this.value=3
result = ShellExecute(0, "open", "firefox.exe",m.lcdest,"",1)

endcase
ENDPROC

PROCEDURE combo1.Init
with this
.additem("1.Export to ie app")
.additem("2.Export to ie full browser")
.additem("3.Export to Firefox")
.listindex=1
.value=1
.style=2
endwith
ENDPROC

PROCEDURE image1.Click
local m.oo
m.oo=m.yrep+"images"
run/n explorer &oo
ENDPROC

PROCEDURE label6.Click
local m.myvar
text to m.myvar noshow
this is clock i have already pointed in html5 canvas examples.
the canvas is a surface drawing as gdiplus or gdiplusX provide, but its available on a web navigator.
Of course canavas is the speciality of javascript language(vfp cannot build dom objects as i shown in previous posts)
here i used a vfp ie browser (activeX) emulated as IE11.
In this clock can customize many parameters as
-color1,color2
-opacity (transparency 8-100%)-(between 0-8 there is bad effect i avoided).
-Graduations color
-Needles color
this can be animated (a web equivalent function setIntervel to vfp timer with interval=1000 millisecond or 1 sec.).
the canvas can captured here with 2 methods :
-with windows utility snipping tool (manually)
-with my personal method (i evoked it in html5 canvas posts).it use the web function datatoURl and parse this string
to obtain a blob of image and apply strtofile vfp function +strconv(..,14) to decode it.

the image is saved to a created "images" directory.
-can export the animated clock to ie application full ie navigator or firefox....(even chrome..)
-can add a text on the clock or cut it
-can set a canvas background image (disc or type a valid web url image....even an animated gif works as well).
-can extract the full html code.
- can build dozens of diffrent clocks.
Note that IE application have modified its behavior then run vfp9 as administrator to avoid some errors...
endtext
#define MB_ICONINFORMATION 0x00000040
#define MB_OK 0x00000000
#define MB_APPLMODAL 0x00000000
#define  MB_DEFBUTTON1 0x0000000

DECLARE INTEGER MessageBox IN user32 As MessageBoxA;
INTEGER hwnd,;
STRING  lpText,;
STRING  lpCaption,;
INTEGER wType

*buttons
#define MB_ABORTRETRYIGNORE 0x00000002
#define MB_CANCELTRYCONTINUE 0x00000006
#define MB_HELP 0x00004000

#define MB_OKCANCEL 0x00000001
#define MB_RETRYCANCEL 0x00000005
#define MB_YESNO  0x00000004
#define MB_YESNOCANCEL 0x00000003

*Icons
#define  MB_ICONEXCLAMATION 0x00000030
#define MB_ICONWARNING 0x00000030

#define MB_ICONASTERISK 0x00000040
#define MB_ICONQUESTION 0x00000020
#define MB_ICONSTOP 0x00000010
#define MB_ICONERROR 0x00000010
#define MB_ICONHAND  0x00000010

*To indicate the default button, specify one of the following values.

#define MB_DEFBUTTON2 0x00000100
#define MB_DEFBUTTON3 0x00000200
#define MB_DEFBUTTON4 0x00000300

*To indicate the modality of the dialog box, specify one of the following values.

#define MB_SYSTEMMODAL 0x00001000
#define MB_TASKMODAL 0x00002000

*To specify other options, use one or more of the following values.
#define MB_DEFAULT_DESKTOP_ONLY 0x00020000
#define MB_RIGHT 0x00080000
#define MB_RTLREADING  0x00100000
#define MB_SETFOREGROUND  0x00010000
#define MB_TOPMOST  0x00040000
#define MB_SERVICE_NOTIFICATION 0x00200000

*Return code
#define IDABORT 3
#define IDCANCEL 2
#define IDCONTINUE 11
#define IDIGNORE 5
#define IDNO 7
#define IDOK 1
#define IDRETRY 4
#define IDTRYAGAIN 10
#define IDYES 6

MessageBoxA(_vfp.hwnd,m.myvar,"Html5 canvas clcock",MB_APPLMODAL+MB_OK +MB_ICONINFORMATION +MB_DEFBUTTON1 )
ENDPROC

PROCEDURE DESTROY
*try
*clean if possible.
dele file addbs(sys(2023)+"test.html"
dele file addbs(sys(2023)+"ysource.txt"
*catch
*endtry

clea events
endproc

ENDDEFINE
*
*-- EndDefine: yclock
*2*
*as said above there is  a bug with vfp native inputbox function.cannot copy/paste with the standard keys: ctrl+C,CTRL+v
*this is a replacement of the native inputbox function.it have hability to use the clipboard
*rightclick on the textbox to paste the clipboard
*it create a public variable yurl of _screen object and ùake it available when the form is released.
*do form yform1.......createObject("yinputbox).......newObject("yinputbox")

*!*	yform1=newObject("yinputbox")
*!*	yform1.show(1)
*!*	messagebox(_screen.yurl)
*!*	retu

DEFINE CLASS yinputbox AS form
BorderStyle = 2
Height = 56
Width = 700
ShowWindow = 1
AutoCenter = .T.
Caption = ""
ControlBox = .F.
*WindowType = 1  &&modal   or use claa with show(1) as in code above
BackColor = RGB(212,210,208)
Name = "Form1"

ADD OBJECT text1 AS textbox WITH ;
FontBold = .T., ;
Height = 27, ;
Left = 6, ;
Top = 22, ;
Width = 660, ;
Name = "Text1"

ADD OBJECT label1 AS label WITH ;
AutoSize = .T., ;
FontBold = .T., ;
FontSize = 14, ;
BackStyle = 0, ;
Caption = "X", ;
Height = 25, ;
Left = 680, ;
MousePointer = 15, ;
Top = 2, ;
Width = 15, ;
ForeColor = RGB(255,0,0), ;
Name = "LABEL1"

ADD OBJECT label2 AS label WITH ;
AutoSize = .T., ;
FontBold = .T., ;
FontSize = 10, ;
Caption = "type the text or Rightclick o, textbox to paste clipboard", ;
Height = 18, ;
Left = 10, ;
Top = 1, ;
Width = 350, ;
ForeColor = RGB(255,0,0), ;
BackColor = RGB(255,255,128), ;
Name = "Label2"

PROCEDURE Init
try
_screen.addproperty("yurl","")
catch
endtry
ENDPROC

PROCEDURE Destroy
_screen.yurl=allt(thisform.text1.value)
ENDPROC

PROCEDURE text1.RightClick
this.value=_cliptext
ENDPROC

PROCEDURE text1.Valid
*thisform.release
ENDPROC

PROCEDURE label1.Click
thisform.release
ENDPROC

ENDDEFINE
*
*-- EndDefine: yinputbox


Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock

Click on code to select [then copy] -click outside to deselect


*2* updated on monday 28 november 2016
*as said above there is  a bug with vfp native inputbox function.cannot copy/paste with the standard keys: ctrl+C,CTRL+v
*this is a replacement of the native inputbox function.it have hability to use the clipboard
*rightclick on the textbox to paste the clipboard
*it creates a public variable yurl of _screen object and makes it available when the form is released.
*do form yform1.......createObject("yinputbox).......newObject("yinputbox").to make the form modal (if not set at design time) use the show(1) as pointed.

local yform
yform1=newObject("yinputbox")
yform1.show(1)
messagebox(_screen.yurl)  && value returned
retu

DEFINE CLASS yinputbox AS form
BorderStyle = 2
Height = 56
Width = 700
ShowWindow = 1
AutoCenter = .T.
Caption = "Type the text or Rightclick on textbox to paste clipboard"
Maxbutton=.f.
minButton=.f.
*WindowType = 1  &&modal  or use show(1) as above to set  the form modality
BackColor = RGB(212,210,208)
Name = "Form1"

ADD OBJECT text1 AS textbox WITH ;
FontBold = .T., ;
Height = 27, ;
Left = 6, ;
Top = 22, ;
Width = 660, ;
Name = "Text1"

PROCEDURE Init
try  &&if the property dont exist
_screen.addproperty("yurl","")
catch
*the property already exists
endtry
ENDPROC

PROCEDURE Destroy
_screen.yurl=allt(thisform.text1.value)
ENDPROC

PROCEDURE text1.RightClick  &&paste clipboard
this.value=_cliptext
ENDPROC

PROCEDURE text1.Valid
*thisform.release
ENDPROC


ENDDEFINE
*
*-- EndDefine: yinputbox


NOTE :for visual forms can use the syntax : do form [modal form] to  varname.......the varname is populated by the string returned by the modal form.

NOTE :for visual forms can use the syntax : do form [modal form] to varname.......the varname is populated by the string returned by the modal form.

Click on code to select [then copy] -click outside to deselect

                  

*3*
*updated on saturday 10 december 2016.
*adapted from https://codepen.io/iliadraznin/pen/JcqbE
*As it this pure css3 clock cannot work or at least cannot start correctly.
*vfp makes it working as well with settings initial time() function and altering the css3 initial code.
*can customize the background picture with any web image or even with local disc one.
*this is a great sample how to use css3.

Publi yform
yform=Newobject("ycssClock")
yform.Show
Read Events
Retu
*
Define Class ycssClock As Form
	Height = 525
	Width = 891
	ShowWindow = 2
	windowstate=2
	AutoCenter = .T.
	Caption = "A pure css3 clock drived from vfp"
	Name = "Form1"

	Add Object olecontrol1 As OleControl With ;
		oleclass="shell.explorer.2",;
		Top = 0, ;
		Left = 0, ;
		Height = 529, ;
		Width = 901, ;
		Anchor = 15, ;
		Name = "Olecontrol1"

	Procedure ybuild
		Local yhour, yminute,ysecond
		Set Hours To 12
		m.yhour=Substr(Time(),1,2)
		m.yminute=Substr(Time(),4,2)
		m.ysecond=Substr(Time(),7,2)

		Local xangleH,xangleMin,xAngleSec
		xangleH   =30*Int(Val(yhour))
		xangleMin =6*Int(Val(m.yminute))
		xAngleSec =6*Int(Val(m.ysecond))

		Local m.myvar
		TEXT to m.myvar textmerge  noshow
		<style>
		body { font-size:62.5%; margin:1em; background:#232425 url('http://www.yannarthusbertrand2.org/index2.php?option=com_datsogallery&func=wmark&mid=406'); background-repeat: no-repeat; background-size: 100% 100%; }
		ul { list-style:none; margin:0; padding:0 }
		#watch { font-size:1em; position:relative }
		#watch .frame-face {
		  position:relative;
		  width:30em;
		  height:30em;
		  margin:2em auto;
		  border-radius:15em;
		  background:-webkit-linear-gradient(top, #f9f9f9,#666);
		  background:-moz-linear-gradient(top, #f9f9f9,#666);
		  background:linear-gradient(to bottom, #f9f9f9,#666);
		  box-shadow:rgba(0,0,0,.8) .5em .5em 4em;
		}
		#watch .frame-face:before {
		  content:'';
		  width:29.4em;
		  height:29.4em;
		  border-radius:14.7em;
		  position:absolute;
		  top:.3em; left:.3em;
		  background:
		    -webkit-linear-gradient(135deg, rgba(246,248,249,0) 0%,rgba(229,235,238,1) 50%,rgba(205,212,217,1) 51%,rgba(245,247,249,0) 100%),
		    -webkit-radial-gradient(center, ellipse cover, rgba(246,248,249,1) 0%,rgba(229,235,238,1) 65%,rgba(205,212,217,1) 66%,rgba(245,247,249,1) 100%);
		  background:
		    -moz-linear-gradient(135deg, rgba(246,248,249,0) 0%,rgba(229,235,238,1) 50%,rgba(205,212,217,1) 51%,rgba(245,247,249,0) 100%),
		    -moz-radial-gradient(center, ellipse cover, rgba(246,248,249,1) 0%,rgba(229,235,238,1) 65%,rgba(205,212,217,1) 66%,rgba(245,247,249,1) 100%);
		  background:
		    linear-gradient(135deg, rgba(246,248,249,0) 0%,rgba(229,235,238,1) 50%,rgba(205,212,217,1) 51%,rgba(245,247,249,0) 100%),
		    radial-gradient(ellipse at center, rgba(246,248,249,1) 0%,rgba(229,235,238,1) 65%,rgba(205,212,217,1) 66%,rgba(245,247,249,1) 100%);
		}
		#watch .frame-face:after {
		  content:'';
		  width:28em;
		  height:28em;
		  border-radius:14.2em;
		  position:absolute;
		  top:.9em; left:.9em;
		  box-shadow:inset rgba(0,0,0,.2) .2em .2em 1em;
		  border:.1em solid rgba(0,0,0,.2);
		  background:-webkit-linear-gradient(top, #fff, #ccc);
		  background:-moz-linear-gradient(top, #fff, #ccc);
		  background:linear-gradient(to bottom, #fff, #ccc);
		}
		#watch .minute-marks li {
		  display:block;
		  width:.2em;
		  height:.6em;
		  background:#929394;
		  position:absolute;
		  top:50%; left:50%;
		  margin:-.4em 0 0 -.1em;
		}
		#watch .minute-marks li:first-child {transform:rotate(6deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(2) {transform:rotate(12deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(3) {transform:rotate(18deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(4) {transform:rotate(24deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(5) {transform:rotate(36deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(6) {transform:rotate(42deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(7) {transform:rotate(48deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(8) {transform:rotate(54deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(9) {transform:rotate(66deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(10) {transform:rotate(72deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(11) {transform:rotate(78deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(12) {transform:rotate(84deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(13) {transform:rotate(96deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(14) {transform:rotate(102deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(15) {transform:rotate(108deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(16) {transform:rotate(114deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(17) {transform:rotate(126deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(18) {transform:rotate(132deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(19) {transform:rotate(138deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(20) {transform:rotate(144deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(21) {transform:rotate(156deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(22) {transform:rotate(162deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(23) {transform:rotate(168deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(24) {transform:rotate(174deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(25) {transform:rotate(186deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(26) {transform:rotate(192deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(27) {transform:rotate(198deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(28) {transform:rotate(204deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(29) {transform:rotate(216deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(30) {transform:rotate(222deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(31) {transform:rotate(228deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(32) {transform:rotate(234deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(33) {transform:rotate(246deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(34) {transform:rotate(252deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(35) {transform:rotate(258deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(36) {transform:rotate(264deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(37) {transform:rotate(276deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(38) {transform:rotate(282deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(39) {transform:rotate(288deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(40) {transform:rotate(294deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(41) {transform:rotate(306deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(42) {transform:rotate(312deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(43) {transform:rotate(318deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(44) {transform:rotate(324deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(45) {transform:rotate(336deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(46) {transform:rotate(342deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(47) {transform:rotate(348deg) translateY(-12.7em)}
		#watch .minute-marks li:nth-child(48) {transform:rotate(354deg) translateY(-12.7em)}
		#watch .digits {
		  width:30em;
		  height:30em;
		  border-radius:15em;
		  position:absolute;
		  top:0; left:50%;
		  margin-left:-15em;
		}
		#watch .digits li {
		  font-size:1.6em;
		  display:block;
		  width:1.6em;
		  height:1.6em;
		  position:absolute;
		  top:50%; left:50%;
		  line-height:1.6em;
		  text-align:center;
		  margin:-.8em 0 0 -.8em;
		  font-weight:bold;
		}
		#watch .digits li:nth-child(1) { transform:translate(3.9em, -6.9em) }
		#watch .digits li:nth-child(2) { transform:translate(6.9em, -4em) }
		#watch .digits li:nth-child(3) { transform:translate(8em, 0) }
		#watch .digits li:nth-child(4) { transform:translate(6.8em, 4em) }
		#watch .digits li:nth-child(5) { transform:translate(3.9em, 6.9em) }
		#watch .digits li:nth-child(6) { transform:translate(0, 8em) }
		#watch .digits li:nth-child(7) { transform:translate(-3.9em, 6.9em) }
		#watch .digits li:nth-child(8) { transform:translate(-6.8em, 4em) }
		#watch .digits li:nth-child(9) { transform:translate(-8em, 0) }
		#watch .digits li:nth-child(10) { transform:translate(-6.9em, -4em) }
		#watch .digits li:nth-child(11) { transform:translate(-3.9em, -6.9em) }
		#watch .digits li:nth-child(12) { transform:translate(0, -8em) }
		#watch .digits:before {
		  content:'';
		  width:1.6em;
		  height:1.6em;
		  border-radius:.8em;
		  position:absolute;
		  top:50%; left:50%;
		  margin:-.8em 0 0 -.8em;
		  background:#121314;
		}
		#watch .digits:after {
		  content:'';
		  width:4em;
		  height:4em;
		  border-radius:2.2em;
		  position:absolute;
		  top:50%; left:50%;
		  margin:-2.1em 0 0 -2.1em;
		  border:.1em solid #c6c6c6;
		  background:-webkit-radial-gradient(center, ellipse cover, rgba(200,200,200,0), rgba(190,190,190,1) 90%, rgba(130,130,130,1) 100%);
		  background:-moz-radial-gradient(center, ellipse cover, rgba(200,200,200,0), rgba(190,190,190,1) 90%, rgba(130,130,130,1) 100%);
		  background:radial-gradient(ellipse at center, rgba(200,200,200,0), rgba(190,190,190,1) 90%, rgba(130,130,130,1) 100%);
		}
		@keyframes hours { to {transform:rotate(335deg)} }
		#watch .hours-hand {
		  width:.8em;
		  height:7em;
		  border-radius:0 0 .9em .9em;
		  background:#232425;
		  position:absolute;
		  bottom:50%; left:50%;
		  margin:0 0 -.8em -.4em;
		  box-shadow:#232425 0 0 2px;
		  transform-origin:0.4em 6.2em;
		  transform:rotate(<<m.xangleH>>deg);
		  animation:hours 43200s linear 0s infinite;
		}
		#watch .hours-hand:before {
		  content:'';
		  background:inherit;
		  width:1.8em;
		  height:.8em;
		  border-radius:0 0 .8em .8em;
		  box-shadow:#232425 0 0 1px;
		  position:absolute;
		  top:-.7em; left:-.5em;
		}
		#watch .hours-hand:after {
		  content:'';
		  width:0; height:0;
		  border:.9em solid #232425;
		  border-width:0 .9em 2.4em .9em;
		  border-left-color:transparent;
		  border-right-color:transparent;
		  position:absolute;
		    top:-3.1em; left:-.5em;
		}
		@keyframes minutes { to {transform:rotate(422deg)} }
		#watch .minutes-hand {
		  width:.8em;
		  height:12.5em;
		  border-radius:.5em;
		  background:#343536;
		  position:absolute;
		  bottom:50%; left:50%;
		  margin:0 0 -1.5em -.4em;
		  box-shadow:#343536 0 0 2px;
		  transform-origin:0.4em 11em;
		  transform:rotate(<<m.xangleMin>>deg);
		  animation:minutes 3600s linear 0s infinite;
		}
		@keyframes seconds { to {transform:rotate(480deg)} }
		#watch .seconds-hand {
		  width:.2em;
		  height:14em;
		  border-radius:.1em .1em 0 0/10em 10em 0 0;
		  background:#c00;
		  position:absolute;
		  bottom:50%; left:50%;
		  margin:0 0 -2em -.1em;
		  box-shadow:rgba(0,0,0,.8) 0 0 .2em;
		  transform-origin:0.1em 12em;
		  transform:rotate(<<m.xangleSec>>deg);
		  animation:seconds 60s steps(60, end) 0s infinite;
		}
		#watch .seconds-hand:after {
		  content:'';
		  width:1.4em;
		  height:1.4em;
		  border-radius:.7em;
		  background:inherit;
		  position:absolute;
		  left:-.65em; bottom:1.35em;
		}
		#watch .seconds-hand:before {
		  content:'';
		  width:.8em;
		  height:3em;
		  border-radius:.2em .2em .4em .4em/.2em .2em 2em 2em;
		  box-shadow:rgba(0,0,0,.8) 0 0 .2em;
		  background:inherit;
		  position:absolute;
		  left:-.35em; bottom:-3em;
		}
		#watch .digital-wrap {
		  width:9em;
		  height:3em;
		  border:.1em solid #222;
		  border-radius:.2em;
		  position:absolute;
		  top:50%; left:50%;
		  margin:3em 0 0 -4.5em;
		  overflow:hidden;
		  background:#4c4c4c;
		  background:-webkit-linear-gradient(top, #4c4c4c 0%,#0f0f0f 100%);
		  background:-moz-linear-gradient(top, #4c4c4c 0%, #0f0f0f 100%);
		  background:-ms-linear-gradient(top, #4c4c4c 0%,#0f0f0f 100%);
		  background:-o-linear-gradient(top, #4c4c4c 0%,#0f0f0f 100%);
		  background:linear-gradient(to bottom, #4c4c4c 0%,#0f0f0f 100%);
		}
		#watch .digital-wrap ul {
		  float:left;
		  width:2.85em;
		  height:3em;
		  border-right:.1em solid #000;
		  color:#ddd;
		  font-family:Consolas, monaco, monospace;
		}
		#watch .digital-wrap ul:last-child { border:none }
		#watch .digital-wrap li {
		  font-size:1.5em;
		  line-height:2;
		  letter-spacing:2px;
		  text-align:center;
		  position:relative;
		  left:1px;
		}
		#watch .digit-minutes li {
		  animation:dsm 3600s steps(60, end) 0s infinite;
		}
		#watch .digit-seconds li {
		  animation:dsm 60s steps(60, end) 0s infinite;
		}
		@keyframes dsm {
		  to { transform:translateY(-120em) }
		}
		</style>
		<body oncontextmenu="return false;" scroll="no">
		<div id="watch" style="margin-top:120px;">
		  <div class="frame-face"></div>
		  <ul class="minute-marks">
		    <li></li><li></li><li></li><li></li><li></li><li></li>
		    <li></li><li></li><li></li><li></li><li></li><li></li>
		    <li></li><li></li><li></li><li></li><li></li><li></li>
		    <li></li><li></li><li></li><li></li><li></li><li></li>
		    <li></li><li></li><li></li><li></li><li></li><li></li>
		    <li></li><li></li><li></li><li></li><li></li><li></li>
		    <li></li><li></li><li></li><li></li><li></li><li></li>
		    <li></li><li></li><li></li><li></li><li></li><li></li>
		  </ul>
		  <div class="digital-wrap">
		    <ul class="digit-hours">
		      <li> <<m.yhour>> </li>
		      <li>00</li><li>01</li><li>02</li><li>03</li><li>04</li><li>05</li>
		      <li>06</li><li>07</li><li>08</li><li>09</li><li>10</li><li>11</li>
		      <li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li>
		      <li>18</li><li>19</li><li>20</li><li>21</li><li>22</li>
		    </ul>
		    <ul class="digit-minutes">
		      <li> <<m.yminute>> </li><li>11</li>
		      <li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li>
		      <li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li>
		      <li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li>
		      <li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li>
		      <li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li>
		      <li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li>
		      <li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li>
		      <li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li>
		      <li>00</li><li>01</li><li>02</li><li>03</li><li>04</li><li>05</li>
		      <li>06</li><li>07</li><li>08</li><li>09</li>
		    </ul>
		    <ul class="digit-seconds">
		      <li><<m.ysecond>></li><li>21</li><li>22</li><li>23</li>
		      <li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li>
		      <li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li>
		      <li>36</li><li>37</li><li>38</li><li>39</li><li>40</li><li>41</li>
		      <li>42</li><li>43</li><li>44</li><li>45</li><li>46</li><li>47</li>
		      <li>48</li><li>49</li><li>50</li><li>51</li><li>52</li><li>53</li>
		      <li>54</li><li>55</li><li>56</li><li>57</li><li>58</li><li>59</li>
		      <li>00</li><li>01</li><li>02</li><li>03</li><li>04</li><li>05</li>
		      <li>06</li><li>07</li><li>08</li><li>09</li><li>10</li><li>11</li>
		      <li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li>
		      <li>18</li><li>19</li>
		    </ul>
		  </div>
		  <ul class="digits">
		    <li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li>
		    <li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li>
		  </ul>
		  <div class="hours-hand"></div>
		  <div class="minutes-hand"></div>
		  <div class="seconds-hand"></div>
		</div>
		</body>
		ENDTEXT

		Local m.lcdest
		m.lcdest=Addbs(Sys(2023))+"ytemp.html"
		Strtofile(m.myvar,m.lcdest)
		Thisform.olecontrol1.Navigate(m.lcdest)
	Endproc

	Procedure Destroy
		Clea Events
	Endproc

	Procedure Resize
		Thisform.ybuild()
	Endproc

	Procedure Load
		Set Safe Off
	Endproc

	Procedure Init
		Thisform.ybuild()
	Endproc

	Procedure olecontrol1.Init
		This.silent=.T.
	Endproc

Enddefine
*
*-- EndDefine: yCssClock


Build your custom canvas clock
Build your custom canvas clock
Build your custom canvas clock

Important:All Codes above are tested on VFP9SP2 & windows 10 pro and IE11 emulation.

To be informed of the latest articles, subscribe:
Comment on this post
M
Dear Yousfi Benameur,<br /> <br /> how to open and control microsoft edge using visual foxpro ?
Reply
Y
*run edge +any URL (dont work for local disc files)<br /> local m.xurl<br /> m.xurl="http://yousfi.over-blog.com/" &&must add http protocole to work !<br /> <br /> &&shellexecute<br /> DECLARE INTEGER ShellExecute IN SHELL32.DLL INTEGER nWinHandle,;<br /> STRING cOperation,;<br /> STRING cFileName,;<br /> STRING cParameters,;<br /> STRING cDirectory,;<br /> INTEGER nShowWindow<br /> result = ShellExecute(0, "open", "explorer.exe ", " microsoft-edge:"+allt(m.xURL),"",1)<br /> retu<br /> <br /> *can read also http://yousfi.over-blog.com/2015/08/a-custom-metro-apps-application-in-systray.html<br /> <br /> <br /> <br />