How to rotate dynamic text from input in Canvas and JS? - javascript

I'm working on a box styling project with Canvas and Javascript, and I can't rotate the text the way I want (written from bottom to the top).
(source: hostpic.xyz)
I followed a tutorial (https://newspaint.wordpress.com/2014/05/22/writing-rotated-text-on-a-javascript-canvas/) and tried to adapt it in my code, but I couldn't make it.
You can find the code on the JSFiddle link below, there's an input where you can type your text and it should be written as the "brand" word in the JSFiddle example.
https://jsfiddle.net/ParkerIndustries/mgne9x5u/5/
Everything is in the init() function:
function init() {
var elem = document.getElementById('elem');
var circle_canvas = document.createElement("canvas");
var context = circle_canvas.getContext("2d");
var img = new Image();
img.src = "https://unblast.com/wp-content/uploads/2018/11/Vertical-Product-Box-Mockup-1.jpg";
context.drawImage(img, 0, 0, 500, 650);
circle_canvas.width = 500;
circle_canvas.height = 650;
context.fillStyle = "#000000";
//context.textAlign = 'center';
var UserInput = document.getElementById("UserInput");
context.save();
context.translate( circle_canvas.width - 1, 0 );
UserInput.oninput = function() {
context.clearRect(0, 0, 500, 650);
context.drawImage(img, 0, 0, 500, 650);
var text = UserInput.value;
console.log(text);
if (text.length < 12) {
context.rotate(3*Math.PI/2);
console.log("-12");
context.font = "50px Righteous";
context.fillText(text, -350, -170);
context.restore();
} else {
context.rotate(3*Math.PI/2);
context.font = "25px Righteous";
context.fillText(text, -350, -170);
context.restore();
}
}
elem.appendChild(circle_canvas);
}
init();
I tried a lot a values in the context.rotate() function but in any way my text is upside down.
(source: hostpic.xyz)

You're pretty close here. I suggest performing the canvas translation to the middle of the screen (width / 2, height / 2) and then rotating by 270 degrees:
context.translate(canvas.width / 2, canvas.height / 2);
context.rotate(270 * Math.PI / 180);
Beyond that, I recommend a round of code cleanup to avoid inconsistent variable names and hardcoded numbers (try to make everything proportional to img.width and img.height, then avoid literal values. This makes it easier to adjust your code dynamically without having to re-type all of the values. You can access img.width and img.height after the img.onload function fires.
Another useful function is context.measureText(text), which makes it simpler to proportionally scale text size.
Full example:
function init() {
var userInput = document.getElementById("user-input");
var elem = document.getElementById("elem");
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
var img = new Image();
img.onload = function () {
canvas.width = img.width / 3;
canvas.height = img.height / 3;
context.drawImage(img, 0, 0, canvas.width, canvas.height);
context.fillStyle = "#000000";
context.textAlign = "center";
elem.appendChild(canvas);
userInput.oninput = function () {
var text = userInput.value;
var textSizePx = 50 - context.measureText(text).width / 10;
context.font = textSizePx + "px Righteous";
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, 0, 0, canvas.width, canvas.height);
context.save();
context.translate(canvas.width / 2, canvas.height / 2);
context.rotate(270 * Math.PI / 180);
context.fillText(text, 0, -canvas.width / 20);
context.restore();
}
};
img.src = "https://unblast.com/wp-content/uploads/2018/11/Vertical-Product-Box-Mockup-1.jpg";
}
init();
<div id="elem">
<input type="text" id="user-input" maxlength="15">
</div>
With that proof-of-concept working, one problem is that scaling the image on canvas causes visual artifacts. This problem can be overcome with JS or by scaling down the source image itself, but at this point, it's best to make the image as an element and circumvent the entire problem.
Similarly, there's no obvious reason to render text on canvas either; we can make an element for this as well. Moving text to HTML/CSS gives more power over how it looks (I didn't do much with style here, so it's an exercise to make it blend more naturally into the image).
Here's a rewrite without canvas that looks much cleaner and should be more maintainable:
function init() {
var userInput = document.querySelector("#user-input");
var img = document.querySelector("#product-img");
var imgRect = img.getBoundingClientRect();
var overlayText = document.querySelector("#overlay-text");
var overlay = document.querySelector("#overlay");
overlay.style.width = (imgRect.width * 0.86) + "px";
overlay.style.height = imgRect.height + "px";
userInput.addEventListener("input", function () {
overlayText.innerText = userInput.value;
overlayText.style.fontSize = (50 - userInput.value.length * 2) + "px";
});
}
init();
#product-img {
position: absolute;
}
#overlay {
position: absolute;
display: flex;
}
#overlay-text {
font-family: Verdana, sans-serif;
color: #333;
transform: rotate(270deg);
margin: auto;
cursor: default;
}
<div>
<input type="text" id="user-input" maxlength="15">
</div>
<div id="product-container">
<img id="product-img" src="https://unblast.com/wp-content/uploads/2018/11/Vertical-Product-Box-Mockup-1.jpg" width=666 height=500 />
<div id="overlay">
<div id="overlay-text"></div>
</div>
</div>

