Canvas renders drawing but it extends outside the canvas - javascript

I'm new to using Canvas in javascript. I have Web Speech API detecting words said by the user. The canvas then renders this as points of text outline using opentype.js library. However when the user says a longer line, I would like the text to draw the word further down the Y axis. Attaching an image of the problem. This is what I've got so far -
JS
var fontFileName = 'fonts/SourceCodePro-Regular.otf';
var font = null; // font object filled once font loads
var fontSize = 60;
var textToRender = "SHWING!"; // holds string value
var drawPoints = false; // bool to draw letterform points
var drawMetrics = false; // bool for drawing grid
var kerning = true; // apply letter spacing
var ligatures = true; // a ligature occurs where two or more graphemes or letters are joined as a single glyph eg fi
var hinting = false; // Hinting, or screen optimising, is the process by which TrueType or PostScript fonts are adjusted for maximum readability on computer monitors.
var snapPath = null; // path of letterforms
var snapStrength = 10; // letter strength
var snapDistance = 10; //
var snapX = 0; // x axis for each letter
var snapY = 0; // y axis for each letter
var fontSizeSlider = document.getElementById("font-size-range");
let recognition = new SpeechRecognition();
recognition.continuous = true;
recognition.lang = 'en-US';
recognition.interimResults = false;
recognition.maxAlternatives = 1
const recordbtn = document.getElementById('record');
recordbtn.addEventListener('click', () => {
// start speech rec
recognition.start();
initialiseMic()
})
recognition.onresult = function (event) {
let current = event.resultIndex
textToRender = event.results[current][0].transcript
renderText()
}
function renderText() {
if (!font) return;
var options = {
kerning: kerning,
hinting: hinting,
features: {
liga: ligatures,
rlig: ligatures
}
};
// path of points
snapPath = font.getPath(textToRender, 0, 200, fontSize, options);
// snap points into grid
doSnap(snapPath);
var snapCtx = document.getElementById('snap').getContext('2d');
// clear canvas before drawing
snapCtx.clearRect(0, 0, 940, 300);
snapPath.draw(snapCtx);
if (drawPoints) { // create points of text form
font.drawPoints(snapCtx, textToRender, 0, 200, fontSize, options);
}
if (drawMetrics) { // create a visual grid for each letter
font.drawMetrics(snapCtx, textToRender, 0, 200, fontSize, options);
}
}
// Round a value to the nearest "step".
function snap(v, distance, strength) {
return (v * (1.0 - strength)) + (strength * Math.round(v / distance) * distance);
}
function doSnap(path) {
var strength = snapStrength / 100.0;
for (let i = 0; i < path.commands.length; i++) {
var cmd = path.commands[i];
if (cmd.type !== 'Z') {
// 'z' indicates a closed path
cmd.x = snap(cmd.x + snapX, snapDistance, strength) - snapX;
cmd.y = snap(cmd.y + snapY, snapDistance, strength) - snapY;
}
if (cmd.type === 'Q' || cmd.type === 'C') {
// 'C' is curveTo and 'Q' is quadratic Béziers
cmd.x1 = snap(cmd.x1 + snapX, snapDistance, strength) - snapX;
cmd.y1 = snap(cmd.y1 + snapY, snapDistance, strength) - snapY;
}
if (cmd.type === 'C') {
// 'C' is curveTo
cmd.x2 = snap(cmd.x2 + snapX, snapDistance, strength) - snapX;
cmd.y2 = snap(cmd.y2 + snapY, snapDistance, strength) - snapY;
}
}
}
HTML
<!DOCTYPE html>
<html>
<head>
<title>Prototype 3</title>
<meta name="description" content="A prototype to change the letterforms of text with speech analysis">
<meta charset="utf-8">
<script src="https://cdn.socket.io/socket.io-3.0.1.min.js"></script>
<script type="text/javascript" src="libraries/opentype.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- title -->
<div class="container">
<span class="info" id="font-name"></span>
<button id ="record">Record</button>
<!-- font size -->
<label>Font Size<input type="range" min="6" max="500" step="2" value="150" id="font-size-range"
autocomplete="off"><span id="fontSize">150</span></label>
</div>
<div class="container2">
<canvas id="snap" width="940" height="600" class="text"></canvas>
</div>
<script src="sketch.js" type="text/javascript"></script>
</body>
</html>

