Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Page 1 of 2 12 LastLast
Results 1 to 15 of 17
  1. #1
    New Coder
    Join Date
    Jun 2012
    Posts
    43
    Thanks
    15
    Thanked 0 Times in 0 Posts

    Find point if within circle and within a sector

    I have a pie chart drawn using canvas HTML5. On mousover I would like to show a tooltip telling me the about details of that value in pie chart. The only way I could think of doing this is by finding if mouse over coordinates are in which sector of the circle. Can someone tell me how it can be done. Or do you have any other better approach to this.

  • #2
    Senior Coder
    Join Date
    Jan 2011
    Location
    Missouri
    Posts
    3,761
    Thanks
    23
    Thanked 546 Times in 545 Posts
    I don't mess with the canvas , but can't you get the color the mouse is over?
    Evolution - The non-random survival of random variants.

  • #3
    Senior Coder
    Join Date
    Mar 2005
    Location
    Portsmouth UK
    Posts
    4,466
    Thanks
    3
    Thanked 495 Times in 482 Posts
    if you know the start and stop angles if the segments

    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    
    <head>
      <title></title>
    <style type="text/css">
    /*<![CDATA[*/
    .reddot {
      position:absolute;width:2px;height:2px;background-Color:red;
    }
    
    /*]]>*/
    </style></head>
    
    <body>
    <form name=Show id=Show style="position:absolute;visibility:visible;top:000px;left:0px;" >
    <input size=100 name=Show0 >
    </form>
    
    <script type="text/javascript">
    /*<![CDATA[*/
    // Mouse Degrees. (26-December-2013)
    // by Vic Phillips
    
    
    var zxcMouseDegrees={
    
    
     init:function(o){
      var c=this.coords(o.coords);
      o.c=this.ellipse(c,o.testclass);
      o.x=c[0]-c[2];
      o.rx=c[2];
      o.y=c[1]-c[3];
      o.ry=c[3];
      this.addevt(document,'mousemove','move',o)
     },
    
     move:function(e,o){
      var xy=this.mse(e),x=Math.round(xy[0]-o.x),y=Math.round(xy[1]-o.y);
      if (o.c[x]&&y>=o.c[x][0]&&y<=o.c[x][1]){
       o.degrees(this.degree(o,x,y));
      }
     },
    
     degree:function(o,x,y){
      var a=x-o.rx+0.0001,b=y-o.ry,c=Math.sqrt(a*a+b*b-(2*a*b*Math.cos(90*Math.PI/180)));
      return Math.abs((y>o.ry?0:360)-Math.acos((a*a+c*c-b*b)/(2*a*c))*180/Math.PI);
     },
    
     mse:function(e){
      var ds=!document.body.scrollTop?[document.documentElement.scrollLeft,document.documentElement.scrollTop]:[document.body.scrollLeft,document.body.scrollTop];
      return window.event?[e.clientX+ds[0],e.clientY+ds[1]]:[e.pageX,e.pageY];
     },
    
     coords:function(c){
      var a=typeof(c)=='string'?c.split(','):c,d=[0,0,50],z0=0;
      for (;z0<4;z0++){
       a[z0]=Math.round(isFinite(a[z0]*1)?a[z0]*1:d[z0]);
      }
      a[3]=a[3]||a[2];
      return a;
     },
    
     ellipse:function(a,cls){
      var ca=this.circum(a[0],a[1],a[2],a[3]),d,n,x=[],c=[],z0=1,z1=0,z1a;
      for (;z0<ca.length;z0++){
       if (cls){  // draw ellipse for testing purposes
        d=document.createElement('DIV')
        d.className=cls;
        d.style.left=a[0]-a[2]+ca[z0][0]+'px';
        d.style.top=a[1]-a[3]+ca[z0][1]+'px';
        document.body.appendChild(d);
       }
       n=ca[z0][0];
       x[n]=x[n]||[]; // create an array for each x of y coords
       x[n].push(ca[z0][1]);
      }
      for (;z1<x.length;z1++){   // conver x array to min an max y coords
       c[z1]=[5000,-1000];
       for (z1a=0;z1a<x[z1].length;z1a++){
        c[z1]=[Math.min(x[z1][z1a],c[z1][0]),Math.max(x[z1][z1a],c[z1][1])]
       }
      }
      return c;
     },
    
     circum:function(lft,top,radx,rady){  // produces an array of x/y coordinates of an ellipse.
      var pi=Math.PI/180,xy=[],ca=[],z0=0,z1=1;
      for (;z0<362;z0++){         // an array of basic xy coordinates
       xy.push([Math.floor(radx*Math.cos(z0*pi)+radx),Math.floor(rady*Math.sin((z0)*pi)+rady)]);
      }
      for (;z1<xy.length;z1++){   // add the coords for each missing x coordinate
       ca=ca.concat(this.line([xy[z1-1],xy[z1]]));
      }
      return ca;
     },
    
     line:function(sf){   // produces a line array from a start finish dimentioned array.
      var sf=sf.sort(function(a,b){ return a[0]-b[0]; }),s=sf[0],f=sf[1],w=f[0]-s[0],h=f[1]-s[1],hyp=Math.sqrt(w*w+h*h);
      for (var ary=[],z0=0;z0<hyp;z0++){
       ary[z0]=[Math.round(s[0]+w*z0/hyp),Math.round(s[1]+h*z0/hyp)];
      }
      return ary;
     },
    
    
     addevt:function(o,t,f,p,p1){
      var oop=this;
      o.addEventListener?o.addEventListener(t,function(e){ return oop[f](e,p,p1);},false):o.attachEvent?o.attachEvent('on'+t,function(e){ return oop[f](e,p,p1); }):null;
     }
    
    
    
    
    }
    
    
    zxcMouseDegrees.init({
     coords:[660,260,150,100],  // the ellipse coordinates.                               (array)
                                // field 0 = the left position of the ellipse center. (number, default = 0)
                                // field 1 = the top position of the ellipse center.  (number, default = 0)
                                // field 2 = the radius of the ellipse.               (number, default = 0)
                                // field 3 = the Y radius of the ellipse.             (number, default = field 2)
     degrees:function(d){       // function to return the mouse degrees over the ellipse. (function)
      document.Show.Show0.value=(Math.round(d+90))%360;
    
     },
     testclass:'reddot'        //(optional) the class name to draw the ellipse.           (string, default = no draw)
    })
    
    
    /*]]>*/
    </script>
    </body>
    
    </html>
    Last edited by vwphillips; 12-26-2013 at 02:13 PM. Reason: code cleanup
    Vic

    God Loves You and will never love you less.

    http://www.vicsjavascripts.org/Home.htm

    If my post has been useful please donate to http://www.operationsmile.org.uk/

  • Users who have thanked vwphillips for this post:

    codingrox (12-25-2013)

  • #4
    Senior Coder Arbitrator's Avatar
    Join Date
    Mar 2006
    Location
    Splendora, Texas, United States of America
    Posts
    3,274
    Thanks
    28
    Thanked 271 Times in 265 Posts
    Quote Originally Posted by codingrox View Post
    I have a pie chart drawn using canvas HTML5. On mousover I would like to show a tooltip telling me the about details of that value in pie chart. The only way I could think of doing this is by finding if mouse over coordinates are in which sector of the circle. Can someone tell me how it can be done. Or do you have any other better approach to this.
    I think a better approach would be to use an SVG graphic. Then you can assign mouse events to the pie slices directly rather than generating a coordinate map or creating a bazillion div elements as vwphillip's code does.

    Another upside is that the math is easier. If you create the vector elements in, say, Adobe Illustrator (by exporting to SVG), you don't need to use any math at all and, if you hand-code the graphic, the only math you have to know is in coding the SVG graphic itself. (Hand-coding involves using elliptical arc curve commands which requires that you calculate the pie slice coordinates where they intersect the circle.)

    Here's a live example: https://patrick.dark.name/web.dev/demos/svg.2/

    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <?xml-stylesheet type="application/xml" href="../style.sheets/boilerplate.xslt"?>
    <html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
    	<head>
    		<title>Demo for CodingForums.com Thread 316069: Find point if within circle and within a sector</title>
    		<style>
    			@namespace "http://www.w3.org/1999/xhtml";
    			@namespace g "http://www.w3.org/2000/svg";
    			* { margin: 0; }
    			g|svg { display: block; margin: 1rem auto; }
    			g|circle, g|path { stroke-width: 3; stroke: black; stroke-linejoin: round; }
    			g|circle { fill: hsla(120, 61%, 34%, 1); filter: url("#dropShadow"); }
    			g|circle:hover { fill: hsla(120, 61%, 50%, 1); }
    			g|path { fill: hsla(50, 70%, 50%, 1); }
    			g|path:hover { fill: hsla(50, 86%, 60%, 1); }
    			#tooltip { border: 0.15rem solid black; border-radius: 0.25rem; padding: 0.25rem 0.4rem; background-color: hsla(0, 0%, 95%, 1); color: hsla(0, 0%, 5%, 1); line-height: 1; }
    		</style>
    	</head>
    	<body>
    		<h1 id="demo.title">Demo for CodingForums.com Thread 316069: <cite>Find point if within circle and within a sector</cite></h1>
    		<section id="demo.description">
    			<h1>Demo Description</h1>
    			<p>This demo demonstrates how to use <abbr title="Scalable Vector Graphics">SVG</abbr> to create a pie chart with interactive pie slices.</p>
    		</section>
    		<section id="demo">
    			<h1>Demo</h1>
    			<figure>
    				<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300px" height="300px" viewBox="0,0 300,300">
    					<title>Pie Chart</title>
    					<defs>
    						<filter id="dropShadow">
    							<title>Drop Shadow Filter</title>
    							<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="dropShadow"/>
    							<feMerge>
    								<feMergeNode in="dropShadow"/>
    								<feMergeNode in="SourceGraphic"/>
    							</feMerge>
    						</filter>
    					</defs>
    					<circle id="big.slice" cx="150" cy="150" r="140">
    						<title>Pie Slice Representing 71%</title>
    					</circle>
    					<path id="small.slice" d="M 150,150 h -140 A 140,140 0 0 1 186.235,14.770 z">
    						<!-- Equations for Coordinate Determinations:
    								x = cx + r * cos(θ)
    								y = cy + r * sin(θ)
    						-->
    						<title>Pie Slice Representing 29%</title>
    					</path>
    				</svg>
    				<figcaption>Pie Chart</figcaption>
    			</figure>
    			<script>
    				// <![CDATA[
    				function initializeScript() {
    					var XHTML = "http://www.w3.org/1999/xhtml";
    					var SVG = "http://www.w3.org/2000/svg";
    					var demo = document.getElementById("demo");
    					var bigSlice = document.getElementById("big.slice");
    					var smallSlice = document.getElementById("small.slice");
    					function suppressTitles(title) {
    						// Eliminates tooltips originating from title elements.
    						var suppressedTitle = document.createElementNS("", "title");
    						suppressedTitle.textContent = title.textContent;
    						title.parentNode.replaceChild(suppressedTitle, title);
    					}
    					function restoreTitles(suppressedTitle) {
    						var restoredTitle = document.createElementNS(SVG, "title");
    						restoredTitle.textContent = suppressedTitle.textContent;
    						suppressedTitle.parentNode.replaceChild(restoredTitle, suppressedTitle);
    					}
    					function showTooltip(event) {
    						var tooltip = document.createElementNS(XHTML, "dialog");
    						var paragraph = document.createElementNS(XHTML, "p");
    						var titles = this.ownerSVGElement.getElementsByTagNameNS(SVG, "title");
    						var titleIndex = 0;
    						while (titleIndex < titles.length) {
    							suppressTitles(titles[titleIndex]);
    						}
    						tooltip.setAttributeNS("", "id", "tooltip");
    						tooltip.style.setProperty("position", "absolute");
    						tooltip.style.setProperty("top", (event.clientY + 0).toString() + "px");
    						tooltip.style.setProperty("left", (event.clientX + 15).toString() + "px");
    						paragraph.textContent = this.getElementsByTagNameNS("", "title").item(0).textContent;
    						tooltip.appendChild(paragraph);
    						demo.appendChild(tooltip);
    					}
    					function moveTooltip(event) {
    						var tooltip = document.getElementById("tooltip");
    						tooltip.style.setProperty("top", (event.clientY + 0).toString() + "px");
    						tooltip.style.setProperty("left",(event.clientX + 15).toString() + "px");
    					}
    					function destroyTooltip(event) {
    						var suppressedTitles = this.ownerSVGElement.getElementsByTagNameNS(SVG, "title");
    						var suppressedTitleIndex = 0;
    						while (suppressedTitleIndex < suppressedTitles.length) {
    							restoreTitles(suppressedTitles[suppressedTitleIndex]);
    						}
    						demo.removeChild(document.getElementById("tooltip"));
    					}
    					bigSlice.style.setProperty("cursor", "pointer");
    					smallSlice.style.setProperty("cursor", "pointer");
    					bigSlice.addEventListener("mouseover", showTooltip);
    					bigSlice.addEventListener("mousemove", moveTooltip);
    					bigSlice.addEventListener("mouseout", destroyTooltip);
    					smallSlice.addEventListener("mouseover", showTooltip);
    					smallSlice.addEventListener("mousemove", moveTooltip);
    					smallSlice.addEventListener("mouseout", destroyTooltip);
    				}
    				document.addEventListener("DOMContentLoaded", initializeScript);
    				// ]]>
    			</script>
    		</section>
    	</body>
    </html>
    For every complex problem, there is an answer that is clear, simple, and wrong.

  • #5
    Regular Coder hdewantara's Avatar
    Join Date
    Aug 2009
    Location
    Jakarta, Indonesia.
    Posts
    328
    Thanks
    9
    Thanked 49 Times in 48 Posts
    Or maybe...
    if only that canvas can be converted to traditional image or <img> using canvas.toDataURL(),
    and mapped dynamically via <map> ?
    Last edited by hdewantara; 12-27-2013 at 09:49 AM.

  • #6
    New Coder
    Join Date
    Jun 2012
    Posts
    43
    Thanks
    15
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by vwphillips View Post
    if you know the start and stop angles if the segments

    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    
    <head>
      <title></title>
    <style type="text/css">
    /*<![CDATA[*/
    .reddot {
      position:absolute;width:2px;height:2px;background-Color:red;
    }
    
    /*]]>*/
    </style></head>
    
    <body>
    <form name=Show id=Show style="position:absolute;visibility:visible;top:000px;left:0px;" >
    <input size=100 name=Show0 >
    </form>
    
    <script type="text/javascript">
    /*<![CDATA[*/
    // Mouse Degrees. (26-December-2013)
    // by Vic Phillips
    
    
    var zxcMouseDegrees={
    
    
     init:function(o){
      var c=this.coords(o.coords);
      o.c=this.ellipse(c,o.testclass);
      o.x=c[0]-c[2];
      o.rx=c[2];
      o.y=c[1]-c[3];
      o.ry=c[3];
      this.addevt(document,'mousemove','move',o)
     },
    
     move:function(e,o){
      var xy=this.mse(e),x=Math.round(xy[0]-o.x),y=Math.round(xy[1]-o.y);
      if (o.c[x]&&y>=o.c[x][0]&&y<=o.c[x][1]){
       o.degrees(this.degree(o,x,y));
      }
     },
    
     degree:function(o,x,y){
      var a=x-o.rx+0.0001,b=y-o.ry,c=Math.sqrt(a*a+b*b-(2*a*b*Math.cos(90*Math.PI/180)));
      return Math.abs((y>o.ry?0:360)-Math.acos((a*a+c*c-b*b)/(2*a*c))*180/Math.PI);
     },
    
     mse:function(e){
      var ds=!document.body.scrollTop?[document.documentElement.scrollLeft,document.documentElement.scrollTop]:[document.body.scrollLeft,document.body.scrollTop];
      return window.event?[e.clientX+ds[0],e.clientY+ds[1]]:[e.pageX,e.pageY];
     },
    
     coords:function(c){
      var a=typeof(c)=='string'?c.split(','):c,d=[0,0,50],z0=0;
      for (;z0<4;z0++){
       a[z0]=Math.round(isFinite(a[z0]*1)?a[z0]*1:d[z0]);
      }
      a[3]=a[3]||a[2];
      return a;
     },
    
     ellipse:function(a,cls){
      var ca=this.circum(a[0],a[1],a[2],a[3]),d,n,x=[],c=[],z0=1,z1=0,z1a;
      for (;z0<ca.length;z0++){
       if (cls){  // draw ellipse for testing purposes
        d=document.createElement('DIV')
        d.className=cls;
        d.style.left=a[0]-a[2]+ca[z0][0]+'px';
        d.style.top=a[1]-a[3]+ca[z0][1]+'px';
        document.body.appendChild(d);
       }
       n=ca[z0][0];
       x[n]=x[n]||[]; // create an array for each x of y coords
       x[n].push(ca[z0][1]);
      }
      for (;z1<x.length;z1++){   // conver x array to min an max y coords
       c[z1]=[5000,-1000];
       for (z1a=0;z1a<x[z1].length;z1a++){
        c[z1]=[Math.min(x[z1][z1a],c[z1][0]),Math.max(x[z1][z1a],c[z1][1])]
       }
      }
      return c;
     },
    
     circum:function(lft,top,radx,rady){  // produces an array of x/y coordinates of an ellipse.
      var pi=Math.PI/180,xy=[],ca=[],z0=0,z1=1;
      for (;z0<362;z0++){         // an array of basic xy coordinates
       xy.push([Math.floor(radx*Math.cos(z0*pi)+radx),Math.floor(rady*Math.sin((z0)*pi)+rady)]);
      }
      for (;z1<xy.length;z1++){   // add the coords for each missing x coordinate
       ca=ca.concat(this.line([xy[z1-1],xy[z1]]));
      }
      return ca;
     },
    
     line:function(sf){   // produces a line array from a start finish dimentioned array.
      var sf=sf.sort(function(a,b){ return a[0]-b[0]; }),s=sf[0],f=sf[1],w=f[0]-s[0],h=f[1]-s[1],hyp=Math.sqrt(w*w+h*h);
      for (var ary=[],z0=0;z0<hyp;z0++){
       ary[z0]=[Math.round(s[0]+w*z0/hyp),Math.round(s[1]+h*z0/hyp)];
      }
      return ary;
     },
    
    
     addevt:function(o,t,f,p,p1){
      var oop=this;
      o.addEventListener?o.addEventListener(t,function(e){ return oop[f](e,p,p1);},false):o.attachEvent?o.attachEvent('on'+t,function(e){ return oop[f](e,p,p1); }):null;
     }
    
    
    
    
    }
    
    
    zxcMouseDegrees.init({
     coords:[660,260,150,100],  // the ellipse coordinates.                               (array)
                                // field 0 = the left position of the ellipse center. (number, default = 0)
                                // field 1 = the top position of the ellipse center.  (number, default = 0)
                                // field 2 = the radius of the ellipse.               (number, default = 0)
                                // field 3 = the Y radius of the ellipse.             (number, default = field 2)
     degrees:function(d){       // function to return the mouse degrees over the ellipse. (function)
      document.Show.Show0.value=(Math.round(d+90))%360;
    
     },
     testclass:'reddot'        //(optional) the class name to draw the ellipse.           (string, default = no draw)
    })
    
    
    /*]]>*/
    </script>
    </body>
    
    </html>
    Hello,

    Looking at your code as I understand your code can have only 4 segments in a circle. How can I change your code to have segments based on start and stop angles for each segment. I may have any number of segments from 2 to 10.

  • #7
    New Coder
    Join Date
    Jun 2012
    Posts
    43
    Thanks
    15
    Thanked 0 Times in 0 Posts
    Quote Originally Posted by Arbitrator View Post
    I think a better approach would be to use an SVG graphic. Then you can assign mouse events to the pie slices directly rather than generating a coordinate map or creating a bazillion div elements as vwphillip's code does.

    Another upside is that the math is easier. If you create the vector elements in, say, Adobe Illustrator (by exporting to SVG), you don't need to use any math at all and, if you hand-code the graphic, the only math you have to know is in coding the SVG graphic itself. (Hand-coding involves using elliptical arc curve commands which requires that you calculate the pie slice coordinates where they intersect the circle.)

    Here's a live example: https://patrick.dark.name/web.dev/demos/svg.2/

    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <?xml-stylesheet type="application/xml" href="../style.sheets/boilerplate.xslt"?>
    <html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
    	<head>
    		<title>Demo for CodingForums.com Thread 316069: Find point if within circle and within a sector</title>
    		<style>
    			@namespace "http://www.w3.org/1999/xhtml";
    			@namespace g "http://www.w3.org/2000/svg";
    			* { margin: 0; }
    			g|svg { display: block; margin: 1rem auto; }
    			g|circle, g|path { stroke-width: 3; stroke: black; stroke-linejoin: round; }
    			g|circle { fill: hsla(120, 61%, 34%, 1); filter: url("#dropShadow"); }
    			g|circle:hover { fill: hsla(120, 61%, 50%, 1); }
    			g|path { fill: hsla(50, 70%, 50%, 1); }
    			g|path:hover { fill: hsla(50, 86%, 60%, 1); }
    			#tooltip { border: 0.15rem solid black; border-radius: 0.25rem; padding: 0.25rem 0.4rem; background-color: hsla(0, 0%, 95%, 1); color: hsla(0, 0%, 5%, 1); line-height: 1; }
    		</style>
    	</head>
    	<body>
    		<h1 id="demo.title">Demo for CodingForums.com Thread 316069: <cite>Find point if within circle and within a sector</cite></h1>
    		<section id="demo.description">
    			<h1>Demo Description</h1>
    			<p>This demo demonstrates how to use <abbr title="Scalable Vector Graphics">SVG</abbr> to create a pie chart with interactive pie slices.</p>
    		</section>
    		<section id="demo">
    			<h1>Demo</h1>
    			<figure>
    				<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300px" height="300px" viewBox="0,0 300,300">
    					<title>Pie Chart</title>
    					<defs>
    						<filter id="dropShadow">
    							<title>Drop Shadow Filter</title>
    							<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="dropShadow"/>
    							<feMerge>
    								<feMergeNode in="dropShadow"/>
    								<feMergeNode in="SourceGraphic"/>
    							</feMerge>
    						</filter>
    					</defs>
    					<circle id="big.slice" cx="150" cy="150" r="140">
    						<title>Pie Slice Representing 71%</title>
    					</circle>
    					<path id="small.slice" d="M 150,150 h -140 A 140,140 0 0 1 186.235,14.770 z">
    						<!-- Equations for Coordinate Determinations:
    								x = cx + r * cos(θ)
    								y = cy + r * sin(θ)
    						-->
    						<title>Pie Slice Representing 29%</title>
    					</path>
    				</svg>
    				<figcaption>Pie Chart</figcaption>
    			</figure>
    			<script>
    				// <![CDATA[
    				function initializeScript() {
    					var XHTML = "http://www.w3.org/1999/xhtml";
    					var SVG = "http://www.w3.org/2000/svg";
    					var demo = document.getElementById("demo");
    					var bigSlice = document.getElementById("big.slice");
    					var smallSlice = document.getElementById("small.slice");
    					function suppressTitles(title) {
    						// Eliminates tooltips originating from title elements.
    						var suppressedTitle = document.createElementNS("", "title");
    						suppressedTitle.textContent = title.textContent;
    						title.parentNode.replaceChild(suppressedTitle, title);
    					}
    					function restoreTitles(suppressedTitle) {
    						var restoredTitle = document.createElementNS(SVG, "title");
    						restoredTitle.textContent = suppressedTitle.textContent;
    						suppressedTitle.parentNode.replaceChild(restoredTitle, suppressedTitle);
    					}
    					function showTooltip(event) {
    						var tooltip = document.createElementNS(XHTML, "dialog");
    						var paragraph = document.createElementNS(XHTML, "p");
    						var titles = this.ownerSVGElement.getElementsByTagNameNS(SVG, "title");
    						var titleIndex = 0;
    						while (titleIndex < titles.length) {
    							suppressTitles(titles[titleIndex]);
    						}
    						tooltip.setAttributeNS("", "id", "tooltip");
    						tooltip.style.setProperty("position", "absolute");
    						tooltip.style.setProperty("top", (event.clientY + 0).toString() + "px");
    						tooltip.style.setProperty("left", (event.clientX + 15).toString() + "px");
    						paragraph.textContent = this.getElementsByTagNameNS("", "title").item(0).textContent;
    						tooltip.appendChild(paragraph);
    						demo.appendChild(tooltip);
    					}
    					function moveTooltip(event) {
    						var tooltip = document.getElementById("tooltip");
    						tooltip.style.setProperty("top", (event.clientY + 0).toString() + "px");
    						tooltip.style.setProperty("left",(event.clientX + 15).toString() + "px");
    					}
    					function destroyTooltip(event) {
    						var suppressedTitles = this.ownerSVGElement.getElementsByTagNameNS(SVG, "title");
    						var suppressedTitleIndex = 0;
    						while (suppressedTitleIndex < suppressedTitles.length) {
    							restoreTitles(suppressedTitles[suppressedTitleIndex]);
    						}
    						demo.removeChild(document.getElementById("tooltip"));
    					}
    					bigSlice.style.setProperty("cursor", "pointer");
    					smallSlice.style.setProperty("cursor", "pointer");
    					bigSlice.addEventListener("mouseover", showTooltip);
    					bigSlice.addEventListener("mousemove", moveTooltip);
    					bigSlice.addEventListener("mouseout", destroyTooltip);
    					smallSlice.addEventListener("mouseover", showTooltip);
    					smallSlice.addEventListener("mousemove", moveTooltip);
    					smallSlice.addEventListener("mouseout", destroyTooltip);
    				}
    				document.addEventListener("DOMContentLoaded", initializeScript);
    				// ]]>
    			</script>
    		</section>
    	</body>
    </html>
    Thanks for this. I want to have my graph PIE using Canvas only.

  • #8
    Senior Coder
    Join Date
    Sep 2010
    Posts
    1,899
    Thanks
    15
    Thanked 226 Times in 226 Posts
    Here's several things you can do. One is, if you open the canvas page with Firefox you can right click on the image and save it as a .png file. Just that simple. You can use that .png or maybe even the canvas with an old fashioned but still workable HTML map. This may be simpler to code than the other alternatives.
    Welcome to http://www.myphotowizard.net

    where you can edit images, make a photo calendar, add text to images, and do much more.


    When you know what you're doing it's called Engineering, when you don't know, it's called Research and Development. And you can always charge more for Research and Development.

  • #9
    Regular Coder hdewantara's Avatar
    Join Date
    Aug 2009
    Location
    Jakarta, Indonesia.
    Posts
    328
    Thanks
    9
    Thanked 49 Times in 48 Posts
    Well,

    This is probably the 3rd method, after vwphillips's and Arbitrator's:
    http://oldhendra.byethost8.com/tests...and-image-map/

    I know this is late, but Happy New Year to all...

    Hendra

  • The Following 2 Users Say Thank You to hdewantara For This Useful Post:

    Arbitrator (01-02-2014), codingrox (01-02-2014)

  • #10
    Senior Coder Arbitrator's Avatar
    Join Date
    Mar 2006
    Location
    Splendora, Texas, United States of America
    Posts
    3,274
    Thanks
    28
    Thanked 271 Times in 265 Posts
    Quote Originally Posted by hdewantara View Post
    This is probably the 3rd method, after vwphillips's and Arbitrator's:
    http://oldhendra.byethost8.com/tests...and-image-map/
    Your demo renders okay as currently constituted, but as soon as the pie slices add up to 100%, the output becomes quite ugly.

    Quote Originally Posted by hdewantara View Post
    I know this is late, but Happy New Year to all...
    Happy New Year.
    For every complex problem, there is an answer that is clear, simple, and wrong.

  • The Following 2 Users Say Thank You to Arbitrator For This Useful Post:

    codingrox (01-02-2014), hdewantara (01-02-2014)

  • #11
    Regular Coder hdewantara's Avatar
    Join Date
    Aug 2009
    Location
    Jakarta, Indonesia.
    Posts
    328
    Thanks
    9
    Thanked 49 Times in 48 Posts
    @Arbitrator:
    Thanks for the feedback.

    It's an implementation of an approach I posted (post #5). No it's not the perfect one; probably because I didn't make it so. But maybe the OP (codingrox) can, and is kind enough to share his/ hers

  • #12
    Senior Coder
    Join Date
    Mar 2005
    Location
    Portsmouth UK
    Posts
    4,466
    Thanks
    3
    Thanked 495 Times in 482 Posts
    Looking at your code as I understand your code can have only 4 segments in a circle. How can I change your code to have segments based on start and stop angles for each segment. I may have any number of segments from 2 to 10.
    the current output is between 0 and 360 degrees

    so there can be as many segments as required totaling 360 degrees

    example with 5 segments

    Code:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    
    <head>
      <title></title>
    <style type="text/css">
    /*<![CDATA[*/
    .reddot {
      position:absolute;width:2px;height:2px;background-Color:red;
    }
    
    /*]]>*/
    </style></head>
    
    <body>
    <form name=Show id=Show style="position:absolute;visibility:visible;top:000px;left:0px;" >
    <input size=100 name=Show0 >
    </form>
    
    <script type="text/javascript">
    /*<![CDATA[*/
    // Mouse Degrees. (26-December-2013)
    // by Vic Phillips
    
    
    var zxcMouseDegrees={
    
    
     init:function(o){
      var c=this.coords(o.coords);
      o.c=this.ellipse(c,o.testclass);
      o.x=c[0]-c[2];
      o.rx=c[2];
      o.y=c[1]-c[3];
      o.ry=c[3];
      this.addevt(document,'mousemove','move',o)
     },
    
     move:function(e,o){
      var xy=this.mse(e),x=Math.round(xy[0]-o.x),y=Math.round(xy[1]-o.y);
      if (o.c[x]&&y>=o.c[x][0]&&y<=o.c[x][1]){
       o.degrees(this.degree(o,x,y));
      }
     },
    
     degree:function(o,x,y){
      var a=x-o.rx+0.0001,b=y-o.ry,c=Math.sqrt(a*a+b*b-(2*a*b*Math.cos(90*Math.PI/180)));
      return Math.abs((y>o.ry?0:360)-Math.acos((a*a+c*c-b*b)/(2*a*c))*180/Math.PI);
     },
    
     mse:function(e){
      var ds=!document.body.scrollTop?[document.documentElement.scrollLeft,document.documentElement.scrollTop]:[document.body.scrollLeft,document.body.scrollTop];
      return window.event?[e.clientX+ds[0],e.clientY+ds[1]]:[e.pageX,e.pageY];
     },
    
     coords:function(c){
      var a=typeof(c)=='string'?c.split(','):c,d=[0,0,50],z0=0;
      for (;z0<4;z0++){
       a[z0]=Math.round(isFinite(a[z0]*1)?a[z0]*1:d[z0]);
      }
      a[3]=a[3]||a[2];
      return a;
     },
    
     ellipse:function(a,cls){
      var ca=this.circum(a[0],a[1],a[2],a[3]),d,n,x=[],c=[],z0=1,z1=0,z1a;
      for (;z0<ca.length;z0++){
       if (cls){  // draw ellipse for testing purposes
        d=document.createElement('DIV')
        d.className=cls;
        d.style.left=a[0]-a[2]+ca[z0][0]+'px';
        d.style.top=a[1]-a[3]+ca[z0][1]+'px';
        document.body.appendChild(d);
       }
       n=ca[z0][0];
       x[n]=x[n]||[]; // create an array for each x of y coords
       x[n].push(ca[z0][1]);
      }
      for (;z1<x.length;z1++){   // conver x array to min an max y coords
       c[z1]=[5000,-1000];
       for (z1a=0;z1a<x[z1].length;z1a++){
        c[z1]=[Math.min(x[z1][z1a],c[z1][0]),Math.max(x[z1][z1a],c[z1][1])]
       }
      }
      return c;
     },
    
     circum:function(lft,top,radx,rady){  // produces an array of x/y coordinates of an ellipse.
      var pi=Math.PI/180,xy=[],ca=[],z0=0,z1=1;
      for (;z0<362;z0++){         // an array of basic xy coordinates
       xy.push([Math.floor(radx*Math.cos(z0*pi)+radx),Math.floor(rady*Math.sin((z0)*pi)+rady)]);
      }
      for (;z1<xy.length;z1++){   // add the coords for each missing x coordinate
       ca=ca.concat(this.line([xy[z1-1],xy[z1]]));
      }
      return ca;
     },
    
     line:function(sf){   // produces a line array from a start finish dimentioned array.
      var sf=sf.sort(function(a,b){ return a[0]-b[0]; }),s=sf[0],f=sf[1],w=f[0]-s[0],h=f[1]-s[1],hyp=Math.sqrt(w*w+h*h);
      for (var ary=[],z0=0;z0<hyp;z0++){
       ary[z0]=[Math.round(s[0]+w*z0/hyp),Math.round(s[1]+h*z0/hyp)];
      }
      return ary;
     },
    
    
     addevt:function(o,t,f,p,p1){
      var oop=this;
      o.addEventListener?o.addEventListener(t,function(e){ return oop[f](e,p,p1);},false):o.attachEvent?o.attachEvent('on'+t,function(e){ return oop[f](e,p,p1); }):null;
     }
    
    
    
    
    }
    
    
    zxcMouseDegrees.init({
     coords:[660,260,150,100],  // the ellipse coordinates.                               (array)
                                // field 0 = the left position of the ellipse center. (number, default = 0)
                                // field 1 = the top position of the ellipse center.  (number, default = 0)
                                // field 2 = the radius of the ellipse.               (number, default = 0)
                                // field 3 = the Y radius of the ellipse.             (number, default = field 2)
     degrees:function(d){       // function to return the mouse degrees over the ellipse. (function)
       var a=(Math.round(d+90))%360;
       if (a>10&&a<50){
    document.Show.Show0.value='segment 1';
       }
       else if (a>50&&a<150){
    document.Show.Show0.value='segment 2';
       }
        else if (a>150&&a<250){
    document.Show.Show0.value='segment 3';
       }
       else if (a>250&&a<310){
    document.Show.Show0.value='segment 4';
       }
       else{
    document.Show.Show0.value='segment 5';
       }
    },
     testclass:'reddot'        //(optional) the class name to draw the ellipse.           (string, default = no draw)
    })
    
    
    /*]]>*/
    </script>
    </body>
    
    </html>
    Vic

    God Loves You and will never love you less.

    http://www.vicsjavascripts.org/Home.htm

    If my post has been useful please donate to http://www.operationsmile.org.uk/

  • #13
    Senior Coder
    Join Date
    Jan 2011
    Location
    Missouri
    Posts
    3,761
    Thanks
    23
    Thanked 546 Times in 545 Posts
    I thought my answer at post 2 was a simple solution, but it has been slided over. So let me expand it in the face of all the higher mathematical solutions.

    I have never seen a pie chart that does not use color to help define the segments. If you have more then 8 segments you need to use a different type of chart.

    If you agree then things are easy, you can get the color the mouse is over and therefore know the segment. Here's a fiddle from http://stackoverflow.com with the solution: http://jsfiddle.net/DV9Bw/1/
    Evolution - The non-random survival of random variants.

  • Users who have thanked sunfighter for this post:

    Arbitrator (01-02-2014)

  • #14
    Senior Coder Arbitrator's Avatar
    Join Date
    Mar 2006
    Location
    Splendora, Texas, United States of America
    Posts
    3,274
    Thanks
    28
    Thanked 271 Times in 265 Posts
    Quote Originally Posted by hdewantara View Post
    It's an implementation of an approach I posted (post #5). No it's not the perfect one; probably because I didn't make it so. But maybe the OP (codingrox) can, and is kind enough to share his/ hers
    I decided to use this approach of creating polygon hit regions with lots of points to write another, canvas element-based version of my SVG demos:

    https://patrick.dark.name/web.dev/demos/canvas.1/ (code at end)

    It was a ridiculously difficult process compared to SVG, but I finally managed to duplicate everything except the drop shadow. I'll try to do that later. Apparently, there's a relatively new hit region API for canvas defined in the HTML5 spec that would make this process easier; I had been wondering why canvas elements lacked a usemap attribute. I don't know that any browser vendor has implemented the API though.

    I also updated the SVG demo to be more complex and fixed an issue or two. Then I made a second one that dynamically generates the pie slices rather than requiring calculations by hand:

    https://patrick.dark.name/web.dev/demos/svg.2a/
    https://patrick.dark.name/web.dev/demos/svg.2b/

    All three demos should look and behave identically sans the drop shadow.

    Code:
    <?xml version="1.0" encoding="utf-8"?>
    <?xml-stylesheet type="application/xml" href="../style.sheets/boilerplate.xslt"?>
    <html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:x="http://www.w3.org/1999/xhtml">
    	<head>
    		<title>Demo C for CodingForums.com Thread 316069: Find point if within circle and within a sector</title>
    		<meta itemprop="see_also" content="../svg.2a/"/>
    		<meta itemprop="see_also" content="../svg.2b/"/>
    	</head>
    	<body>
    		<h1 id="demo.title">Demo C for CodingForums.com Thread 316069: <cite>Find point if within circle and within a sector</cite></h1>
    		<section id="demo.description">
    			<h1>Demo Description</h1>
    			<p>This demo demonstrates how to use the <code>canvas</code> element to create a pie chart with dynamically‐positioned, interactive pie slices that generate a tooltip when hovered over with the cursor.</p>
    			<p>The demo functions by use of six overlapping <code>canvas</code> elements: one for the complete pie chart, one each for each pie slice, and one for strokes. These additional layers are needed because of the destructive nature of <code>canvas</code> drawing. An image map is then overlaid onto all of these elements to capture mouse events.</p>
    			<p>A data‐equivalent table is nested within the <code>canvas</code> element for semantic value. (The table can be viewed by disabling JavaScript.)</p>
    			<p class="version.info">There are three versions of this demo. This version, C, uses the <code>canvas</code> element whereas the other two versions, <a href="../svg.2a/">version A</a> and <a href="../svg.2b/">version B</a>, were written using a more appropriate technology, <abbr title="Scalable Vector Graphics">SVG</abbr>, and are significantly less complex.</p>
    		</section>
    		<section id="demo">
    			<style scoped="">
    				@namespace "http://www.w3.org/1999/xhtml";
    				#marbles\.figure { position: relative; }
    				.slice\.overlay, #marbles\.stroke\.overlay, #hit\.area\.overlay { position: absolute; }
    				.slice\.overlay { visibility: hidden; }
    				#marbles\.stroke\.overlay { z-index: 1; }
    				#hit\.area\.overlay, #tooltip { z-index: 2; }
    				#tooltip { border: 0.15rem solid hsla(0, 0%, 0%, 1); /* black */; border-radius: 0.25rem; padding: 0.25rem 0.4rem; background-color: hsla(0, 0%, 95%, 1); /* off‐white */ color: hsla(0, 0%, 5%, 1); /* off‐black */ line-height: 1; }
    			</style>
    			<h1>Demo</h1>
    			<figure id="marbles.figure">
    				<canvas id="marbles.pie.chart" width="300" height="300">
    					<table id="marbles.table">
    						<style scoped="">
    								@namespace "http://www.w3.org/1999/xhtml";
    								th, td { border: 0 none currentcolor; color: white; }
    								thead th { background-color: hsla(0, 0%, 35%, 1); /* medium‐dark gray */ }
    								tr.blue > * { background-color: hsla(210, 70%, 35%, 1); /* blue */ }
    								tr.blue:hover > * { background-color: hsla(210, 86%, 45%, 1); /* lighter blue */ }
    								tr.green > * { background-color: hsla(120, 70%, 35%, 1); /* green */ }
    								tr.green:hover > * { background-color: hsla(120, 86%, 45%, 1); /* lighter green */ }
    								tr.pink > * { background-color: hsla(340, 70%, 35%, 1); /* pink */ }
    								tr.pink:hover > * { background-color: hsla(340, 86%, 45%, 1); /* lighter pink */ }
    								tr.yellow > * { background-color: hsla(50, 70%, 35%, 1); /* yellow */ }
    								tr.yellow:hover > * { background-color: hsla(50, 86%, 45%, 1); /* lighter yellow */ }
    							</style>
    						<caption class="redundant">Marbles by Color</caption>
    						<thead>
    							<tr>
    								<th>Color</th>
    								<th>Percentage</th>
    							</tr>
    						</thead>
    						<tbody>
    							<tr class="blue">
    								<th>Blue</th>
    								<td class="number">14</td>
    							</tr>
    							<tr class="green">
    								<th>Green</th>
    								<td class="number">43</td>
    							</tr>
    							<tr class="pink">
    								<th>Pink</th>
    								<td class="number">4</td>
    							</tr>
    							<tr class="yellow">
    								<th>Yellow</th>
    								<td class="number">39</td>
    							</tr>
    						</tbody>
    					</table>
    				</canvas>
    				<figcaption>Marbles by Color</figcaption>
    			</figure>
    			<script>
    				// <![CDATA[
    				// This script was validated at http://jshint.com/ using the following settings:
    				/* jshint browser: true, curly: true, eqeqeq: true, devel: false, forin: true, immed: true, latedef: true, newcap: false, noarg: true, noempty: true, nonew: true, plusplus: true, quotmark: double, undef: true, unused: strict, strict: true, trailing: true */
    				function createInteractivePieChart() {
    					var XHTML = "http://www.w3.org/1999/xhtml";
    					var fullCircle = 2 * Math.PI;
    					var demo = document.getElementById("demo");
    					var figure = document.getElementById("marbles.figure");
    					var pieChart = document.getElementById("marbles.pie.chart");
    					var pie = pieChart.getContext("2d");
    					var pieOffset = 10;
    					var pieCenterX = 150;
    					var pieCenterY = 150;
    					var pieCenterCoords = pieCenterX.toString() + "," + pieCenterY.toString();
    					var pieRadius = 140;
    					var sliceData = [
    						{
    							percentage: 0.04,
    							fill: "hsla(340, 70%, 45%, 1)", // pink
    							hoverFill: "hsla(340, 86%, 60%, 1)", // lighter pink
    							tooltipHeading: "Pie Slice Representing Pink Marbles",
    							tooltipInfo: {
    								dataText: "Four percent",
    								dataTextValue: 0.04,
    								genericText: " of marbles are pink."
    							}
    						},
    						{
    							percentage: 0.14,
    							fill: "hsla(210, 70%, 45%, 1)", // blue
    							hoverFill: "hsla(210, 86%, 60%, 1)", // lighter blue
    							tooltipHeading: "Pie Slice Representing Blue Marbles",
    							tooltipInfo: {
    								dataText: "14 percent",
    								dataTextValue: 0.14,
    								genericText: " of marbles are blue."
    							}
    						},
    						{
    							percentage: 0.39,
    							fill: "hsla(50, 70%, 45%, 1)", // yellow
    							hoverFill: "hsla(50, 86%, 60%, 1)", // lighter yellow
    							tooltipHeading: "Pie Slice Representing Yellow Marbles",
    							tooltipInfo: {
    								dataText: "39 percent",
    								dataTextValue: 0.39,
    								genericText: " of marbles are yellow."
    							}
    						},
    						{
    							percentage: 0.43,
    							fill: "hsla(120, 70%, 45%, 1)", // green
    							hoverFill: "hsla(120, 86%, 60%, 1)", // lighter green
    							tooltipHeading: "Pie Slice Representing Green Marbles",
    							tooltipInfo: {
    								dataText: "43 percent",
    								dataTextValue: 0.43,
    								genericText: " of marbles are green."
    							} 
    						}
    					];
    					var sliceDatumIndex = 0;
    					var sliceDatum = null;
    					var sliceStartPercentage = 0.75;
    					var sliceEndPercentage = null;
    					var overlayPositioningXOffset = pieChart.getBoundingClientRect().left - figure.getBoundingClientRect().left;
    					var overlayPositioningYOffset = pieChart.getBoundingClientRect().top - figure.getBoundingClientRect().top;
    					var sliceOverlayReference = document.createElementNS(XHTML, "canvas");
    					var sliceOverlay = null;
    					var slice = null;
    					var strokeOverlay = document.createElementNS(XHTML, "canvas");
    					var strokes = strokeOverlay.getContext("2d");
    					var hitAreaImageOverlay = document.createElementNS(XHTML, "img");
    					var hitAreaMap = document.createElementNS(XHTML, "map");
    					var hitAreaReference = document.createElementNS(XHTML, "area");
    					var hitArea = null;
    					var hitAreaCoords = null;
    					function getCircleIntersectionXCoord(percentage) {
    						// Equation for X‐Coordinate Determination:
    						//     percentage = percentage + (sum of previous percentages)
    						//     angle in radians = percentage * 2π rad
    						//     x = radius * cos(angle) + center‐x + (x‐offset of pie edge from canvas origin)
    						var xCoord = (pieRadius * Math.cos(percentage * fullCircle) + pieRadius + pieOffset);
    						return xCoord;
    					}
    					function getCircleIntersectionYCoord(percentage) {
    						// Equation for Y‐Coordinate Determination:
    						//     percentage = percentage + (sum of previous percentages)
    						//     angle in radians = percentage * 2π rad
    						//     y = radius * sin(angle) + center‐y + (y‐offset of pie edge from canvas origin)
    						var yCoord = (pieRadius * Math.sin(percentage * fullCircle) + pieRadius + pieOffset);
    						return yCoord;
    					}
    					function getCircleIntersectionCoords(percentage) {
    						var xCoord = getCircleIntersectionXCoord(percentage).toFixed(3);
    						var yCoord = getCircleIntersectionYCoord(percentage).toFixed(3);
    						return (xCoord + "," + yCoord);
    					}
    					function getHitAreaCoords(startPercentage, endPercentage) {
    						var hitAreaCoords = pieCenterCoords;
    						var percentageIncrement = 0.005;
    						while (startPercentage < endPercentage) {
    							hitAreaCoords += " " + getCircleIntersectionCoords(startPercentage);
    							startPercentage += percentageIncrement;
    						}
    						hitAreaCoords += " " + getCircleIntersectionCoords(endPercentage);
    						return hitAreaCoords;
    					}
    					function drawSlice(context) {
    						context.beginPath();
    						context.moveTo(pieCenterX, pieCenterY);
    						context.lineTo(getCircleIntersectionXCoord(sliceStartPercentage), getCircleIntersectionYCoord(sliceStartPercentage));
    						context.arc(pieCenterX, pieCenterY, pieRadius, sliceStartPercentage * fullCircle, sliceEndPercentage * fullCircle);
    						context.closePath();
    					}
    					function createOverlay(overlay, identifyingAttributeName, identifyingAttributeValue) {
    						overlay.setAttributeNS("", identifyingAttributeName, identifyingAttributeValue); 
    						overlay.setAttributeNS("", "width", pieChart.getAttributeNS("", "width"));
    						overlay.setAttributeNS("", "height", pieChart.getAttributeNS("", "height"));
    						overlay.style.setProperty("top", overlayPositioningYOffset.toString() + "px");
    						overlay.style.setProperty("left", overlayPositioningXOffset.toString() + "px");
    					}
    					function insertOverlay(overlay) {
    						if (figure.lastElementChild.nodeName === "figcaption") {
    							figure.insertBefore(overlay, figure.lastElementChild);
    						}
    						else {
    							figure.appendChild(overlay);
    						}
    					}
    					function applyHoverEffects(sliceDatum, event) {
    						var tooltip = document.createElementNS(XHTML, "dialog");
    						var tooltipHeading = document.createElementNS(XHTML, "h1");
    						var tooltipInfo = document.createElementNS(XHTML, "p");
    						var tooltipDataText = document.createElementNS(XHTML, "data");
    						this.style.setProperty("visibility", "visible");
    						tooltip.setAttributeNS("", "id", "tooltip");
    						tooltipDataText.setAttribute("value", sliceDatum.tooltipInfo.dataTextValue);
    						tooltip.style.setProperty("position", "absolute");
    						tooltip.style.setProperty("top", event.clientY.toString() + "px");
    						tooltip.style.setProperty("left", (event.clientX + 15).toString() + "px");
    						tooltipHeading.textContent = sliceDatum.tooltipHeading;
    						tooltipDataText.textContent = sliceDatum.tooltipInfo.dataText;
    						tooltipInfo.appendChild(tooltipDataText);
    						tooltipInfo.appendChild(document.createTextNode(sliceDatum.tooltipInfo.genericText));
    						tooltip.appendChild(tooltipHeading);
    						tooltip.appendChild(tooltipInfo);
    						demo.appendChild(tooltip);
    					}
    					function moveTooltip(event) {
    						var tooltip = document.getElementById("tooltip");
    						tooltip.style.setProperty("top", event.clientY.toString() + "px");
    						tooltip.style.setProperty("left",(event.clientX + 15).toString() + "px");
    					}
    					function removeHoverEffects() {
    						this.style.removeProperty("visibility");
    						demo.removeChild(document.getElementById("tooltip"));
    					}
    					createOverlay(sliceOverlayReference, "class", "slice.overlay");
    					createOverlay(strokeOverlay, "id", "marbles.stroke.overlay");
    					createOverlay(hitAreaImageOverlay, "id", "hit.area.overlay");
    					hitAreaImageOverlay.setAttributeNS("", "usemap", "#hit.area.map");
    					hitAreaImageOverlay.setAttributeNS("", "src", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQYV2NgYAAAAAMAAWgmWQ0AAAAASUVORK5CYII="); // 1 Transparent PNG
    					hitAreaMap.setAttributeNS("", "name", "hit.area.map");
    					hitAreaReference.setAttributeNS("", "shape", "polygon");
    					strokes.lineWidth = 3;
    					strokes.lineJoin = "round";
    					while (sliceDatumIndex < sliceData.length) {
    						sliceDatum = sliceData[sliceDatumIndex];
    						sliceEndPercentage = sliceStartPercentage + sliceDatum.percentage;
    						// Draw visible slice.
    						drawSlice(pie);
    						pie.fillStyle = sliceDatum.fill;
    						pie.fill();
    						// Draw slice overlay (for hover effects).
    						sliceOverlay = sliceOverlayReference.cloneNode();
    						sliceOverlay.setAttributeNS("", "class", sliceOverlay.getAttributeNS("", "class") + " slice." + sliceDatumIndex.toString());
    						slice = sliceOverlay.getContext("2d");
    						drawSlice(slice);
    						slice.fillStyle = sliceDatum.hoverFill;
    						slice.fill();
    						insertOverlay(sliceOverlay);
    						// Draw stroke overlay.
    						drawSlice(strokes);
    						strokes.stroke();
    						// Draw slice hit area.
    						hitArea = hitAreaReference.cloneNode();
    						hitArea.setAttributeNS("", "coords", getHitAreaCoords(sliceStartPercentage, sliceEndPercentage));
    						hitArea.addEventListener("mouseover", applyHoverEffects.bind(sliceOverlay, sliceDatum));
    						hitArea.addEventListener("mousemove", moveTooltip);
    						hitArea.addEventListener("mouseout", removeHoverEffects.bind(sliceOverlay));
    						hitAreaMap.appendChild(hitArea);
    						sliceStartPercentage = sliceEndPercentage;
    						sliceDatumIndex += 1;
    					}
    					insertOverlay(strokeOverlay);
    					insertOverlay(hitAreaImageOverlay);
    					insertOverlay(hitAreaMap);
    					document.getElementById("marbles.figure").getElementsByTagNameNS(XHTML, "figcaption").item(0).textContent = "Pie Chart Representing Marbles by Color";
    				}
    				document.addEventListener("DOMContentLoaded", createInteractivePieChart);
    				// ]]>
    			</script>
    		</section>
    	</body>
    </html>
    Last edited by Arbitrator; 01-03-2014 at 08:09 PM. Reason: I fixed the URLs including "localhost" as the address.
    For every complex problem, there is an answer that is clear, simple, and wrong.

  • #15
    Regular Coder
    Join Date
    May 2012
    Location
    France
    Posts
    216
    Thanks
    0
    Thanked 29 Times in 27 Posts
    An ellipse is also the result of projecting a circle (C) in three dimensions onto a plane...
    Then an arc of it can be drawn (stoke or fill) like this with a canvas function (ctx for context) :

    Code:
    function drawEllipseFrmTo(x, y, a, b, rw, rh, ngl, clr){
    	ctx.save();ctx.translate(x,y);ctx.rotate(ngl);ctx.scale(1,rh/rw);
    	ctx.beginPath();ctx.arc(0,0,rw,a,b,false);ctx.restore();
    	ctx.strokeStyle=clr;ctx.stroke();
    }
    x, y : the center coordinates, a, b : start angle and end angle measured on the circle (C constructed on the major axis), rw one half of the major axis (C radius), rh one half of the minor axis, ngl angle of major axis with Ox (probably 0 for a pie chart) and clr : stroke or fill color.

    Then it's easy to draw a pie chart (with the angles on the circle C) and to make all calculation in the circle C !
    You have only to transform the mouse (or touch coordinates) in the axis of the ellipse define by ngl and ngl+Math.PI/2.
    Code:
    var isx,isy;
    window.ontouchstart=window.onmousedown=function(e){
    	if (e.target.nodeName!='CANVAS') return true;
    //...
    	isx=e.clientX !== undefined?e.clientX:e.touches[0].clientX;
    	isy=e.clientY !== undefined?e.clientY:e.touches[0].clientY;
    // If the pie Chart major axis is horizontal
    	cx= isx - ellipseCenterX;
    	cy= (isy - ellipseCenterY)*rw/rh;
    	mouseAngle=Math.atan2(cy,cx); // Angle to compare with the sectors delimiter's angles
    }
    with the inverse transformation which multiply the y coordinate by rw/rh. Then with this new coordinates an Math.atan2(cy,cx) will give the angle to compare with the other pie chart sector radius. That's all !

    NB : It's not useful to stand with their feet on a wall with the y axis down, set only anticlockwise to false !
    Last edited by 007julien; 01-04-2014 at 01:23 PM. Reason: many erreors...

  • Users who have thanked 007julien for this post:

    Arbitrator (01-08-2014)


  •  
    Page 1 of 2 12 LastLast

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •