Changing text color depending on background - css

I have a background that animates (it is not a solid color, but actually a canvas animation), but will at each "end" have two specific colors. I would like some text that sits on top of the animation to change color such that when it sits on top of the lighter of the two it is black, and on top of the darker of the two it is white.
To illustrate, see simplified snippet below with simpler animated background (it's not too far from black, but quite far from white)
window.addEventListener("load", function() {
var ctx = c.getContext("2d");
function draw(timestamp) {
ctx.fillStyle = "#BDDAE4";
ctx.fillRect(0, 0, c.width, c.height);
var x = (timestamp / 50) % (c.width + 40) - 40;
ctx.fillStyle = "#79B3C9";
ctx.fillRect(x, 40, 40, c.height - 40);
ctx.fillRect(0, c.height - 40, c.width, c.height);
window.requestAnimationFrame(draw);
}
window.requestAnimationFrame(draw);
}, false);
* {
margin: 0;
padding: 0;
}
div {
overflow: scroll;
height: 40px;
position: relative;
}
div p {
font-size: 2em;
mix-blend-mode: difference;
color: white;
position: fixed;
pointer-events: none;
top: 0;
}
<div>
<canvas id="c" height="120" width="100"></canvas>
<p>TEXT</p>
</div>
<p>(Scroll on the text to see)</p>
I figure that if there is a way, it will include mix-blend-mode and/or filter.

Related

Ending a svg path drawing in FabricJs using right mouse click

I am using fabric JS version 4.5.0 working on a draw application.
I want to use the right mouse click to end the brush drawing but cannot achieve this.
please take a look at this codepen snippet (credits to michaelsboost) I am doing something similar to it.
if (tool.toString().toLowerCase() === 'pencil') {
changeObjectSelection(false);
canvas.freeDrawingBrush = new fabric.PencilBrush(canvas);
canvas.freeDrawingBrush.strokeLineCap = $('#brushStrokeCap').val(); // butt / round / square
canvas.freeDrawingBrush.strokeLineJoin = $('#brushStrokeLineJoin').val(); // bevel / round / miter
canvas.freeDrawingBrush.strokeMiterLimit = $('#brushMiter').val();
canvas.freeDrawingBrush.width = 1;
canvas.freeDrawingBrush.color = strokePickr.getColor().toRGBA().toString();
canvas.isDrawingMode = true;
}
what changes need to be added there to use left mouse click and right mouse click interchangebly to end a svg path drawing?
currently, if you select the pencil tool, clicked using your left mouse button it starts the drawing.
If you right clicked it opens a menu, select copy image, and move your mouse.
Undesired behaviour: try to left click, the whole drawing disappears.
Desired behaviour: right mouse click should end the drawing as a svg on canvas.
// Get a reference to the canvas element
var canvas = new fabric.Canvas('canvas');
canvas.isDrawingMode = true;
// Add a rectangle to the canvas
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'green',
width: 100,
height: 100
});
canvas.add(rect);
document.onclick = hideMenu;
document.oncontextmenu = rightClick;
function hideMenu() {
document.getElementById("contextMenu").style.display = "none"
}
function rightClick(e) {
e.preventDefault();
var menu = document.getElementById("contextMenu")
menu.style.display = 'block';
menu.style.left = e.pageX + "px";
menu.style.top = e.pageY + "px";
}
.context-menu {
position: absolute;
text-align: center;
background: lightgray;
border: 1px solid black;
}
.context-menu ul {
padding: 0px;
margin: 0px;
min-width: 150px;
list-style: none;
}
.context-menu ul li {
padding-bottom: 7px;
padding-top: 7px;
border: 1px solid black;
}
.context-menu ul li a {
text-decoration: none;
color: black;
}
.context-menu ul li:hover {
background: darkgray;
}
<canvas id="canvas" width="1920px" height="1080px"></canvas>
<div id="contextMenu" class="context-menu" style="display:none">
<ul>
<li onclick="canvas.isDrawingMode = true">Drawing mode true</li>
<li onclick="canvas.isDrawingMode = false">Drawing mode false</li>
</ul>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.5.0/fabric.min.js"></script>

set width and height of an image after transform: rotate

