Backbone svg cube events getting disabled on flip - css

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);
}

Related

How to get SVG container to scroll when scaling it up with transform?

I am using an SVG to load a background image and enabling the user to draw some shapes an upload this new image.
I have a problem, when I rescale the SVG it starts overflowing from its parent container and I can't get the scroll bars to track the area properly.
I am using the library svgdotjs to help out with the SVG creation.
To illustrate my issue:
const url = "https://d32qe1r3a676y7.cloudfront.net/eyJidWNrZXQiOiJibG9nLWVjb3RyZWUiLCJrZXkiOiAiYmxvZy8wMDAxLzAxL2FkNDZkYmI0NDdjZDBlOWE2YWVlY2Q2NGNjMmJkMzMyYjBjYmNiNzkuanBlZyIsImVkaXRzIjp7InJlc2l6ZSI6eyJ3aWR0aCI6IDkwMCwiaGVpZ2h0IjowLCJmaXQiOiJjb3ZlciJ9fX0=";
const container = document.getElementById("container");
const svg = SVG().addTo(container);
const backgroundImage = svg.image(url, (event) => {
const imageOriginalWidth = event.target.naturalWidth;
const imageOriginalHeight = event.target.naturalHeight;
const xFactor = Math.round(container.parentElement.offsetWidth / imageOriginalWidth * 0.96 * 1000) / 1000;
const yFactor = Math.round(container.parentElement.offsetHeight / imageOriginalHeight * 0.96 * 1000) / 1000;
const resizeFactor = Math.min(xFactor, yFactor);
svg.size(imageOriginalWidth * resizeFactor, imageOriginalHeight * resizeFactor);
backgroundImage.size(imageOriginalWidth * resizeFactor, imageOriginalHeight * resizeFactor);
});
document.getElementById("zoomIn").addEventListener("click", () => {
svg.scale(1.1, 0, 0);
});
document.getElementById("zoomOut").addEventListener("click", () => {
svg.scale(0.9, 0, 0);
});
body {
width: 100%;
height: 100%;
}
.card-body {
height: 80%;
width: 80%;
border: solid 1px red;
}
#container {
display: block;
overflow: scroll;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/3.1.2/svg.min.js" integrity="sha512-I+rKw3hArzZIHzrkdELbKqrXfkSvw/h0lW/GgB8FThaBVz2e5ZUlSW8kY8v3q6wq37eybIwyufkEZxe4qSlGcg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<div class="card-body">
<div id="container">
</div>
</div>
<div>
<button id="zoomIn">
ZoomIn
</button>
<button id="zoomOut">
ZoomOut
</button>
</div>
If you click on zoomIn the SVG is going to scale up but the scrollbar is not going to track the overflow properly.
Thank you for your help.

How to show Captions in an external container using JWPlayer v8

