Need help to Modify HTML5 Audio Analyser bar graphic - javascript

There is a custom animated HTML audio analyzer graphic that plays an audio track and moves based on the frequencies of that audio.
This is the code from CodePen HERE, I've found out that it only works on HTTPS domain only.
Now the problem is: I don't need to upload an audio track like what the code does, I just need a simple audio track to play automatically and removing that upload button. let's say I have a track1.mp3 in the same directory on the server and want to play it when my HTML page is loaded.
window.onload = function() {
var file = document.getElementById("thefile");
var audio = document.getElementById("audio");
file.onchange = function() {
var files = this.files;
audio.src = URL.createObjectURL(files[0]);
audio.load();
audio.play();
var context = new AudioContext();
var src = context.createMediaElementSource(audio);
var analyser = context.createAnalyser();
var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
src.connect(analyser);
analyser.connect(context.destination);
analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var barWidth = (WIDTH / bufferLength) * 2.5;
var barHeight;
var x = 0;
function renderFrame() {
requestAnimationFrame(renderFrame);
x = 0;
analyser.getByteFrequencyData(dataArray);
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, WIDTH, HEIGHT);
for (var i = 0; i < bufferLength; i++) {
barHeight = dataArray[i];
var r = barHeight + (25 * (i / bufferLength));
var g = 250 * (i / bufferLength);
var b = 50;
ctx.fillStyle = "rgb(" + r + "," + g + "," + b + ")";
ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
audio.play();
renderFrame();
};
};
#thefile {
position: fixed;
top: 10px;
left: 10px;
z-index: 100;
}
#canvas {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
audio {
position: fixed;
left: 10px;
bottom: 10px;
width: calc(100% - 20px);
}
<div id="content">
<input type="file" id="thefile" accept="audio/*" />
<canvas id="canvas"></canvas>
<audio id="audio" controls></audio>
</div>

Google Forces Yet Another Policy
Nothing is sacred to these guys -- as of Dec 2018 New autoplay policies have been enacted upon Chrome users developing Web Audio API. If the AudioContext(); is created before the user interacts with a gesture (click, tap, burp, snore, etc), the AudioContext(); will be suspended until the user does so.
So to adjust for this engineering marvel I added a play button and wrapped everything in an eventListener.
Changing src
"Now the problem is: I don't need to upload an audio track like what the code does, I just need a simple audio track to play automatically and removing that upload button. let's say I have a track1.mp3 in the same directory and want to play it when my page is loaded."
OK, the demo has been adapted to load a normal url, you'll need to change this line so that it points to the location of the file on your server:
audio.src = "https://host.top/path/to/file.mp3";
The new line that's above the previously mentioned line is added for certain conflicts with CORS:
audio.crossOrigin = "anonymous";
Plunker
Demo
Note: If this Stack Snippet has no sound, then go to this Plunker
document.getElementById('load').addEventListener('click', audioViz);
function audioViz(e) {
var player = document.getElementById("player");
player.crossOrigin = "anonymous";
player.src = "https://glsbx.s3-us-west-1.amazonaws.com/-/dd.mp3";
player.load();
player.play();
var context = new AudioContext();
var src = context.createMediaElementSource(player);
var analyser = context.createAnalyser();
var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
src.connect(analyser);
analyser.connect(context.destination);
analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var barWidth = (WIDTH / bufferLength) * 2.5;
var barHeight;
var x = 0;
function renderFrame() {
requestAnimationFrame(renderFrame);
x = 0;
analyser.getByteFrequencyData(dataArray);
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, WIDTH, HEIGHT);
for (var i = 0; i < bufferLength; i++) {
barHeight = dataArray[i];
var r = barHeight + (25 * (i / bufferLength));
var g = 250 * (i / bufferLength);
var b = 50;
ctx.fillStyle = "rgb(" + r + "," + g + "," + b + ")";
ctx.fillRect(x, HEIGHT - barHeight, barWidth, barHeight);
x += barWidth + 1;
}
}
player.play();
renderFrame();
}
button {
position: fixed;
top: 46px;
left: 46px;
z-index: 100;
display: inline-block;
font-size: 48px;
border: none;
background: none;
color: rgba(223, 6, 39, 0.8);
cursor: pointer;
}
button:hover {
color: rgba(255, 0, 128, 0.8);
}
button:focus {
outline: 0
}
#canvas {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
#player {
position: fixed;
left: 10px;
bottom: 10px;
width: calc(100% - 20px);
}
<button id='load' class='load' type='button'>▶</button>
<canvas id="canvas"></canvas>
<audio id="player" controls>
<source src='about:blank'>
</audio>