i have a div with width: 190px and height: 260px, i assign img tag on that div, when i upload an image that shows how the image before, after that i rotate the image but the width and height of the image didnt change like the div, i have used inherit, everything about position and display, but no good at all..
I have figured out an automated way as below:
First, I am getting natural height and width of the image (from onload trigger):
var naturalWidth = event.currentTarget.naturalWidth
var naturalHeight = event.currentTarget.naturalHeight
Then I am computing a transform scale using aspect-ratio and generating transform style as below (pseudo-code):
For 90deg (y-shift):
const scale = naturalWidth > naturalHeight ? naturalHeight / naturalWidth : 1;
const yshift = -100 * scale;
const style = `transform:rotate(90deg) translateY(${yshift}%) scale(${scale}); transform-origin: top left;`
For 270deg (x-shift):
const scale = naturalWidth > naturalHeight ? naturalHeight / naturalWidth : 1;
const xshift = -100 * scale;
const style = `transform:rotate(270deg) translateX(${xshift}%) scale(${scale}); transform-origin: top left;`
Hope this helps.
Inherit will not work.
Because you have to make the set the width of your image as the height of your parent. Then it will get completely resize in the parent element.
image-width = parent-height
Because after applying transform property width and height property will also get rotate in its respect.
Sol 1:
change the width of your image along with the transform property. (If it is variable then you can use the SCSS variables to assign the same values to the image-width and parent height.)
Sol 2:
This is not the perfect solution but will work in many cases. Add scale property to your transform property like this
transform: rotate(90deg) scale(.7);
Adjust the scale values according to you.
Hey,
Please Try this code.
var $=jQuery.noConflict();
$(document).ready(function(){
$('#RotateButton').click(function(){
$('.col').toggleClass("afterRot");
});
});
/* ----- IE Support CSS Script ----- */
var userAgent, ieReg, ie;
userAgent = window.navigator.userAgent;
ieReg = /msie|Trident.*rv[ :]*11\./gi;
ie = ieReg.test(userAgent);
if(ie) {
$(".col").each(function () {
var $container = $(this),
imgUrl = $container.find("img").prop("src");
if (imgUrl) {
$container.css("backgroundImage", 'url(' + imgUrl + ')').addClass("custom-object-fit");
}
});
}
body { padding: 0; margin: 0; }
.col { position: relative; display: block; width:100vh; height: 100vh; }
.afterRot{ transform: rotate(90deg); object-fit: cover; }
.col img { position: absolute; top: 0; left: 0; right: 0; width: 100%; height: 100%; object-fit: cover; }
.custom-object-fit { position: relative; background-size: cover; background-position: center center; }
.custom-object-fit img { opacity: 0; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="mob">
<button type="button" id="RotateButton"> Rotate </button>
<div class="col">
<img class="nor" id="rowImg" src="https://cdn-images-1.medium.com/max/1600/1*tSyuv3ZRCfsSD5aXB7v8DQ.png">
</div>
</div>
I think this is because you are not removing the class already associated with the Image. Try adding this to your button
$(document).ready(function(){
$('#RotateButton').click(function(){
$('#rowImg').removeClass("normalx").addClass("afterRot");
});
});
for a css like
.col {
width:260px;
height:190px:
border: solid 1px #6c757d;
padding: 10px;
}
.nor{
width:250px;
height:150px;
}
.afterRot{
width:inherit;
transform: rotate(90deg);
}
I have a sample here

Zooming in overflow: scroll

I am trying to implement correctly scaling and zooming in css way. I created an example with scaled view. When click, the view should be zoomed and then to be able to scroll.
https://jsfiddle.net/opb5tcy8/4/
I have several issues with it:
Can I somehow get rid of the margin-left and margin-top on the .zoomed class? I did not manage to scale it without necessity to shift it with these margins.
When clicked, I can get the click position by clientX. I would like to use it to fluently scroll to the clicked position during zooming. However I can't manage the scroll to be fluent and when removing the margin-left it is kind of jumpy and not nice.
When you zoom in and move the scroll to the center and then zoom out, you can see the zoom is not nice as it first scrolls to the right. Is there a way to prevent it?
When you scroll to corners in Chrome on OSX it tends do navigate back/forward in browser. Is there a way to prevent this behaviour?
UPDATE:
The first part can be solved with transform-origin: 0 0. The other issues stays mostly the same as it is demonstrated.
Hm... I could say it is impossible to satisfy point 2 your condition with current browsers' support. The other are possible, as in this demo:
$(document).ready(function() {
var windowHalfWidth = $("#window").width() / 2;
var scalingFactor = 0.55;
var throtte = false;
$("#slider").click(function(event) {
//Simple event throtte to prevent click spamming breaking stuff up
if (throtte) return false;
throtte = true;
setTimeout(function() {
throtte = false;
}, 1000);
var xSelf = event.pageX - $("#window").offset().left + $("#window").scrollLeft();
if ($(this).hasClass("zoomed")) {
$("#window").animate({
scrollLeft: (xSelf / scalingFactor - windowHalfWidth)
}, 1000, "linear");
} else {
$("#window").animate({
scrollLeft: (xSelf * scalingFactor - windowHalfWidth)
}, 1000, "linear");
}
$("#slider").toggleClass("zoomed");
});
});
body {
background-color: #eee;
margin-top: 10px; /*reduced margin for easier view in SO */
}
#window {
width: 500px;
height: 200px;
margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;
border: 1px solid #999;
position: relative;
background-color: white;
}
#slider {
width: 900px;
height: 600px;
background-color: #fff;
position: absolute;
transition: 1s linear;
top: 0;
left: 0;
transform-origin: 0 0;
}
#slider.zoomed {
transform: scale(0.55);
}
#slider div {
width: 50px;
height: 50px;
line-height: 50px;
position: absolute;
top: 75px;
background-color: #eee;
text-align: center;
}
#obj1 {
left: 10px;
}
#obj2 {
left: 210px;
}
#obj3 {
left: 410px;
}
#obj4 {
left: 610px;
}
#obj5 {
left: 810px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="window">
<div id="slider" class="zoomed">
<div id="obj1">1</div>
<div id="obj2">2</div>
<div id="obj3">3</div>
<div id="obj4">4</div>
<div id="obj5">5</div>
</div>
</div>
As you can see, the zooming & scrolling is quite laggy, especially when the far right size is zoomed in.
The reason is simple, because jQuery and css both have their own animation loop, and they are not in sync. In order to solve this we'll need to somehow manage to do both scrolling & scaling animations with only one system, either jQuery or CSS.
Problem is: jQuery don't have a scaling feature, and css can't scroll elements. Wonderful.
If your scaling can be done with width/height though, it would be possible, using jquery width&height animate(). But if the #slider consists of many components I guess it can't be done.
So um writing an answer just to say it's impossible is kind of a let down, so I think maybe I can suggest an alternative, using dragging to scroll content (similar to the way Google map work):
var windowHalfWidth, startX, startLeft, minLeft, dragging = false,
zooming = false;
var zoomElement = function(event) {
var xSelf = event.pageX - $("#window").offset().left - parseFloat($("#slider").css("left"));
if ($("#slider").hasClass("zoomed")) {
minLeft = windowHalfWidth * 2 - 900;
var newLeft = Math.min(Math.max((-(xSelf / 0.55 - windowHalfWidth)), minLeft), 0);
$("#slider").css("left", newLeft + "px");
} else {
minLeft = windowHalfWidth * 2 - 900 * 0.55;
var newLeft = Math.min(Math.max((-(xSelf * 0.55 - windowHalfWidth)), minLeft), 0);
$("#slider").css("left", newLeft + "px");
}
$("#slider").toggleClass("zoomed");
}
$(document).ready(function() {
windowHalfWidth = $("#window").width() / 2;
minLeft = windowHalfWidth * 2 - 900 * 0.55;
$("#slider").on({
mousedown: function(event) {
dragging = true;
startX = event.pageX;
startLeft = parseFloat($(this).css("left"));
},
mousemove: function(event) {
if (dragging && !zooming) {
var newLeft = Math.min(Math.max((startLeft + event.pageX - startX), minLeft), 0);
$("#slider").css("left", newLeft + "px");
}
},
mouseup: function(event) {
dragging = false;
if (Math.abs(startX - event.pageX) < 30 && !zooming) {
// Simple event throtte to prevent click spamming
zooming = true;
$("#slider").css("transition", "1s");
setTimeout(function() {
zooming = false;
$("#slider").css("transition", "initial");
}, 1000);
zoomElement(event);
}
},
mouseleave: function() {
dragging = false;
}
});
});
body {
background-color: #eee;
margin-top: 10px; /*reduced margin for easier view in SO */
}
#window {
width: 500px;
height: 200px;
margin: 0 auto;
overflow: hidden;
border: 1px solid #999;
position: relative;
background-color: white;
}
#slider {
width: 900px;
height: 600px;
background-color: #fff;
position: absolute;
top: 0;
left: 0;
transform-origin: 0 0;
}
#slider.zoomed {
transform: scale(0.55);
}
#slider div {
width: 50px;
height: 50px;
line-height: 50px;
position: absolute;
top: 75px;
background-color: #eee;
text-align: center;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#obj1 {
left: 10px;
}
#obj2 {
left: 210px;
}
#obj3 {
left: 410px;
}
#obj4 {
left: 610px;
}
#obj5 {
left: 810px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="window">
<div id="slider" class="zoomed">
<div id="obj1">1</div>
<div id="obj2">2</div>
<div id="obj3">3</div>
<div id="obj4">4</div>
<div id="obj5">5</div>
</div>
</div>
This variation manages to get CSS to do both animation, by sacrificing the scrollbar (which is pretty ugly imo, who needs it?) and use css left instead.
So I hope if in the end you can't find a good solution, at least you have this to consider as fall back version.
I'll address the points individually and then give an example at the end.
When clicked, I can get the click position by clientX. I would like to
use it to fluently scroll to the clicked position during zooming.
In my opinion scroll animations during transitions can be a bit choppy in webkit browsers. Try balancing the animation time of the jQuery effect with the animation time of the css transition.
When you zoom in and move the scroll to the centre and then zoom out, you can see the zoom is not nice as it first scrolls to the right. Is there a way to prevent it?
Bring the scrollLeft property of the div#window back to 0px. Again, tweaking the animation times will make this less jerky.
When you scroll to corners in Chrome on OSX it tends do navigate back/forward in browser. Is there a way to prevent this behaviour?
You could use the mouseover and mouseout events to toggle a overflow:hidden css on the body.
Here's an example change to your code:
var slider = $("#slider").on('click', function(event) {
if (!slider.hasClass('zoomed')) {
// zoom back to left position
$('#window').animate({scrollLeft:'0px'});
}else{
// zoom to click position within slider
$('#window').animate({scrollLeft:event.clientX + 'px'}, 2000);
}
slider.toggleClass("zoomed");
});
/* stop window scrolling when using slider */
slider
.on('mouseover', function () {
$(document.body).css({overflow:'hidden'});
})
.on('mouseout', function () {
$(document.body).css({overflow:'auto'});
});
And an updated fiddle.