Related

Using PDF-Lib to create a document and print without saving the document locally

Within my web application, I am attempting to create a PDF document (which I am doing successfully) and then print it.
Most of the solutions I have found said that you will have to do it server-side probably with some PHP, which would be fine. but If I did that, I would have no clue how to do this.
The application is only really used by one machine and it is not distributed on the web so it is locally hosted only so no need for another end-user computer.
Application Goal / Expected result
I would like the application to:
Generate a PDF based on the user's input (DONE AND WORKS)
Use the PDF and PRINT straight away
EDIT: I have a printer so I do not need a printer on demand
So it appears I would have a few viable options...
PDF-Lib client-side only (possible client-side DB?)
PDF-Lib client-side and a server-side link using PHP?
Fully server-side
A base 64 link?
I have tried locally saving it to the machine and using the file but it will not allow me, unfortunately :(
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Get Your Certificate for The Event</title>
<link rel="stylesheet" href="style.css">
<link rel="favicon" href="favicon.ico">
</head>
<body>
<header>
<img src="FR_Logo.png" alt="FRSystems Logo" width="500" height="250" />
<h4>Get your certificate of your laps</h4>
</header>
<main>
<label for="name">Type Your Name</label>
<input required type="text" name="Name" autocomplete="name" placeholder="" id="name" minlength="1"
maxlength="16">
<Button id="submitBtn">Get Certificate</Button>
</main>
<script src="https://unpkg.com/pdf-lib/dist/pdf-lib.js"></script>
<script src="https://unpkg.com/pdf-lib/dist/pdf-lib.min.js"></script>
<iframe id="iframe"></iframe>
<script src="./FileSaver.js"></script>
<script src="https://unpkg.com/#pdf-lib/fontkit#0.0.4"></script>
<script src="./index.js"></script>
</body>
</html>
Index.JS
const userName = document.getElementById("name");
const submitBtn = document.getElementById("submitBtn");
const { PDFDocument, rgb, degrees, StandardFonts } = PDFLib;
const capitalize = (str, lower = false) =>
(lower ? str.toLowerCase() : str).replace(/(?:^|\s|["'([{])+\S/g, (match) =>
match.toUpperCase()
);
submitBtn.addEventListener("click", () => {
const val = capitalize(userName.value);
//check if the text is empty or not
if (val.trim() !== "" && userName.checkValidity()) {
console.log(val);
createPdf(val);
} else {
userName.reportValidity();
}
});
function print() {
var frame = document.getElementById('frame');
frame.contentWindow.focus();
frame.contentWindow.print();
};
function readURL(input) {
console.log("GOT HERE");
// if (input.files && input.files[0]) {
console.log("GOT HERE 2");
var reader = new FileReader();
reader.onload = function (e) {
console.log(e.target.result);
// $('#pdfResult')
// .attr('src', e.target.result);
};
reader.readAsDataURL(input.files[0]);
console.log(reader.readAsDataURL(input.files[0]));
// }
};
async function createPdf(val) {
const pdfDoc = await PDFDocument.create();
const timesRomanFont = await pdfDoc.embedFont(StandardFonts.TimesRoman);
const page = pdfDoc.addPage();
const { width, height } = page.getSize();
page.setSize(841.89, 595.28)
// midpoint x = 420.945, y= 297.64
console.log(page.getSize(),width,height)
const fontSize = 30
var textWidth = timesRomanFont.widthOfTextAtSize(val, fontSize);
console.log(timesRomanFont.widthOfTextAtSize(val, fontSize))
var textHeight = timesRomanFont.heightAtSize(fontSize);
var nameY = ((page.getHeight() / 2) + 50) - (textHeight / 2);
var centerY = page.getHeight() / 2 - textHeight / 2;
var centerX = page.getWidth() / 2 - textWidth / 2;
page.drawText(val, {
x: centerX,
y: nameY,
size: fontSize,
font: timesRomanFont,
color: rgb(0, 0, 0),
});
var score = "32"; // Would be taken from the database (Select query) using ID/ChipNumber
var scoreString = "who completed " + score + " laps";
var bottomText = "< EVENT NAME > on < LONG DATE >";
var supportingText = "< Support Text >"
var textWidthScoreString = timesRomanFont.widthOfTextAtSize(scoreString, fontSize);
console.log(timesRomanFont.widthOfTextAtSize(scoreString, fontSize));
var scoreY = ((page.getHeight() / 2) + 0) - (textHeight / 2);
var scoreX = page.getWidth() / 2 - textWidthScoreString / 2;
var bottomTextWidthString = timesRomanFont.widthOfTextAtSize(bottomText, fontSize);
var bottomTextY = ((page.getHeight() / 2) - 50) - (textHeight / 2);
var bottomTextX = page.getWidth() / 2 - bottomTextWidthString / 2;
var supportingTextWidthString = timesRomanFont.widthOfTextAtSize(supportingText, fontSize);
var supportingTextY = ((page.getHeight() / 2) - 100) - (textHeight / 2);
var supportingTextX = page.getWidth() / 2 - supportingTextWidthString / 2;
page.drawText(scoreString, {
x: scoreX,
y: scoreY,
size: fontSize,
font: timesRomanFont,
color: rgb(0, 0, 0),
});
page.drawText(bottomText, {
x: bottomTextX,
y: bottomTextY,
size: fontSize,
font: timesRomanFont,
color: rgb(0, 0, 0),
});
page.drawText(supportingText, {
x: supportingTextX,
y: supportingTextY,
size: fontSize,
font: timesRomanFont,
color: rgb(0, 0, 0),
});
const pdfBytes = await pdfDoc.save();
console.log(pdfBytes);
console.log(pdfDoc)
// Create a new file
// This uses File Saver to save the files, i used this to temp save whilst i moved around the text
var file = new File(
[pdfBytes],
"test-Certificate.pdf",
{
type: "application/pdf;charset=utf-8",
}
);
console.log(file);
// var iframe = document.getElementById('iframe');
// iframe.src = file;
// iframe.contentWindow.focus();
// iframe.contentWindow.print();
// readURL(file);
// saveAs(file);
console.log(saveAs(file));
};

Draw line in Phaser 3

I need your help. I am newbie in Phaser 3. I want to create game with simple rules. There are 36 dots, which situated in 6 rows. Player needs to unite dots with a line, but he can only unite dots with same color and union can happen only vertically and horizontally. So, you can't draw daigonal line. When you will finish union, dots will vanish. How I can realize union with line? My current code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="js/phaser.min.js"></script>
</head>
<body>
<script>
let config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#f0ebeb',
physics: {
default: 'arcade',
arcade: {
gravity: { y: 300 },
debug: false
}
},
scene: {
preload: preload,
create: create,
update: update
},
scale: {
autoCenter: Phaser.Scale.CENTER_BOTH
}
};
let game = new Phaser.Game(config);
let items = [];
function preload() {
for (let i = 1; i < 6; i++)
this.load.image(i, 'img/' + i + '.png');
}
function create() {
let x = 100;
let y = 0;
for (i = 0; i < 36; i++) {
if (i % 6 === 0) {
y += 85;
x = 100;
}
this.add.image(x, y, getRandomInt(5).toString())
x += 125;
}
}
function update() { }
function getRandomInt(max) {
return Math.floor(Math.random() * max) + 1;
}
</script>
</body>
</html>
I want something like this
I would just allow the user only to select (draw a line) to next valid circles.
A valid circle being, on the same row or same column or same color or max union length or ...
And when the drawing is finished I would, only allow union, when more than one circle is selected (is in the given path).
Here a short demo, how it could look like:
let config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 400,
height: 200,
banner: false,
scene: { create }
};
let game = new Phaser.Game(config);
let isDragging = false;
let lineStartPosition = {x:0 , y:0};
let currentPath = [];
let currentColor;
let line;
let pathGraphics;
function create ()
{
let cicles = []
for(let rowIdx = 0; rowIdx < 4; rowIdx++ ){
for(let colIdx = 0; colIdx < 2; colIdx++ ){
let circle = this.add.circle(50 + 100 * rowIdx, 50 + 100 * colIdx, 25, 0x6666ff).setOrigin(.5);
// Just to test a different color
if(rowIdx + colIdx ==2){
circle.fillColor = 0xff0000;
}
circle.setInteractive();
cicles.push(circle);
}
}
line = this.add.line(0,0, 0,0, 100, 100, 0xffffff).setOrigin(0);
line.setLineWidth(5);
line.visible = false;
pathGraphics = this.add.graphics();
// adding the events to the scene
this.input.on('pointerdown', dragStart);
this.input.on('pointerup', dragEnd);
this.input.on('pointermove', drag);
}
function dragStart(pointer, gameObjects){
if(gameObjects.length == 0){
return;
}
isDragging = true;
// remember Starting Color
currentColor = gameObjects[0].fillColor;
// initialize Path
currentPath = [gameObjects[0]];
// draw/save last segment of the path
lineStartPosition.x = gameObjects[0].x;
lineStartPosition.y = gameObjects[0].y;
line.x = gameObjects[0].x;
line.y = gameObjects[0].y;
line.setTo(0, 0, 0, 0);
line.visible = true;
}
function drag(pointer, gameObjects ){
if(isDragging == true){
// Check If Circle is allowed to be added, to path
// Here you would also check if the line is horizontal or vertical (this part is currently not implemented)
if(gameObjects[0] && currentPath.indexOf(gameObjects[0]) === -1 && currentColor == gameObjects[0].fillColor){
currentPath.push(gameObjects[0]);
line.x = gameObjects[0].x;
line.y = gameObjects[0].y;
lineStartPosition.x = gameObjects[0].x;
lineStartPosition.y = gameObjects[0].y;
}
line.setTo(0, 0, pointer.x - lineStartPosition.x, pointer.y - lineStartPosition.y);
drawPath();
}
}
function drawPath(){
pathGraphics.clear();
if(currentPath.length > 0){
pathGraphics.lineStyle(10, 0xffffff);
let path = new Phaser.Curves.Path(currentPath[0].x, currentPath[0].y);
for(let idx = 1; idx < currentPath.length; idx++){
let point = currentPath[idx];
path.lineTo(point.x, point.y);
}
path.draw(pathGraphics);
}
}
function dragEnd(pointer, gameObjects){
if(gameObjects.length == 0){
return;
}
if(currentPath.length < 2) {
console.info('No valid path');
return
} else {
console.info(`Valid Union path, length: ${currentPath.length}`);
}
line.visible = false;
isDragging = false;
}
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>

TF.js load object detection model in model.json format in browser for custom classes

I am working on object detection using Tensorflow.js. I am trying to run custom object detection tensorflow.js model in a browser. I converted the tensorflow model - inference graph to tensorflow.js model.
Prediction for python works fine and the code below:
import io
import os
import scipy.misc
import numpy as np
import six
import time
import glob
from IPython.display import display
from six import BytesIO
import matplotlib
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw, ImageFont
import tensorflow as tf
from object_detection.utils import ops as utils_ops
from object_detection.utils import label_map_util
from object_detection.utils import visualization_utils as vis_util
%matplotlib inline
def load_image_into_numpy_array(path):
img_data = tf.io.gfile.GFile(path, 'rb').read()
image = Image.open(BytesIO(img_data))
(im_width, im_height) = image.size
return np.array(image.getdata()).reshape(
(im_height, im_width, 3)).astype(np.uint8)
category_index = label_map_util.create_category_index_from_labelmap('Models/Annotation/label_map.pbtxt', use_display_name=True)
tf.keras.backend.clear_session()
model = tf.saved_model.load(f'Models/saved_model/')
def run_inference_for_single_image(model, image):
image = np.asarray(image)
input_tensor = tf.convert_to_tensor(image)
input_tensor = input_tensor[tf.newaxis,...]
output_dict = model_fn(input_tensor)
num_detections = int(output_dict.pop('num_detections'))
output_dict = {key:value[0, :num_detections].numpy()
for key,value in output_dict.items()}
output_dict['num_detections'] = num_detections
output_dict['detection_classes'] = output_dict['detection_classes'].astype(np.int64)
if 'detection_masks' in output_dict:
detection_masks_reframed = utils_ops.reframe_box_masks_to_image_masks(
output_dict['detection_masks'], output_dict['detection_boxes'],
image.shape[0], image.shape[1])
detection_masks_reframed = tf.cast(detection_masks_reframed > 0.5,
tf.uint8)
output_dict['detection_masks_reframed'] = detection_masks_reframed.numpy()
return output_dict
for image_path in glob.glob('images/Group_A_406.jpg'):
image_np = load_image_into_numpy_array(image_path)
output_dict = run_inference_for_single_image(model, image_np)
scores = np.squeeze(output_dict['detection_scores'])
vis_util.visualize_boxes_and_labels_on_image_array(
image_np,
output_dict['detection_boxes'],
output_dict['detection_classes'],
output_dict['detection_scores'],
category_index,
instance_masks=output_dict.get('detection_masks_reframed', None),
use_normalized_coordinates=True,
max_boxes_to_draw=50,
min_score_thresh=.45,
line_thickness=8)
display(Image.fromarray(image_np))
sharing the code snippet of index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>The Recognizer</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="styles.css" rel="stylesheet">
</head>
<body>
<h1>Object Detection</h1>
<section id="demos">
<div id="liveView" >
<button id="webcamButton" class="invisible">Loading...</button>
<video id="webcam" class="background" playsinline crossorigin="anonymous"></video>
</div>
</section>
<!-- Import TensorFlow.js library -->
<!-- <script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs/dist/tf.min.js"></script-->
<script src="https://cdn.jsdelivr.net/npm/#tensorflow/tfjs#3.3.0/dist/tf.min.js"></script>
<script src="script.js"></script>
</body>
</html>
code snippet of script.js
//Store hooks and video sizes:
const video = document.getElementById('webcam');
const liveView = document.getElementById('liveView');
const demosSection = document.getElementById('demos');
const enableWebcamButton = document.getElementById('webcamButton');
const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0)
const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0)
var vidWidth = 0;
var vidHeight = 0;
var xStart = 0;
var yStart = 0;
// Check if webcam access is supported.
function getUserMediaSupported() {
return !!(navigator.mediaDevices &&
navigator.mediaDevices.getUserMedia);
}
// If webcam supported, add event listener to activation button:
if (getUserMediaSupported()) {
enableWebcamButton.addEventListener('click', enableCam);
} else {
console.warn('getUserMedia() is not supported by your browser');
}
// Enable the live webcam view and start classification.
function enableCam(event) {
// Only continue if model has finished loading.
if (!model) {
return;
}
// Hide the button once clicked.
enableWebcamButton.classList.add('removed');
// getUsermedia parameters to force video but not audio.
const constraints = {
video: true
};
// Stream video from VAR (for safari also)
navigator.mediaDevices.getUserMedia({
video: {
facingMode: "environment"
},
}).then(stream => {
let $video = document.querySelector('video');
$video.srcObject = stream;
$video.onloadedmetadata = () => {
vidWidth = $video.videoHeight;
vidHeight = $video.videoWidth;
//The start position of the video (from top left corner of the viewport)
xStart = Math.floor((vw - vidWidth) / 2);
yStart = (Math.floor((vh - vidHeight) / 2)>=0) ? (Math.floor((vh - vidHeight) / 2)):0;
$video.play();
//Attach detection model to loaded data event:
$video.addEventListener('loadeddata', predictWebcamTF);
}
});
}
var model = undefined;
model_url = 'https://raw.githubusercontent.com/.../model/mobile_netv2/web_model2/model.json';
//Call load function
asyncLoadModel(model_url);
//Function Loads the GraphModel type model of
async function asyncLoadModel(model_url) {
model = await tf.loadGraphModel(model_url);
console.log('Model loaded');
//Enable start button:
enableWebcamButton.classList.remove('invisible');
enableWebcamButton.innerHTML = 'Start camera';
}
var children = [];
//Perform prediction based on webcam using Layer model model:
function predictWebcamTF() {
// Now let's start classifying a frame in the stream.
detectTFMOBILE(video).then(function () {
// Call this function again to keep predicting when the browser is ready.
window.requestAnimationFrame(predictWebcamTF);
});
}
const imageSize = 300;
//Match prob. threshold for object detection:
var classProbThreshold = 0.4;//40%
//Image detects object that matches the preset:
async function detectTFMOBILE(imgToPredict) {
//Get next video frame:
await tf.nextFrame();
//Create tensor from image:
const tfImg = tf.browser.fromPixels(imgToPredict);
//Create smaller image which fits the detection size
const smallImg = tf.image.resizeBilinear(tfImg, [vidHeight,vidWidth]);
const resized = tf.cast(smallImg, 'int32');
var tf4d_ = tf.tensor4d(Array.from(resized.dataSync()), [1,vidHeight, vidWidth, 3]);
const tf4d = tf.cast(tf4d_, 'int32');
//Perform the detection with your layer model:
let predictions = await model.executeAsync(tf4d);
//Draw box around the detected object:
renderPredictionBoxes(predictions[4].dataSync(), predictions[1].dataSync(), predictions[2].dataSync());
//Dispose of the tensors (so it won't consume memory)
tfImg.dispose();
smallImg.dispose();
resized.dispose();
tf4d.dispose();
}
//Function Renders boxes around the detections:
function renderPredictionBoxes (predictionBoxes, predictionClasses, predictionScores)
{
//Remove all detections:
for (let i = 0; i < children.length; i++) {
liveView.removeChild(children[i]);
}
children.splice(0);
//Loop through predictions and draw them to the live view if they have a high confidence score.
for (let i = 0; i < 99; i++) {
//If we are over 66% sure we are sure we classified it right, draw it!
const minY = (predictionBoxes[i * 4] * vidHeight+yStart).toFixed(0);
const minX = (predictionBoxes[i * 4 + 1] * vidWidth+xStart).toFixed(0);
const maxY = (predictionBoxes[i * 4 + 2] * vidHeight+yStart).toFixed(0);
const maxX = (predictionBoxes[i * 4 + 3] * vidWidth+xStart).toFixed(0);
const score = predictionScores[i * 3] * 100;
const width_ = (maxX-minX).toFixed(0);
const height_ = (maxY-minY).toFixed(0);
//If confidence is above 70%
if (score > 70 && score < 100){
const highlighter = document.createElement('div');
highlighter.setAttribute('class', 'highlighter');
highlighter.style = 'left: ' + minX + 'px; ' +
'top: ' + minY + 'px; ' +
'width: ' + width_ + 'px; ' +
'height: ' + height_ + 'px;';
highlighter.innerHTML = '<p>'+Math.round(score) + '% ' + 'Your Object Name'+'</p>';
liveView.appendChild(highlighter);
children.push(highlighter);
}
}
}
I'm struggling to rewrite the .js code for custom trained classes.
Also I'm unable to trace the tensor shape that needs to be mentioned in .js file. I have fine tuned using ssd mobilenetv2 320*320 on 4 custom classes.
Thanks in advance