Related

Get canvas click coordinates with css scaling and contain:fit

For my pixel art website, I have a canvas that is fixed relative to the viewport, scaled with css, and has object-fit:contain; to keep it the size of the div, no matter what is drawn or resized inside.
I need to get the mouse click coordinates without scaling. The scaled coordinates collected by e.y/e.x wouldn't be useful since object-fit:contain; would change aspect ratios.
Here is some dummy code to better explain my question:
var c = document.getElementById("scaledCanvas");
var ctx = c.getContext('2d');
c.height = 16; // varaible height
c.width = 16; // varaible width
for (var x = 0; x < c.width; x++) {
for (var y = 0; y < c.height; y++) {
ctx.fillStyle = "#" + Math.floor(Math.random() * 16777215).toString(16); // pick random color
ctx.fillRect(x, y, 1, 1); // draw pixel on canvas
}
}
c.addEventListener('click', function(e) {
//this is what i need help with, clickX and clickY need to give the pixel coordinates of the canvas, not the screen
let clickX = e.x - this.offsetLeft;
let clickY = e.y - this.offsetTop;
console.log(clickX + ", " + clickY);
}, false);
#scaledCanvas {
width: 50vw;
height: 50vh;
image-rendering: pixelated;
object-fit: contain;
background-color: black;
}
<!DOCTYPE html>
<html>
<body>
<canvas id="scaledCanvas" width="16" height="16">Canvas Not Supported</canvas>
</body>
</html>
Should it be something like that? I take the "pixel's" cell coords.
var c = document.getElementById("scaledCanvas");
var ctx = c.getContext('2d');
c.height = 16; // varaible height
c.width = 16; // varaible width
for (var x = 0; x < c.width; x++) {
for (var y = 0; y < c.height; y++) {
ctx.fillStyle = "#" + Math.floor(Math.random() * 16777215).toString(16); // pick random color
ctx.fillRect(x, y, 1, 1); // draw pixel on canvas
}
}
c.addEventListener('click', function(e) {
let realWidth = c.getBoundingClientRect().width;
let realHeight = c.getBoundingClientRect().height;
let cellSize = (realWidth < realHeight) ? realWidth/16 : realHeight/16;
let clickX = Math.floor((e.x - this.offsetLeft - (realWidth - cellSize*16)/2)/cellSize);
let clickY = Math.floor((e.y - this.offsetTop - (realHeight - cellSize*16)/2)/cellSize);
console.log(clickX + ", " + clickY);
}, false);
#scaledCanvas {
width: 50vw;
height: 50vh;
image-rendering: pixelated;
object-fit: contain;
background-color: black;
}
<canvas id="scaledCanvas" width="16" height="16">Canvas Not Supported</canvas>

How to link audio file and autoplay

