Skip to content

Instantly share code, notes, and snippets.

@CodeMyUI
Created April 6, 2019 05:53
Show Gist options
  • Save CodeMyUI/4f6a278a6b028f659b1a929974b44c60 to your computer and use it in GitHub Desktop.
Save CodeMyUI/4f6a278a6b028f659b1a929974b44c60 to your computer and use it in GitHub Desktop.
Invisible Ink | Mouse Over! iOS 10
<div class="flex">
<div class="content">
<h2>Invisible Ink</h2>
<div class="text">
<p class="project_text" style="margin-top: 0px; opacity: 1;">Invisible Ink was a simple <em>library</em> that will take specified text and "ink" it out, making it unreadable until hovered upon. It has quite a few applicable uses, like for hiding <span class="ink">spoilers</span> and <span class="ink">security words</span>. It was inspired by one of iOS 10's new features for iMessages.</p>
</div>
</div>
</div>

Invisible Ink | Mouse Over! iOS 10

UPDATED: 07/07/16 - I made it so each word that makes up an inked out message is a separate canvas. This makes the content flow like real words do - text wrapping, etc.

A Pen by Darryl Huffman on CodePen.

License.

/*
Feel free to use this in your projects! It'd be cool if you'd tell me though, to see what you do with it!
The font, color, size, and everything will be carried over accurately.
This is an attempt to re-create the invisible ink texts for iOS, and it turns out that it might work on websites in general... Swipe to see current password? Security Question answers? Who knows.
Usage is simple, the JS file handles CSS and all JS.
Here's the markup:
<span class="ink">ANYTHING</span>
So far there is no support for line breaks.
*/
(function(){
function wrapWords(el) {
'use strict';
$(el).filter(':not(script)').contents().each(function () {
if (this.nodeType === Node.ELEMENT_NODE) {
wrapWords(this);
} else if (this.nodeType === Node.TEXT_NODE && !this.nodeValue.match(/^\s+$/m)) {
$(this).replaceWith($.map(this.nodeValue.split(/(\S+)/), function (w) {
return w.match(/^\s*$/) ? document.createTextNode(w) : $('<span>', {class: 'word', text: w}).get();
}));
}
});
};
$('.ink').each(function(){
$(this).html(wrapWords(this));
$(this).find('.word').each(function(){
inkout($(this));
$(this).addClass('initialized');
});
});
$('body').on('DOMNodeInserted', function(e) {
if ($(e.target).is('.ink') && $(e.target).hasClass('initialized') == false) {
setTimeout(function(){
$(e.target).html(wrapWords(e.target));
$(e.target).find('.word').each(function(){
if(!$(this).hasClass('initialized')){
inkout($(this));
$(this).addClass('initialized');
}
});
$(e.target).addClass('initialized');
}, 100);
}
});
function css( element, property ) {
return window.getComputedStyle( element, null ).getPropertyValue( property );
}
function inkout(element){
element.parent().css('position','relative');
var startTime = new Date().getTime();
var currentTime = startTime / 1000;
var font = element.css('font-size') +' '+ element.css('font-family');
var color = element.css('color');
var text = element.html();
var particles = [];
var hoverArray = [];
var cw = element.width(),
ch = element.height();
element.html('');
var canvas = $('<canvas/>').attr({width: cw, height: ch}).css({display: 'inline-block','vertical-align': 'text-bottom'}).appendTo(element),
context = canvas.get(0).getContext("2d");
function drawText(){
context.clearRect(0,0,cw,ch);
context.fillStyle = color;
context.clearRect(0,0,cw,ch);
context.font = font;
context.textAlign = "center";
context.fillText(text,cw/2, ch - (ch/5));
}
$(window).resize(function(){
element.html(text);
font = element.css('font-size') +' '+ element.css('font-family');
particles = [];
cw = element.width(),
ch = element.height();
element.html('');
canvas = $('<canvas/>').attr({width: cw, height: ch}).css({display: 'inline-block','vertical-align': 'top'}).appendTo(element),
context = canvas.get(0).getContext("2d");
drawText();
scramble();
});
drawText();
function hover(x,y){
var id = hoverArray.length;
hoverArray.push([x,y]);
setTimeout(function(){
hoverArray[id] = undefined;
},1300);
}
$(document).click(function(){
hoverArray = [];
});
element.parent().on('mousemove touchmove',function(e){
e.preventDefault();
var x = e.pageX - element.offset().left;
var y = e.pageY - element.offset().top;
hover(x,y);
});
var particle = function(x,y,visible,color){
this.color = 'rgba('+color[0]+','+color[1]+','+color[2]+','+color[3] / 255+')';
this.visible = visible;
this.realx = x;
this.realy = y;
this.toplace = false;
this.rate = Math.round(Math.random() * 12) - 8;
this.spin = Math.round(Math.random() * 2);
this.x = x;
this.y = y;
particles.push(this);
}
particle.prototype.draw = function(){
var l = false;
for(var i = 0; i < hoverArray.length; i++){
if(hoverArray[i]){
if(this.realx >= hoverArray[i][0] - 25 && this.realx <= hoverArray[i][0] + 25 && hoverArray[i]){
if(this.realy >= hoverArray[i][1] - 25 && this.realy <= hoverArray[i][1] + 25 && hoverArray[i]){
this.toplace = true;
l = true;
}
}
}
}
if(l == false){
this.toplace = false;
}
if(this.toplace == false){
if(this.spin == 1){
this.x = this.realx + Math.floor(Math.sin(currentTime) * this.rate);
} else if(this.spin == 0){
this.y = this.realy + Math.floor(Math.cos(-currentTime) * this.rate);
} else {
this.x = this.realx + Math.floor(Math.sin(-currentTime) * this.rate);
this.y = this.realy + Math.floor(Math.cos(currentTime) * this.rate);
}
} else {
if(this.x < this.realx){
this.x++;
} else if(this.x > this.realx){
this.x--;
}
if(this.y < this.realy){
this.y++;
} else if(this.y > this.realy){
this.y--;
}
}
if(this.visible == true || this.toplace == true){
context.fillStyle = this.color;
context.fillRect(this.x, this.y, 1,1);
}
}
function scramble(){
for(var y = 1; y < ch; y+=1){
for(var x = 0; x < cw; x++){
if(context.getImageData(x, y, 1, 1).data[3] >= 1){
if(Math.round(Math.random() * 3) >= 2){
new particle(x,y,false,context.getImageData(x, y, 1, 1).data);
} else {
new particle(x,y,true,context.getImageData(x, y, 1, 1).data);
}
}
}
}
}
scramble();
var requestframe = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame ||
// IE Fallback, you can even fallback to onscroll
function (callback) {
window.setTimeout(callback, 1000 / 60);
};
function loop(){
var now = new Date().getTime();
currentTime = (now - startTime) / 1000;
context.clearRect(0,0,cw,ch);
for(var i = 0; i < particles.length; i++){
particles[i].draw();
}
requestframe(loop);
}
loop();
}
})();
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
html, body {
background: rgb(34, 34, 34);
height: 100%;
.flex {
width: 100%;
color: rgb(255, 255, 255);
height: 100%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
height: 100%;
}
.content {
width: 500px;
margin: auto auto;
h2 {
padding-top: 0%;
padding-left: 19px;
margin-bottom: 30px;
font-weight: bold;
font-family: didot;
font-size: 75px;
letter-spacing: .2px;
line-height: 75px;
max-width: 550px;
width: 100%;
}
.text {
padding: 0px 0 0 22px;
p {
font-family: didot;
font-size: 16px;
line-height: 32px;
max-width: 463px;
width: 100%;
letter-spacing: 1.1px;
padding: 0px !important;
margin-bottom: 20px;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment