I am trying to build one page from my layout but I have some hard time. I have to create a Process line as shown on the picture. I am trying also to make it responsive but i have the feeling that my code is very messy.
.process-steps h2 { font-family: "Rubik-Regular", sans-serif; font-size: 40px; color: #1e1e22; margin: 55px 0 70px 0; }
.process-steps .green-span { font-family: "Rubik-Bold", sans-serif; color: #23b58a; }
.actual-graph { position: relative; display: flex; justify-content: center; align-items: center; }
.actual-graph h4 { font-family: "Rubik-Medium", sans-serif; font-size: 18px; color: #2a2a2e; line-height: 28px; }
.actual-graph p { font-family: "Rubik-Regular", sans-serif; font-size: 16px; color: #46464c; line-height: 22px; }
.step-1 { position: absolute; width: 25%; right: 86%; bottom: 0; left: 0; top: 42%; }
.step-2 { position: absolute; width: 25%; left: 13%; bottom: 0; right: 0; top: -7.8%; }
.step-3 { position: absolute; width: 25%; left: 37.5%; bottom: 0; right: 0; top: 42%; }
.step-4 { position: absolute; width: 25%; left: 61%; bottom: 0; right: 0; top: -7.8%; }
.step-5 { position: absolute; width: 25%; left: 85%; bottom: 0; right: 0; top: 42%; }
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<section class="process-steps">
<div class="container">
<h2><span class="green-span">5 Steps</span> Process</h2>
<div class="graph-container">
<div class="actual-graph">
<img src="https://s17.postimg.org/bhxksjwkf/graph.png" width="1171" height="191" title="someText" alt="someText" class="img-responsive">
<div class="step-1">
<h4>Create your account</h4>
<p>The process begins when you
<br>create an account with Sellr.</p>
</div>
<!-- step-1 -->
<div class="step-2">
<h4>Select Store Picks</h4>
<p>Select 20-30 products from
<br>each product category that you
<br>want to promote.</p>
</div>
<div class="step-3">
<h4>Wait for processing</h4>
<p>We ensure high quality
<br>information on your store picks
<br>in 7-10 business days.</p>
</div>
<div class="step-4">
<h4>Install Sellr Tablets</h4>
<p>Place Sellr tablets throughout
<br>your store.</p>
</div>
<div class="step-5">
<h4>Start increasing sales!</h4>
<p>Your store is now equipped to
<br>start increasing sales for your
<br>selected products.</p>
</div>
</div>
</div>
</div>
<!-- container -->
</section>
<!-- process-steps -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
[https://codepen.io/sheetalsinghwd/pen/LYYMOam]
var canvas, ctx, p = function (x,y) {
return { x:x, y:y };
};
// drawing
$(function() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext('2d');
ctx.canvas.width = window.innerWidth;
ctx.canvas.height = window.innerHeight;
ctx.lineCap = 'round';
ctx.lineWidth = 4;
ctx.strokeStyle = 'rgba(50,30,120,0.5)';
ctx.beginPath();
ctx.wavy(p(80, 120), p(650, 120), 2, 12, 4);
ctx.stroke();
});
CanvasRenderingContext2D.prototype.wavy = function(from, to, frequency, amplitude, step, negative)
{
var cx = 0, cy = 0,
fx = from.x, fy = from.y,
tx = to.x, ty = to.y,
i = 0, waveOffsetLength = 0,
ang = Math.atan2(ty - fy, tx - fx),
distance = Math.sqrt((fx - tx) * (fx - tx) + (fy - ty) * (fy - ty)),
a = amplitude * (!negative ? 1 : -1),
f = Math.PI * frequency;
for (i; i <= distance; i += step)
{
waveOffsetLength = Math.sin((i / distance) * f) * a;
cx = from.x + Math.cos(ang) * i + Math.cos(ang - Math.PI/2) * waveOffsetLength;
cy = from.y + Math.sin(ang) * i + Math.sin(ang - Math.PI/2) * waveOffsetLength;
i > 0 ? this.lineTo(cx, cy) : this.moveTo(cx, cy);
}
}
use this for canvas
you can refer to this link.. even i am working on that.. i have just tried to create wavy lines through css and javascript`
Related
I am new to working on css/html and I was trying to do parallax effect contained in some border radius but every time I try to do it using a background (url) it doesn't seem to do what I want it to, so I was wondering if it'd be possible to do it from the img tag?
You can solve your problem using JS. Check out the example below. It will work for you. Have a nice day.
$('.img-parallax').each(function() {
var $image = $(this);
var $imageParent = $(this).parent();
function parallaxImg () {
var speed = $image.data('speed');
var imageY = $imageParent.offset().top;
var winY = $(this).scrollTop();
var winH = $(this).height();
var parentH = $imageParent.innerHeight();
// The next pixel to show on screen
var winBottom = winY + winH;
// If block is shown on screen
if (winBottom > imageY && winY < imageY + parentH) {
// Number of pixels shown after block appear
var imgBottom = ((winBottom - imageY) * speed);
// Max number of pixels until block disappear
var imgTop = winH + parentH;
// Percentage between start showing until disappearing
var imgPercent = ((imgBottom / imgTop) * 100) + (50 - (speed * 50));
}
$image.css({ top: imgPercent + '%', transform: 'translate(-50%, -' + imgPercent + '%)' });
}
$(document).on({
scroll: function () {
parallaxImg();
}, ready: function () {
parallaxImg();
}
});
});
#import url(https://fonts.googleapis.com/css?family=Amatic+SC:400,700);
html,
body {
margin: 0;
padding: 0;
height: 100%;
width: 100%;
font-family: "Amatic SC", cursive;
}
.block {
width: 100%;
height: 100%;
position: relative;
overflow: hidden;
font-size: 16px;
}
.block h2 {
position: relative;
display: block;
text-align: center;
margin: 0;
top: 50%;
transform: translateY(-50%);
font-size: 10vw;
color: white;
font-weight: 400;
}
.img-parallax {
width: 100vmax;
z-index: -1;
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, 0);
pointer-events: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="block">
<img src="https://unsplash.it/1920/1920/?image=1003" data-speed="-1" class="img-parallax">
<h2>Parallax 1</h2>
</div>
<div class="block">
<img src="https://unsplash.it/1920/1920/?image=1002" data-speed="1" class="img-parallax">
<h2>Parallax 2</h2>
</div>
<div class="block">
<img src="https://unsplash.it/1920/1920/?image=1014" data-speed="1" class="img-parallax">
<h2>Parallax 3</h2>
</div>
I have this fiddle.
https://jsfiddle.net/oeuc8L9y/2/
If you click the background the coordinates where you clicked get centered.
Is it possible to make the pointer events only work inside the hole?
Since I'm using an image for the ring the whole thing blocks the pointer-events but if I set it to pointer-events: none; I can click trough the ring too.
This is good.
This is bad.
I assume a way would be to get the pixel coordinate and calculate if it's inside the hole but I feel like that would only work for a specific screen size and it'd break if resized.
tooltip_X = $("#x-coords");
tooltip_Y = $("#y-coords");
$("#background").on("mouseover", (e) => {
showTooltip(e);
});
$("#background").on("mousemove", (e) => {
updateCoords(e);
moveTooltip(e);
});
$("#background").on("mouseout", (e) => {
hideTooltip(e);
});
$("#background").on("click", (e) => {
move(e);
updateCoords(e);
});
function showTooltip(e) {
$("#tooltip").css("display", "block");
}
function hideTooltip(e) {
$("#tooltip").css("display", "none");
}
function moveTooltip(e) {
var left = 0;
var top = 0;
if (e.pageX + $("#tooltip").width() + 10 < document.body.clientWidth) {
left = e.pageX + 10;
} else {
left = document.body.clientWidth + 5 - $("#tooltip").width();
}
if (e.pageY + $("#tooltip").height() + 10 < document.body.clientHeight) {
top = e.pageY + 10;
} else {
top = document.body.clientHeight + 5 - $("#tooltip").height();
}
$("#tooltip").offset({ top: top, left: left });
}
function updateCoords(e) {
var mouse_x = e.clientX - $("#background").offset().left;
var mouse_y = e.clientY - $("#background").offset().top;
$("#x-coords").text(Number.parseInt(mouse_x));
$("#y-coords").text(Number.parseInt(mouse_y));
}
function move(e) {
var mouse_x = e.clientX - $("#background").offset().left;
var mouse_y = e.clientY - $("#background").offset().top;
var new_x = 0;
var new_y = 0;
if (mouse_x < 250) {
mouse_x = 250;
}
if (mouse_y < 250) {
mouse_y = 250;
}
if (mouse_x > 1670) {
mouse_x = 1670;
}
if (mouse_y > 950) {
mouse_y = 950;
}
new_x = -(mouse_x - 250);
new_y = -(mouse_y - 250);
$("#background").css("margin-top", new_y);
$("#background").css("margin-left", new_x);
}
#container {
position: relative;
width: 500px;
height: 500px;
overflow: hidden;
z-index: 100;
}
#ring {
position: absolute;
border-radius: 100%;
max-height: 500px;
max-width: 500px;
z-index: 90;
pointer-events: none;
}
#lens {
position: absolute;
border: 1px solid red;
/*
something to make it round
*/
z-index: 80;
pointer-events: none;
}
#background {
position: absolute;
width: 1920px;
height: 1200px;
background-image: url("https://wallpaperaccess.com/full/197542.jpg");
z-index: 80;
outline: 5px dotted purple;
outline-offset: -5px;
}
#tooltip {
position: absolute;
white-space: nowrap;
background: #ffffcc;
border: 1px solid black;
padding: 5px;
color: black;
z-index: 999;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head> </head>
<body>
<div id="container">
<img id="ring" src="https://pngimg.com/uploads/circle/circle_PNG26.png" alt="Lens Ring" />
<div id="lens"></div>
<div id="background"></div>
<span id="tooltip"> Div Coords (<span id="x-coords"></span>,<span id="y-coords"></span>) </span>
</div>
</body>
</html>
I have done this right now with html/css only. But problem is I have used position - relative for outer bar and position absolute for inner item's placement. But as the text gets big/small the positioning isnt center (text below or above charts)
And if I dont use position on elements, the texts below graph floats on top or above that. Also the amount showing up just above chart goes in straight line.
<div class="bar-container">
<div class="fl width-100 r">
<div class="donut-bg width-100 fl mr-c">
<div class="bar" ng-repeat="d in barData track by $index" style="margin: 0 {{chartData.marginRight}}%">
<div class="bar-value" style="bottom: {{+d.perc+20}}%">{{d.value}}K</div>
<div class="bar-chart" style="height: {{d.perc}}%;"></div>
<div class="bar-name c">d.text</div>
</div>
</div>
</div>
</div>
barData = [{"value":33,"text":"AU","perc":"35.36","padPerc":"39.64"},{"value":0,"text":"BD","perc":"0.00","padPerc":"75.00"},{"value":0,"text":"DB","perc":"0.00","padPerc":"75.00"},{"value":11,"text":"ED","perc":"11.79","padPerc":"63.21"},{"value":70,"text":"EI","perc":"75.00","padPerc":"0.00"}]
I have done something like this with HTML, CSS and PHP in the past - maybe this gives you an idea:
diagram.css
#diagram
{
position: relative;
padding: 0;
border: 1px solid #000;
font-family: verdana;
background: #fff;
}
#diagram div.title
{
padding: 0;
position: relative;
font: 12px;
font-weight: bold;
text-align: center;
line-height: 15px;
top: 5px;
}
#diagram div.axis
{
padding: 0;
position: absolute;
top: 50px;
left: 50px;
border-bottom: 1px solid black;
border-left: 1px solid black;
}
#diagram div.xunit
{
padding: 0;
position: absolute;
font-size: 8px;
text-align: center;
left: 50px;
// border: 1px solid black;
}
#diagram div.yunit
{
padding: 0;
position: absolute;
top: 25px;
left: 25px;
font-size: 8px;
text-align: left;
// border: 1px solid black;
}
#diagram div.xlabels
{
padding: 0;
position: absolute;
left: 50px;
height: 25px;
line-height: 25px;
// border: 1px solid #000;
}
#diagram div.xlabel
{
position: absolute;
left: 0;
height: 25px;
padding: 0;
font-size: 8px;
color: #c00;
// border: 1px solid #000;
}
#diagram div.ylabels
{
padding: 0;
position: absolute;
top: 50px;
left: 25px;
width: 25px;
// line-height: 25px;
// border: 1px solid #000;
}
#diagram div.ylabel
{
position: absolute;
left: 0;
width: 25px;
padding: 0;
font-size: 8px;
color: #c00;
// border: 1px solid #000;
}
#diagram div.bar
{
position: absolute;
text-align: right;
font-size: 10px;
color: #fff;
font-weight: bold;
border: 1px solid #000;
padding: 0px 0 0 0;
background: #c00;
}
diagram1.thtml
<!DOCTYPE html>
<html lang="de">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="diagram.css">
</head>
<body>
<div id="diagram" style="width: {DIAGRAMWIDTH}px; height: {DIAGRAMHEIGHT}px;">
<div class="title">{DIAGRAMTITLE}
<form id="diagramform" action="/diagram1.php" method="get">
<input type="text" id ="startcell" name="startcell" value="{DIAGRAMSTARTCELL}" /> - <input type="text" id ="endcell" name="endcell" value="{DIAGRAMENDCELL}" />
<!-- <button type="button" onclick=""><</button> --> <input type="text" id ="date" name="date" value="{DIAGRAMDATE}" /> <button type="button" onclick="var formdate = document.getElementById('date'); var nextdate = new Date(formdate.value); nextdate.setTime(nextdate.getTime() + 1000); formdate.value = nextdate.getFullYear() + '-' + (nextdate.getMonth() + 1) + '-' + nextdate.getDate() + ' ' + nextdate.getHours() + ':' + nextdate.getMinutes() + ':' + nextdate.getSeconds(); document.getElementById('diagramform').submit();">></button>
<input type="submit" style="position: absolute; left: -9999px; width: 1px; height: 1px;" tabindex="-1" />
</form>
</div>
<div class="axis" style="width: {AXISWIDTH}px; height: {AXISHEIGHT}px;">
<div class="bar">
<!-- BEGIN XBAR_POS -->
<div class="bar" style="width: {XBAR_WIDTH}px; left: {XBAR_LEFT}px; top: {XBAR_TOP}px; height: {XBAR_HEIGHT}px;"></div>
<!-- END XBAR_POS -->
</div>
</div>
<div class="xunit" style="top: {XLABEL_TOP}px; width: {XLABEL_WIDTH}px;">{XLABEL}</div>
<div class="yunit" style="height: {YLABEL_HEIGHT}px;">{YLABEL}</div>
<div class="xlabels" style="top: {XLABELS_TOP}px; width: {XLABELS_WIDTH}px;">
<!-- BEGIN XLABEL_POS -->
<div class="xlabel" style="left: {XLABEL_VALUE_LEFT}px;">{XLABEL_VALUE}</div>
<!-- END XLABEL_POS -->
</div>
<div class="ylabels" style="height: {YLABELS_HEIGHT}px;">
<!-- BEGIN YLABEL_POS -->
<div class="ylabel" style="top: {YLABEL_VALUE_TOP}px;">{YLABEL_VALUE}</div>
<!-- END YLABEL_POS -->
</div>
</div>
<hr />
Zellenübersicht | Zeitübersicht | Datenübermittlung
</body>
</html>
diagram1.php
<?php
require_once('HTML/Template/PHPLIB.php');
require_once('config.php');
$diagramdate = htmlspecialchars(#$_GET["date"]);
if (empty($diagramdate))
{
$diagramdate = date("Y-m-d");
}
$lasttimestamp = $diagramdate;
$diagramstartcell = htmlspecialchars(#$_GET["startcell"]);
if (empty($diagramstartcell))
{
$diagramstartcell = 1;
}
$diagramendcell = htmlspecialchars(#$_GET["endcell"]);
if (empty($diagramendcell))
{
$diagramendcell = 12;
}
$diagramwidth = 1000;
$diagramheight = 500;
$diagramtitle = 'Zellenübersicht';
$xlabels = array();
$mysqli = mysqli_connect($dbhost, $dbuser, $dbpasswd, $dbschema);
if ($mysqli->connect_errno)
{
printf("Connect failed: %s\n", $mysqli->connect_error);
exit();
}
$res = mysqli_query($mysqli, "select cell_id, cv_volt, cv_time from cell_voltages where cell_id >= " . $diagramstartcell . " and cell_id <= " . $diagramendcell . " and cv_time >= '" . $diagramdate . "' order by cv_time, cell_id"); // TODO prevent sql injection, use prepared statement
if ($res)
{
while ($row = $res->fetch_assoc())
{
if (isset($xlabels[$row['cell_id']]))
{
break;
}
$xlabels[$row['cell_id']] = $row['cv_volt'];
$lasttimestamp = $row['cv_time'];
}
$res->free();
}
$mysqli->close();
$ylabels = array(4.2, 4.0, 3.5, 3.0, 2.5, 2.0, 1.7);
// ----------
$axiswidth = $diagramwidth - 100;
$axisheight = $diagramheight - 100;
$xlabel_top = $diagramheight - 25;
$xlabel_width = $axiswidth;
$xlabel = 'Zellen';
$xlabels_top = $diagramheight - 50;
$xlabels_width = $axiswidth;
$ylabel_height = $axisheight + 25;
$ylabel = 'V';
$ylabels_height = $axisheight;
header('Content-Type: text/html; charset=utf-8');
$t = new HTML_Template_PHPLIB(dirname(__FILE__), 'keep');
$t->setFile('diagram', 'diagram1.thtml');
$t->setVar('DIAGRAMWIDTH', $diagramwidth);
$t->setVar('DIAGRAMHEIGHT', $diagramheight);
$t->setVar('DIAGRAMTITLE', $diagramtitle);
$t->setVar('DIAGRAMDATE', $lasttimestamp);
$t->setVar('DIAGRAMSTARTCELL', $diagramstartcell);
$t->setVar('DIAGRAMENDCELL', $diagramendcell);
$t->setVar('AXISWIDTH', $axiswidth);
$t->setVar('AXISHEIGHT', $axisheight);
$t->setVar('XLABEL_TOP', $xlabel_top);
$t->setVar('XLABEL_WIDTH', $xlabel_width);
$t->setVar('XLABEL', $xlabel);
$t->setVar('XLABELS_TOP', $xlabels_top);
$t->setVar('XLABELS_WIDTH', $xlabels_width);
$t->setVar('YLABEL_HEIGHT', $ylabel_height);
$t->setVar('YLABEL', $ylabel);
$t->setVar('YLABELS_HEIGHT', $ylabels_height);
$t->setBlock('diagram', 'XLABEL_POS', 'XLABEL_POS_ref');
if (count($xlabels) > 0)
{
$xpixelscale = $axiswidth / count($xlabels);
}
else
{
$xpixelscale = 1;
}
$i = 0;
foreach($xlabels as $xkey => $xvalue)
{
$t->setVar('XLABEL_VALUE', $xkey);
$t->setVar('XLABEL_VALUE_LEFT', ($xpixelscale * $i++) + ($xpixelscale / 2));
$t->parse('XLABEL_POS_ref', 'XLABEL_POS', true);
}
if ($i == 0)
{
$t->setVar('XLABEL_VALUE', '');
$t->setVar('XLABEL_VALUE_LEFT', 0);
$t->parse('XLABEL_POS_ref', 'XLABEL_POS', false);
}
$t->setBlock('diagram', 'YLABEL_POS', 'YLABEL_POS_ref');
$topvalue = reset($ylabels);
$bottomvalue = end($ylabels);
$ypixelscale = $axisheight / ($topvalue - $bottomvalue);
foreach($ylabels as $yvalue)
{
$t->setVar('YLABEL_VALUE', $yvalue);
$t->setVar('YLABEL_VALUE_TOP', $axisheight - (($yvalue - $bottomvalue) * $ypixelscale));
$t->parse('YLABEL_POS_ref', 'YLABEL_POS', true);
}
$t->setBlock('diagram', 'XBAR_POS', 'XBAR_POS_ref');
$i = 0;
foreach($xlabels as $xkey => $xvalue)
{
if ($xvalue - $bottomvalue >= 0)
{
$t->setVar('XBAR_WIDTH', $xpixelscale / 2);
$t->setVar('XBAR_LEFT', ($xpixelscale * $i) + ($xpixelscale / 4));
$t->setVar('XBAR_HEIGHT', ($xvalue - $bottomvalue) * $ypixelscale);
$t->setVar('XBAR_TOP', $axisheight - (($xvalue - $bottomvalue) * $ypixelscale));
$t->parse('XBAR_POS_ref', 'XBAR_POS', true);
}
++$i;
}
if ($i == 0)
{
$t->setVar('XBAR_WIDTH', '0');
$t->setVar('XBAR_LEFT', '0');
$t->setVar('XBAR_HEIGHT', '0');
$t->setVar('XBAR_TOP', '0');
$t->parse('XBAR_POS_ref', 'XBAR_POS', false);
}
echo $t->finish($t->parse('OUT', 'diagram'));
?>
The config.php has been left out, the TemplateEngine is the Pear version from PHPLib. Sorry no time to create a screenshot.
I've encountered a very strange bug in Google Chrome!
if I use mix-blend-mode property on en element then if I apply transform: translateZ(50px); to an element below it, it doesn't work!
Please see this:
function threeD_hover(params) {
// Get the elements inside to be animated ...
var el = params.parent.find(params.element),
// defining the factor to be whether concave or covex style ...
factor = 1;
if (params.convex) {
factor = -1;
}
// Set the nessecory styles
TweenMax.set(el, {
transformPerspective: params.perspective,
rotationY: 0.01,
rotationX: 0.01,
"transform-style": "preserve-3d",
"backface-visibility": " hidden"
});
// Thee core function fo each of the elements inside ...
el.each(function(index, el) {
var $this = $(this);
function core_func(e) {
// Defining the degrees ..
var ax = params.xSensitivity * (($this.offset().left + ($this.outerWidth() / 2)) - e.pageX) / 200,
ay = params.ySensitivity * (($this.offset().top + ($this.outerHeight() / 2)) - e.pageY) / 200;
// Setting the max deg amount ...
if (ax > params.maxRotateDegreeX) {
ax = params.maxRotateDegreeX;
} else if (ax < -params.maxRotateDegreeX) {
ax = -params.maxRotateDegreeX;
}
if (ay > params.maxRotateDegreeY) {
ay = params.maxRotateDegreeY;
} else if (ay < -params.maxRotateDegreeY) {
ay = -params.maxRotateDegreeY;
}
var dx = (-factor) * ax,
dy = factor * ay;
// Animating ...
TweenMax.to($this, params.movementTime, {
rotationY: dx,
rotationX: dy,
ease: params.easing
});
}
if (!params.mouseSensitiveArea) {
params.mouseSensitiveArea = params.parent;
}
// mosuse move on canvas ..
params.mouseSensitiveArea.on("mousemove", core_func);
});
}
threeD_hover({
parent: $(".section"),
element: $(".card"),
// convex: true, // if not set it is false or concave
maxRotateDegreeX: 30,
maxRotateDegreeY: 30,
xSensitivity: 5, // Min: 1 | Max: 10
ySensitivity: 10, // Min: 1 | Max: 10
perspective: 1000,
// mouseSensitiveArea: $window, // if not set it's the parent element
easing: Power4.easeOut,
movementTime: 1
});
.parent {
background-image: url("http://www.intrawallpaper.com/static/images/background-wallpapers-26_HgdHzBm.jpg");
font-family: "Playfair Display", georgia, serif;
}
.mix-blend-overlay {
mix-blend-mode: overlay;
color: #fff;
text-align: center;
}
.section {
padding: 20px 0;
display: block;
}
.card {
pointer-events: none;
padding: 20px;
background: white;
border-radius: 5px;
width: 400px;
height: 150px;
margin: auto;
transform-style: preserve-3d;
backface-visibility: hidden;
display: flex;
box-shadow: 0 0 5px rgba(0, 0, 0, .1);
position: relative;
}
.card-content {
margin: auto;
text-align: center;
transform-style: preserve-3d;
}
h1 {
transform: translateZ(100px);
}
p {
transform: translateZ(50px);
display: block;
}
p.related {
transform: translateZ(80px);
font-style: italic;
}
a {
color: #69c6b8;
pointer-events: auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
<div class="section">
<div class="card">
<div class="card-content">
<h1>Just hover around</h1>
<p><small>by Ershad</small></p>
<p class="related"><strong>This has been done using TweenMax </strong></p>
</div>
</div>
</div>
<h1 class="mix-blend-overlay">Ershad</h1>
<div class="section">
<div class="card">
<div class="card-content">
<h1>Just hover around</h1>
<p><small>by Ershad</small></p>
<p class="related"><strong>This has been done using TweenMax </strong></p>
</div>
</div>
</div>
</div>
The 2 Cards on that demo have exactly the same structure, style and js function yet the latter won't work properly because and element with mix-blend-property is before it, try to remove it and it works just fine!!
How can I solve this problem?!
I'm trying to recreate this game in JavaScript. For this game, I need cells with numbers in them.
I want the game to size to the available space in the browser. I've managed to do this by using vw and vh in combination with width and min-width (and height) as you can see in the example. If you size the viewport in which the cells are shown, the cells size along.
The problem
And now, I want the text in it to size along too. The container (the cell) resizes, and the font of the digit should size accordingly. I now used vmax as a unit, but this doesn't take the horizontal sizing into account. And since there is no min-font-size, I cannot do the same trick I used for the cells themselves.
No jQuery please
I've tried and searched. Most notably, I found Auto-size dynamic text to fill fixed size container, however I think my question is reversed. The text is fixed, and I could set an initial font-size. I just need the font to scale along with the size of the element, so maybe this can be done through CSS after all.
Besides, most questions about this subject suggest using one of the various jQuery plugins and I'm not looking for a jQuery solution. I'm trying to make this game just for fun and practice, and I've set a goal to create it without jQuery. Actually I'm not even looking for a vanilla JavaScript solution. In the end it may boil down to that, but I haven't tried building it myself yet, so I don't want to ask for JavaScript here now. No, I'm looking for a pure CSS solution, if any.
The snippet
The dressed down snippet works best in full page mode. Nevermind the inline styling. These elements are actually generated by JavaScript and need be moved around. And sorry for the chunk of HTML. I brought it down to two cells at first, but that looked confusing, because they only filled a small part of the screen, and you couldn't see what was going on.
.game11,
.game11 .cell,
.game11 .cell .digit {
box-sizing: border-box;
}
.game11 {
width: 90vw;
height: 90vw;
max-width: 90vh;
max-height: 90vh;
box-sizing: border-box;
position: relative;
}
.game11 .cell {
width: 20%;
height: 20%;
position: absolute;
font-size: 7vmax; /* Font size. This obviously doesn't work */
}
.game11 .cell .digit {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
border: 3px solid #666633;
text-align: center;
padding-top: 13%;
font-family: Impact, Charcoal, sans-serif;
color: #111111;
}
<div class="game11">
<div class="cell" style="left: 0%; top: 0%;">
<div class="digit digit2" style="top: 0px;">2</div>
</div>
<div class="cell" style="left: 20%; top: 0%;">
<div class="digit digit2" style="top: 0px;">2</div>
</div>
<div class="cell" style="left: 40%; top: 0%;">
<div class="digit digit3" style="top: 0px;">3</div>
</div>
<div class="cell" style="left: 60%; top: 0%;">
<div class="digit digit1" style="top: 0px;">1</div>
</div>
<div class="cell" style="left: 80%; top: 0%;">
<div class="digit digit3" style="top: 0px;">3</div>
</div>
<div class="cell" style="left: 0%; top: 20%;">
<div class="digit digit1" style="top: 0px;">1</div>
</div>
<div class="cell" style="left: 20%; top: 20%;">
<div class="digit digit1" style="top: 0px;">1</div>
</div>
<div class="cell" style="left: 40%; top: 20%;">
<div class="digit digit4" style="top: 0px;">4</div>
</div>
<div class="cell" style="left: 60%; top: 20%;">
<div class="digit digit1" style="top: 0px;">1</div>
</div>
<div class="cell" style="left: 80%; top: 20%;">
<div class="digit digit3" style="top: 0px;">3</div>
</div>
<div class="cell" style="left: 0%; top: 40%;">
<div class="digit digit3" style="top: 0px;">3</div>
</div>
<div class="cell" style="left: 20%; top: 40%;">
<div class="digit digit2" style="top: 0px;">2</div>
</div>
<div class="cell" style="left: 40%; top: 40%;">
<div class="digit digit4" style="top: 0px;">4</div>
</div>
<div class="cell" style="left: 60%; top: 40%;">
<div class="digit digit3" style="top: 0px;">3</div>
</div>
<div class="cell" style="left: 80%; top: 40%;">
<div class="digit digit4" style="top: 0px;">4</div>
</div>
<div class="cell" style="left: 0%; top: 60%;">
<div class="digit digit2" style="top: 0px;">2</div>
</div>
<div class="cell" style="left: 20%; top: 60%;">
<div class="digit digit3" style="top: 0px;">3</div>
</div>
<div class="cell" style="left: 40%; top: 60%;">
<div class="digit digit5" style="top: 0px;">5</div>
</div>
<div class="cell" style="left: 60%; top: 60%;">
<div class="digit digit3" style="top: 0px;">3</div>
</div>
<div class="cell" style="left: 80%; top: 60%;">
<div class="digit digit1" style="top: 0px;">1</div>
</div>
<div class="cell" style="left: 0%; top: 80%;">
<div class="digit digit4">4</div>
</div>
<div class="cell" style="left: 20%; top: 80%;">
<div class="digit digit1" style="top: 0px;">1</div>
</div>
<div class="cell" style="left: 40%; top: 80%;">
<div class="digit digit2" style="top: 0px;">2</div>
</div>
<div class="cell" style="left: 60%; top: 80%;">
<div class="digit digit5">5</div>
</div>
<div class="cell" style="left: 80%; top: 80%;">
<div class="digit digit3" style="top: 0px;">3</div>
</div>
</div>
Updated: The 'full' (still unfinished) game, including the fix suggested by Pangloss
In the snippet below, you can find the game as I have it so far. It's working for the largest part, so if it's not helpful for the question, at least it may be fun or helpful to future visitors.
/**
* Game11 class
*/
function Game11(container) {
var game = this;
game.element = container;
game.cells = [];
game.highestValue = 4;
game.animations = [];
game.animating = false;
var four = this.random(25);
for (var i = 0; i < 25; i++) {
var cell = new Cell(game, i);
var value = this.random(3) + 1;
if (i == four)
value = 4;
cell.setValue(value);
game.cells[i] = cell;
}
}
Game11.prototype.random = function(to) {
return Math.floor(Math.random() * to);
}
Game11.prototype.cellClicked = function(cell) {
if (cell.selected) {
this.collapse(cell);
} else {
this.select(cell);
}
}
Game11.prototype.collapse = function(cell) {
var newValue = cell.value + 1;
if (newValue > this.highestValue) {
this.highestValue = newValue;
}
cell.setValue(newValue);
for (var i = 24; i >= 0; i--) {
if (this.cells[i].selected) {
if (i !== cell.index) {
this.cells[i].setValue(null);
}
this.cells[i].select(false);
}
}
for (var i = 24; i >= 0; i--) {
if (this.cells[i].value == null) {
this.cells[i].collapse();
}
}
this.animate();
}
Game11.prototype.select = function(cell) {
for (var i = 0; i < 25; i++) {
this.cells[i].select(false);
}
var selectCount = 0;
var stack = [];
stack.push(cell);
while (stack.length > 0) {
var c = stack.pop();
c.select(true);
selectCount++;
var ac = this.getAdjacentCells(c);
for (var i = 0; i < ac.length; i++) {
if (ac[i].selected == false && ac[i].value == cell.value) {
stack.push(ac[i]);
}
}
}
if (selectCount == 1)
cell.select(false);
}
Game11.prototype.getAdjacentCells = function(cell) {
var result = [];
if (cell.x > 0) result.push(this.cells[cell.index - 1]);
if (cell.x < 4) result.push(this.cells[cell.index + 1]);
if (cell.y > 0) result.push(this.cells[cell.index - 5]);
if (cell.y < 4) result.push(this.cells[cell.index + 5]);
return result;
}
Game11.prototype.registerAnimation = function(animation) {
this.animations.push(animation);
}
Game11.prototype.animate = function() {
this.animating = true;
var maxTicks = 300;
var start = new Date().valueOf();
var timer = setInterval(function(){
var tick = new Date().valueOf() - start;
if (tick >= maxTicks) {
tick = maxTicks;
this.animating = false;
}
var percentage = 100 / maxTicks * tick;
for (a = 0; a < this.animations.length; a++) {
this.animations[a].step(percentage);
}
if (this.animating === false) {
clearInterval(timer);
this.animations.length = 0;
console.log('x');
}
}.bind(this), 1);
}
/**
* A single cell
*/
function Cell(game, index) {
var cell = this;
cell.game = game;
cell.index = index;
cell.selected = false;
cell.element = document.createElement('div');
cell.element.className = 'cell';
cell.digit = document.createElement('div');
cell.digit.className = 'digit';
cell.element.appendChild(cell.digit);
cell.element.addEventListener('click', cell.clicked.bind(cell));
game.element.appendChild(cell.element);
cell.x = index % 5;
cell.y = Math.floor((index - cell.x) / 5);
cell.element.style.left = (cell.x * 20) + '%';
cell.element.style.top = (cell.y * 20) + '%';
}
Cell.prototype.clicked = function() {
this.game.cellClicked(this);
}
Cell.prototype.setValue = function(value) {
this.digit.classList.remove('digit' + this.value);
this.value = value;
if (value === null) {
this.digit.innerText = '';
} else {
this.digit.classList.add('digit' + value);
this.digit.innerText = value;
}
}
Cell.prototype.select = function(selected) {
this.element.classList.toggle('selected', selected);
this.selected = selected;
}
Cell.prototype.collapse = function() {
var value, y, cellHere, cellAbove;
var n = this.y;
var offset = 0;
do {
cellHere = this.game.cells[this.x + 5*n];
y = n - offset;
value = null;
do {
if (--y >= 0) {
cellAbove = this.game.cells[this.x + 5*y];
value = cellAbove.value;
cellAbove.setValue(null);
if (value !== null) {
console.log('Value ' + value + ' for cell (' + this.x+','+n+') taken from cell ' + y);
}
} else {
offset++;
value = this.game.random(Math.max(3, this.game.highestValue - 2)) + 1;
console.log('New value ' + value + ' for cell (' + this.x+','+n+')');
}
} while (value === null);
cellHere.animateDrop(value, n-y);
} while (--n >= 0)
}
Cell.prototype.animateDrop = function(value, distance) {
this.setValue(value);
new Animation(this.game, -distance, this.index, value);
}
/**
* A cell animation
*/
function Animation(game, from, to, value) {
this.toCell = game.cells[to];
var cellBounds = this.toCell.element.getBoundingClientRect();
var fromX = toX = cellBounds.left;
var fromY = toY = cellBounds.top;
if (from < 0) {
fromY += cellBounds.height * from;
} else {
// To do: Moving from one cell to another needs an extra sprite.
this.fromCell = game.cells[from];
cellBounds = this.fromCell.element.getBoundingClientRect();
var fromX = cellBounds.left;
var fromY = cellBounds.top;
}
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
this.to = to;
game.registerAnimation(this);
}
Animation.prototype.step = function(percentage) {
var distance = this.toY - this.fromY;
var step = (100-percentage) / 100;
var Y = step * distance;
this.toCell.digit.style.top = '' + (-Y) + 'px';
}
// Start the game
new Game11(document.querySelector('.game11'));
.game11,
.game11 .cell,
.game11 .cell .digit {
box-sizing: border-box;
}
.game11 {
width: 90vmin;
height: 90vmin;
box-sizing: border-box;
position: relative;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.game11 .cell {
width: 20%;
height: 20%;
border: 2px solid #ffffff;
position: absolute;
font-size: 10vmin;
}
.game11 .cell .digit {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
border: 3px solid #666633;
text-align: center;
padding-top: 13%;
font-family: Impact, Charcoal, sans-serif;
color: #111111;
}
.game11 .cell.selected .digit {
color: white;
}
.game11 .digit.digit1 {
background-color: #CC66FF;
}
.game11 .digit.digit2 {
background-color: #FFCC66;
}
.game11 .digit.digit3 {
background-color: #3366FF;
}
.game11 .digit.digit4 {
background-color: #99CCFF;
}
.game11 .digit.digit5 {
background-color: #19D119;
}
.game11 .digit.digit6 {
background-color: #009999;
}
.game11 .digit.digit7 {
background-color: #996600;
}
.game11 .digit.digit8 {
background-color: #009933;
}
.game11 .digit.digit9 {
background-color: #666699;
}
.game11 .digit.digit10 {
background-color: #CC66FF;
}
.game11 .digit.digit11,
.game11 .digit.digitmax {
background-color: #FF0066;
}
<div class="game11">
</div>
You could set font size to vmin value.
.game11 .cell {
font-size: 10vmin;
}
http://jsfiddle.net/a21s77c8/
If there is no CSS solution, you can do it by JavaScript. This is quite easy, since all the game's cells are squared and the same size, so you can just get the font size as a factor of the game width. Because of these boundaries, there is no need for a complex library.
All you need to do is remove the font-size from the CSS and add this piece of code to the constructor of Game11:
// Function that calculates font size based on width of the game itself.
var updateFontSize = function() {
var bounds = game.element.getBoundingClientRect(); // Game
var size = bounds.width / 5; // Cell
size *= 0.6; // Font a bit smaller
game.element.style.fontSize = size + 'px';
};
// Attach to resize event.
window.addEventListener('resize', updateFontSize);
// Initial font size calculation.
updateFontSize();
Updated game:
/**
* Game11 class
*/
function Game11(container) {
var game = this;
game.element = container;
game.cells = [];
game.highestValue = 4;
game.animations = [];
game.animating = false;
var four = this.random(25);
// Function that calculates font size based on width of the game itself.
var updateFontSize = function() {
var bounds = game.element.getBoundingClientRect(); // Game
var size = bounds.width / 5; // Cell
size *= 0.6; // Font a bit smaller
game.element.style.fontSize = size + 'px';
};
// Attach to resize event.
window.addEventListener('resize', updateFontSize);
// Initial font size calculation.
updateFontSize();
for (var i = 0; i < 25; i++) {
var cell = new Cell(game, i);
var value = this.random(3) + 1;
if (i == four)
value = 4;
cell.setValue(value);
game.cells[i] = cell;
}
}
Game11.prototype.random = function(to) {
return Math.floor(Math.random() * to);
}
Game11.prototype.cellClicked = function(cell) {
if (cell.selected) {
this.collapse(cell);
} else {
this.select(cell);
}
}
Game11.prototype.collapse = function(cell) {
var newValue = cell.value + 1;
if (newValue > this.highestValue) {
this.highestValue = newValue;
}
cell.setValue(newValue);
for (var i = 24; i >= 0; i--) {
if (this.cells[i].selected) {
if (i !== cell.index) {
this.cells[i].setValue(null);
}
this.cells[i].select(false);
}
}
for (var i = 24; i >= 0; i--) {
if (this.cells[i].value == null) {
this.cells[i].collapse();
}
}
this.animate();
}
Game11.prototype.select = function(cell) {
for (var i = 0; i < 25; i++) {
this.cells[i].select(false);
}
var selectCount = 0;
var stack = [];
stack.push(cell);
while (stack.length > 0) {
var c = stack.pop();
c.select(true);
selectCount++;
var ac = this.getAdjacentCells(c);
for (var i = 0; i < ac.length; i++) {
if (ac[i].selected == false && ac[i].value == cell.value) {
stack.push(ac[i]);
}
}
}
if (selectCount == 1)
cell.select(false);
}
Game11.prototype.getAdjacentCells = function(cell) {
var result = [];
if (cell.x > 0) result.push(this.cells[cell.index - 1]);
if (cell.x < 4) result.push(this.cells[cell.index + 1]);
if (cell.y > 0) result.push(this.cells[cell.index - 5]);
if (cell.y < 4) result.push(this.cells[cell.index + 5]);
return result;
}
Game11.prototype.registerAnimation = function(animation) {
this.animations.push(animation);
}
Game11.prototype.animate = function() {
this.animating = true;
var maxTicks = 300;
var start = new Date().valueOf();
var timer = setInterval(function(){
var tick = new Date().valueOf() - start;
if (tick >= maxTicks) {
tick = maxTicks;
this.animating = false;
}
var percentage = 100 / maxTicks * tick;
for (a = 0; a < this.animations.length; a++) {
this.animations[a].step(percentage);
}
if (this.animating === false) {
clearInterval(timer);
this.animations.length = 0;
console.log('x');
}
}.bind(this), 1);
}
/**
* A single cell
*/
function Cell(game, index) {
var cell = this;
cell.game = game;
cell.index = index;
cell.selected = false;
cell.element = document.createElement('div');
cell.element.className = 'cell';
cell.digit = document.createElement('div');
cell.digit.className = 'digit';
cell.element.appendChild(cell.digit);
cell.element.addEventListener('click', cell.clicked.bind(cell));
game.element.appendChild(cell.element);
cell.x = index % 5;
cell.y = Math.floor((index - cell.x) / 5);
cell.element.style.left = (cell.x * 20) + '%';
cell.element.style.top = (cell.y * 20) + '%';
}
Cell.prototype.clicked = function() {
this.game.cellClicked(this);
}
Cell.prototype.setValue = function(value) {
this.digit.classList.remove('digit' + this.value);
this.value = value;
if (value === null) {
this.digit.innerText = '';
} else {
this.digit.classList.add('digit' + value);
this.digit.innerText = value;
}
}
Cell.prototype.select = function(selected) {
this.element.classList.toggle('selected', selected);
this.selected = selected;
}
Cell.prototype.collapse = function() {
var value, y, cellHere, cellAbove;
var n = this.y;
var offset = 0;
do {
cellHere = this.game.cells[this.x + 5*n];
y = n - offset;
value = null;
do {
if (--y >= 0) {
cellAbove = this.game.cells[this.x + 5*y];
value = cellAbove.value;
cellAbove.setValue(null);
if (value !== null) {
console.log('Value ' + value + ' for cell (' + this.x+','+n+') taken from cell ' + y);
}
} else {
offset++;
value = this.game.random(Math.max(3, this.game.highestValue - 2)) + 1;
console.log('New value ' + value + ' for cell (' + this.x+','+n+')');
}
} while (value === null);
cellHere.animateDrop(value, n-y);
} while (--n >= 0)
}
Cell.prototype.animateDrop = function(value, distance) {
this.setValue(value);
new Animation(this.game, -distance, this.index, value);
}
/**
* A cell animation
*/
function Animation(game, from, to, value) {
this.toCell = game.cells[to];
var cellBounds = this.toCell.element.getBoundingClientRect();
var fromX = toX = cellBounds.left;
var fromY = toY = cellBounds.top;
if (from < 0) {
fromY += cellBounds.height * from;
} else {
// To do: Moving from one cell to another needs an extra sprite.
this.fromCell = game.cells[from];
cellBounds = this.fromCell.element.getBoundingClientRect();
var fromX = cellBounds.left;
var fromY = cellBounds.top;
}
this.fromX = fromX;
this.fromY = fromY;
this.toX = toX;
this.toY = toY;
this.to = to;
game.registerAnimation(this);
}
Animation.prototype.step = function(percentage) {
var distance = this.toY - this.fromY;
var step = (100-percentage) / 100;
var Y = step * distance;
this.toCell.digit.style.top = '' + (-Y) + 'px';
}
// Start the game
new Game11(document.querySelector('.game11'));
.game11,
.game11 .cell,
.game11 .cell .digit {
box-sizing: border-box;
}
.game11 {
width: 90vw;
height: 90vw;
max-width: 90vh;
max-height: 90vh;
box-sizing: border-box;
position: relative;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.game11 .cell {
width: 20%;
height: 20%;
border: 2px solid #ffffff;
position: absolute;
}
.game11 .cell .digit {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
border: 3px solid #666633;
text-align: center;
padding-top: 13%;
font-family: Impact, Charcoal, sans-serif;
color: #111111;
}
.game11 .cell.selected .digit {
color: white;
}
.game11 .digit.digit1 {
background-color: #CC66FF;
}
.game11 .digit.digit2 {
background-color: #FFCC66;
}
.game11 .digit.digit3 {
background-color: #3366FF;
}
.game11 .digit.digit4 {
background-color: #99CCFF;
}
.game11 .digit.digit5 {
background-color: #19D119;
}
.game11 .digit.digit6 {
background-color: #009999;
}
.game11 .digit.digit7 {
background-color: #996600;
}
.game11 .digit.digit8 {
background-color: #009933;
}
.game11 .digit.digit9 {
background-color: #666699;
}
.game11 .digit.digit10 {
background-color: #CC66FF;
}
.game11 .digit.digit11,
.game11 .digit.digitmax {
background-color: #FF0066;
}
<div class="game11">
</div>
Still, if it could be done through CSS, that'd be great.