I have an audio visualizer that creates audio waves based on the inputed music file. The file has to manually be put into the "choose file" area. How do I make it so that I can simply link a pr-existing file, so that when the page loads, it immediately starts playing audio.mp3
Here is the code that Im working with:
window.onload = function() {
var audio,
analyser,
audioContext,
sourceNode,
stream;
var svg = document.getElementById('svg'),
svgNS = svg.namespaceURI,
g = document.createElementNS(svgNS, "g");
var width = window.innerWidth,
height = window.innerHeight,
maxHeight = Math.max(height * 0.3, 300),
fftSize = 512, // 512
tilt = 40,
choke = 110,
c = 0;
var audioInput = document.getElementById('audiofile');
// choose file
audioInput.addEventListener('change', function(event) {
stream = URL.createObjectURL(event.target.files[0]);
audio = new Audio();
audio.src = stream;
setup();
});
function setup() {
audio.addEventListener('canplay', function () {
document.body.className+='loaded';
audioContext = new AudioContext();
analyser = (analyser || audioContext.createAnalyser());
analyser.minDecibels = -90;
analyser.maxDecibels = -10;
analyser.smoothingTimeConstant = 1;//0.75;
analyser.fftSize = fftSize;
sourceNode = audioContext.createMediaElementSource(audio);
sourceNode.connect(analyser);
sourceNode.connect(audioContext.destination);
audio.play();
update();
});
}
function shape(g, freqValue, freqSequence, freqCount, colorSequence) {
var freqRatio = freqSequence/freqCount,
x = (width - (tilt * 2)) * freqRatio + tilt,
y = height / 2;
var polyline = document.createElementNS(svgNS, "polyline"),
// using power to increase highs and decrease lows
freqRatio = freqValue / 255,
throttledRatio = (freqValue - choke) / (255 - choke),
strokeWidth = width / freqCount * 0.6 * throttledRatio,
throttledY = Math.max(throttledRatio, 0) * maxHeight,
// color
color = "hsl(" +
((freqSequence / 2) + Math.floor(colorSequence)) + ", " +
100 + "%," +
freqRatio * 80 + "%" +
")";
var loc_x = x - strokeWidth / 2,
loc_y1 = y - throttledY / 2,
loc_y2 = y + throttledY / 2,
x_offset = tilt * throttledRatio;
if (throttledRatio > 0) {
var point_1 = (loc_x - x_offset) + "," + loc_y1,
point_2 = (loc_x + x_offset) + "," + loc_y2;
var points = [ point_1, point_2 ];
} else {
var points = [loc_x + "," + (y-1),loc_x + "," + (y+1)]
}
polyline.setAttribute("stroke-width", strokeWidth);
polyline.setAttribute("stroke", color);
polyline.setAttribute("points", points.join(" "));
g.appendChild(polyline);
}
svg.setAttribute("width", width+"px");
svg.setAttribute("height", height+"px");
svg.setAttribute("viewBox", "0 0 " + width + " " + height);
svg.appendChild(g);
function update() {
g.remove();
g = document.createElementNS(svgNS, "g");
var freqArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteTimeDomainData(freqArray);
for (var i = 0; i < freqArray.length; i++) {
var v = freqArray[i];
shape(g, v, i+1, freqArray.length, c);
}
svg.appendChild(g);
c += 0.5;
requestAnimationFrame(update);
}
};
jakealbaughSignature("light");
body {
margin: 0;
background-color: #000000;
font-family: 'Helvetica', sans-serif;
color: #FFFFFF;
}
input {
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
z-index: 2;
}
body.loaded input {
display: none;
}
#svg {
display: block;
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate3d(-50%, -50%, 0);
transform: translate3d(-50%, -50%, 0);
}
#svg polyline {
stroke-linecap: round;
}
<input id=audiofile type=file>
<svg id=svg></svg>
You can't.
Autoplay of audio is disabled on most browsers. There must be some user interaction, and you can only start playback on that user interaction, such as a click event.

After rotate image how to find correct position to crop in specific area