Can't create text in easeljs

currelty working on a small matching puzzle game. Currently it displays text for the time remaining and the number of tiles that have been macthes. I'm trying to create on for best completion time as well (How fast the person finishes the game) however have been running into a lot of problems. for two variables that I created "txt" and "matchesFoundText" when I type them the autocomplete box will popup and ".text" is displayed as one of the options so i would get something like "txt.text. however I'm not getting that option at all for "bestTimeTxt" and I have no idea as to why this is happening. I did all three variables the same way so I'm at a loss as to why Text is not available to select from for "bestTimeTxt". Here is my entire script.
<!DOCTYPE html>
<html>
<head>
<title>Recipe: Drawing a square</title>
<script src="easel.js"></script>
<script type="text/javascript">
var canvas;
var stage;
var squareSide = 70;
var squareOutline = 5;
var max_rgb_color_value = 255;
var gray = Graphics.getRGB(20, 20, 20);
var placementArray = [];
var tileClicked;
var timeAllowable;
var totalMatchesPossible;
var matchesFound;
var txt;
var bestTime;
var bestTimeTxt;
var matchesFoundText;
var squares;
function init() {
var rows = 5;
var columns = 6;
var squarePadding = 10;
canvas = document.getElementById('myCanvas');
stage = new Stage(canvas);
var numberOfTiles = rows*columns;
matchesFound = 0;
timeAllowable = 5;
bestTime = 0;
txt = new Text(timeAllowable, "30px Monospace", "#000");
txt.textBaseline = "top"; // draw text relative to the top of the em box.
txt.x = 500;
txt.y = 0;
bestTimeTxt = new Text(bestTime, "30px Monospace", "#000");
bestTimeTxt.textBaseLine = "top";
bestTimeTxt.x = 500;
bestTimeTxt.y = 80;
stage.addChild(txt);
stage.addChild(bestTimeTxt);
squares = [];
totalMatchesPossible = numberOfTiles/2;
Ticker.init();
Ticker.addListener(window);
Ticker.setPaused(false);
matchesFoundText = new Text("Pairs Found: "+matchesFound+"/"+totalMatchesPossible, "30px Monospace", "#000");
matchesFoundText.textBaseline = "top"; // draw text relative to the top of the em box.
matchesFoundText.x = 500;
matchesFoundText.y = 40;
stage.addChild(matchesFoundText);
setPlacementArray(numberOfTiles);
for(var i=0;i<numberOfTiles;i++){
var placement = getRandomPlacement(placementArray);
if (i % 2 === 0){
var color = randomColor();
}
var square = drawSquare(gray);
square.color = color;
square.x = (squareSide+squarePadding) * (placement % columns);
square.y = (squareSide+squarePadding) * Math.floor(placement / columns);
squares.push(square);
stage.addChild(square);
square.cache(0, 0, squareSide + squarePadding, squareSide + squarePadding);
square.onPress = handleOnPress;
stage.update();
};
}
function drawSquare(color) {
var shape = new Shape();
var graphics = shape.graphics;
graphics.setStrokeStyle(squareOutline);
graphics.beginStroke(gray);
graphics.beginFill(color);
graphics.rect(squareOutline, squareOutline, squareSide, squareSide);
return shape;
}
function randomColor(){
var color = Math.floor(Math.random()*255);
var color2 = Math.floor(Math.random()*255);
var color3 = Math.floor(Math.random()*255);
return Graphics.getRGB(color, color2, color3)
}
function setPlacementArray(numberOfTiles){
for(var i = 0;i< numberOfTiles;i++){
placementArray.push(i);
}
}
function getRandomPlacement(placementArray){
randomNumber = Math.floor(Math.random()*placementArray.length);
return placementArray.splice(randomNumber, 1)[0];
}
function handleOnPress(event){
var tile = event.target;
tile.graphics.beginFill(tile.color).rect(squareOutline, squareOutline, squareSide, squareSide);
if(!!tileClicked === false || tileClicked === tile){
tileClicked = tile;
tileClicked.updateCache("source-overlay");
}else{
if(tileClicked.color === tile.color && tileClicked !== tile){
tileClicked.visible = false;
tile.visible = false;
matchesFound++;
matchesFoundText.text = "Pairs Found: "+matchesFound+"/"+totalMatchesPossible;
if (matchesFound===totalMatchesPossible){
gameOver(true);
}
}else{
tileClicked.graphics.beginFill(gray).rect(squareOutline, squareOutline, squareSide, squareSide);
}
tileClicked.updateCache("source-overlay");
tile.updateCache("source-overlay");
tileClicked = tile;
}
stage.update();
}
function tick() {
secondsLeft = Math.floor((timeAllowable-Ticker.getTime()/1000));
txt.text = secondsLeft;
;
if (secondsLeft <= 0){
gameOver(false);
}
stage.update();
}
function gameOver(win){
Ticker.setPaused(true);
for(var i=0;i<squares.length;i++){
squares[i].graphics.beginFill(squares[i].color).rect(5, 5, 70, 70);
squares[i].onPress = null;
if (win === false){
squares[i].uncache();
}
}
var replayParagraph = document.getElementById("replay");
replayParagraph.innerHTML = "<a href='#' onClick='history.go(0);'>Play Again?</a>";
if (win === true){
matchesFoundText.text = "You win!"
}else{
txt.text = secondsLeft + "... Game Over";
}
}
function replay(){
init();
}
</script>
</head>
<body onload="init()">
<header id="header">
<p id="replay"></p>
</header>
<canvas id="myCanvas" width="960" height="400"></canvas>
</body>
</html>
Okay so apparently the reason why I was having issues is because the x and y positions of the bestTimeTxt variable was causing it to be obscured by the position of everything else.

