I tried pretty much everything I could find on the google and still can't get the solution in canvas.
Because the zoom affects positioning differently in different browsers, I want to use CSS 2d translate() will typically provide better FPS than position: absolute top & left.
https://jsfiddle.net/p0L9ztw8/
const dpr = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1;
const chineseSize = 60
const scale = 2
HanziWriter.create($('#test1')[0], '龍', {
renderer: 'canvas',
width: chineseSize * dpr * scale,
height: chineseSize * dpr * scale,
padding: 2
});
HanziWriter.create($('#test2')[0], '龍', {
renderer: 'canvas',
width: chineseSize * dpr * scale,
height: chineseSize * dpr * scale,
padding: 2
});
html, body {
margin: 0;
padding: 0;
}
div {
position: absolute;
transform-origin: left top;
}
canvas {
width: 60px;
height: 60px;
}
#test1 {
left: 0;
transform: scale(2);
}
#test2 {
left: 50%;
zoom: 200%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hanzi-writer#3.2.0/dist/index.cjs.min.js"></script>
<div id="test1"></div>
<div id="test2"></div>
Have you tried pixelated image rendering in css? It may be what is needed on the canvas and each div to be scaled.
canvas {
image-rendering: -moz-crisp-edges;image-rendering: -webkit-crisp-edges;image-rendering: pixelated;image-rendering: crisp-edges;
width: 60px;
height: 60px;
}
Related
I'm trying to 'transform' elements, img here when the mouse moves on the page. I have integrated a vanilla code to create this effect and thought I understoond it but it seems I was wrong. The element from the code snippet is the orange square (3.png), but I want to apply this effect on the human pic (2.png) behind aswell and can't figure out how. (here's the full code as I don't rly know what's messed up except for my whole architecture prbly: https://github.com/KPq66dw8L/b-code-fiverr)
<section class="container bot-container-img">
<img class="layer closeUp" src="images/1.png" data-speeed="2" alt="">
<img class="layer ellipse2" src="images/2.png" data-speeed="-5" alt="">
<img class="layer" src="images/images/3.png" data-speed="2" alt="">
</section>
CSS:
.bot-container-img {
grid-row-start: 3;
grid-column-start: 1;
grid-column-end: 3;
width: 100%;
height: 100%;
}
section {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
align-items: flex-end;
justify-content: flex-start;
}
section img {
position: absolute;
object-fit: cover;
width: 100%;
height: 100%;
}
JS:
document.addEventListener("mousemove", parallax);
function parallax(e){
this.querySelectorAll('.layer').forEach(layer => {
const speed = layer.getAttribute('data-speed')
const x = (window.innerWidth - e.pageX*speed)/100
const y = (window.innerHeight - e.pageY*speed)/100
layer.style.transform = `translateX(${x}px) translateY(${y}px)`
})
}
There were a few minor errors I corrected:
typo data-speeed="2" corrected to data-speed="2"
I preferred getBoundingClientRect() over window.innerWidth / window.innerHeight
The items being effected by parallax are centered using left, top, width, height, and negative margin-left and margin-top - this allows the transform.translate property to translate them relative to their centers
I wrapped all the logic into a nice applyParallax function, in case you wish to apply it to multiple section elements
I also had to make some changes to get this to work with stackoverflow's snippet system:
Instead of <img> I used <div class="img"></div>, with css to colour different div.img elements distinctly
I decreased the size of the div.img elements to make the effect more visible in the small window
I increased the values for data-speed to make the effect more obvious
I made the html and body elements fill the whole viewport (and the section element fills the whole body element)
let applyParallax = section => {
section.addEventListener('mousemove', e => {
let { width, height } = section.getBoundingClientRect();
let offX = e.pageX - (width * 0.5);
let offY = e.pageY - (height * 0.5);
for (let layer of document.querySelectorAll('.img')) {
const speed = layer.getAttribute('data-speed')
const x = (offX * speed) / 100;
const y = (offY * speed) / 100;
layer.style.transform = `translateX(${x}px) translateY(${y}px)`
}
});
section.addEventListener('mouseleave', e => {
for (let layer of document.querySelectorAll('.img')) {
layer.style.transform = `translateX(0px) translateY(0px)`
}
});
};
applyParallax(document.querySelector('section'));
html, body { position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; }
section {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
align-items: flex-end;
justify-content: flex-start;
}
section > .img {
position: absolute;
left: 50%; top: 50%;
width: 120px; height: 120px;
margin-left: -60px; margin-top: -60px;
}
section > .img.r { background-color: rgba(200, 0, 0, 0.5); }
section > .img.g { background-color: rgba(0, 200, 0, 0.4); }
section > .img.b { background-color: rgba(0, 0, 200, 0.3); }
<section class="container bot-container-img">
<div class="img r" data-speed="22"></div>
<div class="img g" data-speed="-5"></div>
<div class="img b" data-speed="32"></div>
</section>
I was wondering if there is any way to save image original + Draggable blur mask over image
Here is an example of a draggable blur mask over the image : https://codepen.io/netsi1964/pen/AXRabW
$(function() {
$("#mask").draggable({
containment: "parent"
});
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#mask {
width: 50px;
height: 50px;
border-radius: 100%;
overflow: hidden;
position: absolute;
top: calc(50% - 25px);
left: calc(50% - 25px);
}
#unblurred {
position: absolute;
top: 0;
left: 0;
z-index: 999;
width: 100%;
height: 100%;
overflow: hidden;
-webkit-filter: blur(0px);
}
#unblurred img {
position: fixed;
left: 0;
top: 0;
}
#blurred {
-webkit-filter: blur(20px);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<div id="mask">
<div id="unblurred">
<img src="https://i.ytimg.com/vi/LRVsxe5OJVY/maxresdefault.jpg">
</div>
</div>
<img id="blurred" src="https://i.ytimg.com/vi/LRVsxe5OJVY/maxresdefault.jpg">
Wanted to save image with draggable blur mask over image... Maybe using canvas or something of the type
I think that I have a some what working solution, here is the JS code:
function saveMask() {
$("#blurred").hide()
html2canvas(document.querySelector("#mask"), {allowTaint: true}).then(h2c => {
var pos = $("#mask")[0].getBoundingClientRect();
$("#mask").hide()
var image = document.getElementById('blurred');
var canvas = document.createElement("canvas");
canvas.height = image.height;
canvas.width = image.width;
var ctx = canvas.getContext('2d')
ctx.filter = 'blur(20px)'
ctx.drawImage(image, 0, 0);
ctx.filter = 'none'
ctx.drawImage(h2c, pos.x, pos.y);
document.body.appendChild(canvas);
});
}
My idea here is to get as the mask using html2canvas and then we create a canvas with the blurred image and "paste" the mask on top of that.
I have a fully functional example here:
https://raw.githack.com/heldersepu/hs-scripts/master/HTML/html2canvas.html
I want to create a div that maintains aspect ratio with height and width changes of the parent.
In the above gif, you can see that I was able to maintain the box div's aspect ratio when changing width but I'm unable to maintain it when changing height of the parent.
.box {
width: 100px;
background-color: #dfdfdf;
max-width: 100%;
}
.box:after {
content: '';
display: block;
width: 100%;
height: 100%;
padding-bottom: 160%;
}
.wrap9 {
width: 125px;
height: 190px;
}
<div class="wrap9">
<div class="box"></div>
</div>
I want the grey box to behave like the following:
With your default width and height:
.box {
width: 100px;
background-color: #dfdfdf;
max-width: 100%;
max-height:100%;
}
.box:after {
content: '';
display: block;
width: 100%;
height: 100%;
padding-bottom: 160%;
}
.wrap9 {
width: 150px;
height: 200px;
border: 1px solid black;
}
<div class="wrap9">
<div class="box"></div>
</div>
width lower width and height:
.box {
width: 100px;
background-color: #dfdfdf;
max-width: 100%;
max-height:100%;
}
.box:after {
content: '';
display: block;
width: 100%;
height: 100%;
padding-bottom: 160%;
}
.wrap9 {
width: 100px;
height: 120px;
border: 1px solid black;
}
<div class="wrap9">
<div class="box"></div>
</div>
Is this the desired effect?
I'd have to say that this is not currently possible. While you can use calc() and variables, there is no way to keep a dynamic reference to object's current width nor height.
When I looked at doing this with js there was no clean way either. You'll just have to write an interval to periodically check if width or height of parent element has changed.
Google is pushing a dom element observer but the spec is currently very limited.
The funny thing is, just like in your example, images do this by default. However, there seems to be absolutely no clean way of doing this with another element.
You can use JavaScript to calculate the ratio of the width and the height between you object and the parent object. Then your can either scale to FILL the parent object (think CSS background-size: contain;) or scale to FIT the parent object (CSS: background-size: cover;)
Example of the two type of scaling methods.
(A) The left shows SCALE-TO-FILL and (B) on the right we are using SCALE-TO-FIT.
// Find the ratio between the destination width and source width.
RATIO-X = DESTINATION-WIDTH / SOURCE-WIDTH
// Find the ratio between the destination height and source height.
RATIO-Y = DESTINATION-HEIGHT / SOURCE-HEIGHT
// To use the SCALE TO FILL method,
// we use the greater of the two ratios,
// let's assume the RATIO-X is greater than RATIO-Y.
SCALE-W = RATIO-X * SOURCE-WIDTH
SCALE-H = RATIO-X * SOURCE-HEIGHT
// To use the SCALE TO FIT method,
// we use the lesser of the two ratios,
// let's assume the RATIO-Y is less than RATIO-X.
SCALE-W = RATIO-Y * SOURCE-WIDTH
SCALE-H = RATIO-Y * SOURCE-HEIGHT
When your parent object scales, you will need to determine these ratios.
Take a look at the embedded example and you can see how it works.
var $parent = $('.parent'),
$child = $('.child'),
w = $parent.width(),
h = $parent.height(),
cw = $child.width(),
ch = $child.height(),
winc = -10,
hinc = -5;
/*
This function is what you need.{
First we grab the ratio for the width (rx).
Then the ratio for the height (ry).
To scale to FIT, we want the MIN of the two.
To scale to FILL, we want the MAX of the two.
r is used to calculate the new size for ther child obj.
*/
function calcChildSize() {
var rx = w / cw,
ry = h / ch,
r1 = Math.min(rx, ry),
r2 = Math.max(rx, ry);
$('.child.fit').css({
width: r1 * cw,
height: r1 * ch
});
$('.child.fill').css({
width: r2 * cw,
height: r2 * ch
});
}
// just a simple function to change the size
// of the parent object
window.setInterval(function() {
if (w < 70) {
winc = 10;
} else if (w > 200) {
winc = -10;
}
if (h < 50) {
hinc = 5;
} else if (h > 200) {
hinc = -5;
}
w += winc;
h += hinc;
$parent.css({
width: w,
height: h
});
calcChildSize();
}, 100);
.parent {
display: inline-block;
width: 200px;
height: 200px;
border: 1px solid #aaa;
margin-right: 50px;
}
.child {
box-sizing: border-box;
width: 50px;
height: 70px;
background: rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 0, 0, 0.5);
text-align: center;
font-family: monospace;
font-size: 11px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent fit">
<div class="child fit">FIT</div>
</div>
<div class="parent fill">
<div class="child fill">FILL</div>
</div>
Edit #2: I also went ahead and added an example of the two different scale methods in action.
Add max-width: 100% and object-fit:cover, here's a link https://jsfiddle.net/jv1f4bhL/1/
body {
position: relative;
background-color: wheat;
padding: 0;
margin: 0;
}
img {
object-fit: cover;
max-width: 100%;
width: auto;
}
<img src="https://mdbootstrap.com/img/Others/documentation/img%20(7)-mini.jpg" />
.box {
max-height: 100%;
}
....worked perfect.
I have the following progress bar, but I'd like it to go vertically instead of horizontally. In other words, I'd like to flip it 90 degrees and have the text flipped by 90 degrees as well
See my code below, as well as my code pen here:
http://codepen.io/chriscruz/pen/jPGMzW
How would I rotate this chart as well as the text value?
HTML
<!-- Change the below data attribute to play -->
<div class="progress-wrap progress" data-progress-percent="50">
<div class="progress-bar-state progress">50</div>
</div>
CSS
.progress {
width: 100%;
height: 50px;
}
.progress-wrap:before {
content: '66';
position: absolute;
left: 5px;
line-height: 50px;
}
.progress-wrap:after {
content: '$250,000';
right: 5px;
position: absolute;
line-height: 50px;
}
.progress-wrap {
background: #f80;
margin: 20px 0;
overflow: hidden;
position: relative;
}
.progress-wrap .progress-bar-state {
background: #ddd;
left: 0;
position: absolute;
top: 0;
line-height: 50px;
}
Javascript
// on page load...
moveProgressBar();
// on browser resize...
$(window).resize(function() {
moveProgressBar();
});
// SIGNATURE PROGRESS
function moveProgressBar() {
console.log("moveProgressBar");
var getPercent = ($('.progress-wrap').data('progress-percent') / 100);
var getProgressWrapWidth = $('.progress-wrap').width();
var progressTotal = getPercent * getProgressWrapWidth;
var animationLength = 2500;
// on page load, animate percentage bar to data percentage length
// .stop() used to prevent animation queueing
$('.progress-bar-state').stop().animate({
left: progressTotal
}, animationLength);
}
CSS
.progress {
height: 500px;
width: 50px;
}
.progress-wrap:before {
content: '66';
position: absolute;
top: 5px;
line-height: 50px;
}
.progress-wrap:after {
content: '$250,000';
bottom: 5px;
position: absolute;
line-height: 50px;
}
.progress-wrap {
background: #f80;
margin: 20px 0;
overflow: hidden;
position: relative;
}
.progress-wrap .progress-bar-state {
background: #ddd;
left: 0;
position: absolute;
top: 0;
line-height: 50px;
}
Javascript
moveProgressBar();
// on browser resize...
$(window).resize(function() {
moveProgressBar();
});
// SIGNATURE PROGRESS
function moveProgressBar() {
console.log("moveProgressBar");
var getPercent = ($('.progress-wrap').data('progress-percent') / 100);
var getProgressWrapWidth = $('.progress-wrap').height();
var progressTotal = getPercent * getProgressWrapWidth;
var animationLength = 2500;
// on page load, animate percentage bar to data percentage length
// .stop() used to prevent animation queueing
$('.progress-bar-state').stop().animate({
top: progressTotal
}, animationLength);
}
Pretty much its just switching the height and widths as well as the lefts with tops and rights with bottoms.
You can rotate text or anything else using this css rule.
transform: rotate(90deg); /* this is the rotation */
Use -90deg to rotate the other way.
I've been searching and I can't find anything on the web, but I'm interested in creating (or using something already available, hopefully since I'm pressed with time) similar to this site:
http://www.citroen.hr/citroen/#/citroen/
It's also similar to the Safari Top Sites view, but has the added mouse-tracking and 3d rotation.
Does anyone know of something similar created with javascript/html/css or can point me in the right direction?
A basic version with HTML elements, CSS 3D transforms (so it only works in browsers supporting 3D transforms & nesting of 3D transformed elements - this means no Opera and no IE) and a little bit of JavaScript for the mouse tracking:
demo
HTML:
<ul class='tiles'>
<li class='tile'></li>
<!-- more tiles; I used 16 for the demo and put them on an icosagon -->
</ul>
<div class='slider'></div>
Relevant CSS:
.tiles {
position: absolute;
top: 50%; left: 50%;
padding: 0;
width: 0; height: 0;
list-style: none;
transform-style: preserve-3d;
transform: rotateY(-162deg);
}
.tile {
position: absolute;
left: 50%;
margin: 0.5em -10em;
width: 20em; height: 20em;
backface-visibility: hidden;
opacity: 0.5;
/* inradius of an icosagon */
cursor: pointer;
transition: 0.5s;
}
.tile:hover { opacity: 1; }
.tile:nth-child(odd) { bottom: 100%; }
.tile:nth-child(2), .tile:nth-child(1) {
transform: rotateY(18deg) translateZ(-66.29439em);
}
/* and so on... in general, something of the form:
.tile:nth-child(2*i), .tile:nth-child(2*i-1) {
transform: rotateY(1*18deg) translateZ(-66.29439em);
}
where 18deg = outer angle of the icosagon
66.29439em = 1.05*20em*(1 + sqrt(5) + sqrt(5 + 2*sqrt(5)))/2
= 1.05 * inradius of icosagon
see http://mathworld.wolfram.com/Icosagon.html */
.tile:nth-child(1) {
background: url(image1.jpg);
background-size: cover;
}
/* and so on, set backgrounds for each */
.slider {
position: absolute;
bottom: 5%; left: 10%;
height: 0.25em; width: 80%;
opacity: 0.5;
background: grey
linear-gradient(90deg, crimson 100%, transparent 100%) no-repeat;
background-size: 5% 100%;
}
JavaScript:
(function(){
var b = document.body;
b.addEventListener('mousemove', function(e) {
var w = b.clientWidth, x = e.clientX,
perc = x/w,
full_angle = -162,
to_angle = full_angle + (100 - perc)*full_angle,
txt = 'rotateY(' + to_angle + 'deg)',
prefixes = ['Webkit', 'Moz', /*'ms', 'O', */''],
len = prefixes.length,
property = 'Transform',
a = document.querySelector('.tiles'),
s = document.querySelector('.slider');
for(var i = 0; i < len; i++) {
if(prefixes[i] == '')
property = property.toLowerCase();
a.style[prefixes[i] + property] = txt;
}
s.style.backgroundPosition = (perc*100 - .5) + '% 50%';
}, false);
}());