Related

How do I make a color invisible in a canvas using javascript

I am making a clicker game where you click on a potato for stonks. I have this code:
var canvas, canvasContext, imgaeAssets;
window.onload = function() {
canvas = document.getElementById('gaming');
canvasContext = canvas.getContext('2d');
canvasContext.canvas.width = window.innerWidth;
canvasContext.canvas.height = window.innerHeight * 0.95;
setInterval(mainloop, 1000 / 50);
}
var potatoes = 0;
var potatoClick = new Image();
potatoClick.src = 'images/potato.jfif'
function mainloop() { // runs once every second
colorRect(0, 0, canvas.width, canvas.height, 'black')
canvasContext.font = "15px Comic Sans MS";
canvasContext.fillStyle = "white";
canvas.style.backgroundColor = 'rgba(255, 255, 255, 0)';
drawImg(potatoClick, 0, (canvas.height / 2) - 125, 500, 250)
if (potatoes > 0) {
canvasContext.fillText(`you have ${potatoes} potatoes`, 0, 30);
}
}
function colorRect(x, y, w, h, c) {
canvasContext.fillStyle = c;
canvasContext.fillRect(x, y, w, h);
}
function drawImg(src, x, y, w, h) {
canvasContext.drawImage(src, x, y, w, h);
}
function printMousePos(event) {}
I want to make the white in potatoClick transparent, but I can't figure out how. I've already tried assigning an alpha to it, and have also tried changing the opacity of the image, but neither have worked. If you could figure out how to make any color transparent, I would appreciate it. I wouldn't mind needing to change the way to draw the potato, but I think it would be cleaner and easier the way I have it now.
edit: I think my question was fundamentally flawed, sorry for the confusion
After drawing things at canvas, you can't edit them anymore.
Because, Image in canvas doesn't have any parameters after draw it.
It means if you want to edit image on canvas, you need to clear your canvas when the difference is occurred.
and if you want to change the image opacity you should set globalAlpha of ctx (draw image with opacity on to a canvas)
Usually, I use Fabric.js(http://fabricjs.com/) for solve that problem.
but If you want, you can make a your own renderer by defining simple class.
like this!
<body>
<img id="dog" src="https://cdn.pixabay.com/photo/2022/07/19/10/35/puppies-7331739__340.jpg">
<img id="woman" src="https://cdn.pixabay.com/photo/2021/05/04/20/57/woman-6229693__340.jpg">
<canvas id="canvas" width="500" height="500" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
var canvas;
var ctx;
var img;
window.onload = function () {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
dog = document.getElementById("dog");
woman = document.getElementById("woman");
const exam1 = new Image(dog);
const exam2 = new Image(woman);
images = [];
images.push(exam1);
images.push(exam2);
render(images);
dog.onclick = function () {
exam1.opacity = 0.7;
exam2.opacity = 0.3;
exam1.y += 10;
exam2.x += 10;
render(images);
}
}
function render(images) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < images.length; i++) {
images[i].render();
}
}
function Image(original) {
this.image = original;
this.width = this.image.width;
this.height = this.image.height;
this.opacity = 1.0;
this.x = 0;
this.y = 0;
}
Image.prototype.render = function () {
this.image.width = this.width;
this.image.height = this.height;
ctx.globalAlpha = this.opacity;
ctx.drawImage(this.image, this.x, this.y);
ctx.globalAlpha = 1.0;
}
</script>
</body>

Clear canvas on window resize

