How do I rotate my pattern of hexagons so that the hexagon point is at the top and the pattern is consistent across the page
var SVG_NS = 'http://www.w3.org/2000/svg';
var SVG_XLINK = "http://www.w3.org/1999/xlink"
let H = 800, W=500
var R = 9;
//var l = R;
var h = R * Math.sin(Math.PI / 3);
var offset = 1.5 * R;
let i = 0;
for(let y = 0; y<H; y+=h){
i++
let o = (i%2 == 0) ? offset : 0;
for(let x = o; x<W; x+=3*R){
hex(x,y)
}
}
function hex(x,y) {
let angle = map(x, 0, W, 0, 5*Math.PI);
let c = Math.sin(angle);
let r = R * .99;
//let r = R * Math.sin(angle)
let points = ""
for (var a = 0; a < 6; a++) {
let o = {}
o.x = x + r * Math.cos(a * Math.PI / 3);
o.y = y + r * Math.sin(a * Math.PI / 3);
points+= `${o.x}, ${o.y} `
}
let hexagon = drawSVGelmt({points:points},"polygon", svg)
}
function drawSVGelmt(o,tag, parent) {
let elmt = document.createElementNS(SVG_NS, tag);
for (let name in o) {
if (o.hasOwnProperty(name)) {
elmt.setAttributeNS(null, name, o[name]);
}
}
parent.appendChild(elmt);
return elmt;
}
function map(n, a, b, _a, _b) {
let d = b - a;
let _d = _b - _a;
let u = _d / d;
return _a + n * u;
}
html, body {
height: 100%;
margin: 0;
background: #e20341;
}
svg {
}
polygon {
fill: white;
stroke: black;
stroke-width: 1px;
}
<svg viewBox="0 0 500 280" width="100%">
<defs>
<pattern id="hexagons" width="100%" height="100%" >
<g id="svg" fill="black" x="0" y="0"></g>
</pattern>
<mask id="hexagon-halftone-mask">
<rect x="0" y="0" width="100%" height="100%" fill="url(#hexagons)" />
</mask>
</defs>
<image width="100%" xlink:href="https://cdn.pixabay.com/photo/2016/09/07/11/37/tropical-1651426_960_720.jpg" mask="url(#hexagon-halftone-mask)"/>
</svg>
Here is the new code with comments:
var SVG_NS = 'http://www.w3.org/2000/svg';
var SVG_XLINK = "http://www.w3.org/1999/xlink"
let H = 800, W=500
var R = 9;
/* switch offset and h*/
var offset = R * Math.sin(Math.PI / 3);
var h = 1.5 * R;
let i = 0;
for(let y = 0; y<H; y+=h){
i++
let o = (i%2 == 0) ? offset : 0;
for(let x = o; x<W; x+=offset*2){ /*offset*2 instead of 3*R*/
hex(x,y)
}
}
function hex(x,y) {
let angle = map(x, 0, W, 0, 5*Math.PI);
let c = Math.sin(angle);
let r = R * .99;
let points = ""
for (var a = 0; a < 6; a++) {
let o = {}
o.x = x + r * Math.sin(a * Math.PI / 3); /* sin instead of cos */
o.y = y + r * Math.cos(a * Math.PI / 3); /* cos instead of sin */
points+= `${o.x}, ${o.y} `
}
let hexagon = drawSVGelmt({points:points},"polygon", svg)
}
function drawSVGelmt(o,tag, parent) {
let elmt = document.createElementNS(SVG_NS, tag);
for (let name in o) {
if (o.hasOwnProperty(name)) {
elmt.setAttributeNS(null, name, o[name]);
}
}
parent.appendChild(elmt);
return elmt;
}
function map(n, a, b, _a, _b) {
let d = b - a;
let _d = _b - _a;
let u = _d / d;
return _a + n * u;
}
html, body {
height: 100%;
margin: 0;
background: #e20341;
}
svg {
}
polygon {
fill: white;
stroke: black;
stroke-width: 1px;
}
<svg viewBox="0 0 500 280" width="100%">
<defs>
<pattern id="hexagons" width="100%" height="100%" >
<g id="svg" fill="black" x="0" y="0"></g>
</pattern>
<mask id="hexagon-halftone-mask">
<rect x="0" y="0" width="100%" height="100%" fill="url(#hexagons)" />
</mask>
</defs>
<image width="100%" xlink:href="https://cdn.pixabay.com/photo/2016/09/07/11/37/tropical-1651426_960_720.jpg" mask="url(#hexagon-halftone-mask)"/>
</svg>
Related
I am having some difficulty styling the HTML 5 Date input in Chrome.
Using mark up such as
<input type="date" max="2020-06-03" value="2020-06-01">, with some background and font color styling in CSS, renders in Chrome as:
I would like to make the calendar icon on the right hand side white, so it matches the color of the text.
::-webkit-calendar-picker-indicator looked like a possible candidate. Setting the background color on this changes the color behind the icon (as expected). However I can't find any parameter that has an effect on the icon color itself.
I've managed to work around it for now using a CSS filter to invert the black color to white
::-webkit-calendar-picker-indicator {
filter: invert(1);
}
However this feels quite fragile and far from ideal.
Another way, is by setting the "color-scheme" to dark.
input {
color-scheme: dark;
}
<input type="date" />
FYI: this will also put the popup in dark mode.
The Shadow DOM style sets a background-image which can not be interacted with in CSS (except for filter). One option is to replace the whole image where you can set any fill color and this method will be forward-compatible in case Chrome decides to inherit the icon color from color later on, at the cost of having a "hardcoded" icon:
::-webkit-calendar-picker-indicator {
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="15" viewBox="0 0 24 24"><path fill="%23bbbbbb" d="M20 3h-1V1h-2v2H7V1H5v2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 18H4V8h16v13z"/></svg>');
}
You can actually get rather creative using the filter property.
invert(100%) turns the icon white
brightness(50%) makes it gray
sepia(100%) saturates it and makes it... sepia
saturate(10000%) pumps the saturation up and turns it bright red
After that you can play around with hue-rotate to change the hue. hue-rotate(240deg) turns it blue, hue-rotate(120deg) turns it green etc. If you want to get a really specific color you should check out this question on how to transform black into any given color using only CSS filters.
Another example is;
input[type="date"]::-webkit-calendar-picker-indicator {
cursor: pointer;
border-radius: 4px;
margin-right: 2px;
opacity: 0.6;
filter: invert(0.8);
}
input[type="date"]::-webkit-calendar-picker-indicator:hover {
opacity: 1
}
I just found out about this awesome fiddle. You input the color you need in hex, and it gives you your filter code. Very pratical: https://codepen.io/sosuke/pen/Pjoqqp.
The javascript to calculate it is:
'use strict';
class Color {
constructor(r, g, b) {
this.set(r, g, b);
}
toString() {
return `rgb(${Math.round(this.r)}, ${Math.round(this.g)}, ${Math.round(this.b)})`;
}
set(r, g, b) {
this.r = this.clamp(r);
this.g = this.clamp(g);
this.b = this.clamp(b);
}
hueRotate(angle = 0) {
angle = angle / 180 * Math.PI;
const sin = Math.sin(angle);
const cos = Math.cos(angle);
this.multiply([
0.213 + cos * 0.787 - sin * 0.213,
0.715 - cos * 0.715 - sin * 0.715,
0.072 - cos * 0.072 + sin * 0.928,
0.213 - cos * 0.213 + sin * 0.143,
0.715 + cos * 0.285 + sin * 0.140,
0.072 - cos * 0.072 - sin * 0.283,
0.213 - cos * 0.213 - sin * 0.787,
0.715 - cos * 0.715 + sin * 0.715,
0.072 + cos * 0.928 + sin * 0.072,
]);
}
grayscale(value = 1) {
this.multiply([
0.2126 + 0.7874 * (1 - value),
0.7152 - 0.7152 * (1 - value),
0.0722 - 0.0722 * (1 - value),
0.2126 - 0.2126 * (1 - value),
0.7152 + 0.2848 * (1 - value),
0.0722 - 0.0722 * (1 - value),
0.2126 - 0.2126 * (1 - value),
0.7152 - 0.7152 * (1 - value),
0.0722 + 0.9278 * (1 - value),
]);
}
sepia(value = 1) {
this.multiply([
0.393 + 0.607 * (1 - value),
0.769 - 0.769 * (1 - value),
0.189 - 0.189 * (1 - value),
0.349 - 0.349 * (1 - value),
0.686 + 0.314 * (1 - value),
0.168 - 0.168 * (1 - value),
0.272 - 0.272 * (1 - value),
0.534 - 0.534 * (1 - value),
0.131 + 0.869 * (1 - value),
]);
}
saturate(value = 1) {
this.multiply([
0.213 + 0.787 * value,
0.715 - 0.715 * value,
0.072 - 0.072 * value,
0.213 - 0.213 * value,
0.715 + 0.285 * value,
0.072 - 0.072 * value,
0.213 - 0.213 * value,
0.715 - 0.715 * value,
0.072 + 0.928 * value,
]);
}
multiply(matrix) {
const newR = this.clamp(this.r * matrix[0] + this.g * matrix[1] + this.b * matrix[2]);
const newG = this.clamp(this.r * matrix[3] + this.g * matrix[4] + this.b * matrix[5]);
const newB = this.clamp(this.r * matrix[6] + this.g * matrix[7] + this.b * matrix[8]);
this.r = newR;
this.g = newG;
this.b = newB;
}
brightness(value = 1) {
this.linear(value);
}
contrast(value = 1) {
this.linear(value, -(0.5 * value) + 0.5);
}
linear(slope = 1, intercept = 0) {
this.r = this.clamp(this.r * slope + intercept * 255);
this.g = this.clamp(this.g * slope + intercept * 255);
this.b = this.clamp(this.b * slope + intercept * 255);
}
invert(value = 1) {
this.r = this.clamp((value + this.r / 255 * (1 - 2 * value)) * 255);
this.g = this.clamp((value + this.g / 255 * (1 - 2 * value)) * 255);
this.b = this.clamp((value + this.b / 255 * (1 - 2 * value)) * 255);
}
hsl() {
// Code taken from https://stackoverflow.com/a/9493060/2688027, licensed under CC BY-SA.
const r = this.r / 255;
const g = this.g / 255;
const b = this.b / 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0;
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return {
h: h * 100,
s: s * 100,
l: l * 100,
};
}
clamp(value) {
if (value > 255) {
value = 255;
} else if (value < 0) {
value = 0;
}
return value;
}
}
class Solver {
constructor(target, baseColor) {
this.target = target;
this.targetHSL = target.hsl();
this.reusedColor = new Color(0, 0, 0);
}
solve() {
const result = this.solveNarrow(this.solveWide());
return {
values: result.values,
loss: result.loss,
filter: this.css(result.values),
};
}
solveWide() {
const A = 5;
const c = 15;
const a = [60, 180, 18000, 600, 1.2, 1.2];
let best = { loss: Infinity };
for (let i = 0; best.loss > 25 && i < 3; i++) {
const initial = [50, 20, 3750, 50, 100, 100];
const result = this.spsa(A, a, c, initial, 1000);
if (result.loss < best.loss) {
best = result;
}
}
return best;
}
solveNarrow(wide) {
const A = wide.loss;
const c = 2;
const A1 = A + 1;
const a = [0.25 * A1, 0.25 * A1, A1, 0.25 * A1, 0.2 * A1, 0.2 * A1];
return this.spsa(A, a, c, wide.values, 500);
}
spsa(A, a, c, values, iters) {
const alpha = 1;
const gamma = 0.16666666666666666;
let best = null;
let bestLoss = Infinity;
const deltas = new Array(6);
const highArgs = new Array(6);
const lowArgs = new Array(6);
for (let k = 0; k < iters; k++) {
const ck = c / Math.pow(k + 1, gamma);
for (let i = 0; i < 6; i++) {
deltas[i] = Math.random() > 0.5 ? 1 : -1;
highArgs[i] = values[i] + ck * deltas[i];
lowArgs[i] = values[i] - ck * deltas[i];
}
const lossDiff = this.loss(highArgs) - this.loss(lowArgs);
for (let i = 0; i < 6; i++) {
const g = lossDiff / (2 * ck) * deltas[i];
const ak = a[i] / Math.pow(A + k + 1, alpha);
values[i] = fix(values[i] - ak * g, i);
}
const loss = this.loss(values);
if (loss < bestLoss) {
best = values.slice(0);
bestLoss = loss;
}
}
return { values: best, loss: bestLoss };
function fix(value, idx) {
let max = 100;
if (idx === 2 /* saturate */) {
max = 7500;
} else if (idx === 4 /* brightness */ || idx === 5 /* contrast */) {
max = 200;
}
if (idx === 3 /* hue-rotate */) {
if (value > max) {
value %= max;
} else if (value < 0) {
value = max + value % max;
}
} else if (value < 0) {
value = 0;
} else if (value > max) {
value = max;
}
return value;
}
}
loss(filters) {
// Argument is array of percentages.
const color = this.reusedColor;
color.set(0, 0, 0);
color.invert(filters[0] / 100);
color.sepia(filters[1] / 100);
color.saturate(filters[2] / 100);
color.hueRotate(filters[3] * 3.6);
color.brightness(filters[4] / 100);
color.contrast(filters[5] / 100);
const colorHSL = color.hsl();
return (
Math.abs(color.r - this.target.r) +
Math.abs(color.g - this.target.g) +
Math.abs(color.b - this.target.b) +
Math.abs(colorHSL.h - this.targetHSL.h) +
Math.abs(colorHSL.s - this.targetHSL.s) +
Math.abs(colorHSL.l - this.targetHSL.l)
);
}
css(filters) {
function fmt(idx, multiplier = 1) {
return Math.round(filters[idx] * multiplier);
}
return `filter: invert(${fmt(0)}%) sepia(${fmt(1)}%) saturate(${fmt(2)}%) hue-rotate(${fmt(3, 3.6)}deg) brightness(${fmt(4)}%) contrast(${fmt(5)}%);`;
}
}
function hexToRgb(hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, (m, r, g, b) => {
return r + r + g + g + b + b;
});
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result
? [
parseInt(result[1], 16),
parseInt(result[2], 16),
parseInt(result[3], 16),
]
: null;
}
$(document).ready(() => {
$('button.execute').click(() => {
const rgb = hexToRgb($('input.target').val());
if (rgb.length !== 3) {
alert('Invalid format!');
return;
}
const color = new Color(rgb[0], rgb[1], rgb[2]);
const solver = new Solver(color);
const result = solver.solve();
let lossMsg;
if (result.loss < 1) {
lossMsg = 'This is a perfect result.';
} else if (result.loss < 5) {
lossMsg = 'The is close enough.';
} else if (result.loss < 15) {
lossMsg = 'The color is somewhat off. Consider running it again.';
} else {
lossMsg = 'The color is extremely off. Run it again!';
}
$('.realPixel').css('background-color', color.toString());
$('.filterPixel').attr('style', result.filter);
$('.filterDetail').text(result.filter);
$('.lossDetail').html(`Loss: ${result.loss.toFixed(1)}. <b>${lossMsg}</b>`);
});
});
input[type="date"]::-webkit-calendar-picker-indicator {
filter: invert(1);
margin: 0px;
margin-right: 20px !important; }
For posterity, check out this Codepen that transforms black into any color through the filter property
I copied a puzzle code. Now i need to add more puzzles in the same page how i can do that with this javascript. Please anyone guide me to how to handle this code for making multiple puzzles, I have basic skill in javascript, I am trying to add another variable for new puzzle it's not working...
const PUZZLE_DIFFICULTY = 2;
const PUZZLE_HOVER_TINT = '#009900';
var _stage;
var _canvas;
var _img;
var _pieces;
var _puzzleWidth;
var _puzzleHeight;
var _pieceWidth;
var _pieceHeight;
var _currentPiece;
var _currentDropPiece;
var _mouse;
function init() {
_img = new Image();
_img.addEventListener('load', onImage, false);
_img.src = "http://lorempixel.com/output/animals-q-g-640-480-3.jpg";
}
function onImage(e) {
_pieceWidth = Math.floor(_img.width / PUZZLE_DIFFICULTY)
_pieceHeight = Math.floor(_img.height / PUZZLE_DIFFICULTY)
_puzzleWidth = _pieceWidth * PUZZLE_DIFFICULTY;
_puzzleHeight = _pieceHeight * PUZZLE_DIFFICULTY;
setCanvas();
initPuzzle();
}
function setCanvas() {
_canvas = document.getElementById('puzzle');
_stage = _canvas.getContext('2d');
_canvas.width = _puzzleWidth;
_canvas.height = _puzzleHeight;
_canvas.style.border = "1px solid black";
}
function initPuzzle() {
_pieces = [];
_mouse = {
x: 0,
y: 0
};
_currentPiece = null;
_currentDropPiece = null;
_stage.drawImage(_img, 0, 0, _puzzleWidth, _puzzleHeight, 0, 0, _puzzleWidth, _puzzleHeight);
createTitle("Click to Start Puzzle");
buildPieces();
}
function createTitle(msg) {
_stage.fillStyle = "#000000";
_stage.globalAlpha = .4;
_stage.fillRect(100, _puzzleHeight - 40, _puzzleWidth - 200, 40);
_stage.fillStyle = "#FFFFFF";
_stage.globalAlpha = 1;
_stage.textAlign = "center";
_stage.textBaseline = "middle";
_stage.font = "20px Arial";
_stage.fillText(msg, _puzzleWidth / 2, _puzzleHeight - 20);
}
function buildPieces() {
var i;
var piece;
var xPos = 0;
var yPos = 0;
for (i = 0; i < PUZZLE_DIFFICULTY * PUZZLE_DIFFICULTY; i++) {
piece = {};
piece.sx = xPos;
piece.sy = yPos;
_pieces.push(piece);
xPos += _pieceWidth;
if (xPos >= _puzzleWidth) {
xPos = 0;
yPos += _pieceHeight;
}
}
document.onmousedown = shufflePuzzle;
}
function shufflePuzzle() {
_pieces = shuffleArray(_pieces);
_stage.clearRect(0, 0, _puzzleWidth, _puzzleHeight);
var i;
var piece;
var xPos = 0;
var yPos = 0;
for (i = 0; i < _pieces.length; i++) {
piece = _pieces[i];
piece.xPos = xPos;
piece.yPos = yPos;
_stage.drawImage(_img, piece.sx, piece.sy, _pieceWidth, _pieceHeight, xPos, yPos, _pieceWidth, _pieceHeight);
_stage.strokeRect(xPos, yPos, _pieceWidth, _pieceHeight);
xPos += _pieceWidth;
if (xPos >= _puzzleWidth) {
xPos = 0;
yPos += _pieceHeight;
}
}
document.onmousedown = onPuzzleClick;
}
function onPuzzleClick(e) {
if (e.layerX || e.layerX == 0) {
_mouse.x = e.layerX - _canvas.offsetLeft;
_mouse.y = e.layerY - _canvas.offsetTop;
} else if (e.offsetX || e.offsetX == 0) {
_mouse.x = e.offsetX - _canvas.offsetLeft;
_mouse.y = e.offsetY - _canvas.offsetTop;
}
_currentPiece = checkPieceClicked();
if (_currentPiece != null) {
_stage.clearRect(_currentPiece.xPos, _currentPiece.yPos, _pieceWidth, _pieceHeight);
_stage.save();
_stage.globalAlpha = .9;
_stage.drawImage(_img, _currentPiece.sx, _currentPiece.sy, _pieceWidth, _pieceHeight, _mouse.x - (_pieceWidth / 2), _mouse.y - (_pieceHeight / 2), _pieceWidth, _pieceHeight);
_stage.restore();
document.onmousemove = updatePuzzle;
document.onmouseup = pieceDropped;
}
}
function checkPieceClicked() {
var i;
var piece;
for (i = 0; i < _pieces.length; i++) {
piece = _pieces[i];
if (_mouse.x < piece.xPos || _mouse.x > (piece.xPos + _pieceWidth) || _mouse.y < piece.yPos || _mouse.y > (piece.yPos + _pieceHeight)) {
//PIECE NOT HIT
} else {
return piece;
}
}
return null;
}
function updatePuzzle(e) {
_currentDropPiece = null;
if (e.layerX || e.layerX == 0) {
_mouse.x = e.layerX - _canvas.offsetLeft;
_mouse.y = e.layerY - _canvas.offsetTop;
} else if (e.offsetX || e.offsetX == 0) {
_mouse.x = e.offsetX - _canvas.offsetLeft;
_mouse.y = e.offsetY - _canvas.offsetTop;
}
_stage.clearRect(0, 0, _puzzleWidth, _puzzleHeight);
var i;
var piece;
for (i = 0; i < _pieces.length; i++) {
piece = _pieces[i];
if (piece == _currentPiece) {
continue;
}
_stage.drawImage(_img, piece.sx, piece.sy, _pieceWidth, _pieceHeight, piece.xPos, piece.yPos, _pieceWidth, _pieceHeight);
_stage.strokeRect(piece.xPos, piece.yPos, _pieceWidth, _pieceHeight);
if (_currentDropPiece == null) {
if (_mouse.x < piece.xPos || _mouse.x > (piece.xPos + _pieceWidth) || _mouse.y < piece.yPos || _mouse.y > (piece.yPos + _pieceHeight)) {
//NOT OVER
} else {
_currentDropPiece = piece;
_stage.save();
_stage.globalAlpha = .4;
_stage.fillStyle = PUZZLE_HOVER_TINT;
_stage.fillRect(_currentDropPiece.xPos, _currentDropPiece.yPos, _pieceWidth, _pieceHeight);
_stage.restore();
}
}
}
_stage.save();
_stage.globalAlpha = .6;
_stage.drawImage(_img, _currentPiece.sx, _currentPiece.sy, _pieceWidth, _pieceHeight, _mouse.x - (_pieceWidth / 2), _mouse.y - (_pieceHeight / 2), _pieceWidth, _pieceHeight);
_stage.restore();
_stage.strokeRect(_mouse.x - (_pieceWidth / 2), _mouse.y - (_pieceHeight / 2), _pieceWidth, _pieceHeight);
}
function pieceDropped(e) {
document.onmousemove = null;
document.onmouseup = null;
if (_currentDropPiece != null) {
var tmp = {
xPos: _currentPiece.xPos,
yPos: _currentPiece.yPos
};
_currentPiece.xPos = _currentDropPiece.xPos;
_currentPiece.yPos = _currentDropPiece.yPos;
_currentDropPiece.xPos = tmp.xPos;
_currentDropPiece.yPos = tmp.yPos;
}
resetPuzzleAndCheckWin();
}
function resetPuzzleAndCheckWin() {
_stage.clearRect(0, 0, _puzzleWidth, _puzzleHeight);
var gameWin = true;
var i;
var piece;
for (i = 0; i < _pieces.length; i++) {
piece = _pieces[i];
_stage.drawImage(_img, piece.sx, piece.sy, _pieceWidth, _pieceHeight, piece.xPos, piece.yPos, _pieceWidth, _pieceHeight);
_stage.strokeRect(piece.xPos, piece.yPos, _pieceWidth, _pieceHeight);
if (piece.xPos != piece.sx || piece.yPos != piece.sy) {
gameWin = false;
}
}
if (gameWin) {
setTimeout(gameOver, 500);
}
}
function gameOver() {
document.onmousedown = null;
document.onmousemove = null;
document.onmouseup = null;
initPuzzle();
alert("you Won")
}
function shuffleArray(o) {
for (var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
}
<body onload="init();">
<canvas id="puzzle"></canvas>
</body>
I am working on the canvas showing levels according to users below is my code the issue is after clip the image on the first level the next drawing and animations stops working.
The canvas holds a json array which is used to draw the levels Class levels
holds the method to deay static shapes and functions starting with animate uses animation frames to animate line or circles.
HTML:
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
</head>
<body>
<canvas id="levelchart" data-levels="[{"text":"Mark","dotcolor":"#28912e","linecolor":"#28912e","current":"0","completed":"1","image":"http:\/\/nessgoods.com\/timthumb.php?src=http:\/\/www.nessgoods.com\/upload\/users\/3\/pills_311869.jpg&q=100"},{"text":5,"dotcolor":"#28912e","linecolor":"#28912e","current":"0","pending":"0","completed":"1"},{"text":25,"dotcolor":"#28912e","linecolor":"#28912e","current":"0","pending":"0","completed":"1"},{"text":125,"dotcolor":"#28912e","linecolor":"#28912e","current":"0","pending":"0","completed":"1"},{"text":625,"dotcolor":"#28912e","linecolor":"#28912e","current":"0","pending":"0","completed":"1"},{"text":3125,"dotcolor":"#28912e","linecolor":"#28912e","current":"0","pending":"0","completed":"1"},{"text":15625,"dotcolor":"#3498db","linecolor":"#3498db","current":"1","completed":"1","pending":"3125"},{"text":78125,"dotcolor":"#3498db","linecolor":"#3498db","current":0,"pending":"0","completed":0},{"text":390625,"dotcolor":"#3498db","linecolor":"#3498db","current":0,"pending":"0","completed":0}]" width="1360" height="380"></canvas>
</body>
JS:
<script
src="https://code.jquery.com/jquery-2.2.4.min.js"
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
crossorigin="anonymous"></script>
<script type="text/javascript">
class levels{
constructor(){
var x = 0;
var y = 0;
var height = 0;
var width = 0;
var canvas = 0;
var fill = 0;
var start = 0;
var end = 0;
var lineWidth = 0;
var color = 0;
var gradient = 0;
var lineCap = "square";
var to = 0;
var data = 0;
var counter = 0;
var circleanimate = 0;
var percent=0;
var completed = 0;
var imagee = "";
}
config(){
}
line(){
// console.log(this.end);
this.canvas.beginPath();
this.canvas.moveTo(this.start, this.y);
this.canvas.lineTo(this.end, this.y);
this.canvas.lineWidth = this.lineWidth;
this.canvas.strokeStyle = this.color;
this.canvas.lineCap = this.lineCap
this.canvas.stroke();
};
circle(){
this.canvas.beginPath();
this.canvas.moveTo(this.end, this.y);
this.canvas.arc(this.end, this.y, this.radius, 0, 2 * Math.PI);
this.canvas.fillStyle = this.color;
this.canvas.fill();
this.canvas.closePath();
}
baloon(){
var bheight = (10 - lv.counter + lv.counter * 8 / 100 * canvas.height);
var totheight = canvas.height - (60 + bheight);
var height = totheight + 80 / 100 * bheight;
this.canvas.beginPath();
//console.log("check "+bheight+" "+totheight+" "+height);
var last = (lv.end-30) + (15 / 100 * bheight);
var y = lv.y-50;
this.canvas.moveTo(last + (12 / 100 * bheight), height - (13 / 100 * bheight));
this.canvas.bezierCurveTo(last - (16 / 100 * bheight), y, last - (16 / 100 * bheight), y, last - (16 / 100 * bheight), y);
this.canvas.bezierCurveTo(last - (36 / 100 * bheight), height, last - (36 / 100 * bheight), height, last - (36 / 100 * bheight), height);
this.canvas.arc(last - (18 / 100 * bheight), totheight + (38 / 100 * bheight), (last + (14 / 100 * bheight)) - (last - (28 / 100 * bheight)), 0.75 * Math.PI, 0.25 * Math.PI);
this.canvas.strokeStyle = lv.color;
this.canvas.lineWidth=3;
this.canvas.stroke();
// count++;
console.log(lv.imagee+" as");
if (this.imagee != "") {
var img = new Image();
img.src = this.imagee;
var newcanvas = this.canvas;
img.onload = function (e)
{
newcanvas.beginPath();
newcanvas.moveTo(last - (18 / 100 * bheight), totheight + (38 / 100 * bheight));
newcanvas.arc(last - (18 / 100 * bheight), totheight + (38 / 100 * bheight), (last + (14 / 100 * bheight)) - (last - (28 / 100 * bheight)) - 1, 0, 2 * Math.PI);
newcanvas.strokeStyle = "#fff";
newcanvas.stroke();
newcanvas.clip();
newcanvas.drawImage(img,last - (18 / 100 * bheight)-(1.5/100*canvas.width),totheight + (38 / 100 * bheight)-(1.5/100*canvas.width));
lv.canvas.beginPath();
// lv.image="";
}
}
}
}
function animateCircle() {
if(lv.circleanimate<2.1){
requestAnimationFrame(animateCircle);
lv.canvas.beginPath();
lv.canvas.moveTo(lv.end, lv.y);
lv.canvas.arc(lv.end, lv.y, lv.radius, (lv.circleanimate-0.1) * Math.PI, lv.circleanimate * Math.PI);
lv.canvas.fillStyle = lv.color;
lv.strokeStyle = "none";
lv.canvas.fill();
lv.canvas.closePath();
lv.circleanimate=lv.circleanimate+0.1;
}else{
lv.circleanimate=0;
if (lv.end == 0) {
lv.start = 0;
lv.end = 0;
lv.to = 30;
lv.color = lv.data[0].linecolor;
lv.style = "normal";
if(lv.data[0].hasOwnProperty("image")){
lv.imagee = lv.data[0].image;
}
} else {
lv.style = "bold";
lv.start = lv.end + 10;
var index = lv.counter-1;
if(lv.counter>=8){
index = 8;
}
console.log(index+" c ");
lv.imagee = "";
if(lv.data[index].hasOwnProperty("image")){
var w = 3/100*canvas.width;
lv.imagee = lv.data[index].image+"&w="+w+"&h="+w;
}
lv.color = lv.data[index].linecolor;
lv.percent = (Number(lv.data[index].pending) / Number(lv.data[index].text) * 100);
lv.completed = lv.data[index].completed;
lv.end = lv.start;
var p = (lv.counter * 2)+2;
lv.to = lv.to + ((p / 100) * workarea);
}
animateElipse();
animateLineFill();
}
}
function animateElipse(){
if(lv.circleanimate<2.1){
requestAnimationFrame(animateElipse);
var bheight = (10 - lv.counter + lv.counter * 8 / 100 * canvas.height);
var totheight = canvas.height - (60 + bheight);
var height = totheight + 80 / 100 * bheight;
var last = lv.end-25;
var y = lv.y-48;
lv.canvas.beginPath();
lv.canvas.moveTo(last, y);
lv.canvas.ellipse(last, y, 8, 2, 0,0, lv.circleanimate * Math.PI);
lv.canvas.fillStyle = "#e4e5e7";
lv.canvas.fill();
lv.circleanimate=lv.circleanimate+0.1;
}else{
lv.baloon();
}
}
function animateLineFill(){
if(lv.end<lv.to){
requestAnimationFrame(animateLineFill);
}else if(lv.counter<lv.count){
lv.circleanimate=0;
if (lv.end == 0) {
lv.start = 0;
lv.end = 0;
lv.to = 30;
lv.color = lv.data[0].linecolor;
lv.style = "normal";
} else {
lv.style = "bold";
lv.start = lv.end + 8;
var index = lv.counter;
if(lv.counter>=8){
index = 8;
}
lv.imagee = "";
if(lv.data[index].hasOwnProperty("image")){
var w = 3/100*canvas.width;
lv.imagee = lv.data[index].image+"&w="+w+"&h="+w;
}
lv.color = lv.data[index].linecolor;
lv.end = lv.start;
// var p = (lv.counter+1.9 * 5);
// lv.to = lv.to + ((p / 100) * workarea);
}
animateCircle();
lv.counter++;
}
lv.line();
lv.end++;
}
var lv = new levels();
var canvas = document.querySelector("canvas#levelchart");
/*canvas.width = (98 / 100) * $("div.team_link").width();
canvas.height = (28 / 100) * canvas.width;*/
canvas.width = (98 / 100) * $(window).width();
canvas.height = (28 / 100) * canvas.width;
var c = canvas.getContext('2d');
var workarea = (canvas.width);
var points = workarea / 10;
var start = canvas.width - 10;
var last = 0;
var y = canvas.height - 10;
var cheight = canvas.height;
var data = document.getElementById("levelchart").getAttribute("data-levels");
data = JSON.parse(data);
var i = 0;
var style = "normal";
lv.start = start;
lv.end = last;
lv.canvas = c;
lv.color="#000000";
lv.y = y;
lv.start = 50;
lv.end = workarea-50;
lv.lineWidth = 4;
lv.color = "#eee";
lv.lineCap = "round";
lv.line();
lv.end = 0;
lv.radius = 5;
lv.count = data.length;
lv.data = data;
lv.counter = 0;
if (lv.end == 0) {
lv.start = 0;
lv.end = 0;
lv.to = 30;
lv.color = lv.data[0].linecolor;
lv.style = "normal";
}
animateLineFill();
</script>
In image.load function we have to call .save() on canvas and after clip() we have call the .restore() function as defined in below code.
img.onload = function (e)
{
newcanvas.save();
newcanvas.beginPath();
newcanvas.moveTo(last - (18 / 100 * bheight), totheight + (38 / 100 * bheight));
newcanvas.arc(last - (18 / 100 * bheight), totheight + (38 / 100 * bheight), (last + (14 / 100 * bheight)) - (last - (28 / 100 * bheight)) - 1, 0, 2 * Math.PI);
newcanvas.strokeStyle = "#fff";
newcanvas.stroke();
newcanvas.clip();
newcanvas.drawImage(img,last - (18 / 100 * bheight)-(1.5/100*canvas.width),totheight + (38 / 100 * bheight)-(1.5/100*canvas.width));
newcanvas.restore();
// lv.image="";
}
I have this code that draws hexagons randomly in a grid and coloring them randomly from an array.
What I want to do is press a CP5 button to initialize the drawing function. If I press this button again, it will fill all drawn hexagons with black and re-initialize the drawing function.
Currently this initialize the drawing:
void mousePressed() {
if (active_counter == 0) {
hexagons[int(wide/2)][int(tall/2)].active = true;
active_counter++;
}
}
So I tried this approach:
public void startDrawing(int theValue) {
println("a button event from startDrawing: "+theValue);
c1 = c2;
c2 = color(0,0,0);
if (active_counter == 40) {
fill(color(0));
}
}
This is not working, because “fill” is not connected to “hexagons”, but I have difficulty appending it the right way.
This is the full code:
import controlP5.*;
ControlP5 cp5;
int myColor = color(255);
int c1,c2;
float n,n1;
// ------------- Hexagon grid -------------
Hexagon[] [] hexagons;
float rx = 51;
float ry = 56;
int wide;
int tall;
int hexagon;
int active_counter = 0;
boolean active;
int max_hexagons;
float Xoffset, Yoffset;
int randX;
int randY;
int randD;
int x;
int y;
int[] stepX = { -1, -1, 1, 0, 1, 1 };
int[][] stepY = {{ 0, 1, -1, 1, 0, 1 }, { 0, -1, -1, 1, 0, -1 } };
class Hexagon {
float x;
float y;
int rand;
color[] colors;
boolean active;
Hexagon (float ix, float iy) {
x = ix;
y = iy;
active = false;
// Array of colors
colors = new color[10];
colors[0] = color(#62563D); // Infantry green
colors[1] = color(#2C2B2D); // Parisian night blue
colors[2] = color(#3E2224); // Purple heart
colors[3] = color(#A49F9B); // Wild dove grey
colors[4] = color(#684F40); // Brown
colors[5] = color(#5C573D); // Moss green
colors[6] = color(#B9897F); // Pink
colors[7] = color(#24283B); // Dark blue
colors[8] = color(#1F1D20); // Black
colors[9] = color(#C5A9A2); // Brazilian clay
// Takes the colors array and output random colors
rand = (int)random(colors.length);
}
// ------------- Nested draw -------------
void draw() {
if (active) {
// Call the colors array in random order
fill(colors[rand]);
} else {
noFill();
}
stroke(80);
pushMatrix();
translate(x, y);
beginShape();
vertex(-17, -28);
vertex(17, -28);
vertex(34, 0);
vertex(17, 28);
vertex(-17, 28);
vertex(-34, 0);
endShape(CLOSE);
popMatrix();
}
}
// ------------- setup -------------
void setup() {
size(1000, 700);
// ------------- CP5 control buttons -------------
cp5 = new ControlP5(this);
cp5.addButton("start drawing")
.setValue(0)
.setPosition(20,80)
.setSize(200, 19)
;
// ------------- Create hexagon grid -------------
wide = int(width/rx) + 2;
tall = int (height/ry) + 2;
max_hexagons = 40;
hexagons = new Hexagon [wide] [tall];
for (int y = 0; y < tall; y++) {
for (int x = 0; x < wide; x++) {
if ( x % 2 == 0) {
hexagons[x] [y] = new Hexagon(x*rx, y*ry);
} else {
hexagons[x] [y] = new Hexagon(x*rx, (y-.5)*ry);
}
}
}
float targetX = width/2;
float targetY = height/2;
Xoffset = hexagons [int(wide/2)] [int(tall/2)] .x - targetX;
Yoffset = hexagons [int(wide/2)] [int(tall/2)] .y - targetY;
}
// ------------- draw -------------
void draw () {
background(0);
pushMatrix();
translate(-Xoffset, -Yoffset);
for (int y = 0; y < tall; y++) {
for (int x = 0; x < wide; x++) {
hexagons[x] [y] .draw();
}
}
if (active_counter > 0 && active_counter < max_hexagons) {
nextHex();
}
popMatrix();
myColor = lerpColor(c1,c2,n);
n += (1-n)* 0.1;
}
public void controlEvent(ControlEvent theEvent) {
println(theEvent.getController().getName());
n = 0;
}
public void startDrawing(int theValue) {
println("a button event from startDrawing: "+theValue);
c1 = c2;
c2 = color(0,0,0);
if (active_counter == 40) {
fill(color(0));
}
}
// ------------- Mouse interaction -------------
void mousePressed() {
if (active_counter == 0) {
hexagons[int(wide/2)][int(tall/2)].active = true;
active_counter++;
}
}
// ------------- Drawing next hexagon -------------
void nextHex() {
int randX = int(random(wide));
int randY = int(random(tall));
while (!hexagons[randX][randY] .active) {
randX = int(random(wide));
randY = int(random(tall));
}
int randD = int(random(6));
if (
randX + stepX[randD] >= 0 &&
randX + stepX[randD] < wide &&
randY + stepY[randX % 2][randD] >= 0 &&
randY + stepY[randX % 2][randD] < tall
) {
if (!hexagons[randX + stepX[randD]][randY + stepY[randX % 2][randD]] .active) {
active_counter++;
}
hexagons[randX + stepX[randD]][randY + stepY[randX % 2][randD]] .active = true;
}
}
I took the example of Laplace from "Making image filters with Canvas", but I can not understand the use of Math.min() function in the following lines. Can anyone explain to me how the Laplace?
var weights = [-1,-1,-1,
-1, 8,-1,
-1,-1,-1];
var opaque = true;
var side = Math.round(Math.sqrt(weights.length));
var halfSide = Math.floor(side/2);
var imgd = context.getImageData(0, 0, canvas.width, canvas.height);
var src = imgd.data;
var sw = canvas.width;
var sh = canvas.height;
var w = sw;
var h = sh;
var output = contextNew.createImageData(w, h);
var dst = output.data;
var alphaFac = opaque ? 1 : 0;
for (var y=0; y<h; y++) {
for (var x=0; x<w; x++) {
var sy = y;
var sx = x;
var dstOff = (y*w+x)*4;
var r=0, g=0, b=0, a=0;
for (var cy=0; cy<side; cy++) {
for (var cx=0; cx<side; cx++) {
var scy = Math.min(sh-1, Math.max(0, sy + cy - halfSide));
var scx = Math.min(sw-1, Math.max(0, sx + cx - halfSide));
var srcOff = (scy*sw+scx)*4;
var wt = weights[cy*side+cx];
r += src[srcOff] * wt;
g += src[srcOff+1] * wt;
b += src[srcOff+2] * wt;
a += src[srcOff+3] * wt;
}
}
dst[dstOff] = r;
dst[dstOff+1] = g;
dst[dstOff+2] = b;
dst[dstOff+3] = a + alphaFac*(255-a);
}
}
its algorithm is something like
for y = 0 to imageHeight
for x = 0 to imageWidth
sum = 0
for i = -h to h
for j = -w to w
sum = sum + k(j, i) * f(x – j, y – i)
end for j
end for i
g(x, y) = sum end for x end for y