Hi I want to draw a curve as I move slider. I have two kinds of curves. Bezier curve and quadratic cruve. Also As I draw the curve I want to move an object on that same path. I want it to be dynamic so If I should be able to change the curve points.
So I need a function which I can call on the slider change as I am doing for line.
Here is my code. This code will work only in chrome.
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
.wrapper {
margin: 0 auto;
width: 1000px;
}
.canHdr {
float: left;
width: 450px;
height: 400px;
border: 1px solid red;
}
</style>
</head>
<body>
<form>
<!-- wrapper -->
<div class="wrapper">
<!-- canHdr -->
<div id="canHdr" class="canHdr" >
<p>
This is my 1st div with quadratic curve I want to draw this curve as I move the slider. I want to make it dynamic so when I should be able to change the curve points. Also I want to move an object on that curve as I am doing in my 3rd div.
</p>
<div class="canOuterHdr" >
<canvas id="myCanvas1" width="300" height="195" style="position: relative;">
[No canvas support]
</canvas>
</div>
<div id="slider1" class="newBg">
<input id="slide1" type="range" min="0" max="100" step="1" value="0" onchange="counterSlider('slide1');" />
</div>
</div>
<!--/ canHdr -->
<!-- canHdr2 -->
<div id="canHdr2" class="canHdr" >
<p>
This is my 2nd div. I have bezier curve. I want to make it dynamic so when I should be able to change the curve points. Also I want to move an object on that curve as I am doing in my 3rd div.
</p>
<div class="canOuterHdr" >
<canvas id="myCanvas2" width="300" height="195" style="position: relative;">
[No canvas support]
</canvas>
</div>
<div id="slider2" class="newBg">
<input id="slide2" type="range" min="0" max="100" step="1" value="0" onchange="counterSlider('slide2');" />
</div>
</div>
<!-- canHdr2 -->
<!-- canHdr3 -->
<div id="canHdr3" class="canHdr" >
<p>
This is my 3rd div with slanting line. I want to move a ball on this line when I move the slider. So as the line increases ball will also move on the line.
</p>
<div class="canOuterHdr" >
<canvas id="myCanvas3" width="300" height="195" style="position: relative;">
[No canvas support]
</canvas>
</div>
<div id="slider3" class="newBg">
<input id="slide3" type="range" min="0" max="100" step="1" value="0" onchange=" drawSlopeCurve2('slide3','100'); " />
</div>
</div>
<!--/ canHdr3 -->
<!-- canHdr4 -->
<div id="canHdr4" class="canHdr" >
<p>
This is my 4th div with slanting line. I want to move a ball on this line when I move the slider. So as the line increases ball will also move on the line.
</p>
<div class="canOuterHdr" >
<canvas id="myCanvas4" width="300" height="195" style="position: relative;">
[No canvas support]
</canvas>
</div>
<div id="slider4" class="newBg">
<input id="slide4" type="range" min="0" max="100" step="1" value="0" onchange=" drawSlopeCurve1('slide4','100'); " />
</div>
</div>
<!--/ canHdr4 -->
</div>
<!-- /wrapper -->
<script type="text/javascript">
newSprite('myCanvas3', 16, 170);
quadraticCurve('myCanvas1', 18.8, 45, 28, 160, 228, 165);
bezierCurve('myCanvas2', 20, 75, 55.2, 150.0, 200,100, 228, 165)
function counterSlider(sID) {
var slideVal = document.getElementById(sID).value;
/*if (maxValue ==100){
slideVal=slideVal/100;
}*/
slideVal = slideVal / 100;
if (slideVal == 0) {
/* erase('myCanvas2');
erase('myCanvas3');
erase('myCanvas4');*/
//newSprite('myCanvas1b', 18.8, 45);
newSprite('myCanvas3', 16, 170);
} else if (slideVal > 0 && slideVal <= 34) {
/*erase('myCanvas1');
//erase('myCanvas1b');
erase('myCanvas2');
erase('myCanvas3');
erase('myCanvas4');*/
} else if (slideVal > 34 && slideVal <= 67) {
/*erase('myCanvas1');
erase('myCanvas2');
erase('myCanvas3');
erase('myCanvas4');*/
} else if (slideVal > 67 && slideVal <= 100) {
/*erase('myCanvas1');
erase('myCanvas2');
erase('myCanvas3');
erase('myCanvas4');*/
}
}
function erase(canvasId) {
var canvas = document.getElementById(canvasId);
var context = canvas.getContext("2d");
context.beginPath();
context.clearRect(0, 0, canvas.width, canvas.height);
canvas.width = canvas.width;
}
/**********for backgroundImage********************/
function quadraticCurve(canId, spx, spy, cpx, cpy, endx, endy) {
var canvas = document.getElementById(canId);
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(spx, spy);
ctx.quadraticCurveTo(cpx, cpy, endx, endy);
ctx.strokeStyle = "#eaca2d";
ctx.stroke();
}
function bezierCurve(canId, spx, spy, cpx1, cpy1, cpx2, cpy2, endx, endy) {
var canvas = document.getElementById(canId);
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(spx, spy);
ctx.quadraticCurveTo(cpx1, cpy1, cpx2, cpy2, endx, endy);
ctx.strokeStyle = "#eaca2d";
ctx.stroke();
}
function newSprite(canId, mvx, mvy) {
var canvas = document.getElementById(canId);
var ctx = canvas.getContext('2d');
ctx.globalCompositeOperation = 'source-over';
//ctx.globalCompositeOperation = "destination-over";
ctx.beginPath();
ctx.fillStyle = "#0077c1";
ctx.arc(mvx, mvy, 6, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
function drawSlopeCurve1(sID, maxValue) {
// erase('canvasTwo');
var canId = 'myCanvas4';
var slideVal = parseInt(document.getElementById(sID).value);
var canvas = document.getElementById(canId);
var context = canvas.getContext('2d');
canvas.width = canvas.width;
//line end points
x1 = 16;
y1 = 170;
x2 = 200;
y2 = 80;
//get slope (rise over run)
var m = (y2 - y1) / (x2 - x1);
//get y-intercept
var b = y1 - (m * x1);
//get distance between the two points
var distance = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
//get new x and y values
var x = x1 + parseInt(distance / maxValue * slideVal);
var y = parseInt(m * x + b);
context.beginPath();
context.moveTo(x1, y1);
context.lineTo(x, y);
context.lineWidth = 0.6;
context.stroke();
newSprite(canId, x, y);
}
function drawSlopeCurve2(sID, maxValue) {
// erase('canvasTwo');
var canId = 'myCanvas3';
var slideVal = parseInt(document.getElementById(sID).value);
var canvas = document.getElementById(canId);
var context = canvas.getContext('2d');
canvas.width = canvas.width;
//line end points
x1 = 16;
y1 = 170;
x2 = 160;
y2 = 72;
//get slope (rise over run)
var m = (y2 - y1) / (x2 - x1);
//get y-intercept
var b = y1 - (m * x1);
//get distance between the two points
var distance = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
//get new x and y values
var x = x1 + parseInt(distance / maxValue * slideVal);
var y = parseInt(m * x + b);
context.beginPath();
context.moveTo(x1, y1);
context.lineTo(x, y);
context.lineWidth = 0.6;
context.stroke();
newSprite(canId, x, y);
}
</script>
</form>
</body>
</html>
This is link for jsfiddle: http://jsfiddle.net/QRVxH/
You should begin by defining the curve in a function, so you can calculate where the graph should end for each x-position. Then you also know where to draw the end-dot.
My demo function has a function to draw a sine on the canvas:
function calc(x){
var y = 100 + ( 50*Math.sin(x*400));
return y;
}
By drawing a line (not a curve!) between the points you get your graph.
for (var x=0; x<=400 && (x <= slider.value); x+=3){
y= calc(x);
ctx.lineTo(x, y);
}
Working demo: http://jsfiddle.net/w1ll3m/CbjWK/11/
Added html5slider.js to make the slider work in firefox.
Related
I'm actually working on a project which overlay two image, with one that the user upload it and the second is by default.
My only problem is when the uploaded image is a rectangle and not a square, the canvas is resizing it. I need that the canvas crop my image, and be a square. Then I can apply the filter.
Here is my code:
$('.file1, .file2').on('change', function() {
var reader = new FileReader(),
imageSelector = $(this).data('image-selector');
if (this.files && this.files[0]) {
reader.onload = function(e) {
imageIsLoaded(e, imageSelector)
};
reader.readAsDataURL(this.files[0]);
}
});
$('.btn-merge').on('click', merge);
function imageIsLoaded(e, imageSelector) {
$(imageSelector).attr('src', e.target.result);
$(imageSelector).removeClass('hidden');
};
function merge() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
imageObj1 = new Image(),
imageObj2 = new Image();
canvas.width = 300;
canvas.height = 300;
imageObj1.src = $('.image1').attr('src');
imageObj1.onload = function() {
ctx.globalAlpha = 1;
ctx.drawImage(imageObj1, 0, 0, 300, 300);
imageObj2.src = $('.image2').attr('src');
imageObj2.onload = function() {
ctx.globalAlpha = 1;
ctx.drawImage(imageObj2, 0, 0, 300, 300);
var img = canvas.toDataURL('img/png');
$('.merged-image').attr('src', img);
var mergedimage = document.getElementById('mergedimage');
$('.merged-image').removeClass('hidden');
$("#downloadfinal").attr("href", mergedimage.src);
}
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<div class="container-fluid shadow">
<div class="container d-flex flex-column justify-content-center">
<div class="row mb-1 ">
<h2>Votre photo ici : </h2>
<label class="custom ml-3 hover-underline-animation"> <input class="ml-2 file1" type="file" data-image-selector=".image1" />Selectionner un fichier</label>
</div>
<img class="image1 hidden mb-4" alt="abs" width="200px" height="auto" />
<div class="row">
<h2 class="mr-2 ">Filtre par défaut : </h2>
<img alt="abs image3" width="200px" height="auto" src="img/filtre.png" />
</div>
<div class="otherfilter">
<div class="row mt-5 mb-5">
<h2 class="">Mettez un autre filtre ici : </h2>
<label class="custom ml-3 hover-underline-animation"> <input class="ml-2 file2" type="file" data-image-selector=".image2" />Selectionner un fichier</label>
</div>
<img class="hidden image2" alt="ab" width="200px" height="auto" src="img/filtre.png">
</div>
</div>
<br />
<div class="text-center mb-5">
<input class="btn-merge mb-3" type="button" value="Appliquer le filtre" />
<br />
<img class="merged-image hidden mb-3" id="mergedimage" alt="merged image" />
<canvas id="canvas" class="hidden"></canvas>
<br>
<a class="btn-dl" id="downloadfinal" role="button" href="#" download="photo_profil_modifie">
<i class="mr-2 bi bi-download"></i>Télécharger
</a>
</div>
Thanks for read this, hope my english is good, if you don't understand tell me.
To do this you need to scale the input image to fit the canvas either horizontally or vertically while maintaining it's aspect ratio.
That's not hard to do as things are a bit easier since the canvas is squarish. Say we have a canvas of 300 x 300 pixel and we want to draw a non-square image of 400 x 300 onto. First we take the width or height of the canvas - it does not really matter as it's the same - and divide it by the bigger side of the image - 400 in this case.
300 / 400 == 0.75
This is the scale we need to multiply both the width and height of the image before drawing it onto the canvas.
Here's an example:
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
let imageObj1 = new Image();
imageObj1.crossOrigin = 'anonymous';
imageObj1.crossOrigin = 'anonymous';
imageObj1.onload = () => {
let scale = imageObj1.width > imageObj1.height ? canvas.width / imageObj1.width : canvas.height / imageObj1.height;
context.drawImage(imageObj1, canvas.width / 2 - imageObj1.width * scale / 2, canvas.height / 2 - imageObj1.height * scale / 2, imageObj1.width * scale, imageObj1.height * scale);
}
imageObj1.src = 'https://api.codetabs.com/v1/proxy?quest=https://picsum.photos/id/237/300/400';
#canvas {
background: blue;
}
<canvas id="canvas" width="300" height="300"></canvas>
If you prefer to not have unused area on your canvas and stretch the image to the whole canvas and crop the exceess, you simply divide the smaller side of your image by the canvas width/height.
For example:
//ctx.drawImage(imageObj1, 0, 0, 300, 300);let image = new Image();
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
let imageObj1 = new Image();
imageObj1.crossOrigin = 'anonymous';
imageObj1.crossOrigin = 'anonymous';
imageObj1.onload = () => {
let scale = imageObj1.width < imageObj1.height ? canvas.width / imageObj1.width : canvas.height / imageObj1.height;
context.drawImage(imageObj1, canvas.width / 2 - imageObj1.width * scale / 2, canvas.height / 2 - imageObj1.height * scale / 2, imageObj1.width * scale, imageObj1.height * scale);
}
imageObj1.src = 'https://api.codetabs.com/v1/proxy?quest=https://picsum.photos/id/237/300/400';
<canvas id="canvas" width="300" height="300"></canvas>
I've been working for a few hours now and I can't get my donut graph drawn with js anyone can help me with that any solution i want when selected checkbox add 25% when slected two checkbox add +25% thank you .
try this:
JS:
$(document).ready(function () {
var el = document.getElementById('graph'); // get canvas
var options = {
percent: el.getAttribute('data-percent') || 25,
size: el.getAttribute('data-size') || 220,
lineWidth: el.getAttribute('data-line') || 15,
rotate: el.getAttribute('data-rotate') || 0
}
var canvas = document.createElement('canvas');
var span = document.createElement('span');
span.textContent = options.percent + '%';
if (typeof(G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
canvas.width = canvas.height = options.size;
el.appendChild(span);
el.appendChild(canvas);
ctx.translate(options.size / 2, options.size / 2); // change center
ctx.rotate((-1 / 2 + options.rotate / 180) * Math.PI); // rotate -90 deg
//imd = ctx.getImageData(0, 0, 240, 240);
var radius = (options.size - options.lineWidth) / 2;
var drawCircle = function(color, lineWidth, percent) {
percent = Math.min(Math.max(0, percent || 1), 1);
ctx.beginPath();
ctx.arc(0, 0, radius, 0, Math.PI * 2 * percent, false);
ctx.strokeStyle = color;
ctx.lineCap = 'round'; // butt, round or square
ctx.lineWidth = lineWidth
ctx.stroke();
};
drawCircle('#efefef', options.lineWidth, 100 / 100);
drawCircle('#555555', options.lineWidth, options.percent / 100);
$(".chkBox").on("click", function(){
var dp = parseFloat($("#graph").attr("data-percent"));
if($(this).is(":checked")){
$("#graph").attr("data-percent", dp + 25);
}else{
$("#graph").attr("data-percent", dp - 25);
}
span.textContent = parseFloat($("#graph").attr("data-percent")) + '%';
console.log($("#graph").attr("data-percent"));
drawCircle('#efefef', options.lineWidth, 100 / 100);
drawCircle('#555555', options.lineWidth, parseFloat($("#graph").attr("data-percent")) / 100);
});
});
HTML:
<div class="chart" id="graph" data-percent="0"></div>
<label for="id_1">A</label>
<input type="checkbox" class="chkBox" id="id_1" /><br/>
<label for="id_2">B</label>
<input type="checkbox" class="chkBox" id="id_2" /><br/>
<label for="id_3">C</label>
<input type="checkbox" class="chkBox" id="id_3" /><br/>
<label for="id_4">D</label>
<input type="checkbox" class="chkBox" id="id_4" />
CSS:
div {
position:relative;
margin:80px;
width:220px; height:220px;
}
canvas {
display: block;
position:absolute;
top:0;
left:0;
}
span {
color:#555;
display:block;
line-height:220px;
text-align:center;
width:220px;
font-family:sans-serif;
font-size:40px;
font-weight:100;
margin-left:5px;
}
input {
width: 200px;
}
I am trying to zoom images on mouseover but zoom is applied only on first image .
I am using given code in my django templates to zoom images .
{% for image in images_obj %}
<img class="drift-demo-trigger" data-zoom="{% static
'/images/catalog/products/thumbnail/' %}{{image}}" src="{% static
'/images/catalog/products/thumbnail/' %}{{image}}" alt="IMG-PRODUCT"
style="width:99%;border:1px solid #ccc;">
<div class="detail">
<section>
</section>
</div>
{% endfor %}
new Drift(document.querySelector('.drift-demo-trigger'), {
paneContainer: document.querySelector('.detail'),
inlinePane: 900,
inlineOffsetY: -85,
containInline: true,
hoverBoundingBox: true
});
All images which are coming in loop should be zoomed but currently only the first image is able to zoom .
Try this before ur html code:
<style>
* {box-sizing: border-box;}
.img-zoom-container {
position: relative;
}
.img-zoom-lens {
position: absolute;
border: 1px solid #d4d4d4;
/*set the size of the lens:*/
width: 80px;
height: 80px;
}
.img-zoom-result {
border: 1px solid #d4d4d4;
/*set the size of the result div:*/
width: 400px;
height: 400px;
}
</style>
<script>
function imageZoom(imgID, resultID) {
var img, lens, result, cx, cy;
img = document.getElementById(imgID);
result = document.getElementById(resultID);
/*create lens:*/
lens = document.createElement("DIV");
lens.setAttribute("class", "img-zoom-lens");
/*insert lens:*/
img.parentElement.insertBefore(lens, img);
/*calculate the ratio between result DIV and lens:*/
cx = result.offsetWidth / lens.offsetWidth;
cy = result.offsetHeight / lens.offsetHeight;
/*set background properties for the result DIV:*/
result.style.backgroundImage = "url('" + img.src + "')";
result.style.backgroundSize = (img.width * cx) + "px " + (img.height * cy) + "px";
/*execute a function when someone moves the cursor over the image, or the lens:*/
lens.addEventListener("mousemove", moveLens);
img.addEventListener("mousemove", moveLens);
/*and also for touch screens:*/
lens.addEventListener("touchmove", moveLens);
img.addEventListener("touchmove", moveLens);
function moveLens(e) {
var pos, x, y;
/*prevent any other actions that may occur when moving over the image:*/
e.preventDefault();
/*get the cursor's x and y positions:*/
pos = getCursorPos(e);
/*calculate the position of the lens:*/
x = pos.x - (lens.offsetWidth / 2);
y = pos.y - (lens.offsetHeight / 2);
/*prevent the lens from being positioned outside the image:*/
if (x > img.width - lens.offsetWidth) {x = img.width - lens.offsetWidth;}
if (x < 0) {x = 0;}
if (y > img.height - lens.offsetHeight) {y = img.height - lens.offsetHeight;}
if (y < 0) {y = 0;}
/*set the position of the lens:*/
lens.style.left = x + "px";
lens.style.top = y + "px";
/*display what the lens "sees":*/
result.style.backgroundPosition = "-" + (x * cx) + "px -" + (y * cy) + "px";
}
function getCursorPos(e) {
var a, x = 0, y = 0;
e = e || window.event;
/*get the x and y positions of the image:*/
a = img.getBoundingClientRect();
/*calculate the cursor's x and y coordinates, relative to the image:*/
x = e.pageX - a.left;
y = e.pageY - a.top;
/*consider any page scrolling:*/
x = x - window.pageXOffset;
y = y - window.pageYOffset;
return {x : x, y : y};
}
}
</script>
Now in html:
{% extends 'base.html' %}
{% block content %}
<div class="col-md-12"style="margin-left: 0px">
<div class="panel-body">
<table class="table-responsive">
<tbody>
<tr>
<td><div class="img-zoom-container">
<img id="myimage" src="{{ member.immagine.url }}" width="860" >
</div></td><td>
<div id="myresult" class="img-zoom-result"></div></td></tr>
</tbody>
</table>
<br>
<script>
// Initiate zoom effect:
imageZoom("myimage", "myresult");
</script>
</div>
</div>
</div>
</div>
{% endblock %}
I'm trying to imitate the behavior of CSS border-radius property on a canvas. I've done something which is working, but there are some missing adaptations that the browser is handling, which i can't reproduce on the canvas (See image link below as an example)
However, i'm struggling to adapt the borders when they are getting out of
the shape.
Here is an example, let's take an HTML shape of 100px (Width) X 100px (Height), and then apply the following radius : border-radius: 100px 52px 1px 1px;
Then draw this shape in a canvas with the same parameters.
And then i get this (RED SHAPE = Canvas shape, GREEN SHAPE = HTML shape)
https://imgur.com/a/XGuca
(Sorry i'm not able to upload image, because of my reputation)
I'm using this function to draw the shape
function (xx, yy, ww, hh, rad, fill, stroke) {
if (typeof(rad) === "undefined") rad = 5;
this.beginPath();
this.moveTo(xx, yy);
this.arcTo(xx + ww, yy, xx + ww, yy + hh, rad.tr);
this.arcTo(xx + ww, yy + hh, xx, yy + hh, rad.br);
this.arcTo(xx, yy + hh, xx, yy, rad.bl);
this.arcTo(xx, yy, xx + ww, yy, rad.tl);
if (stroke) this.stroke(); // Default to no stroke
if (fill || typeof(fill) === "undefined") this.fill(); // Default to fill
};
Here is the description of the parameters
xx: X axis position
yy: Y axis position
ww: Width
hh: Height
rad: {tl:0, tr:0, br:0, bl: 0} (For top-left, top-right, bottom-right, bottom-left RADIUS)
I'm not getting what i could do in order to make it working, could someone help me or give me a tip in order to do that ? Thanks !
PS: Sorry for my bad english
(See snippet below)
// Ctx
var ctx = document.getElementById("rounded-rect").getContext("2d");
//Round rect func
ctx.constructor.prototype.fillRoundedRect =
function (xx, yy, ww, hh, rad, fill, stroke) {
if (typeof(rad) === "undefined") rad = 5;
this.beginPath();
this.moveTo(xx, yy);
this.arcTo(xx + ww, yy, xx + ww, yy + hh, rad.tr);
this.arcTo(xx + ww, yy + hh, xx, yy + hh, rad.br);
this.arcTo(xx, yy + hh, xx, yy, rad.bl);
this.arcTo(xx, yy, xx + ww, yy, rad.tl);
if (stroke) this.stroke(); // Default to no stroke
if (fill || typeof(fill) === "undefined") this.fill(); // Default to fill
};
ctx.fillStyle = "red";
ctx.strokeStyle = "#ddf";
var copy = document.getElementById('copy');
var tl = document.getElementById('tl');
var tr = document.getElementById('tr');
var bl = document.getElementById('bl');
var br = document.getElementById('br');
var off = document.getElementById('off');
function test() {
ctx.clearRect(0, 0, 600, 500);
/* 1.Top left */
/* 2. Top right */
/* 3. Bottom right */
/* 4. Bottom left */
var borders = [tl.value, tr.value, br.value, bl.value].join('px ') + 'px';
copy.style.borderRadius = borders;
var copyRad = borders.replace(/px/g, '').split(' ').map(function (a) {
return parseInt(a)
});
var rad = {
tl: copyRad[0],
tr: copyRad[1],
br: copyRad[2],
bl: copyRad[3]
};
var o = +off.value;
ctx.fillRoundedRect(15 + o, 15 + o, 100, 100, rad);
}
tl.oninput = test;
tr.oninput = test;
bl.oninput = test;
br.oninput = test;
off.oninput = test;
test();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html, body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div style="display:inline-block; position: absolute;
left:120px;top:120px; width: 100px; height: 100px; background:green;
border-radius: 10px 5px 10px 20px;" id="copy">
</div>
<canvas style="display: inline-block; position: absolute; zindex:0; left:0; top:0;" id="rounded-rect" width="600" height="500">
</canvas>
<div style="top: 300px; position:absolute; z-index: 1;">
<label>
Top left
<input type="range" min="1" max="100" value="0" class="slider" id="tl"></label><br/>
<label>
Top right
<input type="range" min="1" max="100" value="0" class="slider" id="tr"></label><br/>
<label>
Bottom left
<input type="range" min="1" max="100" value="0" class="slider" id="bl"></label><br/>
<label>
Bottom right
<input type="range" min="1" max="100" value="0" class="slider" id="br"></label><br/>
<label>
Offset
<input type="range" min="1" max="200" value="0" class="slider" id="off"></label><br/>
</div>
</body>
</html>
Seems that the browser somehow corrects the radius if it gets out of the shape. I've created the correctRadius function that does something like this. Of course, the result is not exact the same, but at least the shape doesn't have any gaps.
// Ctx
var ctx = document.getElementById("rounded-rect").getContext("2d");
function correctRadius(r, w, h) {
if (r.tl + r.tr > w) {
r.tl -= (r.tl + r.tr - w) / 2;
r.tr = w - r.tl;
}
if (r.bl + r.br > w) {
r.br -= (r.br + r.bl - w) / 2;
r.bl = w - r.br;
}
if (r.tl + r.bl > h) {
r.tl -= (r.tl + r.bl - h) / 2;
r.bl = h - r.tl;
}
if (r.tr + r.br > h) {
r.tr -= (r.tr + r.br - h) / 2;
r.br = h - r.tr;
}
}
//Round rect func
ctx.constructor.prototype.fillRoundedRect =
function (xx, yy, ww, hh, rad, fill, stroke) {
correctRadius(rad, ww, hh);
if (typeof(rad) === "undefined") rad = 5;
this.beginPath();
this.moveTo(xx, yy);
this.arcTo(xx + ww, yy, xx + ww, yy + hh, rad.tr);
this.arcTo(xx + ww, yy + hh, xx, yy + hh, rad.br);
this.arcTo(xx, yy + hh, xx, yy, rad.bl);
this.arcTo(xx, yy, xx + ww, yy, rad.tl);
if (stroke) this.stroke(); // Default to no stroke
if (fill || typeof(fill) === "undefined") this.fill(); // Default to fill
};
ctx.fillStyle = "red";
ctx.strokeStyle = "#ddf";
var copy = document.getElementById('copy');
var tl = document.getElementById('tl');
var tr = document.getElementById('tr');
var bl = document.getElementById('bl');
var br = document.getElementById('br');
var off = document.getElementById('off');
function test() {
ctx.clearRect(0, 0, 600, 500);
/* 1.Top left */
/* 2. Top right */
/* 3. Bottom right */
/* 4. Bottom left */
var borders = [tl.value, tr.value, br.value, bl.value].join('px ') + 'px';
copy.style.borderRadius = borders;
var copyRad = borders.replace(/px/g, '').split(' ').map(function (a) {
return parseInt(a)
});
var rad = {
tl: copyRad[0],
tr: copyRad[1],
br: copyRad[2],
bl: copyRad[3]
};
var o = +off.value;
ctx.fillRoundedRect(15 + o, 15 + o, 100, 100, rad);
}
tl.oninput = test;
tr.oninput = test;
bl.oninput = test;
br.oninput = test;
off.oninput = test;
test();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
html, body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div style="display:inline-block; position: absolute;
left:120px;top:120px; width: 100px; height: 100px; background:green;
border-radius: 10px 5px 10px 20px;" id="copy">
</div>
<canvas style="display: inline-block; position: absolute; zindex:0; left:0; top:0;" id="rounded-rect" width="600" height="500">
</canvas>
<div style="top: 300px; position:absolute; z-index: 1;">
<label>
Top left
<input type="range" min="1" max="100" value="0" class="slider" id="tl"></label><br/>
<label>
Top right
<input type="range" min="1" max="100" value="0" class="slider" id="tr"></label><br/>
<label>
Bottom left
<input type="range" min="1" max="100" value="0" class="slider" id="bl"></label><br/>
<label>
Bottom right
<input type="range" min="1" max="100" value="0" class="slider" id="br"></label><br/>
<label>
Offset
<input type="range" min="1" max="200" value="0" class="slider" id="off"></label><br/>
</div>
</body>
</html>
I am trying to draw quadratic curve on movement of slider. So as slider moves curve will be drawn. I want to do this for quadratic curve and also for bezier curve. This is my code it will work only in chrome
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
.wrapper {
margin: 0 auto;
width: 1000px;
}
.canHdr {
float: left;
width: 450px;
height: 400px;
border: 1px solid red;
}
</style>
</head>
<body>
<form>
<!-- wrapper -->
<div class="wrapper">
<!-- canHdr -->
<div id="canHdr" class="canHdr" >
<p>
This is my 1st div with quadratic curve I want to draw this curve as I move the slider. I want to make it dynamic so when I should be able to change the curve points. Also I want to move an object on that curve as I am doing in my 3rd div.
</p>
<div class="canOuterHdr" >
<canvas id="myCanvas1" width="300" height="195" style="position: relative;">
[No canvas support]
</canvas>
</div>
<div id="slider1" class="newBg">
<input id="slide1" type="range" min="0" max="100" step="1" value="0" onchange="counterSlider('slide1');" />
</div>
</div>
<!--/ canHdr -->
<!-- canHdr2 -->
<div id="canHdr2" class="canHdr" >
<p>
This is my 2nd div. I have bezier curve. I want to make it dynamic so when I should be able to change the curve points. Also I want to move an object on that curve as I am doing in my 3rd div.
</p>
<div class="canOuterHdr" >
<canvas id="myCanvas2" width="300" height="195" style="position: relative;">
[No canvas support]
</canvas>
</div>
<div id="slider2" class="newBg">
<input id="slide2" type="range" min="0" max="100" step="1" value="0" onchange="counterSlider('slide2');" />
</div>
</div>
<!-- canHdr2 -->
</div>
<!-- /wrapper -->
<script type="text/javascript">
// newSprite('myCanvas3', 16, 170);
quadraticCurve('myCanvas1', 18.8, 45, 28, 160, 228, 165);
bezierCurve('myCanvas2', 20, 75, 55.2, 150.0, 200,100, 228, 165)
function counterSlider(sID) {
var slideVal = document.getElementById(sID).value;
/*if (maxValue ==100){
slideVal=slideVal/100;
}*/
slideVal = slideVal / 100;
if (slideVal == 0) {
/* erase('myCanvas2');
erase('myCanvas3');
erase('myCanvas4');*/
//newSprite('myCanvas1b', 18.8, 45);
// newSprite('myCanvas3', 16, 170);
} else if (slideVal > 0 && slideVal <= 34) {
/*erase('myCanvas1');
//erase('myCanvas1b');
erase('myCanvas2');
erase('myCanvas3');
erase('myCanvas4');*/
} else if (slideVal > 34 && slideVal <= 67) {
/*erase('myCanvas1');
erase('myCanvas2');
erase('myCanvas3');
erase('myCanvas4');*/
} else if (slideVal > 67 && slideVal <= 100) {
/*erase('myCanvas1');
erase('myCanvas2');
erase('myCanvas3');
erase('myCanvas4');*/
}
}
function erase(canvasId) {
var canvas = document.getElementById(canvasId);
var context = canvas.getContext("2d");
context.beginPath();
context.clearRect(0, 0, canvas.width, canvas.height);
canvas.width = canvas.width;
}
/**********for backgroundImage********************/
function quadraticCurve(canId, spx, spy, cpx, cpy, endx, endy) {
var canvas = document.getElementById(canId);
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(spx, spy);
ctx.quadraticCurveTo(cpx, cpy, endx, endy);
ctx.strokeStyle = "#eaca2d";
ctx.stroke();
}
function bezierCurve(canId, spx, spy, cpx1, cpy1, cpx2, cpy2, endx, endy) {
var canvas = document.getElementById(canId);
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.moveTo(spx, spy);
ctx.quadraticCurveTo(cpx1, cpy1, cpx2, cpy2, endx, endy);
ctx.strokeStyle = "#eaca2d";
ctx.stroke();
}
function newSprite(canId, mvx, mvy) {
var canvas = document.getElementById(canId);
var ctx = canvas.getContext('2d');
ctx.globalCompositeOperation = 'source-over';
//ctx.globalCompositeOperation = "destination-over";
ctx.beginPath();
ctx.fillStyle = "#0077c1";
ctx.arc(mvx, mvy, 6, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
}
</script>
</form>
</body>
</html>
This is the link for jsfiddle: http://jsfiddle.net/Y5yYD/1/
Here’s how to incrementally draw quad & cubic bezier curves with a slider
Example Fiddle: http://jsfiddle.net/m1erickson/auFam/
This function will return an XY point at the specified percentage of a Quad curve:
// quadratic bezier: percent is 0-1
function getQuadraticBezierXY(percent,startPt,controlPt,endPt) {
var x = Math.pow(1-percent,2) * startPt.x + 2 * (1-percent) * percent * controlPt.x + Math.pow(percent,2) * endPt.x;
var y = Math.pow(1-percent,2) * startPt.y + 2 * (1-percent) * percent * controlPt.y + Math.pow(percent,2) * endPt.y;
return( {x:x,y:y} );
}
This function will return an XY point at the specified percentage of a Cubic curve:
// cubic bezier pct is 0-1
function getCubicBezierXY(pct,startPt,controlPt1,controlPt2,endPt){
var x=CubicN(pct,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
var y=CubicN(pct,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
return({x:x,y:y});
}
// cubic formula at percent distance
function CubicN(pct, a,b,c,d) {
var t2 = pct * pct;
var t3 = t2 * pct;
return a + (-a * 3 + pct * (3 * a - a * pct)) * pct
+ (3 * b + pct * (-6 * b + b * 3 * pct)) * pct
+ (c * 3 - c * 3 * pct) * t2
+ d * t3;
}
Here is example code and a Fiddle: http://jsfiddle.net/m1erickson/auFam/
<!doctype html>
<html lang="en">
<head>
<style>
body{ background-color: ivory; }
#wrapper{ position:relative; }
canvas{ position:absolute; left:40px; top:5px; border:1px solid blue;}
#amount{ position:absolute; left:1px; top:5px; margin-bottom:15px; width:23px; border:0; color:#f6931f; font-weight:bold; }
#slider-vertical{ position:absolute; left:5px; top:40px; width:15px; height:225px; border:0px; color:#f6931f; font-weight:bold; }
</style>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script>
$(function() {
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// starting value
var startingSliderValue=50;
drawBoth(startingSliderValue);
$( "#slider-vertical" ).slider({
orientation: "vertical",
range: "min",
min: 0,
max: 100,
value: startingSliderValue,
slide: function( event, ui ) {
$( "#amount" ).val( ui.value );
drawBoth( $("#amount").val() );
}
});
$( "#amount" ).val( $( "#slider-vertical" ).slider( "value" ) );
function drawBoth(sliderValue){
ctx.clearRect(0,0,canvas.width,canvas.height);
drawQuadBezier(sliderValue/100);
drawCubicBezier(sliderValue/100);
}
function drawQuadBezier(pct){
var startPt={ x:18.8, y:45 };
var controlPt={ x:28, y:160};
var endPt={ x:228, y:165 };
ctx.beginPath();
ctx.moveTo(startPt.x,startPt.y);
for(var p=0;p<=pct;p+=.01){
var pt=getQuadraticBezierXY(p,startPt,controlPt,endPt)
ctx.lineTo(pt.x,pt.y);
}
ctx.strokeStyle="green";
ctx.stroke();
var pt=getQuadraticBezierXY(pct,startPt,controlPt,endPt)
drawDot(pt.x,pt.y,"#0077c1");
}
function drawCubicBezier(pct){
var startPt={ x:20, y:75 };
var controlPt1={ x:55.2, y:150};
var controlPt2={ x:200, y:100};
var endPt={ x:228, y:165 };
ctx.beginPath();
ctx.moveTo(startPt.x,startPt.y);
for(var p=0;p<=pct;p+=.01){
var pt=getCubicBezierXY(p,startPt,controlPt1,controlPt2,endPt);
ctx.lineTo(pt.x,pt.y);
}
ctx.strokeStyle="red";
ctx.stroke();
var pt=getCubicBezierXY(pct,startPt,controlPt1,controlPt2,endPt);
drawDot(pt.x,pt.y,"#0077c1");
}
// just draw a dot at xy
function drawDot(x,y,color){
ctx.fillStyle=color;
ctx.beginPath();
ctx.arc(x,y,6,0,Math.PI*2,false);
ctx.closePath();
ctx.fill();
}
// quadratic bezier: percent is 0-1
function getQuadraticBezierXY(percent,startPt,controlPt,endPt) {
var x = Math.pow(1-percent,2) * startPt.x + 2 * (1-percent) * percent * controlPt.x + Math.pow(percent,2) * endPt.x;
var y = Math.pow(1-percent,2) * startPt.y + 2 * (1-percent) * percent * controlPt.y + Math.pow(percent,2) * endPt.y;
return( {x:x,y:y} );
}
// cubic bezier pct is 0-1
function getCubicBezierXY(pct,startPt,controlPt1,controlPt2,endPt){
var x=CubicN(pct,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
var y=CubicN(pct,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
return({x:x,y:y});
}
// cubic formula at percent distance
function CubicN(pct, a,b,c,d) {
var t2 = pct * pct;
var t3 = t2 * pct;
return a + (-a * 3 + pct * (3 * a - a * pct)) * pct
+ (3 * b + pct * (-6 * b + b * 3 * pct)) * pct
+ (c * 3 - c * 3 * pct) * t2
+ d * t3;
}
}); // end $(function(){});
</script>
</head>
<body>
<div id="wrapper">
<input type="text" id="amount" />
<div id="slider-vertical"></div>
<canvas id="canvas" width=300 height=300></canvas>
</div>
</body>
</html>