Backbone svg cube events getting disabled on flip

Just a bit of trivia: I have started using backbone just a month back and svg about a week back. Basically am still learning.
I mainly have a cube. On load the front face has a circle divided into sectors. Each sector is clickable. On clicking each sector the cube flips 90 degrees right and that particular sector is zoomed and displayed there.
Now there is a slider on the zoomed sector ranging from 0-10. This I have created again using svg circles on a line equidistantly. The problem is that the circles must be clickable so that the value on which it is clicked should be captured.
But once the cube flips none of the events are firing. I have been struggling with this for 3 days now but no luck. Any help from anybody please.
I understand that the delegateEvents() method needs to be called somewhere, but where am not able to make out. Or is it the css transforms that are disabling the events, I don't understand???
Below is my code:
The js file
var CircleView = Backbone.View.extend({
model: this.model,
xmlns: "http://www.w3.org/2000/svg",
events: {
'click path': 'handleClick',
},
handleClick: function(ev) {
var id = $(ev.currentTarget).attr('id');
var el = this.$el;
model = this.model;
var xAngle = 0, yAngle = -90;
// Cube flips here
(document.getElementById('cube')).style.webkitTransform = "rotateX(" + xAngle + "deg) rotateY(" + yAngle + "deg)";
// view to display the zoomed sector
var secView = new SectorView({el: $('#circleEdit2'), model: model, value: value, id: id});
secView.render();
},
render: function(model) {
// Code to draw svg circle with 12 clickable sectors goes here
// On clicking any sector cube flips and zoomed sector is displayed there
// This is working perfectly
el.html($("#face1").html());
return el;
}
})
var SectorView = Backbone.View.extend({
model: this.model,
id: 0,
value: 0,
xmlns: "http://www.w3.org/2000/svg",
events: {
'click circle': 'handleDots'
},
handleDots: function(ev) {
var id = $(ev.currentTarget).attr('id');
var numID = parseInt(id);
alert("Click Event Called");
},
render: function() {
var id = this.id;
var el = this.$el;
model = this.model;
// Code to draw zoomed Sector ranging from 0-10 goes here
// method to draw slider using svg circles on a line equidistantly
// On clicking each circle value should be captured
// Here click event is not firing but all graphics are displayed correctly
this.drawSlider(el, id, winWidth/2, oRadius, value, (winWidth/3 - oRadius/4.7));
$("#face2").html(this.$el);
$("#radios").css("top", winWidth/3.5);
$("#radios").css("left", left);
this.delegateEvents();
}
})
The HTML:
<html>
<head>
<link rel="stylesheet" href="circleEditTool.css">
<script src="jquery-ui-1.10.2\jquery-1.9.1.js"></script>
<script src="underscore.js"></script>
<script src="backbone.js"></script>
<script src="jquery-ui-1.10.2\ui\jquery-ui.js"></script>
<script src="jquery-ui-1.10.2\ui\jquery.ui.core.js"></script>
<script src="jquery-ui-1.10.2\ui\jquery.ui.widget.js"></script>
<script src="jquery-ui-1.10.2\ui\jquery.ui.mouse.js"></script>
<script src="jquery-ui-1.10.2\ui\jquery.ui.slider.js"></script>
</head>
<body>
<div id="cube">
<div class="face one" id="face1">
<svg id="circleEdit1"> </svg>
</div>
<div class="face two" id="face2">
<svg id="circleEdit2"> </svg>
<div id="radios">
<input name='typeOfArea' type='radio' value="Strength" checked>Strength</input>
<input name='typeOfArea' type='radio' value="OK">OK</input>
<input name='typeOfArea' type='radio' value="Weakness">Weakness</input>
</div>
</div>
</div>
</br></br>
<script src="circleEditTool2.js"> </script>
</body>
</html>
The css:
#experiment {
-webkit-perspective: 1200px;
-webkit-perspective-origin: 50% 300px;
}
#cube {
position: center;
margin: auto;
height: 600px;
width: 600px;
-webkit-transition: -webkit-transform 2s linear;
-webkit-transform-style: preserve-3d;
border: 1px solid #ccc;
background: rgba(255, 255, 255, 1);
}
.face {
position: absolute;
height: 600px;
width: 600px;
background-color: rgba(200, 200, 200, 0.7);
-webkit-backface-visibility: hidden;
background-color: #F2F2F2;
}
#cube .one {
-webkit-transform: translateZ(200px);
opacity: 1;
box-shadow: inset 0 0 50px rgba(0, 0, 0, 0.5);
}
#cube .two {
-webkit-transform: rotateY(90deg) translateZ(350px);
opacity: 1;
box-shadow: inset 0 0 50px rgba(0, 0, 0, 0.5);
}

