Image in Canvas get cropped only on chrome - javascript

I am using PIXIjs to draw and modify large size Image! for large size image the image get cropped as following:
but on firefox is totally okay:
I saw something as following on DEVtool-chrome that I think it might be reason for this and tried to override this but does not work:
I would like to have the full image as firefox on chrome as well!
here is js:
private drawImage(): void {
PIXI.Loader.shared.reset();
const frame = document.querySelector('#frame');
const url = this.urlInputImage;
this.removeAllChildNodes(frame);
const app = new PIXI.Application({
backgroundColor: 0xffffff,
});
const container = new PIXI.Container();
app.stage.interactive = true;
app.stage.on('rightclick', e =>{
this.contextmenuClick.emit(e);
this.rightClick(e);
});
const graphics = new PIXI.Graphics();
this.detectedPositions.forEach((detectedInfo) => {
const boundingBox = detectedInfo['boundingBox'];
graphics.lineStyle(/*border width*/5,/*border color*/ PIXI.utils.string2hex(detectedInfo['detectionBoxesHexColor']), 1);
const points = Object.keys(boundingBox).map(function(boundingBoxIndex){
return boundingBox[boundingBoxIndex];
});
const pointsFiltered = points.filter((point) => {
return point !== null;
});
graphics.drawPolygon(pointsFiltered);
graphics.endFill();
});
PIXI.Loader.shared
.add('layout',url)
.load(setup);
function setup() {
const pic = new PIXI.Sprite(PIXI.Loader.shared.resources.layout.texture);
const border = new PIXI.Graphics();
const borderWidth = 5;
const borderColor = 1261722;
border.lineStyle(borderWidth, borderColor);
border.drawRect(app.stage.x , app.stage.y , pic.width , pic.height );
container.addChild(pic);
container.addChild(border);
container.addChild(graphics);
app.stage.addChild(container);
const w = pic.width;
const h = pic.height;
app.renderer.view.style.width = w + "px";
app.renderer.view.style.height = h + "px";
//this part adjusts the ratio:
app.renderer.resize(w, h);
}
frame.appendChild(app.view);
PIXI.BaseTexture.removeFromCache('layout');
}
here is the css:
:host {
display: block;
}
canvas {
background-color: white;
}
#frame {
overflow: auto;
background-color: white;
height: 450px;
width: auto;
}`
here is html
<div id="frame"></div>

Related

How to remove the ghost image of a PNG? (or the white backgorund of the ghost image)

I am a Beginner Developer and am working on a personal chess project.
I just learned how to create a drag and drop system, maybe I could learn other ways of doing It but I would like to know if there's any way to 'remove' the white background.
I don't know really how this should work but I had some ideas:
Somehow remove the white background of the ghost image.
Substitute the ghost image with the actual image being dragged.
Or just entirely remove the ghost image while dragging since we can see the piece in each square when you are dragging over it.
If it's possible to do any of these solutions it would be good!
Here is the link for the project I am working: https://codepen.io/ThalisonAmaral/full/qBYZmZq
You will be probably dealing with the function dragstart();
`
function dragstart() {
squaresDrop.forEach(square => square.classList.add('highlight'))
this.classList.add('is-dragging');
}
`
The Drag and Drop is at the end of the Js Code
Since I don't understand what I am dealing with exactly.
I searched for some possible solutions but I couldn't get any result with
DataTransfer.setDragImage().
Which I think it should be using for replacing the ghost image with an actual image but I would need to check each piece, It doesn't seem to be the way but I could be wrong.
The easiest way of doing this is by setting the opactiy of the image to 0 when you start dragging it and setting it back to 1 when dropping.
I added this.style.opacity = 0; on line 105
and this.style.opacity = 1; on line 11
Hopefully this is what you want!
/* ------- BOARD GENERATOR -------*/
const body = document.body;
const $addClass = (element,className) => {
element.classList.add(className);
};
const $setId = (element,idName)=>{element.setAttribute('id',idName)}
const $createSquare = (element,squareColor,board)=> {
element = document.createElement('div');
$addClass(element,squareColor)
$addClass(element,'square');
board.appendChild(element)
};
const $createBoardBorder = (where) => {
var board = document.createElement('div');
$addClass(board,'board');
where.appendChild(board)
}
var coordinates = [
'a8','b8','c8','d8','e8','f8','g8','h8',
'a7','b7','c7','d7','e7','f7','g7','h7',
'a6','b6','c6','d6','e6','f6','g6','h6',
'a5','b5','c5','d5','e5','f5','g5','h5',
'a4','b4','c4','d4','e4','f4','g4','h4',
'a3','b3','c3','d3','e3','f3','g3','h3',
'a2','b2','c2','d2','e2','f2','g2','h2',
'a1','b1','c1','d1','e1','f1','g1','h1'
];
function createBoard(size,lightColor,darkColor,where){
/* CREATING A DIV WITH A CLASS 'board' */
$createBoardBorder(where);
/* SELECTING THE BOARD */
var board = document.querySelector('.board');
/* GENERATING ALL THE SQUARES AND PUTTING THEM INTO THE BOARD */
var light = 'light'; var dark = 'dark';
for (let i = 0; i < 32; i++) {
$createSquare(coordinates,light,board);
$createSquare(coordinates,dark,board);
if((i+1)%4 === 0 ){
var x = light;
light = dark;
dark = x;
}
}
const squares = document.querySelectorAll('.square');
/*PUTTING ALL THE IDS IN EACH SQUARE */
for (let i = 0; i < squares.length; i++) {
$setId(squares[i],coordinates[i])
}
// ----- BOARD STYLE -----
const lightSquares = document.querySelectorAll('.light');
const darkSquares = document.querySelectorAll('.dark');
board.style.width = size+'px';
board.style.height = size+'px';
lightSquares.forEach((value,index)=>{
value.style.height = size/8+'px';
value.style.width = size/8+'px';
value.style.backgroundColor = lightColor;
darkSquares[index].style.height = size/8+'px';
darkSquares[index].style.width = size/8+'px';
darkSquares[index].style.backgroundColor = darkColor;
})
}
const boardzone = document.getElementById('boardzone');
createBoard(500,'white','rgb(64, 100, 145)',boardzone);
/*-------- PIECE RENDER --------*/
const king = document.createElement('img');
king.setAttribute('class','piece');
king.src = "https://images.chesscomfiles.com/chess-themes/pieces/neo/150/wk.png";
e1.appendChild(king)
/*-------- DRAG AND DROP --------*/
var audio = new Audio('sound.wav');
var pieces = document.querySelectorAll('.piece');
console.log(pieces);
var squaresDrop = document.querySelectorAll('.square');
pieceCheck = ()=> {
var pieces = document.querySelectorAll('.piece');
pieces.forEach(piece=>{
piece.addEventListener('dragstart',dragstart)
piece.addEventListener('drag',drag)
piece.addEventListener('dragend',dragend)
function dragstart() {
squaresDrop.forEach(square => square.classList.add('highlight'))
this.style.opacity = 0;
this.classList.add('is-dragging');
}
function drag(){
}
function dragend(){
this.style.opacity = 1;
this.classList.remove('is-dragging');
audio.play();
}
})}
pieceCheck(); //Checking if a new piece was added in the board
squaresDrop.forEach(square=>{
square.addEventListener('dragenter',dragenter);
square.addEventListener('dragover',dragover);
square.addEventListener('dragleave',dragleave);
square.addEventListener('drop',drop);
function dragenter(){
}
function dragover(){
this.classList.add('over')
//Get dragging piece
const draggedPiece = document.querySelector('.is-dragging');
this.appendChild(draggedPiece);
}
function dragleave(){
log('Leaving')
this.classList.remove('over')
}
function drop(){
}
})
body {
background-color:rgb(15,15,15);
}
.board {
display: grid;
grid-template-columns: repeat(8, 1fr);
}
#boardzone{
margin: 60px auto;
display: flex;
justify-content:center;
}
/* Drag and Drop CSS */
.piece {
height: 100%;
user-select: none;
}
.highlight {
background-color:rgba(14,14,14,0.2);
}
.is-dragging {
cursor:move;
opacity: 0.3;
transform: translate(0, 0);
}
.over{
background-color: rgba(173, 240, 118, 0.315);
}
<div id='boardzone'></div>

How to expose ctx from inside Webcomponent?

When I try to set the width and height of the canvas element in the draw function, it seems to be setting them on some canvas, but not the one I'm looking at. Upon inspection of the canvas with the border I defined in the webcomponent, you will see that it still has the standard dimensions instead of being resized.
I'd like to expose the ctx of the component for use outside of it. What am I doing wrong?
class Component extends HTMLElement {
constructor() {
super();
this.shadow = this.attachShadow({ mode: 'open' });
const canvasContainer = document.createElement('div');
canvasContainer.classList.add('canvas-container')
canvasContainer.innerHTML = `
<style>
.canvas-container {
width: 100%;
height: 100%;
}
canvas {
border: 1px solid black;
}
</style>
<canvas></canvas>
`;
this.shadow.appendChild(canvasContainer);
}
get ctx () {
return this.shadow.querySelector('canvas').getContext('2d');
}
}
customElements.define('canvas-component', Component);
const component = new Component();
const ctx = component.ctx;
const canvas = component.ctx.canvas;
const draw = () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
console.log(canvas);
window.requestAnimationFrame(draw);
}
draw();
html, body {
width: 100%;
height: 100%;
margin: 0;
}
<canvas-component></canvas-component>
repeating comment:
Why const component = new Component(); and not work with the
in the DOM? Those are 2 different objects and only
the latter is visible on your screen (which you do NOT change the size
of)
And you can shorten that code to:
<script>
customElements.define('canvas-component', class Component extends HTMLElement {
constructor() {
super().attachShadow({mode:'open'}).innerHTML = `
<style>canvas { width:100%;height:100%; border:1px solid black }</style>
<canvas></canvas>`;
}
get ctx(){
return this.shadowRoot.querySelector('canvas').getContext('2d');
}
size(w, h) {// also clears the whole canvas
this.ctx.canvas.width = w; this.ctx.canvas.height = h;
}
rect({x=10,y=x,w=20,h=w,l=2,c='red'}){
this.ctx.lineWidth = l;
this.ctx.strokeStyle = c;
this.ctx.strokeRect( x, y, w, h );
}
});
</script>
<canvas-component id="C1"></canvas-component>
<script>
onload = () => {
C1.size(innerWidth, innerHeight);
C1.rect({});
C1.rect({x:80,w:50});
C1.rect({x:50,w:150,c:'green',l:3});
}
</script>

How to change font color based on background image with javascript?

I want to change the font color based on the color of the image. The font color must be black or white, but it should change proportionally to the color of the image as it does in the code below.
So, I have this js function that if you move the mouse it changes the background color and consequently also the text (in the snippet move the pointer under the background). Obviously the part where you move the mouse to change color doesn't interest me, it's just a test. Is there a way to apply the function to my personal div?
In simple terms I want the color of the text to change based on my background and not if you move the mouse. Sorry for the poor explanation, I'm relatively new here, trying to learn how to exercise this function. Currently I don't know how to do it, I appreciate any answer, thanks.
function getTextColor(rgba){
rgba = rgba.match(/\d+/g);
if((rgba[0]*0.299)+(rgba[1]*0.587)+(rgba[2]*0.114)>186) {
return 'black';
} else {
return 'white';
}
}
var div = document.createElement('div');
div.style.height = '100vh';
document.body.appendChild(div);
div.addEventListener('mousemove', (event)=>{
var x = event.clientX;
var y = event.clientY;
div.textContent = `${x} , ${y}`;
div.style.backgroundColor = `rgba(${x},${y},100,100)`;
div.style.color = getTextColor(div.style.backgroundColor);
});
.background {
height: 100vh;
background: url("https://i.pinimg.com/originals/bc/a3/2d/bca32d5cdfabeaeb4faeb12bff160524.jpg");
}
<div class="background">Background example</div>
Explanation
Here is an example showing how to get the average using a canvas rendered to a 1x1-px scale. From there we set the header background and then apply a light or dark class based on the luminance of the aforementioned average.
Notes
Note 1:
There is some extra code to allow for easier visualization, this is commented and can be removed.
Note 2: The below code is not guaranteed to run on all browsers. Please see this thread for more specifics.
Note 3: This code only works with local images and CORS-enabled image URLs due to it's reliance on canvas.drawImage. Please see this for more information.
Example 1:
this example shows the functionality. It uses two image URLs in the JS to toggle between.
/*
THE TOGGLE ACTION
*/
/* The urls for toggling between */
const urlLight = 'https://images.unsplash.com/photo-1484503793037-5c9644d6a80a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=930&q=80';
const urlDark = 'https://images.unsplash.com/photo-1517999144091-3d9dca6d1e43?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=627&q=80';
let currentUrl = urlLight;
const toggle = document.getElementById('toggle');
toggle.addEventListener("click", function() {
if (currentUrl === urlLight) {
currentUrl = urlDark;
} else {
currentUrl = urlLight;
}
getImageBrightness(currentUrl, function(brightness) {
const header = document.getElementById("header");
header.style.backgroundImage = `url(${currentUrl}`;
header.classList.remove("dark");
header.classList.remove("light");
console.log(brightness);
if (brightness > 225 / 2) {
header.classList.toggle("dark");
} else {
header.classList.toggle("light");
}
});
});
/*
Important get brightness code
*/
function getImageBrightness(imageSrc, callback) {
var img = document.createElement("img");
img.src = imageSrc;
img.style.display = "none";
img.crossOrigin = "anonymous";
document.body.appendChild(img);
var colorSum = 0;
img.onload = function() {
// create canvas
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = imageData.data;
var r, g, b, avg;
for (var x = 0, len = data.length; x < len; x += 4) {
r = data[x];
g = data[x + 1];
b = data[x + 2];
avg = Math.floor((r + g + b) / 3);
colorSum += avg;
}
var brightness = Math.floor(colorSum / (this.width * this.height));
callback(brightness);
}
}
getImageBrightness(currentUrl, function(brightness) {
const header = document.getElementById("header");
header.style.backgroundImage = `url(${currentUrl}`;
header.classList.remove("dark");
header.classList.remove("light");
if (brightness > 225 / 2) {
header.classList.toggle("dark");
} else {
header.classList.toggle("light");
}
});
.dark {
color: black;
}
.light {
color: white;
}
* {
text-align: center;
}
#header {
padding: 2rem 0;
font-size: 4rem;
background-size: cover;
margin-bottom: 1rem;
background-position: center center;
}
<div id="header">
Header
</div>
<button id='toggle'>
Toggle Background
</button>
Example 2:
This example directly answers the question by retrieving the background image of the current div and running the function using said image.
/*
Important get brightness code
*/
function getImageBrightness(imageSrc, callback) {
var img = document.createElement("img");
img.src = imageSrc;
img.style.display = "none";
img.crossOrigin = "anonymous";
document.body.appendChild(img);
var colorSum = 0;
img.onload = function() {
// create canvas
var canvas = document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = imageData.data;
var r, g, b, avg;
for (var x = 0, len = data.length; x < len; x += 4) {
r = data[x];
g = data[x + 1];
b = data[x + 2];
avg = Math.floor((r + g + b) / 3);
colorSum += avg;
}
var brightness = Math.floor(colorSum / (this.width * this.height));
callback(brightness);
}
}
/* The element we wish to work on */
const header = document.getElementById("header");
/* To get the background image. Get style and then background image with a slice to remove quotes */
var imageElement = document.getElementById('header'),
style = imageElement.currentStyle || window.getComputedStyle(imageElement, false),
backgroundImage = style.backgroundImage.slice(4, -1).replace(/"/g, "");
getImageBrightness(backgroundImage, function(brightness) {
/* Remove dark and light classes from the element */
header.classList.remove("dark");
header.classList.remove("light");
/* check brightness and apply correct style */
/* Please modify the below brightness comparison statement to adjust to your needs */
if (brightness > 225 / 2) {
header.classList.toggle("dark");
} else {
header.classList.toggle("light");
}
});
.dark {
color: black;
}
.light {
color: white;
}
* {
text-align: center;
}
#header {
padding: 2rem 0;
font-size: 4rem;
background-size: cover;
margin-bottom: 1rem;
background-position: center center;
background-image: url('https://images.unsplash.com/photo-1530128118208-89f6ce02b37b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80')
}
<div id="header">
<h1>
Header
</h1>
</div>

Adjusting size of <canvas> to fit parent div while still maintaining draw functionality - help needed

import React, { useRef, useEffect, useState } from 'react';
import './app.css'
function App() {
const canvasRef = useRef(null)
const contextRef = useRef(null)
const divRef = useRef(null)
const [isDrawing, setIsDrawing] = useState(false)
useEffect(() => {
const canvas = canvasRef.current
canvas.width = divRef.clientWidth * 2;
canvas.height = divRef.clientHeight * 2;
canvas.style.width = `${divRef.clientWidth}px`;
canvas.style.height = `${divRef.clientHeight}px`;
const context = canvas.getContext("2d")
context.scale(2,2)
context.lineCap = "round"
//this line will provide the color - maybe change that to let users type in a color or click a color
context.strokeStyle = "black"
//here the line thickness is defined
context.lineWidth = 5
contextRef.current = context
}, [])
const startDrawing = ({nativeEvent}) => {
const {offsetX, offsetY} = nativeEvent
contextRef.current.beginPath()
contextRef.current.moveTo(offsetX, offsetY)
setIsDrawing(true)
}
const finishDrawing = () => {
contextRef.current.closePath()
setIsDrawing(false)
}
const draw = ({nativeEvent}) => {
if(!isDrawing){
return
}
const {offsetX, offsetY} = nativeEvent;
contextRef.current.lineTo(offsetX, offsetY)
contextRef.current.stroke()
}
return (
<div id="canvasDiv" ref={divRef}>
<canvas
onMouseDown={startDrawing}
onMouseUp={finishDrawing}
onMouseMove={draw}
ref={canvasRef}
/>
</div>
)
}
export default App
#canvasDiv {
width: 500px;
height: 500px;
border-style: solid;
border-width: 2px;
border-color: black;
}
#canvasDiv canvas {
width: 100%;
height: 100%;
}
Having trouble getting my draw application to work within the confines of the parent div. It does manage to resize the canvas but at the expense of the draw functionality no longer working. The code below is how it looks when it works using the entire view window as the canvas, but I am trying to implement it into a moveable window and need to be able to resize it.
const canvas = canvasRef.current
canvas.width = window.innerWidth * 2;
canvas.height = window.innerHeight * 2;
canvas.style.width = `${window.innerWidth}px`;
canvas.style.height = `${window.innerHeight}px`;

Fabric js fit image in given size without stretching

Hello i am working on online print application where we create some designs in FabricJS and then users can edit those designing replacing text and image with their own...everything is working perfect but we are facing an issue with image replace when users replace image we want it to fit in already present image on canvas also maintain aspect ratio..below is current code for replacing image but its does not not fit image if image is vertical.
o = activeCanvas.getActiveObject();
fabric.Image.fromURL(src, function(m) {
var i = m.set({
id: o.id,
left: o.left,
top: o.top,
width: m.width,
height: m.height
});
i.scaleToWidth(o.getScaledWidth());
activeCanvas.remove(o);
activeCanvas.add(i);
renderAppChange();
zoomoutIn(1);
setActiveNew(i);
});
From what I see, you want to scale your new image to fit the smallest of width and height dimensions of the old image:
const widthFactor = old.getScaledWidth() / newImg.width
const heightFactor = old.getScaledHeight() / newImg.height
const minFactor = Math.min(widthFactor, heightFactor)
newImg.scale(minFactor)
Here, scale() will preserve the aspect ratio.
And a snippet to test:
const canvas = new fabric.Canvas("c")
const url = "https://via.placeholder.com/100x50"
const url2 = "https://via.placeholder.com/50x100"
const url3 = "https://via.placeholder.com/100x100"
fabric.Image.fromURL(url, (img) => {
canvas.add(img)
}, {
left: 0,
top: 10,
})
fabric.Image.fromURL(url2, (img) => {
canvas.add(img)
}, {
left: 120,
top: 10,
})
fabric.Image.fromURL(url3, (img) => {
canvas.add(img)
}, {
left: 200,
top: 10,
})
function insertAndFit (imageURL) {
const o = canvas.getActiveObject();
if (!o) {
throw new Error('select an object first')
}
fabric.Image.fromURL(imageURL, function(m) {
m.set({
left: o.left,
top: o.top
})
const widthFactor = o.getScaledWidth() / m.width
const heightFactor = o.getScaledHeight() / m.height
const minFactor = Math.min(widthFactor, heightFactor)
m.scale(minFactor)
canvas.remove(o)
canvas.add(m)
})
}
document.getElementById('b1').onclick = () => {
insertAndFit("https://via.placeholder.com/100x300")
}
document.getElementById('b2').onclick = () => {
insertAndFit("https://via.placeholder.com/300x100")
}
document.getElementById('b3').onclick = () => {
insertAndFit("https://via.placeholder.com/200x200")
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.2/fabric.js"></script>
<canvas id='c' width="400" height="200"></canvas>
<button id='b1'>insert 100x300</button>
<button id='b2'>insert 300x100</button>
<button id='b3'>insert 200x200</button>

Categories