a placeholder-image for angular.js
creates images with long-shadows
A Pen by Gregor Adams on CodePen.
a placeholder-image for angular.js
creates images with long-shadows
A Pen by Gregor Adams on CodePen.
doctype html | |
div(ng-app="app") | |
img(shadow-img | |
size="200x150" | |
fill-color="random") | |
shadow-img(size="200x150" | |
alt="color" | |
fill-color="random") | |
shadow-img(size="200x150" | |
alt="alt attribute" | |
fill-color="random") | |
shadow-img(size="200x150" | |
alt="alt attribute" | |
title="title attribute" | |
fill-color="random") | |
shadow-img(size="200x150" | |
alt="alt attribute" | |
title="title attribute" | |
text="custom text" | |
fill-color="#feac58") | |
br | |
br | |
shadow-img | |
shadow-img(shape="circle") | |
shadow-img(alt="color" | |
shape="circle") | |
shadow-img(alt="color" | |
fill-color="random" | |
shape="circle") | |
shadow-img(size="150" | |
alt="color" | |
fill-color="random" | |
shape="circle") | |
shadow-img(size="150" | |
alt="color" | |
fill-color="random" | |
shape="circle" | |
text-size="50") | |
br | |
br | |
shadow-img(size="400x100" | |
alt="The Simpsons" | |
fill-color="#ffd90f") | |
br | |
br | |
shadow-img(size="300" | |
alt="Homer" | |
fill-color="#70d1ff" | |
shape="circle" | |
initials="true" | |
text-size="200") | |
shadow-img(size="100x300" | |
alt="Marge" | |
fill-color="#d1ff87" | |
initials="true" | |
text-size="50") | |
shadow-img(size="100x150" | |
alt="Bart" | |
fill-color="#ff850c" | |
initials="true" | |
text-size="50") | |
shadow-img(size="100x150" | |
alt="Lisa" | |
fill-color="#ff360f" | |
initials="true" | |
text-size="50") | |
shadow-img(size="100" | |
alt="Maggie" | |
fill-color="#7dffff" | |
initials="true" | |
text-size="50") | |
angular.module('app', []) | |
.directive('shadowImg', function() { | |
return { | |
restrict: 'AE', | |
scope: { | |
dimensions: '@size', | |
shape: '@', | |
alt: '@', | |
title: '@', | |
text: '@', | |
initials: '@', | |
textSize: '@', | |
textColor: '@', | |
fillColor: '@', | |
}, | |
template: '<img draggable="false">', | |
replace: true, | |
link: function(scope, element) { | |
var canvas; | |
function getRandomColor() { | |
var letters = '456789ABCD'.split(''); | |
var color = '#'; | |
for (var i = 0; i < 6; i++ ) { | |
color += letters[Math.floor(Math.random() * 10)]; | |
} | |
return color; | |
} | |
function shadeColor(color, percent) { | |
color = color.slice(1); | |
if (color.split('').length === 3) { | |
var newColor = []; | |
newColor[0] = newColor[1] = color[0]; | |
newColor[2] = newColor[3] = color[1]; | |
newColor[4] = newColor[5] = color[2]; | |
color = newColor.join('');; | |
} | |
var f = parseInt(color, 16), | |
t = percent < 0 ? 0 : 255, | |
p = percent < 0 ? percent * -1 : percent, | |
R = f >> 16, | |
G = f >> 8 & 0x00FF, | |
B = f & 0x0000FF; | |
return "#" + (0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B)).toString(16).slice(1); | |
} | |
var config = { | |
dimensions: scope.dimensions || '100', | |
text: scope.text || scope.title || scope.alt || 'placeholder', | |
textSize: scope.textSize || 20, | |
fontWeight: 'bold', | |
fontFamily: 'sans-serif', | |
shape: scope.shape || 'rectangle', | |
textColor: scope.textColor || '#ffffff', | |
initials: scope.initials || false, | |
fillColor: scope.fillColor === 'random' ? getRandomColor() : scope.fillColor || '#afafaf' | |
}; | |
var matches = [0, 100, 100]; | |
if (config.dimensions.match(/^(\d+)\s?x\s?(\d+)$/)) { | |
matches = config.dimensions.match(/^(\d+)\s?x\s?(\d+)$/).slice(1); | |
} else if (config.dimensions.match(/^(\d+).*?$/)) { | |
matches = config.dimensions.match(/^(\d+).*?$/).slice(1); | |
matches = [matches[0], matches[0]] | |
} | |
scope.size = { | |
width: matches[0], | |
height: matches[1] | |
}; | |
config.text = config.text === "placeholder" ? scope.size.width + ' x ' + scope.size.height : config.text; | |
config.text = config.text === "color" ? config.fillColor.toUpperCase() : config.text; | |
config.minSize = Math.max(scope.size.height, scope.size.width); | |
config.maxSize = Math.min(scope.size.height, scope.size.width); | |
config.textSize = Math.min(config.maxSize * 0.625, config.textSize); | |
config.strokeColor = shadeColor(config.fillColor, -0.1); | |
function getTextSize() { | |
var dimensionArr = [scope.size.height, scope.size.width].sort(); | |
var maxFactor = Math.round(dimensionArr[1] / 8); | |
return Math.max(config.textSize, maxFactor); | |
} | |
function buildFontString(textSize) { | |
var str = config.fontWeight; | |
str += ' '; | |
str += textSize; | |
str += 'px '; | |
str += config.fontFamily; | |
return str; | |
} | |
function drawImage() { | |
canvas = canvas || document.createElement('canvas'); | |
var context = canvas.getContext('2d'); | |
canvas.width = scope.size.width; | |
canvas.height = scope.size.height; | |
context.fillStyle = config.fillColor; | |
if (config.shape === 'circle' && scope.size.height === scope.size.width) { | |
var size = scope.size.height/ 2; | |
context.beginPath(); | |
context.arc(size, size, size, 0,2*Math.PI); | |
context.fill(); | |
context.clip(); | |
} | |
context.fillRect(0, 0, scope.size.width, scope.size.height); | |
var textSize = getTextSize(); | |
var text = config.text; | |
text = config.initials ? text.split('')[0].toUpperCase() : text; | |
context.fillStyle = config.strokeColor; | |
context.textAlign = 'center'; | |
context.textBaseline = 'middle'; | |
context.font = buildFontString(textSize); | |
if (context.measureText(text).width / scope.size.width > 1) { | |
textSize = config.textSize / (context.measureText(text).width / scope.size.width + 0.3); | |
context.font = buildFontString(textSize); | |
} | |
for (var i = 0; i < config.minSize; i++) { | |
context.fillText(text, scope.size.width / 2 + i, scope.size.height / 2 + i); | |
} | |
context.fillStyle = config.textColor; | |
context.fillText(text, scope.size.width / 2, scope.size.height / 2); | |
return canvas.toDataURL('image/png'); | |
} | |
var dataUrl = drawImage(); | |
element.prop('src', dataUrl); | |
} | |
}; | |
}); |