Dynamic Text with surrounding line, whose container has a background image

I need to implement something like this..
-------------------------
| |
| |
|---- dynamic text --- |
| |
-------------------------
I want the line surrounding the "dynamic text" in css.
I tried using &::before and &::after css, but still when the dynamic text changes i need to stretch/decrease that one. Any ideas?
You could use JavaScript to set the width of :before and :after :pseudo-elements dynamically.
function foo() {
var ss = document.styleSheets;
var text = document.getElementById('text');
var box = document.getElementById('box');
var totalWidth = getComputedStyle(box).width.slice(0, -2);
var textWidth = text.offsetWidth;
var lineWidth;
var margin = 4; // Set the margin between text and line.
for (i = 0; i < ss.length; i++) {
var rules = ss[i];
for (j = 0; j < rules.cssRules.length; j++) {
var r = rules.cssRules[j];
if (r.selectorText == "#text:before") {
// If you want the margin to be set on both sides of the line,
// replace 'margin' with '(margin * 2)' in the next line.
lineWidth = ((totalWidth / 2) - (textWidth / 2) - margin);
r.style.width = lineWidth + 'px';
r.style.left = -(lineWidth + margin) + 'px';
} else if (r.selectorText == "#text:after") {
r.style.width = lineWidth + 'px';
r.style.right = -(lineWidth + margin) + 'px';
}
}
}
}
foo();
#box {
width: 300px;
height: 200px;
background-color: #FF0000;
line-height: 200px;
text-align: center;
}
#text {
position: relative;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 10px;
padding: 4px;
color: white;
}
#text:before {
content: "";
position: absolute;
border-bottom: 1px solid black;
height: 100px;
}
#text:after {
content: "";
position: absolute;
border-bottom: 1px solid black;
height: 100px;
}
<div id="box"><span id="text">This is the text which is dynamic</span>
</div>
<div id="divWithBackground">
<div id="divActsAsLine">
<span id="DynamicText">Your text here </span>
</div>
</div>
Now the CSS
#divActsAsLine{
border-botton:1px solid #00;
text-align:center;
}
#DynamicText{
position:relative;
background-color: #fff;
margin-bottom:-20px /*Adjust this based on your requirements*/
z-index:1 /* optional */
}
The logic is to make a div margin as background line and make the span overlap this line, to do this we need to either decrease or increase margin property. you might need to use z-index if necessary

Resources