summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzhang <zch921005@126.com>2022-06-04 08:48:54 +0800
committerzhang <zch921005@126.com>2022-06-04 08:48:54 +0800
commit44097da7288042e988bcb89f1c6cc817a8e1eec9 (patch)
tree7c28da29f31ca429b8d27ed7441d650f1195812d
parent0f885b830ac552bfd357dec74c70e1349434b58b (diff)
0604
-rw-r--r--att/swin_transformer_demo.py1
-rw-r--r--cv/seg/img2video.py3
-rw-r--r--cv/tracker/object_tracker.py106
-rw-r--r--cv/tracker/video.avibin0 -> 12927512 bytes
-rw-r--r--learn_torch/seq/basic_rnn.py43
-rw-r--r--learn_torch/seq/sentiment_analysis.py193
-rw-r--r--learn_torch/seq/test_rnn.py8
-rw-r--r--pose/1.mp4bin0 -> 13892865 bytes
-rw-r--r--pose/4.jpgbin0 -> 333738 bytes
-rw-r--r--pose/PoseEstimation.py64
-rw-r--r--pretrained/swin/demo.py36
-rw-r--r--pretrained/swin/house_finch.jpgbin0 -> 20694 bytes
-rw-r--r--pretrained/swin/imagenet_labels.json1000
-rw-r--r--rl/gym_demo/hello.py10
-rw-r--r--web/Tower of Hanoi Animation by Y. Daniel Liang.html762
-rw-r--r--web/bigai/canvas_layering.html116
-rw-r--r--web/bigai/myrender.py109
-rw-r--r--web/bigai/test.html52
-rw-r--r--web/canvas-transforms.html82
-rw-r--r--web/canvas_animation.html73
-rw-r--r--web/canvas_layering.html113
-rw-r--r--web/layers/CanvasStack-2v01.js207
-rw-r--r--web/layers/index.html13
-rw-r--r--web/layers/main.js15
-rw-r--r--web/learn_canvas/bar_canvas.html50
-rw-r--r--web/learn_canvas/basics/index.html11
-rw-r--r--web/learn_canvas/basics/main.js60
-rw-r--r--web/learn_canvas/canvas_btns/example.js121
-rw-r--r--web/learn_canvas/canvas_btns/index.html43
-rw-r--r--web/learn_canvas/canvas_btns/main.js11
-rw-r--r--web/learn_canvas/canvas_btns/style.css18
-rw-r--r--web/learn_canvas/canvas_btns/test.html77
-rw-r--r--web/learn_canvas/canvas_btns/test2.html47
-rw-r--r--web/multi_layers.html24
-rw-r--r--web/multi_layers/index.html11
-rw-r--r--web/multi_layers/main.js60
36 files changed, 3515 insertions, 24 deletions
diff --git a/att/swin_transformer_demo.py b/att/swin_transformer_demo.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/att/swin_transformer_demo.py
@@ -0,0 +1 @@
+
diff --git a/cv/seg/img2video.py b/cv/seg/img2video.py
index c824c9c..4fdc17b 100644
--- a/cv/seg/img2video.py
+++ b/cv/seg/img2video.py
@@ -9,7 +9,8 @@ images = [img for img in os.listdir(image_folder) if img.endswith(".jpg")]
frame = cv2.imread(os.path.join(image_folder, images[0]))
height, width, layers = frame.shape
-video = cv2.VideoWriter(video_name, 0, 10, (width,height))
+fourcc = cv2.VideoWriter_fourcc(*'XVID')
+video = cv2.VideoWriter(video_name, fourcc, 10, (width,height))
images.sort(key=lambda s: int(s.split('.')[0].split('-')[1]))
for image in tqdm(images):
video.write(cv2.imread(os.path.join(image_folder, image)))
diff --git a/cv/tracker/object_tracker.py b/cv/tracker/object_tracker.py
index 315ffa3..7c99145 100644
--- a/cv/tracker/object_tracker.py
+++ b/cv/tracker/object_tracker.py
@@ -1,35 +1,95 @@
import cv2
+import sys
-cap = cv2.VideoCapture(0)
+(major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.')
-tracker = cv2.TrackerGOTURN_create()
-success, img = cap.read()
+if __name__ == '__main__':
-# select a bounding box ( ROI )
-bbox = cv2.selectROI("Tracking", img, False)
-tracker.init(img, bbox)
+ # Set up tracker.
+ # Instead of MIL, you can also use
+ tracker_types = ['BOOSTING', 'MIL', 'KCF', 'TLD', 'MEDIANFLOW', 'GOTURN', 'MOSSE', 'CSRT']
+ tracker_type = tracker_types[2]
-def drawBox(img, bbox):
- x, y, w, h = int(bbox[0]), int(bbox[1]), int(bbox[2]), int(bbox[3])
- cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 255), 3, 1)
- cv2.putText(img, "Tracking", (75, 75), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
+ if int(minor_ver) < 3:
+ tracker = cv2.Tracker_create(tracker_type)
+ else:
+ if tracker_type == 'BOOSTING':
+ tracker = cv2.TrackerBoosting_create()
+ if tracker_type == 'MIL':
+ tracker = cv2.TrackerMIL_create()
+ if tracker_type == 'KCF':
+ tracker = cv2.TrackerKCF_create()
+ if tracker_type == 'TLD':
+ tracker = cv2.TrackerTLD_create()
+ if tracker_type == 'MEDIANFLOW':
+ tracker = cv2.TrackerMedianFlow_create()
+ if tracker_type == 'GOTURN':
+ tracker = cv2.TrackerGOTURN_create()
+ if tracker_type == 'MOSSE':
+ tracker = cv2.TrackerMOSSE_create()
+ if tracker_type == "CSRT":
+ tracker = cv2.TrackerCSRT_create()
+ # Read video
+ video = cv2.VideoCapture("./video.avi")
-while True:
- timer = cv2.getTickCount()
- success, img = cap.read()
+ # Exit if video not opened.
+ if not video.isOpened():
+ print
+ "Could not open video"
+ sys.exit()
- success, bbox = tracker.update(img)
+ # Read first frame.
+ ok, frame = video.read()
+ if not ok:
+ print
+ 'Cannot read video file'
+ sys.exit()
- if success:
- drawBox(img, bbox)
- else:
- cv2.putText(img, "Loss", (75, 75), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
+ # Define an initial bounding box
+ bbox = (287, 23, 86, 320)
+
+ # Uncomment the line below to select a different bounding box
+ bbox = cv2.selectROI(frame, False)
+
+ # Initialize tracker with first frame and bounding box
+ ok = tracker.init(frame, bbox)
+
+ while True:
+ # Read a new frame
+ ok, frame = video.read()
+ if not ok:
+ break
+
+ # Start timer
+ timer = cv2.getTickCount()
+
+ # Update tracker
+ ok, bbox = tracker.update(frame)
+
+ # Calculate Frames per second (FPS)
+ fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer);
+
+ # Draw bounding box
+ if ok:
+ # Tracking success
+ p1 = (int(bbox[0]), int(bbox[1]))
+ p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3]))
+ cv2.rectangle(frame, p1, p2, (255, 0, 0), 2, 1)
+ else:
+ # Tracking failure
+ cv2.putText(frame, "Tracking failure detected", (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2)
+
+ # Display tracker type on frame
+ cv2.putText(frame, tracker_type + " Tracker", (100, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50, 170, 50), 2);
+
+ # Display FPS on frame
+ cv2.putText(frame, "FPS : " + str(int(fps)), (100, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (50, 170, 50), 2);
- fps = cv2.getTickFrequency() / (cv2.getTickCount() - timer)
- cv2.putText(img, str(int(fps)), (75, 50), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
- cv2.imshow("Tracking", img)
+ # Display result
+ cv2.imshow("Tracking", frame)
- if cv2.waitKey(1) & 0xff == ord('q'):
- break \ No newline at end of file
+ # Exit if ESC pressed
+ k = cv2.waitKey(1) & 0xff
+ if k == 27: break
diff --git a/cv/tracker/video.avi b/cv/tracker/video.avi
new file mode 100644
index 0000000..2006145
--- /dev/null
+++ b/cv/tracker/video.avi
Binary files differ
diff --git a/learn_torch/seq/basic_rnn.py b/learn_torch/seq/basic_rnn.py
new file mode 100644
index 0000000..a2db2af
--- /dev/null
+++ b/learn_torch/seq/basic_rnn.py
@@ -0,0 +1,43 @@
+import torch
+from torch import nn
+
+
+def t1():
+ rnn = nn.RNN(10, 20, 2)
+ input = torch.randn(5, 3, 10)
+ h0 = torch.randn(2, 3, 20)
+ output, hn = rnn(input, h0)
+ print()
+
+def t2():
+ data = torch.Tensor([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
+ print("Data: ", data.shape, "\n\n", data)
+ ###################### OUTPUT ######################
+
+
+ # Number of features used as input. (Number of columns)
+ INPUT_SIZE = 1
+ # Number of previous time stamps taken into account.
+ SEQ_LENGTH = 5
+ # Number of features in last hidden state ie. number of output time-
+ # steps to predict.See image below for more clarity.
+ HIDDEN_SIZE = 2
+ # Number of stacked rnn layers.
+ NUM_LAYERS = 1
+ # We have total of 20 rows in our input.
+ # We divide the input into 4 batches where each batch has only 1
+ # row. Each row corresponds to a sequence of length 5.
+ BATCH_SIZE = 4
+
+ # Initialize the RNN.
+ rnn = nn.RNN(input_size=INPUT_SIZE, hidden_size=HIDDEN_SIZE, num_layers = 1, batch_first=True)
+ # input size : (batch, seq_len, input_size)
+ inputs = data.view(BATCH_SIZE, SEQ_LENGTH, INPUT_SIZE)
+ # out shape = (batch, seq_len, num_directions * hidden_size)
+ # h_n shape = (num_layers * num_directions, batch, hidden_size)
+ out, h_n = rnn(inputs)
+
+
+if __name__ == '__main__':
+ nn.Linear
+ t1()
diff --git a/learn_torch/seq/sentiment_analysis.py b/learn_torch/seq/sentiment_analysis.py
new file mode 100644
index 0000000..8971e31
--- /dev/null
+++ b/learn_torch/seq/sentiment_analysis.py
@@ -0,0 +1,193 @@
+import torch
+from torchtext.legacy import data
+from torchtext.legacy import datasets
+import random
+import torch.nn as nn
+import time
+
+SEED = 1234
+
+torch.manual_seed(SEED)
+torch.backends.cudnn.deterministic = True
+
+TEXT = data.Field(tokenize='spacy',
+ tokenizer_language='en_core_web_sm')
+LABEL = data.LabelField(dtype=torch.float)
+
+
+train_data, test_data = datasets.IMDB.splits(TEXT, LABEL)
+
+print(f'Number of training examples: {len(train_data)}')
+print(f'Number of testing examples: {len(test_data)}')
+
+print(vars(train_data.examples[0]))
+
+train_data, valid_data = train_data.split(random_state = random.seed(SEED))
+
+print(f'Number of training examples: {len(train_data)}')
+print(f'Number of validation examples: {len(valid_data)}')
+print(f'Number of testing examples: {len(test_data)}')
+
+MAX_VOCAB_SIZE = 25_000
+
+TEXT.build_vocab(train_data, max_size = MAX_VOCAB_SIZE)
+LABEL.build_vocab(train_data)
+
+print(f"Unique tokens in TEXT vocabulary: {len(TEXT.vocab)}")
+print(f"Unique tokens in LABEL vocabulary: {len(LABEL.vocab)}")
+
+print(TEXT.vocab.freqs.most_common(20))
+
+print(TEXT.vocab.itos[:10])
+print(LABEL.vocab.stoi)
+
+BATCH_SIZE = 64
+
+device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
+
+train_iterator, valid_iterator, test_iterator = data.BucketIterator.splits(
+ (train_data, valid_data, test_data),
+ batch_size = BATCH_SIZE,
+ device = device)
+
+
+class RNN(nn.Module):
+ def __init__(self, input_dim, embedding_dim, hidden_dim, output_dim):
+ super().__init__()
+
+ self.embedding = nn.Embedding(input_dim, embedding_dim)
+
+ self.rnn = nn.RNN(embedding_dim, hidden_dim)
+
+ self.fc = nn.Linear(hidden_dim, output_dim)
+
+ def forward(self, text):
+ # text = [sent len, batch size]
+
+ embedded = self.embedding(text)
+
+ # embedded = [sent len, batch size, emb dim]
+
+ output, hidden = self.rnn(embedded)
+
+ # output = [sent len, batch size, hid dim]
+ # hidden = [1, batch size, hid dim]
+
+ assert torch.equal(output[-1, :, :], hidden.squeeze(0))
+
+ return self.fc(hidden.squeeze(0))
+
+INPUT_DIM = len(TEXT.vocab)
+EMBEDDING_DIM = 100
+HIDDEN_DIM = 256
+OUTPUT_DIM = 1
+
+model = RNN(INPUT_DIM, EMBEDDING_DIM, HIDDEN_DIM, OUTPUT_DIM)
+
+def count_parameters(model):
+ return sum(p.numel() for p in model.parameters() if p.requires_grad)
+
+print(f'The model has {count_parameters(model):,} trainable parameters')
+
+
+import torch.optim as optim
+
+optimizer = optim.SGD(model.parameters(), lr=1e-3)
+criterion = nn.BCEWithLogitsLoss()
+
+model = model.to(device)
+criterion = criterion.to(device)
+
+def binary_accuracy(preds, y):
+ """
+ Returns accuracy per batch, i.e. if you get 8/10 right, this returns 0.8, NOT 8
+ """
+
+ #round predictions to the closest integer
+ rounded_preds = torch.round(torch.sigmoid(preds))
+ correct = (rounded_preds == y).float() #convert into float for division
+ acc = correct.sum() / len(correct)
+ return acc
+
+
+def train(model, iterator, optimizer, criterion):
+ epoch_loss = 0
+ epoch_acc = 0
+
+ model.train()
+
+ for batch in iterator:
+ optimizer.zero_grad()
+
+ predictions = model(batch.text).squeeze(1)
+
+ loss = criterion(predictions, batch.label)
+
+ acc = binary_accuracy(predictions, batch.label)
+
+ loss.backward()
+
+ optimizer.step()
+
+ epoch_loss += loss.item()
+ epoch_acc += acc.item()
+
+ return epoch_loss / len(iterator), epoch_acc / len(iterator)
+
+
+def evaluate(model, iterator, criterion):
+ epoch_loss = 0
+ epoch_acc = 0
+
+ model.eval()
+
+ with torch.no_grad():
+ for batch in iterator:
+ predictions = model(batch.text).squeeze(1)
+
+ loss = criterion(predictions, batch.label)
+
+ acc = binary_accuracy(predictions, batch.label)
+
+ epoch_loss += loss.item()
+ epoch_acc += acc.item()
+
+ return epoch_loss / len(iterator), epoch_acc / len(iterator)
+
+
+def epoch_time(start_time, end_time):
+ elapsed_time = end_time - start_time
+ elapsed_mins = int(elapsed_time / 60)
+ elapsed_secs = int(elapsed_time - (elapsed_mins * 60))
+ return elapsed_mins, elapsed_secs
+
+
+N_EPOCHS = 5
+
+best_valid_loss = float('inf')
+
+for epoch in range(N_EPOCHS):
+
+ start_time = time.time()
+
+ train_loss, train_acc = train(model, train_iterator, optimizer, criterion)
+ valid_loss, valid_acc = evaluate(model, valid_iterator, criterion)
+
+ end_time = time.time()
+
+ epoch_mins, epoch_secs = epoch_time(start_time, end_time)
+
+ if valid_loss < best_valid_loss:
+ best_valid_loss = valid_loss
+ torch.save(model.state_dict(), 'tut1-model.pt')
+
+ print(f'Epoch: {epoch+1:02} | Epoch Time: {epoch_mins}m {epoch_secs}s')
+ print(f'\tTrain Loss: {train_loss:.3f} | Train Acc: {train_acc*100:.2f}%')
+ print(f'\t Val. Loss: {valid_loss:.3f} | Val. Acc: {valid_acc*100:.2f}%')
+
+
+model.load_state_dict(torch.load('tut1-model.pt'))
+
+test_loss, test_acc = evaluate(model, test_iterator, criterion)
+
+print(f'Test Loss: {test_loss:.3f} | Test Acc: {test_acc*100:.2f}%') \ No newline at end of file
diff --git a/learn_torch/seq/test_rnn.py b/learn_torch/seq/test_rnn.py
new file mode 100644
index 0000000..5a7baf2
--- /dev/null
+++ b/learn_torch/seq/test_rnn.py
@@ -0,0 +1,8 @@
+import torch
+from torch import nn
+
+if __name__ == '__main__':
+ rnn = nn.RNN(10, 20, 2)
+ input = torch.randn(5, 3, 10)
+ h0 = torch.randn(2, 3, 10)
+ rnn(input, h0)
diff --git a/pose/1.mp4 b/pose/1.mp4
new file mode 100644
index 0000000..7435e06
--- /dev/null
+++ b/pose/1.mp4
Binary files differ
diff --git a/pose/4.jpg b/pose/4.jpg
new file mode 100644
index 0000000..04f7515
--- /dev/null
+++ b/pose/4.jpg
Binary files differ
diff --git a/pose/PoseEstimation.py b/pose/PoseEstimation.py
new file mode 100644
index 0000000..cdd594a
--- /dev/null
+++ b/pose/PoseEstimation.py
@@ -0,0 +1,64 @@
+# Created by MediaPipe
+# Modified by Augmented Startups 2021
+# Pose-Estimation in 5 Minutes
+# Watch 5 Minute Tutorial at www.augmentedstartups.info/YouTube
+import cv2
+import mediapipe as mp
+import time
+import os
+
+mp_drawing = mp.solutions.drawing_utils
+mp_pose = mp.solutions.pose
+mp_holistic = mp.solutions.holistic
+
+# For static images:
+with mp_pose.Pose(
+ static_image_mode=True,
+ # model_complexity=2,
+ min_detection_confidence=0.5) as pose:
+ image = cv2.imread('4.jpg') # Insert your Image Here
+ image_height, image_width, _ = image.shape
+ # Convert the BGR image to RGB before processing.
+ results = pose.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
+ # Draw pose landmarks on the image.
+ annotated_image = image.copy()
+ mp_drawing.draw_landmarks(annotated_image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
+ cv2.imwrite(r'4.png', annotated_image)
+
+# For webcam input:
+# cap = cv2.VideoCapture(0)
+cap = cv2.VideoCapture("1.mp4")
+# For Video input:
+prevTime = 0
+with mp_pose.Pose(
+ min_detection_confidence=0.5,
+ min_tracking_confidence=0.5) as pose:
+ while cap.isOpened():
+ success, image = cap.read()
+ if not success:
+ print("Ignoring empty camera frame.")
+ # If loading a video, use 'break' instead of 'continue'.
+ continue
+
+ # Convert the BGR image to RGB.
+ image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
+ # To improve performance, optionally mark the image as not writeable to
+ # pass by reference.
+ image.flags.writeable = False
+ results = pose.process(image)
+
+ # Draw the pose annotation on the image.
+ image.flags.writeable = True
+ image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
+ mp_drawing.draw_landmarks(
+ image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
+ currTime = time.time()
+ fps = 1 / (currTime - prevTime)
+ prevTime = currTime
+ cv2.putText(image, f'FPS: {int(fps)}', (20, 70), cv2.FONT_HERSHEY_PLAIN, 3, (0, 196, 255), 2)
+ cv2.imshow('BlazePose', image)
+ if cv2.waitKey(5) & 0xFF == 27:
+ break
+cap.release()
+# Learn more AI in Computer Vision by Enrolling in our AI_CV Nano Degree:
+# https://bit.ly/AugmentedAICVPRO
diff --git a/pretrained/swin/demo.py b/pretrained/swin/demo.py
new file mode 100644
index 0000000..6f8d87b
--- /dev/null
+++ b/pretrained/swin/demo.py
@@ -0,0 +1,36 @@
+import timm
+import torch
+import torchvision
+from PIL import Image
+from torchvision import transforms as T
+import json
+
+if __name__ == '__main__':
+ trans_ = T.Compose(
+ [
+ T.Resize(256),
+ T.CenterCrop(224),
+ T.ToTensor(),
+ T.Normalize(timm.data.IMAGENET_DEFAULT_MEAN, timm.data.IMAGENET_DEFAULT_STD)]
+ )
+
+ image = Image.open('./house_finch.jpg')
+ transformed = trans_(image)
+ print(transformed.shape)
+ batch_input = transformed.unsqueeze(0)
+ print(batch_input.shape)
+
+ model = timm.create_model('swin_base_patch4_window7_224', pretrained=True)
+
+ with torch.no_grad():
+ output = model(batch_input)
+
+ print(output)
+ print(output.shape)
+ labels = json.load(open('./imagenet_labels.json'))
+ class_ = output.argmax(dim=1)
+ print(class_)
+ print(class_.data)
+ print(output.sum(dim=1))
+ print(labels[class_])
+
diff --git a/pretrained/swin/house_finch.jpg b/pretrained/swin/house_finch.jpg
new file mode 100644
index 0000000..b3b92df
--- /dev/null
+++ b/pretrained/swin/house_finch.jpg
Binary files differ
diff --git a/pretrained/swin/imagenet_labels.json b/pretrained/swin/imagenet_labels.json
new file mode 100644
index 0000000..28fce58
--- /dev/null
+++ b/pretrained/swin/imagenet_labels.json
@@ -0,0 +1,1000 @@
+["tench",
+"goldfish",
+"great white shark",
+"tiger shark",
+"hammerhead shark",
+"electric ray",
+"stingray",
+"cock",
+"hen",
+"ostrich",
+"brambling",
+"goldfinch",
+"house finch",
+"junco",
+"indigo bunting",
+"American robin",
+"bulbul",
+"jay",
+"magpie",
+"chickadee",
+"American dipper",
+"kite",
+"bald eagle",
+"vulture",
+"great grey owl",
+"fire salamander",
+"smooth newt",
+"newt",
+"spotted salamander",
+"axolotl",
+"American bullfrog",
+"tree frog",
+"tailed frog",
+"loggerhead sea turtle",
+"leatherback sea turtle",
+"mud turtle",
+"terrapin",
+"box turtle",
+"banded gecko",
+"green iguana",
+"Carolina anole",
+"desert grassland whiptail lizard",
+"agama",
+"frilled-necked lizard",
+"alligator lizard",
+"Gila monster",
+"European green lizard",
+"chameleon",
+"Komodo dragon",
+"Nile crocodile",
+"American alligator",
+"triceratops",
+"worm snake",
+"ring-necked snake",
+"eastern hog-nosed snake",
+"smooth green snake",
+"kingsnake",
+"garter snake",
+"water snake",
+"vine snake",
+"night snake",
+"boa constrictor",
+"African rock python",
+"Indian cobra",
+"green mamba",
+"sea snake",
+"Saharan horned viper",
+"eastern diamondback rattlesnake",
+"sidewinder",
+"trilobite",
+"harvestman",
+"scorpion",
+"yellow garden spider",
+"barn spider",
+"European garden spider",
+"southern black widow",
+"tarantula",
+"wolf spider",
+"tick",
+"centipede",
+"black grouse",
+"ptarmigan",
+"ruffed grouse",
+"prairie grouse",
+"peacock",
+"quail",
+"partridge",
+"grey parrot",
+"macaw",
+"sulphur-crested cockatoo",
+"lorikeet",
+"coucal",
+"bee eater",
+"hornbill",
+"hummingbird",
+"jacamar",
+"toucan",
+"duck",
+"red-breasted merganser",
+"goose",
+"black swan",
+"tusker",
+"echidna",
+"platypus",
+"wallaby",
+"koala",
+"wombat",
+"jellyfish",
+"sea anemone",
+"brain coral",
+"flatworm",
+"nematode",
+"conch",
+"snail",
+"slug",
+"sea slug",
+"chiton",
+"chambered nautilus",
+"Dungeness crab",
+"rock crab",
+"fiddler crab",
+"red king crab",
+"American lobster",
+"spiny lobster",
+"crayfish",
+"hermit crab",
+"isopod",
+"white stork",
+"black stork",
+"spoonbill",
+"flamingo",
+"little blue heron",
+"great egret",
+"bittern",
+"crane (bird)",
+"limpkin",
+"common gallinule",
+"American coot",
+"bustard",
+"ruddy turnstone",
+"dunlin",
+"common redshank",
+"dowitcher",
+"oystercatcher",
+"pelican",
+"king penguin",
+"albatross",
+"grey whale",
+"killer whale",
+"dugong",
+"sea lion",
+"Chihuahua",
+"Japanese Chin",
+"Maltese",
+"Pekingese",
+"Shih Tzu",
+"King Charles Spaniel",
+"Papillon",
+"toy terrier",
+"Rhodesian Ridgeback",
+"Afghan Hound",
+"Basset Hound",
+"Beagle",
+"Bloodhound",
+"Bluetick Coonhound",
+"Black and Tan Coonhound",
+"Treeing Walker Coonhound",
+"English foxhound",
+"Redbone Coonhound",
+"borzoi",
+"Irish Wolfhound",
+"Italian Greyhound",
+"Whippet",
+"Ibizan Hound",
+"Norwegian Elkhound",
+"Otterhound",
+"Saluki",
+"Scottish Deerhound",
+"Weimaraner",
+"Staffordshire Bull Terrier",
+"American Staffordshire Terrier",
+"Bedlington Terrier",
+"Border Terrier",
+"Kerry Blue Terrier",
+"Irish Terrier",
+"Norfolk Terrier",
+"Norwich Terrier",
+"Yorkshire Terrier",
+"Wire Fox Terrier",
+"Lakeland Terrier",
+"Sealyham Terrier",
+"Airedale Terrier",
+"Cairn Terrier",
+"Australian Terrier",
+"Dandie Dinmont Terrier",
+"Boston Terrier",
+"Miniature Schnauzer",
+"Giant Schnauzer",
+"Standard Schnauzer",
+"Scottish Terrier",
+"Tibetan Terrier",
+"Australian Silky Terrier",
+"Soft-coated Wheaten Terrier",
+"West Highland White Terrier",
+"Lhasa Apso",
+"Flat-Coated Retriever",
+"Curly-coated Retriever",
+"Golden Retriever",
+"Labrador Retriever",
+"Chesapeake Bay Retriever",
+"German Shorthaired Pointer",
+"Vizsla",
+"English Setter",
+"Irish Setter",
+"Gordon Setter",
+"Brittany",
+"Clumber Spaniel",
+"English Springer Spaniel",
+"Welsh Springer Spaniel",
+"Cocker Spaniels",
+"Sussex Spaniel",
+"Irish Water Spaniel",
+"Kuvasz",
+"Schipperke",
+"Groenendael",
+"Malinois",
+"Briard",
+"Australian Kelpie",
+"Komondor",
+"Old English Sheepdog",
+"Shetland Sheepdog",
+"collie",
+"Border Collie",
+"Bouvier des Flandres",
+"Rottweiler",
+"German Shepherd Dog",
+"Dobermann",
+"Miniature Pinscher",
+"Greater Swiss Mountain Dog",
+"Bernese Mountain Dog",
+"Appenzeller Sennenhund",
+"Entlebucher Sennenhund",
+"Boxer",
+"Bullmastiff",
+"Tibetan Mastiff",
+"French Bulldog",
+"Great Dane",
+"St. Bernard",
+"husky",
+"Alaskan Malamute",
+"Siberian Husky",
+"Dalmatian",
+"Affenpinscher",
+"Basenji",
+"pug",
+"Leonberger",
+"Newfoundland",
+"Pyrenean Mountain Dog",
+"Samoyed",
+"Pomeranian",
+"Chow Chow",
+"Keeshond",
+"Griffon Bruxellois",
+"Pembroke Welsh Corgi",
+"Cardigan Welsh Corgi",
+"Toy Poodle",
+"Miniature Poodle",
+"Standard Poodle",
+"Mexican hairless dog",
+"grey wolf",
+"Alaskan tundra wolf",
+"red wolf",
+"coyote",
+"dingo",
+"dhole",
+"African wild dog",
+"hyena",
+"red fox",
+"kit fox",
+"Arctic fox",
+"grey fox",
+"tabby cat",
+"tiger cat",
+"Persian cat",
+"Siamese cat",
+"Egyptian Mau",
+"cougar",
+"lynx",
+"leopard",
+"snow leopard",
+"jaguar",
+"lion",
+"tiger",
+"cheetah",
+"brown bear",
+"American black bear",
+"polar bear",
+"sloth bear",
+"mongoose",
+"meerkat",
+"tiger beetle",
+"ladybug",
+"ground beetle",
+"longhorn beetle",
+"leaf beetle",
+"dung beetle",
+"rhinoceros beetle",
+"weevil",
+"fly",
+"bee",
+"ant",
+"grasshopper",
+"cricket",
+"stick insect",
+"cockroach",
+"mantis",
+"cicada",
+"leafhopper",
+"lacewing",
+"dragonfly",
+"damselfly",
+"red admiral",
+"ringlet",
+"monarch butterfly",
+"small white",
+"sulphur butterfly",
+"gossamer-winged butterfly",
+"starfish",
+"sea urchin",
+"sea cucumber",
+"cottontail rabbit",
+"hare",
+"Angora rabbit",
+"hamster",
+"porcupine",
+"fox squirrel",
+"marmot",
+"beaver",
+"guinea pig",
+"common sorrel",
+"zebra",
+"pig",
+"wild boar",
+"warthog",
+"hippopotamus",
+"ox",
+"water buffalo",
+"bison",
+"ram",
+"bighorn sheep",
+"Alpine ibex",
+"hartebeest",
+"impala",
+"gazelle",
+"dromedary",
+"llama",
+"weasel",
+"mink",
+"European polecat",
+"black-footed ferret",
+"otter",
+"skunk",
+"badger",
+"armadillo",
+"three-toed sloth",
+"orangutan",
+"gorilla",
+"chimpanzee",
+"gibbon",
+"siamang",
+"guenon",
+"patas monkey",
+"baboon",
+"macaque",
+"langur",
+"black-and-white colobus",
+"proboscis monkey",
+"marmoset",
+"white-headed capuchin",
+"howler monkey",
+"titi",
+"Geoffroy's spider monkey",
+"common squirrel monkey",
+"ring-tailed lemur",
+"indri",
+"Asian elephant",
+"African bush elephant",
+"red panda",
+"giant panda",
+"snoek",
+"eel",
+"coho salmon",
+"rock beauty",
+"clownfish",
+"sturgeon",
+"garfish",
+"lionfish",
+"pufferfish",
+"abacus",
+"abaya",
+"academic gown",
+"accordion",
+"acoustic guitar",
+"aircraft carrier",
+"airliner",
+"airship",
+"altar",
+"ambulance",
+"amphibious vehicle",
+"analog clock",
+"apiary",
+"apron",
+"waste container",
+"assault rifle",
+"backpack",
+"bakery",
+"balance beam",
+"balloon",
+"ballpoint pen",
+"Band-Aid",
+"banjo",
+"baluster",
+"barbell",
+"barber chair",
+"barbershop",
+"barn",
+"barometer",
+"barrel",
+"wheelbarrow",
+"baseball",
+"basketball",
+"bassinet",
+"bassoon",
+"swimming cap",
+"bath towel",
+"bathtub",
+"station wagon",
+"lighthouse",
+"beaker",
+"military cap",
+"beer bottle",
+"beer glass",
+"bell-cot",
+"bib",
+"tandem bicycle",
+"bikini",
+"ring binder",
+"binoculars",
+"birdhouse",
+"boathouse",
+"bobsleigh",
+"bolo tie",
+"poke bonnet",
+"bookcase",
+"bookstore",
+"bottle cap",
+"bow",
+"bow tie",
+"brass",
+"bra",
+"breakwater",
+"breastplate",
+"broom",
+"bucket",
+"buckle",
+"bulletproof vest",
+"high-speed train",
+"butcher shop",
+"taxicab",
+"cauldron",
+"candle",
+"cannon",
+"canoe",
+"can opener",
+"cardigan",
+"car mirror",
+"carousel",
+"tool kit",
+"carton",
+"car wheel",
+"automated teller machine",
+"cassette",
+"cassette player",
+"castle",
+"catamaran",
+"CD player",
+"cello",
+"mobile phone",
+"chain",
+"chain-link fence",
+"chain mail",
+"chainsaw",
+"chest",
+"chiffonier",
+"chime",
+"china cabinet",
+"Christmas stocking",
+"church",
+"movie theater",
+"cleaver",
+"cliff dwelling",
+"cloak",
+"clogs",
+"cocktail shaker",
+"coffee mug",
+"coffeemaker",
+"coil",
+"combination lock",
+"computer keyboard",
+"confectionery store",
+"container ship",
+"convertible",
+"corkscrew",
+"cornet",
+"cowboy boot",
+"cowboy hat",
+"cradle",
+"crane (machine)",
+"crash helmet",
+"crate",
+"infant bed",
+"Crock Pot",
+"croquet ball",
+"crutch",
+"cuirass",
+"dam",
+"desk",
+"desktop computer",
+"rotary dial telephone",
+"diaper",
+"digital clock",
+"digital watch",
+"dining table",
+"dishcloth",
+"dishwasher",
+"disc brake",
+"dock",
+"dog sled",
+"dome",
+"doormat",
+"drilling rig",
+"drum",
+"drumstick",
+"dumbbell",
+"Dutch oven",
+"electric fan",
+"electric guitar",
+"electric locomotive",
+"entertainment center",
+"envelope",
+"espresso machine",
+"face powder",
+"feather boa",
+"filing cabinet",
+"fireboat",
+"fire engine",
+"fire screen sheet",
+"flagpole",
+"flute",
+"folding chair",
+"football helmet",
+"forklift",
+"fountain",
+"fountain pen",
+"four-poster bed",
+"freight car",
+"French horn",
+"frying pan",
+"fur coat",
+"garbage truck",
+"gas mask",
+"gas pump",
+"goblet",
+"go-kart",
+"golf ball",
+"golf cart",
+"gondola",
+"gong",
+"gown",
+"grand piano",
+"greenhouse",
+"grille",
+"grocery store",
+"guillotine",
+"barrette",
+"hair spray",
+"half-track",
+"hammer",
+"hamper",
+"hair dryer",
+"hand-held computer",
+"handkerchief",
+"hard disk drive",
+"harmonica",
+"harp",
+"harvester",
+"hatchet",
+"holster",
+"home theater",
+"honeycomb",
+"hook",
+"hoop skirt",
+"horizontal bar",
+"horse-drawn vehicle",
+"hourglass",
+"iPod",
+"clothes iron",
+"jack-o'-lantern",
+"jeans",
+"jeep",
+"T-shirt",
+"jigsaw puzzle",
+"pulled rickshaw",
+"joystick",
+"kimono",
+"knee pad",
+"knot",
+"lab coat",
+"ladle",
+"lampshade",
+"laptop computer",
+"lawn mower",
+"lens cap",
+"paper knife",
+"library",
+"lifeboat",
+"lighter",
+"limousine",
+"ocean liner",
+"lipstick",
+"slip-on shoe",
+"lotion",
+"speaker",
+"loupe",
+"sawmill",
+"magnetic compass",
+"mail bag",
+"mailbox",
+"tights",
+"tank suit",
+"manhole cover",
+"maraca",
+"marimba",
+"mask",
+"match",
+"maypole",
+"maze",
+"measuring cup",
+"medicine chest",
+"megalith",
+"microphone",
+"microwave oven",
+"military uniform",
+"milk can",
+"minibus",
+"miniskirt",
+"minivan",
+"missile",
+"mitten",
+"mixing bowl",
+"mobile home",
+"Model T",
+"modem",
+"monastery",
+"monitor",
+"moped",
+"mortar",
+"square academic cap",
+"mosque",
+"mosquito net",
+"scooter",
+"mountain bike",
+"tent",
+"computer mouse",
+"mousetrap",
+"moving van",
+"muzzle",
+"nail",
+"neck brace",
+"necklace",
+"nipple",
+"notebook computer",
+"obelisk",
+"oboe",
+"ocarina",
+"odometer",
+"oil filter",
+"organ",
+"oscilloscope",
+"overskirt",
+"bullock cart",
+"oxygen mask",
+"packet",
+"paddle",
+"paddle wheel",
+"padlock",
+"paintbrush",
+"pajamas",
+"palace",
+"pan flute",
+"paper towel",
+"parachute",
+"parallel bars",
+"park bench",
+"parking meter",
+"passenger car",
+"patio",
+"payphone",
+"pedestal",
+"pencil case",
+"pencil sharpener",
+"perfume",
+"Petri dish",
+"photocopier",
+"plectrum",
+"Pickelhaube",
+"picket fence",
+"pickup truck",
+"pier",
+"piggy bank",
+"pill bottle",
+"pillow",
+"ping-pong ball",
+"pinwheel",
+"pirate ship",
+"pitcher",
+"hand plane",
+"planetarium",
+"plastic bag",
+"plate rack",
+"plow",
+"plunger",
+"Polaroid camera",
+"pole",
+"police van",
+"poncho",
+"billiard table",
+"soda bottle",
+"pot",
+"potter's wheel",
+"power drill",
+"prayer rug",
+"printer",
+"prison",
+"projectile",
+"projector",
+"hockey puck",
+"punching bag",
+"purse",
+"quill",
+"quilt",
+"race car",
+"racket",
+"radiator",
+"radio",
+"radio telescope",
+"rain barrel",
+"recreational vehicle",
+"reel",
+"reflex camera",
+"refrigerator",
+"remote control",
+"restaurant",
+"revolver",
+"rifle",
+"rocking chair",
+"rotisserie",
+"eraser",
+"rugby ball",
+"ruler",
+"running shoe",
+"safe",
+"safety pin",
+"salt shaker",
+"sandal",
+"sarong",
+"saxophone",
+"scabbard",
+"weighing scale",
+"school bus",
+"schooner",
+"scoreboard",
+"CRT screen",
+"screw",
+"screwdriver",
+"seat belt",
+"sewing machine",
+"shield",
+"shoe store",
+"shoji",
+"shopping basket",
+"shopping cart",
+"shovel",
+"shower cap",
+"shower curtain",
+"ski",
+"ski mask",
+"sleeping bag",
+"slide rule",
+"sliding door",
+"slot machine",
+"snorkel",
+"snowmobile",
+"snowplow",
+"soap dispenser",
+"soccer ball",
+"sock",
+"solar thermal collector",
+"sombrero",
+"soup bowl",
+"space bar",
+"space heater",
+"space shuttle",
+"spatula",
+"motorboat",
+"spider web",
+"spindle",
+"sports car",
+"spotlight",
+"stage",
+"steam locomotive",
+"through arch bridge",
+"steel drum",
+"stethoscope",
+"scarf",
+"stone wall",
+"stopwatch",
+"stove",
+"strainer",
+"tram",
+"stretcher",
+"couch",
+"stupa",
+"submarine",
+"suit",
+"sundial",
+"sunglass",
+"sunglasses",
+"sunscreen",
+"suspension bridge",
+"mop",
+"sweatshirt",
+"swimsuit",
+"swing",
+"switch",
+"syringe",
+"table lamp",
+"tank",
+"tape player",
+"teapot",
+"teddy bear",
+"television",
+"tennis ball",
+"thatched roof",
+"front curtain",
+"thimble",
+"threshing machine",
+"throne",
+"tile roof",
+"toaster",
+"tobacco shop",
+"toilet seat",
+"torch",
+"totem pole",
+"tow truck",
+"toy store",
+"tractor",
+"semi-trailer truck",
+"tray",
+"trench coat",
+"tricycle",
+"trimaran",
+"tripod",
+"triumphal arch",
+"trolleybus",
+"trombone",
+"tub",
+"turnstile",
+"typewriter keyboard",
+"umbrella",
+"unicycle",
+"upright piano",
+"vacuum cleaner",
+"vase",
+"vault",
+"velvet",
+"vending machine",
+"vestment",
+"viaduct",
+"violin",
+"volleyball",
+"waffle iron",
+"wall clock",
+"wallet",
+"wardrobe",
+"military aircraft",
+"sink",
+"washing machine",
+"water bottle",
+"water jug",
+"water tower",
+"whiskey jug",
+"whistle",
+"wig",
+"window screen",
+"window shade",
+"Windsor tie",
+"wine bottle",
+"wing",
+"wok",
+"wooden spoon",
+"wool",
+"split-rail fence",
+"shipwreck",
+"yawl",
+"yurt",
+"website",
+"comic book",
+"crossword",
+"traffic sign",
+"traffic light",
+"dust jacket",
+"menu",
+"plate",
+"guacamole",
+"consomme",
+"hot pot",
+"trifle",
+"ice cream",
+"ice pop",
+"baguette",
+"bagel",
+"pretzel",
+"cheeseburger",
+"hot dog",
+"mashed potato",
+"cabbage",
+"broccoli",
+"cauliflower",
+"zucchini",
+"spaghetti squash",
+"acorn squash",
+"butternut squash",
+"cucumber",
+"artichoke",
+"bell pepper",
+"cardoon",
+"mushroom",
+"Granny Smith",
+"strawberry",
+"orange",
+"lemon",
+"fig",
+"pineapple",
+"banana",
+"jackfruit",
+"custard apple",
+"pomegranate",
+"hay",
+"carbonara",
+"chocolate syrup",
+"dough",
+"meatloaf",
+"pizza",
+"pot pie",
+"burrito",
+"red wine",
+"espresso",
+"cup",
+"eggnog",
+"alp",
+"bubble",
+"cliff",
+"coral reef",
+"geyser",
+"lakeshore",
+"promontory",
+"shoal",
+"seashore",
+"valley",
+"volcano",
+"baseball player",
+"bridegroom",
+"scuba diver",
+"rapeseed",
+"daisy",
+"yellow lady's slipper",
+"corn",
+"acorn",
+"rose hip",
+"horse chestnut seed",
+"coral fungus",
+"agaric",
+"gyromitra",
+"stinkhorn mushroom",
+"earth star",
+"hen-of-the-woods",
+"bolete",
+"ear",
+"toilet paper"] \ No newline at end of file
diff --git a/rl/gym_demo/hello.py b/rl/gym_demo/hello.py
new file mode 100644
index 0000000..766d2b3
--- /dev/null
+++ b/rl/gym_demo/hello.py
@@ -0,0 +1,10 @@
+
+import gym
+# 创建一个小车倒立摆模型
+env = gym.make('CartPole-v0')
+# 初始化环境
+env.reset()
+# 刷新当前环境,并显示
+for _ in range(1000):
+ env.render()
+ env.step(env.action_space.sample()) # take a random action \ No newline at end of file
diff --git a/web/Tower of Hanoi Animation by Y. Daniel Liang.html b/web/Tower of Hanoi Animation by Y. Daniel Liang.html
new file mode 100644
index 0000000..3014467
--- /dev/null
+++ b/web/Tower of Hanoi Animation by Y. Daniel Liang.html
@@ -0,0 +1,762 @@
+<!DOCTYPE html>
+<!-- saved from url=(0065)https://yongdanielliang.github.io/animation/web/TowerOfHanoi.html -->
+<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>Tower of Hanoi Animation by Y. Daniel Liang</title>
+
+
+ <link rel="stylesheet" href="./Tower of Hanoi Animation by Y. Daniel Liang_files/jquery-ui.css">
+ <script type="text/javascript" async="" src="./Tower of Hanoi Animation by Y. Daniel Liang_files/analytics.js"></script><script src="./Tower of Hanoi Animation by Y. Daniel Liang_files/jquery-latest.js"></script>
+<!-- <script src="jquery-1.10.2.js"></script>-->
+ <script src="./Tower of Hanoi Animation by Y. Daniel Liang_files/jquery-ui.js"></script>
+ <script type="text/javascript" src="./Tower of Hanoi Animation by Y. Daniel Liang_files/GetElementPosition.js"></script>
+ <link rel="stylesheet" type="text/css" href="./Tower of Hanoi Animation by Y. Daniel Liang_files/codecolor.css">
+ <link rel="stylesheet" type="text/css" href="./Tower of Hanoi Animation by Y. Daniel Liang_files/boxes.css">
+ <script src="./Tower of Hanoi Animation by Y. Daniel Liang_files/LinkedList.js"></script>
+ <script src="./Tower of Hanoi Animation by Y. Daniel Liang_files/Queue.js"></script>
+
+ <style>
+ .status {
+ color: chocolate;
+ }
+
+ .vbar {
+ background-color: chocolate;
+ /* opacity: 0.25;*/
+ position: absolute;
+ width: 3px;
+ height: 130px;
+ padding: 3px;
+ margin-top: 0px;
+ top: 89px;
+ left: 152px;
+ }
+
+ .hbar {
+ background-color: chocolate;
+ /* opacity: 0.25;*/
+ position: absolute;
+ width: 150px;
+ height: 3px;
+ padding: 3px;
+ margin-top: 0px;
+ top: 219px;
+ left: 50px;
+ }
+
+ .towerText {
+ position: absolute;
+ color: black;
+ font-family: monospace;
+ font-size: 14px;
+ font-weight: bold;
+ }
+
+ .disc {
+ position: absolute;
+ color: #EB0D1B;
+ font-family: monospace;
+ font-size: 14px;
+ font-weight: bold;
+ border: 1px solid black;
+ height: 20px;
+ width: 50px;
+ }
+
+ #highlight {
+ background-color:#37826C;
+ opacity: 0.25;
+ position:absolute;
+ width:318px;
+ height: 10px;
+ padding: 3px;
+ margin-top: 0px;
+ top: 89px;
+ left: 72px;
+ }
+
+ #explanation {
+ color: purple;
+ position:absolute;
+ width: 158px;
+ height: 40px;
+ padding: 3px;
+ margin-top:5px;
+ top: 75px;
+ left: 448px;
+ font-size: 90%;
+ font-family: Times New Roman;
+ }
+
+ #commandPrompt {
+ font-family: times; border: 0px solid gray; text-align: left;
+ position:absolute;
+ width: 217.515px;
+ height: 10px;
+ top: 90px;
+ left: 600px;
+ font-size: 80%;
+ }
+
+ #commandPromptHeader {
+ background-color: navy; color: white; font-size: 90%;
+ border-bottom: 0px solid gray; border-right: 0px solid gray;
+ text-align: center;
+ }
+
+ #commandPromptContent {
+ background-color: white;
+ color: black;
+ width: 212px;
+ height: 40px;
+ font-family: courier;
+ font-size: 80%;
+ font-weight: bold;
+ }
+
+ #startButton {
+ display:inline;
+ width: 150px;
+ height: 30px;
+ color:#fff;
+ font-size: 14px;
+ background: #3070a8;
+ border: none;
+ }
+ </style>
+
+ <script>
+ numberOfDiscs = 6;
+
+ $(function() {
+ var spinner = $("#spinner").spinner();
+ $("#spinner").spinner({value: 3, min: 1, max: numberOfDiscs});
+
+ $("#spinner").spinner("value", 3);
+
+ $("#disable").click(function() {
+ if (spinner.spinner("option", "disabled")) {
+ spinner.spinner("enable");
+ } else {
+ spinner.spinner("disable");
+ }
+ });
+ $("#destroy").click(function() {
+ if (spinner.spinner("instance")) {
+ spinner.spinner("destroy");
+ } else {
+ spinner.spinner();
+ }
+ });
+ $("#getvalue").click(function() {
+ jAlert(spinner.spinner("value"));
+ });
+ $("#setvalue").click(function() {
+ spinner.spinner("value", 5);
+ });
+
+ $("button").button();
+ });
+
+ n = 3; // The number of discs
+ color = [];
+ color[0] = "crimson";
+ color[1] = "cornflowerblue";
+ color[2] = "beige";
+ color[3] = "purple";
+ color[4] = "aqua";
+ color[5] = "darkorange";
+ color[6] = "goldenrod";
+ color[7] = "#37826C";
+
+ number1 = 8;
+ number2 = 7;
+ answer = 15;
+ result = true;
+
+ steps = 7;
+ animationSpeed = 500;
+ slowAnimationSpeed = 1500;
+ lineOffSet = 15;
+ highLight = [];
+ highLight[0] = new HighLight();
+ highLight[0].top = 95;
+ highLight[0].left = 62;
+ highLight[0].width = 318;
+
+ highLight[1] = new HighLight();
+ highLight[1].top = 109;
+ highLight[1].left = 60 + 20;
+ highLight[1].width = 417;
+
+ highLight[2] = new HighLight();
+ highLight[2].top = 125;
+ highLight[2].left = 60 + 20;
+ highLight[2].width = 457;
+
+ highLight[3] = new HighLight();
+ highLight[3].top = 169;
+ highLight[3].left = 60 + 20;
+ highLight[3].width = 304;
+
+ highLight[4] = new HighLight();
+ highLight[4].top = 198;
+ highLight[4].left = 60 + 20;
+ highLight[4].width = 385;
+ highLight[4].height = 25;
+
+ highLight[5] = new HighLight();
+ highLight[5].top = 243;
+ highLight[5].left = 60 + 20;
+ highLight[5].width = 232;
+
+ highLight[6] = new HighLight();
+ highLight[6].top = 273;
+ highLight[6].left = 60 + 20;
+ highLight[6].width = 435;
+ highLight[6].height = 38;
+
+ highLight[7] = new HighLight();
+ highLight[7].top = 314;
+ highLight[7].width = 6;
+ highLight[7].left = 62;
+
+ explanation = [];
+ explanation[0] = new Explanation();
+ explanation[0].innerHTML = "The program starts the execution from the main method.";
+ explanation[0].top = 95;
+ explanation[0].left = 548;
+
+ explanation[1] = new Explanation();
+ explanation[1].innerHTML = "The statement generates a random number " + number1 + " and assigns it to variable number1.";
+ explanation[1].top = 107;
+ explanation[1].left = 550;
+
+ explanation[2] = new Explanation();
+ explanation[2].innerHTML = "The statement assigns a random integer to number2.";
+ explanation[2].top = 137;
+ explanation[2].left = 570;
+
+ explanation[3] = new Explanation();
+ explanation[3].innerHTML = "The statement creates an object for performing console input and assigns the object to the reference variable named input.";
+ explanation[3].top = 157;
+ explanation[3].left = 430;
+ explanation[3].width = 470;
+
+ explanation[4] = new Explanation();
+ explanation[4].innerHTML = "The statement displays a prompting message for the user input.";
+ explanation[4].top = 190;
+ explanation[4].left = 480;
+ explanation[4].width = 160;
+
+ explanation[5] = new Explanation();
+ explanation[5].innerHTML = "The statement receives an input from the user.";
+ explanation[5].top = 225;
+ explanation[5].left = 325;
+ explanation[5].width = 205;
+
+ explanation[6] = new Explanation();
+ explanation[6].innerHTML = "The statement displays the result.";
+ explanation[6].top = 257;
+ explanation[6].left = 325;
+ explanation[6].width = 205;
+
+ explanation[7] = new Explanation();
+ explanation[7].innerHTML = "The main method exits. The program is finished.";
+ explanation[7].top = 320;
+ explanation[7].left = 128;
+
+ commandPrompt = [];
+ commandPrompt[0] = new CommandPrompt();
+ commandPrompt[0].innerHTML = "";
+ commandPrompt[0].top = 95;
+ commandPrompt[0].left = 700;
+ commandPrompt[0].isVisible = false;
+ commandPrompt[1] = new CommandPrompt();
+ commandPrompt[1].isVisible = false;
+ commandPrompt[2] = new CommandPrompt();
+ commandPrompt[2].isVisible = false;
+ commandPrompt[2].innerHTML = "Enter a number for radius: ";
+ commandPrompt[2].top = 161;
+ commandPrompt[2].left = 640;
+
+ commandPrompt[3] = new CommandPrompt();
+ commandPrompt[3].isVisible = false;
+
+ commandPrompt[4] = new CommandPrompt();
+ commandPrompt[4].isVisible = true;
+ commandPrompt[4].innerHTML = "What is " + number1 + " + " + number2 + "? ";
+ commandPrompt[4].top = 200;
+ commandPrompt[4].left = 640;
+
+ commandPrompt[5] = new CommandPrompt();
+ commandPrompt[5].isVisible = true;
+ commandPrompt[5].innerHTML = commandPrompt[4].innerHTML + answer;
+ commandPrompt[5].top = 232;
+ commandPrompt[5].left = 550;
+
+ commandPrompt[6] = new CommandPrompt();
+ commandPrompt[6].isVisible = true;
+ commandPrompt[6].innerHTML = commandPrompt[5].innerHTML + "\n" + number1 + " + " + number2 + " = " + answer + " is " + result;
+ commandPrompt[6].top = 232;
+ commandPrompt[6].left = 550;
+
+ commandPrompt[7] = new CommandPrompt();
+ commandPrompt[7].isVisible = false;
+ commandPrompt[7].innerHTML = commandPrompt[6].innerHTML + "";
+ commandPrompt[7].top = 329;
+ commandPrompt[7].left = 300;
+
+ currentLine = 0;
+
+ function init() {
+ posLoc = getElementPos(document.getElementById('program'));
+ x = posLoc.x;
+ y = posLoc.y;
+
+ $("#status").hide();
+ $("#v1").css("top", y + 90).css("left", x + 115 - 3 / 2);
+ $("#v2").css("top", y + 90).css("left", x + 305 - 3 / 2);
+ $("#v3").css("top", y + 90).css("left", x + 495 - 3 / 2);
+ $("#h1").css("top", y + 220).css("left", x + 40);
+ $("#h2").css("top", y + 220).css("left", x + 230);
+ $("#h3").css("top", y + 220).css("left", x + 420);
+ $("#t1").css("top", y + 230).css("left", x + 90);
+ $("#t2").css("top", y + 230).css("left", x + 280);
+ $("#t3").css("top", y + 230).css("left", x + 470);
+
+ offset = n * 20;
+ for (var i = 1; i <= n; i++) {
+ $("#d" + i).show();
+ $("#d" + i).css("top", y + 220 - (n + 1 - i) * 20)
+ .css("background-color", color[i])
+ .css("left", x + 40 + (8 - i) * 7)
+ .css("width", 150 - (8 - i) * 14);
+ }
+
+ for (var i = 7; i > n; i--) {
+ $("#d" + i).hide(); // css("display", "none");
+ }
+ }
+ </script>
+
+<!-- Global Site Tag (gtag.js) - Google Analytics -->
+<script async="" src="./Tower of Hanoi Animation by Y. Daniel Liang_files/js"></script>
+<script>
+ window.dataLayer = window.dataLayer || [];
+ function gtag(){dataLayer.push(arguments)};
+ gtag('js', new Date());
+ gtag('config', 'UA-89940905-27');
+</script>
+
+<script type="text/javascript" src="./Tower of Hanoi Animation by Y. Daniel Liang_files/logging.js"></script>
+<style type="text/css" id="videoTapeCtxM-style-node">#videoTapeCtxM{display:block;width:auto;text-align:center;border-top:1px solid grey;box-shadow:5px 5px 5px #555;background-color:white;}#videoTapeCtxM a{border:1px solid grey;border-top:none;display:block;color:blue;width:auto;cursor:hand;margin:0px;padding:0px 3px 0px 3px;}#videoTapeCtxM a:hover{background-color:#AAA;}</style></head>
+
+
+
+ <body onload="init()" onresize="draw()" style="font-family: times new roman;" chromeextension:video-tape="true">
+ <h3 style="text-align:center; font: bold">Tower of Hanoi <a href="https://yongdanielliang.github.io/animation/animation.html">Animation</a> by
+ <a href="https://yongdanielliang.github.io/">Y. Daniel Liang</a></h3>
+ <p style="alignment-adjust: central; text-align: center; max-wdith: 800px; margin-left: auto; margin-right: auto">
+ Usage: Click the Start button to move all the discs from Tower A to Tower B. Click the Reset button to reset to the initial state.
+ </p>
+
+ <div id="program" style="width: 610px; height: 250px; font-family: courier; font-size: 100.5%; margin: 0px auto; border: 1px solid #EB0D1B; text-align: left">
+
+ <div id="v1" class="vbar" style="top: 183.438px; left: 647.5px;"></div>
+ <div id="v2" class="vbar" style="top: 183.438px; left: 837.5px;"></div>
+ <div id="v3" class="vbar" style="top: 183.438px; left: 1027.5px;"></div>
+ <div id="h1" style="left: 574px; top: 313.438px;" class="hbar"></div>
+ <div id="h2" style="left: 764px; top: 313.438px;" class="hbar"></div>
+ <div id="h3" style="left: 954px; top: 313.438px;" class="hbar"></div>
+ <div id="t1" style="left: 624px; top: 323.438px;" class="towerText">Tower A</div>
+ <div id="t2" class="towerText" style="top: 323.438px; left: 814px;">Tower B</div>
+ <div id="t3" class="towerText" style="top: 323.438px; left: 1004px;">Tower C</div>
+ <div id="d1" class="disc" style="top: 253.438px; background-color: cornflowerblue; left: 623px; width: 52px;"></div>
+ <div id="d2" class="disc" style="top: 273.438px; background-color: beige; left: 616px; width: 66px;"></div>
+ <div id="d3" class="disc" style="top: 293.438px; background-color: rgb(128, 0, 128); left: 609px; width: 80px;"></div>
+ <div id="d4" class="disc" style="display: none;"></div>
+ <div id="d5" class="disc" style="display: none;"></div>
+ <div id="d6" class="disc" style="display: none;"></div>
+<!-- <div id = "d7" class = "disc"></div>
+ <div id = "d8" class = "disc"></div>-->
+
+
+ </div>
+ <div style="text-align: center; margin-top: 1em">
+ <span style="border: 0px solid #37826C; padding: 3px">
+ <label for="spinner" style="font-weight: bold">Discs:</label>
+ <span class="ui-spinner ui-widget ui-widget-content ui-corner-all"><input id="spinner" name="value" style="width: 25px;" class="ui-spinner-input" autocomplete="off" role="spinbutton" aria-valuemin="1" aria-valuemax="6" aria-valuenow="3"><a class="ui-spinner-button ui-spinner-up ui-corner-tr ui-button ui-widget ui-state-default ui-button-text-only" tabindex="-1" role="button"><span class="ui-button-text"><span class="ui-icon ui-icon-triangle-1-n">▲</span></span></a><a class="ui-spinner-button ui-spinner-down ui-corner-br ui-button ui-widget ui-state-default ui-button-text-only" tabindex="-1" role="button"><span class="ui-button-text"><span class="ui-icon ui-icon-triangle-1-s">▼</span></span></a></span>
+
+ <button id="start" type="button" class="button ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" onclick="start()" role="button"><span class="ui-button-text">Start</span></button>
+ <button id="reset" type="button" class="button ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" onclick="reset()" role="button"><span class="ui-button-text">Reset</span></button>
+ </span>
+ </div>
+ <div style="text-align: center; margin-top: 1em">
+ <span id="status" style="background-color: chocolate; color: white; text-align: center; margin-left: auto; margin-right: auto; display: none;">The number of moves for 3 discs is 7</span>
+ </div>
+
+ <script type="text/javascript">
+
+ $("#nextButton").click(function() {
+ currentLine = currentLine + 1;
+ step();
+ });
+ $("#prevButton").click(function() {
+ currentLine = currentLine - 1;
+ step();
+ });
+
+ count = [];
+ $("#start").click(function() {
+ if (isStarted) {
+ jAlert("Click Reset and then Start");
+ return;
+ }
+ else {
+ isStarted = true;
+ }
+
+ n = $("#spinner").val();
+ count[0] = n;
+ count[1] = 0;
+ count[2] = 0;
+ moveDisks(n, 0, 1, 2);
+ $("#status").show();
+ $("#status").text("The number of moves for " +
+ n + " discs is " + queue.getSize());
+// tuple = queue.dequeue();
+// jAlert(tuple.n + ", " + tuple.fromTower + ", " + tuple.toTower);
+ animateMoves(queue);
+ });
+
+ function animateMoves(queue) {
+ d = 0;
+ if (!queue.isEmpty()) {
+ tuple = queue.dequeue();
+// jAlert(tuple.n + ", " + tuple.fromTower + ", " + tuple.toTower);
+
+ left1 = x + (40 + 150) * tuple.toTower + 40 + (8 - tuple.n) * 7;
+ top1 = y + 220 - (count[tuple.toTower] + 1) * 20;
+ count[tuple.fromTower]--;
+ count[tuple.toTower]++;
+// jAlert( "OVER " + tuple.n + ", " + tuple.fromTower + ", " + tuple.toTower);
+
+ $("#d" + tuple.n).animate({top: y + 40}, slowAnimationSpeed, function() {
+ $("#d" + tuple.n).animate({left: left1}, slowAnimationSpeed, function() {
+ $("#d" + tuple.n).animate({top: top1, left: left1}, slowAnimationSpeed, function() {
+ animateMoves(queue);
+ });
+ });
+ });
+
+// $("#d" + tuple.n).animate({top: top1, left: left1}, slowAnimationSpeed);
+// $("#flyingReturnValue").animate({top: value1Top + 40, left: value1Left}, slowAnimationSpeed);
+ d++;
+ }
+ }
+ isStarted = false;
+ $("#reset").click(function() {
+ isStarted = false;
+ n = 3;
+ $("#spinner").val(3);
+ queue = new Queue();
+ for (var i = 1; i <= 6; i++) {
+ $("#d" + i).stop();
+ }
+ init();
+ });
+
+ $("#spinner").click(function() {
+ jAlert("clicked");
+ n = $("#spinner").val();
+ init();
+ });
+
+ $(function() {
+ var temp = $("#spinner").spinner({
+ step: 1,
+ spin: function(event, ui) {
+ handleSpinnerValue(ui.value);
+ }
+ });
+ });
+
+ function handleSpinnerValue(txtValue)
+ {
+ if (isStarted) {
+ jAlert("Please click Reset before setting the disc numbers");
+ }
+ else {
+ n = txtValue;
+ init();
+ }
+ }
+
+ function fly(n, fromTower, toTower) {
+ left1 = x + (40 + 150) * toTower + 40 + (8 - n) * 7;
+ top1 = y + 220 - (count[toTower] + 1) * 20;
+ $("#d" + n).animate({top: y + 40}, slowAnimationSpeed);
+ $("#d" + n).animate({left: left1}, slowAnimationSpeed);
+ $("#d" + n).animate({top: top1, left: left1}, slowAnimationSpeed);
+// $("#flyingReturnValue").animate({top: value1Top + 40, left: value1Left}, slowAnimationSpeed);
+ count[fromTower]--;
+ count[toTower]++;
+ }
+
+ queue = new Queue();
+ function moveDisks(n, fromTower, toTower, auxTower) {
+ if (n == 1) { // Stopping condition
+// jAlert("Move disk " + n + " from " +
+// fromTower + " to " + toTower);
+ tuple = new Object();
+ tuple.n = n;
+ tuple.toTower = toTower;
+ tuple.fromTower = fromTower;
+ queue.enqueue(tuple);
+ // fly(n, fromTower, toTower);
+ }
+ else {
+ moveDisks(n - 1, fromTower, auxTower, toTower);
+ // fly(n, fromTower, toTower);
+ tuple = new Object();
+ tuple.n = n;
+ tuple.toTower = toTower;
+ tuple.fromTower = fromTower;
+ queue.enqueue(tuple);
+ moveDisks(n - 1, auxTower, toTower, fromTower);
+ }
+ }
+
+// Constructor for Tuple
+ function Tuple(n, fromTower, toTower) {
+ this.n = n;
+ this.toTower = toTower;
+ this.fromTower = fromTower;
+ }
+
+ function startOver() {
+ init();
+// document.getElementById('nextButton').style.display = 'none';
+// document.getElementById('startOverButton').style.display = 'none';
+// document.getElementById('prevButton').style.display = 'none';
+// document.getElementById('startButton').style.visibility = 'visible';
+// document.getElementById('startButton').style.display = 'inline';
+// document.getElementById('startButton').innerHTML = 'Restart Animation';
+
+// document.getElementById('explanation').style.visibility = 'hidden';
+// document.getElementById('highlight').style.visibility = 'hidden';
+// document.getElementById('commandPrompt').style.visibility = 'hidden';
+//// document.getElementById('explanation').style.visibility = 'hidden';
+// currentPromptContent = "";
+// currentLine = 0;
+// finished = false;
+// document.getElementById('memory').style.visibility = 'hidden';
+// document.getElementById('radius').style.visibility = 'hidden';
+// document.getElementById('area').style.visibility = 'hidden';
+ }
+
+ function step() {
+ pos = getElementPos(document.getElementById('line' + currentLine));
+// $("#explanation").animate({top: explanation[currentLine].top, left: explanation[currentLine].left,
+// width: explanation[currentLine].width}, animationSpeed);
+// $("#commandPrompt").animate({top: commandPrompt[currentLine].top, left: commandPrompt[currentLine].left}, animationSpeed);
+//
+ if (currentLine == 0) {
+ document.getElementById('prevButton').style.visibility = 'hidden';
+ document.getElementById('memory').style.visibility = 'hidden';
+ document.getElementById('flyingRadius').style.visibility = 'hidden';
+ document.getElementById('flyingRadius').innerHTML = '';
+ document.getElementById('value1').innerHTML = '';
+ document.getElementById('radius').style.visibility = 'hidden';
+ $("#explanation").animate({top: pos0.y - 30,
+ left: pos0.x + pos0.w + 20,
+ width: 200, height: explanation[currentLine].height}, 'fast');
+ $("#commandPrompt").animate({top: pos2.y + 15,
+ left: pos0.x + pos0.w + 15, }, 'fast');
+ document.getElementById('commandPrompt').style.visibility = 'hidden';
+ }
+ else if (currentLine == 1) {
+ document.getElementById('prevButton').style.visibility = 'visible';
+ document.getElementById('prevButton').style.display = 'inline';
+ number1 = Math.floor(Math.random() * 10);
+ explanation[1].innerHTML = "The statement generates a random number " + number1 + " and assigns it to variable number1.";
+ document.getElementById('memory').style.visibility = 'visible';
+ document.getElementById('flyingRadius').style.visibility = 'visible';
+ document.getElementById('flyingRadius').innerHTML = '';
+ document.getElementById('value1').innerHTML = '';
+ document.getElementById('radius').style.visibility = 'visible';
+//
+// document.getElementById('value1').style.visibility = 'visible';
+
+ posLoc1 = getElementPos(document.getElementById('loc1'));
+ $("#highlight").animate({top: highLight[currentLine].top, left: highLight[currentLine].left,
+ width: highLight[currentLine].width}, animationSpeed, function() {
+ $("#flyingRadius").css("top", posLoc1.y).css("left", posLoc1.x);
+ document.getElementById('flyingRadius').innerHTML = number1;
+ $("#flyingRadius").animate(
+ {top: value1Top - 50, left: value1Left}, slowAnimationSpeed);
+ });
+ document.getElementById('flyingArea').style.visibility = 'hidden';
+ document.getElementById('value2').innerHTML = '';
+ document.getElementById('area').style.visibility = 'hidden';
+ $("#explanation").animate({top: pos.y + 30,
+ left: variableLeft,
+ width: 200, height: explanation[currentLine].height}, 'fast');
+ }
+ else if (currentLine == 2) {
+ document.getElementById('flyingArea').innerHTML = '';
+ number2 = Math.floor(Math.random() * 10);
+ explanation[2].innerHTML = "The statement generates a random number " + number2 + " and assigns it to variable number2.";
+ commandPrompt[4].innerHTML = "What is " + number1 + " + " + number2 + "? ";
+ $("#explanation").animate({top: pos.y + 15,
+ left: variableLeft,
+ width: 200, height: explanation[currentLine].height}, 'fast');
+ document.getElementById('flyingArea').style.visibility = 'visible';
+ document.getElementById('value2').innerHTML = '';
+ document.getElementById('area').style.visibility = 'visible';
+//
+// document.getElementById('value1').style.visibility = 'visible';
+
+ posLoc2 = getElementPos(document.getElementById('loc2'));
+ $("#highlight").animate({top: highLight[currentLine].top, left: highLight[currentLine].left,
+ width: highLight[currentLine].width, height: highLight[currentLine].height}, animationSpeed, function() {
+ $("#flyingArea").css("top", posLoc2.y).css("left", posLoc2.x);
+ document.getElementById('flyingArea').innerHTML = number2;
+ $("#flyingArea").animate(
+ {top: value1Top - 30, left: value1Left}, slowAnimationSpeed);
+ });
+ }
+ else if (currentLine == 3) {
+ pos3 = getElementPos(document.getElementById('line' + currentLine));
+ $("#explanation").animate({top: pos3.y - 30,
+ left: variableLeft,
+ width: 200, height: explanation[currentLine].height}, 'fast');
+ }
+ else if (currentLine == 4) {
+ document.getElementById('flyingAnswer').style.visibility = 'hidden';
+ document.getElementById('flyingAnswer').innerHTML = '';
+ document.getElementById('value3').innerHTML = '';
+ document.getElementById('answer').style.visibility = 'hidden';
+ $("#explanation").animate({top: pos3.y - 20,
+ left: variableLeft,
+ width: 200, height: explanation[currentLine].height}, 'fast');
+ pos5 = getElementPos(document.getElementById('line5'));
+ pos7 = getElementPos(document.getElementById('line7'));
+ $("#commandPrompt").animate({top: pos7.y - 10,
+ left: pos5.x + pos5.w + 45, }, 'fast');
+ }
+ else if (currentLine == 5) {
+ document.getElementById('memory').style.visibility = 'visible';
+ document.getElementById('flyingAnswer').style.visibility = 'visible';
+ document.getElementById('flyingAnswer').innerHTML = '';
+ document.getElementById('value3').innerHTML = '';
+ document.getElementById('answer').style.visibility = 'visible';
+ document.getElementById('explanation').style.visibility = 'hidden';
+ answer = prompt("Here is your chance to enter an answer for " + number1 + " + " + number2 + "? ");
+ result = (answer == number1 + number2);
+ explanation[5].innerHTML = "The statement receives the input " + answer + " from the user.";
+ commandPrompt[5].innerHTML = commandPrompt[4].innerHTML + answer;
+ commandPrompt[6].innerHTML = commandPrompt[5].innerHTML + "\n" + number1 + " + " + number2 + " = " + answer + " is " + result;
+ commandPrompt[7].innerHTML = commandPrompt[6].innerHTML + "";
+ document.getElementById('explanation').style.visibility = 'visible';
+ $("#explanation").animate({top: pos.y - 10,
+ left: pos.x + pos.w + 20,
+ width: 200, height: explanation[currentLine].height}, 'fast');
+ pos5 = getElementPos(document.getElementById('line5'));
+ pos7 = getElementPos(document.getElementById('line7'));
+ $("#commandPrompt").animate({top: pos7.y - 10,
+ left: pos5.x + pos5.w + 45, }, 'fast');
+ posLoc3 = getElementPos(document.getElementById('loc3'));
+ $("#highlight").animate({top: highLight[currentLine].top, left: highLight[currentLine].left,
+ width: highLight[currentLine].width, height: highLight[currentLine].height}, animationSpeed, function() {
+ $("#flyingAnswer").css("top", posLoc3.y).css("left", posLoc3.x);
+ document.getElementById('flyingAnswer').innerHTML = answer;
+ $("#flyingAnswer").animate({top: value1Top + 55, left: value1Left}, slowAnimationSpeed);
+ });
+ }
+ else if (currentLine == 6) {
+ $("#explanation").animate({top: pos.y - 30,
+ left: pos.x + pos.w - 140,
+ width: 200, height: explanation[currentLine].height}, 'fast');
+ $("#commandPrompt").animate({top: pos7.y - 10,
+ left: pos5.x + pos5.w + 45, }, 'fast');
+ }
+ else if (currentLine == 7) {
+ $("#explanation").animate({top: pos.y - 5,
+ left: pos.x + pos.w + 40,
+ width: 200, height: explanation[currentLine].height}, 'fast');
+ $("#commandPrompt").animate({top: pos7.y - 10,
+ left: pos5.x + pos5.w + 45, }, 'fast');
+ document.getElementById('startButton').style.visibility = 'visible';
+ document.getElementById('startButton').style.display = 'inline';
+ document.getElementById('startButton').innerHTML = 'Restart Animation';
+ }
+ else {
+ $("#highlight").animate({top: highLight[currentLine].top, left: highLight[currentLine].left,
+ width: highLight[currentLine].width, height: highLight[currentLine].height}, animationSpeed);
+ }
+
+ if (currentLine == 5) {
+ document.getElementById('commandPrompt').style.visibility = 'visible';
+ }
+
+ if (commandPrompt[currentLine].isVisible) {
+ document.getElementById('commandPrompt').style.visibility = 'visible';
+ document.getElementById('commandPromptContent').innerHTML = commandPrompt[currentLine].innerHTML;
+ }
+ else {
+ document.getElementById('commandPrompt').style.visibility = 'hidden';
+ }
+
+// if (currentLine == 0) {
+// pos = getElementPos(document.getElementById('line0'));
+// }
+// else if (currentLine == 1) {
+// pos = getElementPos(document.getElementById('line1'));
+// }
+// else if (currentLine == 2) {
+// pos = getElementPos(document.getElementById('line2'));
+// }
+// else if (currentLine == 3) {
+// pos = getElementPos(document.getElementById('line3'));
+// }
+// else if (currentLine == 4) {
+// pos = getElementPos(document.getElementById('line4'));
+// }
+// else if (currentLine == 5) {
+// pos = getElementPos(document.getElementById('line5'));
+// }
+// else if (currentLine == 6) {
+// pos = getElementPos(document.getElementById('line6'));
+// }
+// else if (currentLine == 7) {
+// pos = getElementPos(document.getElementById('line7'));
+// }
+
+ document.getElementById('explanation').innerHTML = explanation[currentLine].innerHTML;
+ $("#highlight").animate({top: pos.y, left: pos.x, width: pos.w, height: pos.h}, animationSpeed);
+ if (currentLine == steps) {
+ document.getElementById('nextButton').style.visibility = 'hidden';
+ document.getElementById('prevButton').style.visibility = 'hidden';
+ document.getElementById('memory').style.visibility = 'hidden';
+ document.getElementById('radius').style.visibility = 'hidden';
+ document.getElementById('area').style.visibility = 'hidden';
+ document.getElementById('startButton').style.visibility = 'visible';
+ document.getElementById('startButton').innerHTML = 'Restart Animation';
+ document.getElementById('flyingRadius').style.visibility = 'hidden';
+ document.getElementById('flyingArea').style.visibility = 'hidden';
+ document.getElementById('flyingAnswer').style.visibility = 'hidden';
+ document.getElementById('answer').style.visibility = 'hidden';
+ document.getElementById('flyingRadius').innerHTML = '';
+ document.getElementById('flyingArea').innerHTML = '';
+ document.getElementById('flyingAnswer').innerHTML = '';
+ currentLine = 0;
+ document.getElementById('startOverButton').style.visibility = 'hidden';
+ document.getElementById('startOverButton').style.display = 'none';
+ }
+ }
+
+ </script>
+
+
+<div><div style="display: none; position: fixed; top: 30px; width: auto; max-width: 100%; text-align: center; left: 50%; transform: translateX(-50%); z-index: 99999999;"><div style="display: inline-block; font-size: 14px; font-weight: bold; border: 1px solid rgb(240, 195, 109); background-color: rgb(249, 237, 190); padding: 0px 10px; border-radius: 2px; box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 4px;"></div></div></div></body></html> \ No newline at end of file
diff --git a/web/bigai/canvas_layering.html b/web/bigai/canvas_layering.html
new file mode 100644
index 0000000..669fdf9
--- /dev/null
+++ b/web/bigai/canvas_layering.html
@@ -0,0 +1,116 @@
+<!doctype html>
+<html>
+<head>
+ <meta charset="UTF-8"/>
+ <title>Canvas Layers Test</title>
+</head>
+<body>
+<section>
+ <!--<div id="canvasesdiv" style="position:relative; width:400px; height:300px">-->
+ <canvas id="layer1"
+ style="z-index: 1;
+ position:absolute;
+ left:0px;
+ top:0px;
+ border: 5px, solid;
+ "
+ height="200px" width="300">
+ This text is displayed if your browser does not support HTML5 Canvas.
+ </canvas>
+
+ <canvas id="layer2"
+ style="z-index: 2;
+ position:absolute;
+ left:100px;
+ top:0px;
+ border: 5px, solid;
+ "
+ height="50px" width="50">
+ This text is displayed if your browser does not support HTML5 Canvas.
+ </canvas>
+
+ <canvas id="layer3"
+ style="z-index: 3;
+ position:absolute;
+ left:0px;
+ top:0px;
+ border: 5px, solid;
+ "
+ height="100px" width="200">
+ This text is displayed if your browser does not support HTML5 Canvas.
+ </canvas>
+ <!--</div>-->
+
+ <script type="text/javascript">
+ var layer1; var ctx1;
+ var layer2; var ctx2;
+ var layer3; var ctx3;
+
+ var x = 400;
+ var y = 300;
+ var dx = 2;
+ var dy = 4;
+ var WIDTH = 400;
+ var HEIGHT = 300;
+ var city = new Image();
+
+ function init() {
+ city.src ="city.png";
+ layer1 = document.getElementById("layer1");
+ ctx1 = layer1.getContext("2d");
+ layer2 = document.getElementById("layer2");
+ ctx2 = layer2.getContext("2d");
+ layer3 = document.getElementById("layer3");
+ ctx3 = layer3.getContext("2d");
+ setInterval(drawAll, 20);
+ }
+
+ function drawAll() {
+ draw1();
+ draw2();
+ draw3();
+ }
+
+ function draw1() {
+ ctx1.clearRect(0, 0, WIDTH, HEIGHT);
+ ctx1.fillStyle = "#FAF7F8";
+ ctx1.beginPath();
+ ctx1.rect(0, 0, WIDTH, HEIGHT);
+ ctx1.closePath();
+ ctx1.fill();
+ ctx1.fillStyle = "#444444";
+ ctx1.beginPath();
+ ctx1.arc(x, y, 10, 0, Math.PI*2, true);
+ ctx1.closePath();
+ ctx1.fill();
+
+ if (x + dx > WIDTH || x + dx < 0)
+ dx = -dx;
+ if (y + dy > HEIGHT || y + dy < 0)
+ dy = -dy;
+
+ x += dx;
+ y += dy;
+ }
+
+ function draw2() {
+ ctx2.clearRect(0, 0, WIDTH, HEIGHT);
+ ctx2.drawImage(city, 0, 0);
+ }
+
+ function draw3() {
+ ctx3.clearRect(0, 0, WIDTH, HEIGHT);
+ ctx3.fillStyle = "#444444";
+ ctx3.save();
+ ctx3.translate(200,200);
+ ctx3.rotate(x/20);
+ ctx3.fillRect(-15, -15, 30, 30);
+ ctx3.restore();
+ }
+
+ init();
+
+ </script>
+</section>
+</body>
+</html> \ No newline at end of file
diff --git a/web/bigai/myrender.py b/web/bigai/myrender.py
new file mode 100644
index 0000000..d49e69b
--- /dev/null
+++ b/web/bigai/myrender.py
@@ -0,0 +1,109 @@
+import gym
+from gym.envs.classic_control import rendering
+import math
+from pyglet.gl import *
+import pyglet
+
+class Attr(object):
+ def enable(self):
+ raise NotImplementedError
+ def disable(self):
+ pass
+
+
+class Color(Attr):
+ def __init__(self, vec4):
+ self.vec4 = vec4
+ def enable(self):
+ glColor4f(*self.vec4)
+p
+class Geom(object):
+ def __init__(self):
+ self._color=Color((0, 0, 0, 1.0))
+ self.attrs = [self._color]
+ def render(self):
+ for attr in reversed(self.attrs):
+ attr.enable()
+ self.render1()
+ for attr in self.attrs:
+ attr.disable()
+ def render1(self):
+ raise NotImplementedError
+ def add_attr(self, attr):
+ self.attrs.append(attr)
+ def set_color(self, r, g, b, alpha=1):
+ self._color.vec4 = (r, g, b, alpha)
+
+
+class FilledPolygon(Geom):
+ def __init__(self, v):
+ Geom.__init__(self)
+ self.v = v
+ def render1(self):
+ if len(self.v) == 4 : glBegin(GL_QUADS)
+ elif len(self.v) > 4 : glBegin(GL_POLYGON)
+ else: glBegin(GL_TRIANGLES)
+ for p in self.v:
+ glVertex3f(p[0], p[1],0) # draw each vertex
+ glEnd()
+
+ color = (self._color.vec4[0] * 0.5, self._color.vec4[1] * 0.5, self._color.vec4[2] * 0.5, self._color.vec4[3] * 0.5)
+ glColor4f(*color)
+ glBegin(GL_LINE_LOOP)
+ for p in self.v:
+ glVertex3f(p[0], p[1],0) # draw each vertex
+ glEnd()
+
+
+class MyEnv(gym.Env):
+ metadata = {
+ 'render.modes': ['human', 'rgb_array'],
+ 'videos.frames_per_second': 2
+ }
+
+ def __init__(self):
+ self.viewer = rendering.Viewer(800, 600)
+
+ # def render(self, mode='human', close=False):
+ # line1 = rendering.Line((100, 300), (500, 300))
+ # line2 = rendering.Line((100, 200), (500, 200))
+ # line1.set_color(0, 0, 0)
+ # line2.set_color(0, 0, 0)
+ # self.viewer.add_geom(line1)
+ # self.viewer.add_geom(line2)
+ # return self.viewer.render(return_rgb_array=mode == 'rgb_array')
+
+ def make_agent(self):
+ radius = 10
+ res = 30
+ WORLD_WIDTH = 10
+ visual_distance = 100
+ points = []
+ for i in range(res):
+ ang = 2*math.pi*i/res
+ points.append([math.cos(ang)*radius, math.sin(ang)*radius])
+ for i in range(9):
+ ang = 2 * math.pi * (i - 4) / res
+ points.append((math.cos(ang) * visual_distance + radius, math.sin(ang) * visual_distance))
+ return points
+
+
+ # def render(self, mode='human', close=False):
+ # circle = rendering.make_circle(30)
+ # circle_transform = rendering.Transform(translation=(100, 100))
+ # circle.add_attr(circle_transform)
+ # self.viewer.add_geom(circle)
+ # return self.viewer.render(return_rgb_array=mode == 'rgb_array')
+
+ def render(self, mode='human'):
+ agent_points = self.make_agent()
+ agent = FilledPolygon(agent_points)
+ trans = rendering.Transform(translation=(200, 200))
+ agent.add_attr(trans)
+ self.viewer.add_geom(agent)
+ return self.viewer.render(return_rgb_array=mode == 'rgb_array')
+
+if __name__ == '__main__':
+ env = MyEnv()
+ while True:
+ env.render()
diff --git a/web/bigai/test.html b/web/bigai/test.html
new file mode 100644
index 0000000..abc1d15
--- /dev/null
+++ b/web/bigai/test.html
@@ -0,0 +1,52 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title></title>
+ <script language="javascript">
+ window.onload = function () {
+ var landscape_canvas = document.getElementById("landscape");
+ var ctx = landscape_canvas.getContext("2d");
+ ctx.fillStyle = "Blue";
+ <!--ctx.fillRect(0, 0, 800, 850);-->
+
+ //Cone
+ ctx.fillStyle = "#67ff30";
+ ctx.beginPath();
+ ctx.moveTo(150, 250);
+ ctx.lineTo(300, 20);
+ ctx.lineTo(450, 250);
+ ctx.lineTo(150, 250);
+ ctx.fill();
+ ctx.closePath();
+ ctx.fillStyle = "Brown";
+ ctx.beginPath();
+ ctx.moveTo(400, 250);
+ ctx.lineTo(450, 80);
+ ctx.lineTo(600, 250);
+ ctx.lineTo(400, 250);
+ ctx.fill();
+ ctx.closePath();
+ ctx.beginPath();
+ // get 2 canvas
+ <!--var landscape_canvas = document.getElementById("landscape1");-->
+ <!--var ctx = landscape_canvas.getContext("2d");-->
+ <!--ctx.fillStyle = "blue";-->
+ <!--ctx.fillRect(0, 0, 600, 450);-->
+ <!--ctx.beginPath();-->
+ <!--ctx.fillStyle = "black";-->
+ <!--ctx.moveTo(75, 25);-->
+ <!--ctx.quadraticCurveTo(25, 25, 25, 62.5);-->
+ <!--ctx.quadraticCurveTo(25, 100, 50, 100);-->
+ <!--ctx.quadraticCurveTo(50, 120, 30, 125);-->
+ <!--ctx.quadraticCurveTo(60, 120, 65, 100);-->
+ <!--ctx.quadraticCurveTo(125, 100, 125, 62.5);-->
+ <!--ctx.quadraticCurveTo(125, 25, 75, 25);-->
+ <!--ctx.stroke();-->
+ <!--ctx.beginPath();-->
+ }
+ </script>
+</head>
+<body>
+<canvas id="landscape" width="800" height="350"></canvas>
+<canvas id="landscape1" width="800" height="150"></canvas>
+</body>
+</html> \ No newline at end of file
diff --git a/web/canvas-transforms.html b/web/canvas-transforms.html
new file mode 100644
index 0000000..bfdbe80
--- /dev/null
+++ b/web/canvas-transforms.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta http-equiv="X-UA-Compatible" content="ie=edge">
+ <title>Canvas Rotation</title>
+ <style>
+ html{
+ background-color: #999;
+ }
+ #canvas{
+ background-color: #fff;
+ border: 1px solid #333;
+ width: 70%;
+ margin: 1rem auto;
+ display: block;
+ }
+ </style>
+</head>
+<body>
+ <canvas id="canvas"></canvas>
+ <script>
+ let canvas, ctx;
+
+ document.addEventListener('DOMContentLoaded', ()=>{
+ canvas = document.getElementById('canvas');
+ ctx = canvas.getContext('2d');
+ canvas.width = 600;
+ canvas.height = 800;
+ ctx.fillStyle = 'cornflowerblue';
+ ctx.strokeStyle = '#ccc';
+ ctx.lineWidth = 2;
+ ctx.textAlign = 'start';
+ ctx.font = 'normal 30px Arial';
+ drawGrid(100);
+
+ let x = 100;
+ let y = 100;
+ ctx.save(); //creates a save point
+ ctx.beginPath();
+ ctx.translate(200, 200);
+ ctx.fillText('translate', 10, 30);
+ ctx.fill();
+ ctx.closePath();
+ ctx.restore(); //go back to the last save point
+
+ ctx.save();
+ ctx.beginPath();
+ ctx.arc(0, 0, 10, 0, Math.PI*2);
+ ctx.rotate(Math.PI/4); //3.14 radians 180 deg
+ ctx.fillText('rotate', 300, 0);
+ ctx.fill();
+ ctx.closePath();
+ ctx.restore();
+
+ ctx.beginPath();
+ ctx.translate(100, 500);
+ ctx.scale(1, -1);
+ ctx.fillText('scale', x, y);
+ ctx.fill();
+ ctx.closePath();
+
+
+ });
+
+ function drawGrid(gap){
+ ctx.beginPath();
+ for(x=gap; x<canvas.width; x=x+gap){
+ ctx.moveTo(x, 0);
+ ctx.lineTo(x, canvas.height);
+ }
+ for(let y=gap; y<canvas.height; y=y+gap){
+ ctx.moveTo(0, y);
+ ctx.lineTo(canvas.height, y);
+ }
+ ctx.stroke();
+ ctx.closePath();
+ }
+ </script>
+</body>
+</html> \ No newline at end of file
diff --git a/web/canvas_animation.html b/web/canvas_animation.html
new file mode 100644
index 0000000..205f8fe
--- /dev/null
+++ b/web/canvas_animation.html
@@ -0,0 +1,73 @@
+<!doctype html>
+<html>
+<head>
+ <meta charset="UTF-8"/>
+ <title>Canvas Test</title>
+</head>
+<body>
+<section>
+ <div>
+ <canvas id="canvas" width="400" height="300">
+ This text is displayed if your browser
+ does not support HTML5 Canvas.
+ </canvas>
+ </div>
+
+ <script type="text/javascript">
+ var canvas;
+ var ctx;
+ var x = 200;
+ var y = 150;
+ var dx = 2;
+ var dy = 4;
+ var WIDTH = 200;
+ var HEIGHT = 150;
+
+ function circle(x,y,r) {
+ ctx.beginPath();
+ ctx.arc(x, y, r, 0, Math.PI*2, false);
+ ctx.fill();
+ }
+
+ function rect(x,y,w,h) {
+ ctx.beginPath();
+ ctx.rect(x,y,w,h);
+ ctx.closePath();
+ ctx.fill();
+ }
+
+
+ function clear() {
+ ctx.clearRect(0, 0, WIDTH, HEIGHT);
+ }
+
+ function init() {
+ canvas = document.getElementById("canvas");
+ ctx = canvas.getContext("2d");
+ return setInterval(draw, 100);
+ }
+
+
+ function draw() {
+ clear();
+ ctx.fillStyle = "#FAF7F8";
+ rect(0,0,WIDTH,HEIGHT);
+ ctx.fillStyle = "#444444";
+ circle(x, y, 20);
+
+ if (x + dx > WIDTH || x + dx < 0)
+ dx = -dx;
+ if (y + dy > HEIGHT || y + dy < 0)
+ dy = -dy;
+
+ x += dx;
+ y += dy;
+ }
+
+ init();
+
+ </script>
+
+</section>
+</body>
+</html> \ No newline at end of file
diff --git a/web/canvas_layering.html b/web/canvas_layering.html
new file mode 100644
index 0000000..6214009
--- /dev/null
+++ b/web/canvas_layering.html
@@ -0,0 +1,113 @@
+<!doctype html>
+<html>
+<head>
+ <meta charset="UTF-8"/>
+ <title>Canvas Layers Test</title>
+</head>
+<body>
+<section>
+ <div id="canvasesdiv" style="position:relative; width:400px; height:300px">
+ <canvas id="layer1"
+ style="z-index: 1;
+ position:absolute;
+ left:0px;
+ top:0px;
+ "
+ height="300px" width="400">
+ This text is displayed if your browser does not support HTML5 Canvas.
+ </canvas>
+
+ <canvas id="layer2"
+ style="z-index: 2;
+ position:absolute;
+ left:0px;
+ top:0px;
+ "
+ height="300px" width="400">
+ This text is displayed if your browser does not support HTML5 Canvas.
+ </canvas>
+
+ <canvas id="layer3"
+ style="z-index: 3;
+ position:absolute;
+ left:0px;
+ top:0px;
+ "
+ height="300px" width="400">
+ This text is displayed if your browser does not support HTML5 Canvas.
+ </canvas>
+ </div>
+
+ <script type="text/javascript">
+ var layer1; var ctx1;
+ var layer2; var ctx2;
+ var layer3; var ctx3;
+
+ var x = 400;
+ var y = 300;
+ var dx = 2;
+ var dy = 4;
+ var WIDTH = 400;
+ var HEIGHT = 300;
+ var city = new Image();
+
+ function init() {
+ city.src ="city.png";
+ layer1 = document.getElementById("layer1");
+ ctx1 = layer1.getContext("2d");
+ layer2 = document.getElementById("layer2");
+ ctx2 = layer2.getContext("2d");
+ layer3 = document.getElementById("layer3");
+ ctx3 = layer3.getContext("2d");
+ setInterval(drawAll, 20);
+ }
+
+ function drawAll() {
+ draw1();
+ draw2();
+ draw3();
+ }
+
+ function draw1() {
+ ctx1.clearRect(0, 0, WIDTH, HEIGHT);
+ ctx1.fillStyle = "#FAF7F8";
+ ctx1.beginPath();
+ ctx1.rect(0, 0, WIDTH, HEIGHT);
+ ctx1.closePath();
+ ctx1.fill();
+ ctx1.fillStyle = "#444444";
+ ctx1.beginPath();
+ ctx1.arc(x, y, 10, 0, Math.PI*2, true);
+ ctx1.closePath();
+ ctx1.fill();
+
+ if (x + dx > WIDTH || x + dx < 0)
+ dx = -dx;
+ if (y + dy > HEIGHT || y + dy < 0)
+ dy = -dy;
+
+ x += dx;
+ y += dy;
+ }
+
+ function draw2() {
+ ctx2.clearRect(0, 0, WIDTH, HEIGHT);
+ ctx2.drawImage(city, 0, 0);
+ }
+
+ function draw3() {
+ ctx3.clearRect(0, 0, WIDTH, HEIGHT);
+ ctx3.fillStyle = "#444444";
+ ctx3.save();
+ ctx3.translate(200,200);
+ ctx3.rotate(x/20);
+ ctx3.fillRect(-15, -15, 30, 30);
+ ctx3.restore();
+ }
+
+ init();
+
+ </script>
+</section>
+</body>
+</html> \ No newline at end of file
diff --git a/web/layers/CanvasStack-2v01.js b/web/layers/CanvasStack-2v01.js
new file mode 100644
index 0000000..1d8b328
--- /dev/null
+++ b/web/layers/CanvasStack-2v01.js
@@ -0,0 +1,207 @@
+/*=============================================================
+ Filename: CanvasStack-2v01.js
+ Rev: 2
+ By: A.R.Collins
+ Description: Utilities to create multiple transparent
+ canvas layers suitable for animation.
+ License: Released into the public domain
+ latest version at
+ <http://www/arc.id.au/CanvasLayers.html>
+
+ Date |Description |By
+ -------------------------------------------------------------
+ 30Oct09 Rev 1.00 First release ARC
+ 08Sep12 bugfix: test for emulator failed in IE9 ARC
+ 02Mar13 Re-write to use screen canvas as background ARC
+ 28Jul13 remove getOverlayCanvas (use getElementById)
+ Tidy for JSLint ARC
+ 20Jul14 Setup a resize handler for layers, required when
+ canvas size changes on window resize (width in %).
+ Dropped excanvas support ARC
+ 18Sep19 Re-factor to simplify ARC
+ 21Sep19 Convert to Classes etc ARC
+ 30Sep19 Added addResizeCallback method
+ Released as Rev 2v00 ARC
+ 01Jan20 Add Layer.dragObjects to match Cango Layer ARC
+ =============================================================*/
+
+var CanvasStack;
+
+(function()
+{
+ "use strict";
+
+ class Layer
+ {
+ constructor(canvasID, canvasElement)
+ {
+ this.id = canvasID;
+ this.cElem = canvasElement;
+ this.dragObjects = [];
+ }
+ }
+
+ CanvasStack = class{
+ constructor(cvsID, stackLimit){
+ const savThis = this;
+
+ function setResizeHandler(resizeLayers, timeout){
+ let timer_id = undefined;
+ window.addEventListener("resize", ()=>{
+ if(timer_id != undefined)
+ {
+ clearTimeout(timer_id);
+ timer_id = undefined;
+ }
+ timer_id = setTimeout(()=>{
+ timer_id = undefined;
+ resizeLayers();
+ savThis.bkgCanvas.resizeFns.forEach((currFn)=>currFn());
+ }, timeout);
+ });
+ }
+
+ function resizeLayers(){
+ const t = savThis.bkgCanvas.offsetTop + savThis.bkgCanvas.clientTop,
+ l = savThis.bkgCanvas.offsetLeft + savThis.bkgCanvas.clientLeft,
+ w = savThis.bkgCanvas.offsetWidth,
+ h = savThis.bkgCanvas.offsetHeight;
+
+ // check if canvas size changed when window resized, allow some rounding error in layout calcs
+ if ((Math.abs(w - savThis.rawWidth)/w < 0.01) && (Math.abs(h - savThis.rawHeight)/h < 0.01))
+ {
+ // canvas size didn't change so return
+ return;
+ }
+ // canvas has been resized so resize all the overlay canvases
+ for (let j=1; j<savThis.bkgCanvas.layers.length; j++) // bkg is layer[0]
+ {
+ let ovl = savThis.bkgCanvas.layers[j].cElem;
+ if (ovl) // may have been deleted so empty slot
+ {
+ ovl.style.top = t+'px';
+ ovl.style.left = l+'px';
+ ovl.style.width = w+'px';
+ ovl.style.height = h+'px';
+ ovl.width = w; // reset canvas attribute to pixel width
+ ovl.height = h;
+ }
+ }
+ }
+
+ // check if this is a context for an overlay
+ if (cvsID.indexOf("_ovl_") !== -1)
+ {
+ console.error("CanvasStack: canvas must be a background canvas not an overlay");
+ return {};
+ }
+
+ this.cId = cvsID;
+ this.stackLimit = stackLimit || 6;
+ this.bkgCanvas = document.getElementById(cvsID);
+ this.rawWidth = this.bkgCanvas.offsetWidth;
+ this.rawHeight = this.bkgCanvas.offsetHeight;
+ this.bkgCanvas.resizeFns = [];
+
+ if (!this.bkgCanvas.hasOwnProperty('layers'))
+ {
+ // create an array to hold all the overlay canvases for this canvas
+ this.bkgCanvas.layers = [];
+ // make a Layer object for the bkgCanvas
+ let bkgL = new Layer(this.cId, this.bkgCanvas); // bkgCanvas is always layer[0]
+ this.bkgCanvas.layers[0] = bkgL;
+ // make sure the overlay canvases always match the bkgCanvas size
+ setResizeHandler(resizeLayers, 250);
+ }
+ if (!this.bkgCanvas.hasOwnProperty('unique'))
+ {
+ this.bkgCanvas.unique = 0;
+ }
+ }
+
+ createLayer(){
+ const w = this.rawWidth,
+ h = this.rawHeight,
+ nLyrs = this.bkgCanvas.layers.length; // bkg is layer 0 so at least 1
+
+ // check background canvas is still there
+ if (!(this.bkgCanvas && this.bkgCanvas.layers))
+ {
+ console.log("CanvasStack: missing background canvas");
+ return;
+ }
+ if (this.bkgCanvas.layers.length >= this.stackLimit)
+ {
+ console.error("CanvasStack: too many layers");
+ return;
+ }
+ this.bkgCanvas.unique += 1; // a private static variable
+ const uniqueTag = this.bkgCanvas.unique.toString();
+ const ovlId = this.cId+"_ovl_"+uniqueTag;
+ const ovlHTML = "<canvas id='"+ovlId+"' style='position:absolute' width='"+w+"' height='"+h+"'></canvas>";
+ const topCvs = this.bkgCanvas.layers[nLyrs-1].cElem;
+ topCvs.insertAdjacentHTML('afterend', ovlHTML);
+ const newCvs = document.getElementById(ovlId);
+ newCvs.style.backgroundColor = "transparent";
+ newCvs.style.left = (this.bkgCanvas.offsetLeft+this.bkgCanvas.clientLeft)+'px';
+ newCvs.style.top = (this.bkgCanvas.offsetTop+this.bkgCanvas.clientTop)+'px';
+ // make it the same size as the background canvas
+ newCvs.style.width = this.bkgCanvas.offsetWidth+'px';
+ newCvs.style.height = this.bkgCanvas.offsetHeight+'px';
+ let newL = new Layer(ovlId, newCvs);
+ // save the ID in an array to facilitate removal
+ this.bkgCanvas.layers.push(newL);
+
+ return ovlId; // return the new canvas id
+ }
+
+ deleteLayer(ovlyId){
+ // check background canvas is still there
+ if (!(this.bkgCanvas && this.bkgCanvas.layers))
+ {
+ console.log("CanvasStack: missing background canvas");
+ return;
+ }
+ for (let i=1; i<this.bkgCanvas.layers.length; i++)
+ {
+ if (this.bkgCanvas.layers[i].id === ovlyId)
+ {
+ let ovlNode = this.bkgCanvas.layers[i].cElem;
+ if (ovlNode)
+ {
+ ovlNode.parentNode.removeChild(ovlNode);
+ }
+ // now delete layers array element
+ this.bkgCanvas.layers.splice(i,1); // delete the Layer object
+ }
+ }
+ }
+
+ deleteAllLayers(){
+ // check background canvas is still there
+ if (!(this.bkgCanvas && this.bkgCanvas.layers))
+ {
+ console.log("CanvasStack: missing background canvas");
+ return;
+ }
+ for (let i=this.bkgCanvas.layers.length-1; i>0; i--) // don't delete layers[0] its the bakg canavs
+ {
+ let ovlNode = this.bkgCanvas.layers[i].cElem;
+ if (ovlNode)
+ {
+ let orphan = ovlNode.parentNode.removeChild(ovlNode);
+ orphan = null;
+ }
+ // now delete layers array element
+ this.bkgCanvas.layers.splice(i,1);
+ }
+ // clear any resize callbacks, the layers are gone
+ this.bkgCanvas.resizeFns.length = 0; // remove any added handlers, leave the basic
+ }
+
+ addResizeCallback(callbackFn){
+ this.bkgCanvas.resizeFns.push(callbackFn);
+ }
+ };
+
+}());
diff --git a/web/layers/index.html b/web/layers/index.html
new file mode 100644
index 0000000..e30c96a
--- /dev/null
+++ b/web/layers/index.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
+ <title>Document</title>
+ <script src="CanvasStack-2v01.js"></script>
+
+</head>
+<body>
+ <canvas id="canvas"></canvas>
+ <script src="main.js"></script>
+</body>
+</html> \ No newline at end of file
diff --git a/web/layers/main.js b/web/layers/main.js
new file mode 100644
index 0000000..6bab236
--- /dev/null
+++ b/web/layers/main.js
@@ -0,0 +1,15 @@
+
+var canvas = document.getElementById("canvas");
+var ctx = canvas.getContext("2d");
+
+canvas.width = window.innerWidth;
+canvas.height = window.innerHeight;
+
+var stack = new CanvasStack();
+var layer1 = stack.createLayer();
+var ctx1 = document.getElementById(layer1).getContext("2d");
+
+ctx1.fillRect(0, 0, 100, 100);
+
+
+
diff --git a/web/learn_canvas/bar_canvas.html b/web/learn_canvas/bar_canvas.html
new file mode 100644
index 0000000..c2d7518
--- /dev/null
+++ b/web/learn_canvas/bar_canvas.html
@@ -0,0 +1,50 @@
+<html>
+<head>
+
+<script>
+ function draw() {
+ /* Accepting and seperating comma seperated values */
+ var n = document.getElementById("num").value;
+ var values = n.split(',');
+
+ var canvas = document.getElementById('myCanvas');
+ var ctx = canvas.getContext('2d');
+
+ var width = 40; //bar width
+ var X = 50; // first bar position
+ var base = 200;
+
+ for (var i =0; i<values.length; i++) {
+ ctx.fillStyle = '#008080';
+ var h = values[i];
+ ctx.fillRect(X,canvas.height - h,width,h);
+
+ X += width+15;
+ /* text to display Bar number */
+ ctx.fillStyle = '#4da6ff';
+ ctx.fillText('Bar '+i,X-50,canvas.height - h -10);
+ }
+ /* Text to display scale */
+ ctx.fillStyle = '#000000';
+ ctx.fillText('Scale X : '+canvas.width+' Y : '+canvas.height,800,10);
+
+ }
+ function reset(){
+ var canvas = document.getElementById('myCanvas');
+ var ctx = canvas.getContext('2d');
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ }
+</script>
+</head>
+<body align="center">
+
+
+ Enter the values seperated by a comma<br>
+ <input type="text" name="number" id="num"><br>
+ <input type="button" value="submit" name="submit" onclick="draw()">
+ <input type="button" value="Clear" name="Clear" onclick="reset()"><br><br>
+ <canvas id="myCanvas" width="900" height="500" style="border:1px solid #c3c3c3;">
+ </canvas>
+
+</body>
+</html>
diff --git a/web/learn_canvas/basics/index.html b/web/learn_canvas/basics/index.html
new file mode 100644
index 0000000..3c0cfb8
--- /dev/null
+++ b/web/learn_canvas/basics/index.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Title</title>
+</head>
+<body>
+ <canvas id="canvas"></canvas>
+</body>
+<script src="main.js"></script>
+</html> \ No newline at end of file
diff --git a/web/learn_canvas/basics/main.js b/web/learn_canvas/basics/main.js
new file mode 100644
index 0000000..5aa6458
--- /dev/null
+++ b/web/learn_canvas/basics/main.js
@@ -0,0 +1,60 @@
+let canvas = document.getElementById("canvas");
+let ctx = canvas.getContext("2d");
+
+var win_height = window.innerHeight;
+var win_width = window.innerWidth;
+
+canvas.height = win_height;
+canvas.width = win_width;
+console.log(canvas.width, canvas.height);
+
+canvas.style.background = "#bbf";
+
+
+class Circle {
+ constructor(context, xpos, ypos, radius, color) {
+ this.context = context;
+ this.xpos = xpos;
+ this.ypos = ypos;
+ this.radius = radius;
+ this.color = color;
+ }
+ draw() {
+ this.context.beginPath();
+ this.context.arc(this.xpos, this.ypos, this.radius, 0, Math.PI*2, this.color);
+ this.context.strokeStyle = "grey";
+ this.context.lineWidth = 15;
+ this.context.fillStyle = this.color;
+ this.context.fill();
+ this.context.stroke();
+ this.context.closePath();
+ }
+ clickCircle(xmouse, ymouse) {
+ const distance = Math.sqrt((xmouse - this.xpos) * (xmouse - this.xpos) + (ymouse - this.ypos) * (ymouse - this.ypos));
+ if (distance <= this.radius) {
+ return true;
+ }
+ return false;
+ }
+ changeColor (newColor) {
+ this.color = newColor;
+ this.draw();
+ }
+}
+
+
+let circle = new Circle(ctx, 200, 200, 100, "blue");
+circle.draw(ctx);
+canvas.addEventListener("click", (event) => {
+// console.log(event);
+// console.log("clicked canvas");
+ const rect = canvas.getBoundingClientRect();
+ const x = event.clientX - rect.left;
+ const y = event.clientY - rect.top;
+ if (circle.clickCircle(x, y)) {
+ circle.changeColor("red");
+ } else {
+ circle.changeColor("blue");
+ }
+// console.log(rect);
+});
diff --git a/web/learn_canvas/canvas_btns/example.js b/web/learn_canvas/canvas_btns/example.js
new file mode 100644
index 0000000..0722613
--- /dev/null
+++ b/web/learn_canvas/canvas_btns/example.js
@@ -0,0 +1,121 @@
+var canvas = document.getElementById('canvas'),
+ context = canvas.getContext('2d'),
+ rubberbandDiv = document.getElementById('rubberbandDiv'),
+ resetButton = document.getElementById('resetButton'),
+ image = new Image(),
+ mousedown = {},
+ rubberbandRectangle = {},
+ dragging = false;
+
+// Functions..........................................................
+
+function rubberbandStart(x, y) {
+ mousedown.x = x;
+ mousedown.y = y;
+
+ rubberbandRectangle.left = mousedown.x;
+ rubberbandRectangle.top = mousedown.y;
+
+ moveRubberbandDiv();
+ showRubberbandDiv();
+
+ dragging = true;
+}
+
+function rubberbandStretch(x, y) {
+ rubberbandRectangle.left = x < mousedown.x ? x : mousedown.x;
+ rubberbandRectangle.top = y < mousedown.y ? y : mousedown.y;
+
+ rubberbandRectangle.width = Math.abs(x - mousedown.x),
+ rubberbandRectangle.height = Math.abs(y - mousedown.y);
+
+ moveRubberbandDiv();
+ resizeRubberbandDiv();
+}
+
+function rubberbandEnd() {
+ var bbox = canvas.getBoundingClientRect();
+
+ try {
+ context.drawImage(canvas,
+ rubberbandRectangle.left - bbox.left,
+ rubberbandRectangle.top - bbox.top,
+ rubberbandRectangle.width,
+ rubberbandRectangle.height,
+ 0, 0, canvas.width, canvas.height);
+ }
+ catch (e) {
+ // Suppress error message when mouse is released
+ // outside the canvas
+ }
+
+ resetRubberbandRectangle();
+
+ rubberbandDiv.style.width = 0;
+ rubberbandDiv.style.height = 0;
+
+ hideRubberbandDiv();
+
+ dragging = false;
+}
+
+function moveRubberbandDiv() {
+ rubberbandDiv.style.top = rubberbandRectangle.top + 'px';
+ rubberbandDiv.style.left = rubberbandRectangle.left + 'px';
+}
+
+function resizeRubberbandDiv() {
+ rubberbandDiv.style.width = rubberbandRectangle.width + 'px';
+ rubberbandDiv.style.height = rubberbandRectangle.height + 'px';
+}
+
+function showRubberbandDiv() {
+ rubberbandDiv.style.display = 'inline';
+}
+
+function hideRubberbandDiv() {
+ rubberbandDiv.style.display = 'none';
+}
+
+function resetRubberbandRectangle() {
+ rubberbandRectangle = { top: 0, left: 0, width: 0, height: 0 };
+}
+
+// Event handlers.....................................................
+
+canvas.onmousedown = function (e) {
+ var x = e.clientX,
+ y = e.clientY;
+
+ e.preventDefault();
+ rubberbandStart(x, y);
+};
+
+window.onmousemove = function (e) {
+ var x = e.clientX,
+ y = e.clientY;
+
+ e.preventDefault();
+ if (dragging) {
+ rubberbandStretch(x, y);
+ }
+};
+
+window.onmouseup = function (e) {
+ e.preventDefault();
+ rubberbandEnd();
+};
+
+image.onload = function () {
+ context.drawImage(image, 0, 0, canvas.width, canvas.height);
+};
+
+resetButton.onclick = function(e) {
+ context.clearRect(0, 0, context.canvas.width,
+ context.canvas.height);
+ context.drawImage(image, 0, 0, canvas.width, canvas.height);
+};
+
+// Initialization.....................................................
+
+image.src = 'curved-road.png'; \ No newline at end of file
diff --git a/web/learn_canvas/canvas_btns/index.html b/web/learn_canvas/canvas_btns/index.html
new file mode 100644
index 0000000..9509727
--- /dev/null
+++ b/web/learn_canvas/canvas_btns/index.html
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Title</title>
+ <style>
+ #container
+ {
+ height: 400px;
+ position: relative;
+ width: 400px;
+ }
+ <!--#viewport-->
+ <!--{-->
+ <!--height: 100%;-->
+ <!--width: 100%;-->
+ <!--}-->
+ #controls
+ {
+ top: 0;
+ left: 0;
+ position: absolute;
+ width: 100%;
+ }
+ </style>
+</head>
+<body>
+
+<!--<div id="container">-->
+ <!--<canvas id="viewport">-->
+ <!--</canvas>-->
+ <!--<menu id="controls">-->
+ <!--<button onclick="copy()">belief</button>-->
+ <!--<button onclick="cut()">intents</button>-->
+ <!--</menu>-->
+<!--</div>-->
+<canvas id="viewport" style="z-index:1"></canvas>
+<input type="button" style="z-index:2; position:absolute; top:100; left:100" value="test"/>
+
+</body>
+<script src="main.js"></script>
+
+</html> \ No newline at end of file
diff --git a/web/learn_canvas/canvas_btns/main.js b/web/learn_canvas/canvas_btns/main.js
new file mode 100644
index 0000000..be07ddb
--- /dev/null
+++ b/web/learn_canvas/canvas_btns/main.js
@@ -0,0 +1,11 @@
+let canvas = document.getElementById("viewport");
+let ctx = canvas.getContext("2d");
+
+//var win_height = 600;
+//var win_width = 800;
+
+canvas.height = 600;
+canvas.width = 800;
+console.log(canvas.width, canvas.height);
+
+canvas.style.background = "#bbf"; \ No newline at end of file
diff --git a/web/learn_canvas/canvas_btns/style.css b/web/learn_canvas/canvas_btns/style.css
new file mode 100644
index 0000000..c9b2bbf
--- /dev/null
+++ b/web/learn_canvas/canvas_btns/style.css
@@ -0,0 +1,18 @@
+#container
+{
+ height: 400px;
+ position: relative;
+ width: 400px;
+}
+#viewport
+{
+ height: 100%;
+ width: 100%;
+}
+#controls
+{
+ bottom: 0;
+ left: 0;
+ position: absolute;
+ width: 100%;
+} \ No newline at end of file
diff --git a/web/learn_canvas/canvas_btns/test.html b/web/learn_canvas/canvas_btns/test.html
new file mode 100644
index 0000000..9de2318
--- /dev/null
+++ b/web/learn_canvas/canvas_btns/test.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Bouncing Balls</title>
+
+ <style>
+ body {
+ background: #dddddd;
+ }
+
+ #canvas {
+ margin-left: 10px;
+ margin-top: 10px;
+ background: #ffffff;
+ border: thin solid #aaaaaa;
+ }
+
+ #glasspane {
+ position: absolute;
+ left: 50px;
+ top: 50px;
+ padding: 0px 20px 10px 10px;
+ background: rgba(0, 0, 0, 0.3);
+ border: thin solid rgba(0, 0, 0, 0.6);
+ color:# #eeeeee;
+ font-family: Droid Sans, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ cursor: pointer;
+ -webkit-box-shadow: rgba(0,0,0,0.5) 5px 5px 20px;
+ -moz-box-shadow: rgba(0,0,0,0.5) 5px 5px 20px;
+ box-shadow: rgba(0,0,0,0.5) 5px 5px 20px;
+ }
+
+ #glasspane h2 {
+ font-weight: normal;
+ }
+
+ #glasspane .title {
+ font-size: 2em;
+ color:# rgba(255, 255, 0, 0.8);
+ }
+
+ #glasspane a:hover {
+ color:# yellow;
+ }
+
+ #glasspane a {
+ text-decoration: none;
+ color:# #cccccc;
+ font-size: 3.5em;
+ }
+
+ #glasspane p {
+ margin: 10px;
+ color:# rgba(65, 65, 220, 1.0);
+ font-size: 12pt;
+ font-family: Palatino, Arial, Helvetica, sans-serif;
+ }
+ </style>
+ </head>
+
+ <body>
+ <div id='glasspane'>
+ <h2 class='title'>Bouncing Balls</h2>
+
+ <p>One hundred balls bouncing</p>
+
+ <a id='startButton'>Start</a>
+ </div>
+
+ <canvas id='canvas' width='750' height='500'>
+ Canvas not supported
+ </canvas>
+
+ <script src='example.js'></script>
+ </body>
+</html>
diff --git a/web/learn_canvas/canvas_btns/test2.html b/web/learn_canvas/canvas_btns/test2.html
new file mode 100644
index 0000000..b456738
--- /dev/null
+++ b/web/learn_canvas/canvas_btns/test2.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Rubber bands with layered elements</title>
+
+ <style>
+ body {
+ background: rgba(100, 145, 250, 0.3);
+ }
+
+ #canvas {
+ margin-left: 20px;
+ margin-right: 0;
+ margin-bottom: 20px;
+ border: thin solid #aaaaaa;
+ cursor: crosshair;
+ padding: 0;
+ }
+
+ #controls {
+ margin: 20px 0px 20px 20px;
+ }
+
+ #rubberbandDiv {
+ position: absolute;
+ border: 3px solid blue;
+ cursor: crosshair;
+ display: none;
+ }
+
+ </style>
+ </head>
+
+ <body>
+ <div id='controls'>
+ <input type='button' id='resetButton' value='Reset'/>
+ </div>
+
+ <div id='rubberbandDiv'></div>
+
+ <canvas id='canvas' width='800' height='520'>
+ Canvas not supported
+ </canvas>
+
+ <script src='example.js'></script>
+ </body>
+</html> \ No newline at end of file
diff --git a/web/multi_layers.html b/web/multi_layers.html
new file mode 100644
index 0000000..1311a77
--- /dev/null
+++ b/web/multi_layers.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Title</title>
+ <style>
+ #layer1 {
+ border: 10px, solid;
+
+ }
+ </style>
+</head>
+
+<body>
+
+<div style="position: relative;">
+ <canvas id="layer1" width="200" height="200"
+ style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
+ <canvas id="layer2" width="100" height="100"
+ style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
+</div>
+
+</body>
+</html> \ No newline at end of file
diff --git a/web/multi_layers/index.html b/web/multi_layers/index.html
new file mode 100644
index 0000000..3c0cfb8
--- /dev/null
+++ b/web/multi_layers/index.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <title>Title</title>
+</head>
+<body>
+ <canvas id="canvas"></canvas>
+</body>
+<script src="main.js"></script>
+</html> \ No newline at end of file
diff --git a/web/multi_layers/main.js b/web/multi_layers/main.js
new file mode 100644
index 0000000..5aa6458
--- /dev/null
+++ b/web/multi_layers/main.js
@@ -0,0 +1,60 @@
+let canvas = document.getElementById("canvas");
+let ctx = canvas.getContext("2d");
+
+var win_height = window.innerHeight;
+var win_width = window.innerWidth;
+
+canvas.height = win_height;
+canvas.width = win_width;
+console.log(canvas.width, canvas.height);
+
+canvas.style.background = "#bbf";
+
+
+class Circle {
+ constructor(context, xpos, ypos, radius, color) {
+ this.context = context;
+ this.xpos = xpos;
+ this.ypos = ypos;
+ this.radius = radius;
+ this.color = color;
+ }
+ draw() {
+ this.context.beginPath();
+ this.context.arc(this.xpos, this.ypos, this.radius, 0, Math.PI*2, this.color);
+ this.context.strokeStyle = "grey";
+ this.context.lineWidth = 15;
+ this.context.fillStyle = this.color;
+ this.context.fill();
+ this.context.stroke();
+ this.context.closePath();
+ }
+ clickCircle(xmouse, ymouse) {
+ const distance = Math.sqrt((xmouse - this.xpos) * (xmouse - this.xpos) + (ymouse - this.ypos) * (ymouse - this.ypos));
+ if (distance <= this.radius) {
+ return true;
+ }
+ return false;
+ }
+ changeColor (newColor) {
+ this.color = newColor;
+ this.draw();
+ }
+}
+
+
+let circle = new Circle(ctx, 200, 200, 100, "blue");
+circle.draw(ctx);
+canvas.addEventListener("click", (event) => {
+// console.log(event);
+// console.log("clicked canvas");
+ const rect = canvas.getBoundingClientRect();
+ const x = event.clientX - rect.left;
+ const y = event.clientY - rect.top;
+ if (circle.clickCircle(x, y)) {
+ circle.changeColor("red");
+ } else {
+ circle.changeColor("blue");
+ }
+// console.log(rect);
+});