Our videos use the lower third of the page for introductions, etc. much like TV News stations do. When captions are on, they're blocking all of that, thus creating a LOT of complaints from the communities that need the captions. I've tried tinkering with the CSS, but with a responsive layout, resizing the player wreaks havoc, often putting them out of sight altogether.
Is there a setting that can be changed, or technique to use, that will keep the captions at the top and in view when resized, OR in an external container?
Problem: the JW player 608 live captions are not formatted cleanly.
To solve this, disable the JW caption display and format our own window, named "ccbuffer"
<style type="text/css">
.jw-captions {
display: none !important;
}
#ccbuffer {
border: 2px solid white !important;
border-radius: 4px;
background-color: black !important;
display: flex;
height: 120px;
margin-top: 6px;
font: 22px bold arial, sans-serif;
color: white;
justify-content: center;
align-items: center;
}
</style>
Here is where I show the player, and ccbuffer is a div right below it
<div id="myPlayer">
<p style="color: #FFFFFF; font-weight: bold; font-size: x-large; border-style: solid; border-color: #E2AA4F">
Loading video...
</p>
</div>
<div id="ccbuffer" />
DOMSubtreeModified is deprecated. Use MutationObserver, which is less stressful on the client.
Let's hook the 'captionsChanged' event from JW. if track is 0 then no captions are selected and we disconnect the observer. If captions are selected, then we use jquery to pull the text out of the jw-text-track-cue element, and format it into a nice 3 line display in our ccbuffer window.
<script>
var observer;
jwplayer().on('captionsChanged', function (event) {
if (event.track == 0) {
observer.disconnect();
$('#ccbuffer').hide('slow');
}
else {
$('#ccbuffer').show('slow');
// select the target node
var target = document.querySelector('.jw-captions');
// create an observer instance
observer = new MutationObserver(function(mutations) {
$('.jw-text-track-cue').each(function(i) {
if (i == 0)
$('#ccbuffer').html( $(this).text() );
else
$('#ccbuffer').append("<br/>" + $(this).text() );
});
});
// configuration of the observer:
var config = { attributes: true, childList: true, characterData: true }
// pass in the target node, as well as the observer options
observer.observe(target, config);
}
});
$(document).ready(function () {
$('#ccbuffer').hide();
});
</script>
So when the user enables captions, the ccbuffer window will slide open and display a clean 3 line representation of the CC text.
Final Solution: External Captions that are draggable/resizable
All credit to #Basildane, I worked out how to extenalize the captions with VOD, and to make them draggable and resizable, with CSS experimentation for ADA consideration:
<!DOCTYPE html>
<html>
<head>
<title>JW External Captions</title>
<meta http-equiv="Expires" content="Fri, Jan 01 1900 00:00:00 GMT">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="Lang" content="en">
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="/jwplayer/v8.10/jwplayer.js"></script>
<style type="text/css">
#myPlayer {
margin-bottom:5px;
}
.jw-captions {
display: none !important;
}
#ccbuffer {
color: white;
background-color: black;
opacity:.7;
font: 22px bold san-serif;
width: 100%;
padding: 15px;
height: 100%;
position:relative;
}
.night {
color:silver !important;
background-color: black !important;
opacity:1 !important;
border-color:silver !important;
}
.highcontrast {
color:white ! important;
background-color: black !important;
opacity:1 !important;
border-color:white !important;
}
.highcontrast2 {
color:black !important;
background-color: yellow !important;
opacity:1 !important;
border-color:black !important;
}
.highcontrast3 {
color:yellow !important;
background-color: black !important;
opacity:1 !important;
border-color:yellow !important;
}
#ccContainer {
position: absolute;
z-index: 9;
border: 1px solid inherit;
overflow: hidden;
resize: both;
width: 640px;
height: 180px;
min-width: 120px;
min-height: 90px;
max-width: 960px;
max-height: 300px;
}
#ccContainerheader {
padding: 3px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
border:1px solid;
}
</style>
</head>
<body>
<h3>JW Draggable Captions Container</h3>
<div id="PlayerContainer" style="width:401px;">
<div id="myPlayer">Loading video...</div>
</div>
<div id="ccContainer">
<!-- Include a header DIV with the same name as the draggable DIV, followed by "header" -->
<div style="float:right;">
<form id="myform">
<select id="ccFontFamily">
<option value="sans-serif">Default Font</option>
<option value="serif">Serif</option>
<option value="monospace">Monospace</option>
<option value="cursive">Cursive </option>
</select>
<select id="ccFontSize" style="">
<option value="22">Default Size</option>
<option value="14">14</option>
<option value="18">18</option>
<option value="24">24</option>
<option value="32">32</option>
</select>
<select id="ccContrast" style="">
<option value="ccdefault">Default Contrast</option>
<option value="night">Night</option>
<option value="highcontrast">High Contrast</option>
<option value="highcontrast2">Black/Yellow</option>
<option value="highcontrast3">Yellow/Black</option>
</select>
<button id="ccFontReset">Reset</button>
</form>
</div>
<div id="ccContainerheader">
Captions (click to move)
</div>
<div id="ccbuffer"></div>
</div>
<script type="text/javascript">
$(document).ready(function() {
jwplayer.key = 'xxxxxxxxxxxxxxxxxxx';
jwplayer('myPlayer').setup({
width: '100%', aspectratio: '16:9', repeat: 'false', autostart: 'false',
playlist: [{
sources: [ { file: 'https:www.example.com/video.mp4'}],
tracks: [ { file: 'https:www.example.com/video-captions.vtt', kind: 'captions', label: 'English', 'default': true } ]
}]
})
// External CC Container
$('#ccContainer').hide();
var position = $('#myPlayer').position();
var width = $('#PlayerContainer').outerWidth();
ccTop = position.top;
ccLeft = (width+50)+'px'
$('#ccContainer').css({'top':ccTop, left:ccLeft });
var observer;
jwplayer().on('captionsList', function (event) {
ccObserver(event);
});
jwplayer().on('captionsChanged', function (event) {
ccObserver(event);
});
videoplayer.on('fullscreen', function(event){
if(event.fullscreen){
$('.jw-captions').css('display','block');
}else{
$('.jw-captions').css('display','none');
}
});
$("#ccFontFamily").change(function() {
$('#ccbuffer').css("font-family", $(this).val());
});
$("#ccFontSize").change(function() {
$('#ccbuffer').css("font-size", $(this).val() + "px");
});
$("#ccContrast").change(function() {
$('#ccContainer').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
$('#ccContainerheader').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
$('#ccbuffer').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
$('select').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
$('#ccFontReset').removeClass("night highcontrast highcontrast2 highcontrast3").addClass( $(this).val() );
});
$('#ccFontReset').click(function() {
ccFontReset();
});
function ccFontReset(){
$("#ccFontFamily").val($("#ccFontFamily option:first").val()).trigger('change');
$("#ccFontSize").val($("#ccFontSize option:first").val()).trigger('change');
$("#ccContrast").val($("#ccContrast option:first").val()).trigger('change');
}
ccFontReset();
});
function ccObserver(event){
if (event.track == 0) {
$('#ccContainer').hide('slow');
$('.jw-captions').css('display','block'); // VERY important
if (observer != null){
observer.disconnect();
}
}
else {
$('#ccContainer').show('slow');
$('.jw-captions').css('display','none'); // VERY important
var target = document.querySelector('.jw-captions');
observer = new MutationObserver(function(mutations) {
$('.jw-text-track-cue').each(function(i) {
if (i == 0)
$('#ccbuffer').html( $(this).text() );
else
$('#ccbuffer').append("<br/>" + $(this).text() );
});
});
var config = { attributes: true, childList: true, characterData: true }
observer.observe(target, config);
}
}
// External CC Container - Make the DIV element draggable:
dragElement(document.getElementById("ccContainer"));
function dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById(elmnt.id + "header")) {
document.getElementById(elmnt.id + "header").onmousedown = dragMouseDown;
} else {
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
}
}
</script>
</body>
</html>

