mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-19 10:17:23 -05:00
Apply prettier to css, html, js, md, ts, and yml (#1249)
* Apply prettier to css, js, html, md, ts, and yml As a followup I will add prettier to the .pre-commit config. This patch is 100% generated by prettier. I used a forked version of prettier that understands the py-script tag. See https://github.com/hoodmane/pyscript-prettier-precommit for more info. * Apply old pre-commit * Revert some problems * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Revert some changes * More changes * Fix pre-commit * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
84
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
84
.github/ISSUE_TEMPLATE/bug-report.yml
vendored
@@ -2,62 +2,62 @@ name: Bug Report
|
||||
description: Create a report to help us improve
|
||||
labels: ["type: bug", "needs-triage"]
|
||||
body:
|
||||
- type: markdown
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for helping PyScript! 🐍
|
||||
value: |
|
||||
Thanks for helping PyScript! 🐍
|
||||
|
||||
Going through bugs and issues takes up a lot of time, so please be so kind and take a few minutes to fill out all the areas to the best of your ability.
|
||||
Going through bugs and issues takes up a lot of time, so please be so kind and take a few minutes to fill out all the areas to the best of your ability.
|
||||
|
||||
There will always be more issues than there is time to do them, and so we will need to selectively close issues that don't provide enough information, so we can focus our time on helping people like you who fill out the issue form completely. Thank you for your collaboration!
|
||||
There will always be more issues than there is time to do them, and so we will need to selectively close issues that don't provide enough information, so we can focus our time on helping people like you who fill out the issue form completely. Thank you for your collaboration!
|
||||
|
||||
There are also already a lot of open issues, so please take 2 minutes and search through existing ones to see if what you are experiencing already exists
|
||||
There are also already a lot of open issues, so please take 2 minutes and search through existing ones to see if what you are experiencing already exists
|
||||
|
||||
Thanks for helping PyScript be amazing. We are nothing without people like you helping build a better community 💐!
|
||||
- type: checkboxes
|
||||
Thanks for helping PyScript be amazing. We are nothing without people like you helping build a better community 💐!
|
||||
- type: checkboxes
|
||||
id: checks
|
||||
attributes:
|
||||
label: Checklist
|
||||
description: Please confirm and check all the following options.
|
||||
options:
|
||||
- label: I added a descriptive title
|
||||
required: true
|
||||
- label: I searched for other issues and couldn't find a solution or duplication
|
||||
required: true
|
||||
- label: I already searched in Google and didn't find any good information or help
|
||||
required: true
|
||||
- type: textarea
|
||||
label: Checklist
|
||||
description: Please confirm and check all the following options.
|
||||
options:
|
||||
- label: I added a descriptive title
|
||||
required: true
|
||||
- label: I searched for other issues and couldn't find a solution or duplication
|
||||
required: true
|
||||
- label: I already searched in Google and didn't find any good information or help
|
||||
required: true
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: And what should have happened instead? This really helps everyone review quicker and greatly increases the chance that someone can get around to solve your issue
|
||||
placeholder: Tell us what you see!
|
||||
label: What happened?
|
||||
description: And what should have happened instead? This really helps everyone review quicker and greatly increases the chance that someone can get around to solve your issue
|
||||
placeholder: Tell us what you see!
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: browsers
|
||||
attributes:
|
||||
label: What browsers are you seeing the problem on? (if applicable)
|
||||
multiple: true
|
||||
options:
|
||||
- Firefox
|
||||
- Chrome
|
||||
- Safari
|
||||
- Microsoft Edge
|
||||
- Other
|
||||
label: What browsers are you seeing the problem on? (if applicable)
|
||||
multiple: true
|
||||
options:
|
||||
- Firefox
|
||||
- Chrome
|
||||
- Safari
|
||||
- Microsoft Edge
|
||||
- Other
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
required: false
|
||||
- type: textarea
|
||||
id: list
|
||||
attributes:
|
||||
label: Console info
|
||||
description: |
|
||||
If there are errors in your browser console then its helpful to be able to troubleshoot.
|
||||
- Chrome , Firefox, and Edge: Right-click on the page and select *Inspect*. Alternatively you can press F12 on your keyboard.
|
||||
- Safari: Find instructions [here](https://support.apple.com/guide/safari/use-the-developer-tools-in-the-develop-menu-sfri20948/mac).
|
||||
render: shell
|
||||
- type: textarea
|
||||
label: Console info
|
||||
description: |
|
||||
If there are errors in your browser console then its helpful to be able to troubleshoot.
|
||||
- Chrome , Firefox, and Edge: Right-click on the page and select *Inspect*. Alternatively you can press F12 on your keyboard.
|
||||
- Safari: Find instructions [here](https://support.apple.com/guide/safari/use-the-developer-tools-in-the-develop-menu-sfri20948/mac).
|
||||
render: shell
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Add any additional context information or screenshots you think are useful.
|
||||
label: Additional Context
|
||||
description: Add any additional context information or screenshots you think are useful.
|
||||
|
||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,8 +1,8 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Feature Proposals
|
||||
- name: Feature Proposals
|
||||
url: https://github.com/pyscript/pyscript/discussions/new?category=proposals
|
||||
about: Create a feature request to make PyScript even better
|
||||
- name: Questions
|
||||
- name: Questions
|
||||
url: https://github.com/pyscript/pyscript/discussions/new?category=q-a
|
||||
about: For questions or discussions about pyscript
|
||||
|
||||
5
.github/workflows/build-unstable.yml
vendored
5
.github/workflows/build-unstable.yml
vendored
@@ -28,7 +28,6 @@ jobs:
|
||||
MINICONDA_PYTHON_VERSION: py38
|
||||
MINICONDA_VERSION: 4.11.0
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
@@ -42,7 +41,7 @@ jobs:
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
@@ -97,7 +96,7 @@ jobs:
|
||||
name: pyscript
|
||||
path: ./build/
|
||||
|
||||
# Deploy to S3
|
||||
# Deploy to S3
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
with:
|
||||
|
||||
9
.github/workflows/docs-release.yml
vendored
9
.github/workflows/docs-release.yml
vendored
@@ -13,7 +13,6 @@ jobs:
|
||||
env:
|
||||
SPHINX_HTML_BASE_URL: https://docs.pyscript.net/
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
@@ -40,7 +39,7 @@ jobs:
|
||||
name: pyscript-docs-${{ github.ref_name }}
|
||||
path: docs/_build/html/
|
||||
|
||||
# Deploy to S3
|
||||
# Deploy to S3
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
with:
|
||||
@@ -53,11 +52,11 @@ jobs:
|
||||
- name: Sync to S3
|
||||
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/${{ github.ref_name }}/
|
||||
|
||||
# Make sure to remove the latest folder so we sync the full docs upon release
|
||||
# Make sure to remove the latest folder so we sync the full docs upon release
|
||||
- name: Delete latest directory
|
||||
run: aws s3 rm --recursive s3://docs.pyscript.net/latest/
|
||||
|
||||
# Note that the files are the same as above, but we want to have folders with
|
||||
# /<tag name>/ AND /latest/ which latest will always point to the latest release
|
||||
# Note that the files are the same as above, but we want to have folders with
|
||||
# /<tag name>/ AND /latest/ which latest will always point to the latest release
|
||||
- name: Sync to /latest
|
||||
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/latest/
|
||||
|
||||
3
.github/workflows/docs-review.yml
vendored
3
.github/workflows/docs-review.yml
vendored
@@ -26,7 +26,6 @@ jobs:
|
||||
env:
|
||||
SPHINX_HTML_BASE_URL: https://docs.pyscript.net/
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
@@ -53,7 +52,7 @@ jobs:
|
||||
name: pyscript-docs-review-${{ github.event.number }}
|
||||
path: docs/_build/html/
|
||||
|
||||
# Deploy to S3
|
||||
# Deploy to S3
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
with:
|
||||
|
||||
5
.github/workflows/docs-unstable.yml
vendored
5
.github/workflows/docs-unstable.yml
vendored
@@ -16,7 +16,6 @@ jobs:
|
||||
env:
|
||||
SPHINX_HTML_BASE_URL: https://docs.pyscript.net/
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
@@ -43,13 +42,13 @@ jobs:
|
||||
name: pyscript-docs-latest
|
||||
path: docs/_build/html/
|
||||
|
||||
# Deploy to S3
|
||||
# Deploy to S3
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
with:
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||
|
||||
# Sync will only copy changed files
|
||||
# Sync will only copy changed files
|
||||
- name: Sync to S3
|
||||
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/unstable/
|
||||
|
||||
5
.github/workflows/prepare-release.yml
vendored
5
.github/workflows/prepare-release.yml
vendored
@@ -3,7 +3,7 @@ name: '[CI] Prepare Release'
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- '[0-9][0-9][0-9][0-9].[0-9][0-9].[0-9]+' # YYYY.MM.MICRO
|
||||
- '[0-9][0-9][0-9][0-9].[0-9][0-9].[0-9]+' # YYYY.MM.MICRO
|
||||
|
||||
env:
|
||||
MINICONDA_PYTHON_VERSION: py38
|
||||
@@ -17,7 +17,6 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
@@ -31,7 +30,7 @@ jobs:
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
|
||||
4
.github/workflows/publish-release.yml
vendored
4
.github/workflows/publish-release.yml
vendored
@@ -32,7 +32,7 @@ jobs:
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
- name: Build and Test
|
||||
run: make test
|
||||
|
||||
# Upload to S3
|
||||
# Upload to S3
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||
with:
|
||||
|
||||
5
.github/workflows/sync-examples.yml
vendored
5
.github/workflows/sync-examples.yml
vendored
@@ -15,8 +15,7 @@ jobs:
|
||||
working-directory: examples
|
||||
|
||||
steps:
|
||||
|
||||
# Deploy to S3
|
||||
# Deploy to S3
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Configure AWS credentials
|
||||
@@ -25,5 +24,5 @@ jobs:
|
||||
aws-region: ${{ secrets.AWS_REGION }}
|
||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||
- name: Sync to S3
|
||||
# Sync outdated or new files, delete ones no longer in source
|
||||
# Sync outdated or new files, delete ones no longer in source
|
||||
run: aws s3 sync --quiet --delete . s3://pyscript.net/examples/ # Sync directory, delete what is not in source
|
||||
|
||||
@@ -4,17 +4,17 @@ Thank you for wanting to contribute to the PyScript project!
|
||||
|
||||
## Table of contents
|
||||
|
||||
* [Code of Conduct](#code-of-conduct)
|
||||
* [Contributing](#contributing)
|
||||
* [Reporting bugs](#reporting-bugs)
|
||||
* [Reporting security issues](#reporting-security-issues)
|
||||
* [Asking questions](#asking-questions)
|
||||
* [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
|
||||
* [Places to start](#places-to-start)
|
||||
* [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
|
||||
* [License terms for contributions](#license-terms-for-contributions)
|
||||
* [Becoming a maintainer](#becoming-a-maintainer)
|
||||
* [Trademarks](#trademarks)
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [Contributing](#contributing)
|
||||
- [Reporting bugs](#reporting-bugs)
|
||||
- [Reporting security issues](#reporting-security-issues)
|
||||
- [Asking questions](#asking-questions)
|
||||
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
|
||||
- [Places to start](#places-to-start)
|
||||
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
|
||||
- [License terms for contributions](#license-terms-for-contributions)
|
||||
- [Becoming a maintainer](#becoming-a-maintainer)
|
||||
- [Trademarks](#trademarks)
|
||||
|
||||
# Code of Conduct
|
||||
|
||||
@@ -28,10 +28,10 @@ Bugs are tracked on the [project issues page](https://github.com/pyscript/pyscri
|
||||
|
||||
## Creating useful issues
|
||||
|
||||
* Use a clear and descriptive title.
|
||||
* Describe the specific steps that reproduce the problem with as many details as possible so that someone can verify the issue.
|
||||
* Describe the behavior you observed, and the behavior you had expected.
|
||||
* Include screenshots if they help make the issue clear.
|
||||
- Use a clear and descriptive title.
|
||||
- Describe the specific steps that reproduce the problem with as many details as possible so that someone can verify the issue.
|
||||
- Describe the behavior you observed, and the behavior you had expected.
|
||||
- Include screenshots if they help make the issue clear.
|
||||
|
||||
## Reporting security issues
|
||||
|
||||
@@ -45,10 +45,10 @@ If you have questions about the project, using PyScript, or anything else, pleas
|
||||
|
||||
If you would like to contribute to PyScript, but you aren't sure where to begin, here are some suggestions.
|
||||
|
||||
* **Read over the existing documentation.** Are there things missing, or could they be clearer? Make some changes/additions to those documents.
|
||||
* **Review the open issues.** Are they clear? Can you reproduce them? You can add comments, clarifications, or additions to those issues. If you think you have an idea of how to address the issue, submit a fix!
|
||||
* **Look over the open pull requests.** Do you have comments or suggestions for the proposed changes? Add them.
|
||||
* **Check out the examples.** Is there a use case that would be good to have sample code for? Create an example for it.
|
||||
- **Read over the existing documentation.** Are there things missing, or could they be clearer? Make some changes/additions to those documents.
|
||||
- **Review the open issues.** Are they clear? Can you reproduce them? You can add comments, clarifications, or additions to those issues. If you think you have an idea of how to address the issue, submit a fix!
|
||||
- **Look over the open pull requests.** Do you have comments or suggestions for the proposed changes? Add them.
|
||||
- **Check out the examples.** Is there a use case that would be good to have sample code for? Create an example for it.
|
||||
|
||||
## Setting up your local environment and developing
|
||||
|
||||
@@ -69,5 +69,6 @@ Contributors are invited to be maintainers of the project by demonstrating good
|
||||
The Project abides by the Organization's [trademark policy](https://github.com/pyscript/governance/blob/main/TRADEMARKS.md).
|
||||
|
||||
---
|
||||
|
||||
Part of MVG-0.1-beta.
|
||||
Made with love by GitHub. Licensed under the [CC-BY 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||
@@ -41,5 +41,6 @@ Any names, trademarks, logos, or goodwill developed by and associated with the P
|
||||
Amendments to this governance policy may be made by affirmative vote of 2/3 of all Maintainers, with approval by the Organization's Steering Committee.
|
||||
|
||||
---
|
||||
|
||||
Part of MVG-0.1-beta.
|
||||
Made with love by GitHub. Licensed under the [CC-BY 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||
@@ -17,7 +17,7 @@ This document lists the Maintainers of the Project. Maintainers may be added onc
|
||||
| Paul Everitt | --- |
|
||||
| Fabio Rosado | --- |
|
||||
|
||||
______________________________________________________________________
|
||||
---
|
||||
|
||||
Part of MVG-0.1-beta.
|
||||
Made with love by GitHub. Licensed under the [CC-BY 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||
29
README.md
29
README.md
@@ -11,21 +11,24 @@ To get started see the [getting started tutorial](docs/tutorials/getting-started
|
||||
For examples see [here](examples).
|
||||
|
||||
### Longer Version
|
||||
|
||||
PyScript is a meta project that aims to combine multiple open technologies into a framework that allows users to create sophisticated browser applications with Python. It integrates seamlessly with the way the DOM works in the browser and allows users to add Python logic in a way that feels natural both to web and Python developers.
|
||||
|
||||
## Try PyScript
|
||||
|
||||
To try PyScript, import the appropriate pyscript files into the ```<head>``` tag of your html page with:
|
||||
To try PyScript, import the appropriate pyscript files into the `<head>` tag of your html page with:
|
||||
|
||||
```html
|
||||
<head>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
```
|
||||
|
||||
You can then use PyScript components in your html page. PyScript currently implements the following elements:
|
||||
|
||||
* `<py-script>`: can be used to define python code that is executable within the web page. The element itself is not rendered to the page and is only used to add logic
|
||||
* `<py-repl>`: creates a REPL component that is rendered to the page as a code editor and allows users to write executable code
|
||||
- `<py-script>`: can be used to define python code that is executable within the web page. The element itself is not rendered to the page and is only used to add logic
|
||||
- `<py-repl>`: creates a REPL component that is rendered to the page as a code editor and allows users to write executable code
|
||||
|
||||
Check out the [the examples directory](examples) folder for more examples on how to use it, all you need to do is open them in Chrome.
|
||||
|
||||
@@ -33,20 +36,20 @@ Check out the [the examples directory](examples) folder for more examples on how
|
||||
|
||||
Read the [contributing guide](CONTRIBUTING.md) to learn about our development process, reporting bugs and improvements, creating issues and asking questions.
|
||||
|
||||
Check out the [developing process](https://docs.pyscript.net/latest/development/developing.html) documentation for more information on how to setup your development environment.
|
||||
Check out the [developing process](https://docs.pyscript.net/latest/development/developing.html) documentation for more information on how to setup your development environment.
|
||||
|
||||
## Resources
|
||||
|
||||
* [Official docs](https://docs.pyscript.net)
|
||||
* [Discussion board](https://community.anaconda.cloud/c/tech-topics/pyscript)
|
||||
* [Home Page](https://pyscript.net/)
|
||||
* [Blog Post](https://engineering.anaconda.com/2022/04/welcome-pyscript.html)
|
||||
* [Discord Channel](https://discord.gg/BYB2kvyFwm)
|
||||
- [Official docs](https://docs.pyscript.net)
|
||||
- [Discussion board](https://community.anaconda.cloud/c/tech-topics/pyscript)
|
||||
- [Home Page](https://pyscript.net/)
|
||||
- [Blog Post](https://engineering.anaconda.com/2022/04/welcome-pyscript.html)
|
||||
- [Discord Channel](https://discord.gg/BYB2kvyFwm)
|
||||
|
||||
## Notes
|
||||
|
||||
* This is an extremely experimental project, so expect things to break!
|
||||
* PyScript has been only tested on Chrome at the moment.
|
||||
- This is an extremely experimental project, so expect things to break!
|
||||
- PyScript has been only tested on Chrome at the moment.
|
||||
|
||||
## Governance
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
This page is meant for troubleshooting common problems with PyScript.
|
||||
|
||||
## Table of contents:
|
||||
* [Make Setup](#make-setup)
|
||||
|
||||
- [Make Setup](#make-setup)
|
||||
|
||||
## Make setup
|
||||
|
||||
|
||||
@@ -1,78 +1,78 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Altair</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Altair</a>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
<div id="altair"></div>
|
||||
<py-tutor>
|
||||
<py-config>
|
||||
packages = [
|
||||
"altair",
|
||||
"pandas",
|
||||
"vega_datasets"
|
||||
]
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
]
|
||||
</py-config>
|
||||
<py-script>
|
||||
import altair as alt
|
||||
from vega_datasets import data
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">Altair</a>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
<div id="altair"></div>
|
||||
<py-tutor>
|
||||
<py-config>
|
||||
packages = [
|
||||
"altair",
|
||||
"pandas",
|
||||
"vega_datasets"
|
||||
]
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
]
|
||||
</py-config>
|
||||
<py-script>
|
||||
import altair as alt
|
||||
from vega_datasets import data
|
||||
|
||||
source = data.movies.url
|
||||
source = data.movies.url
|
||||
|
||||
pts = alt.selection(type="single", encodings=['x'])
|
||||
pts = alt.selection(type="single", encodings=['x'])
|
||||
|
||||
rect = alt.Chart(data.movies.url).mark_rect().encode(
|
||||
alt.X('IMDB_Rating:Q', bin=True),
|
||||
alt.Y('Rotten_Tomatoes_Rating:Q', bin=True),
|
||||
alt.Color('count()',
|
||||
scale=alt.Scale(scheme='greenblue'),
|
||||
legend=alt.Legend(title='Total Records')
|
||||
)
|
||||
)
|
||||
rect = alt.Chart(data.movies.url).mark_rect().encode(
|
||||
alt.X('IMDB_Rating:Q', bin=True),
|
||||
alt.Y('Rotten_Tomatoes_Rating:Q', bin=True),
|
||||
alt.Color('count()',
|
||||
scale=alt.Scale(scheme='greenblue'),
|
||||
legend=alt.Legend(title='Total Records')
|
||||
)
|
||||
)
|
||||
|
||||
circ = rect.mark_point().encode(
|
||||
alt.ColorValue('grey'),
|
||||
alt.Size('count()',
|
||||
legend=alt.Legend(title='Records in Selection')
|
||||
)
|
||||
).transform_filter(
|
||||
pts
|
||||
)
|
||||
circ = rect.mark_point().encode(
|
||||
alt.ColorValue('grey'),
|
||||
alt.Size('count()',
|
||||
legend=alt.Legend(title='Records in Selection')
|
||||
)
|
||||
).transform_filter(
|
||||
pts
|
||||
)
|
||||
|
||||
bar = alt.Chart(source).mark_bar().encode(
|
||||
x='Major_Genre:N',
|
||||
y='count()',
|
||||
color=alt.condition(pts, alt.ColorValue("steelblue"), alt.ColorValue("grey"))
|
||||
).properties(
|
||||
width=550,
|
||||
height=200
|
||||
).add_selection(pts)
|
||||
bar = alt.Chart(source).mark_bar().encode(
|
||||
x='Major_Genre:N',
|
||||
y='count()',
|
||||
color=alt.condition(pts, alt.ColorValue("steelblue"), alt.ColorValue("grey"))
|
||||
).properties(
|
||||
width=550,
|
||||
height=200
|
||||
).add_selection(pts)
|
||||
|
||||
display(alt.vconcat(
|
||||
rect + circ,
|
||||
bar
|
||||
).resolve_legend(
|
||||
color="independent",
|
||||
size="independent"
|
||||
), target="altair")
|
||||
</py-script>
|
||||
</py-tutor>
|
||||
</section>
|
||||
display(alt.vconcat(
|
||||
rect + circ,
|
||||
bar
|
||||
).resolve_legend(
|
||||
color="independent",
|
||||
size="independent"
|
||||
), target="altair")
|
||||
</py-script>
|
||||
</py-tutor>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Antigravity</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Antigravity</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">Antigravity</a>
|
||||
</div>
|
||||
</nav>
|
||||
<py-tutor modules="antigravity.py">
|
||||
<section class="pyscript">
|
||||
<py-config>
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
]
|
||||
[[fetch]]
|
||||
files = ["./antigravity.py"]
|
||||
</py-config>
|
||||
<b>Based on xkcd: antigravity https://xkcd.com/353/.</b>
|
||||
<py-script>
|
||||
import antigravity
|
||||
antigravity.fly()
|
||||
</py-script>
|
||||
<py-config>
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
]
|
||||
[[fetch]]
|
||||
files = ["./antigravity.py"]
|
||||
</py-config>
|
||||
<b>Based on xkcd: antigravity https://xkcd.com/353/.</b>
|
||||
<py-script>
|
||||
import antigravity
|
||||
antigravity.fly()
|
||||
</py-script>
|
||||
</section>
|
||||
</py-tutor>
|
||||
</body>
|
||||
|
||||
@@ -1,90 +1,91 @@
|
||||
body {
|
||||
margin: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.pyscript {
|
||||
margin: 0.5rem;
|
||||
margin: 0.5rem;
|
||||
}
|
||||
|
||||
.code {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
z-index: 9998;
|
||||
top: 7rem;
|
||||
display: flex;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
z-index: 9998;
|
||||
top: 7rem;
|
||||
}
|
||||
|
||||
@media (max-width: 1300px) {
|
||||
.code:has(> .code-section-visible) {
|
||||
width: 90%;
|
||||
/* Absolute position is messing up the layout on small screens */
|
||||
right: 70px;
|
||||
}
|
||||
.code:has(> .code-section-visible) {
|
||||
width: 90%;
|
||||
/* Absolute position is messing up the layout on small screens */
|
||||
right: 70px;
|
||||
}
|
||||
}
|
||||
|
||||
.code-section-hidden {
|
||||
width: 0px;
|
||||
display: none;
|
||||
width: 0px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.code-section-visible {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
background-color: rgb(45 46 53 / 90%);
|
||||
padding: 1rem;
|
||||
border-radius: 10px 0px 0px 10px;
|
||||
color: #c6c6c8;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
background-color: rgb(45 46 53 / 90%);
|
||||
padding: 1rem;
|
||||
border-radius: 10px 0px 0px 10px;
|
||||
color: #c6c6c8;
|
||||
}
|
||||
.code-section-visible p{
|
||||
margin: 0;
|
||||
font-style: italic;
|
||||
font-size: small;
|
||||
.code-section-visible p {
|
||||
margin: 0;
|
||||
font-style: italic;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.language-html, .language-python {
|
||||
float: left;
|
||||
.language-html,
|
||||
.language-python {
|
||||
float: left;
|
||||
}
|
||||
|
||||
#view-code-button {
|
||||
writing-mode: tb-rl;
|
||||
text-orientation: sideways-right;
|
||||
background-color: #1D1D22;
|
||||
color: white;
|
||||
padding: 0.5rem;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
height: 81px;
|
||||
writing-mode: tb-rl;
|
||||
text-orientation: sideways-right;
|
||||
background-color: #1d1d22;
|
||||
color: white;
|
||||
padding: 0.5rem;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
height: 81px;
|
||||
}
|
||||
|
||||
nav {
|
||||
position: sticky;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
position: sticky;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.logo {
|
||||
padding-right: 10px;
|
||||
font-size: 28px;
|
||||
height: 30px;
|
||||
max-width: inherit;
|
||||
padding-right: 10px;
|
||||
font-size: 28px;
|
||||
height: 30px;
|
||||
max-width: inherit;
|
||||
}
|
||||
|
||||
.title {
|
||||
text-decoration: none;
|
||||
text-decoration-line: none;
|
||||
text-decoration-style: initial;
|
||||
text-decoration-color: initial;
|
||||
font-weight: 400;
|
||||
font-size: 1.5em;
|
||||
line-height: 2em;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
text-decoration-line: none;
|
||||
text-decoration-style: initial;
|
||||
text-decoration-color: initial;
|
||||
font-weight: 400;
|
||||
font-size: 1.5em;
|
||||
line-height: 2em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.app-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.5rem 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.5rem 1rem;
|
||||
}
|
||||
|
||||
@@ -1,70 +1,74 @@
|
||||
.example {
|
||||
margin-bottom: 5rem;
|
||||
margin-bottom: 5rem;
|
||||
}
|
||||
|
||||
.example h2{
|
||||
/* color: #000000; */
|
||||
font-family: "Inconsolata", monospace;
|
||||
font-size: 2.25rem;
|
||||
margin-bottom: 1rem;
|
||||
.example h2 {
|
||||
/* color: #000000; */
|
||||
font-family: "Inconsolata", monospace;
|
||||
font-size: 2.25rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
height: 15rem;
|
||||
background-color: var(--color-secondary);
|
||||
padding: 1rem;
|
||||
border-radius: 10px;
|
||||
height: 15rem;
|
||||
background-color: var(--color-secondary);
|
||||
padding: 1rem;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.card:hover, .card:hover a, .card:hover a:visited, .card:hover h2 {
|
||||
background-color: var(--color-primary);
|
||||
color: #1D1D22
|
||||
.card:hover,
|
||||
.card:hover a,
|
||||
.card:hover a:visited,
|
||||
.card:hover h2 {
|
||||
background-color: var(--color-primary);
|
||||
color: #1d1d22;
|
||||
}
|
||||
|
||||
.card a h2 {
|
||||
color: var(--color-primary);
|
||||
margin: 0;
|
||||
font-family: "Inconsolata", monospace;
|
||||
font-size: 2.25rem;
|
||||
color: var(--color-primary);
|
||||
margin: 0;
|
||||
font-family: "Inconsolata", monospace;
|
||||
font-size: 2.25rem;
|
||||
}
|
||||
|
||||
.card a p {
|
||||
color: var(--text-color);
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
a .card {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.card-content a, .card-content a:visited {
|
||||
color: var(--color-primary);
|
||||
.card-content a,
|
||||
.card-content a:visited {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.container-card {
|
||||
max-width: 1500px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
max-width: 1500px;
|
||||
margin: 0 auto;
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.container-card {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
.container-card {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 900px) {
|
||||
.container-card {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
.container-card {
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,23 +2,24 @@
|
||||
@import "./variables.css";
|
||||
@import "./reset.css";
|
||||
|
||||
|
||||
body {
|
||||
background: #2D2E35 url('https://assets.anaconda.com/production/Content/1650828148240.png?w=3240&auto=compress%2Cformat&fit=crop&dm=1650828161&s=c558dc55e0ed1f8419a892e842a5728f') repeat-x center bottom / 250px;
|
||||
background-attachment: fixed;
|
||||
overflow-x: hidden;
|
||||
color: var(--text-color)
|
||||
background: #2d2e35
|
||||
url("https://assets.anaconda.com/production/Content/1650828148240.png?w=3240&auto=compress%2Cformat&fit=crop&dm=1650828161&s=c558dc55e0ed1f8419a892e842a5728f")
|
||||
repeat-x center bottom / 250px;
|
||||
background-attachment: fixed;
|
||||
overflow-x: hidden;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1510px;
|
||||
margin: auto;
|
||||
padding: 0 2rem;
|
||||
max-width: 1510px;
|
||||
margin: auto;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
.title-main {
|
||||
font-size: 4.25rem;
|
||||
font-family: "Inconsolata", monospace;
|
||||
text-align: center;
|
||||
margin: 2rem 0;
|
||||
font-size: 4.25rem;
|
||||
font-family: "Inconsolata", monospace;
|
||||
text-align: center;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
*,
|
||||
*:after,
|
||||
*:before {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
text-decoration: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 100%;
|
||||
list-style-type: none;
|
||||
font-size: 100%;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
p {
|
||||
font-family: "Inconsolata", monospace;
|
||||
font-weight: 400;
|
||||
font-family: "Inconsolata", monospace;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
:root {
|
||||
--color-primary: #FDA703;
|
||||
--color-secondary: #1D1D22;
|
||||
--text-color: white;
|
||||
--card-shadow: 0px 5px 11px 0px rgb(0 0 0 / 15%);
|
||||
--color-primary: #fda703;
|
||||
--color-secondary: #1d1d22;
|
||||
--text-color: white;
|
||||
--card-shadow: 0px 5px 11px 0px rgb(0 0 0 / 15%);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
@@ -9,18 +9,18 @@
|
||||
</head>
|
||||
<body>
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
for i in range(3):
|
||||
js.console.log('A', i)
|
||||
await asyncio.sleep(0.1)
|
||||
import js
|
||||
import asyncio
|
||||
for i in range(3):
|
||||
js.console.log('A', i)
|
||||
await asyncio.sleep(0.1)
|
||||
</py-script>
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
for i in range(3):
|
||||
js.console.log('B', i)
|
||||
await asyncio.sleep(0.1)
|
||||
import js
|
||||
import asyncio
|
||||
for i in range(3):
|
||||
js.console.log('B', i)
|
||||
await asyncio.sleep(0.1)
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
@@ -9,7 +9,8 @@
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Pyscript - FIRST ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
||||
Pyscript - FIRST ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME LEVEL AS
|
||||
LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
@@ -23,7 +24,8 @@
|
||||
</py-script>
|
||||
</div>
|
||||
<div>
|
||||
Pyscript - SECOND ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
||||
Pyscript - SECOND ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME LEVEL AS
|
||||
LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
@@ -9,7 +9,8 @@
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Pyscript - FIRST ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
||||
Pyscript - FIRST ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME LEVEL AS
|
||||
LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
@@ -23,7 +24,8 @@
|
||||
</py-script>
|
||||
</div>
|
||||
<div>
|
||||
Pyscript - SECOND ASYNC WITH TOP-LEVEL LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
||||
Pyscript - SECOND ASYNC WITH TOP-LEVEL LOOP BLOCKING AWAIT AT SAME LEVEL
|
||||
AS LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
@@ -9,7 +9,8 @@
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Pyscript - FIRST ASYNC WITH NON-BLOCKING AWAIT AT ONE LEVEL LOWER THAN LOOP Pyscript writing to console.log:
|
||||
Pyscript - FIRST ASYNC WITH NON-BLOCKING AWAIT AT ONE LEVEL LOWER THAN
|
||||
LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
@@ -23,7 +24,8 @@
|
||||
</py-script>
|
||||
</div>
|
||||
<div>
|
||||
Pyscript - SECOND ASYNC WITH NON-BLOCKING AWAIT AT ONE LEVEL LOWER THAN LOOP Pyscript writing to console.log:
|
||||
Pyscript - SECOND ASYNC WITH NON-BLOCKING AWAIT AT ONE LEVEL LOWER THAN
|
||||
LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Pyscript - FIRST ASYNC WITH TOP-LEVEL LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Pyscript - FIRST ASYNC WITH TOP-LEVEL LOOP BLOCKING AWAIT AT SAME LEVEL AS
|
||||
LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
for i in range(3):
|
||||
js.console.log('A', i)
|
||||
await asyncio.sleep(2)
|
||||
</py-script>
|
||||
</div>
|
||||
<div>
|
||||
Pyscript - SECOND ASYNC WITH TOP-LEVEL LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
for i in range(3):
|
||||
js.console.log('A', i)
|
||||
await asyncio.sleep(2)
|
||||
</py-script>
|
||||
</div>
|
||||
<div>
|
||||
Pyscript - SECOND ASYNC WITH TOP-LEVEL LOOP BLOCKING AWAIT AT SAME LEVEL
|
||||
AS LOOP Pyscript writing to console.log:
|
||||
<py-script>
|
||||
import js
|
||||
import asyncio
|
||||
|
||||
for i in range(3):
|
||||
js.console.log('B', i)
|
||||
await asyncio.sleep(2)
|
||||
</py-script>
|
||||
</div>
|
||||
</body>
|
||||
for i in range(3):
|
||||
js.console.log('B', i)
|
||||
await asyncio.sleep(2)
|
||||
</py-script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</head>
|
||||
<body>
|
||||
<py-script>
|
||||
import asyncio
|
||||
from itertools import count
|
||||
for i in count():
|
||||
print(f"Count: {i}")
|
||||
await asyncio.sleep(1)
|
||||
import asyncio
|
||||
from itertools import count
|
||||
for i in count():
|
||||
print(f"Count: {i}")
|
||||
await asyncio.sleep(1)
|
||||
</py-script>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,63 +1,79 @@
|
||||
<html><head>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bokeh Example</title>
|
||||
<meta charset="iso-8859-1">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-3.0.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.0.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.0.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.0.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.0.3.min.js"></script>
|
||||
<meta charset="iso-8859-1" />
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-3.0.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.0.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.0.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.0.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.0.3.min.js"
|
||||
></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Bokeh Example</a>
|
||||
</div>
|
||||
</nav>
|
||||
<py-tutor>
|
||||
<section class="pyscript">
|
||||
<div id="myplot"></div>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">Bokeh Example</a>
|
||||
</div>
|
||||
</nav>
|
||||
<py-tutor>
|
||||
<section class="pyscript">
|
||||
<div id="myplot"></div>
|
||||
|
||||
<py-config>
|
||||
packages = [
|
||||
"pandas",
|
||||
"bokeh",
|
||||
"xyzservices"
|
||||
]
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
]
|
||||
</py-config>
|
||||
<py-config>
|
||||
packages = [
|
||||
"pandas",
|
||||
"bokeh",
|
||||
"xyzservices"
|
||||
]
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
]
|
||||
</py-config>
|
||||
|
||||
<py-script id="main">
|
||||
import json
|
||||
import pyodide
|
||||
import json
|
||||
import pyodide
|
||||
|
||||
from js import Bokeh, console, JSON
|
||||
from js import Bokeh, console, JSON
|
||||
|
||||
from bokeh.embed import json_item
|
||||
from bokeh.plotting import figure
|
||||
from bokeh.resources import CDN
|
||||
from bokeh.embed import json_item
|
||||
from bokeh.plotting import figure
|
||||
from bokeh.resources import CDN
|
||||
|
||||
# create a new plot with default tools, using figure
|
||||
p = figure(width=400, height=400)
|
||||
# create a new plot with default tools, using figure
|
||||
p = figure(width=400, height=400)
|
||||
|
||||
# add a circle renderer with x and y coordinates, size, color, and alpha
|
||||
p.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=15, line_color="navy", fill_color="orange", fill_alpha=0.5)
|
||||
p_json = json.dumps(json_item(p, "myplot"))
|
||||
# add a circle renderer with x and y coordinates, size, color, and alpha
|
||||
p.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=15, line_color="navy", fill_color="orange", fill_alpha=0.5)
|
||||
p_json = json.dumps(json_item(p, "myplot"))
|
||||
|
||||
Bokeh.embed.embed_item(JSON.parse(p_json))
|
||||
Bokeh.embed.embed_item(JSON.parse(p_json))
|
||||
</py-script>
|
||||
</section>
|
||||
</py-tutor>
|
||||
|
||||
@@ -1,114 +1,130 @@
|
||||
<html><head>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bokeh Example</title>
|
||||
<meta charset="iso-8859-1">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.3.min.js"></script>
|
||||
<meta charset="iso-8859-1" />
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.3.min.js"
|
||||
></script>
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Bokeh Example</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">Bokeh Example</a>
|
||||
</div>
|
||||
</nav>
|
||||
<py-tutor>
|
||||
<section class="pyscript">
|
||||
<h1>Bokeh Example</h1>
|
||||
<div id="myplot"></div>
|
||||
<h1>Bokeh Example</h1>
|
||||
<div id="myplot"></div>
|
||||
|
||||
<py-config>
|
||||
packages = [
|
||||
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
|
||||
"numpy",
|
||||
]
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
]
|
||||
</py-config>
|
||||
<py-config>
|
||||
packages = [
|
||||
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
|
||||
"numpy",
|
||||
]
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
]
|
||||
</py-config>
|
||||
|
||||
<py-script id="main">
|
||||
import asyncio
|
||||
import json
|
||||
import pyodide
|
||||
<py-script id="main">
|
||||
import asyncio
|
||||
import json
|
||||
import pyodide
|
||||
|
||||
from js import Bokeh, console, JSON
|
||||
from js import Bokeh, console, JSON
|
||||
|
||||
from bokeh import __version__
|
||||
from bokeh.document import Document
|
||||
from bokeh.embed.util import OutputDocumentFor, standalone_docs_json_and_render_items
|
||||
from bokeh.models import Slider, Div
|
||||
from bokeh.layouts import Row
|
||||
from bokeh.protocol.messages.patch_doc import process_document_events
|
||||
from bokeh import __version__
|
||||
from bokeh.document import Document
|
||||
from bokeh.embed.util import OutputDocumentFor, standalone_docs_json_and_render_items
|
||||
from bokeh.models import Slider, Div
|
||||
from bokeh.layouts import Row
|
||||
from bokeh.protocol.messages.patch_doc import process_document_events
|
||||
|
||||
# create a new plot with default tools, using figure
|
||||
p = Slider(start=0.1, end=10, value=1, step=.1, title="Amplitude")
|
||||
div = Div(text=f'Amplitude is: {p.value}')
|
||||
# create a new plot with default tools, using figure
|
||||
p = Slider(start=0.1, end=10, value=1, step=.1, title="Amplitude")
|
||||
div = Div(text=f'Amplitude is: {p.value}')
|
||||
|
||||
def callback(attr, old, new):
|
||||
div.text = f'Amplitude is: {new}'
|
||||
def callback(attr, old, new):
|
||||
div.text = f'Amplitude is: {new}'
|
||||
|
||||
p.on_change('value', callback)
|
||||
p.on_change('value', callback)
|
||||
|
||||
row = Row(children=[p, div])
|
||||
row = Row(children=[p, div])
|
||||
|
||||
def doc_json(model, target):
|
||||
with OutputDocumentFor([model]) as doc:
|
||||
doc.title = ""
|
||||
docs_json, _ = standalone_docs_json_and_render_items(
|
||||
[model], suppress_callback_warning=True
|
||||
)
|
||||
def doc_json(model, target):
|
||||
with OutputDocumentFor([model]) as doc:
|
||||
doc.title = ""
|
||||
docs_json, _ = standalone_docs_json_and_render_items(
|
||||
[model], suppress_callback_warning=True
|
||||
)
|
||||
|
||||
doc_json = list(docs_json.values())[0]
|
||||
root_id = doc_json['roots']['root_ids'][0]
|
||||
doc_json = list(docs_json.values())[0]
|
||||
root_id = doc_json['roots']['root_ids'][0]
|
||||
|
||||
return doc, json.dumps(dict(
|
||||
target_id = target,
|
||||
root_id = root_id,
|
||||
doc = doc_json,
|
||||
version = __version__,
|
||||
))
|
||||
return doc, json.dumps(dict(
|
||||
target_id = target,
|
||||
root_id = root_id,
|
||||
doc = doc_json,
|
||||
version = __version__,
|
||||
))
|
||||
|
||||
def _link_docs(pydoc, jsdoc):
|
||||
def jssync(event):
|
||||
if getattr(event, 'setter_id', None) is not None:
|
||||
return
|
||||
events = [event]
|
||||
json_patch = jsdoc.create_json_patch_string(pyodide.ffi.to_js(events))
|
||||
pydoc.apply_json_patch(json.loads(json_patch))
|
||||
def _link_docs(pydoc, jsdoc):
|
||||
def jssync(event):
|
||||
if getattr(event, 'setter_id', None) is not None:
|
||||
return
|
||||
events = [event]
|
||||
json_patch = jsdoc.create_json_patch_string(pyodide.ffi.to_js(events))
|
||||
pydoc.apply_json_patch(json.loads(json_patch))
|
||||
|
||||
jsdoc.on_change(pyodide.ffi.create_proxy(jssync), pyodide.ffi.to_js(False))
|
||||
jsdoc.on_change(pyodide.ffi.create_proxy(jssync), pyodide.ffi.to_js(False))
|
||||
|
||||
def pysync(event):
|
||||
json_patch, buffers = process_document_events([event], use_buffers=True)
|
||||
buffer_map = {}
|
||||
for (ref, buffer) in buffers:
|
||||
buffer_map[ref['id']] = buffer
|
||||
jsdoc.apply_json_patch(JSON.parse(json_patch), pyodide.ffi.to_js(buffer_map), setter_id='js')
|
||||
def pysync(event):
|
||||
json_patch, buffers = process_document_events([event], use_buffers=True)
|
||||
buffer_map = {}
|
||||
for (ref, buffer) in buffers:
|
||||
buffer_map[ref['id']] = buffer
|
||||
jsdoc.apply_json_patch(JSON.parse(json_patch), pyodide.ffi.to_js(buffer_map), setter_id='js')
|
||||
|
||||
pydoc.on_change(pysync)
|
||||
pydoc.on_change(pysync)
|
||||
|
||||
async def show(plot, target):
|
||||
pydoc, model_json = doc_json(plot, target)
|
||||
views = await Bokeh.embed.embed_item(JSON.parse(model_json))
|
||||
jsdoc = views[0].model.document
|
||||
_link_docs(pydoc, jsdoc)
|
||||
async def show(plot, target):
|
||||
pydoc, model_json = doc_json(plot, target)
|
||||
views = await Bokeh.embed.embed_item(JSON.parse(model_json))
|
||||
jsdoc = views[0].model.document
|
||||
_link_docs(pydoc, jsdoc)
|
||||
|
||||
asyncio.ensure_future(show(row, 'myplot'))
|
||||
</py-script>
|
||||
asyncio.ensure_future(show(row, 'myplot'))
|
||||
</py-script>
|
||||
</section>
|
||||
</py-tutor>
|
||||
</body>
|
||||
|
||||
182
examples/d3.html
182
examples/d3.html
@@ -1,44 +1,45 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>d3: JavaScript & PyScript visualizations side-by-side</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||
<style>
|
||||
.loading {
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
border-top-color: black;
|
||||
animation: spin 1s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
.loading {
|
||||
display: inline-block;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
border-top-color: black;
|
||||
animation: spin 1s ease-in-out infinite;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Simple d3 visualization</a>
|
||||
<a class="title" href="" style="color: #f0ab3c"
|
||||
>Simple d3 visualization</a
|
||||
>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<section class="pyscript">
|
||||
<py-tutor modules="d3.py">
|
||||
<section class="pyscript">
|
||||
<py-tutor modules="d3.py">
|
||||
<py-config>
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
@@ -46,79 +47,88 @@
|
||||
[[fetch]]
|
||||
files = ["./d3.py"]
|
||||
</py-config>
|
||||
</py-tutor>
|
||||
<b>
|
||||
Based on <i><a href="https://observablehq.com/@d3/learn-d3-shapes?collection=@d3/learn-d3>">Learn D3: Shapes</a></i> tutorial.
|
||||
</b>
|
||||
<div style="display: flex; flex-direction: row">
|
||||
<div>
|
||||
<div style="text-align: center">JavaScript version</div>
|
||||
<div id="js" style="width: 400px; height: 400px">
|
||||
<div class="loading"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="text-align: center">PyScript version</div>
|
||||
<div id="py" style="width: 400px; height: 400px">
|
||||
<div class="loading"></div>
|
||||
</div>
|
||||
</py-tutor>
|
||||
<b>
|
||||
Based on
|
||||
<i
|
||||
><a
|
||||
href="https://observablehq.com/@d3/learn-d3-shapes?collection=@d3/learn-d3>"
|
||||
>Learn D3: Shapes</a
|
||||
></i
|
||||
>
|
||||
tutorial.
|
||||
</b>
|
||||
<div style="display: flex; flex-direction: row">
|
||||
<div>
|
||||
<div style="text-align: center">JavaScript version</div>
|
||||
<div id="js" style="width: 400px; height: 400px">
|
||||
<div class="loading"></div>
|
||||
</div>
|
||||
</div>
|
||||
<py-script src="d3.py"></py-script>
|
||||
</section>
|
||||
<div>
|
||||
<div style="text-align: center">PyScript version</div>
|
||||
<div id="py" style="width: 400px; height: 400px">
|
||||
<div class="loading"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<py-script src="d3.py"></py-script>
|
||||
</section>
|
||||
|
||||
<script type="module">
|
||||
<script type="module">
|
||||
const fruits = [
|
||||
{ name: "🍊", count: 21 },
|
||||
{ name: "🍇", count: 13 },
|
||||
{ name: "🍏", count: 8 },
|
||||
{ name: "🍌", count: 5 },
|
||||
{ name: "🍐", count: 3 },
|
||||
{ name: "🍋", count: 2 },
|
||||
{ name: "🍎", count: 1 },
|
||||
{ name: "🍉", count: 1 },
|
||||
];
|
||||
|
||||
const fruits = [
|
||||
{name: "🍊", count: 21},
|
||||
{name: "🍇", count: 13},
|
||||
{name: "🍏", count: 8},
|
||||
{name: "🍌", count: 5},
|
||||
{name: "🍐", count: 3},
|
||||
{name: "🍋", count: 2},
|
||||
{name: "🍎", count: 1},
|
||||
{name: "🍉", count: 1},
|
||||
]
|
||||
const fn = (d) => d.count;
|
||||
const data = d3.pie().value(fn)(fruits);
|
||||
|
||||
const fn = (d) => d.count
|
||||
const data = d3.pie().value(fn)(fruits)
|
||||
const arc = d3
|
||||
.arc()
|
||||
.innerRadius(210)
|
||||
.outerRadius(310)
|
||||
.padRadius(300)
|
||||
.padAngle(2 / 300)
|
||||
.cornerRadius(8);
|
||||
|
||||
const arc = d3.arc()
|
||||
.innerRadius(210)
|
||||
.outerRadius(310)
|
||||
.padRadius(300)
|
||||
.padAngle(2 / 300)
|
||||
.cornerRadius(8)
|
||||
const js = d3.select("#js");
|
||||
js.select(".loading").remove();
|
||||
|
||||
const js = d3.select("#js")
|
||||
js.select(".loading").remove()
|
||||
const svg = js
|
||||
.append("svg")
|
||||
.attr("viewBox", "-320 -320 640 640")
|
||||
.attr("width", "400")
|
||||
.attr("height", "400");
|
||||
|
||||
const svg = js
|
||||
.append("svg")
|
||||
.attr("viewBox", "-320 -320 640 640")
|
||||
.attr("width", "400")
|
||||
.attr("height", "400")
|
||||
for (const d of data) {
|
||||
svg.append("path").style("fill", "steelblue").attr("d", arc(d));
|
||||
|
||||
for (const d of data) {
|
||||
svg.append("path")
|
||||
.style("fill", "steelblue")
|
||||
.attr("d", arc(d))
|
||||
const text = svg
|
||||
.append("text")
|
||||
.style("fill", "white")
|
||||
.attr("transform", `translate(${arc.centroid(d).join(",")})`)
|
||||
.attr("text-anchor", "middle");
|
||||
|
||||
const text = svg.append("text")
|
||||
.style("fill", "white")
|
||||
.attr("transform", `translate(${arc.centroid(d).join(",")})`)
|
||||
.attr("text-anchor", "middle")
|
||||
text
|
||||
.append("tspan")
|
||||
.style("font-size", "24")
|
||||
.attr("x", "0")
|
||||
.text(d.data.name);
|
||||
|
||||
text.append("tspan")
|
||||
.style("font-size", "24")
|
||||
.attr("x", "0").text(d.data.name)
|
||||
|
||||
text.append("tspan")
|
||||
.style("font-size", "18")
|
||||
.attr("x", "0")
|
||||
.attr("dy", "1.3em")
|
||||
.text(d.value)
|
||||
}
|
||||
text
|
||||
.append("tspan")
|
||||
.style("font-size", "18")
|
||||
.attr("x", "0")
|
||||
.attr("dy", "1.3em")
|
||||
.text(d.value);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Folium</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Folium</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">Folium</a>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
@@ -31,40 +31,39 @@
|
||||
</py-config>
|
||||
|
||||
<py-script>
|
||||
import folium
|
||||
import json
|
||||
import pandas as pd
|
||||
import folium
|
||||
import json
|
||||
import pandas as pd
|
||||
|
||||
from pyodide.http import open_url
|
||||
from pyodide.http import open_url
|
||||
|
||||
url = (
|
||||
"https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
|
||||
)
|
||||
state_geo = f"{url}/us-states.json"
|
||||
state_unemployment = f"{url}/US_Unemployment_Oct2012.csv"
|
||||
state_data = pd.read_csv(open_url(state_unemployment))
|
||||
geo_json = json.loads(open_url(state_geo).read())
|
||||
url = (
|
||||
"https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
|
||||
)
|
||||
state_geo = f"{url}/us-states.json"
|
||||
state_unemployment = f"{url}/US_Unemployment_Oct2012.csv"
|
||||
state_data = pd.read_csv(open_url(state_unemployment))
|
||||
geo_json = json.loads(open_url(state_geo).read())
|
||||
|
||||
m = folium.Map(location=[48, -102], zoom_start=3)
|
||||
m = folium.Map(location=[48, -102], zoom_start=3)
|
||||
|
||||
folium.Choropleth(
|
||||
geo_data=geo_json,
|
||||
name="choropleth",
|
||||
data=state_data,
|
||||
columns=["State", "Unemployment"],
|
||||
key_on="feature.id",
|
||||
fill_color="YlGn",
|
||||
fill_opacity=0.7,
|
||||
line_opacity=0.2,
|
||||
legend_name="Unemployment Rate (%)",
|
||||
).add_to(m)
|
||||
folium.Choropleth(
|
||||
geo_data=geo_json,
|
||||
name="choropleth",
|
||||
data=state_data,
|
||||
columns=["State", "Unemployment"],
|
||||
key_on="feature.id",
|
||||
fill_color="YlGn",
|
||||
fill_opacity=0.7,
|
||||
line_opacity=0.2,
|
||||
legend_name="Unemployment Rate (%)",
|
||||
).add_to(m)
|
||||
|
||||
folium.LayerControl().add_to(m)
|
||||
folium.LayerControl().add_to(m)
|
||||
|
||||
display(m, target="folium")
|
||||
display(m, target="folium")
|
||||
</py-script>
|
||||
|
||||
</py-tutor>
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
@@ -13,12 +13,12 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Hello World</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">Hello World</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
</py-config>
|
||||
|
||||
<section class="pyscript">
|
||||
Hello world! <br>
|
||||
Hello world! <br />
|
||||
This is the current date and time, as computed by Python:
|
||||
<py-script>
|
||||
from datetime import datetime
|
||||
|
||||
@@ -1,173 +1,167 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>PyScript demo</title>
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="stylesheet" href="./assets/css/main.css" />
|
||||
<link rel="stylesheet" href="./assets/css/index.css" />
|
||||
</head>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>PyScript demo</title>
|
||||
<link rel="icon" type="image/png" href="favicon.png" />
|
||||
<link rel="stylesheet" href="./assets/css/main.css" />
|
||||
<link rel="stylesheet" href="./assets/css/index.css" />
|
||||
</head>
|
||||
|
||||
<body class="container">
|
||||
<h1 class="title-main">PyScript demos</h1>
|
||||
<section class="example">
|
||||
<h2>Basic examples</h2>
|
||||
<div class="container-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./hello_world.html" target="_blank">
|
||||
<h2>Hello world</h2>
|
||||
</a>
|
||||
<p>
|
||||
A static demo of the <code><py-script></code> tag
|
||||
</p>
|
||||
<body class="container">
|
||||
<h1 class="title-main">PyScript demos</h1>
|
||||
<section class="example">
|
||||
<h2>Basic examples</h2>
|
||||
<div class="container-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./hello_world.html" target="_blank">
|
||||
<h2>Hello world</h2>
|
||||
</a>
|
||||
<p>A static demo of the <code><py-script></code> tag</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./simple_clock.html" target="_blank">
|
||||
<h2>Simple clock</h2>
|
||||
</a>
|
||||
<p>
|
||||
A dynamic demo of the <code><py-script></code> tag
|
||||
</p>
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./simple_clock.html" target="_blank">
|
||||
<h2>Simple clock</h2>
|
||||
</a>
|
||||
<p>A dynamic demo of the <code><py-script></code> tag</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./repl.html" target="_blank">
|
||||
<h2>REPL</h2>
|
||||
</a>
|
||||
<p>
|
||||
A Python REPL (Read Eval Print Loop)
|
||||
</p>
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./repl.html" target="_blank">
|
||||
<h2>REPL</h2>
|
||||
</a>
|
||||
<p>A Python REPL (Read Eval Print Loop)</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./repl2.html" target="_blank">
|
||||
<h2>REPL2</h2>
|
||||
</a>
|
||||
</a>
|
||||
<p>
|
||||
A Python REPL (Read Eval Print Loop) with slightly better formatting
|
||||
A Python REPL (Read Eval Print Loop) with slightly better
|
||||
formatting
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./todo.html" target="_blank">
|
||||
<h2>TODO App</h2>
|
||||
</a>
|
||||
<p>
|
||||
Simple TODO App
|
||||
</p>
|
||||
<p>Simple TODO App</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./todo-pylist.html" target="_blank">
|
||||
<h2>PyScript Native TODO App</h2>
|
||||
</a>
|
||||
<p>
|
||||
Simple TODO App using <code><py-list></code>
|
||||
</p>
|
||||
<p>Simple TODO App using <code><py-list></code></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="example">
|
||||
<h2>MIME Rendering</h2>
|
||||
<div class="container-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<section class="example">
|
||||
<h2>MIME Rendering</h2>
|
||||
<div class="container-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./matplotlib.html" target="_blank">
|
||||
<h2>Matplotlib</h2>
|
||||
</a>
|
||||
<p>
|
||||
Demonstrates rendering a <a href="https://matplotlib.org/" target="_blank">Matplotlib</a> figure as output of the py-script tag
|
||||
Demonstrates rendering a
|
||||
<a href="https://matplotlib.org/" target="_blank">Matplotlib</a>
|
||||
figure as output of the py-script tag
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./altair.html" target="_blank">
|
||||
<h2>
|
||||
Altair
|
||||
</h2>
|
||||
<h2>Altair</h2>
|
||||
</a>
|
||||
<p>
|
||||
Demonstrates rendering a <a href="https://altair-viz.github.io/" target="_blank">Altair</a> plot as output of the py-script tag
|
||||
Demonstrates rendering a
|
||||
<a href="https://altair-viz.github.io/" target="_blank">Altair</a>
|
||||
plot as output of the py-script tag
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./folium.html" target="_blank">
|
||||
<h2>Folium</h2>
|
||||
</a>
|
||||
<p>
|
||||
Demonstrates rendering a
|
||||
<a
|
||||
href="https://python-visualization.github.io/folium/"
|
||||
target="_blank"
|
||||
>Folium</a
|
||||
>
|
||||
map as output of the py-script tag
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./folium.html" target="_blank">
|
||||
<h2>
|
||||
Folium
|
||||
</h2>
|
||||
</a>
|
||||
<p>
|
||||
Demonstrates rendering a
|
||||
<a href="https://python-visualization.github.io/folium/" target="_blank">Folium</a>
|
||||
map as output of the py-script tag
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="example">
|
||||
<h2>JS Interaction</h2>
|
||||
<div class="container-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<section class="example">
|
||||
<h2>JS Interaction</h2>
|
||||
<div class="container-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./d3.html" target="_blank">
|
||||
<h2>
|
||||
Simple d3 visualization
|
||||
</h2>
|
||||
<h2>Simple d3 visualization</h2>
|
||||
</a>
|
||||
<p>
|
||||
Minimal <a href="https://d3js.org/" target="_blank">D3</a>
|
||||
demo demonstrating how to create a visualization
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./webgl/raycaster/index.html" target="_blank">
|
||||
<h2>
|
||||
Webgl Icosahedron Example
|
||||
</h2>
|
||||
<h2>Webgl Icosahedron Example</h2>
|
||||
</a>
|
||||
<p>
|
||||
Demo showing how a Simple <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API" target="_blank">WebGL</a>
|
||||
Demo showing how a Simple
|
||||
<a
|
||||
href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API"
|
||||
target="_blank"
|
||||
>WebGL</a
|
||||
>
|
||||
scene would work in the <code><py-script></code> tag
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="example">
|
||||
<h2>Visualizations & Dashboards</h2>
|
||||
<div class="container-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<section class="example">
|
||||
<h2>Visualizations & Dashboards</h2>
|
||||
<div class="container-card">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./bokeh.html" target="_blank">
|
||||
<h2>
|
||||
Simple Static Bokeh Plot
|
||||
</h2>
|
||||
<h2>Simple Static Bokeh Plot</h2>
|
||||
</a>
|
||||
<p>
|
||||
Minimal Bokeh demo demonstrating how to create a simple
|
||||
@@ -175,10 +169,10 @@
|
||||
plot from code
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./bokeh_interactive.html" target="_blank">
|
||||
<h2 class="text-2xl font-bold text-blue-600">
|
||||
Bokeh Interactive
|
||||
@@ -187,14 +181,14 @@
|
||||
<p>
|
||||
Interactive demo using a
|
||||
<a href="https://bokeh.org/" target="_blank">Bokeh</a>
|
||||
slider widget to dynamically change a value in the page
|
||||
WARNING: This examples takes a little longer to load. So be patient :)
|
||||
slider widget to dynamically change a value in the page WARNING:
|
||||
This examples takes a little longer to load. So be patient :)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./panel_kmeans.html" target="_blank">
|
||||
<h2 class="text-2xl font-bold text-blue-600">
|
||||
KMeans Demo in Panel
|
||||
@@ -203,13 +197,14 @@
|
||||
<p>
|
||||
Interactive KMeans Chart using
|
||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a>
|
||||
WARNING: This examples takes a little longer to load. So be patient :)
|
||||
WARNING: This examples takes a little longer to load. So be
|
||||
patient :)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./panel_stream.html" target="_blank">
|
||||
<h2 class="text-2xl font-bold text-blue-600">
|
||||
Streaming Demo in Panel
|
||||
@@ -218,13 +213,14 @@
|
||||
<p>
|
||||
Interactive Streaming Table and Bokeh plot using
|
||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a>
|
||||
WARNING: This examples takes a little longer to load. So be patient :)
|
||||
WARNING: This examples takes a little longer to load. So be
|
||||
patient :)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./panel.html" target="_blank">
|
||||
<h2 class="text-3xl font-bold text-blue-600">
|
||||
Simple Panel Demo
|
||||
@@ -233,14 +229,14 @@
|
||||
<p>
|
||||
Simple demo showing
|
||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a>
|
||||
widgets interacting with parts of the page
|
||||
WARNING: This examples takes a little longer to load. So be patient :)
|
||||
widgets interacting with parts of the page WARNING: This examples
|
||||
takes a little longer to load. So be patient :)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./panel_deckgl.html" target="_blank">
|
||||
<h2 class="text-2xl font-bold text-blue-600">
|
||||
NYC Taxi Data Panel DeckGL Demo
|
||||
@@ -248,14 +244,16 @@
|
||||
</a>
|
||||
<p>
|
||||
Interactive application exploring the NYC Taxi dataset using
|
||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a> and <a href="https://deck.gl/" target="_blank">DeckGL</a>
|
||||
WARNING: This examples takes a little longer to load. So be patient :)
|
||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a> and
|
||||
<a href="https://deck.gl/" target="_blank">DeckGL</a>
|
||||
WARNING: This examples takes a little longer to load. So be
|
||||
patient :)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<a href="./numpy_canvas_fractals.html" target="_blank">
|
||||
<h2 class="text-2xl font-bold text-blue-600">
|
||||
Fractals with NumPy and canvas
|
||||
@@ -264,13 +262,16 @@
|
||||
<p>
|
||||
Visualization of Mandelbrot and Julia sets with
|
||||
<a href="https://numpy.org/" target="_blank">Numpy</a> and
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API" target="_blank">
|
||||
<a
|
||||
href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API"
|
||||
target="_blank"
|
||||
>
|
||||
HTML5 canvas
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
html, body, ul, li {
|
||||
html,
|
||||
body,
|
||||
ul,
|
||||
li {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
var Bcoin = Mario.Bcoin = function(pos) {
|
||||
var Bcoin = (Mario.Bcoin = function (pos) {
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: level.bcoinSprite(),
|
||||
hitbox: [0,0,16,16]
|
||||
hitbox: [0, 0, 16, 16],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Mario.Util.inherits(Bcoin, Mario.Entity);
|
||||
|
||||
//I'm not sure whether it makes sense to use an array for vel and acc here
|
||||
//in order to keep with convention, or to just use a single value, since
|
||||
//it's literally impossible for these to move left or right.
|
||||
Bcoin.prototype.spawn = function() {
|
||||
Bcoin.prototype.spawn = function () {
|
||||
sounds.coin.currentTime = 0.05;
|
||||
sounds.coin.play();
|
||||
this.idx = level.items.length;
|
||||
@@ -23,9 +22,9 @@
|
||||
this.active = true;
|
||||
this.vel = -12;
|
||||
this.targetpos = this.pos[1] - 32;
|
||||
}
|
||||
};
|
||||
|
||||
Bcoin.prototype.update = function(dt) {
|
||||
Bcoin.prototype.update = function (dt) {
|
||||
if (!this.active) return;
|
||||
|
||||
if (this.vel > 0 && this.pos[1] >= this.targetpos) {
|
||||
@@ -38,8 +37,7 @@
|
||||
this.vel += this.acc;
|
||||
this.pos[1] += this.vel;
|
||||
this.sprite.update(dt);
|
||||
}
|
||||
|
||||
Bcoin.prototype.checkCollisions = function() {;}
|
||||
};
|
||||
|
||||
Bcoin.prototype.checkCollisions = function () {};
|
||||
})();
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
//TODO: clean up the logic for sprite switching.
|
||||
//TODO: There's a weird bug with the collision logic. Look into it.
|
||||
|
||||
var Block = Mario.Block = function(options) {
|
||||
var Block = (Mario.Block = function (options) {
|
||||
this.item = options.item;
|
||||
this.usedSprite = options.usedSprite;
|
||||
this.bounceSprite = options.bounceSprite;
|
||||
@@ -14,26 +13,27 @@
|
||||
Mario.Entity.call(this, {
|
||||
pos: options.pos,
|
||||
sprite: options.sprite,
|
||||
hitbox: [0,0,16,16]
|
||||
hitbox: [0, 0, 16, 16],
|
||||
});
|
||||
|
||||
this.standing = true;
|
||||
}
|
||||
});
|
||||
|
||||
Mario.Util.inherits(Block, Mario.Floor);
|
||||
|
||||
Block.prototype.break = function() {
|
||||
Block.prototype.break = function () {
|
||||
sounds.breakBlock.play();
|
||||
(new Mario.Rubble()).spawn(this.pos);
|
||||
var x = this.pos[0] / 16, y = this.pos[1] / 16;
|
||||
new Mario.Rubble().spawn(this.pos);
|
||||
var x = this.pos[0] / 16,
|
||||
y = this.pos[1] / 16;
|
||||
delete level.blocks[y][x];
|
||||
}
|
||||
};
|
||||
|
||||
Block.prototype.bonk = function(power) {
|
||||
Block.prototype.bonk = function (power) {
|
||||
sounds.bump.play();
|
||||
if (power > 0 && this.breakable) {
|
||||
this.break();
|
||||
} else if (this.standing){
|
||||
} else if (this.standing) {
|
||||
this.standing = false;
|
||||
if (this.item) {
|
||||
this.item.spawn();
|
||||
@@ -51,9 +51,9 @@
|
||||
|
||||
this.vel[1] = -2;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Block.prototype.update = function(dt, gameTime) {
|
||||
Block.prototype.update = function (dt, gameTime) {
|
||||
if (!this.standing) {
|
||||
if (this.pos[1] < this.opos[1] - 8) {
|
||||
this.vel[1] = 2;
|
||||
@@ -68,7 +68,8 @@
|
||||
}
|
||||
} else {
|
||||
if (this.sprite === this.usedSprite) {
|
||||
var x = this.pos[0] / 16, y = this.pos[1] / 16;
|
||||
var x = this.pos[0] / 16,
|
||||
y = this.pos[1] / 16;
|
||||
level.statics[y][x] = new Mario.Floor(this.pos, this.usedSprite);
|
||||
delete level.blocks[y][x];
|
||||
}
|
||||
@@ -76,6 +77,5 @@
|
||||
|
||||
this.pos[1] += this.vel[1];
|
||||
this.sprite.update(dt, gameTime);
|
||||
}
|
||||
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,47 +1,59 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
var Coin = Mario.Coin = function(pos, sprite) {
|
||||
var Coin = (Mario.Coin = function (pos, sprite) {
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: sprite,
|
||||
hitbox: [0,0,16,16]
|
||||
hitbox: [0, 0, 16, 16],
|
||||
});
|
||||
this.idx = level.items.length
|
||||
}
|
||||
this.idx = level.items.length;
|
||||
});
|
||||
|
||||
Mario.Util.inherits(Coin, Mario.Entity);
|
||||
|
||||
Coin.prototype.isPlayerCollided = function() {
|
||||
Coin.prototype.isPlayerCollided = function () {
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [this.pos[0] + this.hitbox[0], this.pos[1] + this.hitbox[1]];
|
||||
var hpos2 = [player.pos[0] + player.hitbox[0], player.pos[1] + player.hitbox[1]];
|
||||
var hpos2 = [
|
||||
player.pos[0] + player.hitbox[0],
|
||||
player.pos[1] + player.hitbox[1],
|
||||
];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+player.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+player.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
if (
|
||||
!(
|
||||
hpos1[0] > hpos2[0] + player.hitbox[2] ||
|
||||
hpos1[0] + this.hitbox[2] < hpos2[0]
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!(
|
||||
hpos1[1] > hpos2[1] + player.hitbox[3] ||
|
||||
hpos1[1] + this.hitbox[3] < hpos2[1]
|
||||
)
|
||||
) {
|
||||
this.collect();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Coin.prototype.render = function(ctx, vX, vY) {
|
||||
Coin.prototype.render = function (ctx, vX, vY) {
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
}
|
||||
};
|
||||
|
||||
//money is not affected by gravity, you see.
|
||||
Coin.prototype.update = function(dt) {
|
||||
Coin.prototype.update = function (dt) {
|
||||
this.sprite.update(dt);
|
||||
}
|
||||
Coin.prototype.checkCollisions = function() {
|
||||
};
|
||||
Coin.prototype.checkCollisions = function () {
|
||||
this.isPlayerCollided();
|
||||
}
|
||||
};
|
||||
|
||||
Coin.prototype.collect = function() {
|
||||
Coin.prototype.collect = function () {
|
||||
sounds.coin.currentTime = 0.05;
|
||||
sounds.coin.play();
|
||||
player.coins += 1;
|
||||
delete level.items[this.idx]
|
||||
}
|
||||
delete level.items[this.idx];
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
var Entity = Mario.Entity = function(options) {
|
||||
this.vel = [0,0];
|
||||
this.acc = [0,0];
|
||||
this.standing = true;
|
||||
this.pos = options.pos;
|
||||
this.sprite = options.sprite;
|
||||
this.hitbox = options.hitbox;
|
||||
this.left = false;
|
||||
}
|
||||
var Entity = (Mario.Entity = function (options) {
|
||||
this.vel = [0, 0];
|
||||
this.acc = [0, 0];
|
||||
this.standing = true;
|
||||
this.pos = options.pos;
|
||||
this.sprite = options.sprite;
|
||||
this.hitbox = options.hitbox;
|
||||
this.left = false;
|
||||
});
|
||||
|
||||
Entity.prototype.render = function(ctx, vX, vY) {
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY)
|
||||
}
|
||||
Entity.prototype.render = function (ctx, vX, vY) {
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
};
|
||||
|
||||
Entity.prototype.collideWall = function(wall) {
|
||||
//the wall will always be a 16x16 block with hitbox = [0,0,16,16].
|
||||
if (this.pos[0] > wall.pos[0]) {
|
||||
//from the right
|
||||
this.pos[0] = wall.pos[0] + wall.hitbox[2] - this.hitbox[0];
|
||||
this.vel[0] = Math.max(0, this.vel[0]);
|
||||
this.acc[0] = Math.max(0, this.acc[0]);
|
||||
} else {
|
||||
this.pos[0] = wall.pos[0] + wall.hitbox[0] - this.hitbox[2] - this.hitbox[0];
|
||||
this.vel[0] = Math.min(0, this.vel[0]);
|
||||
this.acc[0] = Math.min(0, this.acc[0]);
|
||||
}
|
||||
}
|
||||
Entity.prototype.collideWall = function (wall) {
|
||||
//the wall will always be a 16x16 block with hitbox = [0,0,16,16].
|
||||
if (this.pos[0] > wall.pos[0]) {
|
||||
//from the right
|
||||
this.pos[0] = wall.pos[0] + wall.hitbox[2] - this.hitbox[0];
|
||||
this.vel[0] = Math.max(0, this.vel[0]);
|
||||
this.acc[0] = Math.max(0, this.acc[0]);
|
||||
} else {
|
||||
this.pos[0] =
|
||||
wall.pos[0] + wall.hitbox[0] - this.hitbox[2] - this.hitbox[0];
|
||||
this.vel[0] = Math.min(0, this.vel[0]);
|
||||
this.acc[0] = Math.min(0, this.acc[0]);
|
||||
}
|
||||
};
|
||||
|
||||
Entity.prototype.bump = function() {;}
|
||||
Entity.prototype.bump = function () {};
|
||||
})();
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
var Fireball = Mario.Fireball = function(pos) {
|
||||
var Fireball = (Mario.Fireball = function (pos) {
|
||||
this.hit = 0;
|
||||
this.standing = false;
|
||||
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: new Mario.Sprite('sprites/items.png', [96, 144], [8,8], 5, [0,1,2,3]),
|
||||
hitbox: [0,0,8,8]
|
||||
sprite: new Mario.Sprite(
|
||||
"sprites/items.png",
|
||||
[96, 144],
|
||||
[8, 8],
|
||||
5,
|
||||
[0, 1, 2, 3],
|
||||
),
|
||||
hitbox: [0, 0, 8, 8],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Mario.Util.inherits(Fireball, Mario.Entity);
|
||||
|
||||
Fireball.prototype.spawn = function(left) {
|
||||
Fireball.prototype.spawn = function (left) {
|
||||
sounds.fireball.currentTime = 0;
|
||||
sounds.fireball.play();
|
||||
if (fireballs[0]) {
|
||||
@@ -25,20 +30,20 @@
|
||||
this.idx = 0;
|
||||
fireballs[0] = this;
|
||||
}
|
||||
this.vel[0] = (left ? -5 : 5);
|
||||
this.vel[0] = left ? -5 : 5;
|
||||
this.standing = false;
|
||||
this.vel[1] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
Fireball.prototype.render = function(ctx, vX, vY) {
|
||||
Fireball.prototype.render = function (ctx, vX, vY) {
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
}
|
||||
};
|
||||
|
||||
Fireball.prototype.update = function(dt) {
|
||||
Fireball.prototype.update = function (dt) {
|
||||
if (this.hit == 1) {
|
||||
this.sprite.pos = [96, 160];
|
||||
this.sprite.size = [16,16];
|
||||
this.sprite.frames = [0,1,2];
|
||||
this.sprite.size = [16, 16];
|
||||
this.sprite.frames = [0, 1, 2];
|
||||
this.sprite.speed = 8;
|
||||
this.hit += 1;
|
||||
return;
|
||||
@@ -67,13 +72,13 @@
|
||||
this.hit = 1;
|
||||
}
|
||||
this.sprite.update(dt);
|
||||
}
|
||||
};
|
||||
|
||||
Fireball.prototype.collideWall = function() {
|
||||
Fireball.prototype.collideWall = function () {
|
||||
if (!this.hit) this.hit = 1;
|
||||
}
|
||||
};
|
||||
|
||||
Fireball.prototype.checkCollisions = function() {
|
||||
Fireball.prototype.checkCollisions = function () {
|
||||
if (this.hit) return;
|
||||
var h = this.pos[1] % 16 < 8 ? 1 : 2;
|
||||
var w = this.pos[0] % 16 < 8 ? 1 : 2;
|
||||
@@ -99,28 +104,39 @@
|
||||
}
|
||||
|
||||
var that = this;
|
||||
level.enemies.forEach(function(enemy){
|
||||
if (enemy.flipping || enemy.pos[0] - vX > 336){ //stop checking once we get to far away dudes.
|
||||
level.enemies.forEach(function (enemy) {
|
||||
if (enemy.flipping || enemy.pos[0] - vX > 336) {
|
||||
//stop checking once we get to far away dudes.
|
||||
return;
|
||||
} else {
|
||||
that.isCollideWith(enemy);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Fireball.prototype.isCollideWith = function(ent) {
|
||||
Fireball.prototype.isCollideWith = function (ent) {
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [this.pos[0] + this.hitbox[0], this.pos[1] + this.hitbox[1]];
|
||||
var hpos2 = [ent.pos[0] + ent.hitbox[0], ent.pos[1] + ent.hitbox[1]];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+ent.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+ent.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
if (
|
||||
!(
|
||||
hpos1[0] > hpos2[0] + ent.hitbox[2] ||
|
||||
hpos1[0] + this.hitbox[2] < hpos2[0]
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!(
|
||||
hpos1[1] > hpos2[1] + ent.hitbox[3] ||
|
||||
hpos1[1] + this.hitbox[3] < hpos2[1]
|
||||
)
|
||||
) {
|
||||
this.hit = 1;
|
||||
ent.bump();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Fireball.prototype.bump = function() {;}
|
||||
Fireball.prototype.bump = function () {};
|
||||
})();
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
var Fireflower = Mario.Fireflower = function(pos) {
|
||||
var Fireflower = (Mario.Fireflower = function (pos) {
|
||||
this.spawning = false;
|
||||
this.waiting = 0;
|
||||
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: level.fireFlowerSprite,
|
||||
hitbox: [0,0,16,16]
|
||||
hitbox: [0, 0, 16, 16],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Mario.Util.inherits(Fireflower, Mario.Entity);
|
||||
|
||||
Fireflower.prototype.render = function(ctx, vX, vY) {
|
||||
Fireflower.prototype.render = function (ctx, vX, vY) {
|
||||
if (this.spawning > 1) return;
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
}
|
||||
};
|
||||
|
||||
Fireflower.prototype.spawn = function() {
|
||||
Fireflower.prototype.spawn = function () {
|
||||
sounds.itemAppear.play();
|
||||
this.idx = level.items.length;
|
||||
level.items.push(this);
|
||||
@@ -28,12 +27,12 @@
|
||||
this.targetpos = [];
|
||||
this.targetpos[0] = this.pos[0];
|
||||
this.targetpos[1] = this.pos[1] - 16;
|
||||
}
|
||||
};
|
||||
|
||||
Fireflower.prototype.update = function(dt) {
|
||||
Fireflower.prototype.update = function (dt) {
|
||||
if (this.spawning > 1) {
|
||||
this.spawning -= 1;
|
||||
if (this.spawning == 1) this.vel[1] = -.5;
|
||||
if (this.spawning == 1) this.vel[1] = -0.5;
|
||||
return;
|
||||
}
|
||||
if (this.spawning) {
|
||||
@@ -44,31 +43,45 @@
|
||||
}
|
||||
}
|
||||
|
||||
this.vel[1] += this.acc[1];
|
||||
this.pos[0] += this.vel[0];
|
||||
this.pos[1] += this.vel[1];
|
||||
this.sprite.update(dt);
|
||||
}
|
||||
this.vel[1] += this.acc[1];
|
||||
this.pos[0] += this.vel[0];
|
||||
this.pos[1] += this.vel[1];
|
||||
this.sprite.update(dt);
|
||||
};
|
||||
|
||||
Fireflower.prototype.checkCollisions = function() {
|
||||
if (this.spawning) {return;}
|
||||
Fireflower.prototype.checkCollisions = function () {
|
||||
if (this.spawning) {
|
||||
return;
|
||||
}
|
||||
this.isPlayerCollided();
|
||||
}
|
||||
};
|
||||
|
||||
Fireflower.prototype.isPlayerCollided = function() {
|
||||
Fireflower.prototype.isPlayerCollided = function () {
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [this.pos[0] + this.hitbox[0], this.pos[1] + this.hitbox[1]];
|
||||
var hpos2 = [player.pos[0] + player.hitbox[0], player.pos[1] + player.hitbox[1]];
|
||||
var hpos2 = [
|
||||
player.pos[0] + player.hitbox[0],
|
||||
player.pos[1] + player.hitbox[1],
|
||||
];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+player.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+player.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
if (
|
||||
!(
|
||||
hpos1[0] > hpos2[0] + player.hitbox[2] ||
|
||||
hpos1[0] + this.hitbox[2] < hpos2[0]
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!(
|
||||
hpos1[1] > hpos2[1] + player.hitbox[3] ||
|
||||
hpos1[1] + this.hitbox[3] < hpos2[1]
|
||||
)
|
||||
) {
|
||||
player.powerUp(this.idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//This should never be called, but just in case.
|
||||
Fireflower.prototype.bump = function() {;}
|
||||
|
||||
Fireflower.prototype.bump = function () {};
|
||||
})();
|
||||
|
||||
@@ -1,47 +1,45 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
Flag = Mario.Flag = function(pos) {
|
||||
Flag = Mario.Flag = function (pos) {
|
||||
//afaik flags always have the same height and Y-position
|
||||
this.pos = [pos, 49];
|
||||
this.hitbox = [0,0,0,0];
|
||||
this.vel = [0,0];
|
||||
this.acc = [0,0];
|
||||
}
|
||||
this.hitbox = [0, 0, 0, 0];
|
||||
this.vel = [0, 0];
|
||||
this.acc = [0, 0];
|
||||
};
|
||||
|
||||
Flag.prototype.collideWall = function() {;
|
||||
}
|
||||
Flag.prototype.collideWall = function () {};
|
||||
|
||||
Flag.prototype.update = function(dt){
|
||||
Flag.prototype.update = function (dt) {
|
||||
if (!this.done && this.pos[1] >= 170) {
|
||||
this.vel = [0,0];
|
||||
this.vel = [0, 0];
|
||||
this.pos[1] = 170;
|
||||
player.exit();
|
||||
this.done = true;
|
||||
}
|
||||
this.pos[1] += this.vel[1];
|
||||
}
|
||||
};
|
||||
|
||||
Flag.prototype.checkCollisions = function() {
|
||||
Flag.prototype.checkCollisions = function () {
|
||||
this.isPlayerCollided();
|
||||
}
|
||||
};
|
||||
|
||||
Flag.prototype.isPlayerCollided = function() {
|
||||
Flag.prototype.isPlayerCollided = function () {
|
||||
if (this.hit) return;
|
||||
if (player.pos[0] + 8 >= this.pos[0]) {
|
||||
music.overworld.pause();
|
||||
sounds.flagpole.play();
|
||||
setTimeout(function() {
|
||||
setTimeout(function () {
|
||||
music.clear.play();
|
||||
}, 2000);
|
||||
this.hit = true;
|
||||
player.flag();
|
||||
this.vel = [0, 2];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Flag.prototype.render = function() {
|
||||
level.flagpoleSprites[2].render(ctx, this.pos[0]-8, this.pos[1], vX, vY);
|
||||
}
|
||||
Flag.prototype.render = function () {
|
||||
level.flagpoleSprites[2].render(ctx, this.pos[0] - 8, this.pos[1], vX, vY);
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,56 +1,75 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
var Floor = Mario.Floor = function(pos, sprite) {
|
||||
var Floor = (Mario.Floor = function (pos, sprite) {
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: sprite,
|
||||
hitbox: [0, 0, 16, 16],
|
||||
});
|
||||
});
|
||||
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: sprite,
|
||||
hitbox: [0,0,16,16]
|
||||
});
|
||||
}
|
||||
Mario.Util.inherits(Floor, Mario.Entity);
|
||||
|
||||
Mario.Util.inherits(Floor, Mario.Entity);
|
||||
Floor.prototype.isCollideWith = function (ent) {
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [
|
||||
Math.floor(this.pos[0] + this.hitbox[0]),
|
||||
Math.floor(this.pos[1] + this.hitbox[1]),
|
||||
];
|
||||
var hpos2 = [
|
||||
Math.floor(ent.pos[0] + ent.hitbox[0]),
|
||||
Math.floor(ent.pos[1] + ent.hitbox[1]),
|
||||
];
|
||||
|
||||
Floor.prototype.isCollideWith = function (ent) {
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [Math.floor(this.pos[0] + this.hitbox[0]), Math.floor(this.pos[1] + this.hitbox[1])];
|
||||
var hpos2 = [Math.floor(ent.pos[0] + ent.hitbox[0]), Math.floor(ent.pos[1] + ent.hitbox[1])];
|
||||
//if the hitboxes actually overlap
|
||||
if (
|
||||
!(
|
||||
hpos1[0] > hpos2[0] + ent.hitbox[2] ||
|
||||
hpos1[0] + this.hitbox[2] < hpos2[0]
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!(
|
||||
hpos1[1] > hpos2[1] + ent.hitbox[3] ||
|
||||
hpos1[1] + this.hitbox[3] < hpos2[1]
|
||||
)
|
||||
) {
|
||||
if (!this.standing) {
|
||||
ent.bump();
|
||||
} else {
|
||||
//if the entity is over the block, it's basically floor
|
||||
var center = hpos2[0] + ent.hitbox[2] / 2;
|
||||
if (Math.abs(hpos2[1] + ent.hitbox[3] - hpos1[1]) <= ent.vel[1]) {
|
||||
if (level.statics[this.pos[1] / 16 - 1][this.pos[0] / 16]) {
|
||||
return;
|
||||
}
|
||||
ent.vel[1] = 0;
|
||||
ent.pos[1] = hpos1[1] - ent.hitbox[3] - ent.hitbox[1];
|
||||
ent.standing = true;
|
||||
if (ent instanceof Mario.Player) {
|
||||
ent.jumping = 0;
|
||||
}
|
||||
} else if (
|
||||
Math.abs(hpos2[1] - hpos1[1] - this.hitbox[3]) > ent.vel[1] &&
|
||||
center + 2 >= hpos1[0] &&
|
||||
center - 2 <= hpos1[0] + this.hitbox[2]
|
||||
) {
|
||||
//ent is under the block.
|
||||
ent.vel[1] = 0;
|
||||
ent.pos[1] = hpos1[1] + this.hitbox[3];
|
||||
if (ent instanceof Mario.Player) {
|
||||
this.bonk(ent.power);
|
||||
ent.jumping = 0;
|
||||
}
|
||||
} else {
|
||||
//entity is hitting it from the side, we're a wall
|
||||
ent.collideWall(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+ent.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+ent.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
if (!this.standing) {
|
||||
ent.bump();
|
||||
} else {
|
||||
//if the entity is over the block, it's basically floor
|
||||
var center = hpos2[0] + ent.hitbox[2] / 2;
|
||||
if (Math.abs(hpos2[1] + ent.hitbox[3] - hpos1[1]) <= ent.vel[1]) {
|
||||
if (level.statics[(this.pos[1] / 16) - 1][this.pos[0] / 16]) {return};
|
||||
ent.vel[1] = 0;
|
||||
ent.pos[1] = hpos1[1] - ent.hitbox[3] - ent.hitbox[1];
|
||||
ent.standing = true;
|
||||
if (ent instanceof Mario.Player) {
|
||||
ent.jumping = 0;
|
||||
}
|
||||
} else if (Math.abs(hpos2[1] - hpos1[1] - this.hitbox[3]) > ent.vel[1] &&
|
||||
center + 2 >= hpos1[0] && center - 2 <= hpos1[0] + this.hitbox[2]) {
|
||||
//ent is under the block.
|
||||
ent.vel[1] = 0;
|
||||
ent.pos[1] = hpos1[1] + this.hitbox[3];
|
||||
if (ent instanceof Mario.Player) {
|
||||
this.bonk(ent.power);
|
||||
ent.jumping = 0;
|
||||
}
|
||||
} else {
|
||||
//entity is hitting it from the side, we're a wall
|
||||
ent.collideWall(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Floor.prototype.bonk = function() {;}
|
||||
Floor.prototype.bonk = function () {};
|
||||
})();
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
var requestAnimFrame = (function(){
|
||||
return window.requestAnimationFrame ||
|
||||
var requestAnimFrame = (function () {
|
||||
return (
|
||||
window.requestAnimationFrame ||
|
||||
window.webkitRequestAnimationFrame ||
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.oRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame ||
|
||||
function(callback){
|
||||
window.mozRequestAnimationFrame ||
|
||||
window.oRequestAnimationFrame ||
|
||||
window.msRequestAnimationFrame ||
|
||||
function (callback) {
|
||||
window.setTimeout(callback, 1000 / 60);
|
||||
};
|
||||
}
|
||||
);
|
||||
})();
|
||||
|
||||
//create the canvas
|
||||
var canvas = document.createElement("canvas");
|
||||
var ctx = canvas.getContext('2d');
|
||||
var ctx = canvas.getContext("2d");
|
||||
var updateables = [];
|
||||
var fireballs = [];
|
||||
var player = new Mario.Player([0,0]);
|
||||
var player = new Mario.Player([0, 0]);
|
||||
|
||||
//we might have to get the size and calculate the scaling
|
||||
//but this method should let us make it however big.
|
||||
@@ -23,23 +25,23 @@ var player = new Mario.Player([0,0]);
|
||||
//TODO: fiddling with scaled sprites looks BETTER, but not perfect. Hmm.
|
||||
canvas.width = 762;
|
||||
canvas.height = 720;
|
||||
ctx.scale(3,3);
|
||||
ctx.scale(3, 3);
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
//viewport
|
||||
var vX = 0,
|
||||
vY = 0,
|
||||
vWidth = 256,
|
||||
vHeight = 240;
|
||||
vY = 0,
|
||||
vWidth = 256,
|
||||
vHeight = 240;
|
||||
|
||||
//load our images
|
||||
resources.load([
|
||||
'sprites/player.png',
|
||||
'sprites/enemy.png',
|
||||
'sprites/tiles.png',
|
||||
'sprites/playerl.png',
|
||||
'sprites/items.png',
|
||||
'sprites/enemyr.png',
|
||||
"sprites/player.png",
|
||||
"sprites/enemy.png",
|
||||
"sprites/tiles.png",
|
||||
"sprites/playerl.png",
|
||||
"sprites/items.png",
|
||||
"sprites/enemyr.png",
|
||||
]);
|
||||
|
||||
resources.onReady(init);
|
||||
@@ -51,24 +53,24 @@ var music;
|
||||
var lastTime;
|
||||
function init() {
|
||||
music = {
|
||||
overworld: new Audio('sounds/aboveground_bgm.ogg'),
|
||||
underground: new Audio('sounds/underground_bgm.ogg'),
|
||||
clear: new Audio('sounds/stage_clear.wav'),
|
||||
death: new Audio('sounds/mariodie.wav')
|
||||
overworld: new Audio("sounds/aboveground_bgm.ogg"),
|
||||
underground: new Audio("sounds/underground_bgm.ogg"),
|
||||
clear: new Audio("sounds/stage_clear.wav"),
|
||||
death: new Audio("sounds/mariodie.wav"),
|
||||
};
|
||||
sounds = {
|
||||
smallJump: new Audio('sounds/jump-small.wav'),
|
||||
bigJump: new Audio('sounds/jump-super.wav'),
|
||||
breakBlock: new Audio('sounds/breakblock.wav'),
|
||||
bump: new Audio('sounds/bump.wav'),
|
||||
coin: new Audio('sounds/coin.wav'),
|
||||
fireball: new Audio('sounds/fireball.wav'),
|
||||
flagpole: new Audio('sounds/flagpole.wav'),
|
||||
kick: new Audio('sounds/kick.wav'),
|
||||
pipe: new Audio('sounds/pipe.wav'),
|
||||
itemAppear: new Audio('sounds/itemAppear.wav'),
|
||||
powerup: new Audio('sounds/powerup.wav'),
|
||||
stomp: new Audio('sounds/stomp.wav')
|
||||
smallJump: new Audio("sounds/jump-small.wav"),
|
||||
bigJump: new Audio("sounds/jump-super.wav"),
|
||||
breakBlock: new Audio("sounds/breakblock.wav"),
|
||||
bump: new Audio("sounds/bump.wav"),
|
||||
coin: new Audio("sounds/coin.wav"),
|
||||
fireball: new Audio("sounds/fireball.wav"),
|
||||
flagpole: new Audio("sounds/flagpole.wav"),
|
||||
kick: new Audio("sounds/kick.wav"),
|
||||
pipe: new Audio("sounds/pipe.wav"),
|
||||
itemAppear: new Audio("sounds/itemAppear.wav"),
|
||||
powerup: new Audio("sounds/powerup.wav"),
|
||||
stomp: new Audio("sounds/stomp.wav"),
|
||||
};
|
||||
Mario.oneone();
|
||||
lastTime = Date.now();
|
||||
@@ -101,28 +103,29 @@ function update(dt) {
|
||||
function handleInput(dt) {
|
||||
if (player.piping || player.dying || player.noInput) return; //don't accept input
|
||||
|
||||
if (input.isDown('RUN')){
|
||||
if (input.isDown("RUN")) {
|
||||
player.run();
|
||||
} else {
|
||||
player.noRun();
|
||||
}
|
||||
if (input.isDown('JUMP')) {
|
||||
if (input.isDown("JUMP")) {
|
||||
player.jump();
|
||||
} else {
|
||||
//we need this to handle the timing for how long you hold it
|
||||
player.noJump();
|
||||
}
|
||||
|
||||
if (input.isDown('DOWN')) {
|
||||
if (input.isDown("DOWN")) {
|
||||
player.crouch();
|
||||
} else {
|
||||
player.noCrouch();
|
||||
}
|
||||
|
||||
if (input.isDown('LEFT')) { // 'd' or left arrow
|
||||
if (input.isDown("LEFT")) {
|
||||
// 'd' or left arrow
|
||||
player.moveLeft();
|
||||
}
|
||||
else if (input.isDown('RIGHT')) { // 'k' or right arrow
|
||||
} else if (input.isDown("RIGHT")) {
|
||||
// 'k' or right arrow
|
||||
player.moveRight();
|
||||
} else {
|
||||
player.noWalk();
|
||||
@@ -132,51 +135,54 @@ function handleInput(dt) {
|
||||
//update all the moving stuff
|
||||
function updateEntities(dt, gameTime) {
|
||||
player.update(dt, vX);
|
||||
updateables.forEach (function(ent) {
|
||||
updateables.forEach(function (ent) {
|
||||
ent.update(dt, gameTime);
|
||||
});
|
||||
|
||||
//This should stop the jump when he switches sides on the flag.
|
||||
if (player.exiting) {
|
||||
if (player.pos[0] > vX + 96)
|
||||
vX = player.pos[0] - 96
|
||||
}else if (level.scrolling && player.pos[0] > vX + 80) {
|
||||
if (player.pos[0] > vX + 96) vX = player.pos[0] - 96;
|
||||
} else if (level.scrolling && player.pos[0] > vX + 80) {
|
||||
vX = player.pos[0] - 80;
|
||||
}
|
||||
|
||||
if (player.powering.length !== 0 || player.dying) { return; }
|
||||
level.items.forEach (function(ent) {
|
||||
if (player.powering.length !== 0 || player.dying) {
|
||||
return;
|
||||
}
|
||||
level.items.forEach(function (ent) {
|
||||
ent.update(dt);
|
||||
});
|
||||
|
||||
level.enemies.forEach (function(ent) {
|
||||
level.enemies.forEach(function (ent) {
|
||||
ent.update(dt, vX);
|
||||
});
|
||||
|
||||
fireballs.forEach(function(fireball) {
|
||||
fireballs.forEach(function (fireball) {
|
||||
fireball.update(dt);
|
||||
});
|
||||
level.pipes.forEach (function(pipe) {
|
||||
level.pipes.forEach(function (pipe) {
|
||||
pipe.update(dt);
|
||||
});
|
||||
}
|
||||
|
||||
//scan for collisions
|
||||
function checkCollisions() {
|
||||
if (player.powering.length !== 0 || player.dying) { return; }
|
||||
if (player.powering.length !== 0 || player.dying) {
|
||||
return;
|
||||
}
|
||||
player.checkCollisions();
|
||||
|
||||
//Apparently for each will just skip indices where things were deleted.
|
||||
level.items.forEach(function(item) {
|
||||
level.items.forEach(function (item) {
|
||||
item.checkCollisions();
|
||||
});
|
||||
level.enemies.forEach (function(ent) {
|
||||
level.enemies.forEach(function (ent) {
|
||||
ent.checkCollisions();
|
||||
});
|
||||
fireballs.forEach(function(fireball){
|
||||
fireballs.forEach(function (fireball) {
|
||||
fireball.checkCollisions();
|
||||
});
|
||||
level.pipes.forEach (function(pipe) {
|
||||
level.pipes.forEach(function (pipe) {
|
||||
pipe.checkCollisions();
|
||||
});
|
||||
}
|
||||
@@ -189,8 +195,8 @@ function render() {
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
//scenery gets drawn first to get layering right.
|
||||
for(var i = 0; i < 15; i++) {
|
||||
for (var j = Math.floor(vX / 16) - 1; j < Math.floor(vX / 16) + 20; j++){
|
||||
for (var i = 0; i < 15; i++) {
|
||||
for (var j = Math.floor(vX / 16) - 1; j < Math.floor(vX / 16) + 20; j++) {
|
||||
if (level.scenery[i][j]) {
|
||||
renderEntity(level.scenery[i][j]);
|
||||
}
|
||||
@@ -198,23 +204,21 @@ function render() {
|
||||
}
|
||||
|
||||
//then items
|
||||
level.items.forEach (function (item) {
|
||||
level.items.forEach(function (item) {
|
||||
renderEntity(item);
|
||||
});
|
||||
|
||||
level.enemies.forEach (function(enemy) {
|
||||
level.enemies.forEach(function (enemy) {
|
||||
renderEntity(enemy);
|
||||
});
|
||||
|
||||
|
||||
|
||||
fireballs.forEach(function(fireball) {
|
||||
fireballs.forEach(function (fireball) {
|
||||
renderEntity(fireball);
|
||||
})
|
||||
});
|
||||
|
||||
//then we draw every static object.
|
||||
for(var i = 0; i < 15; i++) {
|
||||
for (var j = Math.floor(vX / 16) - 1; j < Math.floor(vX / 16) + 20; j++){
|
||||
for (var i = 0; i < 15; i++) {
|
||||
for (var j = Math.floor(vX / 16) - 1; j < Math.floor(vX / 16) + 20; j++) {
|
||||
if (level.statics[i][j]) {
|
||||
renderEntity(level.statics[i][j]);
|
||||
}
|
||||
@@ -231,7 +235,7 @@ function render() {
|
||||
}
|
||||
|
||||
//Mario goes INTO pipes, so naturally they go after.
|
||||
level.pipes.forEach (function(pipe) {
|
||||
level.pipes.forEach(function (pipe) {
|
||||
renderEntity(pipe);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
//TODO: On console the hitbox is smaller. Measure it and edit this.
|
||||
|
||||
var Goomba = Mario.Goomba = function(pos, sprite) {
|
||||
var Goomba = (Mario.Goomba = function (pos, sprite) {
|
||||
this.dying = false;
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: sprite,
|
||||
hitbox: [0,0,16,16]
|
||||
hitbox: [0, 0, 16, 16],
|
||||
});
|
||||
this.vel[0] = -0.5;
|
||||
this.idx = level.enemies.length;
|
||||
};
|
||||
});
|
||||
|
||||
Goomba.prototype.render = function(ctx, vX, vY) {
|
||||
Goomba.prototype.render = function (ctx, vX, vY) {
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
};
|
||||
|
||||
Goomba.prototype.update = function(dt, vX) {
|
||||
if (this.pos[0] - vX > 336) { //if we're too far away, do nothing.
|
||||
Goomba.prototype.update = function (dt, vX) {
|
||||
if (this.pos[0] - vX > 336) {
|
||||
//if we're too far away, do nothing.
|
||||
return;
|
||||
} else if (this.pos[0] - vX < -32) {
|
||||
delete level.enemies[this.idx];
|
||||
@@ -39,11 +39,11 @@
|
||||
this.sprite.update(dt);
|
||||
};
|
||||
|
||||
Goomba.prototype.collideWall = function() {
|
||||
Goomba.prototype.collideWall = function () {
|
||||
this.vel[0] = -this.vel[0];
|
||||
};
|
||||
|
||||
Goomba.prototype.checkCollisions = function() {
|
||||
Goomba.prototype.checkCollisions = function () {
|
||||
if (this.flipping) {
|
||||
return;
|
||||
}
|
||||
@@ -70,10 +70,12 @@
|
||||
}
|
||||
}
|
||||
var that = this;
|
||||
level.enemies.forEach(function(enemy){
|
||||
if (enemy === that) { //don't check collisions with ourselves.
|
||||
level.enemies.forEach(function (enemy) {
|
||||
if (enemy === that) {
|
||||
//don't check collisions with ourselves.
|
||||
return;
|
||||
} else if (enemy.pos[0] - vX > 336){ //stop checking once we get to far away dudes.
|
||||
} else if (enemy.pos[0] - vX > 336) {
|
||||
//stop checking once we get to far away dudes.
|
||||
return;
|
||||
} else {
|
||||
that.isCollideWith(enemy);
|
||||
@@ -82,7 +84,7 @@
|
||||
this.isCollideWith(player);
|
||||
};
|
||||
|
||||
Goomba.prototype.isCollideWith = function(ent) {
|
||||
Goomba.prototype.isCollideWith = function (ent) {
|
||||
if (ent instanceof Mario.Player && (this.dying || ent.invincibility)) {
|
||||
return;
|
||||
}
|
||||
@@ -92,14 +94,27 @@
|
||||
var hpos2 = [ent.pos[0] + ent.hitbox[0], ent.pos[1] + ent.hitbox[1]];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+ent.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+ent.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
if (ent instanceof Mario.Player) { //if we hit the player
|
||||
if (ent.vel[1] > 0) { //then the goomba dies
|
||||
if (
|
||||
!(
|
||||
hpos1[0] > hpos2[0] + ent.hitbox[2] ||
|
||||
hpos1[0] + this.hitbox[2] < hpos2[0]
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!(
|
||||
hpos1[1] > hpos2[1] + ent.hitbox[3] ||
|
||||
hpos1[1] + this.hitbox[3] < hpos2[1]
|
||||
)
|
||||
) {
|
||||
if (ent instanceof Mario.Player) {
|
||||
//if we hit the player
|
||||
if (ent.vel[1] > 0) {
|
||||
//then the goomba dies
|
||||
this.stomp();
|
||||
} else if (ent.starTime) {
|
||||
this.bump();
|
||||
} else { //or the player gets hit
|
||||
} else {
|
||||
//or the player gets hit
|
||||
ent.damage();
|
||||
}
|
||||
} else {
|
||||
@@ -109,7 +124,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
Goomba.prototype.stomp = function() {
|
||||
Goomba.prototype.stomp = function () {
|
||||
sounds.stomp.play();
|
||||
player.bounce = true;
|
||||
this.sprite.pos[0] = 32;
|
||||
@@ -118,9 +133,9 @@
|
||||
this.dying = 10;
|
||||
};
|
||||
|
||||
Goomba.prototype.bump = function() {
|
||||
Goomba.prototype.bump = function () {
|
||||
sounds.kick.play();
|
||||
this.sprite.img = 'sprites/enemyr.png';
|
||||
this.sprite.img = "sprites/enemyr.png";
|
||||
this.flipping = true;
|
||||
this.pos[1] -= 1;
|
||||
this.vel[0] = 0;
|
||||
|
||||
@@ -1,54 +1,61 @@
|
||||
(function() {
|
||||
var pressedKeys = {};
|
||||
(function () {
|
||||
var pressedKeys = {};
|
||||
|
||||
function setKey(event, status) {
|
||||
var code = event.keyCode;
|
||||
var key;
|
||||
function setKey(event, status) {
|
||||
var code = event.keyCode;
|
||||
var key;
|
||||
|
||||
switch(code) {
|
||||
case 32:
|
||||
key = 'SPACE'; break;
|
||||
case 37:
|
||||
key = 'LEFT'; break;
|
||||
case 38:
|
||||
key = 'UP'; break;
|
||||
case 39:
|
||||
key = 'RIGHT'; break;
|
||||
case 40:
|
||||
key = 'DOWN'; break;
|
||||
case 88:
|
||||
key = 'JUMP'; break;
|
||||
case 90:
|
||||
key = 'RUN'; break;
|
||||
default:
|
||||
key = String.fromCharCode(code);
|
||||
}
|
||||
|
||||
pressedKeys[key] = status;
|
||||
switch (code) {
|
||||
case 32:
|
||||
key = "SPACE";
|
||||
break;
|
||||
case 37:
|
||||
key = "LEFT";
|
||||
break;
|
||||
case 38:
|
||||
key = "UP";
|
||||
break;
|
||||
case 39:
|
||||
key = "RIGHT";
|
||||
break;
|
||||
case 40:
|
||||
key = "DOWN";
|
||||
break;
|
||||
case 88:
|
||||
key = "JUMP";
|
||||
break;
|
||||
case 90:
|
||||
key = "RUN";
|
||||
break;
|
||||
default:
|
||||
key = String.fromCharCode(code);
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function(e) {
|
||||
setKey(e, true);
|
||||
});
|
||||
pressedKeys[key] = status;
|
||||
}
|
||||
|
||||
document.addEventListener('keyup', function(e) {
|
||||
setKey(e, false);
|
||||
});
|
||||
document.addEventListener("keydown", function (e) {
|
||||
setKey(e, true);
|
||||
});
|
||||
|
||||
window.addEventListener('blur', function() {
|
||||
pressedKeys = {};
|
||||
});
|
||||
document.addEventListener("keyup", function (e) {
|
||||
setKey(e, false);
|
||||
});
|
||||
|
||||
window.input = {
|
||||
isDown: function(key) {
|
||||
return pressedKeys[key.toUpperCase()];
|
||||
},
|
||||
reset: function() {
|
||||
pressedKeys['RUN'] = false;
|
||||
pressedKeys['LEFT'] = false;
|
||||
pressedKeys['RIGHT'] = false;
|
||||
pressedKeys['DOWN'] = false;
|
||||
pressedKeys['JUMP'] = false;
|
||||
}
|
||||
};
|
||||
window.addEventListener("blur", function () {
|
||||
pressedKeys = {};
|
||||
});
|
||||
|
||||
window.input = {
|
||||
isDown: function (key) {
|
||||
return pressedKeys[key.toUpperCase()];
|
||||
},
|
||||
reset: function () {
|
||||
pressedKeys["RUN"] = false;
|
||||
pressedKeys["LEFT"] = false;
|
||||
pressedKeys["RIGHT"] = false;
|
||||
pressedKeys["DOWN"] = false;
|
||||
pressedKeys["JUMP"] = false;
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
var Koopa = Mario.Koopa = function(pos, sprite, para) {
|
||||
var Koopa = (Mario.Koopa = function (pos, sprite, para) {
|
||||
this.dying = false;
|
||||
this.shell = false;
|
||||
|
||||
@@ -14,33 +13,34 @@
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: sprite,
|
||||
hitbox: [2,8,12,24]
|
||||
hitbox: [2, 8, 12, 24],
|
||||
});
|
||||
this.vel[0] = -0.5;
|
||||
this.idx = level.enemies.length;
|
||||
};
|
||||
});
|
||||
|
||||
Koopa.prototype.render = function(ctx, vX, vY) {
|
||||
Koopa.prototype.render = function (ctx, vX, vY) {
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
};
|
||||
|
||||
Koopa.prototype.update = function(dt, vX) {
|
||||
Koopa.prototype.update = function (dt, vX) {
|
||||
if (this.turn) {
|
||||
this.vel[0] = -this.vel[0];
|
||||
if (this.shell) sounds.bump.play();
|
||||
this.turn = false;
|
||||
}
|
||||
if (this.vel[0] != 0) {
|
||||
this.left = (this.vel[0] < 0);
|
||||
this.left = this.vel[0] < 0;
|
||||
}
|
||||
|
||||
if (this.left) {
|
||||
this.sprite.img = 'sprites/enemy.png';
|
||||
this.sprite.img = "sprites/enemy.png";
|
||||
} else {
|
||||
this.sprite.img = 'sprites/enemyr.png';
|
||||
this.sprite.img = "sprites/enemyr.png";
|
||||
}
|
||||
|
||||
if (this.pos[0] - vX > 336) { //if we're too far away, do nothing.
|
||||
if (this.pos[0] - vX > 336) {
|
||||
//if we're too far away, do nothing.
|
||||
return;
|
||||
} else if (this.pos[0] - vX < -32) {
|
||||
delete level.enemies[this.idx];
|
||||
@@ -61,9 +61,9 @@
|
||||
}
|
||||
if (this.shell == 0) {
|
||||
this.sprite = level.koopaSprite();
|
||||
this.hitbox = [2,8,12,24]
|
||||
this.hitbox = [2, 8, 12, 24];
|
||||
if (this.left) {
|
||||
this.sprite.img = 'sprites/enemyr.png';
|
||||
this.sprite.img = "sprites/enemyr.png";
|
||||
this.vel[0] = 0.5;
|
||||
this.left = false;
|
||||
} else {
|
||||
@@ -85,13 +85,13 @@
|
||||
this.sprite.update(dt);
|
||||
};
|
||||
|
||||
Koopa.prototype.collideWall = function() {
|
||||
Koopa.prototype.collideWall = function () {
|
||||
//This stops us from flipping twice on the same frame if we collide
|
||||
//with multiple wall tiles simultaneously.
|
||||
this.turn = true;
|
||||
};
|
||||
|
||||
Koopa.prototype.checkCollisions = function() {
|
||||
Koopa.prototype.checkCollisions = function () {
|
||||
var h = this.shell ? 1 : 2;
|
||||
if (this.pos[1] % 16 !== 0) {
|
||||
h += 1;
|
||||
@@ -121,10 +121,12 @@
|
||||
}
|
||||
}
|
||||
var that = this;
|
||||
level.enemies.forEach(function(enemy){
|
||||
if (enemy === that) { //don't check collisions with ourselves.
|
||||
level.enemies.forEach(function (enemy) {
|
||||
if (enemy === that) {
|
||||
//don't check collisions with ourselves.
|
||||
return;
|
||||
} else if (enemy.pos[0] - vX > 336){ //stop checking once we get to far away dudes.
|
||||
} else if (enemy.pos[0] - vX > 336) {
|
||||
//stop checking once we get to far away dudes.
|
||||
return;
|
||||
} else {
|
||||
that.isCollideWith(enemy);
|
||||
@@ -133,7 +135,7 @@
|
||||
this.isCollideWith(player);
|
||||
};
|
||||
|
||||
Koopa.prototype.isCollideWith = function(ent) {
|
||||
Koopa.prototype.isCollideWith = function (ent) {
|
||||
if (ent instanceof Mario.Player && (this.dying || ent.invincibility)) {
|
||||
return;
|
||||
}
|
||||
@@ -143,8 +145,18 @@
|
||||
var hpos2 = [ent.pos[0] + ent.hitbox[0], ent.pos[1] + ent.hitbox[1]];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+ent.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+ent.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
if (
|
||||
!(
|
||||
hpos1[0] > hpos2[0] + ent.hitbox[2] ||
|
||||
hpos1[0] + this.hitbox[2] < hpos2[0]
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!(
|
||||
hpos1[1] > hpos2[1] + ent.hitbox[3] ||
|
||||
hpos1[1] + this.hitbox[3] < hpos2[1]
|
||||
)
|
||||
) {
|
||||
if (ent instanceof Mario.Player) {
|
||||
if (ent.vel[1] > 0) {
|
||||
player.bounce = true;
|
||||
@@ -152,7 +164,8 @@
|
||||
if (this.shell) {
|
||||
sounds.kick.play();
|
||||
if (this.vel[0] === 0) {
|
||||
if (ent.left) { //I'm pretty sure this isn't the real logic.
|
||||
if (ent.left) {
|
||||
//I'm pretty sure this isn't the real logic.
|
||||
this.vel[0] = -4;
|
||||
} else {
|
||||
this.vel[0] = 4;
|
||||
@@ -162,13 +175,15 @@
|
||||
this.vel[0] = 0;
|
||||
} else ent.damage();
|
||||
}
|
||||
} else if (ent.vel[1] > 0) { //then we get BOPPED.
|
||||
} else if (ent.vel[1] > 0) {
|
||||
//then we get BOPPED.
|
||||
this.stomp();
|
||||
} else { //or the player gets hit
|
||||
} else {
|
||||
//or the player gets hit
|
||||
ent.damage();
|
||||
}
|
||||
} else {
|
||||
if (this.shell && (ent instanceof Mario.Goomba)) {
|
||||
if (this.shell && ent instanceof Mario.Goomba) {
|
||||
ent.bump();
|
||||
} else this.collideWall();
|
||||
}
|
||||
@@ -176,7 +191,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
Koopa.prototype.stomp = function() {
|
||||
Koopa.prototype.stomp = function () {
|
||||
//Turn this thing into a shell if it isn't already. Kick it if it is.
|
||||
player.bounce = true;
|
||||
if (this.para) {
|
||||
@@ -187,22 +202,21 @@
|
||||
this.shell = 360;
|
||||
this.sprite.pos[0] += 64;
|
||||
this.sprite.pos[1] += 16;
|
||||
this.sprite.size = [16,16];
|
||||
this.hitbox = [2,0,12,16];
|
||||
this.sprite.size = [16, 16];
|
||||
this.hitbox = [2, 0, 12, 16];
|
||||
this.sprite.speed = 0;
|
||||
this.frames = [0,1];
|
||||
this.vel = [0,0];
|
||||
this.frames = [0, 1];
|
||||
this.vel = [0, 0];
|
||||
this.pos[1] += 16;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Koopa.prototype.bump = function() {
|
||||
Koopa.prototype.bump = function () {
|
||||
sounds.kick.play();
|
||||
if (this.flipping) return;
|
||||
this.flipping = true;
|
||||
this.sprite.pos = [160, 0];
|
||||
this.sprite.size = [16,16];
|
||||
this.sprite.size = [16, 16];
|
||||
this.hitbox = [2, 0, 12, 16];
|
||||
this.sprite.speed = 0;
|
||||
this.vel[0] = 0;
|
||||
|
||||
@@ -1,117 +1,208 @@
|
||||
var oneone = Mario.oneone = function() {
|
||||
var oneone = (Mario.oneone = function () {
|
||||
//The things that need to be passed in are basically just dependent on what
|
||||
//tileset we're in, so it makes more sense to just make one variable for that, so
|
||||
//TODO: put as much of this in the Level object definition as possible.
|
||||
level = new Mario.Level({
|
||||
playerPos: [56,192],
|
||||
playerPos: [56, 192],
|
||||
loader: Mario.oneone,
|
||||
background: "#7974FF",
|
||||
scrolling: true,
|
||||
invincibility: [144, 192, 240],
|
||||
exit: 204,
|
||||
floorSprite: new Mario.Sprite('sprites/tiles.png', [0,0],[16,16],0),
|
||||
cloudSprite: new Mario.Sprite('sprites/tiles.png', [0,320],[48,32],0),
|
||||
wallSprite: new Mario.Sprite('sprites/tiles.png', [0, 16],[16,16],0),
|
||||
brickSprite: new Mario.Sprite('sprites/tiles.png', [16, 0], [16,16], 0),
|
||||
brickBounceSprite: new Mario.Sprite('sprites/tiles.png',[32,0],[16,16],0),
|
||||
floorSprite: new Mario.Sprite("sprites/tiles.png", [0, 0], [16, 16], 0),
|
||||
cloudSprite: new Mario.Sprite("sprites/tiles.png", [0, 320], [48, 32], 0),
|
||||
wallSprite: new Mario.Sprite("sprites/tiles.png", [0, 16], [16, 16], 0),
|
||||
brickSprite: new Mario.Sprite("sprites/tiles.png", [16, 0], [16, 16], 0),
|
||||
brickBounceSprite: new Mario.Sprite(
|
||||
"sprites/tiles.png",
|
||||
[32, 0],
|
||||
[16, 16],
|
||||
0,
|
||||
),
|
||||
rubbleSprite: function () {
|
||||
return new Mario.Sprite('sprites/items.png', [64,0], [8,8], 3, [0,1])
|
||||
return new Mario.Sprite("sprites/items.png", [64, 0], [8, 8], 3, [0, 1]);
|
||||
},
|
||||
ublockSprite: new Mario.Sprite('sprites/tiles.png', [48, 0], [16,16],0),
|
||||
superShroomSprite: new Mario.Sprite('sprites/items.png', [0,0], [16,16], 0),
|
||||
fireFlowerSprite: new Mario.Sprite('sprites/items.png', [0,32], [16,16], 20, [0,1,2,3]),
|
||||
starSprite: new Mario.Sprite('sprites/items.png', [0,48], [16,16], 20, [0,1,2,3]),
|
||||
pipeLEndSprite: new Mario.Sprite('sprites/tiles.png', [0, 128], [16,16], 0),
|
||||
pipeREndSprite: new Mario.Sprite('sprites/tiles.png', [16, 128], [16,16], 0),
|
||||
pipeLMidSprite: new Mario.Sprite('sprites/tiles.png', [0, 144], [16,16], 0),
|
||||
pipeRMidSprite: new Mario.Sprite('sprites/tiles.png', [16, 144], [16,16], 0),
|
||||
ublockSprite: new Mario.Sprite("sprites/tiles.png", [48, 0], [16, 16], 0),
|
||||
superShroomSprite: new Mario.Sprite(
|
||||
"sprites/items.png",
|
||||
[0, 0],
|
||||
[16, 16],
|
||||
0,
|
||||
),
|
||||
fireFlowerSprite: new Mario.Sprite(
|
||||
"sprites/items.png",
|
||||
[0, 32],
|
||||
[16, 16],
|
||||
20,
|
||||
[0, 1, 2, 3],
|
||||
),
|
||||
starSprite: new Mario.Sprite(
|
||||
"sprites/items.png",
|
||||
[0, 48],
|
||||
[16, 16],
|
||||
20,
|
||||
[0, 1, 2, 3],
|
||||
),
|
||||
pipeLEndSprite: new Mario.Sprite(
|
||||
"sprites/tiles.png",
|
||||
[0, 128],
|
||||
[16, 16],
|
||||
0,
|
||||
),
|
||||
pipeREndSprite: new Mario.Sprite(
|
||||
"sprites/tiles.png",
|
||||
[16, 128],
|
||||
[16, 16],
|
||||
0,
|
||||
),
|
||||
pipeLMidSprite: new Mario.Sprite(
|
||||
"sprites/tiles.png",
|
||||
[0, 144],
|
||||
[16, 16],
|
||||
0,
|
||||
),
|
||||
pipeRMidSprite: new Mario.Sprite(
|
||||
"sprites/tiles.png",
|
||||
[16, 144],
|
||||
[16, 16],
|
||||
0,
|
||||
),
|
||||
|
||||
pipeUpMid: new Mario.Sprite('sprites/tiles.png', [0, 144], [32,16], 0),
|
||||
pipeSideMid: new Mario.Sprite('sprites/tiles.png', [48, 128], [16,32], 0),
|
||||
pipeLeft: new Mario.Sprite('sprites/tiles.png', [32, 128], [16,32], 0),
|
||||
pipeTop: new Mario.Sprite('sprites/tiles.png', [0, 128], [32,16], 0),
|
||||
qblockSprite: new Mario.Sprite('sprites/tiles.png', [384, 0], [16,16], 8, [0,0,0,0,1,2,1]),
|
||||
bcoinSprite: function() {
|
||||
return new Mario.Sprite('sprites/items.png', [0,112],[16,16], 20,[0,1,2,3]);
|
||||
pipeUpMid: new Mario.Sprite("sprites/tiles.png", [0, 144], [32, 16], 0),
|
||||
pipeSideMid: new Mario.Sprite("sprites/tiles.png", [48, 128], [16, 32], 0),
|
||||
pipeLeft: new Mario.Sprite("sprites/tiles.png", [32, 128], [16, 32], 0),
|
||||
pipeTop: new Mario.Sprite("sprites/tiles.png", [0, 128], [32, 16], 0),
|
||||
qblockSprite: new Mario.Sprite(
|
||||
"sprites/tiles.png",
|
||||
[384, 0],
|
||||
[16, 16],
|
||||
8,
|
||||
[0, 0, 0, 0, 1, 2, 1],
|
||||
),
|
||||
bcoinSprite: function () {
|
||||
return new Mario.Sprite(
|
||||
"sprites/items.png",
|
||||
[0, 112],
|
||||
[16, 16],
|
||||
20,
|
||||
[0, 1, 2, 3],
|
||||
);
|
||||
},
|
||||
cloudSprites:[
|
||||
new Mario.Sprite('sprites/tiles.png', [0,320],[16,32],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [16,320],[16,32],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [32,320],[16,32],0)
|
||||
cloudSprites: [
|
||||
new Mario.Sprite("sprites/tiles.png", [0, 320], [16, 32], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [16, 320], [16, 32], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [32, 320], [16, 32], 0),
|
||||
],
|
||||
hillSprites: [
|
||||
new Mario.Sprite('sprites/tiles.png', [128,128],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [144,128],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [160,128],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [128,144],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [144,144],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [160,144],[16,16],0)
|
||||
new Mario.Sprite("sprites/tiles.png", [128, 128], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [144, 128], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [160, 128], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [128, 144], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [144, 144], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [160, 144], [16, 16], 0),
|
||||
],
|
||||
bushSprite: new Mario.Sprite('sprites/tiles.png', [176, 144], [48, 16], 0),
|
||||
bushSprite: new Mario.Sprite("sprites/tiles.png", [176, 144], [48, 16], 0),
|
||||
bushSprites: [
|
||||
new Mario.Sprite('sprites/tiles.png', [176,144], [16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [192,144], [16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [208,144], [16,16],0)],
|
||||
goombaSprite: function() {
|
||||
return new Mario.Sprite('sprites/enemy.png', [0, 16], [16,16], 3, [0,1]);
|
||||
},
|
||||
koopaSprite: function() {
|
||||
return new Mario.Sprite('sprites/enemy.png', [96,0], [16,32], 2, [0,1]);
|
||||
},
|
||||
flagPoleSprites: [
|
||||
new Mario.Sprite('sprites/tiles.png', [256, 128], [16,16], 0),
|
||||
new Mario.Sprite('sprites/tiles.png', [256, 144], [16,16], 0),
|
||||
new Mario.Sprite('sprites/items.png', [128, 32], [16,16], 0)
|
||||
]
|
||||
});
|
||||
ground = [[0,69],[71,86],[89,153],[155,212]];
|
||||
new Mario.Sprite("sprites/tiles.png", [176, 144], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [192, 144], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [208, 144], [16, 16], 0),
|
||||
],
|
||||
goombaSprite: function () {
|
||||
return new Mario.Sprite(
|
||||
"sprites/enemy.png",
|
||||
[0, 16],
|
||||
[16, 16],
|
||||
3,
|
||||
[0, 1],
|
||||
);
|
||||
},
|
||||
koopaSprite: function () {
|
||||
return new Mario.Sprite(
|
||||
"sprites/enemy.png",
|
||||
[96, 0],
|
||||
[16, 32],
|
||||
2,
|
||||
[0, 1],
|
||||
);
|
||||
},
|
||||
flagPoleSprites: [
|
||||
new Mario.Sprite("sprites/tiles.png", [256, 128], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [256, 144], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/items.png", [128, 32], [16, 16], 0),
|
||||
],
|
||||
});
|
||||
ground = [
|
||||
[0, 69],
|
||||
[71, 86],
|
||||
[89, 153],
|
||||
[155, 212],
|
||||
];
|
||||
player.pos[0] = level.playerPos[0];
|
||||
player.pos[1] = level.playerPos[1];
|
||||
vX = 0;
|
||||
|
||||
//build THE GROUND
|
||||
ground.forEach(function(loc) {
|
||||
level.putFloor(loc[0],loc[1]);
|
||||
ground.forEach(function (loc) {
|
||||
level.putFloor(loc[0], loc[1]);
|
||||
});
|
||||
|
||||
//build scenery
|
||||
clouds = [[7,3],[19, 2],[56, 3],[67, 2],[87, 2],[103, 2],[152, 3],[163, 2],[200, 3]];
|
||||
clouds.forEach(function(cloud){
|
||||
level.putCloud(cloud[0],cloud[1]);
|
||||
clouds = [
|
||||
[7, 3],
|
||||
[19, 2],
|
||||
[56, 3],
|
||||
[67, 2],
|
||||
[87, 2],
|
||||
[103, 2],
|
||||
[152, 3],
|
||||
[163, 2],
|
||||
[200, 3],
|
||||
];
|
||||
clouds.forEach(function (cloud) {
|
||||
level.putCloud(cloud[0], cloud[1]);
|
||||
});
|
||||
|
||||
twoClouds = [[36,2],[132,2],[180,2]];
|
||||
twoClouds.forEach(function(cloud){
|
||||
level.putTwoCloud(cloud[0],cloud[1]);
|
||||
twoClouds = [
|
||||
[36, 2],
|
||||
[132, 2],
|
||||
[180, 2],
|
||||
];
|
||||
twoClouds.forEach(function (cloud) {
|
||||
level.putTwoCloud(cloud[0], cloud[1]);
|
||||
});
|
||||
|
||||
threeClouds = [[27,3],[75,3],[123,3],[171,3]];
|
||||
threeClouds.forEach(function(cloud){
|
||||
level.putThreeCloud(cloud[0],cloud[1]);
|
||||
threeClouds = [
|
||||
[27, 3],
|
||||
[75, 3],
|
||||
[123, 3],
|
||||
[171, 3],
|
||||
];
|
||||
threeClouds.forEach(function (cloud) {
|
||||
level.putThreeCloud(cloud[0], cloud[1]);
|
||||
});
|
||||
|
||||
bHills = [0,48,96,144,192]
|
||||
bHills.forEach(function(hill) {
|
||||
bHills = [0, 48, 96, 144, 192];
|
||||
bHills.forEach(function (hill) {
|
||||
level.putBigHill(hill, 12);
|
||||
});
|
||||
|
||||
sHills = [16,64,111,160];
|
||||
sHills.forEach(function(hill) {
|
||||
sHills = [16, 64, 111, 160];
|
||||
sHills.forEach(function (hill) {
|
||||
level.putSmallHill(hill, 12);
|
||||
});
|
||||
|
||||
bushes = [23,71,118,167];
|
||||
bushes.forEach(function(bush) {
|
||||
bushes = [23, 71, 118, 167];
|
||||
bushes.forEach(function (bush) {
|
||||
level.putBush(bush, 12);
|
||||
});
|
||||
|
||||
twoBushes = [41,89,137];
|
||||
twoBushes.forEach(function(bush) {
|
||||
twoBushes = [41, 89, 137];
|
||||
twoBushes.forEach(function (bush) {
|
||||
level.putTwoBush(bush, 12);
|
||||
});
|
||||
|
||||
threeBushes = [11,59,106];
|
||||
threeBushes.forEach(function(bush) {
|
||||
threeBushes = [11, 59, 106];
|
||||
threeBushes.forEach(function (bush) {
|
||||
level.putThreeBush(bush, 12);
|
||||
});
|
||||
|
||||
@@ -216,4 +307,4 @@ var oneone = Mario.oneone = function() {
|
||||
music.underground.pause();
|
||||
// music.overworld.currentTime = 0;
|
||||
music.overworld.play();
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,65 +1,113 @@
|
||||
var oneonetunnel = Mario.oneonetunnel = function() {
|
||||
var oneonetunnel = (Mario.oneonetunnel = function () {
|
||||
level = new Mario.Level({
|
||||
playerPos: [40,16],
|
||||
playerPos: [40, 16],
|
||||
loader: Mario.oneonetunnel,
|
||||
background: "#000000",
|
||||
scrolling: false,
|
||||
coinSprite: function() {
|
||||
return new Mario.Sprite('sprites/items.png', [0,96],[16,16], 6,[0,0,0,0,1,2,1]);
|
||||
coinSprite: function () {
|
||||
return new Mario.Sprite(
|
||||
"sprites/items.png",
|
||||
[0, 96],
|
||||
[16, 16],
|
||||
6,
|
||||
[0, 0, 0, 0, 1, 2, 1],
|
||||
);
|
||||
},
|
||||
floorSprite: new Mario.Sprite('sprites/tiles.png', [0,32],[16,16],0),
|
||||
wallSprite: new Mario.Sprite('sprites/tiles.png', [32, 32],[16,16],0),
|
||||
brickSprite: new Mario.Sprite('sprites/tiles.png', [16, 0], [16,16], 0),
|
||||
brickBounceSprite: new Mario.Sprite('sprites/tiles.png',[32,0],[16,16],0),
|
||||
ublockSprite: new Mario.Sprite('sprites/tiles.png', [48, 0], [16,16],0),
|
||||
pipeLMidSprite: new Mario.Sprite('sprites/tiles.png', [0, 144], [16,16], 0),
|
||||
pipeRMidSprite: new Mario.Sprite('sprites/tiles.png', [16, 144], [16,16], 0),
|
||||
pipeLEndSprite: new Mario.Sprite('sprites/tiles.png', [0, 128], [16,16], 0),
|
||||
pipeREndSprite: new Mario.Sprite('sprites/tiles.png', [16, 128], [16,16], 0),
|
||||
pipeUpMid: new Mario.Sprite('sprites/tiles.png', [0, 144], [32,16], 0),
|
||||
pipeSideMid: new Mario.Sprite('sprites/tiles.png', [48, 128], [16,32], 0),
|
||||
pipeLeft: new Mario.Sprite('sprites/tiles.png', [32, 128], [16,32], 0),
|
||||
pipeTop: new Mario.Sprite('sprites/tiles.png', [0, 128], [32,16], 0),
|
||||
|
||||
LPipeSprites:[
|
||||
new Mario.Sprite('sprites/tiles.png', [32,128],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [32,144],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [48,128],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [48,144],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [64,128],[16,16],0),
|
||||
new Mario.Sprite('sprites/tiles.png', [64,144],[16,16],0),
|
||||
]
|
||||
floorSprite: new Mario.Sprite("sprites/tiles.png", [0, 32], [16, 16], 0),
|
||||
wallSprite: new Mario.Sprite("sprites/tiles.png", [32, 32], [16, 16], 0),
|
||||
brickSprite: new Mario.Sprite("sprites/tiles.png", [16, 0], [16, 16], 0),
|
||||
brickBounceSprite: new Mario.Sprite(
|
||||
"sprites/tiles.png",
|
||||
[32, 0],
|
||||
[16, 16],
|
||||
0,
|
||||
),
|
||||
ublockSprite: new Mario.Sprite("sprites/tiles.png", [48, 0], [16, 16], 0),
|
||||
pipeLMidSprite: new Mario.Sprite(
|
||||
"sprites/tiles.png",
|
||||
[0, 144],
|
||||
[16, 16],
|
||||
0,
|
||||
),
|
||||
pipeRMidSprite: new Mario.Sprite(
|
||||
"sprites/tiles.png",
|
||||
[16, 144],
|
||||
[16, 16],
|
||||
0,
|
||||
),
|
||||
pipeLEndSprite: new Mario.Sprite(
|
||||
"sprites/tiles.png",
|
||||
[0, 128],
|
||||
[16, 16],
|
||||
0,
|
||||
),
|
||||
pipeREndSprite: new Mario.Sprite(
|
||||
"sprites/tiles.png",
|
||||
[16, 128],
|
||||
[16, 16],
|
||||
0,
|
||||
),
|
||||
pipeUpMid: new Mario.Sprite("sprites/tiles.png", [0, 144], [32, 16], 0),
|
||||
pipeSideMid: new Mario.Sprite("sprites/tiles.png", [48, 128], [16, 32], 0),
|
||||
pipeLeft: new Mario.Sprite("sprites/tiles.png", [32, 128], [16, 32], 0),
|
||||
pipeTop: new Mario.Sprite("sprites/tiles.png", [0, 128], [32, 16], 0),
|
||||
|
||||
LPipeSprites: [
|
||||
new Mario.Sprite("sprites/tiles.png", [32, 128], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [32, 144], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [48, 128], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [48, 144], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [64, 128], [16, 16], 0),
|
||||
new Mario.Sprite("sprites/tiles.png", [64, 144], [16, 16], 0),
|
||||
],
|
||||
});
|
||||
|
||||
player.pos[0] = level.playerPos[0];
|
||||
player.pos[1] = level.playerPos[1];
|
||||
vX = 0;
|
||||
level.putFloor(0,16);
|
||||
level.putWall(0,13,11);
|
||||
walls = [4,5,6,7,8,9,10];
|
||||
walls.forEach(function(loc){
|
||||
level.putWall(loc,13,3);
|
||||
level.putWall(loc,3,1);
|
||||
level.putFloor(0, 16);
|
||||
level.putWall(0, 13, 11);
|
||||
walls = [4, 5, 6, 7, 8, 9, 10];
|
||||
walls.forEach(function (loc) {
|
||||
level.putWall(loc, 13, 3);
|
||||
level.putWall(loc, 3, 1);
|
||||
});
|
||||
|
||||
coins = [[5,5], [6,5], [7,5], [8,5], [9,5],
|
||||
[4,7], [5,7], [6,7], [7,7], [8,7], [9,7], [10,7],
|
||||
[4,9], [5,9], [6,9], [7,9], [8,9], [9,9], [10,9]];
|
||||
coins.forEach(function(pos){
|
||||
level.putCoin(pos[0],pos[1]);
|
||||
coins = [
|
||||
[5, 5],
|
||||
[6, 5],
|
||||
[7, 5],
|
||||
[8, 5],
|
||||
[9, 5],
|
||||
[4, 7],
|
||||
[5, 7],
|
||||
[6, 7],
|
||||
[7, 7],
|
||||
[8, 7],
|
||||
[9, 7],
|
||||
[10, 7],
|
||||
[4, 9],
|
||||
[5, 9],
|
||||
[6, 9],
|
||||
[7, 9],
|
||||
[8, 9],
|
||||
[9, 9],
|
||||
[10, 9],
|
||||
];
|
||||
coins.forEach(function (pos) {
|
||||
level.putCoin(pos[0], pos[1]);
|
||||
});
|
||||
|
||||
//level.putLeftPipe(13,11);
|
||||
level.putRealPipe(13,11,3,"RIGHT", function() {
|
||||
level.putRealPipe(13, 11, 3, "RIGHT", function () {
|
||||
Mario.oneone.call();
|
||||
player.pos = [2616, 177]
|
||||
player.pipe("UP", function() {;});
|
||||
player.pos = [2616, 177];
|
||||
player.pipe("UP", function () {});
|
||||
});
|
||||
|
||||
level.putPipe(15,13,13);
|
||||
level.putPipe(15, 13, 13);
|
||||
|
||||
music.overworld.pause();
|
||||
music.underground.currentTime = 0;
|
||||
music.underground.play();
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
(function() {
|
||||
var Level = Mario.Level = function(options) {
|
||||
(function () {
|
||||
var Level = (Mario.Level = function (options) {
|
||||
this.playerPos = options.playerPos;
|
||||
this.scrolling = options.scrolling;
|
||||
this.loader = options.loader;
|
||||
@@ -55,164 +55,241 @@
|
||||
this.scenery[i] = [];
|
||||
this.blocks[i] = [];
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
Level.prototype.putFloor = function(start, end) {
|
||||
Level.prototype.putFloor = function (start, end) {
|
||||
for (var i = start; i < end; i++) {
|
||||
this.statics[13][i] = new Mario.Floor([16*i,208], this.floorSprite);
|
||||
this.statics[14][i] = new Mario.Floor([16*i,224], this.floorSprite);
|
||||
this.statics[13][i] = new Mario.Floor([16 * i, 208], this.floorSprite);
|
||||
this.statics[14][i] = new Mario.Floor([16 * i, 224], this.floorSprite);
|
||||
}
|
||||
};
|
||||
|
||||
Level.prototype.putGoomba = function(x, y) {
|
||||
this.enemies.push(new Mario.Goomba([16*x, 16*y], this.goombaSprite() ));
|
||||
Level.prototype.putGoomba = function (x, y) {
|
||||
this.enemies.push(new Mario.Goomba([16 * x, 16 * y], this.goombaSprite()));
|
||||
};
|
||||
|
||||
Level.prototype.putKoopa = function(x, y) {
|
||||
this.enemies.push(new Mario.Koopa([16*x, 16*y], this.koopaSprite(), false));
|
||||
Level.prototype.putKoopa = function (x, y) {
|
||||
this.enemies.push(
|
||||
new Mario.Koopa([16 * x, 16 * y], this.koopaSprite(), false),
|
||||
);
|
||||
};
|
||||
|
||||
Level.prototype.putWall = function(x, y, height) {
|
||||
Level.prototype.putWall = function (x, y, height) {
|
||||
//y is the bottom of the wall in this case.
|
||||
for (var i = y-height; i < y; i++) {
|
||||
this.statics[i][x] = new Mario.Floor([16*x, 16*i], this.wallSprite);
|
||||
for (var i = y - height; i < y; i++) {
|
||||
this.statics[i][x] = new Mario.Floor([16 * x, 16 * i], this.wallSprite);
|
||||
}
|
||||
};
|
||||
|
||||
Level.prototype.putPipe = function(x, y, height) {
|
||||
Level.prototype.putPipe = function (x, y, height) {
|
||||
for (var i = y - height; i < y; i++) {
|
||||
if (i === y - height) {
|
||||
this.statics[i][x] = new Mario.Floor([16*x, 16*i], this.pipeLEndSprite);
|
||||
this.statics[i][x+1] = new Mario.Floor([16*x+16, 16*i], this.pipeREndSprite);
|
||||
this.statics[i][x] = new Mario.Floor(
|
||||
[16 * x, 16 * i],
|
||||
this.pipeLEndSprite,
|
||||
);
|
||||
this.statics[i][x + 1] = new Mario.Floor(
|
||||
[16 * x + 16, 16 * i],
|
||||
this.pipeREndSprite,
|
||||
);
|
||||
} else {
|
||||
this.statics[i][x] = new Mario.Floor([16*x, 16*i], this.pipeLMidSprite);
|
||||
this.statics[i][x+1] = new Mario.Floor([16*x+16, 16*i], this.pipeRMidSprite);
|
||||
this.statics[i][x] = new Mario.Floor(
|
||||
[16 * x, 16 * i],
|
||||
this.pipeLMidSprite,
|
||||
);
|
||||
this.statics[i][x + 1] = new Mario.Floor(
|
||||
[16 * x + 16, 16 * i],
|
||||
this.pipeRMidSprite,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//sometimes, pipes don't go straight up and down.
|
||||
Level.prototype.putLeftPipe = function(x,y) {
|
||||
this.statics[y][x] = new Mario.Floor([16*x, 16*y], this.LPipeSprites[0]);
|
||||
this.statics[y+1][x] = new Mario.Floor([16*x,16*(y+1)], this.LPipeSprites[1]);
|
||||
this.statics[y][x+1] = new Mario.Floor([16*(x+1),16*y], this.LPipeSprites[2]);
|
||||
this.statics[y+1][x+1] = new Mario.Floor([16*(x+1),16*(y+1)], this.LPipeSprites[3]);
|
||||
this.statics[y][x+2] = new Mario.Floor([16*(x+2),16*y], this.LPipeSprites[4]);
|
||||
this.statics[y+1][x+2] = new Mario.Floor([16*(x+2),16*(y+1)], this.LPipeSprites[5]);
|
||||
Level.prototype.putLeftPipe = function (x, y) {
|
||||
this.statics[y][x] = new Mario.Floor(
|
||||
[16 * x, 16 * y],
|
||||
this.LPipeSprites[0],
|
||||
);
|
||||
this.statics[y + 1][x] = new Mario.Floor(
|
||||
[16 * x, 16 * (y + 1)],
|
||||
this.LPipeSprites[1],
|
||||
);
|
||||
this.statics[y][x + 1] = new Mario.Floor(
|
||||
[16 * (x + 1), 16 * y],
|
||||
this.LPipeSprites[2],
|
||||
);
|
||||
this.statics[y + 1][x + 1] = new Mario.Floor(
|
||||
[16 * (x + 1), 16 * (y + 1)],
|
||||
this.LPipeSprites[3],
|
||||
);
|
||||
this.statics[y][x + 2] = new Mario.Floor(
|
||||
[16 * (x + 2), 16 * y],
|
||||
this.LPipeSprites[4],
|
||||
);
|
||||
this.statics[y + 1][x + 2] = new Mario.Floor(
|
||||
[16 * (x + 2), 16 * (y + 1)],
|
||||
this.LPipeSprites[5],
|
||||
);
|
||||
};
|
||||
|
||||
Level.prototype.putCoin = function(x, y) {
|
||||
this.items.push(new Mario.Coin(
|
||||
[x*16, y*16],
|
||||
this.coinSprite()
|
||||
));
|
||||
Level.prototype.putCoin = function (x, y) {
|
||||
this.items.push(new Mario.Coin([x * 16, y * 16], this.coinSprite()));
|
||||
};
|
||||
|
||||
Level.prototype.putCloud = function(x, y) {
|
||||
this.scenery[y][x] = new Mario.Prop([x*16, y*16], this.cloudSprite);
|
||||
Level.prototype.putCloud = function (x, y) {
|
||||
this.scenery[y][x] = new Mario.Prop([x * 16, y * 16], this.cloudSprite);
|
||||
};
|
||||
|
||||
Level.prototype.putQBlock = function(x, y, item) {
|
||||
this.blocks[y][x] = new Mario.Block( {
|
||||
pos: [x*16, y*16],
|
||||
Level.prototype.putQBlock = function (x, y, item) {
|
||||
this.blocks[y][x] = new Mario.Block({
|
||||
pos: [x * 16, y * 16],
|
||||
item: item,
|
||||
sprite: this.qblockSprite,
|
||||
usedSprite: this.ublockSprite
|
||||
usedSprite: this.ublockSprite,
|
||||
});
|
||||
};
|
||||
|
||||
Level.prototype.putBrick = function(x,y,item) {
|
||||
Level.prototype.putBrick = function (x, y, item) {
|
||||
this.blocks[y][x] = new Mario.Block({
|
||||
pos: [x*16, y*16],
|
||||
pos: [x * 16, y * 16],
|
||||
item: item,
|
||||
sprite: this.brickSprite,
|
||||
bounceSprite: this.brickBounceSprite,
|
||||
usedSprite: this.ublockSprite,
|
||||
breakable: !item
|
||||
breakable: !item,
|
||||
});
|
||||
};
|
||||
|
||||
Level.prototype.putBigHill = function(x, y) {
|
||||
var px = x*16, py = y*16;
|
||||
Level.prototype.putBigHill = function (x, y) {
|
||||
var px = x * 16,
|
||||
py = y * 16;
|
||||
this.scenery[y][x] = new Mario.Prop([px, py], this.hillSprites[0]);
|
||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.hillSprites[3]);
|
||||
this.scenery[y-1][x+1] = new Mario.Prop([px+16, py-16], this.hillSprites[0]);
|
||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.hillSprites[4]);
|
||||
this.scenery[y-1][x+2] = new Mario.Prop([px+32, py-16], this.hillSprites[3]);
|
||||
this.scenery[y-2][x+2] = new Mario.Prop([px+32, py-32], this.hillSprites[1]);
|
||||
this.scenery[y][x+3] = new Mario.Prop([px+48, py], this.hillSprites[5]);
|
||||
this.scenery[y-1][x+3] = new Mario.Prop([px+48, py-16], this.hillSprites[2]);
|
||||
this.scenery[y][x+4] = new Mario.Prop([px+64, py], this.hillSprites[2]);
|
||||
this.scenery[y][x + 1] = new Mario.Prop([px + 16, py], this.hillSprites[3]);
|
||||
this.scenery[y - 1][x + 1] = new Mario.Prop(
|
||||
[px + 16, py - 16],
|
||||
this.hillSprites[0],
|
||||
);
|
||||
this.scenery[y][x + 2] = new Mario.Prop([px + 32, py], this.hillSprites[4]);
|
||||
this.scenery[y - 1][x + 2] = new Mario.Prop(
|
||||
[px + 32, py - 16],
|
||||
this.hillSprites[3],
|
||||
);
|
||||
this.scenery[y - 2][x + 2] = new Mario.Prop(
|
||||
[px + 32, py - 32],
|
||||
this.hillSprites[1],
|
||||
);
|
||||
this.scenery[y][x + 3] = new Mario.Prop([px + 48, py], this.hillSprites[5]);
|
||||
this.scenery[y - 1][x + 3] = new Mario.Prop(
|
||||
[px + 48, py - 16],
|
||||
this.hillSprites[2],
|
||||
);
|
||||
this.scenery[y][x + 4] = new Mario.Prop([px + 64, py], this.hillSprites[2]);
|
||||
};
|
||||
|
||||
Level.prototype.putBush = function(x, y) {
|
||||
this.scenery[y][x] = new Mario.Prop([x*16, y*16], this.bushSprite);
|
||||
Level.prototype.putBush = function (x, y) {
|
||||
this.scenery[y][x] = new Mario.Prop([x * 16, y * 16], this.bushSprite);
|
||||
};
|
||||
|
||||
Level.prototype.putThreeBush = function(x,y) {
|
||||
px = x*16;
|
||||
py = y*16;
|
||||
Level.prototype.putThreeBush = function (x, y) {
|
||||
px = x * 16;
|
||||
py = y * 16;
|
||||
this.scenery[y][x] = new Mario.Prop([px, py], this.bushSprites[0]);
|
||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.bushSprites[1]);
|
||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.bushSprites[1]);
|
||||
this.scenery[y][x+3] = new Mario.Prop([px+48, py], this.bushSprites[1]);
|
||||
this.scenery[y][x+4] = new Mario.Prop([px+64, py], this.bushSprites[2]);
|
||||
this.scenery[y][x + 1] = new Mario.Prop([px + 16, py], this.bushSprites[1]);
|
||||
this.scenery[y][x + 2] = new Mario.Prop([px + 32, py], this.bushSprites[1]);
|
||||
this.scenery[y][x + 3] = new Mario.Prop([px + 48, py], this.bushSprites[1]);
|
||||
this.scenery[y][x + 4] = new Mario.Prop([px + 64, py], this.bushSprites[2]);
|
||||
};
|
||||
|
||||
Level.prototype.putTwoBush = function(x,y) {
|
||||
px = x*16;
|
||||
py = y*16;
|
||||
Level.prototype.putTwoBush = function (x, y) {
|
||||
px = x * 16;
|
||||
py = y * 16;
|
||||
this.scenery[y][x] = new Mario.Prop([px, py], this.bushSprites[0]);
|
||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.bushSprites[1]);
|
||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.bushSprites[1]);
|
||||
this.scenery[y][x+3] = new Mario.Prop([px+48, py], this.bushSprites[2]);
|
||||
this.scenery[y][x + 1] = new Mario.Prop([px + 16, py], this.bushSprites[1]);
|
||||
this.scenery[y][x + 2] = new Mario.Prop([px + 32, py], this.bushSprites[1]);
|
||||
this.scenery[y][x + 3] = new Mario.Prop([px + 48, py], this.bushSprites[2]);
|
||||
};
|
||||
|
||||
Level.prototype.putSmallHill = function(x, y) {
|
||||
var px = x*16, py = y*16;
|
||||
Level.prototype.putSmallHill = function (x, y) {
|
||||
var px = x * 16,
|
||||
py = y * 16;
|
||||
this.scenery[y][x] = new Mario.Prop([px, py], this.hillSprites[0]);
|
||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.hillSprites[3]);
|
||||
this.scenery[y-1][x+1] = new Mario.Prop([px+16, py-16], this.hillSprites[1]);
|
||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.hillSprites[2]);
|
||||
this.scenery[y][x + 1] = new Mario.Prop([px + 16, py], this.hillSprites[3]);
|
||||
this.scenery[y - 1][x + 1] = new Mario.Prop(
|
||||
[px + 16, py - 16],
|
||||
this.hillSprites[1],
|
||||
);
|
||||
this.scenery[y][x + 2] = new Mario.Prop([px + 32, py], this.hillSprites[2]);
|
||||
};
|
||||
|
||||
Level.prototype.putTwoCloud = function(x,y) {
|
||||
px = x*16;
|
||||
py = y*16;
|
||||
Level.prototype.putTwoCloud = function (x, y) {
|
||||
px = x * 16;
|
||||
py = y * 16;
|
||||
this.scenery[y][x] = new Mario.Prop([px, py], this.cloudSprites[0]);
|
||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.cloudSprites[1]);
|
||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.cloudSprites[1]);
|
||||
this.scenery[y][x+3] = new Mario.Prop([px+48, py], this.cloudSprites[2]);
|
||||
this.scenery[y][x + 1] = new Mario.Prop(
|
||||
[px + 16, py],
|
||||
this.cloudSprites[1],
|
||||
);
|
||||
this.scenery[y][x + 2] = new Mario.Prop(
|
||||
[px + 32, py],
|
||||
this.cloudSprites[1],
|
||||
);
|
||||
this.scenery[y][x + 3] = new Mario.Prop(
|
||||
[px + 48, py],
|
||||
this.cloudSprites[2],
|
||||
);
|
||||
};
|
||||
|
||||
Level.prototype.putThreeCloud = function(x,y) {
|
||||
px = x*16;
|
||||
py = y*16;
|
||||
Level.prototype.putThreeCloud = function (x, y) {
|
||||
px = x * 16;
|
||||
py = y * 16;
|
||||
this.scenery[y][x] = new Mario.Prop([px, py], this.cloudSprites[0]);
|
||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.cloudSprites[1]);
|
||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.cloudSprites[1]);
|
||||
this.scenery[y][x+3] = new Mario.Prop([px+48, py], this.cloudSprites[1]);
|
||||
this.scenery[y][x+4] = new Mario.Prop([px+64, py], this.cloudSprites[2]);
|
||||
this.scenery[y][x + 1] = new Mario.Prop(
|
||||
[px + 16, py],
|
||||
this.cloudSprites[1],
|
||||
);
|
||||
this.scenery[y][x + 2] = new Mario.Prop(
|
||||
[px + 32, py],
|
||||
this.cloudSprites[1],
|
||||
);
|
||||
this.scenery[y][x + 3] = new Mario.Prop(
|
||||
[px + 48, py],
|
||||
this.cloudSprites[1],
|
||||
);
|
||||
this.scenery[y][x + 4] = new Mario.Prop(
|
||||
[px + 64, py],
|
||||
this.cloudSprites[2],
|
||||
);
|
||||
};
|
||||
|
||||
Level.prototype.putRealPipe = function(x, y, length, direction, destination) {
|
||||
px = x*16;
|
||||
py = y*16;
|
||||
this.pipes.push(new Mario.Pipe({
|
||||
pos: [px, py],
|
||||
length: length,
|
||||
direction: direction,
|
||||
destination: destination
|
||||
}));
|
||||
}
|
||||
Level.prototype.putRealPipe = function (
|
||||
x,
|
||||
y,
|
||||
length,
|
||||
direction,
|
||||
destination,
|
||||
) {
|
||||
px = x * 16;
|
||||
py = y * 16;
|
||||
this.pipes.push(
|
||||
new Mario.Pipe({
|
||||
pos: [px, py],
|
||||
length: length,
|
||||
direction: direction,
|
||||
destination: destination,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
Level.prototype.putFlagpole = function(x) {
|
||||
this.statics[12][x] = new Mario.Floor([16*x, 192], this.wallSprite);
|
||||
for (i=3; i < 12; i++) {
|
||||
this.scenery[i][x] = new Mario.Prop([16*x, 16*i], this.flagpoleSprites[1])
|
||||
Level.prototype.putFlagpole = function (x) {
|
||||
this.statics[12][x] = new Mario.Floor([16 * x, 192], this.wallSprite);
|
||||
for (i = 3; i < 12; i++) {
|
||||
this.scenery[i][x] = new Mario.Prop(
|
||||
[16 * x, 16 * i],
|
||||
this.flagpoleSprites[1],
|
||||
);
|
||||
}
|
||||
this.scenery[2][x] = new Mario.Prop([16*x, 32], this.flagpoleSprites[0]);
|
||||
this.items.push(new Mario.Flag(16*x));
|
||||
}
|
||||
this.scenery[2][x] = new Mario.Prop([16 * x, 32], this.flagpoleSprites[0]);
|
||||
this.items.push(new Mario.Flag(16 * x));
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
var Mushroom = Mario.Mushroom = function(pos) {
|
||||
var Mushroom = (Mario.Mushroom = function (pos) {
|
||||
this.spawning = false;
|
||||
this.waiting = 0;
|
||||
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: level.superShroomSprite,
|
||||
hitbox: [0,0,16,16]
|
||||
hitbox: [0, 0, 16, 16],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Mario.Util.inherits(Mushroom, Mario.Entity);
|
||||
|
||||
Mushroom.prototype.render = function(ctx, vX, vY) {
|
||||
Mushroom.prototype.render = function (ctx, vX, vY) {
|
||||
if (this.spawning > 1) return;
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
}
|
||||
};
|
||||
|
||||
Mushroom.prototype.spawn = function() {
|
||||
Mushroom.prototype.spawn = function () {
|
||||
if (player.power > 0) {
|
||||
//replace this with a fire flower
|
||||
var ff = new Mario.Fireflower(this.pos)
|
||||
var ff = new Mario.Fireflower(this.pos);
|
||||
ff.spawn();
|
||||
return;
|
||||
}
|
||||
@@ -34,12 +33,12 @@
|
||||
this.targetpos = [];
|
||||
this.targetpos[0] = this.pos[0];
|
||||
this.targetpos[1] = this.pos[1] - 16;
|
||||
}
|
||||
};
|
||||
|
||||
Mushroom.prototype.update = function(dt) {
|
||||
Mushroom.prototype.update = function (dt) {
|
||||
if (this.spawning > 1) {
|
||||
this.spawning -= 1;
|
||||
if (this.spawning == 1) this.vel[1] = -.5;
|
||||
if (this.spawning == 1) this.vel[1] = -0.5;
|
||||
return;
|
||||
}
|
||||
if (this.spawning) {
|
||||
@@ -62,14 +61,14 @@
|
||||
this.pos[1] += this.vel[1];
|
||||
this.sprite.update(dt);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Mushroom.prototype.collideWall = function() {
|
||||
Mushroom.prototype.collideWall = function () {
|
||||
this.vel[0] = -this.vel[0];
|
||||
}
|
||||
};
|
||||
|
||||
Mushroom.prototype.checkCollisions = function() {
|
||||
if(this.spawning) {
|
||||
Mushroom.prototype.checkCollisions = function () {
|
||||
if (this.spawning) {
|
||||
return;
|
||||
}
|
||||
var h = this.pos[1] % 16 == 0 ? 1 : 2;
|
||||
@@ -95,24 +94,36 @@
|
||||
}
|
||||
|
||||
this.isPlayerCollided();
|
||||
}
|
||||
};
|
||||
|
||||
//we have access to player everywhere, so let's just do this.
|
||||
Mushroom.prototype.isPlayerCollided = function() {
|
||||
Mushroom.prototype.isPlayerCollided = function () {
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [this.pos[0] + this.hitbox[0], this.pos[1] + this.hitbox[1]];
|
||||
var hpos2 = [player.pos[0] + player.hitbox[0], player.pos[1] + player.hitbox[1]];
|
||||
var hpos2 = [
|
||||
player.pos[0] + player.hitbox[0],
|
||||
player.pos[1] + player.hitbox[1],
|
||||
];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+player.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+player.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
if (
|
||||
!(
|
||||
hpos1[0] > hpos2[0] + player.hitbox[2] ||
|
||||
hpos1[0] + this.hitbox[2] < hpos2[0]
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!(
|
||||
hpos1[1] > hpos2[1] + player.hitbox[3] ||
|
||||
hpos1[1] + this.hitbox[3] < hpos2[1]
|
||||
)
|
||||
) {
|
||||
player.powerUp(this.idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Mushroom.prototype.bump = function() {
|
||||
Mushroom.prototype.bump = function () {
|
||||
this.vel[1] = -2;
|
||||
}
|
||||
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,97 +1,122 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
//there are too many possible configurations of pipe to capture in a reasonable
|
||||
//set of simple variables. Joints, etc. are just too much.
|
||||
//To that end, the pipe class handles simple pipes, and we'll put together
|
||||
//anything more complex with individual props. OK? OK.
|
||||
Pipe = Mario.Pipe = function(options) {
|
||||
this.pos = options.pos
|
||||
Pipe = Mario.Pipe = function (options) {
|
||||
this.pos = options.pos;
|
||||
|
||||
//NOTE: direction is the direction you move INTO the pipe.
|
||||
this.direction = options.direction
|
||||
this.destination = options.destination
|
||||
this.direction = options.direction;
|
||||
this.destination = options.destination;
|
||||
this.length = options.length;
|
||||
|
||||
if (this.direction === "UP" || this.direction === "DOWN") {
|
||||
this.hitbox = [0,0, 32, this.length * 16];
|
||||
this.hitbox = [0, 0, 32, this.length * 16];
|
||||
this.midsection = level.pipeUpMid;
|
||||
this.endsection = level.pipeTop;
|
||||
} else {
|
||||
this.hitbox = [0,0, 16*this.length, 32];
|
||||
this.hitbox = [0, 0, 16 * this.length, 32];
|
||||
this.midsection = level.pipeSideMid;
|
||||
this.endsection = level.pipeLeft;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Pipe.prototype.checkPipe = function() {
|
||||
Pipe.prototype.checkPipe = function () {
|
||||
if (this.destination === undefined || !input.isDown(this.direction)) return;
|
||||
|
||||
var h = player.power===0 ? 16 : 32;
|
||||
var h = player.power === 0 ? 16 : 32;
|
||||
var x = Math.floor(player.pos[0]);
|
||||
var y = Math.floor(player.pos[1]);
|
||||
switch (this.direction) {
|
||||
case 'RIGHT': if (x === this.pos[0]-16 &&
|
||||
y >= this.pos[1] &&
|
||||
y+h <= this.pos[1]+32) {
|
||||
player.pipe(this.direction, this.destination)
|
||||
}
|
||||
case "RIGHT":
|
||||
if (
|
||||
x === this.pos[0] - 16 &&
|
||||
y >= this.pos[1] &&
|
||||
y + h <= this.pos[1] + 32
|
||||
) {
|
||||
player.pipe(this.direction, this.destination);
|
||||
}
|
||||
break;
|
||||
case 'LEFT': if (x === this.pos[0]+16*this.length &&
|
||||
y >= this.pos[1] &&
|
||||
y+h <= this.pos[1]+32) {
|
||||
player.pipe(this.direction, this.destination)
|
||||
}
|
||||
case "LEFT":
|
||||
if (
|
||||
x === this.pos[0] + 16 * this.length &&
|
||||
y >= this.pos[1] &&
|
||||
y + h <= this.pos[1] + 32
|
||||
) {
|
||||
player.pipe(this.direction, this.destination);
|
||||
}
|
||||
break;
|
||||
case 'UP': if (y === this.pos[1] + 16*this.length &&
|
||||
x >= this.pos[0] &&
|
||||
x+16 <= this.pos[0]+32) {
|
||||
player.pipe(this.direction, this.destination)
|
||||
}
|
||||
case "UP":
|
||||
if (
|
||||
y === this.pos[1] + 16 * this.length &&
|
||||
x >= this.pos[0] &&
|
||||
x + 16 <= this.pos[0] + 32
|
||||
) {
|
||||
player.pipe(this.direction, this.destination);
|
||||
}
|
||||
break;
|
||||
case 'DOWN': if (y+h === this.pos[1] &&
|
||||
x >= this.pos[0] &&
|
||||
x+16 <= this.pos[0]+32) {
|
||||
player.pipe(this.direction, this.destination);
|
||||
}
|
||||
case "DOWN":
|
||||
if (
|
||||
y + h === this.pos[1] &&
|
||||
x >= this.pos[0] &&
|
||||
x + 16 <= this.pos[0] + 32
|
||||
) {
|
||||
player.pipe(this.direction, this.destination);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//Note to self: next time, decide on a convention for which thing checks for collisions
|
||||
//and stick to it. This is a pain.
|
||||
Pipe.prototype.checkCollisions = function() {
|
||||
Pipe.prototype.checkCollisions = function () {
|
||||
var that = this;
|
||||
level.enemies.forEach (function(ent) {
|
||||
level.enemies.forEach(function (ent) {
|
||||
that.isCollideWith(ent);
|
||||
});
|
||||
|
||||
level.items.forEach (function(ent) {
|
||||
level.items.forEach(function (ent) {
|
||||
that.isCollideWith(ent);
|
||||
});
|
||||
|
||||
fireballs.forEach(function(ent){
|
||||
that.isCollideWith(ent)
|
||||
fireballs.forEach(function (ent) {
|
||||
that.isCollideWith(ent);
|
||||
});
|
||||
|
||||
if (!player.piping) this.isCollideWith(player);
|
||||
}
|
||||
};
|
||||
|
||||
Pipe.prototype.isCollideWith = function (ent) {
|
||||
//long story short: because we scan every item, and and one 'rubble' item is four things with separate positions
|
||||
//we'll crash without this line as soon as we destroy a block. OOPS.
|
||||
if (ent.pos === undefined) return;
|
||||
|
||||
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [Math.floor(this.pos[0] + this.hitbox[0]), Math.floor(this.pos[1] + this.hitbox[1])];
|
||||
var hpos2 = [Math.floor(ent.pos[0] + ent.hitbox[0]), Math.floor(ent.pos[1] + ent.hitbox[1])];
|
||||
var hpos1 = [
|
||||
Math.floor(this.pos[0] + this.hitbox[0]),
|
||||
Math.floor(this.pos[1] + this.hitbox[1]),
|
||||
];
|
||||
var hpos2 = [
|
||||
Math.floor(ent.pos[0] + ent.hitbox[0]),
|
||||
Math.floor(ent.pos[1] + ent.hitbox[1]),
|
||||
];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+ent.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+ent.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
if (
|
||||
!(
|
||||
hpos1[0] > hpos2[0] + ent.hitbox[2] ||
|
||||
hpos1[0] + this.hitbox[2] < hpos2[0]
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!(
|
||||
hpos1[1] > hpos2[1] + ent.hitbox[3] ||
|
||||
hpos1[1] + this.hitbox[3] < hpos2[1]
|
||||
)
|
||||
) {
|
||||
//if the entity is over the block, it's basically floor
|
||||
var center = hpos2[0] + ent.hitbox[2] / 2;
|
||||
if (Math.abs(hpos2[1] + ent.hitbox[3] - hpos1[1]) <= ent.vel[1]) {
|
||||
@@ -101,8 +126,11 @@
|
||||
if (ent instanceof Mario.Player) {
|
||||
ent.jumping = 0;
|
||||
}
|
||||
} else if (Math.abs(hpos2[1] - hpos1[1] - this.hitbox[3]) > ent.vel[1] &&
|
||||
center + 2 >= hpos1[0] && center - 2 <= hpos1[0] + this.hitbox[2]) {
|
||||
} else if (
|
||||
Math.abs(hpos2[1] - hpos1[1] - this.hitbox[3]) > ent.vel[1] &&
|
||||
center + 2 >= hpos1[0] &&
|
||||
center - 2 <= hpos1[0] + this.hitbox[2]
|
||||
) {
|
||||
//ent is under the block.
|
||||
ent.vel[1] = 0;
|
||||
ent.pos[1] = hpos1[1] + this.hitbox[3];
|
||||
@@ -115,46 +143,82 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//we COULD try to write some shenanigans so that the check gets put into the
|
||||
//collision code, but there won't ever be more than a handful of pipes in a level
|
||||
//so the performance hit of scanning all of them is miniscule.
|
||||
Pipe.prototype.update = function(dt) {
|
||||
Pipe.prototype.update = function (dt) {
|
||||
if (this.destination) this.checkPipe();
|
||||
}
|
||||
};
|
||||
|
||||
//http://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-an-unsorted-array
|
||||
//I honestly have no idea if javascript does this, but I feel like it makes sense
|
||||
//stylistically to prefer branching outside of loops when possible as convention
|
||||
|
||||
//TODO: edit the spritesheet so UP and LEFT pipes aren't backwards.
|
||||
Pipe.prototype.render = function(ctx, vX, vY) {
|
||||
Pipe.prototype.render = function (ctx, vX, vY) {
|
||||
switch (this.direction) {
|
||||
case "DOWN":
|
||||
this.endsection.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
for (var i = 1; i < this.length; i++) {
|
||||
this.midsection.render(ctx, this.pos[0], this.pos[1]+i*16, vX, vY)
|
||||
this.midsection.render(
|
||||
ctx,
|
||||
this.pos[0],
|
||||
this.pos[1] + i * 16,
|
||||
vX,
|
||||
vY,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "UP":
|
||||
this.endsection.render(ctx, this.pos[0], this.pos[1]+16*(this.length-1), vX, vY)
|
||||
for (var i=0; i < this.length - 1; i++) {
|
||||
this.midsection.render(ctx, this.pos[0], this.pos[1]+i*16, vX, vY)
|
||||
this.endsection.render(
|
||||
ctx,
|
||||
this.pos[0],
|
||||
this.pos[1] + 16 * (this.length - 1),
|
||||
vX,
|
||||
vY,
|
||||
);
|
||||
for (var i = 0; i < this.length - 1; i++) {
|
||||
this.midsection.render(
|
||||
ctx,
|
||||
this.pos[0],
|
||||
this.pos[1] + i * 16,
|
||||
vX,
|
||||
vY,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "RIGHT":
|
||||
this.endsection.render(ctx, this.pos[0], this.pos[1], vX, vY)
|
||||
this.endsection.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
for (var i = 1; i < this.length; i++) {
|
||||
this.midsection.render(ctx, this.pos[0]+16*i, this.pos[1], vX, vY)
|
||||
this.midsection.render(
|
||||
ctx,
|
||||
this.pos[0] + 16 * i,
|
||||
this.pos[1],
|
||||
vX,
|
||||
vY,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "LEFT":
|
||||
this.endsection.render(ctx, this.pos[0]+16*(this.length-1), this.pos[1], vX, vY)
|
||||
for (var i = 0; i < this.legth-1; i++) {
|
||||
this.midsection.render(ctx, this.pos[0], this.pos[1]+i*16, vX, vY)
|
||||
this.endsection.render(
|
||||
ctx,
|
||||
this.pos[0] + 16 * (this.length - 1),
|
||||
this.pos[1],
|
||||
vX,
|
||||
vY,
|
||||
);
|
||||
for (var i = 0; i < this.legth - 1; i++) {
|
||||
this.midsection.render(
|
||||
ctx,
|
||||
this.pos[0],
|
||||
this.pos[1] + i * 16,
|
||||
vX,
|
||||
vY,
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,446 +1,498 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
var Player = Mario.Player = function(pos) {
|
||||
//I know, I know, there are a lot of variables tracking Mario's state.
|
||||
//Maybe these can be consolidated some way? We'll see once they're all in.
|
||||
this.power = 0;
|
||||
this.coins = 0;
|
||||
this.powering = [];
|
||||
this.bounce = false;
|
||||
this.jumping = 0;
|
||||
this.canJump = true;
|
||||
this.invincibility = 0;
|
||||
this.crouching = false;
|
||||
this.fireballs = 0;
|
||||
this.runheld = false;
|
||||
this.noInput = false;
|
||||
this.targetPos = [];
|
||||
var Player = (Mario.Player = function (pos) {
|
||||
//I know, I know, there are a lot of variables tracking Mario's state.
|
||||
//Maybe these can be consolidated some way? We'll see once they're all in.
|
||||
this.power = 0;
|
||||
this.coins = 0;
|
||||
this.powering = [];
|
||||
this.bounce = false;
|
||||
this.jumping = 0;
|
||||
this.canJump = true;
|
||||
this.invincibility = 0;
|
||||
this.crouching = false;
|
||||
this.fireballs = 0;
|
||||
this.runheld = false;
|
||||
this.noInput = false;
|
||||
this.targetPos = [];
|
||||
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: new Mario.Sprite('sprites/player.png', [80,32],[16,16],0),
|
||||
hitbox: [0,0,16,16]
|
||||
});
|
||||
};
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: new Mario.Sprite("sprites/player.png", [80, 32], [16, 16], 0),
|
||||
hitbox: [0, 0, 16, 16],
|
||||
});
|
||||
});
|
||||
|
||||
Mario.Util.inherits(Player, Mario.Entity);
|
||||
Mario.Util.inherits(Player, Mario.Entity);
|
||||
|
||||
Player.prototype.run = function() {
|
||||
this.maxSpeed = 2.5;
|
||||
if (this.power == 2 && !this.runheld) {
|
||||
this.shoot();
|
||||
}
|
||||
this.runheld = true;
|
||||
}
|
||||
|
||||
Player.prototype.shoot = function() {
|
||||
if (this.fireballs >= 2) return; //Projectile limit!
|
||||
this.fireballs += 1;
|
||||
var fb = new Mario.Fireball([this.pos[0]+8,this.pos[1]]); //I hate you, Javascript.
|
||||
fb.spawn(this.left);
|
||||
this.shooting = 2;
|
||||
}
|
||||
|
||||
Player.prototype.noRun = function() {
|
||||
this.maxSpeed = 1.5;
|
||||
this.moveAcc = 0.07;
|
||||
this.runheld = false;
|
||||
}
|
||||
|
||||
Player.prototype.moveRight = function() {
|
||||
//we're on the ground
|
||||
if (this.vel[1] === 0 && this.standing) {
|
||||
if (this.crouching) {
|
||||
this.noWalk();
|
||||
return;
|
||||
}
|
||||
this.acc[0] = this.moveAcc;
|
||||
this.left = false;
|
||||
} else {
|
||||
this.acc[0] = this.moveAcc;
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.moveLeft = function() {
|
||||
if (this.vel[1] === 0 && this.standing) {
|
||||
if (this.crouching) {
|
||||
this.noWalk();
|
||||
return;
|
||||
}
|
||||
this.acc[0] = -this.moveAcc;
|
||||
this.left = true;
|
||||
} else {
|
||||
this.acc[0] = -this.moveAcc;
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.noWalk = function() {
|
||||
this.maxSpeed = 0;
|
||||
if (this.vel[0] === 0) return;
|
||||
|
||||
if (Math.abs(this.vel[0]) <= 0.1) {
|
||||
this.vel[0] = 0;
|
||||
this.acc[0] = 0;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Player.prototype.crouch = function() {
|
||||
if (this.power === 0) {
|
||||
this.crouching = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.standing) this.crouching = true;
|
||||
}
|
||||
|
||||
Player.prototype.noCrouch = function() {
|
||||
this.crouching = false;
|
||||
}
|
||||
|
||||
Player.prototype.jump = function() {
|
||||
if (this.vel[1] > 0) {
|
||||
return;
|
||||
}
|
||||
if (this.jumping) {
|
||||
this.jumping -= 1;
|
||||
} else if (this.standing && this.canJump) {
|
||||
this.jumping = 20;
|
||||
this.canJump = false;
|
||||
this.standing = false;
|
||||
this.vel[1] = -6;
|
||||
if (this.power === 0) {
|
||||
sounds.smallJump.currentTime = 0;
|
||||
sounds.smallJump.play();
|
||||
} else {
|
||||
sounds.bigJump.currentTime = 0;
|
||||
sounds.bigJump.play();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.noJump = function() {
|
||||
this.canJump = true;
|
||||
if (this.jumping) {
|
||||
if (this.jumping <= 16) {
|
||||
this.vel[1] = 0;
|
||||
this.jumping = 0;
|
||||
} else this.jumping -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.setAnimation = function() {
|
||||
if (this.dying) return;
|
||||
|
||||
if (this.starTime) {
|
||||
var index;
|
||||
if (this.starTime > 60)
|
||||
index = Math.floor(this.starTime / 2) % 3;
|
||||
else index = Math.floor(this.starTime / 8) % 3;
|
||||
|
||||
this.sprite.pos[1] = level.invincibility[index];
|
||||
if (this.power == 0) {
|
||||
this.sprite.pos[1] += 32;
|
||||
}
|
||||
this.starTime -= 1;
|
||||
if (this.starTime == 0) {
|
||||
switch(this.power) {
|
||||
case 0: this.sprite.pos[1] = 32; break;
|
||||
case 1: this.sprite.pos[1] = 0; break;
|
||||
case 2: this.sprite.pos[1] = 96; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//okay cool, now set the sprite
|
||||
if (this.crouching) {
|
||||
this.sprite.pos[0] = 176;
|
||||
this.sprite.speed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.jumping) {
|
||||
this.sprite.pos[0] = 160;
|
||||
this.sprite.speed = 0;
|
||||
} else if (this.standing) {
|
||||
if (Math.abs(this.vel[0]) > 0) {
|
||||
if (this.vel[0] * this.acc[0] >= 0) {
|
||||
this.sprite.pos[0] = 96;
|
||||
this.sprite.frames = [0,1,2];
|
||||
if (this.vel[0] < 0.2) {
|
||||
this.sprite.speed = 5;
|
||||
} else {
|
||||
this.sprite.speed = Math.abs(this.vel[0]) * 8;
|
||||
}
|
||||
} else if ((this.vel[0] > 0 && this.left) || (this.vel[0] < 0 && !this.left)){
|
||||
this.sprite.pos[0] = 144;
|
||||
this.sprite.speed = 0;
|
||||
}
|
||||
} else {
|
||||
this.sprite.pos[0] = 80;
|
||||
this.sprite.speed = 0;
|
||||
}
|
||||
if (this.shooting) {
|
||||
this.sprite.pos[0] += 160;
|
||||
this.shooting -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.flagging) {
|
||||
this.sprite.pos[0] = 192;
|
||||
this.sprite.frames = [0,1];
|
||||
this.sprite.speed = 10;
|
||||
if (this.vel[1] === 0) this.sprite.frames = [0];
|
||||
}
|
||||
|
||||
//which way are we facing?
|
||||
if (this.left) {
|
||||
this.sprite.img = 'sprites/playerl.png';
|
||||
} else {
|
||||
this.sprite.img = 'sprites/player.png';
|
||||
}
|
||||
Player.prototype.run = function () {
|
||||
this.maxSpeed = 2.5;
|
||||
if (this.power == 2 && !this.runheld) {
|
||||
this.shoot();
|
||||
}
|
||||
this.runheld = true;
|
||||
};
|
||||
|
||||
Player.prototype.update = function(dt, vX) {
|
||||
if (this.powering.length !== 0) {
|
||||
var next = this.powering.shift();
|
||||
if (next == 5) return;
|
||||
this.sprite.pos = this.powerSprites[next];
|
||||
this.sprite.size = this.powerSizes[next];
|
||||
this.pos[1] += this.shift[next];
|
||||
if (this.powering.length === 0) {
|
||||
delete level.items[this.touchedItem];
|
||||
}
|
||||
return;
|
||||
}
|
||||
Player.prototype.shoot = function () {
|
||||
if (this.fireballs >= 2) return; //Projectile limit!
|
||||
this.fireballs += 1;
|
||||
var fb = new Mario.Fireball([this.pos[0] + 8, this.pos[1]]); //I hate you, Javascript.
|
||||
fb.spawn(this.left);
|
||||
this.shooting = 2;
|
||||
};
|
||||
|
||||
if (this.invincibility) {
|
||||
this.invincibility -= Math.round(dt * 60);
|
||||
}
|
||||
Player.prototype.noRun = function () {
|
||||
this.maxSpeed = 1.5;
|
||||
this.moveAcc = 0.07;
|
||||
this.runheld = false;
|
||||
};
|
||||
|
||||
if (this.waiting) {
|
||||
this.waiting -= dt;
|
||||
if (this.waiting <= 0) {
|
||||
this.waiting = 0;
|
||||
} else return;
|
||||
}
|
||||
Player.prototype.moveRight = function () {
|
||||
//we're on the ground
|
||||
if (this.vel[1] === 0 && this.standing) {
|
||||
if (this.crouching) {
|
||||
this.noWalk();
|
||||
return;
|
||||
}
|
||||
this.acc[0] = this.moveAcc;
|
||||
this.left = false;
|
||||
} else {
|
||||
this.acc[0] = this.moveAcc;
|
||||
}
|
||||
};
|
||||
|
||||
if (this.bounce) {
|
||||
this.bounce = false;
|
||||
this.standing = false;
|
||||
this.vel[1] = -3;
|
||||
}
|
||||
Player.prototype.moveLeft = function () {
|
||||
if (this.vel[1] === 0 && this.standing) {
|
||||
if (this.crouching) {
|
||||
this.noWalk();
|
||||
return;
|
||||
}
|
||||
this.acc[0] = -this.moveAcc;
|
||||
this.left = true;
|
||||
} else {
|
||||
this.acc[0] = -this.moveAcc;
|
||||
}
|
||||
};
|
||||
|
||||
if (this.pos[0] <= vX) {
|
||||
this.pos[0] = vX;
|
||||
this.vel[0] = Math.max(this.vel[0], 0);
|
||||
}
|
||||
Player.prototype.noWalk = function () {
|
||||
this.maxSpeed = 0;
|
||||
if (this.vel[0] === 0) return;
|
||||
|
||||
if (Math.abs(this.vel[0]) > this.maxSpeed) {
|
||||
this.vel[0] -= 0.05 * this.vel[0] / Math.abs(this.vel[0]);
|
||||
this.acc[0] = 0;
|
||||
}
|
||||
if (Math.abs(this.vel[0]) <= 0.1) {
|
||||
this.vel[0] = 0;
|
||||
this.acc[0] = 0;
|
||||
}
|
||||
};
|
||||
|
||||
if (this.dying){
|
||||
if (this.pos[1] < this.targetPos[1]) {
|
||||
this.vel[1] = 1;
|
||||
}
|
||||
this.dying -= 1 * dt;
|
||||
if (this.dying <= 0) {
|
||||
player = new Mario.Player(level.playerPos);
|
||||
level.loader.call();
|
||||
input.reset();
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.acc[1] = 0.25
|
||||
if (this.pos[1] > 240) {
|
||||
this.die();
|
||||
}
|
||||
}
|
||||
Player.prototype.crouch = function () {
|
||||
if (this.power === 0) {
|
||||
this.crouching = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.piping) {
|
||||
this.acc = [0,0];
|
||||
var pos = [Math.round(this.pos[0]), Math.round(this.pos[1])]
|
||||
if (pos[0] === this.targetPos[0] && pos[1] === this.targetPos[1]) {
|
||||
this.piping = false;
|
||||
this.pipeLoc.call();
|
||||
}
|
||||
}
|
||||
if (this.standing) this.crouching = true;
|
||||
};
|
||||
|
||||
if (this.flagging) {
|
||||
this.acc = [0,0];
|
||||
}
|
||||
Player.prototype.noCrouch = function () {
|
||||
this.crouching = false;
|
||||
};
|
||||
|
||||
if (this.exiting) {
|
||||
this.left = false;
|
||||
this.flagging = false;
|
||||
this.vel[0] = 1.5;
|
||||
if (this.pos[0] >= this.targetPos[0]) {
|
||||
this.sprite.size = [0,0];
|
||||
this.vel = [0,0];
|
||||
window.setTimeout(function() {
|
||||
player.sprite.size = player.power===0 ? [16,16] : [16,32];
|
||||
player.exiting = false;
|
||||
player.noInput = false;
|
||||
level.loader();
|
||||
if (player.power !== 0) player.pos[1] -= 16;
|
||||
music.overworld.currentTime = 0;
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
Player.prototype.jump = function () {
|
||||
if (this.vel[1] > 0) {
|
||||
return;
|
||||
}
|
||||
if (this.jumping) {
|
||||
this.jumping -= 1;
|
||||
} else if (this.standing && this.canJump) {
|
||||
this.jumping = 20;
|
||||
this.canJump = false;
|
||||
this.standing = false;
|
||||
this.vel[1] = -6;
|
||||
if (this.power === 0) {
|
||||
sounds.smallJump.currentTime = 0;
|
||||
sounds.smallJump.play();
|
||||
} else {
|
||||
sounds.bigJump.currentTime = 0;
|
||||
sounds.bigJump.play();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//approximate acceleration
|
||||
this.vel[0] += this.acc[0];
|
||||
this.vel[1] += this.acc[1];
|
||||
this.pos[0] += this.vel[0];
|
||||
this.pos[1] += this.vel[1];
|
||||
Player.prototype.noJump = function () {
|
||||
this.canJump = true;
|
||||
if (this.jumping) {
|
||||
if (this.jumping <= 16) {
|
||||
this.vel[1] = 0;
|
||||
this.jumping = 0;
|
||||
} else this.jumping -= 1;
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.setAnimation = function () {
|
||||
if (this.dying) return;
|
||||
|
||||
if (this.starTime) {
|
||||
var index;
|
||||
if (this.starTime > 60) index = Math.floor(this.starTime / 2) % 3;
|
||||
else index = Math.floor(this.starTime / 8) % 3;
|
||||
|
||||
this.sprite.pos[1] = level.invincibility[index];
|
||||
if (this.power == 0) {
|
||||
this.sprite.pos[1] += 32;
|
||||
}
|
||||
this.starTime -= 1;
|
||||
if (this.starTime == 0) {
|
||||
switch (this.power) {
|
||||
case 0:
|
||||
this.sprite.pos[1] = 32;
|
||||
break;
|
||||
case 1:
|
||||
this.sprite.pos[1] = 0;
|
||||
break;
|
||||
case 2:
|
||||
this.sprite.pos[1] = 96;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//okay cool, now set the sprite
|
||||
if (this.crouching) {
|
||||
this.sprite.pos[0] = 176;
|
||||
this.sprite.speed = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.jumping) {
|
||||
this.sprite.pos[0] = 160;
|
||||
this.sprite.speed = 0;
|
||||
} else if (this.standing) {
|
||||
if (Math.abs(this.vel[0]) > 0) {
|
||||
if (this.vel[0] * this.acc[0] >= 0) {
|
||||
this.sprite.pos[0] = 96;
|
||||
this.sprite.frames = [0, 1, 2];
|
||||
if (this.vel[0] < 0.2) {
|
||||
this.sprite.speed = 5;
|
||||
} else {
|
||||
this.sprite.speed = Math.abs(this.vel[0]) * 8;
|
||||
}
|
||||
} else if (
|
||||
(this.vel[0] > 0 && this.left) ||
|
||||
(this.vel[0] < 0 && !this.left)
|
||||
) {
|
||||
this.sprite.pos[0] = 144;
|
||||
this.sprite.speed = 0;
|
||||
}
|
||||
} else {
|
||||
this.sprite.pos[0] = 80;
|
||||
this.sprite.speed = 0;
|
||||
}
|
||||
if (this.shooting) {
|
||||
this.sprite.pos[0] += 160;
|
||||
this.shooting -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.flagging) {
|
||||
this.sprite.pos[0] = 192;
|
||||
this.sprite.frames = [0, 1];
|
||||
this.sprite.speed = 10;
|
||||
if (this.vel[1] === 0) this.sprite.frames = [0];
|
||||
}
|
||||
|
||||
//which way are we facing?
|
||||
if (this.left) {
|
||||
this.sprite.img = "sprites/playerl.png";
|
||||
} else {
|
||||
this.sprite.img = "sprites/player.png";
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.update = function (dt, vX) {
|
||||
if (this.powering.length !== 0) {
|
||||
var next = this.powering.shift();
|
||||
if (next == 5) return;
|
||||
this.sprite.pos = this.powerSprites[next];
|
||||
this.sprite.size = this.powerSizes[next];
|
||||
this.pos[1] += this.shift[next];
|
||||
if (this.powering.length === 0) {
|
||||
delete level.items[this.touchedItem];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.invincibility) {
|
||||
this.invincibility -= Math.round(dt * 60);
|
||||
}
|
||||
|
||||
if (this.waiting) {
|
||||
this.waiting -= dt;
|
||||
if (this.waiting <= 0) {
|
||||
this.waiting = 0;
|
||||
} else return;
|
||||
}
|
||||
|
||||
if (this.bounce) {
|
||||
this.bounce = false;
|
||||
this.standing = false;
|
||||
this.vel[1] = -3;
|
||||
}
|
||||
|
||||
if (this.pos[0] <= vX) {
|
||||
this.pos[0] = vX;
|
||||
this.vel[0] = Math.max(this.vel[0], 0);
|
||||
}
|
||||
|
||||
if (Math.abs(this.vel[0]) > this.maxSpeed) {
|
||||
this.vel[0] -= (0.05 * this.vel[0]) / Math.abs(this.vel[0]);
|
||||
this.acc[0] = 0;
|
||||
}
|
||||
|
||||
if (this.dying) {
|
||||
if (this.pos[1] < this.targetPos[1]) {
|
||||
this.vel[1] = 1;
|
||||
}
|
||||
this.dying -= 1 * dt;
|
||||
if (this.dying <= 0) {
|
||||
player = new Mario.Player(level.playerPos);
|
||||
level.loader.call();
|
||||
input.reset();
|
||||
}
|
||||
} else {
|
||||
this.acc[1] = 0.25;
|
||||
if (this.pos[1] > 240) {
|
||||
this.die();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.piping) {
|
||||
this.acc = [0, 0];
|
||||
var pos = [Math.round(this.pos[0]), Math.round(this.pos[1])];
|
||||
if (pos[0] === this.targetPos[0] && pos[1] === this.targetPos[1]) {
|
||||
this.piping = false;
|
||||
this.pipeLoc.call();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.flagging) {
|
||||
this.acc = [0, 0];
|
||||
}
|
||||
|
||||
if (this.exiting) {
|
||||
this.left = false;
|
||||
this.flagging = false;
|
||||
this.vel[0] = 1.5;
|
||||
if (this.pos[0] >= this.targetPos[0]) {
|
||||
this.sprite.size = [0, 0];
|
||||
this.vel = [0, 0];
|
||||
window.setTimeout(function () {
|
||||
player.sprite.size = player.power === 0 ? [16, 16] : [16, 32];
|
||||
player.exiting = false;
|
||||
player.noInput = false;
|
||||
level.loader();
|
||||
if (player.power !== 0) player.pos[1] -= 16;
|
||||
music.overworld.currentTime = 0;
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
//approximate acceleration
|
||||
this.vel[0] += this.acc[0];
|
||||
this.vel[1] += this.acc[1];
|
||||
this.pos[0] += this.vel[0];
|
||||
this.pos[1] += this.vel[1];
|
||||
|
||||
this.setAnimation();
|
||||
this.sprite.update(dt);
|
||||
};
|
||||
this.sprite.update(dt);
|
||||
};
|
||||
|
||||
Player.prototype.checkCollisions = function() {
|
||||
if (this.piping || this.dying) return;
|
||||
//x-axis first!
|
||||
var h = this.power > 0 ? 2 : 1;
|
||||
var w = 1;
|
||||
if (this.pos[1] % 16 !== 0) {
|
||||
h += 1;
|
||||
}
|
||||
if (this.pos[0] % 16 !== 0) {
|
||||
w += 1;
|
||||
}
|
||||
var baseX = Math.floor(this.pos[0] / 16);
|
||||
var baseY = Math.floor(this.pos[1] / 16);
|
||||
Player.prototype.checkCollisions = function () {
|
||||
if (this.piping || this.dying) return;
|
||||
//x-axis first!
|
||||
var h = this.power > 0 ? 2 : 1;
|
||||
var w = 1;
|
||||
if (this.pos[1] % 16 !== 0) {
|
||||
h += 1;
|
||||
}
|
||||
if (this.pos[0] % 16 !== 0) {
|
||||
w += 1;
|
||||
}
|
||||
var baseX = Math.floor(this.pos[0] / 16);
|
||||
var baseY = Math.floor(this.pos[1] / 16);
|
||||
|
||||
for (var i = 0; i < h; i++) {
|
||||
if (baseY + i < 0 || baseY + i >= 15) continue;
|
||||
for (var j = 0; j < w; j++) {
|
||||
if (baseY < 0) { i++;}
|
||||
if (level.statics[baseY + i][baseX + j]) {
|
||||
level.statics[baseY + i][baseX + j].isCollideWith(this);
|
||||
}
|
||||
if (level.blocks[baseY + i][baseX + j]) {
|
||||
level.blocks[baseY + i][baseX + j].isCollideWith(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
for (var i = 0; i < h; i++) {
|
||||
if (baseY + i < 0 || baseY + i >= 15) continue;
|
||||
for (var j = 0; j < w; j++) {
|
||||
if (baseY < 0) {
|
||||
i++;
|
||||
}
|
||||
if (level.statics[baseY + i][baseX + j]) {
|
||||
level.statics[baseY + i][baseX + j].isCollideWith(this);
|
||||
}
|
||||
if (level.blocks[baseY + i][baseX + j]) {
|
||||
level.blocks[baseY + i][baseX + j].isCollideWith(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.powerUp = function(idx) {
|
||||
sounds.powerup.play();
|
||||
this.powering = [0,5,2,5,1,5,2,5,1,5,2,5,3,5,1,5,2,5,3,5,1,5,4];
|
||||
this.touchedItem = idx;
|
||||
Player.prototype.powerUp = function (idx) {
|
||||
sounds.powerup.play();
|
||||
this.powering = [
|
||||
0, 5, 2, 5, 1, 5, 2, 5, 1, 5, 2, 5, 3, 5, 1, 5, 2, 5, 3, 5, 1, 5, 4,
|
||||
];
|
||||
this.touchedItem = idx;
|
||||
|
||||
if (this.power === 0) {
|
||||
this.sprite.pos[0] = 80;
|
||||
var newy = this.sprite.pos[1] - 32;
|
||||
this.powerSprites = [[80, newy+32], [80, newy+32], [320, newy], [80, newy], [128, newy]];
|
||||
this.powerSizes = [[16,16],[16,16],[16,32],[16,32],[16,32]];
|
||||
this.shift = [0,16,-16,0,-16];
|
||||
this.power = 1;
|
||||
this.hitbox = [0,0,16,32];
|
||||
} else if (this.power == 1) {
|
||||
var curx = this.sprite.pos[0];
|
||||
this.powerSprites = [[curx, 96], [curx, level.invincibility[0]],
|
||||
[curx, level.invincibility[1]], [curx, level.invincibility[2]],
|
||||
[curx, 96]];
|
||||
this.powerSizes[[16,32],[16,32],[16,32],[16,32],[16,32]];
|
||||
this.shift = [0,0,0,0,0];
|
||||
this.power = 2;
|
||||
} else {
|
||||
this.powering = [];
|
||||
delete level.items[idx];
|
||||
//no animation, but we play the sound and you get 5000 points.
|
||||
}
|
||||
};
|
||||
if (this.power === 0) {
|
||||
this.sprite.pos[0] = 80;
|
||||
var newy = this.sprite.pos[1] - 32;
|
||||
this.powerSprites = [
|
||||
[80, newy + 32],
|
||||
[80, newy + 32],
|
||||
[320, newy],
|
||||
[80, newy],
|
||||
[128, newy],
|
||||
];
|
||||
this.powerSizes = [
|
||||
[16, 16],
|
||||
[16, 16],
|
||||
[16, 32],
|
||||
[16, 32],
|
||||
[16, 32],
|
||||
];
|
||||
this.shift = [0, 16, -16, 0, -16];
|
||||
this.power = 1;
|
||||
this.hitbox = [0, 0, 16, 32];
|
||||
} else if (this.power == 1) {
|
||||
var curx = this.sprite.pos[0];
|
||||
this.powerSprites = [
|
||||
[curx, 96],
|
||||
[curx, level.invincibility[0]],
|
||||
[curx, level.invincibility[1]],
|
||||
[curx, level.invincibility[2]],
|
||||
[curx, 96],
|
||||
];
|
||||
this.powerSizes[([16, 32], [16, 32], [16, 32], [16, 32], [16, 32])];
|
||||
this.shift = [0, 0, 0, 0, 0];
|
||||
this.power = 2;
|
||||
} else {
|
||||
this.powering = [];
|
||||
delete level.items[idx];
|
||||
//no animation, but we play the sound and you get 5000 points.
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.damage = function() {
|
||||
if (this.power === 0) { //if you're already small, you dead!
|
||||
this.die();
|
||||
} else { //otherwise, you get turned into small mario
|
||||
sounds.pipe.play();
|
||||
this.powering = [0,5,1,5,2,5,1,5,2,5,1,5,2,5,1,5,2,5,1,5,2,5,3];
|
||||
this.shift = [0,16,-16,16];
|
||||
this.sprite.pos = [160, 0];
|
||||
this.powerSprites = [[160,0], [240, 32], [240, 0], [160, 32]];
|
||||
this.powerSizes = [[16, 32], [16,16], [16,32], [16,16]];
|
||||
this.invincibility = 120;
|
||||
this.power = 0;
|
||||
this.hitbox = [0,0,16,16];
|
||||
}
|
||||
};
|
||||
Player.prototype.damage = function () {
|
||||
if (this.power === 0) {
|
||||
//if you're already small, you dead!
|
||||
this.die();
|
||||
} else {
|
||||
//otherwise, you get turned into small mario
|
||||
sounds.pipe.play();
|
||||
this.powering = [
|
||||
0, 5, 1, 5, 2, 5, 1, 5, 2, 5, 1, 5, 2, 5, 1, 5, 2, 5, 1, 5, 2, 5, 3,
|
||||
];
|
||||
this.shift = [0, 16, -16, 16];
|
||||
this.sprite.pos = [160, 0];
|
||||
this.powerSprites = [
|
||||
[160, 0],
|
||||
[240, 32],
|
||||
[240, 0],
|
||||
[160, 32],
|
||||
];
|
||||
this.powerSizes = [
|
||||
[16, 32],
|
||||
[16, 16],
|
||||
[16, 32],
|
||||
[16, 16],
|
||||
];
|
||||
this.invincibility = 120;
|
||||
this.power = 0;
|
||||
this.hitbox = [0, 0, 16, 16];
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.die = function () {
|
||||
//TODO: rewrite the way sounds work to emulate the channels of an NES.
|
||||
music.overworld.pause();
|
||||
music.underground.pause();
|
||||
music.overworld.currentTime = 0;
|
||||
music.death.play();
|
||||
this.noWalk();
|
||||
this.noRun();
|
||||
this.noJump();
|
||||
Player.prototype.die = function () {
|
||||
//TODO: rewrite the way sounds work to emulate the channels of an NES.
|
||||
music.overworld.pause();
|
||||
music.underground.pause();
|
||||
music.overworld.currentTime = 0;
|
||||
music.death.play();
|
||||
this.noWalk();
|
||||
this.noRun();
|
||||
this.noJump();
|
||||
|
||||
this.acc[0] = 0;
|
||||
this.sprite.pos = [176, 32];
|
||||
this.sprite.speed = 0;
|
||||
this.power = 0;
|
||||
this.waiting = 0.5;
|
||||
this.dying = 2;
|
||||
this.acc[0] = 0;
|
||||
this.sprite.pos = [176, 32];
|
||||
this.sprite.speed = 0;
|
||||
this.power = 0;
|
||||
this.waiting = 0.5;
|
||||
this.dying = 2;
|
||||
|
||||
if (this.pos[1] < 240) { //falling into a pit doesn't do the animation.
|
||||
this.targetPos = [this.pos[0], this.pos[1]-128];
|
||||
this.vel = [0,-5];
|
||||
} else {
|
||||
this.vel = [0,0];
|
||||
this.targetPos = [this.pos[0], this.pos[1] - 16];
|
||||
}
|
||||
};
|
||||
if (this.pos[1] < 240) {
|
||||
//falling into a pit doesn't do the animation.
|
||||
this.targetPos = [this.pos[0], this.pos[1] - 128];
|
||||
this.vel = [0, -5];
|
||||
} else {
|
||||
this.vel = [0, 0];
|
||||
this.targetPos = [this.pos[0], this.pos[1] - 16];
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.star = function(idx) {
|
||||
delete level.items[idx];
|
||||
this.starTime = 660;
|
||||
}
|
||||
Player.prototype.star = function (idx) {
|
||||
delete level.items[idx];
|
||||
this.starTime = 660;
|
||||
};
|
||||
|
||||
Player.prototype.pipe = function(direction, destination) {
|
||||
sounds.pipe.play();
|
||||
this.piping = true;
|
||||
this.pipeLoc = destination;
|
||||
switch(direction) {
|
||||
case "LEFT":
|
||||
this.vel = [-1,0];
|
||||
this.targetPos = [Math.round(this.pos[0]-16), Math.round(this.pos[1])]
|
||||
break;
|
||||
case "RIGHT":
|
||||
this.vel = [1,0];
|
||||
this.targetPos = [Math.round(this.pos[0]+16), Math.round(this.pos[1])]
|
||||
break;
|
||||
case "DOWN":
|
||||
this.vel = [0,1];
|
||||
this.targetPos = [Math.round(this.pos[0]), Math.round(this.pos[1]+this.hitbox[3])]
|
||||
break;
|
||||
case "UP":
|
||||
this.vel = [0,-1];
|
||||
this.targetPos = [Math.round(this.pos[0]), Math.round(this.pos[1]-this.hitbox[3])]
|
||||
break;
|
||||
}
|
||||
}
|
||||
Player.prototype.pipe = function (direction, destination) {
|
||||
sounds.pipe.play();
|
||||
this.piping = true;
|
||||
this.pipeLoc = destination;
|
||||
switch (direction) {
|
||||
case "LEFT":
|
||||
this.vel = [-1, 0];
|
||||
this.targetPos = [
|
||||
Math.round(this.pos[0] - 16),
|
||||
Math.round(this.pos[1]),
|
||||
];
|
||||
break;
|
||||
case "RIGHT":
|
||||
this.vel = [1, 0];
|
||||
this.targetPos = [
|
||||
Math.round(this.pos[0] + 16),
|
||||
Math.round(this.pos[1]),
|
||||
];
|
||||
break;
|
||||
case "DOWN":
|
||||
this.vel = [0, 1];
|
||||
this.targetPos = [
|
||||
Math.round(this.pos[0]),
|
||||
Math.round(this.pos[1] + this.hitbox[3]),
|
||||
];
|
||||
break;
|
||||
case "UP":
|
||||
this.vel = [0, -1];
|
||||
this.targetPos = [
|
||||
Math.round(this.pos[0]),
|
||||
Math.round(this.pos[1] - this.hitbox[3]),
|
||||
];
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
Player.prototype.flag = function() {
|
||||
this.noInput = true;
|
||||
this.flagging = true;
|
||||
this.vel = [0, 2];
|
||||
this.acc = [0, 0];
|
||||
}
|
||||
Player.prototype.flag = function () {
|
||||
this.noInput = true;
|
||||
this.flagging = true;
|
||||
this.vel = [0, 2];
|
||||
this.acc = [0, 0];
|
||||
};
|
||||
|
||||
Player.prototype.exit = function() {
|
||||
this.pos[0] += 16;
|
||||
this.targetPos[0] = level.exit * 16;
|
||||
this.left = true;
|
||||
this.setAnimation();
|
||||
this.waiting = 1;
|
||||
this.exiting = true;
|
||||
}
|
||||
Player.prototype.exit = function () {
|
||||
this.pos[0] += 16;
|
||||
this.targetPos[0] = level.exit * 16;
|
||||
this.left = true;
|
||||
this.setAnimation();
|
||||
this.waiting = 1;
|
||||
this.exiting = true;
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
//props do even less than entities, so they don't need to inherit really
|
||||
var Prop = Mario.Prop = function(pos, sprite) {
|
||||
var Prop = (Mario.Prop = function (pos, sprite) {
|
||||
this.pos = pos;
|
||||
this.sprite = sprite;
|
||||
}
|
||||
});
|
||||
|
||||
//but we will be using the same Render, more or less.
|
||||
Prop.prototype.render = function(ctx, vX, vY) {
|
||||
Prop.prototype.render = function (ctx, vX, vY) {
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,62 +1,61 @@
|
||||
//simple resource loader
|
||||
(function() {
|
||||
var resourceCache = {};
|
||||
var loading = [];
|
||||
var readyCallbacks = [];
|
||||
(function () {
|
||||
var resourceCache = {};
|
||||
var loading = [];
|
||||
var readyCallbacks = [];
|
||||
|
||||
// Load an image url or an array of image urls
|
||||
function load(urlOrArr) {
|
||||
if(urlOrArr instanceof Array) {
|
||||
urlOrArr.forEach(function(url) {
|
||||
_load(url);
|
||||
});
|
||||
}
|
||||
else {
|
||||
_load(urlOrArr);
|
||||
}
|
||||
// Load an image url or an array of image urls
|
||||
function load(urlOrArr) {
|
||||
if (urlOrArr instanceof Array) {
|
||||
urlOrArr.forEach(function (url) {
|
||||
_load(url);
|
||||
});
|
||||
} else {
|
||||
_load(urlOrArr);
|
||||
}
|
||||
}
|
||||
|
||||
function _load(url) {
|
||||
if(resourceCache[url]) {
|
||||
return resourceCache[url];
|
||||
}
|
||||
else {
|
||||
var img = new Image();
|
||||
img.onload = function() {
|
||||
resourceCache[url] = img;
|
||||
|
||||
if(isReady()) {
|
||||
readyCallbacks.forEach(function(func) { func(); });
|
||||
}
|
||||
};
|
||||
resourceCache[url] = false;
|
||||
img.src = url;
|
||||
function _load(url) {
|
||||
if (resourceCache[url]) {
|
||||
return resourceCache[url];
|
||||
} else {
|
||||
var img = new Image();
|
||||
img.onload = function () {
|
||||
resourceCache[url] = img;
|
||||
|
||||
if (isReady()) {
|
||||
readyCallbacks.forEach(function (func) {
|
||||
func();
|
||||
});
|
||||
}
|
||||
};
|
||||
resourceCache[url] = false;
|
||||
img.src = url;
|
||||
}
|
||||
}
|
||||
|
||||
function get(url) {
|
||||
return resourceCache[url];
|
||||
function get(url) {
|
||||
return resourceCache[url];
|
||||
}
|
||||
|
||||
function isReady() {
|
||||
var ready = true;
|
||||
for (var k in resourceCache) {
|
||||
if (resourceCache.hasOwnProperty(k) && !resourceCache[k]) {
|
||||
ready = false;
|
||||
}
|
||||
}
|
||||
return ready;
|
||||
}
|
||||
|
||||
function isReady() {
|
||||
var ready = true;
|
||||
for(var k in resourceCache) {
|
||||
if(resourceCache.hasOwnProperty(k) &&
|
||||
!resourceCache[k]) {
|
||||
ready = false;
|
||||
}
|
||||
}
|
||||
return ready;
|
||||
}
|
||||
function onReady(func) {
|
||||
readyCallbacks.push(func);
|
||||
}
|
||||
|
||||
function onReady(func) {
|
||||
readyCallbacks.push(func);
|
||||
}
|
||||
|
||||
window.resources = {
|
||||
load: load,
|
||||
get: get,
|
||||
onReady: onReady,
|
||||
isReady: isReady
|
||||
};
|
||||
window.resources = {
|
||||
load: load,
|
||||
get: get,
|
||||
onReady: onReady,
|
||||
isReady: isReady,
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
//TODO: make each rubble an entity, use that render and write in Entity.update
|
||||
var Rubble = Mario.Rubble = function() {
|
||||
var Rubble = (Mario.Rubble = function () {
|
||||
this.sprites = [];
|
||||
this.poss = [];
|
||||
this.vels = [];
|
||||
}
|
||||
});
|
||||
|
||||
Rubble.prototype.spawn = function(pos) {
|
||||
Rubble.prototype.spawn = function (pos) {
|
||||
this.idx = level.items.length;
|
||||
level.items.push(this);
|
||||
this.sprites[0] = level.rubbleSprite();
|
||||
@@ -17,19 +16,19 @@
|
||||
this.sprites[2] = level.rubbleSprite();
|
||||
this.sprites[3] = level.rubbleSprite();
|
||||
this.poss[0] = pos;
|
||||
this.poss[1] = [ pos[0] + 8, pos[1] ];
|
||||
this.poss[2] = [ pos[0], pos[1] + 8 ];
|
||||
this.poss[3] = [ pos[0] + 8, pos[1] + 8 ];
|
||||
this.poss[1] = [pos[0] + 8, pos[1]];
|
||||
this.poss[2] = [pos[0], pos[1] + 8];
|
||||
this.poss[3] = [pos[0] + 8, pos[1] + 8];
|
||||
this.vels[0] = [-1.25, -5];
|
||||
this.vels[1] = [1.25, -5];
|
||||
this.vels[2] = [-1.25, -3];
|
||||
this.vels[3] = [1.25, -3];
|
||||
}
|
||||
};
|
||||
|
||||
Rubble.prototype.update = function(dt) {
|
||||
for(var i = 0; i < 4; i++) {
|
||||
if (this.sprites[i]===undefined) continue;
|
||||
this.vels[i][1] += .3;
|
||||
Rubble.prototype.update = function (dt) {
|
||||
for (var i = 0; i < 4; i++) {
|
||||
if (this.sprites[i] === undefined) continue;
|
||||
this.vels[i][1] += 0.3;
|
||||
this.poss[i][0] += this.vels[i][0];
|
||||
this.poss[i][1] += this.vels[i][1];
|
||||
this.sprites[i].update(dt);
|
||||
@@ -37,19 +36,23 @@
|
||||
delete this.sprites[i];
|
||||
}
|
||||
}
|
||||
if (this.sprites.every(function (el) {return !el})) {
|
||||
if (
|
||||
this.sprites.every(function (el) {
|
||||
return !el;
|
||||
})
|
||||
) {
|
||||
delete level.items[this.idx];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//You might argue that things that can't collide are more like scenery
|
||||
//but these move and need to be deleted, and i'd rather deal with the 1d array.
|
||||
Rubble.prototype.checkCollisions = function() {;}
|
||||
Rubble.prototype.checkCollisions = function () {};
|
||||
|
||||
Rubble.prototype.render = function() {
|
||||
for(var i = 0; i < 4; i++) {
|
||||
Rubble.prototype.render = function () {
|
||||
for (var i = 0; i < 4; i++) {
|
||||
if (this.sprites[i] === undefined) continue;
|
||||
this.sprites[i].render(ctx, this.poss[i][0], this.poss[i][1], vX, vY);
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
var Sprite = Mario.Sprite = function(img, pos, size, speed, frames, once) {
|
||||
var Sprite = (Mario.Sprite = function (img, pos, size, speed, frames, once) {
|
||||
this.pos = pos;
|
||||
this.size = size;
|
||||
this.speed = speed;
|
||||
@@ -10,19 +9,19 @@
|
||||
this.img = img;
|
||||
this.once = once;
|
||||
this.frames = frames;
|
||||
}
|
||||
});
|
||||
|
||||
Sprite.prototype.update = function(dt, gameTime) {
|
||||
Sprite.prototype.update = function (dt, gameTime) {
|
||||
if (gameTime && gameTime == this.lastUpdated) return;
|
||||
this._index += this.speed*dt;
|
||||
this._index += this.speed * dt;
|
||||
if (gameTime) this.lastUpdated = gameTime;
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.setFrame = function(frame) {
|
||||
Sprite.prototype.setFrame = function (frame) {
|
||||
this._index = frame;
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.render = function(ctx, posx, posy, vX, vY) {
|
||||
Sprite.prototype.render = function (ctx, posx, posy, vX, vY) {
|
||||
var frame;
|
||||
|
||||
if (this.speed > 0) {
|
||||
@@ -41,7 +40,17 @@
|
||||
var x = this.pos[0];
|
||||
var y = this.pos[1];
|
||||
|
||||
x += frame*this.size[0];
|
||||
ctx.drawImage(resources.get(this.img), x + (1/3),y + (1/3), this.size[0] - (2/3), this.size[1] - (2/3), Math.round(posx - vX), Math.round(posy - vY), this.size[0],this.size[1]);
|
||||
}
|
||||
x += frame * this.size[0];
|
||||
ctx.drawImage(
|
||||
resources.get(this.img),
|
||||
x + 1 / 3,
|
||||
y + 1 / 3,
|
||||
this.size[0] - 2 / 3,
|
||||
this.size[1] - 2 / 3,
|
||||
Math.round(posx - vX),
|
||||
Math.round(posy - vY),
|
||||
this.size[0],
|
||||
this.size[1],
|
||||
);
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,38 +1,37 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined')
|
||||
window.Mario = {};
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") window.Mario = {};
|
||||
|
||||
var Star = Mario.Star = function(pos) {
|
||||
var Star = (Mario.Star = function (pos) {
|
||||
this.spawning = false;
|
||||
this.waiting = 0;
|
||||
|
||||
Mario.Entity.call(this, {
|
||||
pos: pos,
|
||||
sprite: level.starSprite,
|
||||
hitbox: [0,0,16,16]
|
||||
hitbox: [0, 0, 16, 16],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Mario.Util.inherits(Star, Mario.Entity);
|
||||
|
||||
Star.prototype.render = function(ctx, vX, vY) {
|
||||
Star.prototype.render = function (ctx, vX, vY) {
|
||||
if (this.spawning > 1) return;
|
||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||
}
|
||||
};
|
||||
|
||||
Star.prototype.spawn = function() {
|
||||
Star.prototype.spawn = function () {
|
||||
this.idx = level.items.length;
|
||||
level.items.push(this);
|
||||
this.spawning = 12;
|
||||
this.targetpos = [];
|
||||
this.targetpos[0] = this.pos[0];
|
||||
this.targetpos[1] = this.pos[1] - 16;
|
||||
}
|
||||
};
|
||||
|
||||
Star.prototype.update = function(dt) {
|
||||
Star.prototype.update = function (dt) {
|
||||
if (this.spawning > 1) {
|
||||
this.spawning -= 1;
|
||||
if (this.spawning == 1) this.vel[1] = -.5;
|
||||
if (this.spawning == 1) this.vel[1] = -0.5;
|
||||
return;
|
||||
}
|
||||
if (this.spawning) {
|
||||
@@ -60,14 +59,14 @@
|
||||
this.pos[1] += this.vel[1];
|
||||
this.sprite.update(dt);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Star.prototype.collideWall = function() {
|
||||
Star.prototype.collideWall = function () {
|
||||
this.vel[0] = -this.vel[0];
|
||||
}
|
||||
};
|
||||
|
||||
Star.prototype.checkCollisions = function() {
|
||||
if(this.spawning) {
|
||||
Star.prototype.checkCollisions = function () {
|
||||
if (this.spawning) {
|
||||
return;
|
||||
}
|
||||
var h = this.pos[1] % 16 == 0 ? 1 : 2;
|
||||
@@ -93,24 +92,36 @@
|
||||
}
|
||||
|
||||
this.isPlayerCollided();
|
||||
}
|
||||
};
|
||||
|
||||
//we have access to player everywhere, so let's just do this.
|
||||
Star.prototype.isPlayerCollided = function() {
|
||||
Star.prototype.isPlayerCollided = function () {
|
||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
||||
var hpos1 = [this.pos[0] + this.hitbox[0], this.pos[1] + this.hitbox[1]];
|
||||
var hpos2 = [player.pos[0] + player.hitbox[0], player.pos[1] + player.hitbox[1]];
|
||||
var hpos2 = [
|
||||
player.pos[0] + player.hitbox[0],
|
||||
player.pos[1] + player.hitbox[1],
|
||||
];
|
||||
|
||||
//if the hitboxes actually overlap
|
||||
if (!(hpos1[0] > hpos2[0]+player.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
||||
if (!(hpos1[1] > hpos2[1]+player.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
||||
if (
|
||||
!(
|
||||
hpos1[0] > hpos2[0] + player.hitbox[2] ||
|
||||
hpos1[0] + this.hitbox[2] < hpos2[0]
|
||||
)
|
||||
) {
|
||||
if (
|
||||
!(
|
||||
hpos1[1] > hpos2[1] + player.hitbox[3] ||
|
||||
hpos1[1] + this.hitbox[3] < hpos2[1]
|
||||
)
|
||||
) {
|
||||
player.star(this.idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Star.prototype.bump = function() {
|
||||
Star.prototype.bump = function () {
|
||||
this.vel[1] = -2;
|
||||
}
|
||||
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
(function() {
|
||||
if (typeof Mario === 'undefined') {
|
||||
window.Mario = {};
|
||||
}
|
||||
(function () {
|
||||
if (typeof Mario === "undefined") {
|
||||
window.Mario = {};
|
||||
}
|
||||
|
||||
var Util = Mario.Util = {};
|
||||
var Util = (Mario.Util = {});
|
||||
|
||||
Util.inherits = function(subclass, superclass) {
|
||||
function Surrogate() {};
|
||||
Util.inherits = function (subclass, superclass) {
|
||||
function Surrogate() {}
|
||||
|
||||
Surrogate.prototype = superclass.prototype;
|
||||
subclass.prototype = new Surrogate();
|
||||
}
|
||||
})()
|
||||
Surrogate.prototype = superclass.prototype;
|
||||
subclass.prototype = new Surrogate();
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Matplotlib</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Matplotlib</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">Matplotlib</a>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
@@ -30,39 +30,39 @@
|
||||
</py-config>
|
||||
|
||||
<py-script>
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.tri as tri
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib.tri as tri
|
||||
import numpy as np
|
||||
|
||||
# First create the x and y coordinates of the points.
|
||||
n_angles = 36
|
||||
n_radii = 8
|
||||
min_radius = 0.25
|
||||
radii = np.linspace(min_radius, 0.95, n_radii)
|
||||
# First create the x and y coordinates of the points.
|
||||
n_angles = 36
|
||||
n_radii = 8
|
||||
min_radius = 0.25
|
||||
radii = np.linspace(min_radius, 0.95, n_radii)
|
||||
|
||||
angles = np.linspace(0, 2 * np.pi, n_angles, endpoint=False)
|
||||
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
|
||||
angles[:, 1::2] += np.pi / n_angles
|
||||
angles = np.linspace(0, 2 * np.pi, n_angles, endpoint=False)
|
||||
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
|
||||
angles[:, 1::2] += np.pi / n_angles
|
||||
|
||||
x = (radii * np.cos(angles)).flatten()
|
||||
y = (radii * np.sin(angles)).flatten()
|
||||
z = (np.cos(radii) * np.cos(3 * angles)).flatten()
|
||||
x = (radii * np.cos(angles)).flatten()
|
||||
y = (radii * np.sin(angles)).flatten()
|
||||
z = (np.cos(radii) * np.cos(3 * angles)).flatten()
|
||||
|
||||
# Create the Triangulation; no triangles so Delaunay triangulation created.
|
||||
triang = tri.Triangulation(x, y)
|
||||
# Create the Triangulation; no triangles so Delaunay triangulation created.
|
||||
triang = tri.Triangulation(x, y)
|
||||
|
||||
# Mask off unwanted triangles.
|
||||
triang.set_mask(np.hypot(x[triang.triangles].mean(axis=1),
|
||||
y[triang.triangles].mean(axis=1))
|
||||
< min_radius)
|
||||
# Mask off unwanted triangles.
|
||||
triang.set_mask(np.hypot(x[triang.triangles].mean(axis=1),
|
||||
y[triang.triangles].mean(axis=1))
|
||||
< min_radius)
|
||||
|
||||
fig1, ax1 = plt.subplots()
|
||||
ax1.set_aspect('equal')
|
||||
tpc = ax1.tripcolor(triang, z, shading='flat')
|
||||
fig1.colorbar(tpc)
|
||||
ax1.set_title('tripcolor of Delaunay triangulation, flat shading')
|
||||
fig1, ax1 = plt.subplots()
|
||||
ax1.set_aspect('equal')
|
||||
tpc = ax1.tripcolor(triang, z, shading='flat')
|
||||
fig1.colorbar(tpc)
|
||||
ax1.set_title('tripcolor of Delaunay triangulation, flat shading')
|
||||
|
||||
display(fig1, target="mpl")
|
||||
display(fig1, target="mpl")
|
||||
</py-script>
|
||||
</py-tutor>
|
||||
</section>
|
||||
|
||||
@@ -1,37 +1,35 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<head>
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<py-tutor>
|
||||
<py-config>
|
||||
packages = [
|
||||
"numpy",
|
||||
"networkx",
|
||||
"matplotlib"
|
||||
]
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
]
|
||||
</py-config>
|
||||
<py-config>
|
||||
packages = [
|
||||
"numpy",
|
||||
"networkx",
|
||||
"matplotlib"
|
||||
]
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
]
|
||||
</py-config>
|
||||
|
||||
<py-script>
|
||||
import numpy as np
|
||||
import networkx as nx
|
||||
</py-script>
|
||||
<py-script>
|
||||
import numpy as np
|
||||
import networkx as nx
|
||||
</py-script>
|
||||
|
||||
<p>Message passing with linear algebra: a demo.</p>
|
||||
<p>Imagine we have a chain graph that looks like this:</p>
|
||||
<pre><code>O --> 1 --> 2 --> 3</code></pre>
|
||||
<p>In NetworkX this graph would look like the following:</p>
|
||||
<pre>
|
||||
<p>Message passing with linear algebra: a demo.</p>
|
||||
<p>Imagine we have a chain graph that looks like this:</p>
|
||||
<pre><code>O --> 1 --> 2 --> 3</code></pre>
|
||||
<p>In NetworkX this graph would look like the following:</p>
|
||||
<pre>
|
||||
<py-script>
|
||||
G = nx.Graph()
|
||||
nodes = list(range(4))
|
||||
@@ -39,28 +37,29 @@ G.add_edges_from(zip(nodes[0:-1], nodes[1:]))
|
||||
print(G.edges())
|
||||
</py-script>
|
||||
</pre>
|
||||
<p>This chain graph has the following adjacency matrix:</p>
|
||||
<pre>
|
||||
<p>This chain graph has the following adjacency matrix:</p>
|
||||
<pre>
|
||||
<py-script>
|
||||
adj_mat = np.eye(4, k=1)
|
||||
print(f"A: {adj_mat}")
|
||||
</py-script>
|
||||
</pre>
|
||||
<p>And imagine that we have a message that lives on the graph:</p>
|
||||
<pre>
|
||||
<p>And imagine that we have a message that lives on the graph:</p>
|
||||
<pre>
|
||||
<py-script>
|
||||
message = np.array([1.0, 0.0, 0.0, 0.0])
|
||||
print(f"message: {message}")
|
||||
</py-script>
|
||||
</pre>
|
||||
<p>Try out message passing below by doing any one of the following steps:</p>
|
||||
<pre><code>message @ adj_mat</code></pre>
|
||||
<pre><code>message @ adj_mat @ adj_mat</code></pre>
|
||||
<pre><code>message @ adj_mat @ adj_mat @ adj_mat</code></pre>
|
||||
<div>
|
||||
<p>
|
||||
Try out message passing below by doing any one of the following steps:
|
||||
</p>
|
||||
<pre><code>message @ adj_mat</code></pre>
|
||||
<pre><code>message @ adj_mat @ adj_mat</code></pre>
|
||||
<pre><code>message @ adj_mat @ adj_mat @ adj_mat</code></pre>
|
||||
<div>
|
||||
<py-repl id="my-repl" auto-generate="true"> </py-repl>
|
||||
</div>
|
||||
</div>
|
||||
</py-tutor>
|
||||
</body>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,191 +1,186 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
|
||||
<title>micrograd</title>
|
||||
<title>micrograd</title>
|
||||
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous">
|
||||
</head>
|
||||
<link
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
</head>
|
||||
|
||||
<body style="padding-top: 20px; padding-right: 20px; padding-bottom: 20px; padding-left: 20px">
|
||||
<h1>Micrograd - A tiny Autograd engine (with a bite! :))</h1><br>
|
||||
<body
|
||||
style="
|
||||
padding-top: 20px;
|
||||
padding-right: 20px;
|
||||
padding-bottom: 20px;
|
||||
padding-left: 20px;
|
||||
"
|
||||
>
|
||||
<h1>Micrograd - A tiny Autograd engine (with a bite! :))</h1>
|
||||
<br />
|
||||
|
||||
<py-config>
|
||||
packages = [
|
||||
"micrograd",
|
||||
"numpy",
|
||||
"matplotlib"
|
||||
]
|
||||
</py-config>
|
||||
<py-config>
|
||||
packages = [
|
||||
"micrograd",
|
||||
"numpy",
|
||||
"matplotlib"
|
||||
]
|
||||
</py-config>
|
||||
|
||||
<div>
|
||||
<p>
|
||||
<a href="https://github.com/karpathy/micrograd">Micrograd</a> is a tiny Autograd engine created
|
||||
by <a href="https://twitter.com/karpathy">Andrej Karpathy</a>. This app recreates the
|
||||
<a href="https://github.com/karpathy/micrograd/blob/master/demo.ipynb">demo</a>
|
||||
he prepared for this package using pyscript to train a basic model, written in Python, natively in
|
||||
the browser. <br>
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
You may run each Python REPL cell interactively by pressing (Shift + Enter) or (Ctrl + Enter).
|
||||
You can also modify the code directly as you wish. If you want to run all the code at once,
|
||||
not each cell individually, you may instead click the 'Run All' button. Training the model
|
||||
takes between 1-2 min if you decide to 'Run All' at once. 'Run All' is your only option if
|
||||
you are running this on a mobile device where you cannot press (Shift + Enter). After the
|
||||
model is trained, a plot image should be displayed depicting the model's ability to
|
||||
classify the data. <br>
|
||||
</p>
|
||||
<p>
|
||||
Currently the <code>></code> symbol is being imported incorrectly as <code>&gt;</code> into the REPL's.
|
||||
In this app the <code>></code> symbol has been replaced with <code>().__gt__()</code> so you can run the code
|
||||
without issue. Ex: instead of <code>a > b</code>, you will see <code>(a).__gt__(b)</code> instead. <br>
|
||||
</p>
|
||||
<py-script>import js; js.document.getElementById('python-status').innerHTML = 'Python is now ready. You may proceed.'</py-script>
|
||||
<div id="python-status">Python is currently starting. Please wait...</div>
|
||||
<button id="run-all-button" class="btn btn-primary" type="submit" py-onClick="run_all_micrograd_demo()">Run All</button><br>
|
||||
<py-script src="/micrograd_ai.py"></py-script>
|
||||
<div id="micrograd-run-all-print-div"></div><br>
|
||||
<div id="micrograd-run-all-fig1-div"></div>
|
||||
<div id="micrograd-run-all-fig2-div"></div><br>
|
||||
</div>
|
||||
<py-repl auto-generate="false">
|
||||
import random
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
</py-repl><br>
|
||||
<py-repl auto-generate="false">
|
||||
from micrograd.engine import Value
|
||||
from micrograd.nn import Neuron, Layer, MLP
|
||||
</py-repl><br>
|
||||
<py-repl auto-generate="true">
|
||||
np.random.seed(1337)
|
||||
random.seed(1337)
|
||||
</py-repl><br>
|
||||
<py-repl auto-generate="true">
|
||||
#An adaptation of sklearn's make_moons function https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_moons.html
|
||||
def make_moons(n_samples=100, noise=None):
|
||||
n_samples_out, n_samples_in = n_samples, n_samples
|
||||
<div>
|
||||
<p>
|
||||
<a href="https://github.com/karpathy/micrograd">Micrograd</a> is a tiny
|
||||
Autograd engine created by
|
||||
<a href="https://twitter.com/karpathy">Andrej Karpathy</a>. This app
|
||||
recreates the
|
||||
<a href="https://github.com/karpathy/micrograd/blob/master/demo.ipynb"
|
||||
>demo</a
|
||||
>
|
||||
he prepared for this package using pyscript to train a basic model,
|
||||
written in Python, natively in the browser. <br />
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p>
|
||||
You may run each Python REPL cell interactively by pressing (Shift +
|
||||
Enter) or (Ctrl + Enter). You can also modify the code directly as you
|
||||
wish. If you want to run all the code at once, not each cell
|
||||
individually, you may instead click the 'Run All' button. Training the
|
||||
model takes between 1-2 min if you decide to 'Run All' at once. 'Run
|
||||
All' is your only option if you are running this on a mobile device
|
||||
where you cannot press (Shift + Enter). After the model is trained, a
|
||||
plot image should be displayed depicting the model's ability to classify
|
||||
the data. <br />
|
||||
</p>
|
||||
<p>
|
||||
Currently the <code>></code> symbol is being imported incorrectly as
|
||||
<code>&gt;</code> into the REPL's. In this app the
|
||||
<code>></code> symbol has been replaced with
|
||||
<code>().__gt__()</code> so you can run the code without issue. Ex:
|
||||
instead of <code>a > b</code>, you will see
|
||||
<code>(a).__gt__(b)</code> instead. <br />
|
||||
</p>
|
||||
<py-script>
|
||||
import js; js.document.getElementById('python-status').innerHTML = 'Python is now ready. You may proceed.'
|
||||
</py-script>
|
||||
<div id="python-status">Python is currently starting. Please wait...</div>
|
||||
<button
|
||||
id="run-all-button"
|
||||
class="btn btn-primary"
|
||||
type="submit"
|
||||
py-onClick="run_all_micrograd_demo()"
|
||||
>
|
||||
Run All</button
|
||||
><br />
|
||||
<py-script src="/micrograd_ai.py"></py-script>
|
||||
<div id="micrograd-run-all-print-div"></div>
|
||||
<br />
|
||||
<div id="micrograd-run-all-fig1-div"></div>
|
||||
<div id="micrograd-run-all-fig2-div"></div>
|
||||
<br />
|
||||
</div>
|
||||
<py-repl auto-generate="false">
|
||||
import random import numpy as np import matplotlib.pyplot as plt </py-repl
|
||||
><br />
|
||||
<py-repl auto-generate="false">
|
||||
from micrograd.engine import Value from micrograd.nn import Neuron, Layer,
|
||||
MLP </py-repl
|
||||
><br />
|
||||
<py-repl auto-generate="true">
|
||||
np.random.seed(1337) random.seed(1337) </py-repl
|
||||
><br />
|
||||
<py-repl auto-generate="true">
|
||||
#An adaptation of sklearn's make_moons function
|
||||
https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_moons.html
|
||||
def make_moons(n_samples=100, noise=None): n_samples_out, n_samples_in =
|
||||
n_samples, n_samples outer_circ_x = np.cos(np.linspace(0, np.pi,
|
||||
n_samples_out)) outer_circ_y = np.sin(np.linspace(0, np.pi,
|
||||
n_samples_out)) inner_circ_x = 1 - np.cos(np.linspace(0, np.pi,
|
||||
n_samples_in)) inner_circ_y = 1 - np.sin(np.linspace(0, np.pi,
|
||||
n_samples_in)) - 0.5 X = np.vstack([np.append(outer_circ_x, inner_circ_x),
|
||||
np.append(outer_circ_y, inner_circ_y)]).T y =
|
||||
np.hstack([np.zeros(n_samples_out, dtype=np.intp), np.ones(n_samples_in,
|
||||
dtype=np.intp)]) if noise is not None: X += np.random.normal(loc=0.0,
|
||||
scale=noise, size=X.shape) return X, y X, y = make_moons(n_samples=100,
|
||||
noise=0.1) </py-repl
|
||||
><br />
|
||||
<py-repl auto-generate="true">
|
||||
y = y*2 - 1 # make y be -1 or 1 # visualize in 2D
|
||||
plt.figure(figsize=(5,5)) plt.scatter(X[:,0], X[:,1], c=y, s=20,
|
||||
cmap='jet') plt </py-repl
|
||||
><br />
|
||||
<py-repl auto-generate="true">
|
||||
model = MLP(2, [16, 16, 1]) # 2-layer neural network print(model)
|
||||
print("number of parameters", len(model.parameters())) </py-repl
|
||||
><br />
|
||||
|
||||
outer_circ_x = np.cos(np.linspace(0, np.pi, n_samples_out))
|
||||
outer_circ_y = np.sin(np.linspace(0, np.pi, n_samples_out))
|
||||
inner_circ_x = 1 - np.cos(np.linspace(0, np.pi, n_samples_in))
|
||||
inner_circ_y = 1 - np.sin(np.linspace(0, np.pi, n_samples_in)) - 0.5
|
||||
<div>
|
||||
Line 24 has been changed from: <br />
|
||||
<code
|
||||
>accuracy = [(yi > 0) == (scorei.data > 0) for yi, scorei in
|
||||
zip(yb, scores)]</code
|
||||
><br />
|
||||
to: <br />
|
||||
<code
|
||||
>accuracy = [((yi).__gt__(0)) == ((scorei.data).__gt__(0)) for yi,
|
||||
scorei in zip(yb, scores)]</code
|
||||
><br />
|
||||
</div>
|
||||
|
||||
X = np.vstack([np.append(outer_circ_x, inner_circ_x), np.append(outer_circ_y, inner_circ_y)]).T
|
||||
y = np.hstack([np.zeros(n_samples_out, dtype=np.intp), np.ones(n_samples_in, dtype=np.intp)])
|
||||
if noise is not None: X += np.random.normal(loc=0.0, scale=noise, size=X.shape)
|
||||
return X, y
|
||||
X, y = make_moons(n_samples=100, noise=0.1)
|
||||
</py-repl><br>
|
||||
<py-repl auto-generate="true">
|
||||
y = y*2 - 1 # make y be -1 or 1
|
||||
# visualize in 2D
|
||||
plt.figure(figsize=(5,5))
|
||||
plt.scatter(X[:,0], X[:,1], c=y, s=20, cmap='jet')
|
||||
plt
|
||||
</py-repl><br>
|
||||
<py-repl auto-generate="true">
|
||||
model = MLP(2, [16, 16, 1]) # 2-layer neural network
|
||||
print(model)
|
||||
print("number of parameters", len(model.parameters()))
|
||||
</py-repl><br>
|
||||
<py-repl auto-generate="true">
|
||||
# loss function def loss(batch_size=None): # inline DataLoader :) if
|
||||
batch_size is None: Xb, yb = X, y else: ri =
|
||||
np.random.permutation(X.shape[0])[:batch_size] Xb, yb = X[ri], y[ri]
|
||||
inputs = [list(map(Value, xrow)) for xrow in Xb] # forward the model to
|
||||
get scores scores = list(map(model, inputs)) # svm "max-margin" loss
|
||||
losses = [(1 + -yi*scorei).relu() for yi, scorei in zip(yb, scores)]
|
||||
data_loss = sum(losses) * (1.0 / len(losses)) # L2 regularization alpha =
|
||||
1e-4 reg_loss = alpha * sum((p*p for p in model.parameters())) total_loss
|
||||
= data_loss + reg_loss # also get accuracy accuracy = [((yi).__gt__(0)) ==
|
||||
((scorei.data).__gt__(0)) for yi, scorei in zip(yb, scores)] return
|
||||
total_loss, sum(accuracy) / len(accuracy) total_loss, acc = loss()
|
||||
print(total_loss, acc) </py-repl
|
||||
><br />
|
||||
<py-repl auto-generate="true">
|
||||
# optimization for k in range(20): #was 100. Accuracy can be further
|
||||
improved w/ more epochs (to 100%). # forward total_loss, acc = loss() #
|
||||
backward model.zero_grad() total_loss.backward() # update (sgd)
|
||||
learning_rate = 1.0 - 0.9*k/100 for p in model.parameters(): p.data -=
|
||||
learning_rate * p.grad if k % 1 == 0: print(f"step {k} loss
|
||||
{total_loss.data}, accuracy {acc*100}%") </py-repl
|
||||
><br />
|
||||
<div>
|
||||
<p>
|
||||
Please wait for the training loop above to complete. It will not print
|
||||
out stats until it has completely finished. This typically takes 1-2
|
||||
min. <br /><br />
|
||||
|
||||
<div>
|
||||
Line 24 has been changed from: <br>
|
||||
<code>accuracy = [(yi > 0) == (scorei.data > 0) for yi, scorei in zip(yb, scores)]</code><br>
|
||||
to: <br>
|
||||
<code>accuracy = [((yi).__gt__(0)) == ((scorei.data).__gt__(0)) for yi, scorei in zip(yb, scores)]</code><br>
|
||||
</div>
|
||||
|
||||
<py-repl auto-generate="true">
|
||||
# loss function
|
||||
def loss(batch_size=None):
|
||||
|
||||
# inline DataLoader :)
|
||||
if batch_size is None:
|
||||
Xb, yb = X, y
|
||||
else:
|
||||
ri = np.random.permutation(X.shape[0])[:batch_size]
|
||||
Xb, yb = X[ri], y[ri]
|
||||
inputs = [list(map(Value, xrow)) for xrow in Xb]
|
||||
|
||||
# forward the model to get scores
|
||||
scores = list(map(model, inputs))
|
||||
|
||||
# svm "max-margin" loss
|
||||
losses = [(1 + -yi*scorei).relu() for yi, scorei in zip(yb, scores)]
|
||||
data_loss = sum(losses) * (1.0 / len(losses))
|
||||
# L2 regularization
|
||||
alpha = 1e-4
|
||||
reg_loss = alpha * sum((p*p for p in model.parameters()))
|
||||
total_loss = data_loss + reg_loss
|
||||
|
||||
# also get accuracy
|
||||
accuracy = [((yi).__gt__(0)) == ((scorei.data).__gt__(0)) for yi, scorei in zip(yb, scores)]
|
||||
return total_loss, sum(accuracy) / len(accuracy)
|
||||
|
||||
total_loss, acc = loss()
|
||||
print(total_loss, acc)
|
||||
</py-repl><br>
|
||||
<py-repl auto-generate="true">
|
||||
# optimization
|
||||
for k in range(20): #was 100. Accuracy can be further improved w/ more epochs (to 100%).
|
||||
|
||||
# forward
|
||||
total_loss, acc = loss()
|
||||
|
||||
# backward
|
||||
model.zero_grad()
|
||||
total_loss.backward()
|
||||
|
||||
# update (sgd)
|
||||
learning_rate = 1.0 - 0.9*k/100
|
||||
for p in model.parameters():
|
||||
p.data -= learning_rate * p.grad
|
||||
|
||||
if k % 1 == 0:
|
||||
print(f"step {k} loss {total_loss.data}, accuracy {acc*100}%")
|
||||
</py-repl><br>
|
||||
<div>
|
||||
<p>
|
||||
Please wait for the training loop above to complete. It will not print out stats until it
|
||||
has completely finished. This typically takes 1-2 min. <br><br>
|
||||
|
||||
Line 9 has been changed from: <br>
|
||||
<code>Z = np.array([s.data > 0 for s in scores])</code><br>
|
||||
to: <br>
|
||||
<code>Z = np.array([(s.data).__gt__(0) for s in scores])</code><br>
|
||||
</p>
|
||||
</div>
|
||||
<py-repl auto-generate="true">
|
||||
h = 0.25
|
||||
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
|
||||
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
|
||||
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
|
||||
np.arange(y_min, y_max, h))
|
||||
Xmesh = np.c_[xx.ravel(), yy.ravel()]
|
||||
inputs = [list(map(Value, xrow)) for xrow in Xmesh]
|
||||
scores = list(map(model, inputs))
|
||||
Z = np.array([(s.data).__gt__(0) for s in scores])
|
||||
Z = Z.reshape(xx.shape)
|
||||
|
||||
fig = plt.figure()
|
||||
plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral, alpha=0.8)
|
||||
plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.Spectral)
|
||||
plt.xlim(xx.min(), xx.max())
|
||||
plt.ylim(yy.min(), yy.max())
|
||||
plt
|
||||
</py-repl><br>
|
||||
<py-repl auto-generate="true">
|
||||
1+1
|
||||
</py-repl><br>
|
||||
</body>
|
||||
Line 9 has been changed from: <br />
|
||||
<code>Z = np.array([s.data > 0 for s in scores])</code><br />
|
||||
to: <br />
|
||||
<code>Z = np.array([(s.data).__gt__(0) for s in scores])</code><br />
|
||||
</p>
|
||||
</div>
|
||||
<py-repl auto-generate="true">
|
||||
h = 0.25 x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min, y_max
|
||||
= X[:, 1].min() - 1, X[:, 1].max() + 1 xx, yy =
|
||||
np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h)) Xmesh
|
||||
= np.c_[xx.ravel(), yy.ravel()] inputs = [list(map(Value, xrow)) for xrow
|
||||
in Xmesh] scores = list(map(model, inputs)) Z =
|
||||
np.array([(s.data).__gt__(0) for s in scores]) Z = Z.reshape(xx.shape) fig
|
||||
= plt.figure() plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral, alpha=0.8)
|
||||
plt.scatter(X[:, 0], X[:, 1], c=y, s=40, cmap=plt.cm.Spectral)
|
||||
plt.xlim(xx.min(), xx.max()) plt.ylim(yy.min(), yy.max()) plt </py-repl
|
||||
><br />
|
||||
<py-repl auto-generate="true"> 1+1 </py-repl><br />
|
||||
</body>
|
||||
</html>
|
||||
<!-- Adapted by Mat Miller -->
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Visualization of Mandelbrot, Julia and Newton sets with NumPy and HTML5 canvas</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<title>
|
||||
Visualization of Mandelbrot, Julia and Newton sets with NumPy and HTML5
|
||||
canvas
|
||||
</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
@@ -27,19 +30,22 @@
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Fractals with NumPy and canvas</a>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
<div style="display: flex; flex-direction: column; gap: 1em; width: 600px">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c"
|
||||
>Fractals with NumPy and canvas</a
|
||||
>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
<div
|
||||
style="display: flex; flex-direction: column; gap: 1em; width: 600px"
|
||||
>
|
||||
<div id="mandelbrot">
|
||||
<div style="text-align: center">Mandelbrot set</div>
|
||||
<div>
|
||||
@@ -57,25 +63,63 @@
|
||||
<div id="newton">
|
||||
<div style="text-align: center">Newton set</div>
|
||||
<fieldset style="display: flex; flex-direction: row; gap: 1em">
|
||||
<div><span style="white-space: pre">p(z) = </span><input id="poly" type="text" value="z**3 - 2*z + 2"></div>
|
||||
<div><span style="white-space: pre">a = </span><input id="coef" type="text" value="1" style="width: 40px"></div>
|
||||
<div>
|
||||
<span style="white-space: pre">p(z) = </span
|
||||
><input id="poly" type="text" value="z**3 - 2*z + 2" />
|
||||
</div>
|
||||
<div>
|
||||
<span style="white-space: pre">a = </span
|
||||
><input id="coef" type="text" value="1" style="width: 40px" />
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: row">
|
||||
<span style="white-space: pre">x = [</span>
|
||||
<input id="x0" type="text" value="-2.5" style="width: 80px; text-align: right">
|
||||
<input
|
||||
id="x0"
|
||||
type="text"
|
||||
value="-2.5"
|
||||
style="width: 80px; text-align: right"
|
||||
/>
|
||||
<span style="white-space: pre">, </span>
|
||||
<input id="x1" type="text" value="2.5" style="width: 80px; text-align: right">
|
||||
<input
|
||||
id="x1"
|
||||
type="text"
|
||||
value="2.5"
|
||||
style="width: 80px; text-align: right"
|
||||
/>
|
||||
<span style="white-space: pre">]</span>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: row">
|
||||
<span style="white-space: pre">y = [</span>
|
||||
<input id="y0" type="text" value="-5.0" style="width: 80px; text-align: right">
|
||||
<input
|
||||
id="y0"
|
||||
type="text"
|
||||
value="-5.0"
|
||||
style="width: 80px; text-align: right"
|
||||
/>
|
||||
<span style="white-space: pre">, </span>
|
||||
<input id="y1" type="text" value="5.0" style="width: 80px; text-align: right">
|
||||
<input
|
||||
id="y1"
|
||||
type="text"
|
||||
value="5.0"
|
||||
style="width: 80px; text-align: right"
|
||||
/>
|
||||
<span style="white-space: pre">]</span>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: row; gap: 1em">
|
||||
<div style="white-space: pre"><input type="radio" id="conv" name="type" value="convergence" checked> convergence</div>
|
||||
<div style="white-space: pre"><input type="radio" id="iter" name="type" value="iterations"> iterations</div>
|
||||
<div style="white-space: pre">
|
||||
<input
|
||||
type="radio"
|
||||
id="conv"
|
||||
name="type"
|
||||
value="convergence"
|
||||
checked
|
||||
/>
|
||||
convergence
|
||||
</div>
|
||||
<div style="white-space: pre">
|
||||
<input type="radio" id="iter" name="type" value="iterations" />
|
||||
iterations
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div>
|
||||
@@ -106,236 +150,236 @@
|
||||
</py-config>
|
||||
|
||||
<py-script>
|
||||
from pyodide.ffi import to_js, create_proxy
|
||||
from pyodide.ffi import to_js, create_proxy
|
||||
|
||||
import numpy as np
|
||||
import sympy
|
||||
import numpy as np
|
||||
import sympy
|
||||
|
||||
from palettes import Magma256
|
||||
from fractals import mandelbrot, julia, newton
|
||||
from palettes import Magma256
|
||||
from fractals import mandelbrot, julia, newton
|
||||
|
||||
from js import (
|
||||
console,
|
||||
document,
|
||||
devicePixelRatio,
|
||||
ImageData,
|
||||
Uint8ClampedArray,
|
||||
CanvasRenderingContext2D as Context2d,
|
||||
requestAnimationFrame,
|
||||
)
|
||||
from js import (
|
||||
console,
|
||||
document,
|
||||
devicePixelRatio,
|
||||
ImageData,
|
||||
Uint8ClampedArray,
|
||||
CanvasRenderingContext2D as Context2d,
|
||||
requestAnimationFrame,
|
||||
)
|
||||
|
||||
def prepare_canvas(width: int, height: int, canvas: Element) -> Context2d:
|
||||
ctx = canvas.getContext("2d")
|
||||
def prepare_canvas(width: int, height: int, canvas: Element) -> Context2d:
|
||||
ctx = canvas.getContext("2d")
|
||||
|
||||
canvas.style.width = f"{width}px"
|
||||
canvas.style.height = f"{height}px"
|
||||
canvas.style.width = f"{width}px"
|
||||
canvas.style.height = f"{height}px"
|
||||
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
|
||||
ctx.clearRect(0, 0, width, height)
|
||||
ctx.clearRect(0, 0, width, height)
|
||||
|
||||
return ctx
|
||||
return ctx
|
||||
|
||||
def color_map(array: np.array, palette: np.array) -> np.array:
|
||||
size, _ = palette.shape
|
||||
index = (array/array.max()*(size - 1)).round().astype("uint8")
|
||||
def color_map(array: np.array, palette: np.array) -> np.array:
|
||||
size, _ = palette.shape
|
||||
index = (array/array.max()*(size - 1)).round().astype("uint8")
|
||||
|
||||
width, height = array.shape
|
||||
image = np.full((width, height, 4), 0xff, dtype=np.uint8)
|
||||
image[:, :, :3] = palette[index]
|
||||
width, height = array.shape
|
||||
image = np.full((width, height, 4), 0xff, dtype=np.uint8)
|
||||
image[:, :, :3] = palette[index]
|
||||
|
||||
return image
|
||||
return image
|
||||
|
||||
def draw_image(ctx: Context2d, image: np.array) -> None:
|
||||
data = Uint8ClampedArray.new(to_js(image.tobytes()))
|
||||
width, height, _ = image.shape
|
||||
image_data = ImageData.new(data, width, height)
|
||||
ctx.putImageData(image_data, 0, 0)
|
||||
def draw_image(ctx: Context2d, image: np.array) -> None:
|
||||
data = Uint8ClampedArray.new(to_js(image.tobytes()))
|
||||
width, height, _ = image.shape
|
||||
image_data = ImageData.new(data, width, height)
|
||||
ctx.putImageData(image_data, 0, 0)
|
||||
|
||||
width, height = 600, 600
|
||||
width, height = 600, 600
|
||||
|
||||
async def draw_mandelbrot() -> None:
|
||||
spinner = document.querySelector("#mandelbrot .loading")
|
||||
canvas = document.querySelector("#mandelbrot canvas")
|
||||
async def draw_mandelbrot() -> None:
|
||||
spinner = document.querySelector("#mandelbrot .loading")
|
||||
canvas = document.querySelector("#mandelbrot canvas")
|
||||
|
||||
spinner.style.display = ""
|
||||
canvas.style.display = "none"
|
||||
spinner.style.display = ""
|
||||
canvas.style.display = "none"
|
||||
|
||||
ctx = prepare_canvas(width, height, canvas)
|
||||
ctx = prepare_canvas(width, height, canvas)
|
||||
|
||||
console.log("Computing Mandelbrot set ...")
|
||||
console.time("mandelbrot")
|
||||
iters = mandelbrot(width, height)
|
||||
console.timeEnd("mandelbrot")
|
||||
console.log("Computing Mandelbrot set ...")
|
||||
console.time("mandelbrot")
|
||||
iters = mandelbrot(width, height)
|
||||
console.timeEnd("mandelbrot")
|
||||
|
||||
image = color_map(iters, Magma256)
|
||||
draw_image(ctx, image)
|
||||
image = color_map(iters, Magma256)
|
||||
draw_image(ctx, image)
|
||||
|
||||
spinner.style.display = "none"
|
||||
canvas.style.display = "block"
|
||||
spinner.style.display = "none"
|
||||
canvas.style.display = "block"
|
||||
|
||||
async def draw_julia() -> None:
|
||||
spinner = document.querySelector("#julia .loading")
|
||||
canvas = document.querySelector("#julia canvas")
|
||||
async def draw_julia() -> None:
|
||||
spinner = document.querySelector("#julia .loading")
|
||||
canvas = document.querySelector("#julia canvas")
|
||||
|
||||
spinner.style.display = ""
|
||||
canvas.style.display = "none"
|
||||
spinner.style.display = ""
|
||||
canvas.style.display = "none"
|
||||
|
||||
ctx = prepare_canvas(width, height, canvas)
|
||||
ctx = prepare_canvas(width, height, canvas)
|
||||
|
||||
console.log("Computing Julia set ...")
|
||||
console.time("julia")
|
||||
iters = julia(width, height)
|
||||
console.timeEnd("julia")
|
||||
console.log("Computing Julia set ...")
|
||||
console.time("julia")
|
||||
iters = julia(width, height)
|
||||
console.timeEnd("julia")
|
||||
|
||||
image = color_map(iters, Magma256)
|
||||
draw_image(ctx, image)
|
||||
image = color_map(iters, Magma256)
|
||||
draw_image(ctx, image)
|
||||
|
||||
spinner.style.display = "none"
|
||||
canvas.style.display = "block"
|
||||
spinner.style.display = "none"
|
||||
canvas.style.display = "block"
|
||||
|
||||
def ranges():
|
||||
x0_in = document.querySelector("#x0")
|
||||
x1_in = document.querySelector("#x1")
|
||||
y0_in = document.querySelector("#y0")
|
||||
y1_in = document.querySelector("#y1")
|
||||
def ranges():
|
||||
x0_in = document.querySelector("#x0")
|
||||
x1_in = document.querySelector("#x1")
|
||||
y0_in = document.querySelector("#y0")
|
||||
y1_in = document.querySelector("#y1")
|
||||
|
||||
xr = (float(x0_in.value), float(x1_in.value))
|
||||
yr = (float(y0_in.value), float(y1_in.value))
|
||||
xr = (float(x0_in.value), float(x1_in.value))
|
||||
yr = (float(y0_in.value), float(y1_in.value))
|
||||
|
||||
return xr, yr
|
||||
return xr, yr
|
||||
|
||||
current_image = None
|
||||
async def draw_newton() -> None:
|
||||
spinner = document.querySelector("#newton .loading")
|
||||
canvas = document.querySelector("#newton canvas")
|
||||
current_image = None
|
||||
async def draw_newton() -> None:
|
||||
spinner = document.querySelector("#newton .loading")
|
||||
canvas = document.querySelector("#newton canvas")
|
||||
|
||||
spinner.style.display = ""
|
||||
canvas.style.display = "none"
|
||||
spinner.style.display = ""
|
||||
canvas.style.display = "none"
|
||||
|
||||
ctx = prepare_canvas(width, height, canvas)
|
||||
ctx = prepare_canvas(width, height, canvas)
|
||||
|
||||
console.log("Computing Newton set ...")
|
||||
console.log("Computing Newton set ...")
|
||||
|
||||
poly_in = document.querySelector("#poly")
|
||||
coef_in = document.querySelector("#coef")
|
||||
conv_in = document.querySelector("#conv")
|
||||
iter_in = document.querySelector("#iter")
|
||||
poly_in = document.querySelector("#poly")
|
||||
coef_in = document.querySelector("#coef")
|
||||
conv_in = document.querySelector("#conv")
|
||||
iter_in = document.querySelector("#iter")
|
||||
|
||||
xr, yr = ranges()
|
||||
xr, yr = ranges()
|
||||
|
||||
# z**3 - 1
|
||||
# z**8 + 15*z**4 - 16
|
||||
# z**3 - 2*z + 2
|
||||
# z**3 - 1
|
||||
# z**8 + 15*z**4 - 16
|
||||
# z**3 - 2*z + 2
|
||||
|
||||
expr = sympy.parse_expr(poly_in.value)
|
||||
coeffs = [ complex(c) for c in reversed(sympy.Poly(expr, sympy.Symbol("z")).all_coeffs()) ]
|
||||
poly = np.polynomial.Polynomial(coeffs)
|
||||
expr = sympy.parse_expr(poly_in.value)
|
||||
coeffs = [ complex(c) for c in reversed(sympy.Poly(expr, sympy.Symbol("z")).all_coeffs()) ]
|
||||
poly = np.polynomial.Polynomial(coeffs)
|
||||
|
||||
coef = complex(sympy.parse_expr(coef_in.value))
|
||||
coef = complex(sympy.parse_expr(coef_in.value))
|
||||
|
||||
console.time("newton")
|
||||
iters, roots = newton(width, height, p=poly, a=coef, xr=xr, yr=yr)
|
||||
console.timeEnd("newton")
|
||||
console.time("newton")
|
||||
iters, roots = newton(width, height, p=poly, a=coef, xr=xr, yr=yr)
|
||||
console.timeEnd("newton")
|
||||
|
||||
if conv_in.checked:
|
||||
n = poly.degree() + 1
|
||||
k = int(len(Magma256)/n)
|
||||
if conv_in.checked:
|
||||
n = poly.degree() + 1
|
||||
k = int(len(Magma256)/n)
|
||||
|
||||
colors = Magma256[::k, :][:n]
|
||||
colors[0, :] = [255, 0, 0] # red: no convergence
|
||||
colors = Magma256[::k, :][:n]
|
||||
colors[0, :] = [255, 0, 0] # red: no convergence
|
||||
|
||||
image = color_map(roots, colors)
|
||||
else:
|
||||
image = color_map(iters, Magma256)
|
||||
image = color_map(roots, colors)
|
||||
else:
|
||||
image = color_map(iters, Magma256)
|
||||
|
||||
global current_image
|
||||
current_image = image
|
||||
draw_image(ctx, image)
|
||||
global current_image
|
||||
current_image = image
|
||||
draw_image(ctx, image)
|
||||
|
||||
spinner.style.display = "none"
|
||||
canvas.style.display = "block"
|
||||
spinner.style.display = "none"
|
||||
canvas.style.display = "block"
|
||||
|
||||
handler = create_proxy(lambda _event: draw_newton())
|
||||
document.querySelector("#newton fieldset").addEventListener("change", handler)
|
||||
handler = create_proxy(lambda _event: draw_newton())
|
||||
document.querySelector("#newton fieldset").addEventListener("change", handler)
|
||||
|
||||
canvas = document.querySelector("#newton canvas")
|
||||
canvas = document.querySelector("#newton canvas")
|
||||
|
||||
is_selecting = False
|
||||
init_sx, init_sy = None, None
|
||||
sx, sy = None, None
|
||||
async def mousemove(event):
|
||||
global is_selecting
|
||||
global init_sx
|
||||
global init_sy
|
||||
global sx
|
||||
global sy
|
||||
is_selecting = False
|
||||
init_sx, init_sy = None, None
|
||||
sx, sy = None, None
|
||||
async def mousemove(event):
|
||||
global is_selecting
|
||||
global init_sx
|
||||
global init_sy
|
||||
global sx
|
||||
global sy
|
||||
|
||||
def invert(sx, source_range, target_range):
|
||||
source_start, source_end = source_range
|
||||
target_start, target_end = target_range
|
||||
factor = (target_end - target_start)/(source_end - source_start)
|
||||
offset = -(factor * source_start) + target_start
|
||||
return (sx - offset) / factor
|
||||
def invert(sx, source_range, target_range):
|
||||
source_start, source_end = source_range
|
||||
target_start, target_end = target_range
|
||||
factor = (target_end - target_start)/(source_end - source_start)
|
||||
offset = -(factor * source_start) + target_start
|
||||
return (sx - offset) / factor
|
||||
|
||||
bds = canvas.getBoundingClientRect()
|
||||
event_sx, event_sy = event.clientX - bds.x, event.clientY - bds.y
|
||||
bds = canvas.getBoundingClientRect()
|
||||
event_sx, event_sy = event.clientX - bds.x, event.clientY - bds.y
|
||||
|
||||
ctx = canvas.getContext("2d")
|
||||
ctx = canvas.getContext("2d")
|
||||
|
||||
pressed = event.buttons == 1
|
||||
if is_selecting:
|
||||
if not pressed:
|
||||
xr, yr = ranges()
|
||||
pressed = event.buttons == 1
|
||||
if is_selecting:
|
||||
if not pressed:
|
||||
xr, yr = ranges()
|
||||
|
||||
x0 = invert(init_sx, xr, (0, width))
|
||||
x1 = invert(sx, xr, (0, width))
|
||||
y0 = invert(init_sy, yr, (0, height))
|
||||
y1 = invert(sy, yr, (0, height))
|
||||
x0 = invert(init_sx, xr, (0, width))
|
||||
x1 = invert(sx, xr, (0, width))
|
||||
y0 = invert(init_sy, yr, (0, height))
|
||||
y1 = invert(sy, yr, (0, height))
|
||||
|
||||
document.querySelector("#x0").value = x0
|
||||
document.querySelector("#x1").value = x1
|
||||
document.querySelector("#y0").value = y0
|
||||
document.querySelector("#y1").value = y1
|
||||
document.querySelector("#x0").value = x0
|
||||
document.querySelector("#x1").value = x1
|
||||
document.querySelector("#y0").value = y0
|
||||
document.querySelector("#y1").value = y1
|
||||
|
||||
is_selecting = False
|
||||
init_sx, init_sy = None, None
|
||||
sx, sy = init_sx, init_sy
|
||||
is_selecting = False
|
||||
init_sx, init_sy = None, None
|
||||
sx, sy = init_sx, init_sy
|
||||
|
||||
await draw_newton()
|
||||
else:
|
||||
ctx.save()
|
||||
ctx.clearRect(0, 0, width, height)
|
||||
draw_image(ctx, current_image)
|
||||
sx, sy = event_sx, event_sy
|
||||
ctx.beginPath()
|
||||
ctx.rect(init_sx, init_sy, sx - init_sx, sy - init_sy)
|
||||
ctx.fillStyle = "rgba(255, 255, 255, 0.4)"
|
||||
ctx.strokeStyle = "rgba(255, 255, 255, 1.0)"
|
||||
ctx.fill()
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
else:
|
||||
if pressed:
|
||||
is_selecting = True
|
||||
init_sx, init_sy = event_sx, event_sy
|
||||
sx, sy = init_sx, init_sy
|
||||
await draw_newton()
|
||||
else:
|
||||
ctx.save()
|
||||
ctx.clearRect(0, 0, width, height)
|
||||
draw_image(ctx, current_image)
|
||||
sx, sy = event_sx, event_sy
|
||||
ctx.beginPath()
|
||||
ctx.rect(init_sx, init_sy, sx - init_sx, sy - init_sy)
|
||||
ctx.fillStyle = "rgba(255, 255, 255, 0.4)"
|
||||
ctx.strokeStyle = "rgba(255, 255, 255, 1.0)"
|
||||
ctx.fill()
|
||||
ctx.stroke()
|
||||
ctx.restore()
|
||||
else:
|
||||
if pressed:
|
||||
is_selecting = True
|
||||
init_sx, init_sy = event_sx, event_sy
|
||||
sx, sy = init_sx, init_sy
|
||||
|
||||
canvas.addEventListener("mousemove", create_proxy(mousemove))
|
||||
canvas.addEventListener("mousemove", create_proxy(mousemove))
|
||||
|
||||
import asyncio
|
||||
import asyncio
|
||||
|
||||
async def main():
|
||||
_ = await asyncio.gather(
|
||||
draw_mandelbrot(),
|
||||
draw_julia(),
|
||||
draw_newton(),
|
||||
)
|
||||
async def main():
|
||||
_ = await asyncio.gather(
|
||||
draw_mandelbrot(),
|
||||
draw_julia(),
|
||||
draw_newton(),
|
||||
)
|
||||
|
||||
asyncio.ensure_future(main())
|
||||
asyncio.ensure_future(main())
|
||||
</py-script>
|
||||
</py-tutor>
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,120 +1,124 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title id="header-title"></title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<link rel="icon" type="image/png" href="./favicon.png" />
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<head>
|
||||
<title id="header-title"></title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<link rel="icon" type="image/png" href="./favicon.png" />
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
</head>
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
</a>
|
||||
<a class="title" id="page-title" href="" style="color: #f0ab3c;"></a>
|
||||
</div>
|
||||
</nav>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" id="page-title" href="" style="color: #f0ab3c"></a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<br />
|
||||
<div id="page-message"></div>
|
||||
<br />
|
||||
<div id="page-message"></div>
|
||||
|
||||
<div id="pandas-source">
|
||||
<h3>Data Source</h3>
|
||||
<input type="text" id="txt-url" class="py-input" size="70">
|
||||
<button type="submit" id="btn-load" class="py-button" py-click="loadFromURL()">Load CSV</button>
|
||||
</div>
|
||||
<div id="pandas-source">
|
||||
<h3>Data Source</h3>
|
||||
<input type="text" id="txt-url" class="py-input" size="70" />
|
||||
<button
|
||||
type="submit"
|
||||
id="btn-load"
|
||||
class="py-button"
|
||||
py-click="loadFromURL()"
|
||||
>
|
||||
Load CSV
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="pandas-repl" hidden>
|
||||
<h3>Python REPL</h3>
|
||||
<py-repl id ="pandas-repl-inner" output="pandas-output-inner">
|
||||
# Hit SHIFT + ENTER to execute example code
|
||||
<div id="pandas-repl" hidden>
|
||||
<h3>Python REPL</h3>
|
||||
<py-repl id="pandas-repl-inner" output="pandas-output-inner">
|
||||
# Hit SHIFT + ENTER to execute example code # Get all closed airports in
|
||||
Great Britain df2 = df.query("type == 'closed' & iso_country == 'GB'")
|
||||
df2
|
||||
</py-repl>
|
||||
</div>
|
||||
|
||||
# Get all closed airports in Great Britain
|
||||
df2 = df.query("type == 'closed' & iso_country == 'GB'")
|
||||
df2
|
||||
</py-repl>
|
||||
<div id="pandas-output" hidden>
|
||||
<h3>Output</h3>
|
||||
<div id="pandas-output-inner"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="pandas-dev-console" hidden>
|
||||
<h3>Dev Console</h3>
|
||||
<py-terminal auto></py-terminal>
|
||||
</div>
|
||||
|
||||
<div id ="pandas-output" hidden>
|
||||
<h3>Output</h3>
|
||||
<div id="pandas-output-inner"></div>
|
||||
</div>
|
||||
<py-tutor>
|
||||
<py-config>
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
]
|
||||
packages = ["pandas"]
|
||||
</py-config>
|
||||
|
||||
<div id="pandas-dev-console" hidden>
|
||||
<h3>Dev Console</h3>
|
||||
<py-terminal auto></py-terminal>
|
||||
</div>
|
||||
<section class="pyscript">
|
||||
<py-script>
|
||||
import pandas as pd
|
||||
from pyodide.http import open_url
|
||||
import sys
|
||||
|
||||
<py-tutor>
|
||||
<py-config>
|
||||
plugins = [
|
||||
"../build/plugins/python/py_tutor.py"
|
||||
]
|
||||
packages = ["pandas"]
|
||||
</py-config>
|
||||
title = "Pandas (and basic DOM manipulation)"
|
||||
page_message = "This example loads a remote CSV file into a Pandas dataframe, displays it and lets you manipulate it through a Python REPL"
|
||||
|
||||
<section class="pyscript">
|
||||
<py-script>
|
||||
import pandas as pd
|
||||
from pyodide.http import open_url
|
||||
import sys
|
||||
url = "https://raw.githubusercontent.com/datasets/airport-codes/master/data/airport-codes.csv"
|
||||
|
||||
title = "Pandas (and basic DOM manipulation)"
|
||||
page_message = "This example loads a remote CSV file into a Pandas dataframe, displays it and lets you manipulate it through a Python REPL"
|
||||
Element("header-title").element.innerText = title
|
||||
Element("page-title").element.innerText = title
|
||||
Element("page-message").element.innerText = page_message
|
||||
|
||||
url = "https://raw.githubusercontent.com/datasets/airport-codes/master/data/airport-codes.csv"
|
||||
Element("txt-url").element.value = url
|
||||
|
||||
Element("header-title").element.innerText = title
|
||||
Element("page-title").element.innerText = title
|
||||
Element("page-message").element.innerText = page_message
|
||||
# Depending on the type of DOM element, there are several alternative methods to write to it
|
||||
# Element("id-of-dom-element").write("example")
|
||||
# Element("id-of-dom-element").innerText = "example"
|
||||
# Element("id-of-dom-element").value = "example"
|
||||
# Element("id-of-dom-element").element.innerText = "example"
|
||||
# Element("id-of-dom-element").element.value = "example"
|
||||
# js.document.getElementById("id-of-dom-element").innerText = "example"
|
||||
# js.document.getElementById("id-of-dom-element").value = "example"
|
||||
|
||||
Element("txt-url").element.value = url
|
||||
|
||||
# Depending on the type of DOM element, there are several alternative methods to write to it
|
||||
# Element("id-of-dom-element").write("example")
|
||||
# Element("id-of-dom-element").innerText = "example"
|
||||
# Element("id-of-dom-element").value = "example"
|
||||
# Element("id-of-dom-element").element.innerText = "example"
|
||||
# Element("id-of-dom-element").element.value = "example"
|
||||
# js.document.getElementById("id-of-dom-element").innerText = "example"
|
||||
# js.document.getElementById("id-of-dom-element").value = "example"
|
||||
|
||||
df = pd.DataFrame()
|
||||
df = pd.DataFrame()
|
||||
|
||||
|
||||
def loadFromURL(*ags, **kws):
|
||||
global df
|
||||
def loadFromURL(*ags, **kws):
|
||||
global df
|
||||
|
||||
# clear dataframe & output
|
||||
df = pd.DataFrame()
|
||||
Element("pandas-output-inner").element.innerHTML = ""
|
||||
# clear dataframe & output
|
||||
df = pd.DataFrame()
|
||||
Element("pandas-output-inner").element.innerHTML = ""
|
||||
|
||||
url = Element("txt-url").element.value
|
||||
log ("Trying to fetch CSV from " + url)
|
||||
url = Element("txt-url").element.value
|
||||
log ("Trying to fetch CSV from " + url)
|
||||
|
||||
df = pd.read_csv(open_url(url))
|
||||
df = pd.read_csv(open_url(url))
|
||||
|
||||
Element("pandas-repl").element.style.display = "block"
|
||||
Element("pandas-output").element.style.display = "block"
|
||||
Element("pandas-dev-console").element.style.display = "block"
|
||||
Element("pandas-repl").element.style.display = "block"
|
||||
Element("pandas-output").element.style.display = "block"
|
||||
Element("pandas-dev-console").element.style.display = "block"
|
||||
|
||||
display (df, target="pandas-output-inner", append="False")
|
||||
display (df, target="pandas-output-inner", append="False")
|
||||
|
||||
def log(message):
|
||||
# log to pyscript dev console
|
||||
print (message)
|
||||
def log(message):
|
||||
# log to pyscript dev console
|
||||
print (message)
|
||||
|
||||
# log to JS console
|
||||
js.console.log (message)
|
||||
</py-script>
|
||||
</section>
|
||||
</py-tutor>
|
||||
</body>
|
||||
# log to JS console
|
||||
js.console.log (message)
|
||||
</py-script>
|
||||
</section>
|
||||
</py-tutor>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,23 +1,35 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Panel Example</title>
|
||||
<meta charset="iso-8859-1">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.14.1/dist/panel.min.js"></script>
|
||||
<meta charset="iso-8859-1" />
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.14.1/dist/panel.min.js"
|
||||
></script>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Panel Example</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">Panel Example</a>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
|
||||
@@ -1,34 +1,88 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||||
<meta name="theme-color" content="#0072b5">
|
||||
<meta name="name" content="PyScript/Panel DeckGL Demo">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
||||
<meta name="theme-color" content="#0072b5" />
|
||||
<meta name="name" content="PyScript/Panel DeckGL Demo" />
|
||||
|
||||
<title>PyScript/Panel DeckGL Demo</title>
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css" type="text/css" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css" type="text/css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css"
|
||||
type="text/css"
|
||||
/>
|
||||
|
||||
<script type="text/javascript" src="https://unpkg.com/h3-js@3.7.2/dist/h3-js.umd.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/deck.gl@8.6.7/dist.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@deck.gl/json@8.6.7/dist.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@loaders.gl/csv@3.1.7/dist/dist.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@loaders.gl/json@3.1.7/dist/dist.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@loaders.gl/3d-tiles@3.1.7/dist/dist.min.js"></script>
|
||||
<script type="text/javascript" src="https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://unpkg.com/@holoviz/panel@0.13.1/dist/panel.js"></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/h3-js@3.7.2/dist/h3-js.umd.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.jsdelivr.net/npm/deck.gl@8.6.7/dist.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.jsdelivr.net/npm/@deck.gl/json@8.6.7/dist.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.jsdelivr.net/npm/@loaders.gl/csv@3.1.7/dist/dist.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.jsdelivr.net/npm/@loaders.gl/json@3.1.7/dist/dist.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.jsdelivr.net/npm/@loaders.gl/3d-tiles@3.1.7/dist/dist.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://api.mapbox.com/mapbox-gl-js/v2.6.1/mapbox-gl.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/@holoviz/panel@0.13.1/dist/panel.js"
|
||||
></script>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
|
||||
/>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
@@ -44,20 +98,22 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Panel DeckGL NYC Taxi Demo</a>
|
||||
<a class="title" href="" style="color: #f0ab3c"
|
||||
>Panel DeckGL NYC Taxi Demo</a
|
||||
>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
<div class="d-flex flex-nowrap" id="content">
|
||||
<div class="sidenav" id="sidebar">
|
||||
<ul class="nav flex-column" >
|
||||
<div class="bk-root" id="widgets"></div>
|
||||
<py-repl id="my-repl" auto-generate="true"> </py-repl>
|
||||
<ul class="nav flex-column">
|
||||
<div class="bk-root" id="widgets"></div>
|
||||
<py-repl id="my-repl" auto-generate="true"> </py-repl>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col mh-100" style="padding: 0">
|
||||
@@ -79,148 +135,147 @@
|
||||
</py-config>
|
||||
|
||||
<py-script>
|
||||
import panel as pn
|
||||
import pandas as pd
|
||||
import param
|
||||
import panel as pn
|
||||
import pandas as pd
|
||||
import param
|
||||
|
||||
from pyodide.http import open_url
|
||||
from pyodide.http import open_url
|
||||
|
||||
MAPBOX_KEY = "pk.eyJ1IjoicGFuZWxvcmciLCJhIjoiY2s1enA3ejhyMWhmZjNobjM1NXhtbWRrMyJ9.B_frQsAVepGIe-HiOJeqvQ"
|
||||
MAPBOX_KEY = "pk.eyJ1IjoicGFuZWxvcmciLCJhIjoiY2s1enA3ejhyMWhmZjNobjM1NXhtbWRrMyJ9.B_frQsAVepGIe-HiOJeqvQ"
|
||||
|
||||
class App(param.Parameterized):
|
||||
class App(param.Parameterized):
|
||||
|
||||
data = param.DataFrame(precedence=-1)
|
||||
data = param.DataFrame(precedence=-1)
|
||||
|
||||
view = param.DataFrame(precedence=-1)
|
||||
view = param.DataFrame(precedence=-1)
|
||||
|
||||
arc_view = param.DataFrame(precedence=-1)
|
||||
arc_view = param.DataFrame(precedence=-1)
|
||||
|
||||
radius = param.Integer(default=50, bounds=(20, 1000))
|
||||
radius = param.Integer(default=50, bounds=(20, 1000))
|
||||
|
||||
elevation = param.Integer(default=10, bounds=(0, 50))
|
||||
elevation = param.Integer(default=10, bounds=(0, 50))
|
||||
|
||||
hour = param.Integer(default=0, bounds=(0, 23))
|
||||
hour = param.Integer(default=0, bounds=(0, 23))
|
||||
|
||||
speed = param.Integer(default=1, bounds=(0, 10), precedence=-1)
|
||||
speed = param.Integer(default=1, bounds=(0, 10), precedence=-1)
|
||||
|
||||
play = param.Event(label='▷')
|
||||
play = param.Event(label='▷')
|
||||
|
||||
def __init__(self, **params):
|
||||
self.deck_gl = None
|
||||
super().__init__(**params)
|
||||
self.deck_gl = pn.pane.DeckGL(
|
||||
dict(self.spec),
|
||||
mapbox_api_key=MAPBOX_KEY,
|
||||
throttle={'click': 10},
|
||||
sizing_mode='stretch_both',
|
||||
margin=0
|
||||
)
|
||||
self.deck_gl.param.watch(self._update_arc_view, 'click_state')
|
||||
self._playing = False
|
||||
self._cb = pn.state.add_periodic_callback(
|
||||
self._update_hour, 1000//self.speed, start=False
|
||||
)
|
||||
def __init__(self, **params):
|
||||
self.deck_gl = None
|
||||
super().__init__(**params)
|
||||
self.deck_gl = pn.pane.DeckGL(
|
||||
dict(self.spec),
|
||||
mapbox_api_key=MAPBOX_KEY,
|
||||
throttle={'click': 10},
|
||||
sizing_mode='stretch_both',
|
||||
margin=0
|
||||
)
|
||||
self.deck_gl.param.watch(self._update_arc_view, 'click_state')
|
||||
self._playing = False
|
||||
self._cb = pn.state.add_periodic_callback(
|
||||
self._update_hour, 1000//self.speed, start=False
|
||||
)
|
||||
|
||||
@property
|
||||
def spec(self):
|
||||
return {
|
||||
"initialViewState": {
|
||||
"bearing": 0,
|
||||
"latitude": 40.7,
|
||||
"longitude": -73.9,
|
||||
"maxZoom": 15,
|
||||
"minZoom": 5,
|
||||
"pitch": 40.5,
|
||||
"zoom": 11
|
||||
},
|
||||
"layers": [self.hex_layer, self.arc_layer],
|
||||
"mapStyle": "mapbox://styles/mapbox/dark-v9",
|
||||
"views": [
|
||||
{"@@type": "MapView", "controller": True}
|
||||
]
|
||||
}
|
||||
@property
|
||||
def spec(self):
|
||||
return {
|
||||
"initialViewState": {
|
||||
"bearing": 0,
|
||||
"latitude": 40.7,
|
||||
"longitude": -73.9,
|
||||
"maxZoom": 15,
|
||||
"minZoom": 5,
|
||||
"pitch": 40.5,
|
||||
"zoom": 11
|
||||
},
|
||||
"layers": [self.hex_layer, self.arc_layer],
|
||||
"mapStyle": "mapbox://styles/mapbox/dark-v9",
|
||||
"views": [
|
||||
{"@@type": "MapView", "controller": True}
|
||||
]
|
||||
}
|
||||
|
||||
@property
|
||||
def hex_layer(self):
|
||||
return {
|
||||
"@@type": "HexagonLayer",
|
||||
"autoHighlight": True,
|
||||
"coverage": 1,
|
||||
"data": self.data if self.view is None else self.view,
|
||||
"elevationRange": [0, 100],
|
||||
"elevationScale": self.elevation,
|
||||
"radius": self.radius,
|
||||
"extruded": True,
|
||||
"getPosition": "@@=[pickup_x, pickup_y]",
|
||||
"id": "8a553b25-ef3a-489c-bbe2-e102d18a3211"
|
||||
}
|
||||
@property
|
||||
def hex_layer(self):
|
||||
return {
|
||||
"@@type": "HexagonLayer",
|
||||
"autoHighlight": True,
|
||||
"coverage": 1,
|
||||
"data": self.data if self.view is None else self.view,
|
||||
"elevationRange": [0, 100],
|
||||
"elevationScale": self.elevation,
|
||||
"radius": self.radius,
|
||||
"extruded": True,
|
||||
"getPosition": "@@=[pickup_x, pickup_y]",
|
||||
"id": "8a553b25-ef3a-489c-bbe2-e102d18a3211"
|
||||
}
|
||||
|
||||
@property
|
||||
def arc_layer(self):
|
||||
return {
|
||||
"@@type": "ArcLayer",
|
||||
"id": 'arc-layer',
|
||||
"data": self.arc_view,
|
||||
"pickable": True,
|
||||
"getWidth": 1,
|
||||
"getSourcePosition": "@@=[pickup_x, pickup_y]",
|
||||
"getTargetPosition": "@@=[dropoff_x, dropoff_y]",
|
||||
"getSourceColor": [0, 255, 0, 180],
|
||||
"getTargetColor": [240, 100, 0, 180]
|
||||
}
|
||||
@property
|
||||
def arc_layer(self):
|
||||
return {
|
||||
"@@type": "ArcLayer",
|
||||
"id": 'arc-layer',
|
||||
"data": self.arc_view,
|
||||
"pickable": True,
|
||||
"getWidth": 1,
|
||||
"getSourcePosition": "@@=[pickup_x, pickup_y]",
|
||||
"getTargetPosition": "@@=[dropoff_x, dropoff_y]",
|
||||
"getSourceColor": [0, 255, 0, 180],
|
||||
"getTargetColor": [240, 100, 0, 180]
|
||||
}
|
||||
|
||||
def _update_hour(self):
|
||||
self.hour = (self.hour+1) % 24
|
||||
def _update_hour(self):
|
||||
self.hour = (self.hour+1) % 24
|
||||
|
||||
@param.depends('view', watch=True)
|
||||
def _update_arc_view(self, event=None):
|
||||
data = self.data if self.view is None else self.view
|
||||
if not self.deck_gl or not self.deck_gl.click_state:
|
||||
self.arc_view = data.iloc[:0]
|
||||
return
|
||||
lon, lat = self.deck_gl.click_state['coordinate']
|
||||
tol = 0.001
|
||||
self.arc_view = data[
|
||||
(df.pickup_x>=float(lon-tol)) &
|
||||
(df.pickup_x<=float(lon+tol)) &
|
||||
(df.pickup_y>=float(lat-tol)) &
|
||||
(df.pickup_y<=float(lat+tol))
|
||||
]
|
||||
@param.depends('view', watch=True)
|
||||
def _update_arc_view(self, event=None):
|
||||
data = self.data if self.view is None else self.view
|
||||
if not self.deck_gl or not self.deck_gl.click_state:
|
||||
self.arc_view = data.iloc[:0]
|
||||
return
|
||||
lon, lat = self.deck_gl.click_state['coordinate']
|
||||
tol = 0.001
|
||||
self.arc_view = data[
|
||||
(df.pickup_x>=float(lon-tol)) &
|
||||
(df.pickup_x<=float(lon+tol)) &
|
||||
(df.pickup_y>=float(lat-tol)) &
|
||||
(df.pickup_y<=float(lat+tol))
|
||||
]
|
||||
|
||||
@param.depends('hour', watch=True, on_init=True)
|
||||
def _update_hourly_view(self):
|
||||
self.view = self.data[self.data.hour==self.hour]
|
||||
@param.depends('hour', watch=True, on_init=True)
|
||||
def _update_hourly_view(self):
|
||||
self.view = self.data[self.data.hour==self.hour]
|
||||
|
||||
@param.depends('speed', watch=True)
|
||||
def _update_speed(self):
|
||||
self._cb.period = 1000//self.speed
|
||||
@param.depends('speed', watch=True)
|
||||
def _update_speed(self):
|
||||
self._cb.period = 1000//self.speed
|
||||
|
||||
@param.depends('play', watch=True)
|
||||
def _play_pause(self):
|
||||
if self._playing:
|
||||
self._cb.stop()
|
||||
self.param.play.label = '▷'
|
||||
self.param.speed.precedence = -1
|
||||
else:
|
||||
self._cb.start()
|
||||
self.param.play.label = '❚❚'
|
||||
self.param.speed.precedence = 1
|
||||
self._playing = not self._playing
|
||||
@param.depends('play', watch=True)
|
||||
def _play_pause(self):
|
||||
if self._playing:
|
||||
self._cb.stop()
|
||||
self.param.play.label = '▷'
|
||||
self.param.speed.precedence = -1
|
||||
else:
|
||||
self._cb.start()
|
||||
self.param.play.label = '❚❚'
|
||||
self.param.speed.precedence = 1
|
||||
self._playing = not self._playing
|
||||
|
||||
@param.depends('view', 'radius', 'elevation', 'arc_view', watch=True)
|
||||
def update_spec(self):
|
||||
self.deck_gl.object = dict(self.spec)
|
||||
@param.depends('view', 'radius', 'elevation', 'arc_view', watch=True)
|
||||
def update_spec(self):
|
||||
self.deck_gl.object = dict(self.spec)
|
||||
|
||||
url = 'https://s3.eu-west-1.amazonaws.com/assets.holoviews.org/data/nyc_taxi_wide.csv'
|
||||
df = pd.read_csv(open_url(url))
|
||||
app = App(data=df)
|
||||
controls = pn.Param(app.param, sizing_mode='stretch_width', show_name=False)
|
||||
url = 'https://s3.eu-west-1.amazonaws.com/assets.holoviews.org/data/nyc_taxi_wide.csv'
|
||||
df = pd.read_csv(open_url(url))
|
||||
app = App(data=df)
|
||||
controls = pn.Param(app.param, sizing_mode='stretch_width', show_name=False)
|
||||
|
||||
app.deck_gl.servable(target='plot')
|
||||
controls.servable(target='widgets');
|
||||
app.deck_gl.servable(target='plot')
|
||||
controls.servable(target='widgets');
|
||||
</py-script>
|
||||
</py-tutor>
|
||||
</section>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,38 +1,83 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<meta name="name" content="PyScript/Panel KMeans Demo">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="name" content="PyScript/Panel KMeans Demo" />
|
||||
|
||||
<title>Pyscript/Panel KMeans Demo</title>
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css" type="text/css" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css" type="text/css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css"
|
||||
type="text/css"
|
||||
/>
|
||||
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vega@5"></script>
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vega-lite@5"></script>
|
||||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
|
||||
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://unpkg.com/@holoviz/panel@0.13.1/dist/panel.min.js"></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.jsdelivr.net/npm/vega@5"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.jsdelivr.net/npm/vega-lite@5"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.jsdelivr.net/npm/vega-embed@6"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/@holoviz/panel@0.13.1/dist/panel.min.js"
|
||||
></script>
|
||||
<script type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
|
||||
/>
|
||||
|
||||
<style>
|
||||
#sidebar {
|
||||
width: 350px;
|
||||
width: 350px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -45,21 +90,23 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Panel KMeans Clustering Demo</a>
|
||||
<a class="title" href="" style="color: #f0ab3c"
|
||||
>Panel KMeans Clustering Demo</a
|
||||
>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
<div class="row overflow-hidden" id="content">
|
||||
<div class="sidenav" id="sidebar">
|
||||
<div class="sidenav" id="sidebar">
|
||||
<ul class="nav flex-column">
|
||||
<div class="bk-root" id="x-widget"></div>
|
||||
<div class="bk-root" id="y-widget"></div>
|
||||
<div class="bk-root" id="n-widget"></div>
|
||||
<div class="bk-root" id="x-widget"></div>
|
||||
<div class="bk-root" id="y-widget"></div>
|
||||
<div class="bk-root" id="n-widget"></div>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col mh-100 float-left" id="main">
|
||||
@@ -159,15 +206,19 @@
|
||||
update_table()
|
||||
update_chart()
|
||||
</py-script>
|
||||
</py-tutor>
|
||||
</py-tutor>
|
||||
</section>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
$('#sidebarCollapse').on('click', function () {
|
||||
$('#sidebar').toggleClass('active')
|
||||
$(this).toggleClass('active')
|
||||
var interval = setInterval(function () { window.dispatchEvent(new Event('resize')); }, 10);
|
||||
setTimeout(function () { clearInterval(interval) }, 210)
|
||||
$("#sidebarCollapse").on("click", function () {
|
||||
$("#sidebar").toggleClass("active");
|
||||
$(this).toggleClass("active");
|
||||
var interval = setInterval(function () {
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
}, 10);
|
||||
setTimeout(function () {
|
||||
clearInterval(interval);
|
||||
}, 210);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,31 +1,67 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<meta name="name" content="PyScript/Panel Streaming Demo">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta name="name" content="PyScript/Panel Streaming Demo" />
|
||||
|
||||
<title>PyScript/Panel Streaming Demo</title>
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.ico">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.ico" />
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css" type="text/css" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css" type="text/css" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/widgets.css"
|
||||
type="text/css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/css/markdown.css"
|
||||
type="text/css"
|
||||
/>
|
||||
|
||||
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js"></script>
|
||||
<script type="text/javascript" src="https://unpkg.com/@holoviz/panel@0.13.1/dist/panel.min.js"></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/tabulator-tables@4.9.3/dist/js/tabulator.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.3.min.js"
|
||||
></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/@holoviz/panel@0.13.1/dist/panel.min.js"
|
||||
></script>
|
||||
<script type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css">
|
||||
<link rel="stylesheet" href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/bootstraptemplate/bootstrap.css"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/@holoviz/panel@0.13.1/dist/bundled/defaulttheme/default.css"
|
||||
/>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"></script>
|
||||
@@ -36,12 +72,12 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Panel Streaming Demo</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">Panel Streaming Demo</a>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#output > div {
|
||||
font-family: 'monospace';
|
||||
background-color: #e5e5e5;
|
||||
border: 1px solid lightgray;
|
||||
border-top: 0;
|
||||
font-size: 0.875rem;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
font-family: "monospace";
|
||||
background-color: #e5e5e5;
|
||||
border: 1px solid lightgray;
|
||||
border-top: 0;
|
||||
font-size: 0.875rem;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
#output > div:first-child {
|
||||
border-top: 1px solid lightgray;
|
||||
}
|
||||
#output > div:first-child {
|
||||
border-top: 1px solid lightgray;
|
||||
}
|
||||
|
||||
#output > div:nth-child(even) {
|
||||
border: 0;
|
||||
}
|
||||
#output > div:nth-child(even) {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
@@ -13,18 +13,18 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">PyScript REPL</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">PyScript REPL</a>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
<h1><b>PyScript REPL</b></h1>
|
||||
Tip: press Shift-ENTER to evaluate a cell
|
||||
<br>
|
||||
<br />
|
||||
<py-tutor modules="antigravity.py">
|
||||
<py-config>
|
||||
plugins = [
|
||||
@@ -33,10 +33,10 @@
|
||||
[[fetch]]
|
||||
files = ["./antigravity.py"]
|
||||
</py-config>
|
||||
<div style="margin-right: 3rem;">
|
||||
<div style="margin-right: 3rem">
|
||||
<py-repl id="my-repl" auto-generate="true"> </py-repl>
|
||||
</div>
|
||||
</py-tutor>
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
@@ -14,12 +14,12 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Custom REPL</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">Custom REPL</a>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
@@ -37,11 +37,11 @@
|
||||
[[fetch]]
|
||||
files = ["./utils.py", "./antigravity.py"]
|
||||
</py-config>
|
||||
<div style="margin-right: 3rem;">
|
||||
<div style="margin-right: 3rem">
|
||||
<py-repl id="my-repl" auto-generate="true"> </py-repl>
|
||||
<div id="output" class="p-4"></div>
|
||||
</div>
|
||||
</py-tutor>
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,129 +1,172 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>PyScript — Simple Bioinformatics Example</title>
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1'>
|
||||
<link rel='stylesheet' type='text/css' media='screen' href='https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css'>
|
||||
<link rel="icon" type="image/png" href="https://user-images.githubusercontent.com/49681382/166738771-d0c26557-426c-4688-9641-8db5e6b08348.png" />
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
type="text/css"
|
||||
media="screen"
|
||||
href="https://cdn.jsdelivr.net/npm/bulma@0.9.3/css/bulma.min.css"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
href="https://user-images.githubusercontent.com/49681382/166738771-d0c26557-426c-4688-9641-8db5e6b08348.png"
|
||||
/>
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Header -->
|
||||
<section class="hero is-primary is-small">
|
||||
<div class="hero-body">
|
||||
<p class="title is-3">PyScript — Simple Bioinformatics Example <span class="tag is-white">v.1</span></p>
|
||||
<p class="subtitle is-6">
|
||||
Demonstrates the simple use of <a href="https://pyscript.net/" target="_blank"><code>PyScript</code></a>
|
||||
in <strong>Bioinformatics/Computational Biology</strong> fields!
|
||||
</head>
|
||||
<body>
|
||||
<!-- Header -->
|
||||
<section class="hero is-primary is-small">
|
||||
<div class="hero-body">
|
||||
<p class="title is-3">
|
||||
PyScript — Simple Bioinformatics Example
|
||||
<span class="tag is-white">v.1</span>
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
<p class="subtitle is-6">
|
||||
Demonstrates the simple use of
|
||||
<a href="https://pyscript.net/" target="_blank"
|
||||
><code>PyScript</code></a
|
||||
>
|
||||
in <strong>Bioinformatics/Computational Biology</strong> fields!
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container is-white is-fluid" style="margin-top: 45px">
|
||||
<p class="title is-3">🧬 DNA Sequence Tool</p>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="container is-white is-fluid" style="margin-top:45px">
|
||||
<p class="title is-3">🧬 DNA Sequence Tool</p>
|
||||
|
||||
<!--- DNA Sequence Input -->
|
||||
<div class="field">
|
||||
<!--- DNA Sequence Input -->
|
||||
<div class="field">
|
||||
<label class="label">Input DNA Sequence</label>
|
||||
<div class="control">
|
||||
<textarea class="textarea" placeholder="GATTACA" id="dna_seq"></textarea>
|
||||
<textarea
|
||||
class="textarea"
|
||||
placeholder="GATTACA"
|
||||
id="dna_seq"
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Operation Selection -->
|
||||
<label class="label">Pick the operation to be applied</label>
|
||||
<div class="field has-addons">
|
||||
<!-- Operation Selection -->
|
||||
<label class="label">Pick the operation to be applied</label>
|
||||
<div class="field has-addons">
|
||||
<div class="control is-expanded">
|
||||
<div class="select is-fullwidth">
|
||||
<div class="select is-fullwidth">
|
||||
<select name="operation" id="operation">
|
||||
<option value="Reverse">Compute the reverse counterpart</option>
|
||||
<option value="Complement">Compute the complement counterpart</option>
|
||||
<option value="ReverseComplement">Compute the reverse complement counterpart</option>
|
||||
<option value="Reverse">Compute the reverse counterpart</option>
|
||||
<option value="Complement">
|
||||
Compute the complement counterpart
|
||||
</option>
|
||||
<option value="ReverseComplement">
|
||||
Compute the reverse complement counterpart
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control">
|
||||
<button id="run" type="button" class="button is-primary" py-onClick="run()">Run!</button>
|
||||
<button id="clear" type="button" class="button is-danger" py-onClick="clear()">Clear</button>
|
||||
</div>
|
||||
<button
|
||||
id="run"
|
||||
type="button"
|
||||
class="button is-primary"
|
||||
py-onClick="run()"
|
||||
>
|
||||
Run!
|
||||
</button>
|
||||
<button
|
||||
id="clear"
|
||||
type="button"
|
||||
class="button is-danger"
|
||||
py-onClick="clear()"
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<hr />
|
||||
|
||||
<!--- DNA Sequence Output -->
|
||||
<label class="label">Output for the <code id="operation_name_output">given operation</code></label>
|
||||
<div id="output"></div>
|
||||
</div>
|
||||
|
||||
<br><br>
|
||||
<!-- Footer -->
|
||||
<footer class="footer">
|
||||
<div class="content has-text-centered">
|
||||
<p>
|
||||
Developed by <a href="mailto:furkanmtorun@gmail.com"><strong>Furkan M. Torun (@furkanmtorun)</strong></a>
|
||||
<br>
|
||||
<a href="https://github.com/furkanmtorun">GitHub</a>
|
||||
| <a href="https://scholar.google.com/citations?user=d5ZyOZ4AAAAJ">Google Scholar</a>
|
||||
| <a href="https://twitter.com/furkanmtorun">Twitter</a>
|
||||
| <a href="https://www.linkedin.com/in/furkanmtorun/">LinkedIn</a>
|
||||
</p>
|
||||
<!--- DNA Sequence Output -->
|
||||
<label class="label"
|
||||
>Output for the
|
||||
<code id="operation_name_output">given operation</code></label
|
||||
>
|
||||
<div id="output"></div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<py-script>
|
||||
# Define HTML elements and inputs
|
||||
dna_alphabet = "ATGC"
|
||||
output = Element("output")
|
||||
dna_seq_element = Element("dna_seq")
|
||||
operation_element = Element("operation")
|
||||
operation_name_output_element = Element("operation_name_output")
|
||||
<br /><br />
|
||||
<!-- Footer -->
|
||||
<footer class="footer">
|
||||
<div class="content has-text-centered">
|
||||
<p>
|
||||
Developed by
|
||||
<a href="mailto:furkanmtorun@gmail.com"
|
||||
><strong>Furkan M. Torun (@furkanmtorun)</strong></a
|
||||
>
|
||||
<br />
|
||||
<a href="https://github.com/furkanmtorun">GitHub</a>
|
||||
|
|
||||
<a href="https://scholar.google.com/citations?user=d5ZyOZ4AAAAJ"
|
||||
>Google Scholar</a
|
||||
>
|
||||
| <a href="https://twitter.com/furkanmtorun">Twitter</a> |
|
||||
<a href="https://www.linkedin.com/in/furkanmtorun/">LinkedIn</a>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
# DNA Sequene Operations
|
||||
def return_reverse(dna_seq):
|
||||
return dna_seq[::-1]
|
||||
def return_complement(dna_seq):
|
||||
return dna_seq.translate(str.maketrans("ATCG", "TAGC"))
|
||||
def return_reverse_complement(dna_seq):
|
||||
return dna_seq.translate(str.maketrans("ATCG", "TAGC"))[::-1]
|
||||
<py-script>
|
||||
# Define HTML elements and inputs
|
||||
dna_alphabet = "ATGC"
|
||||
output = Element("output")
|
||||
dna_seq_element = Element("dna_seq")
|
||||
operation_element = Element("operation")
|
||||
operation_name_output_element = Element("operation_name_output")
|
||||
|
||||
# Check DNA seq is valid
|
||||
def check_dna_seq(dna_seq):
|
||||
return all(letter in dna_alphabet for letter in dna_seq.upper())
|
||||
# DNA Sequene Operations
|
||||
def return_reverse(dna_seq):
|
||||
return dna_seq[::-1]
|
||||
def return_complement(dna_seq):
|
||||
return dna_seq.translate(str.maketrans("ATCG", "TAGC"))
|
||||
def return_reverse_complement(dna_seq):
|
||||
return dna_seq.translate(str.maketrans("ATCG", "TAGC"))[::-1]
|
||||
|
||||
# Clear the form and output
|
||||
def clear(*args, **kwargs):
|
||||
dna_seq_element.clear()
|
||||
output.clear()
|
||||
# Check DNA seq is valid
|
||||
def check_dna_seq(dna_seq):
|
||||
return all(letter in dna_alphabet for letter in dna_seq.upper())
|
||||
|
||||
# Run
|
||||
def run(*args, **kwargs):
|
||||
dna_seq = dna_seq_element.value
|
||||
is_dna_seq_valid = check_dna_seq(dna_seq)
|
||||
if is_dna_seq_valid:
|
||||
operation_name = operation_element.value
|
||||
operation_name_output_element.write(operation_name)
|
||||
# Clear the form and output
|
||||
def clear(*args, **kwargs):
|
||||
dna_seq_element.clear()
|
||||
output.clear()
|
||||
|
||||
# Compute the desired outputs
|
||||
if operation_name == "Reverse":
|
||||
output_dna_seq = return_reverse(dna_seq)
|
||||
elif operation_name == "Complement":
|
||||
output_dna_seq = return_complement(dna_seq)
|
||||
elif operation_name == "ReverseComplement":
|
||||
output_dna_seq = return_reverse_complement(dna_seq)
|
||||
# Run
|
||||
def run(*args, **kwargs):
|
||||
dna_seq = dna_seq_element.value
|
||||
is_dna_seq_valid = check_dna_seq(dna_seq)
|
||||
if is_dna_seq_valid:
|
||||
operation_name = operation_element.value
|
||||
operation_name_output_element.write(operation_name)
|
||||
|
||||
# Output the result
|
||||
output.write(output_dna_seq)
|
||||
elif (dna_seq.strip() == "") or (dna_seq is None):
|
||||
output.write("No DNA sequence provided")
|
||||
else:
|
||||
output.write("Invalid DNA sequence entered")
|
||||
</py-script>
|
||||
# Compute the desired outputs
|
||||
if operation_name == "Reverse":
|
||||
output_dna_seq = return_reverse(dna_seq)
|
||||
elif operation_name == "Complement":
|
||||
output_dna_seq = return_complement(dna_seq)
|
||||
elif operation_name == "ReverseComplement":
|
||||
output_dna_seq = return_reverse_complement(dna_seq)
|
||||
|
||||
</body>
|
||||
# Output the result
|
||||
output.write(output_dna_seq)
|
||||
elif (dna_seq.strip() == "") or (dna_seq is None):
|
||||
output.write("No DNA sequence provided")
|
||||
else:
|
||||
output.write("Invalid DNA sequence entered")
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
@@ -14,12 +14,12 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Simple Clock</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">Simple Clock</a>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
@@ -36,29 +36,29 @@
|
||||
files = ["./utils.py"]
|
||||
</py-config>
|
||||
<py-script>
|
||||
import utils
|
||||
display(utils.now())
|
||||
import utils
|
||||
display(utils.now())
|
||||
</py-script>
|
||||
|
||||
<py-script>
|
||||
from utils import now
|
||||
import asyncio
|
||||
from utils import now
|
||||
import asyncio
|
||||
|
||||
async def foo():
|
||||
while True:
|
||||
await asyncio.sleep(1)
|
||||
output = now()
|
||||
Element("outputDiv2").write(output)
|
||||
async def foo():
|
||||
while True:
|
||||
await asyncio.sleep(1)
|
||||
output = now()
|
||||
Element("outputDiv2").write(output)
|
||||
|
||||
out3 = Element("outputDiv3")
|
||||
if output[-1] in ["0", "4", "8"]:
|
||||
out3.write("It's espresso time!")
|
||||
else:
|
||||
out3.clear()
|
||||
out3 = Element("outputDiv3")
|
||||
if output[-1] in ["0", "4", "8"]:
|
||||
out3.write("It's espresso time!")
|
||||
else:
|
||||
out3.clear()
|
||||
|
||||
pyscript.run_until_complete(foo())
|
||||
pyscript.run_until_complete(foo())
|
||||
</py-script>
|
||||
</py-tutor>
|
||||
</section>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
@@ -13,18 +13,24 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Pyscript Native TODO App</a>
|
||||
<a class="title" href="" style="color: #f0ab3c"
|
||||
>Pyscript Native TODO App</a
|
||||
>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
<h1>To Do List</h1>
|
||||
<py-tutor modules="utils.py;pylist.py">
|
||||
<py-register-widget src="./pylist.py" name="py-list" klass="PyList"></py-register-widget>
|
||||
<py-register-widget
|
||||
src="./pylist.py"
|
||||
name="py-list"
|
||||
klass="PyList"
|
||||
></py-register-widget>
|
||||
|
||||
<py-config>
|
||||
plugins = [
|
||||
@@ -62,11 +68,12 @@
|
||||
"keypress",
|
||||
handle_keypress
|
||||
)
|
||||
|
||||
</py-script>
|
||||
<div class="py-box">
|
||||
<input id="new-task-content" />
|
||||
<button py-click="add_task()" id="new-task-btn" class="py-button">Add Task!</button>
|
||||
<button py-click="add_task()" id="new-task-btn" class="py-button">
|
||||
Add Task!
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<py-list id="myList"></py-list>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
@@ -14,12 +14,12 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<nav class="navbar" style="background-color: #000000;">
|
||||
<nav class="navbar" style="background-color: #000000">
|
||||
<div class="app-header">
|
||||
<a href="/">
|
||||
<img src="./logo.png" class="logo">
|
||||
<img src="./logo.png" class="logo" />
|
||||
</a>
|
||||
<a class="title" href="" style="color: #f0ab3c;">Todo App</a>
|
||||
<a class="title" href="" style="color: #f0ab3c">Todo App</a>
|
||||
</div>
|
||||
</nav>
|
||||
<section class="pyscript">
|
||||
@@ -32,34 +32,45 @@
|
||||
files = ["./utils.py", "./todo.py"]
|
||||
</py-config>
|
||||
|
||||
<py-script src="./todo.py"> </py-script>
|
||||
</py-tutor>
|
||||
<py-script src="./todo.py"></py-script>
|
||||
</py-tutor>
|
||||
<main>
|
||||
<section>
|
||||
|
||||
<div class="text-center w-full mb-8">
|
||||
<h1 class="text-3xl font-bold text-gray-800 uppercase tracking-tight">To Do List</h1>
|
||||
<h1
|
||||
class="text-3xl font-bold text-gray-800 uppercase tracking-tight"
|
||||
>
|
||||
To Do List
|
||||
</h1>
|
||||
</div>
|
||||
<div>
|
||||
<input id="new-task-content" class="py-input" type="text">
|
||||
<button id="new-task-btn" class="py-button" type="submit" py-click="add_task()">
|
||||
<input id="new-task-content" class="py-input" type="text" />
|
||||
<button
|
||||
id="new-task-btn"
|
||||
class="py-button"
|
||||
type="submit"
|
||||
py-click="add_task()"
|
||||
>
|
||||
Add task
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<py-list id="myList"></py-list>
|
||||
<div id="list-tasks-container" class="flex flex-col-reverse mt-4"></div>
|
||||
<div
|
||||
id="list-tasks-container"
|
||||
class="flex flex-col-reverse mt-4"
|
||||
></div>
|
||||
|
||||
<template id="task-template">
|
||||
<section class="task py-li-element">
|
||||
<label for="flex items-center p-2 ">
|
||||
<input class="mr-2" type="checkbox">
|
||||
<p class="m-0 inline"></p>
|
||||
</label>
|
||||
<label for="flex items-center p-2 ">
|
||||
<input class="mr-2" type="checkbox" />
|
||||
<p class="m-0 inline"></p>
|
||||
</label>
|
||||
</section>
|
||||
</template>
|
||||
</section>
|
||||
</main>
|
||||
</section>
|
||||
</body>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -9,13 +9,13 @@ It can be served as a Single Page App from a static web server.
|
||||
1. Create and activate a virtual environment, and move into the `freedom`
|
||||
project directory:
|
||||
|
||||
$ python -m venv venv
|
||||
$ . ./venv/bin/activate
|
||||
$ cd freedom
|
||||
$ python -m venv venv
|
||||
$ . ./venv/bin/activate
|
||||
$ cd freedom
|
||||
|
||||
2. Install Briefcase:
|
||||
|
||||
$ pip install briefcase
|
||||
$ pip install briefcase
|
||||
|
||||
## Web app
|
||||
|
||||
|
||||
@@ -1,51 +1,59 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<title>Freedom Units</title>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, shrink-to-fit=no"
|
||||
/>
|
||||
<title>Freedom Units</title>
|
||||
|
||||
<link rel="icon" type="image/png" href="/static/logo-32.png"/>
|
||||
<link rel="icon" type="image/png" href="/static/logo-32.png" />
|
||||
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"
|
||||
integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css"
|
||||
integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N"
|
||||
crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/static/css/briefcase.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="app-placeholder"></div>
|
||||
|
||||
<link rel="stylesheet" href="/static/css/briefcase.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app-placeholder"></div>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
|
||||
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
|
||||
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct"
|
||||
crossorigin="anonymous"></script>
|
||||
<py-config>
|
||||
name = "Freedom Units"
|
||||
description = "A testing app"
|
||||
version = "0.0.1"
|
||||
terminal = false
|
||||
packages = [
|
||||
"./static/wheels/freedom-0.0.1-py3-none-any.whl",
|
||||
"toga_core==0.3.0",
|
||||
"toga_web==0.3.0",
|
||||
"travertino==0.1.3",
|
||||
]
|
||||
|
||||
<py-config>
|
||||
name = "Freedom Units"
|
||||
description = "A testing app"
|
||||
version = "0.0.1"
|
||||
terminal = false
|
||||
packages = [
|
||||
"./static/wheels/freedom-0.0.1-py3-none-any.whl",
|
||||
"toga_core==0.3.0",
|
||||
"toga_web==0.3.0",
|
||||
"travertino==0.1.3",
|
||||
]
|
||||
|
||||
[splashscreen]
|
||||
autoclose = true
|
||||
</py-config>
|
||||
<py-script>
|
||||
import runpy
|
||||
result = runpy.run_module("freedom", run_name="__main__", alter_sys=True)
|
||||
</py-script>
|
||||
</body>
|
||||
[splashscreen]
|
||||
autoclose = true
|
||||
</py-config>
|
||||
<py-script>
|
||||
import runpy
|
||||
result = runpy.run_module("freedom", run_name="__main__", alter_sys=True)
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
|
||||
/* Unset the overly generic pyscript .label style */
|
||||
#app-placeholder .label {
|
||||
margin-top: inherit;
|
||||
color: inherit;
|
||||
text-align: inherit;
|
||||
width: inherit;
|
||||
display: inherit;
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
margin-top: inherit;
|
||||
|
||||
margin-top: inherit;
|
||||
color: inherit;
|
||||
text-align: inherit;
|
||||
width: inherit;
|
||||
display: inherit;
|
||||
color: inherit;
|
||||
font-size: inherit;
|
||||
margin-top: inherit;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
@@ -23,15 +21,15 @@
|
||||
*******************************************************/
|
||||
|
||||
main.toga.window {
|
||||
margin-top: 5em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 5em;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
div.toga.box {
|
||||
display: flex;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
span.toga.label {
|
||||
white-space: nowrap;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -1,194 +1,192 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" >
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Raycaster</title>
|
||||
<link rel="icon" type="image/png" href="../favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="./style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid fixed-top header disable-selection">
|
||||
<div class="row">
|
||||
<div class="col"></div>
|
||||
<div class="col-md-6">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Raycaster</title>
|
||||
<link rel="icon" type="image/png" href="../favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet" href="./style.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid fixed-top header disable-selection">
|
||||
<div class="row">
|
||||
<div class="col"></div>
|
||||
<div class="col-md-6">
|
||||
<div class="row">
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
</div>
|
||||
</div>
|
||||
<script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/0.147.0/three.min.js'></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.147.0/three.min.js"></script>
|
||||
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<py-script>
|
||||
from pyodide.ffi import create_proxy, to_js
|
||||
from js import window
|
||||
from js import Math
|
||||
from js import THREE
|
||||
from js import performance
|
||||
from js import Object
|
||||
from js import document
|
||||
import asyncio
|
||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||
<py-script>
|
||||
from pyodide.ffi import create_proxy, to_js
|
||||
from js import window
|
||||
from js import Math
|
||||
from js import THREE
|
||||
from js import performance
|
||||
from js import Object
|
||||
from js import document
|
||||
import asyncio
|
||||
|
||||
mouse = THREE.Vector2.new();
|
||||
mouse = THREE.Vector2.new();
|
||||
|
||||
renderer = THREE.WebGLRenderer.new({"antialias":True})
|
||||
renderer.setSize(1000, 1000)
|
||||
renderer.shadowMap.enabled = False
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap
|
||||
renderer.shadowMap.needsUpdate = True
|
||||
renderer = THREE.WebGLRenderer.new({"antialias":True})
|
||||
renderer.setSize(1000, 1000)
|
||||
renderer.shadowMap.enabled = False
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap
|
||||
renderer.shadowMap.needsUpdate = True
|
||||
|
||||
document.body.appendChild( renderer.domElement )
|
||||
document.body.appendChild( renderer.domElement )
|
||||
|
||||
import js, pyodide
|
||||
def onMouseMove(event):
|
||||
event.preventDefault();
|
||||
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||
js.document.addEventListener('mousemove', pyodide.ffi.create_proxy(onMouseMove))
|
||||
import js, pyodide
|
||||
def onMouseMove(event):
|
||||
event.preventDefault();
|
||||
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
|
||||
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
|
||||
js.document.addEventListener('mousemove', pyodide.ffi.create_proxy(onMouseMove))
|
||||
|
||||
camera = THREE.PerspectiveCamera.new( 35, window.innerWidth / window.innerHeight, 1, 500 )
|
||||
scene = THREE.Scene.new()
|
||||
cameraRange = 3
|
||||
camera = THREE.PerspectiveCamera.new( 35, window.innerWidth / window.innerHeight, 1, 500 )
|
||||
scene = THREE.Scene.new()
|
||||
cameraRange = 3
|
||||
|
||||
camera.aspect = window.innerWidth / window.innerHeight
|
||||
camera.updateProjectionMatrix()
|
||||
renderer.setSize( window.innerWidth, window.innerHeight )
|
||||
camera.aspect = window.innerWidth / window.innerHeight
|
||||
camera.updateProjectionMatrix()
|
||||
renderer.setSize( window.innerWidth, window.innerHeight )
|
||||
|
||||
setcolor = "#000000"
|
||||
setcolor = "#000000"
|
||||
|
||||
scene.background = THREE.Color.new(setcolor)
|
||||
scene.fog = THREE.Fog.new(setcolor, 2.5, 3.5);
|
||||
scene.background = THREE.Color.new(setcolor)
|
||||
scene.fog = THREE.Fog.new(setcolor, 2.5, 3.5);
|
||||
|
||||
sceneGroup = THREE.Object3D.new();
|
||||
particularGroup = THREE.Object3D.new();
|
||||
sceneGroup = THREE.Object3D.new();
|
||||
particularGroup = THREE.Object3D.new();
|
||||
|
||||
def mathRandom(num = 1):
|
||||
setNumber = - Math.random() * num + Math.random() * num
|
||||
return setNumber
|
||||
def mathRandom(num = 1):
|
||||
setNumber = - Math.random() * num + Math.random() * num
|
||||
return setNumber
|
||||
|
||||
particularGroup = THREE.Object3D.new();
|
||||
modularGroup = THREE.Object3D.new();
|
||||
particularGroup = THREE.Object3D.new();
|
||||
modularGroup = THREE.Object3D.new();
|
||||
|
||||
perms = {"flatShading":True, "color":"#111111", "transparent":False, "opacity":1, "wireframe":False}
|
||||
perms = Object.fromEntries(to_js(perms))
|
||||
perms = {"flatShading":True, "color":"#111111", "transparent":False, "opacity":1, "wireframe":False}
|
||||
perms = Object.fromEntries(to_js(perms))
|
||||
|
||||
particle_perms = {"color":"#FFFFFF", "side":THREE.DoubleSide}
|
||||
particle_perms = Object.fromEntries(to_js(particle_perms))
|
||||
particle_perms = {"color":"#FFFFFF", "side":THREE.DoubleSide}
|
||||
particle_perms = Object.fromEntries(to_js(particle_perms))
|
||||
|
||||
def create_cubes(mathRandom, modularGroup):
|
||||
i = 0
|
||||
while i < 30:
|
||||
geometry = THREE.IcosahedronGeometry.new();
|
||||
material = THREE.MeshStandardMaterial.new(perms);
|
||||
cube = THREE.Mesh.new(geometry, material);
|
||||
cube.speedRotation = Math.random() * 0.1;
|
||||
cube.positionX = mathRandom();
|
||||
cube.positionY = mathRandom();
|
||||
cube.positionZ = mathRandom();
|
||||
cube.castShadow = True;
|
||||
cube.receiveShadow = True;
|
||||
newScaleValue = mathRandom(0.3);
|
||||
cube.scale.set(newScaleValue,newScaleValue,newScaleValue);
|
||||
cube.rotation.x = mathRandom(180 * Math.PI / 180);
|
||||
cube.rotation.y = mathRandom(180 * Math.PI / 180);
|
||||
cube.rotation.z = mathRandom(180 * Math.PI / 180);
|
||||
cube.position.set(cube.positionX, cube.positionY, cube.positionZ);
|
||||
modularGroup.add(cube);
|
||||
i += 1
|
||||
def create_cubes(mathRandom, modularGroup):
|
||||
i = 0
|
||||
while i < 30:
|
||||
geometry = THREE.IcosahedronGeometry.new();
|
||||
material = THREE.MeshStandardMaterial.new(perms);
|
||||
cube = THREE.Mesh.new(geometry, material);
|
||||
cube.speedRotation = Math.random() * 0.1;
|
||||
cube.positionX = mathRandom();
|
||||
cube.positionY = mathRandom();
|
||||
cube.positionZ = mathRandom();
|
||||
cube.castShadow = True;
|
||||
cube.receiveShadow = True;
|
||||
newScaleValue = mathRandom(0.3);
|
||||
cube.scale.set(newScaleValue,newScaleValue,newScaleValue);
|
||||
cube.rotation.x = mathRandom(180 * Math.PI / 180);
|
||||
cube.rotation.y = mathRandom(180 * Math.PI / 180);
|
||||
cube.rotation.z = mathRandom(180 * Math.PI / 180);
|
||||
cube.position.set(cube.positionX, cube.positionY, cube.positionZ);
|
||||
modularGroup.add(cube);
|
||||
i += 1
|
||||
|
||||
create_cubes(mathRandom, modularGroup)
|
||||
create_cubes(mathRandom, modularGroup)
|
||||
|
||||
|
||||
def generateParticle(mathRandom, particularGroup, num, amp = 2):
|
||||
gmaterial = THREE.MeshPhysicalMaterial.new(particle_perms);
|
||||
gparticular = THREE.CircleGeometry.new(0.2,5);
|
||||
i = 0
|
||||
while i < num:
|
||||
pscale = 0.001+Math.abs(mathRandom(0.03));
|
||||
particular = THREE.Mesh.new(gparticular, gmaterial);
|
||||
particular.position.set(mathRandom(amp),mathRandom(amp),mathRandom(amp));
|
||||
particular.rotation.set(mathRandom(),mathRandom(),mathRandom());
|
||||
particular.scale.set(pscale,pscale,pscale);
|
||||
particular.speedValue = mathRandom(1);
|
||||
particularGroup.add(particular);
|
||||
i += 1
|
||||
def generateParticle(mathRandom, particularGroup, num, amp = 2):
|
||||
gmaterial = THREE.MeshPhysicalMaterial.new(particle_perms);
|
||||
gparticular = THREE.CircleGeometry.new(0.2,5);
|
||||
i = 0
|
||||
while i < num:
|
||||
pscale = 0.001+Math.abs(mathRandom(0.03));
|
||||
particular = THREE.Mesh.new(gparticular, gmaterial);
|
||||
particular.position.set(mathRandom(amp),mathRandom(amp),mathRandom(amp));
|
||||
particular.rotation.set(mathRandom(),mathRandom(),mathRandom());
|
||||
particular.scale.set(pscale,pscale,pscale);
|
||||
particular.speedValue = mathRandom(1);
|
||||
particularGroup.add(particular);
|
||||
i += 1
|
||||
|
||||
generateParticle(mathRandom, particularGroup, 200, 2)
|
||||
generateParticle(mathRandom, particularGroup, 200, 2)
|
||||
|
||||
sceneGroup.add(particularGroup);
|
||||
scene.add(modularGroup);
|
||||
scene.add(sceneGroup);
|
||||
sceneGroup.add(particularGroup);
|
||||
scene.add(modularGroup);
|
||||
scene.add(sceneGroup);
|
||||
|
||||
camera.position.set(0, 0, cameraRange);
|
||||
cameraValue = False;
|
||||
camera.position.set(0, 0, cameraRange);
|
||||
cameraValue = False;
|
||||
|
||||
ambientLight = THREE.AmbientLight.new(0xFFFFFF, 0.1);
|
||||
ambientLight = THREE.AmbientLight.new(0xFFFFFF, 0.1);
|
||||
|
||||
light = THREE.SpotLight.new(0xFFFFFF, 3);
|
||||
light.position.set(5, 5, 2);
|
||||
light.castShadow = True;
|
||||
light.shadow.mapSize.width = 10000;
|
||||
light.shadow.mapSize.height = light.shadow.mapSize.width;
|
||||
light.penumbra = 0.5;
|
||||
light = THREE.SpotLight.new(0xFFFFFF, 3);
|
||||
light.position.set(5, 5, 2);
|
||||
light.castShadow = True;
|
||||
light.shadow.mapSize.width = 10000;
|
||||
light.shadow.mapSize.height = light.shadow.mapSize.width;
|
||||
light.penumbra = 0.5;
|
||||
|
||||
lightBack = THREE.PointLight.new(0x0FFFFF, 1);
|
||||
lightBack.position.set(0, -3, -1);
|
||||
lightBack = THREE.PointLight.new(0x0FFFFF, 1);
|
||||
lightBack.position.set(0, -3, -1);
|
||||
|
||||
scene.add(sceneGroup);
|
||||
scene.add(light);
|
||||
scene.add(lightBack);
|
||||
scene.add(sceneGroup);
|
||||
scene.add(light);
|
||||
scene.add(lightBack);
|
||||
|
||||
rectSize = 2
|
||||
intensity = 14
|
||||
rectLight = THREE.RectAreaLight.new( 0x0FFFFF, intensity, rectSize, rectSize )
|
||||
rectLight.position.set( 0, 0, 1 )
|
||||
rectLight.lookAt( 0, 0, 0 )
|
||||
scene.add( rectLight )
|
||||
rectSize = 2
|
||||
intensity = 14
|
||||
rectLight = THREE.RectAreaLight.new( 0x0FFFFF, intensity, rectSize, rectSize )
|
||||
rectLight.position.set( 0, 0, 1 )
|
||||
rectLight.lookAt( 0, 0, 0 )
|
||||
scene.add( rectLight )
|
||||
|
||||
raycaster = THREE.Raycaster.new();
|
||||
uSpeed = 0.1
|
||||
raycaster = THREE.Raycaster.new();
|
||||
uSpeed = 0.1
|
||||
|
||||
time = 0.0003;
|
||||
camera.lookAt(scene.position)
|
||||
time = 0.0003;
|
||||
camera.lookAt(scene.position)
|
||||
|
||||
async def main():
|
||||
while True:
|
||||
time = performance.now() * 0.0003;
|
||||
i = 0
|
||||
while i < particularGroup.children.length:
|
||||
newObject = particularGroup.children[i];
|
||||
newObject.rotation.x += newObject.speedValue/10;
|
||||
newObject.rotation.y += newObject.speedValue/10;
|
||||
newObject.rotation.z += newObject.speedValue/10;
|
||||
i += 1
|
||||
async def main():
|
||||
while True:
|
||||
time = performance.now() * 0.0003;
|
||||
i = 0
|
||||
while i < particularGroup.children.length:
|
||||
newObject = particularGroup.children[i];
|
||||
newObject.rotation.x += newObject.speedValue/10;
|
||||
newObject.rotation.y += newObject.speedValue/10;
|
||||
newObject.rotation.z += newObject.speedValue/10;
|
||||
i += 1
|
||||
|
||||
i = 0
|
||||
while i < modularGroup.children.length:
|
||||
newCubes = modularGroup.children[i];
|
||||
newCubes.rotation.x += 0.008;
|
||||
newCubes.rotation.y += 0.005;
|
||||
newCubes.rotation.z += 0.003;
|
||||
i = 0
|
||||
while i < modularGroup.children.length:
|
||||
newCubes = modularGroup.children[i];
|
||||
newCubes.rotation.x += 0.008;
|
||||
newCubes.rotation.y += 0.005;
|
||||
newCubes.rotation.z += 0.003;
|
||||
|
||||
newCubes.position.x = Math.sin(time * newCubes.positionZ) * newCubes.positionY;
|
||||
newCubes.position.y = Math.cos(time * newCubes.positionX) * newCubes.positionZ;
|
||||
newCubes.position.z = Math.sin(time * newCubes.positionY) * newCubes.positionX;
|
||||
i += 1
|
||||
newCubes.position.x = Math.sin(time * newCubes.positionZ) * newCubes.positionY;
|
||||
newCubes.position.y = Math.cos(time * newCubes.positionX) * newCubes.positionZ;
|
||||
newCubes.position.z = Math.sin(time * newCubes.positionY) * newCubes.positionX;
|
||||
i += 1
|
||||
|
||||
particularGroup.rotation.y += 0.005;
|
||||
particularGroup.rotation.y += 0.005;
|
||||
|
||||
modularGroup.rotation.y -= ((mouse.x * 4) + modularGroup.rotation.y) * uSpeed;
|
||||
modularGroup.rotation.x -= ((-mouse.y * 4) + modularGroup.rotation.x) * uSpeed;
|
||||
modularGroup.rotation.y -= ((mouse.x * 4) + modularGroup.rotation.y) * uSpeed;
|
||||
modularGroup.rotation.x -= ((-mouse.y * 4) + modularGroup.rotation.x) * uSpeed;
|
||||
|
||||
renderer.render( scene, camera )
|
||||
await asyncio.sleep(0.02)
|
||||
renderer.render( scene, camera )
|
||||
await asyncio.sleep(0.02)
|
||||
|
||||
asyncio.ensure_future(main())
|
||||
|
||||
</py-script>
|
||||
</body>
|
||||
asyncio.ensure_future(main())
|
||||
</py-script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -12,10 +12,10 @@ canvas {
|
||||
.header {
|
||||
/*top:45%;*/
|
||||
top: 45%;
|
||||
color: #DDDDDD;
|
||||
color: #dddddd;
|
||||
}
|
||||
.footer {
|
||||
bottom:3%;
|
||||
bottom: 3%;
|
||||
}
|
||||
.description {
|
||||
color: gray;
|
||||
@@ -25,29 +25,31 @@ canvas {
|
||||
border-radius: 30px;
|
||||
padding: 10px 30px;
|
||||
}
|
||||
a, a:hover, a:visited {
|
||||
a,
|
||||
a:hover,
|
||||
a:visited {
|
||||
color: red;
|
||||
text-decoration: none;
|
||||
}
|
||||
.disable-selection {
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* Internet Explorer */
|
||||
-khtml-user-select: none; /* KHTML browsers (e.g. Konqueror) */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* Internet Explorer */
|
||||
-khtml-user-select: none; /* KHTML browsers (e.g. Konqueror) */
|
||||
-webkit-user-select: none; /* Chrome, Safari, and Opera */
|
||||
-webkit-touch-callout: none; /* Disable Android and iOS callouts*/
|
||||
}
|
||||
h1::after {
|
||||
content: ' V 2.0';
|
||||
content: " V 2.0";
|
||||
font-size: 12px;
|
||||
position:absolute;
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
padding-left: 5px;
|
||||
font-weight: 400;
|
||||
}
|
||||
h2::after {
|
||||
content: '2';
|
||||
content: "2";
|
||||
font-size: 12px;
|
||||
position:absolute;
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
module.exports = "";
|
||||
module.exports = '';
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* nothing.
|
||||
*/
|
||||
|
||||
console.warn(`.py files that are not explicitly mocked in \
|
||||
console.warn(`.py files that are not explicitly mocked in \
|
||||
jest.config.js and /__mocks__/ are mocked as empty strings`);
|
||||
|
||||
module.exports = "";
|
||||
module.exports = '';
|
||||
|
||||
@@ -17,7 +17,7 @@ module.exports = {
|
||||
url: 'http://localhost',
|
||||
},
|
||||
moduleNameMapper: {
|
||||
'^.*?pyscript\.py$': '<rootDir>/__mocks__/_pyscript.js',
|
||||
'^.*?pyscript.py$': '<rootDir>/__mocks__/_pyscript.js',
|
||||
'^[./a-zA-Z0-9$_-]+\\.py$': '<rootDir>/__mocks__/fileMock.js',
|
||||
'\\.(css)$': '<rootDir>/__mocks__/cssMock.js',
|
||||
},
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
{
|
||||
"name": "pyscript",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"build-min": "NODE_ENV=production rollup -c",
|
||||
"build": "rollup -c",
|
||||
"dev": "rollup -c -w",
|
||||
"tsc": "tsc --noEmit",
|
||||
"format:check": "prettier --check './src/**/*.{js,html,ts}'",
|
||||
"format": "prettier --write './src/**/*.{js,html,ts}'",
|
||||
"lint": "eslint './src/**/*.{js,html,ts}'",
|
||||
"lint:fix": "eslint --fix './src/**/*.{js,html,ts}'",
|
||||
"xprelint": "npm run format",
|
||||
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage",
|
||||
"test:watch": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jest/globals": "29.1.2",
|
||||
"@rollup/plugin-commonjs": "22.0.2",
|
||||
"@rollup/plugin-legacy": "2.2.0",
|
||||
"@rollup/plugin-node-resolve": "14.1.0",
|
||||
"@rollup/plugin-typescript": "8.5.0",
|
||||
"@types/codemirror": "^5.60.5",
|
||||
"@types/jest": "29.1.2",
|
||||
"@types/node": "18.8.3",
|
||||
"@typescript-eslint/eslint-plugin": "5.39.0",
|
||||
"@typescript-eslint/parser": "5.39.0",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint": "8.25.0",
|
||||
"jest": "29.1.2",
|
||||
"jest-environment-jsdom": "29.1.2",
|
||||
"prettier": "2.7.1",
|
||||
"pyodide": "0.22.1",
|
||||
"rollup": "2.79.1",
|
||||
"rollup-plugin-copy": "3.4.0",
|
||||
"rollup-plugin-css-only": "3.1.0",
|
||||
"rollup-plugin-livereload": "2.0.5",
|
||||
"rollup-plugin-serve": "2.0.1",
|
||||
"rollup-plugin-string": "3.0.0",
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
"ts-jest": "29.0.3",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.8.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/commands": "6.1.1",
|
||||
"@codemirror/lang-python": "6.0.2",
|
||||
"@codemirror/language": "6.2.1",
|
||||
"@codemirror/state": "6.1.2",
|
||||
"@codemirror/theme-one-dark": "6.1.0",
|
||||
"@codemirror/view": "6.3.0",
|
||||
"codemirror": "6.0.1"
|
||||
}
|
||||
"name": "pyscript",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"build-min": "NODE_ENV=production rollup -c",
|
||||
"build": "rollup -c",
|
||||
"dev": "rollup -c -w",
|
||||
"tsc": "tsc --noEmit",
|
||||
"format:check": "prettier --check './src/**/*.{js,html,ts}'",
|
||||
"format": "prettier --write './src/**/*.{js,html,ts}'",
|
||||
"lint": "eslint './src/**/*.{js,html,ts}'",
|
||||
"lint:fix": "eslint --fix './src/**/*.{js,html,ts}'",
|
||||
"xprelint": "npm run format",
|
||||
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --coverage",
|
||||
"test:watch": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jest/globals": "29.1.2",
|
||||
"@rollup/plugin-commonjs": "22.0.2",
|
||||
"@rollup/plugin-legacy": "2.2.0",
|
||||
"@rollup/plugin-node-resolve": "14.1.0",
|
||||
"@rollup/plugin-typescript": "8.5.0",
|
||||
"@types/codemirror": "^5.60.5",
|
||||
"@types/jest": "29.1.2",
|
||||
"@types/node": "18.8.3",
|
||||
"@typescript-eslint/eslint-plugin": "5.39.0",
|
||||
"@typescript-eslint/parser": "5.39.0",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint": "8.25.0",
|
||||
"jest": "29.1.2",
|
||||
"jest-environment-jsdom": "29.1.2",
|
||||
"prettier": "2.7.1",
|
||||
"pyodide": "0.22.1",
|
||||
"rollup": "2.79.1",
|
||||
"rollup-plugin-copy": "3.4.0",
|
||||
"rollup-plugin-css-only": "3.1.0",
|
||||
"rollup-plugin-livereload": "2.0.5",
|
||||
"rollup-plugin-serve": "2.0.1",
|
||||
"rollup-plugin-string": "3.0.0",
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
"ts-jest": "29.0.3",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.8.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@codemirror/commands": "6.1.1",
|
||||
"@codemirror/lang-python": "6.0.2",
|
||||
"@codemirror/language": "6.2.1",
|
||||
"@codemirror/state": "6.1.2",
|
||||
"@codemirror/theme-one-dark": "6.1.0",
|
||||
"@codemirror/view": "6.3.0",
|
||||
"codemirror": "6.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/mvp.css@1.12/mvp.css" />
|
||||
<link rel="stylesheet" href="pyscript.css" />
|
||||
<script defer src="pyscript.min.js"></script>
|
||||
<title>PyScript</title>
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="https://unpkg.com/mvp.css@1.12/mvp.css">
|
||||
<link rel="stylesheet" href="pyscript.css">
|
||||
<script defer src="pyscript.min.js"></script>
|
||||
<title>PyScript</title>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1><py-script></h1>
|
||||
<ul>
|
||||
<li><a href="pyscript.js">pyscript.js</a></li>
|
||||
<li><a href="pyscript.min.js">pyscript.min.js</a></li>
|
||||
<li><a href="pyscript.css">pyscript.css</a></li>
|
||||
<li><a href="pyscript.min.js.map">pyscript.min.js.map</a></li>
|
||||
<li><a href="pyscript.js.map">pyscript.js.map</a></li>
|
||||
</ul>
|
||||
<div id="out"></div>
|
||||
<py-script std-out="out">
|
||||
import sys
|
||||
print(sys.version)
|
||||
</py-script>
|
||||
|
||||
<body>
|
||||
<main>
|
||||
<h1><py-script></h1>
|
||||
<ul>
|
||||
<li><a href="pyscript.js">pyscript.js</a></li>
|
||||
<li><a href="pyscript.min.js">pyscript.min.js</a></li>
|
||||
<li><a href="pyscript.css">pyscript.css</a></li>
|
||||
<li><a href="pyscript.min.js.map">pyscript.min.js.map</a></li>
|
||||
<li><a href="pyscript.js.map">pyscript.js.map</a></li>
|
||||
</ul>
|
||||
<div id="out"></div>
|
||||
<py-script std-out="out">
|
||||
import sys
|
||||
print(sys.version)
|
||||
</py-script>
|
||||
|
||||
<h2>Example</h2>
|
||||
<pre style="padding:1em;border:1px solid #000000;"><!DOCTYPE html>
|
||||
<h2>Example</h2>
|
||||
<pre style="padding: 1em; border: 1px solid #000000">
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
@@ -47,8 +47,8 @@ now = datetime.now()
|
||||
now.strftime("%m/%d/%Y, %H:%M:%S")
|
||||
</py-script>
|
||||
</body>
|
||||
</html></pre>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html></pre
|
||||
>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,69 +1,70 @@
|
||||
import commonjs from "@rollup/plugin-commonjs";
|
||||
import resolve from "@rollup/plugin-node-resolve";
|
||||
import { terser } from "rollup-plugin-terser";
|
||||
import commonjs from '@rollup/plugin-commonjs';
|
||||
import resolve from '@rollup/plugin-node-resolve';
|
||||
import { terser } from 'rollup-plugin-terser';
|
||||
import legacy from '@rollup/plugin-legacy';
|
||||
import typescript from "@rollup/plugin-typescript";
|
||||
import css from "rollup-plugin-css-only";
|
||||
import serve from "rollup-plugin-serve";
|
||||
import { string } from "rollup-plugin-string";
|
||||
import copy from 'rollup-plugin-copy'
|
||||
import typescript from '@rollup/plugin-typescript';
|
||||
import css from 'rollup-plugin-css-only';
|
||||
import serve from 'rollup-plugin-serve';
|
||||
import { string } from 'rollup-plugin-string';
|
||||
import copy from 'rollup-plugin-copy';
|
||||
|
||||
const production = !process.env.ROLLUP_WATCH || (process.env.NODE_ENV === "production");
|
||||
const production = !process.env.ROLLUP_WATCH || process.env.NODE_ENV === 'production';
|
||||
|
||||
const copy_targets = {
|
||||
targets: [
|
||||
{ src: 'public/index.html', dest: 'build' },
|
||||
{ src: 'src/plugins/*', dest: 'build/plugins' }
|
||||
]
|
||||
}
|
||||
targets: [
|
||||
{ src: 'public/index.html', dest: 'build' },
|
||||
{ src: 'src/plugins/*', dest: 'build/plugins' },
|
||||
],
|
||||
};
|
||||
|
||||
if( !production ){
|
||||
copy_targets.targets.push({ src: 'build/*', dest: 'examples/build' })
|
||||
if (!production) {
|
||||
copy_targets.targets.push({ src: 'build/*', dest: 'examples/build' });
|
||||
}
|
||||
|
||||
export default {
|
||||
input: "src/main.ts",
|
||||
output:[
|
||||
{
|
||||
file: "build/pyscript.js",
|
||||
format: "iife",
|
||||
sourcemap: true,
|
||||
inlineDynamicImports: true,
|
||||
name: "pyscript",
|
||||
input: 'src/main.ts',
|
||||
output: [
|
||||
{
|
||||
file: 'build/pyscript.js',
|
||||
format: 'iife',
|
||||
sourcemap: true,
|
||||
inlineDynamicImports: true,
|
||||
name: 'pyscript',
|
||||
},
|
||||
{
|
||||
file: 'build/pyscript.min.js',
|
||||
format: 'iife',
|
||||
sourcemap: true,
|
||||
inlineDynamicImports: true,
|
||||
name: 'pyscript',
|
||||
plugins: [terser()],
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
css({ output: 'pyscript.css' }),
|
||||
// Bundle all the Python files into the output file
|
||||
string({
|
||||
include: './src/**/*.py',
|
||||
}),
|
||||
legacy({ 'src/toml.js': 'toml' }),
|
||||
resolve({
|
||||
browser: true,
|
||||
}),
|
||||
commonjs(),
|
||||
typescript({
|
||||
sourceMap: !production,
|
||||
inlineSources: !production,
|
||||
}),
|
||||
// This will make sure that examples will always get the latest build folder
|
||||
copy(copy_targets),
|
||||
// production && terser(),
|
||||
!production &&
|
||||
serve({
|
||||
port: 8080,
|
||||
contentBase: 'examples',
|
||||
}),
|
||||
],
|
||||
watch: {
|
||||
clearScreen: false,
|
||||
},
|
||||
{
|
||||
file: "build/pyscript.min.js",
|
||||
format: "iife",
|
||||
sourcemap: true,
|
||||
inlineDynamicImports: true,
|
||||
name: "pyscript",
|
||||
plugins: [terser()],
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
css({ output: "pyscript.css" }),
|
||||
// Bundle all the Python files into the output file
|
||||
string({
|
||||
include: "./src/**/*.py",
|
||||
}),
|
||||
legacy({ 'src/toml.js': 'toml' }),
|
||||
resolve({
|
||||
browser: true,
|
||||
}),
|
||||
commonjs(),
|
||||
typescript({
|
||||
sourceMap: !production,
|
||||
inlineSources: !production,
|
||||
}),
|
||||
// This will make sure that examples will always get the latest build folder
|
||||
copy(copy_targets),
|
||||
// production && terser(),
|
||||
!production && serve({
|
||||
port: 8080,
|
||||
contentBase: 'examples'}
|
||||
)
|
||||
],
|
||||
watch: {
|
||||
clearScreen: false,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -34,11 +34,16 @@ export function make_PyScript(interpreter: InterpreterClient, app: PyScriptApp)
|
||||
const pySrc = await this.getPySrc();
|
||||
this.innerHTML = '';
|
||||
|
||||
app.plugins.beforePyScriptExec({interpreter: interpreter, src: pySrc, pyScriptTag: this});
|
||||
app.plugins.beforePyScriptExec({ interpreter: interpreter, src: pySrc, pyScriptTag: this });
|
||||
const result = (await pyExec(interpreter, pySrc, this)).result;
|
||||
app.plugins.afterPyScriptExec({interpreter: interpreter, src: pySrc, pyScriptTag: this, result: result});
|
||||
app.plugins.afterPyScriptExec({
|
||||
interpreter: interpreter,
|
||||
src: pySrc,
|
||||
pyScriptTag: this,
|
||||
result: result,
|
||||
});
|
||||
} finally {
|
||||
releaseLock()
|
||||
releaseLock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,8 +204,7 @@ function createElementsWithEventListeners(interpreter: InterpreterClient, pyAttr
|
||||
void (async () => {
|
||||
try {
|
||||
await interpreter.run(handlerCode);
|
||||
}
|
||||
catch (err) {
|
||||
} catch (err) {
|
||||
displayPyException(err, el.parentElement);
|
||||
}
|
||||
})();
|
||||
|
||||
@@ -12,51 +12,49 @@ The convention is:
|
||||
*/
|
||||
|
||||
export enum ErrorCode {
|
||||
GENERIC = "PY0000", // Use this only for development then change to a more specific error code
|
||||
FETCH_ERROR = "PY0001",
|
||||
FETCH_NAME_ERROR = "PY0002",
|
||||
// Currently these are created depending on error code received from fetching
|
||||
FETCH_UNAUTHORIZED_ERROR = "PY0401",
|
||||
FETCH_FORBIDDEN_ERROR = "PY0403",
|
||||
FETCH_NOT_FOUND_ERROR = "PY0404",
|
||||
FETCH_SERVER_ERROR = "PY0500",
|
||||
FETCH_UNAVAILABLE_ERROR = "PY0503",
|
||||
BAD_CONFIG = "PY1000",
|
||||
MICROPIP_INSTALL_ERROR = "PY1001",
|
||||
BAD_PLUGIN_FILE_EXTENSION = "PY2000",
|
||||
NO_DEFAULT_EXPORT = "PY2001",
|
||||
TOP_LEVEL_AWAIT = "PY9000"
|
||||
GENERIC = 'PY0000', // Use this only for development then change to a more specific error code
|
||||
FETCH_ERROR = 'PY0001',
|
||||
FETCH_NAME_ERROR = 'PY0002',
|
||||
// Currently these are created depending on error code received from fetching
|
||||
FETCH_UNAUTHORIZED_ERROR = 'PY0401',
|
||||
FETCH_FORBIDDEN_ERROR = 'PY0403',
|
||||
FETCH_NOT_FOUND_ERROR = 'PY0404',
|
||||
FETCH_SERVER_ERROR = 'PY0500',
|
||||
FETCH_UNAVAILABLE_ERROR = 'PY0503',
|
||||
BAD_CONFIG = 'PY1000',
|
||||
MICROPIP_INSTALL_ERROR = 'PY1001',
|
||||
BAD_PLUGIN_FILE_EXTENSION = 'PY2000',
|
||||
NO_DEFAULT_EXPORT = 'PY2001',
|
||||
TOP_LEVEL_AWAIT = 'PY9000',
|
||||
}
|
||||
|
||||
export class UserError extends Error {
|
||||
messageType: MessageType;
|
||||
errorCode: ErrorCode;
|
||||
messageType: MessageType;
|
||||
errorCode: ErrorCode;
|
||||
|
||||
constructor(errorCode: ErrorCode, message: string, t: MessageType = "text") {
|
||||
super(message);
|
||||
this.errorCode = errorCode;
|
||||
this.name = "UserError";
|
||||
this.messageType = t;
|
||||
this.message = `(${errorCode}): ${message}`;
|
||||
}
|
||||
constructor(errorCode: ErrorCode, message: string, t: MessageType = 'text') {
|
||||
super(message);
|
||||
this.errorCode = errorCode;
|
||||
this.name = 'UserError';
|
||||
this.messageType = t;
|
||||
this.message = `(${errorCode}): ${message}`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class FetchError extends UserError {
|
||||
errorCode: ErrorCode;
|
||||
constructor(errorCode: ErrorCode, message: string) {
|
||||
super(errorCode, message)
|
||||
this.name = "FetchError";
|
||||
}
|
||||
errorCode: ErrorCode;
|
||||
constructor(errorCode: ErrorCode, message: string) {
|
||||
super(errorCode, message);
|
||||
this.name = 'FetchError';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class InstallError extends UserError {
|
||||
errorCode: ErrorCode;
|
||||
constructor(errorCode: ErrorCode, message: string) {
|
||||
super(errorCode, message)
|
||||
this.name = "InstallError";
|
||||
}
|
||||
errorCode: ErrorCode;
|
||||
constructor(errorCode: ErrorCode, message: string) {
|
||||
super(errorCode, message);
|
||||
this.name = 'InstallError';
|
||||
}
|
||||
}
|
||||
|
||||
export function _createAlertBanner(
|
||||
|
||||
@@ -11,7 +11,6 @@ InterpreterClient class is responsible to request code execution
|
||||
(among other things) from a `RemoteInterpreter`
|
||||
*/
|
||||
export class InterpreterClient extends Object {
|
||||
|
||||
_remote: RemoteInterpreter;
|
||||
config: AppConfig;
|
||||
/**
|
||||
@@ -41,7 +40,7 @@ export class InterpreterClient extends Object {
|
||||
* the remote interpreter.
|
||||
* Python exceptions are turned into JS exceptions.
|
||||
* */
|
||||
async run(code: string): Promise<{result: any}> {
|
||||
async run(code: string): Promise<{ result: any }> {
|
||||
return await this._remote.run(code);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ function getLogger(prefix: string): Logger {
|
||||
}
|
||||
|
||||
function _makeLogger(prefix: string): Logger {
|
||||
prefix =`[${prefix}] `;
|
||||
prefix = `[${prefix}] `;
|
||||
|
||||
function make(level: string) {
|
||||
const out_fn = console[level].bind(console);
|
||||
|
||||
@@ -208,7 +208,7 @@ export class PyScriptApp {
|
||||
logger.info('importing pyscript');
|
||||
|
||||
// Save and load pyscript.py from FS
|
||||
interpreter._remote.interface.FS.mkdirTree("/home/pyodide/pyscript");
|
||||
interpreter._remote.interface.FS.mkdirTree('/home/pyodide/pyscript');
|
||||
interpreter._remote.interface.FS.writeFile('pyscript/__init__.py', pyscript);
|
||||
//Refresh the module cache so Python consistently finds pyscript module
|
||||
interpreter._remote.invalidate_module_path_cache();
|
||||
|
||||
@@ -5,7 +5,7 @@ import { make_PyScript } from './components/pyscript';
|
||||
import { InterpreterClient } from './interpreter_client';
|
||||
|
||||
const logger = getLogger('plugin');
|
||||
type PyScriptTag = InstanceType<ReturnType<typeof make_PyScript>>;
|
||||
type PyScriptTag = InstanceType<ReturnType<typeof make_PyScript>>;
|
||||
|
||||
export class Plugin {
|
||||
/** Validate the configuration of the plugin and handle default values.
|
||||
@@ -48,7 +48,7 @@ export class Plugin {
|
||||
* @param options.src {string} The Python source code to be evaluated
|
||||
* @param options.pyScriptTag The <py-script> HTML tag that originated the evaluation
|
||||
*/
|
||||
beforePyScriptExec(options: {interpreter: InterpreterClient, src: string, pyScriptTag: PyScriptTag}) {}
|
||||
beforePyScriptExec(options: { interpreter: InterpreterClient; src: string; pyScriptTag: PyScriptTag }) {}
|
||||
|
||||
/** The Python in a <py-script> has just been evaluated, but control
|
||||
* has not been ceded back to the JavaScript event loop yet
|
||||
@@ -58,7 +58,12 @@ export class Plugin {
|
||||
* @param options.pyScriptTag The <py-script> HTML tag that originated the evaluation
|
||||
* @param options.result The returned result of evaluating the Python (if any)
|
||||
*/
|
||||
afterPyScriptExec(options: {interpreter: InterpreterClient, src: string, pyScriptTag: PyScriptTag, result: any}) {}
|
||||
afterPyScriptExec(options: {
|
||||
interpreter: InterpreterClient;
|
||||
src: string;
|
||||
pyScriptTag: PyScriptTag;
|
||||
result: any;
|
||||
}) {}
|
||||
|
||||
/** Startup complete. The interpreter is initialized and ready, user
|
||||
* scripts have been executed: the main initialization logic ends here and
|
||||
@@ -122,13 +127,13 @@ export class PluginManager {
|
||||
for (const p of this._pythonPlugins) p.afterStartup?.(interpreter);
|
||||
}
|
||||
|
||||
beforePyScriptExec(options: {interpreter: InterpreterClient, src: string, pyScriptTag: PyScriptTag}) {
|
||||
beforePyScriptExec(options: { interpreter: InterpreterClient; src: string; pyScriptTag: PyScriptTag }) {
|
||||
for (const p of this._plugins) p.beforePyScriptExec?.(options);
|
||||
|
||||
for (const p of this._pythonPlugins) p.beforePyScriptExec?.callKwargs(options);
|
||||
}
|
||||
|
||||
afterPyScriptExec(options: {interpreter: InterpreterClient, src: string, pyScriptTag: PyScriptTag, result: any}) {
|
||||
afterPyScriptExec(options: { interpreter: InterpreterClient; src: string; pyScriptTag: PyScriptTag; result: any }) {
|
||||
for (const p of this._plugins) p.afterPyScriptExec?.(options);
|
||||
|
||||
for (const p of this._pythonPlugins) p.afterPyScriptExec?.callKwargs(options);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { joinPaths } from '../utils';
|
||||
import { FetchConfig } from "../pyconfig";
|
||||
import { FetchConfig } from '../pyconfig';
|
||||
import { UserError, ErrorCode } from '../exceptions';
|
||||
|
||||
export function calculatePaths(fetch_cfg: FetchConfig[]) {
|
||||
@@ -10,14 +10,9 @@ export function calculatePaths(fetch_cfg: FetchConfig[]) {
|
||||
const to_folder = each_fetch_cfg.to_folder || '.';
|
||||
const to_file = each_fetch_cfg.to_file;
|
||||
const files = each_fetch_cfg.files;
|
||||
if (files !== undefined)
|
||||
{
|
||||
if (to_file !== undefined)
|
||||
{
|
||||
throw new UserError(
|
||||
ErrorCode.BAD_CONFIG,
|
||||
`Cannot use 'to_file' and 'files' parameters together!`
|
||||
);
|
||||
if (files !== undefined) {
|
||||
if (to_file !== undefined) {
|
||||
throw new UserError(ErrorCode.BAD_CONFIG, `Cannot use 'to_file' and 'files' parameters together!`);
|
||||
}
|
||||
for (const each_f of files) {
|
||||
const each_fetch_path = joinPaths([from, each_f]);
|
||||
@@ -31,10 +26,9 @@ export function calculatePaths(fetch_cfg: FetchConfig[]) {
|
||||
if (filename === '') {
|
||||
throw new UserError(
|
||||
ErrorCode.BAD_CONFIG,
|
||||
`Couldn't determine the filename from the path ${from}, please supply 'to_file' parameter.`
|
||||
`Couldn't determine the filename from the path ${from}, please supply 'to_file' parameter.`,
|
||||
);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
paths.push(joinPaths([to_folder, filename]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Plugin } from "../plugin";
|
||||
import { TargetedStdio, StdioMultiplexer } from "../stdio";
|
||||
import { make_PyScript } from "../components/pyscript";
|
||||
import { InterpreterClient } from "../interpreter_client";
|
||||
import { Plugin } from '../plugin';
|
||||
import { TargetedStdio, StdioMultiplexer } from '../stdio';
|
||||
import { make_PyScript } from '../components/pyscript';
|
||||
import { InterpreterClient } from '../interpreter_client';
|
||||
|
||||
type PyScriptTag = InstanceType<ReturnType<typeof make_PyScript>>;
|
||||
type PyScriptTag = InstanceType<ReturnType<typeof make_PyScript>>;
|
||||
|
||||
/**
|
||||
* The StdioDirector plugin captures the output to Python's sys.stdio and
|
||||
@@ -17,8 +17,8 @@ export class StdioDirector extends Plugin {
|
||||
_stdioMultiplexer: StdioMultiplexer;
|
||||
|
||||
constructor(stdio: StdioMultiplexer) {
|
||||
super()
|
||||
this._stdioMultiplexer = stdio
|
||||
super();
|
||||
this._stdioMultiplexer = stdio;
|
||||
}
|
||||
|
||||
/** Prior to a <py-script> tag being evaluated, if that tag itself has
|
||||
@@ -27,30 +27,35 @@ export class StdioDirector extends Plugin {
|
||||
* with that ID for the duration of the evaluation.
|
||||
*
|
||||
*/
|
||||
beforePyScriptExec(options: {interpreter: InterpreterClient, src: string, pyScriptTag: PyScriptTag}): void {
|
||||
if (options.pyScriptTag.hasAttribute("output")){
|
||||
const targeted_io = new TargetedStdio(options.pyScriptTag, "output", true, true)
|
||||
options.pyScriptTag.stdout_manager = targeted_io
|
||||
this._stdioMultiplexer.addListener(targeted_io)
|
||||
beforePyScriptExec(options: { interpreter: InterpreterClient; src: string; pyScriptTag: PyScriptTag }): void {
|
||||
if (options.pyScriptTag.hasAttribute('output')) {
|
||||
const targeted_io = new TargetedStdio(options.pyScriptTag, 'output', true, true);
|
||||
options.pyScriptTag.stdout_manager = targeted_io;
|
||||
this._stdioMultiplexer.addListener(targeted_io);
|
||||
}
|
||||
if (options.pyScriptTag.hasAttribute("stderr")){
|
||||
const targeted_io = new TargetedStdio(options.pyScriptTag, "stderr", false, true)
|
||||
options.pyScriptTag.stderr_manager = targeted_io
|
||||
this._stdioMultiplexer.addListener(targeted_io)
|
||||
if (options.pyScriptTag.hasAttribute('stderr')) {
|
||||
const targeted_io = new TargetedStdio(options.pyScriptTag, 'stderr', false, true);
|
||||
options.pyScriptTag.stderr_manager = targeted_io;
|
||||
this._stdioMultiplexer.addListener(targeted_io);
|
||||
}
|
||||
}
|
||||
|
||||
/** After a <py-script> tag is evaluated, if that tag has a 'stdout_manager'
|
||||
* (presumably TargetedStdio, or some other future IO handler), it is removed.
|
||||
*/
|
||||
afterPyScriptExec(options: {interpreter: InterpreterClient, src: string, pyScriptTag: PyScriptTag, result: any}): void {
|
||||
if (options.pyScriptTag.stdout_manager != null){
|
||||
this._stdioMultiplexer.removeListener(options.pyScriptTag.stdout_manager)
|
||||
options.pyScriptTag.stdout_manager = null
|
||||
afterPyScriptExec(options: {
|
||||
interpreter: InterpreterClient;
|
||||
src: string;
|
||||
pyScriptTag: PyScriptTag;
|
||||
result: any;
|
||||
}): void {
|
||||
if (options.pyScriptTag.stdout_manager != null) {
|
||||
this._stdioMultiplexer.removeListener(options.pyScriptTag.stdout_manager);
|
||||
options.pyScriptTag.stdout_manager = null;
|
||||
}
|
||||
if (options.pyScriptTag.stderr_manager != null){
|
||||
this._stdioMultiplexer.removeListener(options.pyScriptTag.stderr_manager)
|
||||
options.pyScriptTag.stderr_manager = null
|
||||
if (options.pyScriptTag.stderr_manager != null) {
|
||||
this._stdioMultiplexer.removeListener(options.pyScriptTag.stderr_manager);
|
||||
options.pyScriptTag.stderr_manager = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,14 +22,14 @@ export async function pyExec(interpreter: InterpreterClient, pysrc: string, outE
|
||||
'\nSee https://docs.pyscript.net/latest/guides/asyncio.html for more information.',
|
||||
);
|
||||
}
|
||||
return (await interpreter.run(pysrc));
|
||||
return await interpreter.run(pysrc);
|
||||
} catch (err) {
|
||||
// XXX: currently we display exceptions in the same position as
|
||||
// the output. But we probably need a better way to do that,
|
||||
// e.g. allowing plugins to intercept exceptions and display them
|
||||
// in a configurable way.
|
||||
displayPyException(err, outElem);
|
||||
return {result: undefined};
|
||||
return { result: undefined };
|
||||
}
|
||||
} finally {
|
||||
pyscript_py.set_current_display_target(undefined);
|
||||
|
||||
@@ -37,9 +37,7 @@ export class RemoteInterpreter extends Object {
|
||||
// TODO: Remove this once `runtimes` is removed!
|
||||
interpreter: InterpreterInterface;
|
||||
|
||||
constructor(
|
||||
src = 'https://cdn.jsdelivr.net/pyodide/v0.22.1/full/pyodide.js'
|
||||
) {
|
||||
constructor(src = 'https://cdn.jsdelivr.net/pyodide/v0.22.1/full/pyodide.js') {
|
||||
super();
|
||||
this.src = src;
|
||||
}
|
||||
@@ -87,11 +85,11 @@ export class RemoteInterpreter extends Object {
|
||||
await this.loadPackage('micropip');
|
||||
}
|
||||
logger.info('pyodide loaded and initialized');
|
||||
await this.run('print("Python initialization complete")')
|
||||
await this.run('print("Python initialization complete")');
|
||||
}
|
||||
|
||||
/* eslint-disable */
|
||||
async run(code: string): Promise<{result: any}> {
|
||||
async run(code: string): Promise<{ result: any }> {
|
||||
/**
|
||||
* eslint wants `await` keyword to be used i.e.
|
||||
* { result: await this.interface.runPython(code) }
|
||||
@@ -134,10 +132,12 @@ export class RemoteInterpreter extends Object {
|
||||
// for which the signature of `loadPackage` accepts the above params as args i.e.
|
||||
// the call uses `logger.info.bind(logger), logger.info.bind(logger)`.
|
||||
const pyodide_version = (await this.run("import sys; sys.modules['pyodide'].__version__")).result.toString();
|
||||
if (pyodide_version.startsWith("0.22")) {
|
||||
await this.interface.loadPackage(names, { messageCallback: logger.info.bind(logger), errorCallback: logger.info.bind(logger) });
|
||||
}
|
||||
else {
|
||||
if (pyodide_version.startsWith('0.22')) {
|
||||
await this.interface.loadPackage(names, {
|
||||
messageCallback: logger.info.bind(logger),
|
||||
errorCallback: logger.info.bind(logger),
|
||||
});
|
||||
} else {
|
||||
await this.interface.loadPackage(names, logger.info.bind(logger), logger.info.bind(logger));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createSingularWarning, escape } from "./utils";
|
||||
import { createSingularWarning, escape } from './utils';
|
||||
|
||||
export interface Stdio {
|
||||
stdout_writeline: (msg: string) => void;
|
||||
@@ -42,8 +42,7 @@ export class CaptureStdio implements Stdio {
|
||||
* specified by ID. Used with "output" keyword.
|
||||
*
|
||||
*/
|
||||
export class TargetedStdio implements Stdio{
|
||||
|
||||
export class TargetedStdio implements Stdio {
|
||||
source_element: HTMLElement;
|
||||
source_attribute: string;
|
||||
capture_stdout: boolean;
|
||||
@@ -66,31 +65,32 @@ export class TargetedStdio implements Stdio{
|
||||
*
|
||||
* @param msg The output to be written
|
||||
*/
|
||||
writeline_by_attribute(msg:string){
|
||||
const target_id = this.source_element.getAttribute(this.source_attribute)
|
||||
const target = document.getElementById(target_id)
|
||||
if (target === null) { // No matching ID
|
||||
createSingularWarning(`${this.source_attribute} = "${target_id}" does not match the id of any element on the page.`)
|
||||
writeline_by_attribute(msg: string) {
|
||||
const target_id = this.source_element.getAttribute(this.source_attribute);
|
||||
const target = document.getElementById(target_id);
|
||||
if (target === null) {
|
||||
// No matching ID
|
||||
createSingularWarning(
|
||||
`${this.source_attribute} = "${target_id}" does not match the id of any element on the page.`,
|
||||
);
|
||||
} else {
|
||||
msg = escape(msg).replace('\n', '<br>');
|
||||
if (!msg.endsWith('<br/>') && !msg.endsWith('<br>')) {
|
||||
msg = msg + '<br>';
|
||||
}
|
||||
else {
|
||||
msg = escape(msg).replace("\n", "<br>")
|
||||
if (!msg.endsWith("<br/>") && !msg.endsWith("<br>")){
|
||||
msg = msg + "<br>"
|
||||
}
|
||||
target.innerHTML += msg
|
||||
}
|
||||
}
|
||||
|
||||
stdout_writeline (msg: string) {
|
||||
if (this.capture_stdout){
|
||||
this.writeline_by_attribute(msg)
|
||||
target.innerHTML += msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
stderr_writeline (msg: string) {
|
||||
if (this.capture_stderr){
|
||||
this.writeline_by_attribute(msg)
|
||||
stdout_writeline(msg: string) {
|
||||
if (this.capture_stdout) {
|
||||
this.writeline_by_attribute(msg);
|
||||
}
|
||||
}
|
||||
|
||||
stderr_writeline(msg: string) {
|
||||
if (this.capture_stderr) {
|
||||
this.writeline_by_attribute(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,9 +109,9 @@ export class StdioMultiplexer implements Stdio {
|
||||
}
|
||||
|
||||
removeListener(obj: Stdio) {
|
||||
const index = this._listeners.indexOf(obj)
|
||||
if (index > -1){
|
||||
this._listeners.splice(index, 1)
|
||||
const index = this._listeners.indexOf(obj);
|
||||
if (index > -1) {
|
||||
this._listeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +1,35 @@
|
||||
/* py-config - not a component */
|
||||
py-config {
|
||||
display: none
|
||||
display: none;
|
||||
}
|
||||
/* py-{el} - components not defined */
|
||||
py-script:not(:defined) {
|
||||
display: none
|
||||
display: none;
|
||||
}
|
||||
|
||||
py-repl:not(:defined) {
|
||||
display: none
|
||||
display: none;
|
||||
}
|
||||
|
||||
py-title:not(:defined) {
|
||||
display: none
|
||||
display: none;
|
||||
}
|
||||
|
||||
py-inputbox:not(:defined) {
|
||||
display: none
|
||||
display: none;
|
||||
}
|
||||
|
||||
py-button:not(:defined) {
|
||||
display: none
|
||||
display: none;
|
||||
}
|
||||
|
||||
py-box:not(:defined) {
|
||||
display: none
|
||||
display: none;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
|
||||
Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@@ -110,7 +111,7 @@ html {
|
||||
/* Pop-up second layer end */
|
||||
.alert-banner {
|
||||
position: relative;
|
||||
padding: .5rem 1.5rem .5rem .5rem;
|
||||
padding: 0.5rem 1.5rem 0.5rem 0.5rem;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
@@ -118,8 +119,8 @@ html {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.py-error{
|
||||
background-color: #FFE9E8;
|
||||
.py-error {
|
||||
background-color: #ffe9e8;
|
||||
border: solid;
|
||||
border-color: #f0625f;
|
||||
color: #9d041c;
|
||||
@@ -132,24 +133,24 @@ html {
|
||||
color: #794700;
|
||||
}
|
||||
|
||||
.alert-banner.py-error>#alert-close-button {
|
||||
.alert-banner.py-error > #alert-close-button {
|
||||
color: #9d041c;
|
||||
}
|
||||
|
||||
.alert-banner.py-warning>#alert-close-button {
|
||||
color: #794700
|
||||
.alert-banner.py-warning > #alert-close-button {
|
||||
color: #794700;
|
||||
}
|
||||
|
||||
#alert-close-button {
|
||||
position: absolute;
|
||||
right: .5rem;
|
||||
top: .5rem;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: none;
|
||||
position: absolute;
|
||||
right: 0.5rem;
|
||||
top: 0.5rem;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.py-box{
|
||||
.py-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
@@ -168,10 +169,7 @@ border: none;
|
||||
border-color: rgba(209, 213, 219, var(--tw-border-opacity));
|
||||
border-width: 1px;
|
||||
position: relative;
|
||||
--tw-ring-inset: var(--tw-empty,
|
||||
/*!*/
|
||||
/*!*/
|
||||
);
|
||||
--tw-ring-inset: var(--tw-empty, /*!*/ /*!*/);
|
||||
--tw-ring-offset-width: 0px;
|
||||
--tw-ring-offset-color: #fff;
|
||||
--tw-ring-color: rgba(59, 130, 246, 0.5);
|
||||
@@ -183,7 +181,7 @@ border: none;
|
||||
box-sizing: border-box;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: rgb(209, 213, 219)
|
||||
border-color: rgb(209, 213, 219);
|
||||
}
|
||||
|
||||
.editor-box:hover button {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { _createAlertBanner } from "./exceptions"
|
||||
import { _createAlertBanner } from './exceptions';
|
||||
|
||||
export function addClasses(element: HTMLElement, classes: string[]) {
|
||||
for (const entry of classes) {
|
||||
@@ -127,11 +127,11 @@ export function createLock() {
|
||||
* @private
|
||||
*/
|
||||
async function acquireLock() {
|
||||
const old_lock = _lock;
|
||||
let releaseLock: () => void;
|
||||
_lock = new Promise((resolve) => (releaseLock = resolve));
|
||||
await old_lock;
|
||||
return releaseLock;
|
||||
const old_lock = _lock;
|
||||
let releaseLock: () => void;
|
||||
_lock = new Promise(resolve => (releaseLock = resolve));
|
||||
await old_lock;
|
||||
return releaseLock;
|
||||
}
|
||||
return acquireLock;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,127 +1,123 @@
|
||||
import { expect, it, jest, describe, afterEach } from "@jest/globals"
|
||||
import { _createAlertBanner, UserError, FetchError, ErrorCode } from "../../src/exceptions"
|
||||
import { expect, it, jest, describe, afterEach } from '@jest/globals';
|
||||
import { _createAlertBanner, UserError, FetchError, ErrorCode } from '../../src/exceptions';
|
||||
|
||||
describe("Test _createAlertBanner", () => {
|
||||
afterEach(() => {
|
||||
// Ensure we always have a clean body
|
||||
document.body.innerHTML = `<div>Hello World</div>`;
|
||||
})
|
||||
describe('Test _createAlertBanner', () => {
|
||||
afterEach(() => {
|
||||
// Ensure we always have a clean body
|
||||
document.body.innerHTML = `<div>Hello World</div>`;
|
||||
});
|
||||
|
||||
it("error level shouldn't contain close button", async () => {
|
||||
_createAlertBanner('Something went wrong!', 'error');
|
||||
|
||||
it("error level shouldn't contain close button", async () => {
|
||||
_createAlertBanner("Something went wrong!", "error");
|
||||
const banner = document.getElementsByClassName('alert-banner');
|
||||
const closeButton = document.getElementById('alert-close-button');
|
||||
expect(banner.length).toBe(1);
|
||||
expect(banner[0].innerHTML).toBe('Something went wrong!');
|
||||
expect(closeButton).toBeNull();
|
||||
});
|
||||
|
||||
const banner = document.getElementsByClassName("alert-banner");
|
||||
const closeButton = document.getElementById("alert-close-button");
|
||||
expect(banner.length).toBe(1);
|
||||
expect(banner[0].innerHTML).toBe("Something went wrong!");
|
||||
expect(closeButton).toBeNull();
|
||||
})
|
||||
it('warning level should contain close button', async () => {
|
||||
_createAlertBanner('This is a warning', 'warning');
|
||||
|
||||
it("warning level should contain close button", async () => {
|
||||
_createAlertBanner("This is a warning", "warning");
|
||||
const banner = document.getElementsByClassName('alert-banner');
|
||||
const closeButton = document.getElementById('alert-close-button');
|
||||
expect(banner.length).toBe(1);
|
||||
expect(banner[0].innerHTML).toContain('This is a warning');
|
||||
expect(closeButton).not.toBeNull();
|
||||
});
|
||||
|
||||
const banner = document.getElementsByClassName("alert-banner");
|
||||
const closeButton = document.getElementById("alert-close-button");
|
||||
expect(banner.length).toBe(1);
|
||||
expect(banner[0].innerHTML).toContain("This is a warning");
|
||||
expect(closeButton).not.toBeNull();
|
||||
})
|
||||
it('error level banner should log to console', async () => {
|
||||
const logSpy = jest.spyOn(console, 'error');
|
||||
|
||||
it("error level banner should log to console", async () => {
|
||||
const logSpy = jest.spyOn(console, "error");
|
||||
_createAlertBanner('Something went wrong!');
|
||||
|
||||
_createAlertBanner("Something went wrong!");
|
||||
expect(logSpy).toHaveBeenCalledWith('Something went wrong!');
|
||||
});
|
||||
|
||||
expect(logSpy).toHaveBeenCalledWith("Something went wrong!");
|
||||
it('warning level banner should log to console', async () => {
|
||||
const logSpy = jest.spyOn(console, 'warn');
|
||||
|
||||
})
|
||||
_createAlertBanner('This warning', 'warning');
|
||||
|
||||
it("warning level banner should log to console", async () => {
|
||||
const logSpy = jest.spyOn(console, "warn");
|
||||
expect(logSpy).toHaveBeenCalledWith('This warning');
|
||||
});
|
||||
|
||||
_createAlertBanner("This warning", "warning");
|
||||
it('close button should remove element from page', async () => {
|
||||
let banner = document.getElementsByClassName('alert-banner');
|
||||
expect(banner.length).toBe(0);
|
||||
|
||||
expect(logSpy).toHaveBeenCalledWith("This warning");
|
||||
})
|
||||
_createAlertBanner('Warning!', 'warning');
|
||||
|
||||
it("close button should remove element from page", async () => {
|
||||
let banner = document.getElementsByClassName("alert-banner");
|
||||
expect(banner.length).toBe(0);
|
||||
// Just a sanity check
|
||||
banner = document.getElementsByClassName('alert-banner');
|
||||
expect(banner.length).toBe(1);
|
||||
|
||||
_createAlertBanner("Warning!", "warning");
|
||||
const closeButton = document.getElementById('alert-close-button');
|
||||
if (closeButton) {
|
||||
closeButton.click();
|
||||
// Confirm that clicking the close button, removes the element
|
||||
banner = document.getElementsByClassName('alert-banner');
|
||||
expect(banner.length).toBe(0);
|
||||
} else {
|
||||
fail('Unable to find close button on the page, but should exist');
|
||||
}
|
||||
});
|
||||
|
||||
// Just a sanity check
|
||||
banner = document.getElementsByClassName("alert-banner");
|
||||
expect(banner.length).toBe(1);
|
||||
it("toggling logging off on error alert shouldn't log to console", async () => {
|
||||
const errorLogSpy = jest.spyOn(console, 'error');
|
||||
|
||||
const closeButton = document.getElementById("alert-close-button");
|
||||
if(closeButton) {
|
||||
closeButton.click();
|
||||
// Confirm that clicking the close button, removes the element
|
||||
banner = document.getElementsByClassName("alert-banner");
|
||||
expect(banner.length).toBe(0);
|
||||
} else {
|
||||
fail("Unable to find close button on the page, but should exist");
|
||||
}
|
||||
_createAlertBanner('Test error', 'error', 'text', false);
|
||||
expect(errorLogSpy).not.toHaveBeenCalledWith('Test error');
|
||||
});
|
||||
|
||||
})
|
||||
it("toggling logging off on warning alert shouldn't log to console", async () => {
|
||||
const warnLogSpy = jest.spyOn(console, 'warn');
|
||||
_createAlertBanner('Test warning', 'warning', 'text', false);
|
||||
expect(warnLogSpy).not.toHaveBeenCalledWith('Test warning');
|
||||
});
|
||||
|
||||
it("toggling logging off on error alert shouldn't log to console", async () => {
|
||||
const errorLogSpy = jest.spyOn(console, "error");
|
||||
it('_createAlertbanner messageType text writes message to content', async () => {
|
||||
let banner = document.getElementsByClassName('alert-banner');
|
||||
expect(banner.length).toBe(0);
|
||||
|
||||
_createAlertBanner("Test error", "error", "text", false);
|
||||
expect(errorLogSpy).not.toHaveBeenCalledWith("Test error");
|
||||
})
|
||||
const message = '<p>Test message</p>';
|
||||
_createAlertBanner(message, 'error', 'text');
|
||||
banner = document.getElementsByClassName('alert-banner');
|
||||
|
||||
it("toggling logging off on warning alert shouldn't log to console", async () => {
|
||||
const warnLogSpy = jest.spyOn(console, "warn");
|
||||
_createAlertBanner("Test warning", "warning", "text", false);
|
||||
expect(warnLogSpy).not.toHaveBeenCalledWith("Test warning");
|
||||
})
|
||||
expect(banner.length).toBe(1);
|
||||
expect(banner[0].innerHTML).toBe('<p>Test message</p>');
|
||||
expect(banner[0].textContent).toBe(message);
|
||||
});
|
||||
|
||||
it('_createAlertbanner messageType html writes message to innerHTML', async () => {
|
||||
let banner = document.getElementsByClassName('alert-banner');
|
||||
expect(banner.length).toBe(0);
|
||||
|
||||
it('_createAlertbanner messageType text writes message to content', async () => {
|
||||
let banner = document.getElementsByClassName("alert-banner");
|
||||
expect(banner.length).toBe(0);
|
||||
const message = '<p>Test message</p>';
|
||||
_createAlertBanner(message, 'error', 'html');
|
||||
banner = document.getElementsByClassName('alert-banner');
|
||||
|
||||
const message = '<p>Test message</p>'
|
||||
_createAlertBanner(message, 'error', 'text');
|
||||
banner = document.getElementsByClassName("alert-banner");
|
||||
expect(banner.length).toBe(1);
|
||||
expect(banner[0].innerHTML).toBe(message);
|
||||
expect(banner[0].textContent).toBe('Test message');
|
||||
});
|
||||
});
|
||||
|
||||
expect(banner.length).toBe(1);
|
||||
expect(banner[0].innerHTML).toBe("<p>Test message</p>");
|
||||
expect(banner[0].textContent).toBe(message);
|
||||
})
|
||||
describe('Test Exceptions', () => {
|
||||
it('UserError contains errorCode and shows in message', async () => {
|
||||
const errorCode = ErrorCode.BAD_CONFIG;
|
||||
const message = 'Test error';
|
||||
const userError = new UserError(ErrorCode.BAD_CONFIG, message);
|
||||
expect(userError.errorCode).toBe(errorCode);
|
||||
expect(userError.message).toBe(`(${errorCode}): ${message}`);
|
||||
});
|
||||
|
||||
it('_createAlertbanner messageType html writes message to innerHTML', async () => {
|
||||
let banner = document.getElementsByClassName("alert-banner");
|
||||
expect(banner.length).toBe(0);
|
||||
|
||||
const message = '<p>Test message</p>';
|
||||
_createAlertBanner(message, 'error', 'html');
|
||||
banner = document.getElementsByClassName("alert-banner");
|
||||
|
||||
expect(banner.length).toBe(1);
|
||||
expect(banner[0].innerHTML).toBe(message);
|
||||
expect(banner[0].textContent).toBe("Test message");
|
||||
})
|
||||
})
|
||||
|
||||
describe("Test Exceptions", () => {
|
||||
it('UserError contains errorCode and shows in message', async() => {
|
||||
const errorCode = ErrorCode.BAD_CONFIG;
|
||||
const message = 'Test error';
|
||||
const userError = new UserError(ErrorCode.BAD_CONFIG, message);
|
||||
expect(userError.errorCode).toBe(errorCode);
|
||||
expect(userError.message).toBe(`(${errorCode}): ${message}`);
|
||||
})
|
||||
|
||||
it('FetchError contains errorCode and shows in message', async() => {
|
||||
const errorCode = ErrorCode.FETCH_NOT_FOUND_ERROR;
|
||||
const message = 'Test error';
|
||||
const fetchError = new FetchError(errorCode, message);
|
||||
expect(fetchError.errorCode).toBe(errorCode);
|
||||
expect(fetchError.message).toBe(`(${errorCode}): ${message}`);
|
||||
})
|
||||
})
|
||||
it('FetchError contains errorCode and shows in message', async () => {
|
||||
const errorCode = ErrorCode.FETCH_NOT_FOUND_ERROR;
|
||||
const message = 'Test error';
|
||||
const fetchError = new FetchError(errorCode, message);
|
||||
expect(fetchError.errorCode).toBe(errorCode);
|
||||
expect(fetchError.message).toBe(`(${errorCode}): ${message}`);
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user