I am trying to reset my progress ring, which is drawn with canvas on resize.
Currently, when I resize my window the function is run again as expected, but instead of the canvas being reset another progress ring is being drawn within the same canvas, please see screenshot below:
I have found clearRect() found in an answer here: How to clear the canvas for redrawing and similar solutions but it doesn't seem to resolve my issue.
Please find my codepen with the code: https://codepen.io/MayhemBliz/pen/OJQyLbN
Javascript:
// Progress ring
function progressRing() {
const percentageRings = document.querySelectorAll('.percentage-ring');
for (const percentageRing of Array.from(percentageRings)) {
console.log(percentageRing.offsetWidth)
var percentageRingOptions = {
percent: percentageRing.dataset.percent,
size: percentageRing.offsetWidth,
lineWidth: 30,
rotate: 0
}
var canvas = document.querySelector('.percentage-ring canvas');
var span = document.querySelector('.percentage-ring span');
span.textContent = percentageRingOptions.percent + '%';
if (typeof (G_vmlCanvasManager) !== 'undefined') {
G_vmlCanvasManager.initElement(canvas);
}
var ctx = canvas.getContext('2d');
//clear canvas for resize
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.beginPath();
// end clear canvas
canvas.width = canvas.height = percentageRingOptions.size;
percentageRing.appendChild(span);
percentageRing.appendChild(canvas);
ctx.translate(percentageRingOptions.size / 2, percentageRingOptions.size / 2); // change center
ctx.rotate((-1 / 2 + percentageRingOptions.rotate / 180) * Math.PI); // rotate -90 deg
//imd = ctx.getImageData(0, 0, 240, 240);
var radius = (percentageRingOptions.size - percentageRingOptions.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', percentageRingOptions.lineWidth, 100 / 100);
var i = 0; var int = setInterval(function () {
i++;
drawCircle('#555555', percentageRingOptions.lineWidth, i / 100);
span.textContent = i + "%";
if (i >= percentageRingOptions.percent) {
clearInterval(int);
}
}, 50);
}
}
window.addEventListener('load', progressRing);
window.addEventListener('resize', progressRing);
HTML:
<div class="percentage-ring" data-percent="88">
<span>88%</span>
<canvas></canvas>
</div>
Your help would be greatly appreciated.
Thanks in advance
1. Clear size problem
var canvas = document.querySelector('.percentage-ring canvas');
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
You have to specify canvas size with (canvas.width, canvas.height) instead of ctx.canvas.width, ctx.canvas.height
ctx.clearRect(0, 0, canvas.width, canvas.height);
2. Interval timer usage problem
If progressRing() is called again after setInterval() without clearInterval(), e.g., due to resizing, it will continue to run with the previous interval execution surviving. This will cause the ring to be drawn twice, thrice and more.
Place var int = 0; outside functions. This initializes the int to 0 first.
And modify var int = setInterval( to int = setInterval(
Then place the following code at the beginning of progressRing()
if (int) {
clearInterval(int);
int = 0;
}
And also place int = 0; immediately after the clearInterval() call that was already there.

How to render custom font in HTML5 canvas? [duplicate]

This question already has an answer here:
How to render icon fonts on HTML canvas and Material Design icon fonts in particular?
(1 answer)
Closed 2 years ago.
I saw a code pen here for rendering Microsoft Fabric UI Icons in a canvas in code pen. This is the working link
https://codepen.io/joshmcrty/pen/GOBWeV
There is a lot of extra stuff here to customize it. So I attempted to minimize this to barebones. What I did is completely remove the css, change the HTML to just the canvas tag, and reduced the JS code. The result looks like this:
HTML
<canvas id="canvas" width="92" height="92"></canvas>
CSS
/*none*/
JS
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
function getFontIconCharacter(className, pseudo = ':before') {
var testI = document.createElement('i');
var char;
testI.className = `ms-Icon ms-Icon--${className}`;
document.body.appendChild(testI);
char = window.getComputedStyle(testI, pseudo).getPropertyValue('content').replace(/'|"/g, '');
testI.remove();
return char;
}
function drawRect() {
context.fillStyle = "#777777";
context.fillRect(0, 0, canvas.width, canvas.height);
}
function drawIcon() {
context.clearRect(0, 0, canvas.width, canvas.height);
drawRect();
context.fillStyle = "#FFFFFF";
let fontClass = "Contact",
fontSize = 56,
topOffset = 46,
leftOffset = 46;
context.font = fontSize + "px FabricMDL2Icons";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText(getFontIconCharacter(fontClass), parseInt(leftOffset, 10), parseInt(topOffset, 10));
}
window.addEventListener('load', function() {
drawIcon();
});
The weird thing is if I replace the code from the working example into the above, the custom font in the canvas still renders correctly. However if I recreate it on a new file, it does not render the font properly. I saved my attempt here
HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Fabric UI Icons</title>
<link rel="stylesheet" href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/11.0.0/css/fabric.min.css">
</head>
<body>
<canvas id="canvas" width="92" height="92"></canvas>
<script>
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
function getFontIconCharacter(className, pseudo = ':before') {
var testI = document.createElement('i');
var char;
testI.className = `ms-Icon ms-Icon--${className}`;
document.body.appendChild(testI);
char = window.getComputedStyle(testI, pseudo).getPropertyValue('content').replace(/'|"/g, '');
testI.remove();
return char;
}
function drawCircle() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = canvas.width / 2;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = "#777777";
context.fill();
}
function drawRect() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.fillStyle = "#777777";
context.fillRect(0, 0, canvas.width, canvas.height);
}
function drawIcon() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.clearRect(0, 0, canvas.width, canvas.height);
drawRect();
context.fillStyle = "#ffffff"; // icon color
let fontClass = "Contact",
fontSize = 56,
topOffset = 46,
leftOffset = 46;
context.font = fontSize + "px FabricMDL2Icons";
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText(getFontIconCharacter(fontClass), parseInt(leftOffset, 10), parseInt(topOffset, 10));
}
window.addEventListener('load', function() {
drawIcon();
});
</script>
</body>
</html>
I noticed they include a css file to the font, so I have that as well, but it still doesn't work.
Does anyone see what is wrong?
Thanks
I figured it out, I had to start the font loading process with this. Just because it's defined in a <link> tag doesn't mean it will start loading. Something needs to reference it before its used on the canvas for the browser to load it.
<style>
body {
font-family: FabricMDL2Icons;
}
</style>

Pixelated resize using canvas with transparent PNG

I want to accomplish a pixelated effect using the canvas option imageSmoothingEnabled=false; so the image "unblurs" on scroll.
Everything works fine until using transparent images namely PNGs. The scaled image is projected, which stays in the background.
Also the image does not get loaded until the user has scrolled a few pixels.
I've found out that the canvas.drawImage() function owns parameters to set the offset. However I haven't found a solution to this.
Demo https://jsfiddle.net/aLjfemru/
var ctx = canvas.getContext('2d'),
img = new Image(),
play = false;
/// turn off image smoothing - this will give the pixelated effect
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
/// wait until image is actually available
img.onload = function(){
image1.src="nf.png";
context.drawImage(image1, 50, 50, 10, 10);
};
img.src = 'https://upload.wikimedia.org/wikipedia/commons/b/bb/Gorgosaurus_BW_transparent.png';
/// MAIN function
function pixelate(v) {
document.getElementById("v").innerHTML = "(v): " + v;
/// if in play mode use that value, else use slider value
var size = v * 0.01;
var w = canvas.width * size;
var h = canvas.height * size;
/// draw original image to the scaled size
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0, w, h);
ctx.drawImage(canvas, 0, 0, w, h, 0, 0, canvas.width, canvas.height);
}
function onScroll() {
$(window).on('scroll', function() {
var y = window.pageYOffset;
if (y > 10) {
y = Math.pow(y, 0.8);
if (y >= 60) {
y = 100;
}
pixelate(y);
}
});
}
onScroll();
Some quick changes to get it happening
Use a second canvas to do the pixelation
Wait for the images to load before doing the rendering.
The onscroll will not fire until you scroll, so when image has loaded call the rendering function to display the image.
canvas.width = innerWidth-20;
ctx = canvas.getContext("2d");
var ctxImage;
const img = new Image;
img.src = 'https://upload.wikimedia.org/wikipedia/commons/b/bb/Gorgosaurus_BW_transparent.png';
/// wait until image is actually available
img.onload = function(){
// I dont knwo what this is for so removed the following two lines
//image1.src="nf.png";
//context.drawImage(image1, 50, 50, 10, 10);
// Create a canvas to match the image
var c = document.createElement("canvas");
canvas.width = Math.min(canvas.width,(c.width = this.naturalWidth));
canvas.height = c.height = this.naturalHeight;
ctxImage = c.getContext("2d");
// changing canvas size resets the state so need to set this again.
ctx.imageSmoothingEnabled = false;
onScroll();
pixelate(100); // call first time
};
ctx.font = "32px arial";
ctx.textAlign = "center";
ctx.fillText("Loading please wait.",ctx.canvas.width /2, ctx.canvas.height / 4);
/// MAIN function
function pixelate(v) {
document.getElementById("v").innerHTML = "(v): " + v;
/// if in play mode use that value, else use slider value
var size = Number(v) * 0.01;
var w = img.width * size;
var h = img.height * size;
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctxImage.clearRect(0, 0, ctxImage.canvas.width, ctxImage.canvas.height);
ctxImage.drawImage(img, 0, 0, w, h);
ctx.drawImage(ctxImage.canvas, 0, 0, w, h, 0, 0, canvas.width, canvas.height);
}
function onScroll() {
addEventListener("scroll", function() {
var y = window.pageYOffset;
if (y > 10) {
y = Math.pow(y, 0.65);
if (y >= 100) {
y = 100;
}
pixelate(y);
}
});
}
#fix {
position: fixed;
}
html {
height: 2000px;
}
<div id="fix">
<p id="v" value="Animate">1</p><br />
<canvas id="canvas"></canvas>
</div>
This has since been made into an extremely minimalist library, and my PR for PNG support can be found here.
Once it has been merged I will come back and update this answer.
The full code, generalized and simplified from #Blindman67's answer:
/**
* 8bit
*
* A module that converts an image into a pixelated version (just like
* 8bit artwork).
*
* #author rogeriopvl <https://github.com/rogeriopvl>
* #license MIT
*/
(function (root, factory) {
if (typeof define === "function" && define.amd) {
define([], factory);
} else if (typeof exports === "object") {
module.exports = factory();
} else {
root.eightBit = factory();
}
} (this, function () {
// Necessary to hide the original image with PNG transparency
const invisibleCanvas = document.createElement("canvas");
const invisibleCtx = invisibleCanvas.getContext("2d");
/**
* Draws a pixelated version of an image in a given canvas.
* #param {object} canvas - a canvas object
* #param {object} image - an image HTMLElement object
* #param {number} quality - the new quality: between 0 and 100
*/
const eightBit = function (canvas, image, quality) {
quality /= 100;
canvas.width = invisibleCanvas.width = image.width;
canvas.height = invisibleCanvas.height = image.height;
const scaledW = canvas.width * quality;
const scaledH = canvas.height * quality;
const ctx = canvas.getContext("2d");
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
// Draws image scaled to desired quality on the invisible canvas, then
// draws that scaled image on the visible canvas.
ctx.clearRect(0, 0, canvas.width, canvas.height);
invisibleCtx.clearRect(0, 0, invisibleCtx.canvas.width, invisibleCtx.canvas.height);
invisibleCtx.drawImage(image, 0, 0, scaledW, scaledH);
ctx.drawImage(invisibleCtx.canvas, 0, 0, scaledW, scaledH, 0, 0, canvas.width, canvas.height);
};
return eightBit;
}));