I want to crop image in specific area, I made below example
it is work when the inner not been rotate
my problem is after rotate the inner, I don't get how to find correct sx,sy,sw,sh to crop
UPDATE
base on this answer fix the draw rotate image part, I update in fiddle.
but I still don't get how to find correct position to crop rotated image ...
https://jsfiddle.net/ve219z34/3/
var crop = function() {
var transformMediaBlock = $('.mediaBlock');
var transformCropInner = $('.transformCropInner');
var transformCropLimit = $('.transformCropLimit');
var canvasContainer = $('.canvasContainer')
var limitLeft = transformCropLimit.offset().left;
var limitTop = transformCropLimit.offset().top;
var limitRight = limitLeft + transformCropLimit.width();
var limitBottom = limitTop + transformCropLimit.height();
var imageRatio = transformMediaBlock.find('img')[0].naturalWidth/transformMediaBlock.find('img').width();
// draw rotate image
var deg2Rad = Math.PI/180;
var rotateDegree = -20;
$('<canvas/>',{'class':'rotate'}).appendTo($(canvasContainer));
var canvas = $('.canvasContainer canvas')[0];
var ctx = canvas.getContext("2d");
var width = 0;
var height = 0;
var diagonal = 0;
var angleInDegrees = 0;
width = transformMediaBlock.find('img')[0].naturalWidth;
height = transformMediaBlock.find('img')[0].naturalHeight;
diagonal = Math.sqrt(Math.pow(width,2)+Math.pow(height,2));
ctx.canvas.width = diagonal;
ctx.canvas.height = diagonal;
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.translate(diagonal/2,diagonal/2);
ctx.rotate(0*Math.PI/180);
ctx.drawImage(transformMediaBlock.find('img')[0],-width/2,-height/2);
ctx.restore();
var drawRotated = function(degrees){
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
ctx.translate(diagonal/2,diagonal/2);
ctx.rotate(degrees*Math.PI/180);
ctx.drawImage(transformMediaBlock.find('img')[0],-width/2,-height/2);
ctx.restore();
};
drawRotated(rotateDegree);
// problem is here don't know how to get correct sx sy sw sh with image been rotate
// draw crop rotate image
var imageLeft = transformMediaBlock.find('img').offset().left;
var imageTop = transformMediaBlock.find('img').offset().top;
var imageRight = imageLeft + transformMediaBlock.find('img').width();
var imageBottom = imageTop + transformMediaBlock.find('img').height();
if (limitLeft <= imageLeft) {
var sx = 0;
} else {
var sx = limitLeft - imageLeft;
}
if (limitTop <= imageTop) {
var sy = 0;
} else {
var sy = limitTop - imageTop;
}
if (limitLeft <= imageLeft) {
var l = imageLeft;
} else {
var l = limitLeft;
}
if (limitRight <= imageRight) {
var r = limitRight;
} else {
var r = imageRight;
}
var sw = r - l;
if (limitTop <= imageTop) {
var t = imageTop;
} else {
var t = limitTop;
}
if (limitBottom <= imageBottom) {
var b = limitBottom;
} else {
var b = imageBottom;
}
var sh = b - t;
sx = sx*imageRatio;
sy = sy*imageRatio;
sw = sw*imageRatio;
sh = sh*imageRatio;
var dx = 0;
var dy = 0;
var dw = sw;
var dh = sh;
};
$('#container').on('click', '.action.crop', function (e) {
var transformMediaBlock = $('.mediaBlock');
transformMediaBlock.find('img').on('load', function() {
$('.transformCropInner').addClass('rotate');
crop();
}).each(function() {
if(this.complete) $(this).load();
});
});
.mediaBlock {
position: relative;
display: block;
overflow: hidden;
}
.mediaBlock img {
max-width: 100%;
}
.transformCropLimit {
position: relative;
top: 20px;
left: 20px;
width: 200px;
height: 200px;
border: 1px solid blue;
}
.transformCropInner {
width: 100px;
cursor: pointer;
position: relative;
top: 10px;
left: 100px;
}
.transformCropInner.rotate {
transform: rotate(9-2deg);
-ms-transform: rotate(-20deg); /* IE 9 */
-moz-transform: rotate(-20deg); /* Firefox */
-webkit-transform: rotate(-20deg); /* Safari and Chrome */
-o-transform: rotate(-20deg); /* Opera */
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container">
<div class="canvasContainer"></div>
<div class="content main">
<div class="action crop">Crop</div>
<div class="transformCropLimit">
<div class="transformCropInner">
<div class="mediaBlock">
<img src="http://image.vsco.co/1/55210eb4aceed3144059/57f2471df662677e548b4568/300x400/25e7b55c-6ed9-490c-95c2-6d69520eb7bd1835072132.jpg">
</div>
</div>
</div>
</div>
</div>
Please don't provide plugin as an answer, and css crop is not what I'm looking for.

Image not showing up on canvas onload

I'm trying to make a player image move around on a canvas. The player image doesn't show up on load. I used an alert to check the onload and it does seem to be running but the image is not displayed.
The player image does not show up if I only move left and right, and it does not show up if I only move up and down. The image does show up after I have moved in both the X and Y directions which makes me think that the X and Y are not correctly set until my animation function sets them. I can't see what is wrong with the initial X and Y onload though I'm using my own images on my computer but I just plugged in some random pictures so you guys could see something load.
I just put the whole code on here I don't know if that is too much but I'm not sure what I did wrong. I'm very new at this and this is my first time posting a question on here. I would appreciate if someone tells me what I'm doing wrong.
edit: I changed
var destX = xToCenter;
var destY = yToCenter;
to just the actual numbers
var destX = 260;
var destY = 220;
and that works but I don't really understand why. Can someone explain why I can't use xToCenter and yToCenter for onload but it works during the movement function?
here is my jsfiddle
//create canvas
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
canvas.width = 600;
canvas.height = 600;
//create background canvas
var worldCanvas = document.getElementById("worldCanvas");
var wctx = worldCanvas.getContext('2d');
worldCanvas.width = 600;
worldCanvas.height = 600;
//player image
var avatar = new Image();
var sourceX = 32;
var sourceY = 32;
var sourceWidth = 16;
var sourceHeight = 32;
var destWidth = sourceWidth * 5;
var destHeight = sourceHeight * 5;
var destX = xToCenter;
var destY = yToCenter;
var speed = 4;
var faceRight = 0;
var faceLeft = 1;
var faceDown = 2;
var faceUp = 3;
var animation = [0, 32, 64];
var i = 0;
//background image
var worldMap = new Image();
var sMapX = 0;
var sMapY = 0;
var sMapWidth = canvas.width;
var sMapHeight = canvas.height;
var dMapX = 0;
var dMapY = 0;
var dMapWidth = canvas.width;
var dMapHeight = canvas.height;
var worldWidth = 1280;
var worldHeight = 873;
//center player
var xToCenter = (0.5 * dMapWidth - 0.5 * destWidth);
var yToCenter = (0.5 * dMapHeight - 0.5 * destHeight);
//load and draw background
worldMap.src = "http://img06.deviantart.net/75db/i/2013/332/5/2/random_background_by_electriczerox-d6vyp1u.png";
worldMap.onload = function() {
wctx.drawImage(worldMap, sMapX, sMapY, sMapWidth, sMapHeight, dMapX, dMapY, dMapWidth, dMapHeight);
alert("worldMap loaded");
}
//load and draw avatar
avatar.src = "http://www.somerandomfacts.com/wp-content/uploads/2013/11/jpg1";
avatar.onload = function() {
ctx.drawImage(avatar, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);
alert("avatar loaded");
}
//clear and redraw
;
(function() {
function main() {
window.requestAnimationFrame(main);
wctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.clearRect(0, 0, canvas.width, canvas.height);
wctx.drawImage(worldMap, sMapX, sMapY, sMapWidth, sMapHeight, dMapX, dMapY, dMapWidth, dMapHeight);
ctx.drawImage(avatar, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight);
}
main();
})();
//move avatar
window.addEventListener('keydown', function(event) {
var keyPressed = event.keyCode;
switch (keyPressed) {
//a moves left
case 65:
if (sMapX > 0) sMapX -= speed;
destX = xToCenter;
sourceX = faceLeft * sourceWidth;
animationLoop();
sourceY = animation[i];
break;
//w moves up
case 87:
if (sMapY > 0) sMapY -= speed;
destY = yToCenter;
sourceX = faceUp * sourceWidth;
animationLoop();
sourceY = animation[i];
break;
//d moves right
case 68:
if (sMapX < worldWidth - dMapWidth) sMapX += speed;
destX = xToCenter;
sourceX = faceRight * sourceWidth;
animationLoop();
sourceY = animation[i];
break;
//s moves down
case 83:
if (sMapY < worldHeight - dMapHeight) sMapY += speed;
destY = yToCenter;
sourceX = faceDown * sourceWidth;
animationLoop();
sourceY = animation[i];
break;
}
});
//animate while moving
function animationLoop() {
window.requestAnimationFrame(changeI);
}
function changeI() {
if (i <= animation.length) i += 1;
animation[i];
if (i == animation.length) i = 0;
}
.canvas {
border: 1px solid;
position: fixed;
top: 0;
left: 0;
}
.worldCanvas {
border: 1px solid;
z-index: -1;
position: fixed;
top: 0;
left: 0;
}
<canvas class="canvas" id="canvas"></canvas>
<canvas class="worldCanvas" id="worldCanvas"></canvas>
I'm still learning but I think I can answer my own question. When I create a variable I should give it an initial value before I set it equal to another variable.

Save only a certain part of an HTML canvas

Is it possible to save or export only a certain part of the canvas rather than the whole canvas?
http://i.stack.imgur.com/hmvYh.jpg
At the moment, when I save the file I get the composition plus the transparent background (light blue in example above) of the entire canvas element I have on the site. What I would like to get is only the gray region (which could be made up of several images and text elements).
Yes you can. Here is the JSFiddle.
First, you need to take a clipping of the image in your canvas. This is pretty simple. I made another canvas (a hidden one) and used the context.drawImage
var hidden_ctx = hidden_canvas.getContext('2d');
hidden_ctx.drawImage(
MainCanvas,
startClippingX,
startClippingY,
clippingWidth,
clippingHeight,
pasteX,
pasteY,
pasteWidth,
pasteHeight
);
Now, we need the Data URL from this canvas so we can download the contents. For this, we will use the canvas.toDataURL method.
var data_url = hidden_canv.toDataURL("image/png");
Now, all we need to do is make a download link (an a element with an href attribute of our data_url) and we're done!
Suppose you have a canvas called oldCanvas and you want to save a rectangular area of width w and height h with its upper left corner at x, y.
Start by making a new canvas element of width w and height h:
var newCanvas = document.createElement('canvas');
newCanvas.width = w;
newCanvas.height = h;
Now copy the rectangular area to the new canvas:
var newContext = newCanvas.getContext('2d');
newContext.drawImage(oldCanvas, x, y, w, h, 0, 0, w, h);
Finally, save the new canvas using toDataUrl() or whatever method you were using previously to save a whole canvas.
For example, you can make an image out of the new canvas:
var newImage = document.createElement('img');
newImage.src = newCanvas.toDataURL();
Then append the new image to the web page:
document.body.appendChild(newImage);
Or maybe you have a container div that you want to append it to.
In any case, once the image is in the document, you can right-click on it and save it as usual.
I've implemented this approach in the following snippet. When you run it, a canvas will be randomly painted. Click and drag on the canvas to select a region that you want to download. A new, downloadable image appears at right.
// Returns a random RGB string (RGBA if alpha is true).
function randomColor(alpha) {
var rgb = [
Math.floor(Math.random() * 255),
Math.floor(Math.random() * 255),
Math.floor(Math.random() * 255)
];
if (alpha) {
rgb.push(Math.random());
}
return 'rgb' + (alpha ? 'a' : '') + '(' + rgb.join(', ') + ')';
}
// Makes a random picture for use in the demonstration.
function makeCanvas() {
var canvas = document.getElementById('oldCanvas'),
context = canvas.getContext('2d'),
width = canvas.width = 400,
height = canvas.height = 500;
context.fillStyle = randomColor();
context.fillRect(0, 0, width, height);
for (var i = 0; i < 200; ++i) {
var x = Math.floor(Math.random() * width),
y = Math.floor(Math.random() * height),
w = Math.floor(Math.random() * width/5),
h = Math.floor(Math.random() * height/5);
context.fillStyle = randomColor(true);
if (Math.floor(Math.random() * 2) === 0) {
context.fillRect(x - w / 2, y - h / 2, w, h);
} else {
context.beginPath();
context.arc(x, y, w, 0, 2 * Math.PI);
context.closePath();
context.fill();
}
}
return canvas;
};
window.onload = function () {
var oldCanvas = makeCanvas(),
oldContext = oldCanvas.getContext('2d'),
targetImage = document.getElementById('targetImage'),
downloadContainer = document.getElementById('downloadContainer'),
selectCanvas = document.getElementById('selectCanvas'),
selectContext = selectCanvas.getContext('2d'),
width = selectCanvas.width = oldCanvas.width,
height = selectCanvas.height = oldCanvas.height;
selectContext.fillStyle = '#000';
downloadContainer.style.left = width + 25 + 'px';
var clipCanvas = document.createElement('canvas'),
clipContext = clipCanvas.getContext('2d');
downloadContainer.appendChild(clipCanvas);
selectCanvas.onmousedown = function (event) {
var x0 = Math.max(0, Math.min(event.clientX, width)),
y0 = Math.max(0, Math.min(event.clientY, height));
targetImage.style.display = 'none';
function update(event) {
var x = Math.max(0, Math.min(event.clientX, width)),
y = Math.max(0, Math.min(event.clientY, height)),
dx = x - x0, w = Math.abs(dx),
dy = y - y0, h = Math.abs(dy);
selectContext.clearRect(0, 0, width, height);
selectContext.fillRect(x0, y0, dx, dy);
clipCanvas.width = w;
clipCanvas.height = h;
if (w*h == 0) {
downloadContainer.style.visibility = 'hidden';
} else {
downloadContainer.style.visibility = 'visible';
clipContext.drawImage(oldCanvas,
x0 + Math.min(0, dx), y0 + Math.min(0, dy), w, h,
0, 0, w, h);
downloadContainer.style.visibility = (w*h == 0 ? 'hidden' : 'visible');
downloadContainer.style.top = Math.min(y0, y) + 'px';
}
};
update(event);
selectCanvas.onmousemove = update;
document.onmouseup = function (event) {
selectCanvas.onmousemove = undefined;
document.onmouseup = undefined;
targetImage.src = clipCanvas.toDataURL();
targetImage.style.display = 'block';
};
};
};
body, div, canvas, img {
margin: 0;
padding: 0;
}
#targetImage {
display: none;
position: absolute;
left: 0;
top: 0;
}
canvas {
display: block;
}
#oldCanvas, #selectCanvas, #downloadContainer {
position: fixed;
}
#downloadContainer {
visibility: hidden;
}
#downloadContainer .label {
position: absolute;
width: 500px;
bottom: -20px;
font-family: sans-serif;
font-size: 17px;
color: #444;
}
#selectCanvas {
opacity: 0.5;
cursor: default;
}
<canvas id="oldCanvas"></canvas>
<canvas id="selectCanvas"></canvas>
<div id="downloadContainer">
<div class="label"> right-click above to download this image </div>
<img id="targetImage">
</div>

Categories

Resources