Javascript Color Animation

I want to animate (transition) from 1 color to another in raw javascript.
I dont want to use any framework (jquery, mootools) or css3. plain raw javascript.
I have been really having trouble to do this, can someone help me out ? :)
maybe something like this:
lerp = function(a, b, u) {
return (1 - u) * a + u * b;
};
fade = function(element, property, start, end, duration) {
var interval = 10;
var steps = duration / interval;
var step_u = 1.0 / steps;
var u = 0.0;
var theInterval = setInterval(function() {
if (u >= 1.0) {
clearInterval(theInterval);
}
var r = Math.round(lerp(start.r, end.r, u));
var g = Math.round(lerp(start.g, end.g, u));
var b = Math.round(lerp(start.b, end.b, u));
var colorname = 'rgb(' + r + ',' + g + ',' + b + ')';
el.style.setProperty(property, colorname);
u += step_u;
}, interval);
};
You can play around an try it out as a jsfiddle or check out the full working example below. You might want to improve this by using HSL/HSV colors, which gives you a prettier transition, but i'll leave that up to you.
<html>
<head>
<title>Fade</title>
<style type="text/css">
#box {
width: 100px;
height: 100px;
background-color: rgb(255,0,0);
}
</style>
</head>
<body>
<div id="box"></div>
<script type="text/javascript" charset="utf-8">
// linear interpolation between two values a and b
// u controls amount of a/b and is in range [0.0,1.0]
lerp = function(a,b,u) {
return (1-u) * a + u * b;
};
fade = function(element, property, start, end, duration) {
var interval = 10;
var steps = duration/interval;
var step_u = 1.0/steps;
var u = 0.0;
var theInterval = setInterval(function(){
if (u >= 1.0){ clearInterval(theInterval) }
var r = parseInt(lerp(start.r, end.r, u));
var g = parseInt(lerp(start.g, end.g, u));
var b = parseInt(lerp(start.b, end.b, u));
var colorname = 'rgb('+r+','+g+','+b+')';
el.style.setProperty(property, colorname);
u += step_u;
}, interval);
};
// in action
el = document.getElementById('box'); // your element
property = 'background-color'; // fading property
startColor = {r:255, g: 0, b: 0}; // red
endColor = {r: 0, g:128, b:128}; // dark turquoise
fade(el,'background-color',startColor,endColor,1000);
// fade back after 2 secs
setTimeout(function(){
fade(el,'background-color',endColor,startColor,1000);
},2000);
</script>
</body>
</html>
Here is also my solution:
<html><head>
<script type="text/javascript">
<!--
function animate(id,color0,color1,duration){
//public attributes
this.elem = document.getElementById(id);
//private attributes
var r0= parseInt(color0.substring(0,2),16);
var g0= parseInt(color0.substring(2,4),16);
var b0= parseInt(color0.substring(4,6),16);
var r1= parseInt(color1.substring(0,2),16);
var g1= parseInt(color1.substring(2,4),16);
var b1= parseInt(color1.substring(4,6),16);
var wait = 100; //100ms
var steps = duration/wait;
var rstep = (r1 - r0) / (steps);
var gstep = (g1 - g0) / (steps);
var bstep = (b1 - b0) / (steps);
var self = this;
//public functions
this.step = function() {
steps--;
if ( steps>0 ) {
r0 = Math.floor(r0 + rstep);
g0 = Math.floor(g0 + gstep);
b0 = Math.floor(b0 + bstep);
elem.style.backgroundColor = 'rgb('+r0+','+g0+','+b0+')';
//alert(steps + ' ; ' + elem.style.backgroundColor);
window.setTimeout(function(){self.step();}, wait);
} else {
elem.style.backgroundColor = '#'+color1;
}
}
step();
//alert(this.r0);
}
//-->
</script>
</head><body>
<div id="anim" style="width:100px; height:100px; background-color:#ff0000"></div>
<input type="button" onclick="animate('anim','1122ff','ff2211',1000)" value="test" />
</body>
</html>
html at pastebin, how to call the timeout function - see for example 1, 2
if canvas would be ok you could try doing it like this ;)
var context = document.getElementsByTagName('canvas')[0].getContext('2d');
var hue = 0;
function bgcolor() {
hue = hue + Math.random() * 3 ;
context.fillStyle = 'hsl(' + hue + ', 100%, 50%)';
context.fillRect(0, 0, context.canvas.width, context.canvas.height);
}
setInterval(bgcolor, 20 );
Yes ;) it`s not perfect and just an excample but give it a try. Here is the complete pen on codepen.
One way might be to use setTimeout to call some function which incrementally changes the colour (I'm assuming background-color) by some small amount each time it's called. At each iteration, just check to see if you've arrived at your target colour and if not, increase or decrease your RGB value as necessary.

Categories

Resources