Clipping polygons paths in html5 canvas

Published on by Yousfi Benameur


*1* This application uses the canvas context clip() function  to build a workshop for any polygon.
I used to make first an inside html buttons on the page.There is some security restrictions for
working from outside the page (vfp),for ex cannot open a new window to save canvas...
Input the spikes number of the polygon(sides).can be from 1 to >10000 and more.
Input the innerRadius fraction  parameter (from 0 to 1 even more, can input until  10)
Input the lineWidth parameter and border color  for the polygon border.

for inputs:type values and click on canvas to see the effect.
Can generate the PNG image or print it (this fi

All is tested on Windows8.1 only

 

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


*1* clipping polygons with html5 canvas
Local m.xpict,m.yhelp,m.myvar
m.xpict=Getpict()  &&only for starting
m.xpict=Strtran(m.xpict,"\","/")
m.yhelp=yhelp()

TEXT to m.myvar textmerge noshow
<body  scroll="no" bgcolor="black" oncontextmenu="window.close();return false;">
<canvas id="ycanvas1" width="<<sysmetric(1)>>" height="<<sysmetric(2)-50>>"></canvas><br>
<center><div>
<input type="text" id ="ospikes" value="7" title="Spikes 0--more 100)" style="width:50;"  onchange="ydraw();">
<input type="text" id ="yr" value="0.5" title="innerRadius 0 to  1 to 10)"  style="width:50;" onchange="ydraw();">
<input type="button" id ="osave" value="save as PNG" style="background-color:lime;color:red;"  onclick="ysave();">
<input type="text" id ="ol" value="5" title="lineWidth 1--20.. )" style="width:50;"  onchange="ydraw();">
<input type="button" id ="ocont" value="Rand Contour" style="background-color:lime;color:red;"  onclick="ydraw();">
<input type="file" id="ximage" accept="image/x-png, image/gif, image/jpeg" value="<<m.xpict>>"  onchange='ydraw();' />
<input type="button" id ="ohelp" value="Help" style="background-color:lime;color:red;"  onclick="yhelp();">
<input type="button" id ="oclose" value="Exit" style="background-color:lime;color:red;"  onclick="window.close();">
</div></center>
<script>
var canvas = document.getElementById("ycanvas1");
canvas.style.background="black";

var ctx = canvas.getContext("2d");
ydraw();
////////////////////////////////////////////////////////
function ydraw(){
ctx.fillStyle="black";
ctx.clearRect(0,0,canvas.width,canvas.height);

var cx=canvas.width/2;
var cy=canvas.height/2;
var spikes=document.getElementById("ospikes").value;    //20;

var outerRadius=300;
var innerRadius=outerRadius*document.getElementById('yr').value;
var col='#'+(0x1000000+(Math.random())*0xffffff).toString(16).substr(1,6);

// Create an image element
var img = document.createElement('IMG');
img.id="img";
 // Specify the src to load the image
img.src =document.getElementById("ximage").value;    //"<<allt(m.xpict)>>";

//////////////////////////////////////////////////////
img.onload = function () {
  // Save the state, so we can undo the clipping
 ctx.save();
drawStar(cx, cy, spikes, outerRadius, innerRadius,col)
ctx.clip();
ctx.drawImage(img, 0, 0,canvas.width,canvas.height);
 // Undo the clipping
   ctx.restore();
}

}
////////////////////////////////////////////////////////
function drawStar(cx, cy, spikes, outerRadius, innerRadius,col) {
    var rot = Math.PI / 2 * 3;
    var x = cx;
    var y = cy;
    var step = Math.PI / spikes;
    ctx.strokeSyle = "#000";
 ctx.save();

    ctx.beginPath();
    ctx.moveTo(cx, cy - outerRadius)
    for (i = 0; i < spikes; i++) {
        x = cx + Math.cos(rot) * outerRadius;
        y = cy + Math.sin(rot) * outerRadius;
        ctx.lineTo(x, y)
        rot += step

        x = cx + Math.cos(rot) * innerRadius;
        y = cy + Math.sin(rot) * innerRadius;
        ctx.lineTo(x, y)
        rot += step
    }
    ctx.lineTo(cx, cy - outerRadius)
    ctx.closePath();
    ctx.lineWidth=document.getElementById("ol").value;
    ctx.strokeStyle=col;
    ctx.stroke();
}
////////////////////////////////////////////////////////////////
function ysave () {
var c=document.getElementById("ycanvas1");
var d=c.toDataURL("image/png");

var w=window.open('about:blank','image from canvas');
w.document.write('<center><h2 style="background-color:yellow";color:maroon;width:500px">Right click on image to save as PNG (or print)</h2></center><br>'+"<img src='"+d+"' alt='from canvas'/>");
  }
//////////////////////////
function yhelp(){
alert(<<m.yhelp>>);
}
</script>
ENDTEXT

Local apie
apie=Newobject("internetexplorer.application")
Set Safe Off
m.lcdest=Addbs(Sys(2023))+"test.html"
Strtofile(m.myvar,m.lcdest)
apie.Navigate(m.lcdest)

Declare Integer BringWindowToTop In user32 Integer


Try
    With apie
		.menubar=0
		.Toolbar=0
		.StatusBar=0
		.fullscreen=1
		BringWindowToTop(.HWnd)
		.Visible=.T.
	Endwith
Catch
Endtry
_Cliptext=m.myvar

Function yhelp()
	TEXT to m.yhelp noshow
Choose an picture(PNG,JPG,Gif) on apie button dialog.	
Input the spikes number of the polygon.can be from 1 to >10000 and more.
Input the innerRadious paramete (from 0 to 1 even more)
Input the lineWidth parameter for the polygon border width.
for inputs:type change value and click on canvas to see the effect.
Can generate the PNG image or print it (this fires a new window.Simply Rightclick to
fire the context menu (save,print).
the canvas is fullscreen and the image is stretched to canvas dimensions.

	ENDTEXT
	x="'*'"
	For i=1 To Memlines(m.yhelp)
		If !i=Memlines(m.yhelp)
			x=x+ '+" '+Mline(m.yhelp,i)+'" +" \n" ' +Chr(13)
		Else
			x=x+'+" +'+Mline(m.yhelp,i)+'" +" \n" ' +Chr(13)
		Endi
	Endfor
	Return m.x
Endfunc


 

Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.
Can geneate an infinite numver of diffrent images with the application.

Can geneate an infinite numver of diffrent images with the application.


This code is similar to the first above but uses a top level form (alwaysOnTop) to set all parameters and interact directly with the canvas through the IE fullscreen window.
the same settings are available and the same results also.
click on the green shape to show the form or collapse it.

 

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

 
 *2*
Publi yform
yform=Newobject("yclip")
yform.Show
Read Events
return
*
Define Class yclip As Form
    BorderStyle = 0
	Top = 0
	Left = 5
	Height = 207
	Width = 193
	ShowWindow = 2
	ShowTips=.T.
	Caption = "yClip"
	MaxButton = .F.
	AlwaysOnTop = .T.
	BackColor = Rgb(112,112,112)
	ycl = 0
	Name = "Form1"

	Add Object command1 As CommandButton With ;
		Top = 163, ;
		Left = 25, ;
		Height = 37, ;
		Width = 97, ;
		FontBold = .T., ;
		FontSize = 11, ;
		Caption = "Draw", ;
		ForeColor = Rgb(0,0,255), ;
		BackColor = Rgb(255,128,0), ;
		Name = "Command1"

	Add Object yhelp As Label With ;
		AutoSize = .T., ;
		FontBold = .T., ;
		FontSize = 16, ;
		BackStyle = 0, ;
		Caption = "?", ;
		Left = 5, ;
		Top = 175, ;
		ForeColor = Rgb(0,255,0), ;
		mousepointer=15,;
		Name = "yhelp"

	Add Object shape1 As Shape With ;
		Top = -1, ;
		Left = 167, ;
		Height = 205, ;
		Width = 25, ;
		BorderStyle = 0, ;
		MousePointer = 15, ;
		BackColor = Rgb(0,255,0), ;
		Name = "Shape1"

	Add Object spinner1 As Spinner With ;
		Height = 25, ;
		KeyboardHighValue = 5000, ;
		KeyboardLowValue = 0, ;
		Left = 82, ;
		SpinnerHighValue = 5000.00, ;
		SpinnerLowValue =   0.00, ;
		Top = 9, ;
		Width = 81, ;
		Value = 5, ;
		Name = "Spinner1"

	Add Object label1 As Label With ;
		AutoSize = .T., ;
		FontBold = .T., ;
		FontSize = 9, ;
		BackStyle = 0, ;
		Caption = "Spikes 0-5000", ;
		Height = 16, ;
		Left = 0, ;
		Top = 12, ;
		Width = 77, ;
		ForeColor = Rgb(255,0,0), ;
		Name = "Label1"

	Add Object spinner2 As Spinner With ;
		Height = 25, ;
		Increment =   0.05, ;
		InputMask = "99.999", ;
		KeyboardHighValue = 10, ;
		KeyboardLowValue = 0, ;
		Left = 82, ;
		SpinnerHighValue =   10.00, ;
		SpinnerLowValue =   0.00, ;
		Top = 50, ;
		Width = 81, ;
		Format = "R", ;
		Value = 0.70, ;
		Name = "Spinner2"

	Add Object label2 As Label With ;
		AutoSize = .T., ;
		FontBold = .T., ;
		FontSize = 9, ;
		BackStyle = 0, ;
		Caption = "InnerRadius", ;
		Height = 16, ;
		Left = 2, ;
		Top = 53, ;
		Width = 68, ;
		ForeColor = Rgb(255,0,0), ;
		Name = "Label2"

	Add Object command2 As CommandButton With ;
		Top = 84, ;
		Left = 12, ;
		Height = 25, ;
		Width = 109, ;
		FontBold = .T., ;
		FontSize = 10, ;
		Caption = "Picture", ;
		MousePointer = 15, ;
		BackColor = Rgb(0,255,0), ;
		Name = "Command2"

	Add Object command3 As CommandButton With ;
		Top = 123, ;
		Left = 1, ;
		Height = 25, ;
		Width = 109, ;
		FontBold = .T., ;
		FontSize = 10, ;
		Caption = "Contour Color", ;
		MousePointer = 15, ;
		BackColor = Rgb(0,255,0), ;
		Name = "Command3"

	Add Object spinner3 As Spinner With ;
		Height = 25, ;
		KeyboardHighValue = 100, ;
		KeyboardLowValue = 1, ;
		Left = 112, ;
		SpinnerHighValue = 100.00, ;
		SpinnerLowValue =   1.00, ;
		Top = 123, ;
		Width = 50, ;
		Value = 5, ;
		tooltiptext="lineWidth",;
		Name = "Spinner3"

	Procedure ybuild
		If !Vartype(apie)="O"
			apie=Newobject("internetexplorer.application")
		Endi

		TEXT to m.myvar textmerge noshow
		<body topmargin=0  leftmargin=0 bgcolor="black" scroll="no"  onContextmenu="return false;" onload="ydraw();" >
		<div>
		<canvas id="ycanvas1" width="<<sysmetric(1)>>" height="<<sysmetric(2)-27>>" </canvas><br>
		</div>
		<center><div>
		<input type="button" id ="osave" value="save as PNG" style="background-color:lime;color:red;"  onclick="ysave();">
		</div></center>
		<script>
		var canvas = document.getElementById("ycanvas1");
		canvas.style.background="black";
		var ctx = canvas.getContext("2d");
		////////////////////////////////////////////////////////
		function ydraw(){
		ctx.fillStyle="black";
		ctx.clearRect(0,0,canvas.width,canvas.height);

		var cx=canvas.width/2;
		var cy=canvas.height/2;
		var spikes=<<_screen.spikes>>

		var outerRadius=300;
		var innerRadius=<<_screen.innerRadius>>*outerRadius;
		var col="<<_screen.col>>";

		// Create an image element
		var img = document.createElement('IMG');
		 // Specify the src to load the image
		img.src ="<<_screen.xpict>>";     //or  "http://.....
		//////////////////////////////////////////////////////
		img.onload = function () {
		  // Save the state, so we can undo the clipping
		 ctx.save();
		drawStar(cx, cy, spikes, outerRadius, innerRadius,col);
		ctx.clip();
		ctx.drawImage(img, 0, 0,canvas.width,canvas.height);
		 // Undo the clipping
		   ctx.restore();
		}

		}
		////////////////////////////////////////////////////////
		function drawStar(cx, cy, spikes, outerRadius, innerRadius,col) {
		    var rot = Math.PI / 2 * 3;
		    var x = cx;
		    var y = cy;
		    var step = Math.PI / spikes;
		    ctx.strokeSyle = "#000";
		 ctx.save();

		    ctx.beginPath();
		    ctx.moveTo(cx, cy - outerRadius)
		    for (i = 0; i < spikes; i++) {
		        x = cx + Math.cos(rot) * outerRadius;
		        y = cy + Math.sin(rot) * outerRadius;
		        ctx.lineTo(x, y)
		        rot += step

		        x = cx + Math.cos(rot) * innerRadius;
		        y = cy + Math.sin(rot) * innerRadius;
		        ctx.lineTo(x, y)
		        rot += step
		    }
		    ctx.lineTo(cx, cy - outerRadius)
		    ctx.closePath();
		    ctx.lineWidth=<<_screen.lineWidth>>
		    ctx.strokeStyle=col;
		    ctx.stroke();
		}
		////////////////////////////////////////////////////////////////
		function ysave () {
		//var c=document.getElementById("ycanvas1");
		var d=canvas.toDataURL("image/png");
		alert(d);

		var w=window.open('about:blank','image from canvas');
		w.document.write("<img src='"+d+"' alt='from canvas'/>");
		//w.document.body.style.background="black";
		  }

		</script>
		ENDTEXT
		Set Safe Off
		m.lcdest=Addbs(Sys(2023))+"test.html"
		Strtofile(m.myvar,m.lcdest)
		apie.Navigate(m.lcdest)

		Declare Integer BringWindowToTop In user32 Integer

		Try
			With apie
				.menubar=0
				.Toolbar=0
				.StatusBar=0
				.fullscreen=1
				BringWindowToTop(.HWnd)
				.Visible=.T.
			Endwith
		Catch
		Endtry
		_Cliptext=m.myvar
	Endproc

	Procedure Destroy
		Try
			apie.Quit
			Release apie
		Catch
		Endtry
	Endproc

	Procedure Init
		With _Screen
			.AddProperty("spikes",5)
			.AddProperty("innerRadius",0.8)
			.AddProperty("xpict","")
			.AddProperty("col","rgb(255,0,0)")
			.AddProperty("lineWidth",5)
		Endwith
		_Screen.xpict=Strtran(_Screen.xpict,"\","/")
		With Thisform
			.MaxButton=.F.
			.MinButton=.F.
		Endwith

		Publi apie
	Endproc

	Procedure command1.Click
		Thisform.shape1.Click()
		Thisform.ybuild()
	Endproc

	Procedure shape1.MouseLeave
		Lparameters nButton, nShift, nXCoord, nYCoord
	Endproc

	Procedure shape1.MouseEnter
		Lparameters nButton, nShift, nXCoord, nYCoord
	Endproc

	Procedure shape1.Click
		Thisform.ycl=Iif(Thisform.ycl=0,1,0)
		If Thisform.ycl=1
			Thisform.Left=-0.9*Thisform.Width
		Else
			Thisform.Left=0
		Endi
		DoEvents
	Endproc

	Procedure spinner1.InteractiveChange
		_Screen.spikes=This.Value
		*	thisform.command1.click
	Endproc

	Procedure spinner2.InteractiveChange
		_Screen.innerRadius=This.Value
		*	thisform.command1.click
	Endproc
	Procedure spinner3.InteractiveChange
		_Screen.lineWidth=This.Value
		*	thisform.command1.click
	Endproc

	Procedure command2.Click
		m.xpict=Getpict()
		_Screen.xpict=Strtran(m.xpict,"\","/")
		Thisform.command1.Click
	Endproc

	Procedure command3.Click
		m.xcolor=Getcol()
		If Empty(m.xcolor)
			m.xcolor=Rgb(255,0,0)
		Endi
		_Screen.Col="#"+Chrtran("123456","563412",Right(Trans[m.xcolor ,"@0" ],6))
		Thisform.command1.Click
	Endproc


	Procedure yhelp.Click
		TEXT to m.myvar noshow
this.code asks to a picture and draw it on canvas.this picture is stretched
to the canvas dimension
it asks for a polygon with parameters as follow:
  -polygon spikes 0-5000 (and more)
  -InnerRadius(outerRadius fraction) from 0-1-i limited to 10
  -contour color
  -contour lineWidth 1-100 and more
 it draws the defined polygon on an internetexplorer.application window
 -can save as (PNG,BMP) the built image.
 -click on the green shape to show the form or collapse it.
		
        ENDTEXT
		Messagebox(m.myvar,0+32+4096,"Summary help")

	Endproc

Enddefine
*
*-- EndDefine: yclip


 

A top level form configures the html5 canvas interactively.
A top level form configures the html5 canvas interactively.
A top level form configures the html5 canvas interactively.
A top level form configures the html5 canvas interactively.

A top level form configures the html5 canvas interactively.

To be informed of the latest articles, subscribe:
Comment on this post