Unable to click checkboxes after styling

I have tried to style some checkboxes but now I can't click on/ activate/ check them. Radio buttons that are mostly styled the same way do work.
$(document).ready(function() {
var $selection = $('.sc-checkbox');
$selection.each(function() {
var $this = $(this),
$id = $this.attr('id');
$this.after( '<label for="' + $id + '"></label>' );
});
});
input[type="checkbox"].sc-checkbox {
-webkit-opacity: 0;
opacity: 0;
left: -102%;
position: absolute
}
input[type="checkbox"].sc-checkbox+label{
padding: 0 5px 0 10px;
}
input[type="checkbox"].sc-checkbox+label:before {
content: '';
display: inline-block;
background: transparent;
border: .14286rem solid rgba(0, 0, 0, 0.54);
width: .92857rem;
height: .92857rem;
border-radius: .14286rem;
font-family: 'Material Icons';
position: relative;
vertical-align: middle;
left: 0;
line-height: .92857rem;
-webkit-transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1)
}
input[type="checkbox"].sc-checkbox:checked+label:before {
background: #3f51b5;
border: .14286rem solid #3f51b5;
content: '\E5CA';
color: #fff
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet">
<input type="checkbox" class="sc-checkbox" id="test"></label><label for="test">Test</label>
<input type="checkbox" class="sc-checkbox" id="test1" checked></label><label for="test1">Test1</label>
When you run the example everything works but on my website it doesn't work.
I have fiddled around with positions, paddings and margins on the :before but nothing seems to be working.
I hope someone can help me make the checkboxes work again.
Thanks in advance.
You have a code that fixes a bug when text field isn't selected when label is clicked:
textfields.js, line 30:
// Fix bug that text field isn't selected when label is clicked
$('label').click(function() {
var $id = $(this).attr('for');
$('#'+$id).trigger('click');
});
However this code cause your click on the label to be triggered twice, so you get two clicks on the checkbox (which causes your checkbox to be checked and then unchecked immediately, or the opposite).
I'm not sure if you really need this code or not, but you can change your fix-bug to something like this:
// Fix bug that text field isn't selected when label is clicked
$('label').click(function() {
var $id = $(this).attr('for');
if ($('#'+$id).is(':checkbox')) {
return;
}
$('#'+$id).trigger('click');
});

image slider multiple rows with just css or angularjs?

Is there a way to create an multiple row image slider like the one in the image below using just css? or is there a way to do this with angular?
The slider needs to move as one (single rows cannot be swiped individually).
First you need to understand the overflow property in css:
https://css-tricks.com/almanac/properties/o/overflow/
This will allow you to see there is a scroll property. That can make your scroll bars. Yours should use overflow-x to scroll the direction you want it to go.
As for angular, you need to look into ng-repeat command. Here is a fiddle that is doing what you are looking for:
<div ng-repeat="user in users | limitTo:display_limit">
http://jsfiddle.net/bmleite/hp4w7/
Quick answer to your question.. no, there is no way to do this with just CSS because you will have to handle the swipe, touch, click, etc. events using javascript. I guess I was working under the assumption that you would be adding angularjs into your application solely for this purpose, so I made a jQuery solution. If that is a wrong assumption, I will rewrite an angular solution.
Basically, the idea is that you structure your HTML/CSS in a way to get the effect of the sliding within a given container, and then use event handlers to update the slider as the user interacts with it.
Working DEMO
HTML
<div class="slider-display centered">
<div class="image-container">
<div class="image">Image<br>1</div>
<div class="image">Image<br>2</div>
<div class="image">Image<br>3</div>
<div class="image">Image<br>4</div>
<div class="image">Image<br>5</div>
<div class="image">Image<br>6</div>
<div class="image">Image<br>7</div>
<div class="image">Image<br>8</div>
<div class="image">Image<br>9</div>
<div class="image">Image<br>10</div>
<div class="image">Image<br>11</div>
<div class="image">Image<br>12</div>
<div class="image">Image<br>13</div>
<div class="image">Image<br>14</div>
<div class="image">Image<br>15</div>
<div class="image">Image<br>16</div>
<div class="image">Image<br>17</div>
<div class="image">Image<br>18</div>
</div>
</div>
<div class="centered" style="text-align: center; max-width: 350px;">
<button class="move-left"><--</button>
<button class="move-right">--></button>
</div>
Javascript
$(function () {
var getWidth = function ($element) {
var total = 0;
total += $element.width();
total += Number($element.css("padding-left").replace("px", ""));
total += Number($element.css("padding-right").replace("px", ""));
total += Number($element.css("border-left").split("px")[0]);
total += Number($element.css("border-right").split("px")[0]);
total += Number($element.css("margin-left").split("px")[0]);
total += Number($element.css("margin-right").split("px")[0]);
return total;
};
var sliderPosition = 0;
var imageWidth = getWidth($(".image").eq(0));
$(".move-left").on("click.slider", function () {
var maxVisibleItems = Math.ceil($(".slider-display").width() / imageWidth);
var maxItemsPerRow = Math.ceil($(".image-container").width() / imageWidth);
var numRows = Math.ceil($(".image-container .image").length / maxItemsPerRow);
var maxPosition = numRows > 1 ? maxVisibleItems - maxItemsPerRow : maxVisibleItems - $(".image-container .image").length;
if (sliderPosition > (maxPosition)) {
sliderPosition--;
var $imageContainer = $(".image-container");
$(".image-container").animate({
"margin-left": sliderPosition * imageWidth
},{
duration: 200,
easing: "linear",
queue: true,
start: function () {
$(".move-left").prop("disabled", true);
},
done: function () {
$(".move-left").prop("disabled", false);
}
});
}
});
$(".move-right").on("click.slider", function () {
if (sliderPosition < 0) {
sliderPosition++;
var $imageContainer = $(".image-container");
$(".image-container").animate({
"margin-left": sliderPosition * imageWidth
},{
duration: 200,
easing: "linear",
queue: true,
start: function () {
$(".move-right").prop("disabled", true);
},
done: function () {
$(".move-right").prop("disabled", false);
}
});
}
});
});
CSS
.image {
float: left;
height: 80px;
width: 80px;
background: #888888;
text-align: center;
padding: 5px;
margin: 5px;
font-size: 1.5rem;
}
.image-container {
width: 650px;
position: relative;
}
.slider-display {
max-width: 450px;
overflow: hidden;
background: #ddd
}
.centered {
margin: 0 auto;
}

Changing text color depending on background

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.

Resources