Resize an image with javascript for use inside a canvas createPattern

I've seen a few tricks on how you resize an image you want to
use inside an IMG-tag but I want to have an image variable inside
a Javascript, resize it and then use the image inside a
context.createPattern(image, "repeat"). I have not found any hint
on how to do that.
You can find a functional demo at http://karllarsson.batcave.net/moon.html
with images on what I want to do.
The solution from Loktar looks good. I haven't had the time yet to fix the
correct aspect but now I know how to do it. Thank you once again. Here is an
working demo http://karllarsson.batcave.net/moon2.html
This is the two lines I don't get to work as I want them too.
image.width = side * 2;
image.height = side * 2;
function drawShape() {
try {
var canvas = document.getElementById('tutorial');
var image = new Image();
image.src = "http://xxx.yyy.zzz/jjj.jpg";
image.width = side * 2;
image.height = side * 2;
if (canvas.getContext){
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = ctx.createPattern(image, "repeat");
ctx.beginPath();
var centerX = canvas.width / 2 - side / 2;
var centerY = canvas.height / 2 - side / 2;
ctx.rect(centerX, centerY, side, side);
ctx.fill();
} else {
alert('You need Safari or Firefox 1.5+ to see this demo.');
}
} catch (err) {
console.log(err);
}
}
What you can do is make a temporary canvas, and copy the image to it with the dimensions you require, and then use that temporary canvas as the pattern rather than the image itself.
Live Demo
First create the canvas
var tempCanvas = document.createElement("canvas"),
tCtx = tempCanvas.getContext("2d");
tempCanvas.width = side*2;
tempCanvas.height = side*2;
Now draw the image to it, making the the scaled size you require
tCtx.drawImage(image,0,0,image.width,image.height,0,0,side*2,side*2);
And now use the canvas you just created as the pattern
ctx.fillStyle = ctx.createPattern(tempCanvas, "repeat");
Full code
edit created a more generic reusable example
function drawPattern(img, size) {
var canvas = document.getElementById('canvas');
canvas.height = 500;
canvas.width = 500;
var tempCanvas = document.createElement("canvas"),
tCtx = tempCanvas.getContext("2d");
tempCanvas.width = size;
tempCanvas.height = size;
tCtx.drawImage(img, 0, 0, img.width, img.height, 0, 0, size, size);
// use getContext to use the canvas for drawing
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = ctx.createPattern(tempCanvas, 'repeat');
ctx.beginPath();
ctx.rect(0,0,canvas.width,canvas.height);
ctx.fill();
}
var img = new Image();
img.src = "http://static6.depositphotos.com/1070439/567/v/450/dep_5679549-Moon-Surface-seamless.jpg";
img.onload = function(){
drawPattern(this, 100);
}
There is another way, which worked great for me:
const ctx: CanvasRenderingContext2D;
const patternAsBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpGRjIyRTA3RDgyNkUxMUU5ODQ1QUM2QjE5RUMzRTMwRCIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpGRjIyRTA3RTgyNkUxMUU5ODQ1QUM2QjE5RUMzRTMwRCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkZGMjJFMDdCODI2RTExRTk4NDVBQzZCMTlFQzNFMzBEIiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkZGMjJFMDdDODI2RTExRTk4NDVBQzZCMTlFQzNFMzBEIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+y2y13AAAAV1JREFUeNqc0kFLAkEUB/B9b1ZR1m4FQZeocx2MYI3CxC8QmVBfJAjqVLQQfY/MFI+dREpQIeqQxwgiCrq72661M9Nb0ZKo3dU5zOU//Hj/3Qep04YUn04Ludxq7mdflYCzfFKbprdnLKatc9u8Z1zZbBxkHwc58q79gpGYLgBKqaPqTBB4s5t5Ewx2XNu8YvHEImeysnJYnf8GoyCz/MO+ZXFN56iUw6JSxW333SJ0YoEzpbJq1Oe8DLxLN2qzQoqSGkss8a41Un1wZUGNa2mq346A3IBB6KGSUOahdqeFEsZAO20YDnXjktDomKgoUMM0/A6HJ3UJZSNOCn+FPVSIMv3FpOuYTSaUfGj0v/AH1ZLcsZoYEgW/sF+/TPUJNUOh6Be29jJPAJijlbgjNEV7ehG0p6CEOIP62K/v900xXyyyILA3KWJO2FbgpPj8MHm+dnw9FRp1/Ot/CTAAd/XmF3ta0fUAAAAASUVORK5CYII=';
const imagePattern = new Image();
imagePattern.onload = () => {
const pattern: CanvasPattern = ctx.createPattern(imagePattern, 'repeat-y');
const svgMatrix: SVGMatrix = document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGMatrix();
svgMatrix.scale(0.5);
pattern.setTransform(svgMatrix);
}
imagePattern.src = patternAsBase64;
Basically the same as setting the transform matrix to this (the following down under) (But attention! patterns setTransform method awaits a SVGMatrix.
This did still work for me, too in Chrome (But TypeScript complained of course):
pattern.setTransform({
a: 0.5, // Horizontal scaling. A value of 1 results in no scaling.
b: 0, // Vertical skewing.
c: 0, // Horizontal skewing.
d: 0.5, // Vertical scaling. A value of 1 results in no scaling.
e: 0, // Horizontal translation (moving).
f: 0 // Vertical translation (moving).
// https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/transform
});
Keep in mind, that you also maybe need to translate your canvas before drawing the pattern, otherwise it could not start where you want it to start to.
const offset_x: number = positionXOfElement;
const offset_y: number = positionYOfElement;
// offset
ctx.translate(offset_x, offset_y);
// draw
ctx.fillStyle = pattern;
roundRect.fill();
//ctx.fillRect(0, 0, 300, 300);
// undo offset
ctx.translate(-offset_x, -offset_y);
Here is another way to resize pattern on image with range button.
var img1 = new Image, img2 = new Image, cnt = 2,
canvas = document.getElementById("canvas"),
canvas_original = document.getElementById("canvas_original"),
ctx_original = canvas_original.getContext("2d"),
ctx = canvas.getContext("2d");
img1.onload = img2.onload = function() {if (!--cnt) go()};
img1.src = "https://www.itailor.co.uk/images/product/shirt/it1823-1.png"; // shirt
img2.src = "https://i.stack.imgur.com/tkBVh.png"; // pattern
function go(source = null) {
canvas.width = document.getElementById("first").clientWidth;
canvas.height = window.innerHeight / 2;
canvas_original.width = document.getElementById("second").clientWidth;
canvas_original.height = window.innerHeight / 2;
var oc = document.createElement('canvas'), octx = oc.getContext('2d');
var cur = {
width: Math.floor(img1.width * 0.5),
height: Math.floor(img1.height * 0.5)
}
oc.width = cur.width;
oc.height = cur.height;
octx.drawImage(img1, 0, 0, cur.width, cur.height);
while (cur.width * 0.5 > document.getElementById("first").clientWidth) {
cur = {
width: Math.floor(cur.width * 0.5),
height: Math.floor(cur.height * 0.5)
};
octx.drawImage(oc, 0, 0, cur.width * 2, cur.height * 2, 0, 0, cur.width, cur.height);
}
ctx_original.drawImage(oc, 0, 0, cur.width, cur.height, 0, 0, canvas.width, canvas.height);
//****//
var rate = $('#rate').val();
var tempCanvas = document.createElement("canvas"),
tCtx = tempCanvas.getContext("2d");
tempCanvas.width = canvas.width / 4 * rate;
tempCanvas.height = canvas.height / 4 * rate;
tCtx.drawImage(img2, 0, 0, img2.width, img2.height, 0, 0, tempCanvas.width, tempCanvas.height);
//****//
if (source !== null) {
ctx.fillStyle = ctx.createPattern(tempCanvas, "repeat");
}
else {
ctx.fillStyle = ctx.createPattern(tempCanvas, "repeat");
}
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "multiply";
ctx.drawImage(oc, 0, 0, cur.width, cur.height, 0, 0, canvas.width, canvas.height);
ctx.globalCompositeOperation = "destination-in";
ctx.drawImage(oc, 0, 0, cur.width, cur.height, 0, 0, canvas.width, canvas.height);
}
HTML Markup
<div class="container" style="width: 100%; padding-right: 0 !important; padding-left: 0 !important;">
<div id="clothesDiv" class="col-lg-2" style="max-height: 100vh; overflow-y: auto;">
</div>
<div class="col-lg-10">
<div class="row" style="margin-right: 0 !important; margin-left: 0 !important; border: 0.5px solid black;">
<div id="first" class="col-lg-6" style="padding-right: 0 !important; padding-left: 0 !important;">
<canvas id="canvas_original"></canvas>
</div>
<div id="second" class="col-lg-6" style="padding-right: 0 !important; padding-left: 0 !important;">
<canvas id="canvas"></canvas>
</div>
</div>
<div class="row" style="margin-right: 0 !important; margin-left: 0 !important;">
<div class="col-lg-offset-3 col-lg-6">
<p class="text-center">Desen Ölçeklendirme</p>
<input id="rate" type="range" min="1" max="4" value="4" onchange="resizePattern()"/>
</div>
</div>
And function
function resizePattern() {
go();
}
You can tweak it to see different results.

Categories

Resources