mirror of
https://github.com/pyscript/pyscript.git
synced 2025-12-20 10:47:35 -05:00
Compare commits
243 Commits
2022.12.1
...
fpliger/ne
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db66bb71e8 | ||
|
|
fc89d157ce | ||
|
|
4658b6d9a1 | ||
|
|
8cb5294f2a | ||
|
|
f226506856 | ||
|
|
c739e23cc5 | ||
|
|
5f93eb24bb | ||
|
|
da5569871e | ||
|
|
e33095249c | ||
|
|
efcd872ece | ||
|
|
829e4f89f1 | ||
|
|
0e710461fe | ||
|
|
bed56df606 | ||
|
|
78aa257a21 | ||
|
|
a43dab9850 | ||
|
|
e63ce9b685 | ||
|
|
93e4e485ff | ||
|
|
df7be28c18 | ||
|
|
da3b43abdd | ||
|
|
4cc9647dc6 | ||
|
|
74cd7c840a | ||
|
|
0f2deeb71a | ||
|
|
93539c9b5a | ||
|
|
e48e6276e1 | ||
|
|
75a57a49f5 | ||
|
|
8a1db288fc | ||
|
|
84dcde188b | ||
|
|
27c91e9703 | ||
|
|
b5a0cd4057 | ||
|
|
77d8fe3562 | ||
|
|
a484aff457 | ||
|
|
c96f5912df | ||
|
|
8a01a56e51 | ||
|
|
2774e49ab9 | ||
|
|
26e7a54f1f | ||
|
|
f0e69cbc36 | ||
|
|
413428f535 | ||
|
|
0c54036466 | ||
|
|
2555833831 | ||
|
|
7e0aceced1 | ||
|
|
77234f6df3 | ||
|
|
45af96aad4 | ||
|
|
184d29055e | ||
|
|
9e73181816 | ||
|
|
0b0e03456c | ||
|
|
c6b5ce7f55 | ||
|
|
a14e701be4 | ||
|
|
7813c3f03f | ||
|
|
3a3cb7b11d | ||
|
|
d7b0731385 | ||
|
|
df8973736f | ||
|
|
9121071ba3 | ||
|
|
bf6470c046 | ||
|
|
3b7099cd3d | ||
|
|
f6dfc5361e | ||
|
|
0a7e1ce0d7 | ||
|
|
d6b1c393f6 | ||
|
|
bccd5e3750 | ||
|
|
6df5905b2b | ||
|
|
6284c02032 | ||
|
|
db27d52352 | ||
|
|
8ba28989fb | ||
|
|
da544929ac | ||
|
|
bb364b0524 | ||
|
|
818614b798 | ||
|
|
50b1a1d7c5 | ||
|
|
7d3b792a79 | ||
|
|
af72e232c3 | ||
|
|
0cdbfbeb30 | ||
|
|
339e40063a | ||
|
|
4467898473 | ||
|
|
17d16b987f | ||
|
|
8e86daac71 | ||
|
|
856720da49 | ||
|
|
8f2c150d1e | ||
|
|
7d8b4c980a | ||
|
|
932756c7a0 | ||
|
|
538aac9a28 | ||
|
|
856bf8f5fb | ||
|
|
e1758ae2e2 | ||
|
|
61b3154461 | ||
|
|
fb9b30d144 | ||
|
|
b0df96b13f | ||
|
|
a469062a32 | ||
|
|
89d5d5c7db | ||
|
|
b8c2d6b05d | ||
|
|
b247864414 | ||
|
|
d3bcd87cfa | ||
|
|
82e5b64bad | ||
|
|
73e0271c23 | ||
|
|
a2dabee0e9 | ||
|
|
6a27c6d9f2 | ||
|
|
213ced0c7f | ||
|
|
5086c23d47 | ||
|
|
ee345a5206 | ||
|
|
f74cddc3b1 | ||
|
|
5b986b8b26 | ||
|
|
14887b9814 | ||
|
|
ecc40315b3 | ||
|
|
e7aed7fcf0 | ||
|
|
cd1aa948f9 | ||
|
|
82613d016a | ||
|
|
3a66be585f | ||
|
|
0a4e36ae09 | ||
|
|
92643539cf | ||
|
|
a1281d1331 | ||
|
|
074ca0ef8f | ||
|
|
464a9633dc | ||
|
|
fc2d91c5bb | ||
|
|
d68169bffb | ||
|
|
7efdb04e1e | ||
|
|
0155e122fd | ||
|
|
eb03f16a77 | ||
|
|
5ac39641ab | ||
|
|
8d1e48e400 | ||
|
|
0021ccb49f | ||
|
|
8590c7e5b8 | ||
|
|
8c5475f78f | ||
|
|
dfa116eb70 | ||
|
|
3a9fd3c074 | ||
|
|
5a92ef3c11 | ||
|
|
d3902f5c93 | ||
|
|
c886f887ae | ||
|
|
fc5089ac59 | ||
|
|
e3602f464b | ||
|
|
f3db6a339c | ||
|
|
c05195c045 | ||
|
|
af981fc719 | ||
|
|
088a264910 | ||
|
|
d7e80ad51b | ||
|
|
b53ddd401f | ||
|
|
e9122bca9d | ||
|
|
b61e8435d1 | ||
|
|
146afb6532 | ||
|
|
854e9d1378 | ||
|
|
689878ce32 | ||
|
|
d7ab177cc5 | ||
|
|
f4c6093c47 | ||
|
|
9fedfe3699 | ||
|
|
26f07246e1 | ||
|
|
3ae4b3c4de | ||
|
|
c8f9f16791 | ||
|
|
88f0738500 | ||
|
|
03c79d5f2f | ||
|
|
e7c3b7bcfe | ||
|
|
c8becca044 | ||
|
|
543a27271f | ||
|
|
a62aba83a0 | ||
|
|
53c6cf5f45 | ||
|
|
89842e20da | ||
|
|
ef793aecf3 | ||
|
|
51d51409d3 | ||
|
|
371b5eac45 | ||
|
|
5319bd13d5 | ||
|
|
e10d055453 | ||
|
|
716254e655 | ||
|
|
4c00b1683f | ||
|
|
37c9db09c6 | ||
|
|
653e2c9be4 | ||
|
|
a2a9613da1 | ||
|
|
e8d92d0d34 | ||
|
|
755b98a8c0 | ||
|
|
13e9252260 | ||
|
|
6a9c27325a | ||
|
|
a1cb78eb85 | ||
|
|
716b57ebd3 | ||
|
|
8e231313b8 | ||
|
|
84e4e361c5 | ||
|
|
41a8d804e3 | ||
|
|
03e798a079 | ||
|
|
34a0205757 | ||
|
|
ba145f04ea | ||
|
|
22fd023635 | ||
|
|
08f34f748b | ||
|
|
7ffe6a598e | ||
|
|
71d24a445e | ||
|
|
6bcbbfb085 | ||
|
|
04fe1348d8 | ||
|
|
3033c779b0 | ||
|
|
4483f0db0f | ||
|
|
727267ae22 | ||
|
|
b5d15c2f7e | ||
|
|
589c614e57 | ||
|
|
4588e90226 | ||
|
|
8665a14dec | ||
|
|
43d598d951 | ||
|
|
68018cf078 | ||
|
|
ef4ab0d7a8 | ||
|
|
e66a2702df | ||
|
|
c57d4a7054 | ||
|
|
a36f08f0f1 | ||
|
|
760a8c75a5 | ||
|
|
740fd921e1 | ||
|
|
065c697070 | ||
|
|
e2c2459290 | ||
|
|
11c79a5344 | ||
|
|
429fe4c356 | ||
|
|
a18b4edfc0 | ||
|
|
b14a2bba5f | ||
|
|
1f825edc28 | ||
|
|
6ed834807a | ||
|
|
9a908e5fd0 | ||
|
|
4c30359b71 | ||
|
|
34dfe2d80b | ||
|
|
25bcff10b7 | ||
|
|
81268d0545 | ||
|
|
8f0a7706d7 | ||
|
|
46150f9b80 | ||
|
|
247745b7e7 | ||
|
|
94cc09b610 | ||
|
|
a210b2d5f5 | ||
|
|
12bf6db331 | ||
|
|
697ac9de9a | ||
|
|
4124bb5edc | ||
|
|
d55340a817 | ||
|
|
0de8cd9ab7 | ||
|
|
4e8281c749 | ||
|
|
357fbc644d | ||
|
|
7947a8a2dc | ||
|
|
35de3aa154 | ||
|
|
1ea687beb8 | ||
|
|
bb5c59307a | ||
|
|
5a3c414c8f | ||
|
|
cc4b460183 | ||
|
|
470c3489dd | ||
|
|
e1b4415193 | ||
|
|
77d98a565e | ||
|
|
412da2de08 | ||
|
|
dbdcd0b3d0 | ||
|
|
5c67384fbf | ||
|
|
35b0f9d377 | ||
|
|
95783bc284 | ||
|
|
4b840f7cbd | ||
|
|
f73d6cd9f2 | ||
|
|
15bb8f03ea | ||
|
|
059dbc88c9 | ||
|
|
c0f36aa047 | ||
|
|
d4120d2af3 | ||
|
|
dd1c008447 | ||
|
|
3721d2cd72 | ||
|
|
e0dda0e547 | ||
|
|
3c7568c72c | ||
|
|
6be1758548 |
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
|
description: Create a report to help us improve
|
||||||
labels: ["type: bug", "needs-triage"]
|
labels: ["type: bug", "needs-triage"]
|
||||||
body:
|
body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thanks for helping PyScript! 🐍
|
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 💐!
|
Thanks for helping PyScript be amazing. We are nothing without people like you helping build a better community 💐!
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
id: checks
|
id: checks
|
||||||
attributes:
|
attributes:
|
||||||
label: Checklist
|
label: Checklist
|
||||||
description: Please confirm and check all the following options.
|
description: Please confirm and check all the following options.
|
||||||
options:
|
options:
|
||||||
- label: I added a descriptive title
|
- label: I added a descriptive title
|
||||||
required: true
|
required: true
|
||||||
- label: I searched for other issues and couldn't find a solution or duplication
|
- label: I searched for other issues and couldn't find a solution or duplication
|
||||||
required: true
|
required: true
|
||||||
- label: I already searched in Google and didn't find any good information or help
|
- label: I already searched in Google and didn't find any good information or help
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: what-happened
|
id: what-happened
|
||||||
attributes:
|
attributes:
|
||||||
label: What happened?
|
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
|
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!
|
placeholder: Tell us what you see!
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
id: browsers
|
id: browsers
|
||||||
attributes:
|
attributes:
|
||||||
label: What browsers are you seeing the problem on? (if applicable)
|
label: What browsers are you seeing the problem on? (if applicable)
|
||||||
multiple: true
|
multiple: true
|
||||||
options:
|
options:
|
||||||
- Firefox
|
- Firefox
|
||||||
- Chrome
|
- Chrome
|
||||||
- Safari
|
- Safari
|
||||||
- Microsoft Edge
|
- Microsoft Edge
|
||||||
- Other
|
- Other
|
||||||
validations:
|
validations:
|
||||||
required: false
|
required: false
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: list
|
id: list
|
||||||
attributes:
|
attributes:
|
||||||
label: Console info
|
label: Console info
|
||||||
description: |
|
description: |
|
||||||
If there are errors in your browser console then its helpful to be able to troubleshoot.
|
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.
|
- 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).
|
- Safari: Find instructions [here](https://support.apple.com/guide/safari/use-the-developer-tools-in-the-develop-menu-sfri20948/mac).
|
||||||
render: shell
|
render: shell
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: context
|
id: context
|
||||||
attributes:
|
attributes:
|
||||||
label: Additional Context
|
label: Additional Context
|
||||||
description: Add any additional context information or screenshots you think are useful.
|
description: Add any additional context information or screenshots you think are useful.
|
||||||
|
|||||||
7
.github/ISSUE_TEMPLATE/config.yml
vendored
7
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,5 +1,8 @@
|
|||||||
blank_issues_enabled: true
|
blank_issues_enabled: true
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Question
|
- name: Feature Proposals
|
||||||
url: https://community.anaconda.cloud/c/tech-topics/pyscript
|
url: https://github.com/pyscript/pyscript/discussions/new?category=proposals
|
||||||
|
about: Create a feature request to make PyScript even better
|
||||||
|
- name: Questions
|
||||||
|
url: https://github.com/pyscript/pyscript/discussions/new?category=q-a
|
||||||
about: For questions or discussions about pyscript
|
about: For questions or discussions about pyscript
|
||||||
|
|||||||
67
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
67
.github/ISSUE_TEMPLATE/feature-request.yml
vendored
@@ -1,67 +0,0 @@
|
|||||||
name: Feature Request
|
|
||||||
description: Create a feature request to make PyScript even better
|
|
||||||
labels: ["type: enhancement", "needs-triage"]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
### Thanks for helping PyScript! 🐍
|
|
||||||
|
|
||||||
Going through feature requests 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 great ideas than there is time to do them, and so we will need to selectively close issues that don't provide enough information, so everyone can focus our time on helping people like you who fill out the form completely. Thank you for your collaboration!
|
|
||||||
|
|
||||||
There are also already a lot of open requests, so please take 2 minutes and search through existing ones to see if your idea already exists. If you find something close, please upvote that request and comment.
|
|
||||||
|
|
||||||
Thanks for helping PyScript be amazing. We are nothing without people like you helping build a better community 💐!
|
|
||||||
|
|
||||||
### Lets make sure you are in the right place. If you have an idea/request for:
|
|
||||||
|
|
||||||
- #### A specific package/library (such as pandas or scikit learn):
|
|
||||||
|
|
||||||
Search for that respective library on github repo or website. You will have much more success there.
|
|
||||||
|
|
||||||
- #### A general Python question/feature request:
|
|
||||||
|
|
||||||
Try out a forum post [here](https://discuss.python.org/c/users/7)
|
|
||||||
|
|
||||||
- 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 feature requests and couldn't find a duplicate (including also the ``type-feature`` tag)
|
|
||||||
required: true
|
|
||||||
- label: I confirmed that it's not related to another project area (see the above section)
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: request-idea
|
|
||||||
attributes:
|
|
||||||
label: What is the idea?
|
|
||||||
description: Describe what the feature is and the desired state
|
|
||||||
placeholder: This feature would allow any user of PyScript to type in a simple command in the console and show all variables currently in use
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: why
|
|
||||||
attributes:
|
|
||||||
label: Why is this needed
|
|
||||||
description: |
|
|
||||||
Who would benefit from this and why would this add value to them? What problem does this solve?
|
|
||||||
placeholder: This would benefit users who would like to see what is being used so they can learn and debug faster
|
|
||||||
- type: textarea
|
|
||||||
id: what
|
|
||||||
attributes:
|
|
||||||
label: What should happen?
|
|
||||||
description: |
|
|
||||||
What should be the user experience with the feature? Describe from a user perpective what they would do and see
|
|
||||||
placeholder: A user would type in ``PyScript debug`` in the browser console and see a list of all variables created.
|
|
||||||
- type: textarea
|
|
||||||
id: context
|
|
||||||
attributes:
|
|
||||||
label: Additional Context
|
|
||||||
description: |
|
|
||||||
Is there any other information that you think would be valuable for the team to know?
|
|
||||||
37
.github/ISSUE_TEMPLATE/misc.yml
vendored
37
.github/ISSUE_TEMPLATE/misc.yml
vendored
@@ -1,37 +0,0 @@
|
|||||||
name: Miscellaneous
|
|
||||||
description: For issues that don't belong in other categories
|
|
||||||
labels: ["type: misc", "needs-triage"]
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
Thanks for helping PyScript! 🐍
|
|
||||||
|
|
||||||
This issue is for things that doesn't make sense to put into the other issue categories and we don't want it to get lost.
|
|
||||||
|
|
||||||
Going through 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 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
|
|
||||||
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 duplication
|
|
||||||
required: true
|
|
||||||
- label: I already searched in Google and didn't find any good information or help
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
id: what
|
|
||||||
attributes:
|
|
||||||
label: What is the issue/comment/problem?
|
|
||||||
description: This is a miscellaneous issue so this could be just about anything. We simply ask that you provide as many details as you can to help spur discussion or the outcome you want.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
15
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
## Description
|
||||||
|
|
||||||
|
<!--Please describe the changes in your pull request in few words here. -->
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
|
||||||
|
<!-- List the changes done to fix a bug or introduce a new feature.Please note both user-facing changes and changes to internal API's here -->
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
<!-- Note: Only user-facing changes require a changelog entry. Internal-only API changes do not require a changelog entry. Changes in documentation do not require a changelog entry. -->
|
||||||
|
|
||||||
|
- [ ] All tests pass locally
|
||||||
|
- [ ] I have updated `docs/changelog.md`
|
||||||
|
- [ ] I have created documentation for this(if applicable)
|
||||||
6
.github/release.yml
vendored
6
.github/release.yml
vendored
@@ -1,5 +1,5 @@
|
|||||||
changelog:
|
changelog:
|
||||||
categories:
|
categories:
|
||||||
- title: New Features
|
- title: New Features
|
||||||
- title: Breaking Changes
|
- title: Breaking Changes
|
||||||
- title: Known Issues
|
- title: Known Issues
|
||||||
|
|||||||
26
.github/stale.yaml
vendored
26
.github/stale.yaml
vendored
@@ -1,26 +0,0 @@
|
|||||||
# Number of days of inactivity before an issue becomes stale
|
|
||||||
daysUntilStale: 60
|
|
||||||
|
|
||||||
# Number of days of inactivity before a stale issue is closed
|
|
||||||
daysUntilClose: 7
|
|
||||||
|
|
||||||
# Issues with these labels will never be considered stale
|
|
||||||
exemptLabels:
|
|
||||||
- backlog
|
|
||||||
- needs-triage
|
|
||||||
- needs-work
|
|
||||||
- epic
|
|
||||||
|
|
||||||
# Label to use when marking an issue as stale
|
|
||||||
staleLabel: stale
|
|
||||||
|
|
||||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
|
||||||
markComment: >
|
|
||||||
This issue has been automatically marked as stale because it has not had
|
|
||||||
recent activity. It will be closed if no further activity occurs. Thank you
|
|
||||||
for your contributions.
|
|
||||||
|
|
||||||
# Comment to post when closing a stale issue. Set to `false` to disable
|
|
||||||
closeComment: >
|
|
||||||
This issue has been automatically closed because it has not had
|
|
||||||
recent activity. Thank you for your contributions.
|
|
||||||
157
.github/workflows/build-unstable.yml
vendored
157
.github/workflows/build-unstable.yml
vendored
@@ -1,21 +1,21 @@
|
|||||||
name: '[CI] Build Unstable'
|
name: "[CI] Build Unstable"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push: # Only run on merges into main that modify files under pyscriptjs/ and examples/
|
push: # Only run on merges into main that modify files under pyscriptjs/ and examples/
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- pyscriptjs/**
|
- pyscriptjs/**
|
||||||
- examples/**
|
- examples/**
|
||||||
- .github/workflows/build-latest.yml # Test that workflow works when changed
|
- .github/workflows/build-unstable.yml # Test that workflow works when changed
|
||||||
|
|
||||||
pull_request: # Run on any PR that modifies files under pyscriptjs/ and examples/
|
pull_request: # Run on any PR that modifies files under pyscriptjs/ and examples/
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- pyscriptjs/**
|
- pyscriptjs/**
|
||||||
- examples/**
|
- examples/**
|
||||||
- .github/workflows/build-unstable.yml # Test that workflow works when changed
|
- .github/workflows/build-unstable.yml # Test that workflow works when changed
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -28,53 +28,94 @@ jobs:
|
|||||||
MINICONDA_PYTHON_VERSION: py38
|
MINICONDA_PYTHON_VERSION: py38
|
||||||
MINICONDA_VERSION: 4.11.0
|
MINICONDA_VERSION: 4.11.0
|
||||||
steps:
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Checkout
|
- name: Install node
|
||||||
uses: actions/checkout@v3
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18.x
|
||||||
|
|
||||||
- name: Install node
|
- name: Cache node modules
|
||||||
uses: actions/setup-node@v3
|
uses: actions/cache@v3
|
||||||
with:
|
env:
|
||||||
node-version: 18.x
|
cache-name: cache-node-modules
|
||||||
|
with:
|
||||||
|
# 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: |
|
||||||
|
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||||
|
${{ runner.os }}-build-
|
||||||
|
${{ runner.os }}-
|
||||||
|
|
||||||
- name: Cache node modules
|
- name: setup Miniconda
|
||||||
uses: actions/cache@v3
|
uses: conda-incubator/setup-miniconda@v2
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
# 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: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
|
||||||
${{ runner.os }}-build-
|
|
||||||
${{ runner.os }}-
|
|
||||||
|
|
||||||
- name: setup Miniconda
|
- name: Setup Environment
|
||||||
uses: conda-incubator/setup-miniconda@v2
|
run: make setup
|
||||||
|
|
||||||
- name: Setup Environment
|
- name: Build
|
||||||
run: make setup
|
run: make build
|
||||||
|
|
||||||
- name: Build
|
- name: TypeScript Tests
|
||||||
run: make build
|
run: make test-ts
|
||||||
|
|
||||||
- name: TypeScript Tests
|
- name: Python Tests
|
||||||
run: make test-ts
|
run: make test-py
|
||||||
|
|
||||||
- name: Python Tests
|
- name: Integration Tests
|
||||||
run: make test-py
|
run: make test-integration-parallel
|
||||||
|
|
||||||
- name: Integration Tests
|
- name: Examples Tests
|
||||||
run: make test-integration-parallel
|
run: make test-examples
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: pyscript
|
name: pyscript
|
||||||
path: |
|
path: |
|
||||||
pyscriptjs/build/
|
pyscriptjs/build/
|
||||||
if-no-files-found: error
|
if-no-files-found: error
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: success() || failure()
|
||||||
|
with:
|
||||||
|
name: test_results
|
||||||
|
path: pyscriptjs/test_results
|
||||||
|
if-no-files-found: error
|
||||||
|
eslint:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: pyscriptjs
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18.x
|
||||||
|
|
||||||
|
- name: Cache node modules
|
||||||
|
uses: actions/cache@v3
|
||||||
|
env:
|
||||||
|
cache-name: cache-node-modules
|
||||||
|
with:
|
||||||
|
# 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: |
|
||||||
|
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||||
|
${{ runner.os }}-build-
|
||||||
|
${{ runner.os }}-
|
||||||
|
|
||||||
|
- name: npm install
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Eslint
|
||||||
|
run: npx eslint src -c .eslintrc.js
|
||||||
|
|
||||||
Deploy:
|
Deploy:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -85,17 +126,17 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: pyscript
|
name: pyscript
|
||||||
path: ./build/
|
path: ./build/
|
||||||
|
|
||||||
# Deploy to S3
|
# Deploy to S3
|
||||||
- name: Configure AWS credentials
|
- name: Configure AWS credentials
|
||||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||||
with:
|
with:
|
||||||
aws-region: ${{ secrets.AWS_REGION }}
|
aws-region: ${{ secrets.AWS_REGION }}
|
||||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||||
|
|
||||||
- name: Sync to S3
|
- name: Sync to S3
|
||||||
run: aws s3 sync --quiet ./build/ s3://pyscript.net/unstable/
|
run: aws s3 sync --quiet ./build/ s3://pyscript.net/unstable/
|
||||||
|
|||||||
84
.github/workflows/docs-release.yml
vendored
84
.github/workflows/docs-release.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: '[Docs] Build Release'
|
name: "[Docs] Build Release"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
@@ -13,54 +13,50 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
SPHINX_HTML_BASE_URL: https://docs.pyscript.net/
|
SPHINX_HTML_BASE_URL: https://docs.pyscript.net/
|
||||||
steps:
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
||||||
|
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
||||||
|
|
||||||
- name: Checkout
|
- name: Setup
|
||||||
uses: actions/checkout@v3
|
uses: conda-incubator/setup-miniconda@v2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
auto-update-conda: true
|
||||||
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
activate-environment: docs
|
||||||
|
environment-file: docs/environment.yml
|
||||||
|
python-version: "3.9"
|
||||||
|
|
||||||
- name: Setup
|
- name: Build
|
||||||
uses: conda-incubator/setup-miniconda@v2
|
shell: bash -l {0}
|
||||||
with:
|
run: |
|
||||||
auto-update-conda: true
|
cd docs/
|
||||||
activate-environment: docs
|
make html
|
||||||
environment-file: docs/environment.yml
|
|
||||||
python-version: '3.9'
|
|
||||||
|
|
||||||
- name: Build
|
- name: Upload artifacts
|
||||||
shell: bash -l {0}
|
uses: actions/upload-artifact@v3
|
||||||
run: |
|
with:
|
||||||
cd docs/
|
name: pyscript-docs-${{ github.ref_name }}
|
||||||
make html
|
path: docs/_build/html/
|
||||||
|
|
||||||
- name: Upload artifacts
|
# Deploy to S3
|
||||||
uses: actions/upload-artifact@v3
|
- name: Configure AWS credentials
|
||||||
with:
|
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||||
name: pyscript-docs-${{ github.ref_name }}
|
with:
|
||||||
path: docs/_build/html/
|
aws-region: ${{ secrets.AWS_REGION }}
|
||||||
|
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||||
|
|
||||||
# Deploy to S3
|
- name: Copy redirect file
|
||||||
- name: Configure AWS credentials
|
run: aws s3 cp --quiet ./docs/_build/html/_static/redirect.html s3://docs.pyscript.net/index.html
|
||||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
|
||||||
with:
|
|
||||||
aws-region: ${{ secrets.AWS_REGION }}
|
|
||||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
|
||||||
|
|
||||||
- name: Copy redirect file
|
- name: Sync to S3
|
||||||
run: aws s3 cp --quiet ./docs/_build/html/_static/redirect.html s3://docs.pyscript.net/index.html
|
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/${{ github.ref_name }}/
|
||||||
|
|
||||||
# - name: Delete release directory
|
# Make sure to remove the latest folder so we sync the full docs upon release
|
||||||
# run: aws s3 rm --recursive s3://docs.pyscript.net/${{ github.ref_name }}/
|
- name: Delete latest directory
|
||||||
|
run: aws s3 rm --recursive s3://docs.pyscript.net/latest/
|
||||||
|
|
||||||
- name: Sync to S3
|
# Note that the files are the same as above, but we want to have folders with
|
||||||
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/${{ github.ref_name }}/
|
# /<tag name>/ AND /latest/ which latest will always point to the latest release
|
||||||
|
- name: Sync to /latest
|
||||||
# Make sure to remove the latest folder so we sync the full docs upon release
|
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/latest/
|
||||||
- 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
|
|
||||||
- name: Sync to /latest
|
|
||||||
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/latest/
|
|
||||||
|
|||||||
81
.github/workflows/docs-review.yml
vendored
81
.github/workflows/docs-review.yml
vendored
@@ -1,18 +1,18 @@
|
|||||||
name: '[Docs] Build Review'
|
name: "[Docs] Build Review"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- '*'
|
- "*"
|
||||||
paths:
|
paths:
|
||||||
- docs/**
|
- docs/**
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
# Concurrency group that uses the workflow name and PR number if available
|
# Concurrency group that uses the workflow name and PR number if available
|
||||||
# or commit SHA as a fallback. If a new build is triggered under that
|
# or commit SHA as a fallback. If a new build is triggered under that
|
||||||
# concurrency group while a previous build is running it will be canceled.
|
# concurrency group while a previous build is running it will be canceled.
|
||||||
# Repeated pushes to a PR will cancel all previous builds, while multiple
|
# Repeated pushes to a PR will cancel all previous builds, while multiple
|
||||||
# merges to main will not cancel.
|
# merges to main will not cancel.
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
@@ -26,49 +26,28 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
SPHINX_HTML_BASE_URL: https://docs.pyscript.net/
|
SPHINX_HTML_BASE_URL: https://docs.pyscript.net/
|
||||||
steps:
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
||||||
|
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
||||||
|
|
||||||
- name: Checkout
|
- name: Setup
|
||||||
uses: actions/checkout@v3
|
uses: conda-incubator/setup-miniconda@v2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
auto-update-conda: true
|
||||||
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
activate-environment: docs
|
||||||
|
environment-file: docs/environment.yml
|
||||||
|
python-version: "3.9"
|
||||||
|
|
||||||
- name: Setup
|
- name: Build
|
||||||
uses: conda-incubator/setup-miniconda@v2
|
shell: bash -l {0}
|
||||||
with:
|
run: |
|
||||||
auto-update-conda: true
|
cd docs/
|
||||||
activate-environment: docs
|
make html
|
||||||
environment-file: docs/environment.yml
|
|
||||||
python-version: '3.9'
|
|
||||||
|
|
||||||
- name: Build
|
- name: Upload artifacts
|
||||||
shell: bash -l {0}
|
uses: actions/upload-artifact@v3
|
||||||
run: |
|
with:
|
||||||
cd docs/
|
name: pyscript-docs-review-${{ github.event.number }}
|
||||||
make html
|
path: docs/_build/html/
|
||||||
|
|
||||||
- name: Upload artifacts
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: pyscript-docs-review-${{ github.event.number }}
|
|
||||||
path: docs/_build/html/
|
|
||||||
|
|
||||||
# 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 }}
|
|
||||||
|
|
||||||
- name: Copy redirect file
|
|
||||||
run: aws s3 cp --quiet ./docs/_build/html/_static/redirect.html s3://docs.pyscript.net/index.html
|
|
||||||
|
|
||||||
- name: Sync to S3
|
|
||||||
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/review/${{ github.event.number }}/
|
|
||||||
|
|
||||||
- name: Adding step summary
|
|
||||||
run: |
|
|
||||||
echo "### Review documentation" >> $GITHUB_STEP_SUMMARY
|
|
||||||
echo "As with any pull request, you can find the rendered documentation version for pull request ${{ github.event.number }} here:"
|
|
||||||
echo "" >> $GITHUB_STEP_SUMMARY # this is a blank line
|
|
||||||
echo "https://docs.pyscript.net/review/${{ github.event.number }}/" >> $GITHUB_STEP_SUMMARY
|
|
||||||
|
|||||||
71
.github/workflows/docs-unstable.yml
vendored
71
.github/workflows/docs-unstable.yml
vendored
@@ -1,11 +1,11 @@
|
|||||||
name: '[Docs] Build Latest'
|
name: "[Docs] Build Latest"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
paths:
|
paths:
|
||||||
- docs/**
|
- docs/**
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -16,40 +16,43 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
SPHINX_HTML_BASE_URL: https://docs.pyscript.net/
|
SPHINX_HTML_BASE_URL: https://docs.pyscript.net/
|
||||||
steps:
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
||||||
|
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
||||||
|
|
||||||
- name: Checkout
|
- name: Setup
|
||||||
uses: actions/checkout@v3
|
uses: conda-incubator/setup-miniconda@v2
|
||||||
with:
|
with:
|
||||||
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal access token.
|
auto-update-conda: true
|
||||||
fetch-depth: 0 # otherwise, there would be errors pushing refs to the destination repository.
|
activate-environment: docs
|
||||||
|
environment-file: docs/environment.yml
|
||||||
|
python-version: "3.9"
|
||||||
|
|
||||||
- name: Setup
|
- name: Build
|
||||||
uses: conda-incubator/setup-miniconda@v2
|
shell: bash -l {0}
|
||||||
with:
|
run: |
|
||||||
auto-update-conda: true
|
cd docs/
|
||||||
activate-environment: docs
|
make html
|
||||||
environment-file: docs/environment.yml
|
|
||||||
python-version: '3.9'
|
|
||||||
|
|
||||||
- name: Build
|
- name: Upload artifacts
|
||||||
shell: bash -l {0}
|
uses: actions/upload-artifact@v3
|
||||||
run: |
|
with:
|
||||||
cd docs/
|
name: pyscript-docs-latest
|
||||||
make html
|
path: docs/_build/html/
|
||||||
|
|
||||||
- name: Upload artifacts
|
# Deploy to S3
|
||||||
uses: actions/upload-artifact@v3
|
- name: Configure AWS credentials
|
||||||
with:
|
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||||
name: pyscript-docs-latest
|
with:
|
||||||
path: docs/_build/html/
|
aws-region: ${{ secrets.AWS_REGION }}
|
||||||
|
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||||
|
|
||||||
# Deploy to S3
|
# Sync will only copy changed files
|
||||||
- name: Configure AWS credentials
|
- name: Sync Error
|
||||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
run: aws s3 cp --quiet ./docs/_static/s3_error.html s3://docs.pyscript.net/error.html
|
||||||
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
|
- name: Sync to S3
|
||||||
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/unstable/
|
run: aws s3 sync --quiet ./docs/_build/html/ s3://docs.pyscript.net/unstable/
|
||||||
|
|||||||
71
.github/workflows/prepare-release.yml
vendored
71
.github/workflows/prepare-release.yml
vendored
@@ -1,9 +1,9 @@
|
|||||||
name: '[CI] Prepare Release'
|
name: "[CI] Prepare Release"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags:
|
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:
|
env:
|
||||||
MINICONDA_PYTHON_VERSION: py38
|
MINICONDA_PYTHON_VERSION: py38
|
||||||
@@ -17,44 +17,43 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Checkout
|
- name: Install node
|
||||||
uses: actions/checkout@v3
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18.x
|
||||||
|
|
||||||
- name: Install node
|
- name: Cache node modules
|
||||||
uses: actions/setup-node@v3
|
uses: actions/cache@v3
|
||||||
with:
|
env:
|
||||||
node-version: 18.x
|
cache-name: cache-node-modules
|
||||||
|
with:
|
||||||
|
# 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: |
|
||||||
|
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||||
|
${{ runner.os }}-build-
|
||||||
|
${{ runner.os }}-
|
||||||
|
|
||||||
- name: Cache node modules
|
- name: setup Miniconda
|
||||||
uses: actions/cache@v3
|
uses: conda-incubator/setup-miniconda@v2
|
||||||
env:
|
|
||||||
cache-name: cache-node-modules
|
|
||||||
with:
|
|
||||||
# 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: |
|
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
|
||||||
${{ runner.os }}-build-
|
|
||||||
${{ runner.os }}-
|
|
||||||
|
|
||||||
- name: setup Miniconda
|
- name: Setup Environment
|
||||||
uses: conda-incubator/setup-miniconda@v2
|
run: make setup
|
||||||
|
|
||||||
- name: Setup Environment
|
- name: Build and Test
|
||||||
run: make setup
|
run: make test
|
||||||
|
|
||||||
- name: Build and Test
|
- name: Zip build folder
|
||||||
run: make test
|
run: zip -r -q ./build.zip ./build
|
||||||
|
|
||||||
- name: Zip build folder
|
- name: Prepare Release
|
||||||
run: zip -r -q ./build.zip ./build
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
- name: Prepare Release
|
draft: true
|
||||||
uses: softprops/action-gh-release@v1
|
prerelease: true
|
||||||
with:
|
generate_release_notes: true
|
||||||
draft: true
|
files: ./build.zip
|
||||||
prerelease: true
|
|
||||||
generate_release_notes: true
|
|
||||||
files: ./build.zip
|
|
||||||
|
|||||||
71
.github/workflows/publish-release.yml
vendored
71
.github/workflows/publish-release.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: '[CI] Publish Release'
|
name: "[CI] Publish Release"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
@@ -19,44 +19,45 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
id-token: write
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- name: Install node
|
- name: Install node
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18.x
|
node-version: 18.x
|
||||||
|
|
||||||
- name: Cache node modules
|
- name: Cache node modules
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v3
|
||||||
env:
|
env:
|
||||||
cache-name: cache-node-modules
|
cache-name: cache-node-modules
|
||||||
with:
|
with:
|
||||||
# npm cache files are stored in `~/.npm` on Linux/macOS
|
# npm cache files are stored in `~/.npm` on Linux/macOS
|
||||||
path: ~/.npm
|
path: ~/.npm
|
||||||
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||||
${{ runner.os }}-build-
|
${{ runner.os }}-build-
|
||||||
${{ runner.os }}-
|
${{ runner.os }}-
|
||||||
|
|
||||||
- name: setup Miniconda
|
- name: setup Miniconda
|
||||||
uses: conda-incubator/setup-miniconda@v2
|
uses: conda-incubator/setup-miniconda@v2
|
||||||
|
|
||||||
- name: Setup Environment
|
- name: Setup Environment
|
||||||
run: make setup
|
run: make setup
|
||||||
|
|
||||||
- name: Build and Test
|
- name: Build and Test
|
||||||
run: make test
|
run: make test
|
||||||
|
|
||||||
# Upload to S3
|
# Upload to S3
|
||||||
- name: Configure AWS credentials
|
- name: Configure AWS credentials
|
||||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||||
with:
|
with:
|
||||||
aws-region: ${{ secrets.AWS_REGION }}
|
aws-region: ${{ secrets.AWS_REGION }}
|
||||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||||
|
|
||||||
- name: Sync to S3
|
- name: Sync to S3
|
||||||
run: | # Update /latest and create an explicitly versioned directory under releases/YYYY.MM.MICRO/
|
run:
|
||||||
aws s3 sync --quiet ./build/ s3://pyscript.net/latest/
|
| # Update /latest and create an explicitly versioned directory under releases/YYYY.MM.MICRO/
|
||||||
aws s3 sync --quiet ./build/ s3://pyscript.net/releases/${{ github.ref_name }}/
|
aws s3 sync --quiet ./build/ s3://pyscript.net/latest/
|
||||||
|
aws s3 sync --quiet ./build/ s3://pyscript.net/releases/${{ github.ref_name }}/
|
||||||
|
|||||||
20
.github/workflows/publish-snapshot.yml
vendored
20
.github/workflows/publish-snapshot.yml
vendored
@@ -1,11 +1,11 @@
|
|||||||
name: '[CI] Publish Snapshot'
|
name: "[CI] Publish Snapshot"
|
||||||
# Copy /unstable/ to /snapshots/2022.09.1.RC1/
|
# Copy /unstable/ to /snapshots/2022.09.1.RC1/
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
snapshot_version:
|
snapshot_version:
|
||||||
description: 'The calver version of this snapshot: 2022.09.1 or 2022.09.1.RC1'
|
description: "The calver version of this snapshot: 2022.09.1 or 2022.09.1.RC1"
|
||||||
type: string
|
type: string
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
@@ -16,11 +16,11 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
id-token: write
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- name: Configure AWS credentials
|
- name: Configure AWS credentials
|
||||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||||
with:
|
with:
|
||||||
aws-region: ${{ secrets.AWS_REGION }}
|
aws-region: ${{ secrets.AWS_REGION }}
|
||||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||||
- name: Sync to S3
|
- name: Sync to S3
|
||||||
run: >
|
run: >
|
||||||
aws s3 sync s3://pyscript.net/unstable/ s3://pyscript.net/snapshots/${{ inputs.snapshot_version }}/
|
aws s3 sync s3://pyscript.net/unstable/ s3://pyscript.net/snapshots/${{ inputs.snapshot_version }}/
|
||||||
|
|||||||
26
.github/workflows/sync-examples.yml
vendored
26
.github/workflows/sync-examples.yml
vendored
@@ -1,4 +1,4 @@
|
|||||||
name: '[CI] Sync Examples'
|
name: "[CI] Sync Examples"
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
release:
|
||||||
@@ -15,15 +15,15 @@ jobs:
|
|||||||
working-directory: examples
|
working-directory: examples
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
|
# Deploy to S3
|
||||||
# Deploy to S3
|
- name: Checkout
|
||||||
- name: Checkout
|
uses: actions/checkout@v3
|
||||||
uses: actions/checkout@v3
|
- name: Configure AWS credentials
|
||||||
- name: Configure AWS credentials
|
uses: aws-actions/configure-aws-credentials@v1.6.1
|
||||||
uses: aws-actions/configure-aws-credentials@v1.6.1
|
with:
|
||||||
with:
|
aws-region: ${{ secrets.AWS_REGION }}
|
||||||
aws-region: ${{ secrets.AWS_REGION }}
|
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
||||||
role-to-assume: ${{ secrets.AWS_OIDC_RUNNER_ROLE }}
|
- name:
|
||||||
- name: Sync to S3
|
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
|
run: aws s3 sync --quiet --delete . s3://pyscript.net/examples/ # Sync directory, delete what is not in source
|
||||||
|
|||||||
74
.github/workflows/test-next.yml
vendored
Normal file
74
.github/workflows/test-next.yml
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
name: "[CI] Test Next"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push: # Only run on merges into main that modify files under pyscriptjs/ and examples/
|
||||||
|
branches:
|
||||||
|
- next
|
||||||
|
paths:
|
||||||
|
- pyscript.core/**
|
||||||
|
- .github/workflows/test-next.yml # Test that workflow works when changed
|
||||||
|
|
||||||
|
pull_request: # Run on any PR that modifies files under pyscriptjs/ and examples/
|
||||||
|
branches:
|
||||||
|
- next
|
||||||
|
paths:
|
||||||
|
- pyscript.core/**
|
||||||
|
- .github/workflows/test-next.yml # Test that workflow works when changed
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestNext:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: pyscript.core
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install node
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 20.x
|
||||||
|
|
||||||
|
- name: Cache node modules
|
||||||
|
uses: actions/cache@v3
|
||||||
|
env:
|
||||||
|
cache-name: cache-node-modules
|
||||||
|
with:
|
||||||
|
# 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: |
|
||||||
|
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||||
|
${{ runner.os }}-build-
|
||||||
|
${{ runner.os }}-
|
||||||
|
|
||||||
|
# TODO: this will likely change soon to pyscript.next
|
||||||
|
# - name: install next deps
|
||||||
|
# working-directory: pyscript.core
|
||||||
|
# run: npm i; npx playwright install
|
||||||
|
|
||||||
|
# - name: build next
|
||||||
|
# working-directory: pyscript.core
|
||||||
|
# run: npm run build
|
||||||
|
|
||||||
|
# - name: Run next tests
|
||||||
|
# working-directory: pyscript.core
|
||||||
|
# run: npm run test
|
||||||
|
|
||||||
|
# TODO: DO we want to upload next yet?
|
||||||
|
# - uses: actions/upload-artifact@v3
|
||||||
|
# with:
|
||||||
|
# name: pyscript
|
||||||
|
# path: |
|
||||||
|
# pyscriptjs/build/
|
||||||
|
# if-no-files-found: error
|
||||||
|
# retention-days: 7
|
||||||
|
|
||||||
|
# - uses: actions/upload-artifact@v3
|
||||||
|
# if: success() || failure()
|
||||||
|
# with:
|
||||||
|
# name: test_results
|
||||||
|
# path: pyscriptjs/test_results
|
||||||
|
# if-no-files-found: error
|
||||||
16
.github/workflows/test_report.yml
vendored
Normal file
16
.github/workflows/test_report.yml
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
name: Test Report
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: ['\[CI\] Build Unstable']
|
||||||
|
types:
|
||||||
|
- completed
|
||||||
|
jobs:
|
||||||
|
report:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: dorny/test-reporter@v1.6.0
|
||||||
|
with:
|
||||||
|
artifact: test_results
|
||||||
|
name: Test reports
|
||||||
|
path: "*.xml"
|
||||||
|
reporter: java-junit
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -73,6 +73,7 @@ instance/
|
|||||||
# Sphinx documentation
|
# Sphinx documentation
|
||||||
docs/_build/
|
docs/_build/
|
||||||
docs/_env/
|
docs/_env/
|
||||||
|
newdocs/_env/
|
||||||
|
|
||||||
# PyBuilder
|
# PyBuilder
|
||||||
target/
|
target/
|
||||||
@@ -138,3 +139,6 @@ dmypy.json
|
|||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
coverage/
|
coverage/
|
||||||
|
|
||||||
|
# junit xml for test results
|
||||||
|
test_results
|
||||||
|
|||||||
@@ -1,89 +1,63 @@
|
|||||||
# This is the configuration for pre-commit, a local framework for managing pre-commit hooks
|
# This is the configuration for pre-commit, a local framework for managing pre-commit hooks
|
||||||
# Check out the docs at: https://pre-commit.com/
|
# Check out the docs at: https://pre-commit.com/
|
||||||
|
ci:
|
||||||
|
skip: [eslint]
|
||||||
|
autoupdate_schedule: monthly
|
||||||
|
|
||||||
default_stages: [commit]
|
default_stages: [commit]
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.4.0
|
rev: v4.4.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: check-builtin-literals
|
- id: check-builtin-literals
|
||||||
- id: check-case-conflict
|
- id: check-case-conflict
|
||||||
- id: check-docstring-first
|
- id: check-docstring-first
|
||||||
- id: check-executables-have-shebangs
|
- id: check-executables-have-shebangs
|
||||||
- id: check-json
|
- id: check-json
|
||||||
exclude: tsconfig.json
|
exclude: tsconfig\.json
|
||||||
- id: check-toml
|
- id: check-toml
|
||||||
- id: check-xml
|
- id: check-xml
|
||||||
- id: check-yaml
|
- id: check-yaml
|
||||||
- id: detect-private-key
|
- id: detect-private-key
|
||||||
- id: end-of-file-fixer
|
- id: end-of-file-fixer
|
||||||
exclude: \.min\.js$
|
exclude: pyscript\.core/core.*|\.min\.js$
|
||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/bandit
|
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
||||||
rev: 1.7.4
|
rev: v0.0.257
|
||||||
hooks:
|
hooks:
|
||||||
- id: bandit
|
- id: ruff
|
||||||
args:
|
exclude: pyscript\.core/test|pyscript\.core/src/display.py
|
||||||
- --skip=B101,B201
|
args: [--fix]
|
||||||
|
|
||||||
- repo: https://github.com/psf/black
|
- repo: https://github.com/psf/black
|
||||||
rev: 22.12.0
|
rev: 23.1.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
|
|
||||||
|
- repo: https://github.com/codespell-project/codespell
|
||||||
|
rev: v2.2.4
|
||||||
|
hooks:
|
||||||
|
- id: codespell # See 'pyproject.toml' for args
|
||||||
|
exclude: \.js\.map$
|
||||||
|
additional_dependencies:
|
||||||
|
- tomli
|
||||||
|
|
||||||
- repo: https://github.com/codespell-project/codespell
|
- repo: https://github.com/hoodmane/pyscript-prettier-precommit
|
||||||
rev: v2.2.2
|
rev: "v3.0.0-alpha.6"
|
||||||
hooks:
|
hooks:
|
||||||
- id: codespell # See 'setup.cfg' for args
|
- id: prettier
|
||||||
|
exclude: pyscript\.core/test|pyscript\.core/core.*|pyscript\.core/types/|pyscript\.sw/
|
||||||
|
args: [--tab-width, "4"]
|
||||||
|
|
||||||
- repo: https://github.com/PyCQA/flake8
|
- repo: https://github.com/pre-commit/mirrors-eslint
|
||||||
rev: 6.0.0
|
rev: v8.36.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: flake8 # See 'setup.cfg' for args
|
- id: eslint
|
||||||
additional_dependencies: [flake8-bugbear, flake8-comprehensions]
|
files: pyscriptjs/src/.*\.[jt]sx?$ # *.js, *.jsx, *.ts and *.tsx
|
||||||
|
types: [file]
|
||||||
- repo: https://github.com/pycqa/isort
|
additional_dependencies:
|
||||||
rev: 5.11.1
|
- eslint@8.25.0
|
||||||
hooks:
|
- typescript@5.0.4
|
||||||
- id: isort
|
- "@typescript-eslint/eslint-plugin@5.58.0"
|
||||||
name: isort (python)
|
- "@typescript-eslint/parser@5.58.0"
|
||||||
args: [--profile, black]
|
|
||||||
|
|
||||||
- repo: https://github.com/macisamuele/language-formatters-pre-commit-hooks
|
|
||||||
rev: v2.5.0
|
|
||||||
hooks:
|
|
||||||
- id: pretty-format-yaml
|
|
||||||
args: [--autofix, --indent, '4']
|
|
||||||
exclude: .github/ISSUE_TEMPLATE/.*\.yml$
|
|
||||||
|
|
||||||
- repo: https://github.com/asottile/pyupgrade
|
|
||||||
rev: v3.3.1
|
|
||||||
hooks:
|
|
||||||
- id: pyupgrade
|
|
||||||
args:
|
|
||||||
- --py310-plus
|
|
||||||
|
|
||||||
- repo: https://github.com/pre-commit/mirrors-eslint
|
|
||||||
rev: v8.29.0
|
|
||||||
hooks:
|
|
||||||
- id: eslint
|
|
||||||
files: pyscriptjs/src/.*\.[jt]sx?$ # *.js, *.jsx, *.ts and *.tsx
|
|
||||||
types: [file]
|
|
||||||
additional_dependencies:
|
|
||||||
- eslint@8.25.0
|
|
||||||
- typescript@4.8.4
|
|
||||||
- '@typescript-eslint/eslint-plugin@5.39.0'
|
|
||||||
- '@typescript-eslint/parser@5.39.0'
|
|
||||||
|
|
||||||
# Commented out until mdformat-myst supports custom extensions
|
|
||||||
# See https://github.com/executablebooks/mdformat-myst/pull/9
|
|
||||||
# - repo: https://github.com/executablebooks/mdformat
|
|
||||||
# rev: 0.7.14 # Use the ref you want to point at
|
|
||||||
# hooks:
|
|
||||||
# - id: mdformat
|
|
||||||
# additional_dependencies:
|
|
||||||
# - mdformat-gfm
|
|
||||||
# - mdformat-myst
|
|
||||||
# - mdformat-black
|
|
||||||
|
|||||||
5
.prettierignore
Normal file
5
.prettierignore
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
ISSUE_TEMPLATE
|
||||||
|
*.min.*
|
||||||
|
package-lock.json
|
||||||
|
docs
|
||||||
|
examples/panel.html
|
||||||
@@ -25,4 +25,4 @@ conda:
|
|||||||
# Optionally declare the Python requirements required to build your docs
|
# Optionally declare the Python requirements required to build your docs
|
||||||
python:
|
python:
|
||||||
install:
|
install:
|
||||||
- requirements: docs/requirements.txt
|
- requirements: docs/requirements.txt
|
||||||
|
|||||||
@@ -4,17 +4,24 @@ Thank you for wanting to contribute to the PyScript project!
|
|||||||
|
|
||||||
## Table of contents
|
## Table of contents
|
||||||
|
|
||||||
* [Code of Conduct](#code-of-conduct)
|
- [Contributing to PyScript](#contributing-to-pyscript)
|
||||||
* [Contributing](#contributing)
|
- [Table of contents](#table-of-contents)
|
||||||
* [Reporting bugs](#reporting-bugs)
|
- [Code of Conduct](#code-of-conduct)
|
||||||
* [Reporting security issues](#reporting-security-issues)
|
- [Contributing](#contributing)
|
||||||
* [Asking questions](#asking-questions)
|
- [Reporting bugs](#reporting-bugs)
|
||||||
* [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
|
- [Creating useful issues](#creating-useful-issues)
|
||||||
* [Places to start](#places-to-start)
|
- [Reporting security issues](#reporting-security-issues)
|
||||||
* [Submitting a change](#submitting-a-change)
|
- [Asking questions](#asking-questions)
|
||||||
* [License terms for contributions](#license-terms-for-contributions)
|
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
|
||||||
* [Becoming a maintainer](#becoming-a-maintainer)
|
- [Developing](#developing)
|
||||||
* [Trademarks](#trademarks)
|
- [Rebasing changes](#rebasing-changes)
|
||||||
|
- [Building the docs](#building-the-docs)
|
||||||
|
- [Places to start](#places-to-start)
|
||||||
|
- [Setting up your local environment and developing](#setting-up-your-local-environment-and-developing)
|
||||||
|
- [Submitting a change](#submitting-a-change)
|
||||||
|
- [License terms for contributions](#license-terms-for-contributions)
|
||||||
|
- [Becoming a maintainer](#becoming-a-maintainer)
|
||||||
|
- [Trademarks](#trademarks)
|
||||||
|
|
||||||
# Code of Conduct
|
# Code of Conduct
|
||||||
|
|
||||||
@@ -28,10 +35,10 @@ Bugs are tracked on the [project issues page](https://github.com/pyscript/pyscri
|
|||||||
|
|
||||||
## Creating useful issues
|
## Creating useful issues
|
||||||
|
|
||||||
* Use a clear and descriptive title.
|
- 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 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.
|
- Describe the behavior you observed, and the behavior you had expected.
|
||||||
* Include screenshots if they help make the issue clear.
|
- Include screenshots if they help make the issue clear.
|
||||||
|
|
||||||
## Reporting security issues
|
## Reporting security issues
|
||||||
|
|
||||||
@@ -43,18 +50,18 @@ If you have questions about the project, using PyScript, or anything else, pleas
|
|||||||
|
|
||||||
## Places to start
|
## Places to start
|
||||||
|
|
||||||
If you would like to contribute to PyScript, but you aren't sure where to begin, here are some suggestions.
|
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.
|
- **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!
|
- **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.
|
- **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.
|
- **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
|
## Setting up your local environment and developing
|
||||||
|
|
||||||
If you would like to contribute to PyScript, you will need to set up a local development environment. The [following instructions](https://docs.pyscript.net/latest/development/setting-up-environment.html) will help you get started.
|
If you would like to contribute to PyScript, you will need to set up a local development environment. The [following instructions](https://docs.pyscript.net/latest/development/setting-up-environment.html) will help you get started.
|
||||||
|
|
||||||
You can also read the [developing process](https://docs.pyscript.net/latest/development/developing.html) and how to rebase your branch with the latest changes.
|
You can also read about PyScript's [development process](https://docs.pyscript.net/latest/development/developing.html) to learn how to contribute code to PyScript, how to run tests and what's the PR etiquette of the community!
|
||||||
|
|
||||||
## License terms for contributions
|
## License terms for contributions
|
||||||
|
|
||||||
@@ -69,5 +76,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).
|
The Project abides by the Organization's [trademark policy](https://github.com/pyscript/governance/blob/main/TRADEMARKS.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Part of MVG-0.1-beta.
|
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/).
|
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.
|
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.
|
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/).
|
Made with love by GitHub. Licensed under the [CC-BY 4.0 License](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||||
|
|||||||
@@ -9,15 +9,16 @@ This document lists the Maintainers of the Project. Maintainers may be added onc
|
|||||||
| Philipp Rudiger | Anaconda, Inc |
|
| Philipp Rudiger | Anaconda, Inc |
|
||||||
| Peter Wang | Anaconda, Inc |
|
| Peter Wang | Anaconda, Inc |
|
||||||
| Kevin Goldsmith | Anaconda, Inc |
|
| Kevin Goldsmith | Anaconda, Inc |
|
||||||
| Mariana Meireles | Anaconda, Inc |
|
| Mariana Meireles | |
|
||||||
| Nicholas H.Tollervey | Anaconda, Inc |
|
| Nicholas H.Tollervey | Anaconda, Inc |
|
||||||
| Madhur Tandon | Anaconda, Inc |
|
| Madhur Tandon | Anaconda, Inc |
|
||||||
| Ted Patrick | Anaconda, Inc |
|
| Ted Patrick | Anaconda, Inc |
|
||||||
| Jeff Glass | --- |
|
| Jeff Glass | |
|
||||||
| Paul Everitt | --- |
|
| Paul Everitt | |
|
||||||
| Fabio Rosado | --- |
|
| Fabio Rosado | Anaconda, Inc |
|
||||||
|
| Andrea Giammarchi | Anaconda, Inc |
|
||||||
|
|
||||||
______________________________________________________________________
|
---
|
||||||
|
|
||||||
Part of MVG-0.1-beta.
|
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/).
|
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).
|
For examples see [here](examples).
|
||||||
|
|
||||||
### Longer Version
|
### 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.
|
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
|
## 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
|
```html
|
||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
</head>
|
</head>
|
||||||
```
|
```
|
||||||
|
|
||||||
You can then use PyScript components in your html page. PyScript currently implements the following elements:
|
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-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-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.
|
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,18 +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.
|
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.
|
||||||
|
|
||||||
## Resources
|
## Resources
|
||||||
|
|
||||||
* [Official docs](https://docs.pyscript.net)
|
- [Official docs](https://docs.pyscript.net)
|
||||||
* [Discussion board](https://community.anaconda.cloud/c/tech-topics/pyscript)
|
- [Discussion board](https://community.anaconda.cloud/c/tech-topics/pyscript)
|
||||||
* [Home Page](https://pyscript.net/)
|
- [Home Page](https://pyscript.net/)
|
||||||
* [Blog Post](https://engineering.anaconda.com/2022/04/welcome-pyscript.html)
|
- [Blog Post](https://engineering.anaconda.com/2022/04/welcome-pyscript.html)
|
||||||
* [Discord Channel](https://discord.gg/BYB2kvyFwm)
|
- [Discord Channel](https://discord.gg/BYB2kvyFwm)
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
* This is an extremely experimental project, so expect things to break!
|
- This is an extremely experimental project, so expect things to break!
|
||||||
* PyScript has been only tested on Chrome at the moment.
|
- PyScript has been only tested on Chrome at the moment.
|
||||||
|
|
||||||
## Governance
|
## Governance
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
This page is meant for troubleshooting common problems with PyScript.
|
This page is meant for troubleshooting common problems with PyScript.
|
||||||
|
|
||||||
## Table of contents:
|
## Table of contents:
|
||||||
* [Make Setup](#make-setup)
|
|
||||||
|
- [Make Setup](#make-setup)
|
||||||
|
|
||||||
## Make setup
|
## Make setup
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ shell:
|
|||||||
@export CONDA_ENV_PROMPT='<{name}>'
|
@export CONDA_ENV_PROMPT='<{name}>'
|
||||||
@echo 'conda activate $(env)'
|
@echo 'conda activate $(env)'
|
||||||
|
|
||||||
htmlserve:
|
htmlserve: html
|
||||||
@echo 'visit docs at http://localhost:8080'
|
@echo 'visit docs at http://localhost:8080'
|
||||||
python -m http.server -d "$(BUILDDIR)/html/" 8080
|
python -m http.server -d "$(BUILDDIR)/html/" 8080
|
||||||
|
|
||||||
|
|||||||
@@ -29,3 +29,26 @@ static files like templates and themes, to build the static end result.
|
|||||||
### Build
|
### Build
|
||||||
|
|
||||||
To learn how to build the docs, head over the [CONTRIBUTING](../CONTRIBUTING.md) page.
|
To learn how to build the docs, head over the [CONTRIBUTING](../CONTRIBUTING.md) page.
|
||||||
|
|
||||||
|
|
||||||
|
## Cross-referencing
|
||||||
|
|
||||||
|
You can link to other pages in the documentation by using the `{doc}` role. For example, to link to the `docs/README.md` file, you would use:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
{doc}`docs/README.md`
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also cross-reference the python glossary by using the `{term}` role. For example, to link to the `iterable` term, you would use:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
{term}`iterable`
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also cross-reference functions, methods or data attributes by using the `{attr}` for example:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
{py:func}`repr`
|
||||||
|
```
|
||||||
|
|
||||||
|
This would link to the `repr` function in the python builtins.
|
||||||
|
|||||||
4
docs/_static/examples/what-is-pyscript.html
vendored
4
docs/_static/examples/what-is-pyscript.html
vendored
@@ -3,6 +3,10 @@
|
|||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
<style>
|
<style>
|
||||||
|
h1 {
|
||||||
|
color: #459db9;
|
||||||
|
}
|
||||||
|
|
||||||
.pulse {
|
.pulse {
|
||||||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||||
}
|
}
|
||||||
|
|||||||
4
docs/_static/s3_error.html
vendored
Normal file
4
docs/_static/s3_error.html
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<html><head><meta http-equiv="refresh" content="5; URL='/latest/'" /></head><body>
|
||||||
|
<h1>404 - File not found</h1>
|
||||||
|
<p>You will be redirected to the latest documentation in 5 seconds.</p>
|
||||||
|
</body></html>
|
||||||
94
docs/changelog.md
Normal file
94
docs/changelog.md
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# Release Notes
|
||||||
|
|
||||||
|
2023.XX.X
|
||||||
|
=========
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
- Added the `xterm` attribute to `py-config`. When set to `True` or `xterm`, an (output-only) [xterm.js](http://xtermjs.org/) terminal will be used in place of the default py-terminal.
|
||||||
|
- The default version of Pyodide is now `0.23.2`. See the [Pyodide Changelog](https://pyodide.org/en/stable/project/changelog.html#version-0-23-2) for a detailed list of changes.
|
||||||
|
- Added the `@when` decorator for attaching Python functions as event handlers
|
||||||
|
- The `py-mount` attribute on HTML elements has been deprecated, and will be removed in a future release.
|
||||||
|
|
||||||
|
|
||||||
|
### Runtime py- attributes
|
||||||
|
|
||||||
|
- Added logic to react to `py-*` attributes changes, removal, `py-*` attributes added to already live nodes but also `py-*` attributes added or defined via injected nodes (either appended or via `innerHTML` operations). ([#1435](https://github.com/pyscript/pyscript/pull/1435))
|
||||||
|
|
||||||
|
### <script type="py">
|
||||||
|
- Added the ability to optionally use `<script type="py">`, `<script type="pyscript">` or `<script type="py-script">` instead of a `<py-script>` custom element, in order to tackle cases where the content of the `<py-script>` tag, inevitably parsed by browsers, could accidentally contain *HTML* able to break the surrounding page layout. ([#1396](https://github.com/pyscript/pyscript/pull/1396))
|
||||||
|
|
||||||
|
### <py-terminal>
|
||||||
|
- Added a `docked` field and attribute for the `<py-terminal>` custom element, enabled by default when the terminal is in `auto` mode, and able to dock the terminal at the bottom of the page with auto scroll on new code execution.
|
||||||
|
|
||||||
|
### <py-script>
|
||||||
|
- Restored the `output` attribute of `py-script` tags to route `sys.stdout` to a DOM element with the given ID. ([#1063](https://github.com/pyscript/pyscript/pull/1063))
|
||||||
|
- Added a `stderr` attribute of `py-script` tags to route `sys.stderr` to a DOM element with the given ID. ([#1063](https://github.com/pyscript/pyscript/pull/1063))
|
||||||
|
|
||||||
|
### <py-repl>
|
||||||
|
- The `output` attribute of `py-repl` tags now specifies the id of the DOM element that `sys.stdout`, `sys.stderr`, and the results of a REPL execution are written to. It no longer affects the location of calls to `display()`
|
||||||
|
- Added a `stderr` attribute of `py-repl` tags to route `sys.stderr` to a DOM element with the given ID. ([#1106](https://github.com/pyscript/pyscript/pull/1106))
|
||||||
|
- Resored the `output-mode` attribute of `py-repl` tags. If `output-mode` == 'append', the DOM element where output is printed is _not_ cleared before writing new results.
|
||||||
|
- Load code from the attribute src of py-repl and preload it into the corresponding py-repl tag by use the attribute `str` in your `py-repl` tag([#1292](https://github.com/pyscript/pyscript/pull/1292))
|
||||||
|
|
||||||
|
### Plugins
|
||||||
|
- Plugins may now implement the `beforePyReplExec()` and `afterPyReplExec()` hooks, which are called immediately before and after code in a `py-repl` tag is executed. ([#1106](https://github.com/pyscript/pyscript/pull/1106))
|
||||||
|
|
||||||
|
### Web worker support
|
||||||
|
- introduced the new experimental `execution_thread` config option: if you set `execution_thread = "worker"`, the python interpreter runs inside a web worker
|
||||||
|
- worker support is still **very** experimental: not everything works, use it at your own risk
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
- Fixes [#1280](https://github.com/pyscript/pyscript/issues/1280), which describes the errors on the PyRepl tests related to having auto-gen tags that shouldn't be there.
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
------------
|
||||||
|
|
||||||
|
- Py-REPL tests now run on both osx and non osx OSs
|
||||||
|
- migrated from *rollup* to *esbuild* to create artifacts
|
||||||
|
- updated `@codemirror` dependency to its latest
|
||||||
|
|
||||||
|
Docs
|
||||||
|
----
|
||||||
|
|
||||||
|
- Add docs for event handlers
|
||||||
|
|
||||||
|
2023.01.1
|
||||||
|
=========
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
- Fixed an issue where `pyscript` would not be available when using the minified version of PyScript. ([#1054](https://github.com/pyscript/pyscript/pull/1054))
|
||||||
|
- Fixed missing closing tag when rendering an image with `display`. ([#1058](https://github.com/pyscript/pyscript/pull/1058))
|
||||||
|
- Fixed a bug where Python plugins methods were being executed twice. ([#1064](https://github.com/pyscript/pyscript/pull/1064))
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
------------
|
||||||
|
|
||||||
|
- When adding a `py-` attribute to an element but didn't added an `id` attribute, PyScript will now generate a random ID for the element instead of throwing an error which caused the splash screen to not shutdown. ([#1122](https://github.com/pyscript/pyscript/pull/1122))
|
||||||
|
- You can now disable the splashscreen by setting `enabled = false` in your `py-config` under the `[splashscreen]` configuration section. ([#1138](https://github.com/pyscript/pyscript/pull/1138))
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
- Fixed 'Direct usage of document is deprecated' warning in the getting started guide. ([#1052](https://github.com/pyscript/pyscript/pull/1052))
|
||||||
|
- Added reference documentation for the `py-splashscreen` plugin ([#1138](https://github.com/pyscript/pyscript/pull/1138))
|
||||||
|
- Adds doc for installing tests ([#1156](https://github.com/pyscript/pyscript/pull/1156))
|
||||||
|
- Adds docs for custom Pyscript attributes (`py-*`) that allow you to add event listeners to an element ([#1125](https://github.com/pyscript/pyscript/pull/1125))
|
||||||
|
|
||||||
|
Deprecations and Removals
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
- The py-config `runtimes` to specify an interpreter has been deprecated. The `interpreters` config should be used instead. ([#1082](https://github.com/pyscript/pyscript/pull/1082))
|
||||||
|
- The attributes `pys-onClick` and `pys-onKeyDown` have been deprecated, but the warning was only shown in the console. An alert banner will now be shown on the page if the attributes are used. They will be removed in the next release. ([#1084](https://github.com/pyscript/pyscript/pull/1084))
|
||||||
|
- The pyscript elements `py-button`, `py-inputbox`, `py-box` and `py-title` have now completed their deprecation cycle and have been removed. ([#1084](https://github.com/pyscript/pyscript/pull/1084))
|
||||||
|
- The attributes `pys-onClick` and `pys-onKeyDown` have been removed. Use `py-click` and `py-keydown` instead ([#1361](https://github.com/pyscript/pyscript/pull/1361))
|
||||||
@@ -19,7 +19,7 @@ import os
|
|||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
project = "PyScript"
|
project = "PyScript"
|
||||||
copyright = "(c) 2022, Anaconda, Inc."
|
copyright = "(c) 2023, Anaconda, Inc."
|
||||||
author = "Anaconda, Inc."
|
author = "Anaconda, Inc."
|
||||||
language = "en"
|
language = "en"
|
||||||
|
|
||||||
@@ -36,8 +36,13 @@ extensions = [
|
|||||||
"sphinx_sitemap",
|
"sphinx_sitemap",
|
||||||
"sphinxemoji.sphinxemoji",
|
"sphinxemoji.sphinxemoji",
|
||||||
"sphinxcontrib.youtube",
|
"sphinxcontrib.youtube",
|
||||||
|
"sphinx.ext.intersphinx",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
intersphinx_mapping = {
|
||||||
|
"python": ("https://docs.python.org/3.10", None),
|
||||||
|
}
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
templates_path = ["_templates"]
|
templates_path = ["_templates"]
|
||||||
|
|
||||||
|
|||||||
@@ -28,3 +28,11 @@ showWarning(`
|
|||||||
</p>
|
</p>
|
||||||
`, "html")
|
`, "html")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Deprecation History
|
||||||
|
|
||||||
|
This section tracks deprecations of specific features, both for historical record and to help the development team remember to actually remove deprecated features in future releases.
|
||||||
|
|
||||||
|
|Attribute/Object/Functionality|Deprecated In|Removed In|
|
||||||
|
|-|-|-|
|
||||||
|
|`py-mount` attribute | (Release following 2023.03.1) | -|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Developing Process
|
# Development Process
|
||||||
|
|
||||||
This document is intended to help you get started developing for pyscript, it assumes that you have [setup your development environment](setting-up-environment.md).
|
This document is intended to help you get started in developing software for the PyScript project. It assumes that you have [a working development environment](setting-up-environment.md). It also assumes you have a remote named `upstream` pointing to PyScript's repository and one named `origin` pointing to your own repository.
|
||||||
|
|
||||||
* First, make sure you are using the latest version of the pyscript main branch
|
* First, make sure you are using the latest version of the pyscript main branch
|
||||||
|
|
||||||
@@ -34,29 +34,57 @@ pre-commit install
|
|||||||
git checkout -b <your branch name>
|
git checkout -b <your branch name>
|
||||||
```
|
```
|
||||||
|
|
||||||
* Work on your change
|
* Work on your changes
|
||||||
|
|
||||||
**NOTE**: If you are working on a python file, you may encounter linting issues when pre-commit runs. Pyscript uses [black](https://black.readthedocs.io/en/stable/) to fix any linting problems automatically. All you need to do is add the changes again and commit using your previous commit message (the previous one that failed didn't complete due to black formatting files).
|
**NOTE**: If you are working on a python file, you may encounter linting issues when pre-commit runs. Pyscript uses [black](https://black.readthedocs.io/en/stable/) to fix any linting problems automatically. All you need to do is add the changes again and commit using your previous commit message (the previous one that failed didn't complete due to black formatting files).
|
||||||
|
|
||||||
* Run tests before pushing the changes
|
* Run tests before pushing the changes
|
||||||
|
|
||||||
```
|
```
|
||||||
make tests
|
make test
|
||||||
```
|
```
|
||||||
|
|
||||||
* When you make changes locally, double check that your contribution follows the PyScript formatting rules by running `npm run lint`. Note that in this case you're looking for the errors, <u>**NOT**</u> the warnings (Unless the warning is created by a local change). If an error is found by lint you should fix it <u>**before**</u> creating a pull request
|
To learn more about tests please refer to the session [Quick guide to pytest](## Quick guide to pytest).
|
||||||
|
|
||||||
|
* When you make changes locally, double check that your contribution follows the PyScript formatting rules by running `npm run lint`. Note that in this case you're looking for the errors, <u>**NOT**</u> the warnings (Unless the warning is created by a local change). If an error is found by the linter you should fix it <u>**before**</u> creating a pull request.
|
||||||
|
|
||||||
## Rebasing changes
|
#### Rebasing changes
|
||||||
|
|
||||||
Sometimes you might be asked to rebase main into your branch. Please refer to this [section on git rebase from GitHub docs](https://docs.github.com/en/get-started/using-git/about-git-rebase).
|
Sometimes you might be asked to rebase the main branch into your local branch. Please refer to this [section on git rebase from GitHub docs](https://docs.github.com/en/get-started/using-git/about-git-rebase).
|
||||||
|
|
||||||
If you need help with anything, feel free to reach out and ask for help!
|
If you need help with anything, feel free to reach out and ask for help!
|
||||||
|
|
||||||
|
|
||||||
## pytest quick guide
|
## Updating the changelog
|
||||||
|
|
||||||
We make a heavy usage of `pytest`. Here is a quick guide and collection of
|
As you work on your changes, please update the changelog file `changelog.md` with a short description of the changes you made. This will help us keep track of what has changed in each release.
|
||||||
|
|
||||||
|
You can look at the [changelog](../changelog.md) for examples on how to add your changes to the changelog. But here's a quick example:
|
||||||
|
|
||||||
|
```
|
||||||
|
2023.02.01
|
||||||
|
=========
|
||||||
|
|
||||||
|
Bug fixes
|
||||||
|
---------
|
||||||
|
|
||||||
|
- Fixed a bug that was causing the app to crash when you tried to do something #PR_NUMBER
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
------------
|
||||||
|
|
||||||
|
- Made awesome new feature #PR_NUMBER
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
- Added a new section to the docs #PR_NUMBER
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick guide to pytest
|
||||||
|
|
||||||
|
We make heavy usage of `pytest`. Here is a quick guide and collection of
|
||||||
useful options:
|
useful options:
|
||||||
|
|
||||||
- To run all tests in the current directory and subdirectories: `pytest`
|
- To run all tests in the current directory and subdirectories: `pytest`
|
||||||
@@ -79,7 +107,7 @@ useful options:
|
|||||||
- `-k 'foo and not bar'`
|
- `-k 'foo and not bar'`
|
||||||
|
|
||||||
|
|
||||||
## Running integration tests under pytest
|
### Running integration tests under pytest
|
||||||
|
|
||||||
`make test` is useful to run all the tests, but during the development is
|
`make test` is useful to run all the tests, but during the development is
|
||||||
useful to have more control on how tests are run. The following guide assumes
|
useful to have more control on how tests are run. The following guide assumes
|
||||||
@@ -118,8 +146,8 @@ $ pytest test_01_basic.py -k test_pyscript_hello -s
|
|||||||
[ 0.00 page.goto ] pyscript_hello.html
|
[ 0.00 page.goto ] pyscript_hello.html
|
||||||
[ 0.01 request ] 200 - fake_server - http://fake_server/pyscript_hello.html
|
[ 0.01 request ] 200 - fake_server - http://fake_server/pyscript_hello.html
|
||||||
...
|
...
|
||||||
[ 0.17 console.info ] [py-loader] Downloading pyodide-0.21.3...
|
[ 0.17 console.info ] [py-loader] Downloading pyodide-x.y.z...
|
||||||
[ 0.18 request ] 200 - CACHED - https://cdn.jsdelivr.net/pyodide/v0.21.3/full/pyodide.js
|
[ 0.18 request ] 200 - CACHED - https://cdn.jsdelivr.net/pyodide/vx.y.z/full/pyodide.js
|
||||||
...
|
...
|
||||||
[ 3.59 console.info ] [pyscript/main] PyScript page fully initialized
|
[ 3.59 console.info ] [pyscript/main] PyScript page fully initialized
|
||||||
[ 3.60 console.log ] hello pyscript
|
[ 3.60 console.log ] hello pyscript
|
||||||
@@ -162,8 +190,18 @@ $ pytest test_01_basic.py -k test_pyscript_hello -s --dev
|
|||||||
`--dev` implies `--headed --no-fake-server`. In addition, it also
|
`--dev` implies `--headed --no-fake-server`. In addition, it also
|
||||||
automatically open chrome dev tools.
|
automatically open chrome dev tools.
|
||||||
|
|
||||||
|
#### To run only main thread or worker tests
|
||||||
|
|
||||||
#### Fake server, HTTP cache
|
By default, we run each test twice: one with `execution_thread = "main"` and
|
||||||
|
one with `execution_thread = "worker"`. If you want to run only half of them,
|
||||||
|
you can use `-m`:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ pytest -m main # run only the tests in the main thread
|
||||||
|
$ pytest -m worker # ron only the tests in the web worker
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fake server, HTTP cache
|
||||||
|
|
||||||
By default, our test machinery uses a playwright router which intercepts and
|
By default, our test machinery uses a playwright router which intercepts and
|
||||||
cache HTTP requests, so that for example you don't have to download pyodide
|
cache HTTP requests, so that for example you don't have to download pyodide
|
||||||
@@ -179,25 +217,6 @@ If you want to temporarily disable the cache, the easiest thing is to use
|
|||||||
If you want to clear the cache, you can use the special option
|
If you want to clear the cache, you can use the special option
|
||||||
`--clear-http-cache`:
|
`--clear-http-cache`:
|
||||||
|
|
||||||
```
|
|
||||||
$ pytest --clear-http-cache
|
|
||||||
...
|
|
||||||
-------------------- SmartRouter HTTP cache --------------------
|
|
||||||
Requests found in the cache:
|
|
||||||
https://raw.githubusercontent.com/pyscript/pyscript/main/README.md
|
|
||||||
https://cdn.jsdelivr.net/pyodide/v0.21.3/full/repodata.json
|
|
||||||
https://cdn.jsdelivr.net/pyodide/v0.21.3/full/pyodide.asm.js
|
|
||||||
https://cdn.jsdelivr.net/pyodide/v0.21.3/full/micropip-0.1-py3-none-any.whl
|
|
||||||
https://cdn.jsdelivr.net/pyodide/v0.21.3/full/pyodide.asm.data
|
|
||||||
https://cdn.jsdelivr.net/pyodide/v0.21.3/full/pyodide.js
|
|
||||||
https://cdn.jsdelivr.net/pyodide/v0.21.3/full/pyodide.asm.wasm
|
|
||||||
https://cdn.jsdelivr.net/pyodide/v0.21.3/full/pyodide_py.tar
|
|
||||||
https://cdn.jsdelivr.net/pyodide/v0.21.3/full/pyparsing-3.0.9-py3-none-any.whl
|
|
||||||
https://cdn.jsdelivr.net/pyodide/v0.21.3/full/distutils.tar
|
|
||||||
https://cdn.jsdelivr.net/pyodide/v0.21.3/full/packaging-21.3-py3-none-any.whl
|
|
||||||
Cache cleared
|
|
||||||
```
|
|
||||||
|
|
||||||
**NOTE**: this works only if you are inside `tests/integration`, or if you
|
**NOTE**: this works only if you are inside `tests/integration`, or if you
|
||||||
explicitly specify `tests/integration` from the command line. This is due to
|
explicitly specify `tests/integration` from the command line. This is due to
|
||||||
how `pytest` decides to search for and load the various `conftest.py`.
|
how `pytest` decides to search for and load the various `conftest.py`.
|
||||||
|
|||||||
@@ -1,69 +1,285 @@
|
|||||||
# Setting up your development environment
|
# Setting up your development environment
|
||||||
|
|
||||||
* Fork the repository - [quicklink](https://github.com/pyscript/pyscript/fork)
|
These steps will help you set up your development environment. We suggest completing each step before going to the next step, as some parts have dependencies on previous commands.
|
||||||
|
|
||||||
* Clone your fork of the project
|
## Prepare your repository
|
||||||
|
|
||||||
```
|
* Create a fork of the [PyScript github repository](https://github.com/pyscript/pyscript/fork) to your github.
|
||||||
|
|
||||||
|
* In your development machine, clone your fork of PyScript. Use this command in your terminal.
|
||||||
|
|
||||||
|
```sh
|
||||||
git clone https://github.com/<your username>/pyscript
|
git clone https://github.com/<your username>/pyscript
|
||||||
```
|
```
|
||||||
|
|
||||||
* Add the original project as your upstream (this will allow you to pull the latest changes)
|
* With the following command, add the original project as your upstream. This will allow you to pull the latest changes.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
git remote add upstream https://github.com/pyscript/pyscript.git
|
||||||
|
git pull upstream main
|
||||||
|
```
|
||||||
|
|
||||||
|
* If the above fails, try this alternative:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git remote remove upstream
|
||||||
git remote add upstream git@github.com:pyscript/pyscript.git
|
git remote add upstream git@github.com:pyscript/pyscript.git
|
||||||
|
git pull upstream main
|
||||||
```
|
```
|
||||||
|
|
||||||
* cd into the `pyscriptjs` folder using the line below in your terminal (if your terminal is already in pyscript then use **cd pyscriptjs** instead)
|
## Install the dependencies
|
||||||
|
|
||||||
```
|
* change directory into `pyscriptjs` using this command:
|
||||||
|
|
||||||
|
```sh
|
||||||
cd pyscript/pyscriptjs
|
cd pyscript/pyscriptjs
|
||||||
```
|
```
|
||||||
|
|
||||||
* Install the dependencies with the command below (you must have node >=16)
|
We need to ensure that we have installed `conda`, `nodejs` >= 16 and `make`, before we can continue.
|
||||||
|
|
||||||
|
* Install `conda` by downloading one of the following packages that include it [MiniConda](https://docs.conda.io/en/latest/miniconda.html) or [Anaconda](https://www.anaconda.com/download/).
|
||||||
|
|
||||||
|
* Install `nodejs` with at least version 16. This can be downloaded at [https://nodejs.org](https://nodejs.org)
|
||||||
|
|
||||||
|
* Ensure that `make` is available on your system:
|
||||||
|
|
||||||
|
* *Linux*. `make` is usually installed by default in most Linux distributions. In the case it is not installed, run the terminal command `sudo apt install make`.
|
||||||
|
|
||||||
|
* *OS X*. Install Apple Developer Tools. `make` is included in this package.
|
||||||
|
|
||||||
|
* *Windows*. It is recommended to use either Windows Subsystem for Linux (WSL) or GNUWin32 for installing `make`. Instructions can be found [in this StackOverflow question](https://stackoverflow.com/questions/32127524/how-to-install-and-use-make-in-windows).
|
||||||
|
|
||||||
|
* The following command will download and install the rest of the PyScript dependencies:
|
||||||
|
|
||||||
```
|
```
|
||||||
make setup
|
make setup
|
||||||
```
|
```
|
||||||
**NOTE**: If `make setup` gives a node/npm version required error then go to [troubleshooting](https://github.com/pyscript/pyscript/blob/main/TROUBLESHOOTING.md)
|
|
||||||
|
|
||||||
* You can also run the examples locally by running the command below in your terminal
|
* **NOTE**: If `make setup` gives an error on an incompatible version for node or npm, please refer to [troubleshooting](https://github.com/pyscript/pyscript/blob/main/TROUBLESHOOTING.md).
|
||||||
|
|
||||||
|
## Activating the environment
|
||||||
|
|
||||||
|
* After the above `make setup` command is completed, it will print out the command for activating the environment using the following format. Use this to work on the development environment:
|
||||||
|
|
||||||
|
```
|
||||||
|
conda activate <environment name>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deactivating the environment
|
||||||
|
|
||||||
|
* To deactivate the environment, use the following command:
|
||||||
|
```
|
||||||
|
conda deactivate
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# Running PyScript examples server
|
||||||
|
|
||||||
|
The examples server is used to view and edit the example files.
|
||||||
|
|
||||||
|
* change directory into `pyscriptjs` using this command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd pyscript/pyscriptjs
|
||||||
|
```
|
||||||
|
|
||||||
|
* To build the examples, run this command:
|
||||||
|
|
||||||
```
|
```
|
||||||
make examples
|
make examples
|
||||||
```
|
```
|
||||||
|
|
||||||
* Run ***npm run dev*** to build and run the dev server. This will also watch for changes and rebuild when a file is saved.
|
* To serve the examples, run this command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
python -m http.server 8080 --directory examples
|
||||||
|
```
|
||||||
|
|
||||||
|
* Alternately, you can also run this command if conda is not activated:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
conda run -p <environment name> python -m http.server 8080 --directory examples
|
||||||
|
```
|
||||||
|
|
||||||
|
* You can access the examples server by visiting the following url in your browser: [http://localhost:8080](http://localhost:8080)
|
||||||
|
|
||||||
|
|
||||||
|
# Running the PyScript development server
|
||||||
|
|
||||||
|
The PyScript development server will regularly check for any changes in the src directory. If any changes were detected, the server will rebuild itself to reflect the changes. This is useful for development with PyScript.
|
||||||
|
|
||||||
|
* change directory into `pyscriptjs` using this command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd pyscript/pyscriptjs
|
||||||
|
```
|
||||||
|
|
||||||
|
* Use the following command to build and run the PyScript dev server.
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
**NOTE**: To access your local build paste `http://localhost:8080` into your browser
|
|
||||||
|
|
||||||
|
* You can access the PyScript development server by visiting the following url in your browser: [http://localhost:8080](http://localhost:8080)
|
||||||
|
|
||||||
Now that node and npm have both been updated `make setup` should work, and you can continue [setting up your local environment](setting-up-environment.md) without problems (hopefully).
|
# Setting up the test environment
|
||||||
|
|
||||||
|
A key to good development is to perform tests before sending a Pull Request for your changes.
|
||||||
|
|
||||||
## Setting up and building the docs
|
## Install the dependencies
|
||||||
|
|
||||||
To build the documentation locally first make sure you are in the `docs` directory.
|
* change directory into `pyscriptjs` using this command:
|
||||||
|
|
||||||
You'll need `make` and `conda` installed in your machine. The rest of the environment should be automatically download and created for you once you use the command:
|
```sh
|
||||||
|
cd pyscript/pyscriptjs
|
||||||
|
```
|
||||||
|
|
||||||
|
* The following command will download the dependencies needed for running the tests:
|
||||||
|
|
||||||
```
|
```
|
||||||
make setup
|
make setup
|
||||||
```
|
```
|
||||||
|
|
||||||
Use `conda activate $environment_name` to activate your environment.
|
* If you are not using a conda environment, or wish to install the dependencies manually, here are the packages needed:
|
||||||
|
* `pillow`
|
||||||
|
* `requests`
|
||||||
|
* `numpy`
|
||||||
|
* `playwright`
|
||||||
|
* `pytest-playwright`. Note that this is only available as a `pip` package.
|
||||||
|
|
||||||
To add new information to the documentation make sure you conform with PyScript's code of conduct and with the general principles of Diataxis. Don't worry about reading too much on it, just do your best to keep your contributions on the correct axis.
|
## Activating the environment
|
||||||
|
|
||||||
Write your documentation files using [Markedly Structured Text](https://myst-parser.readthedocs.io/en/latest/syntax/optional.html), which is very similar to vanilla Markdown but with some addons to create the documentation infrastructure.
|
* After the above `make setup` command is completed, it will print out the command for activating the environment using the following format:
|
||||||
|
|
||||||
Once done, initialize a server to check your work:
|
```
|
||||||
|
conda activate <environment name>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deactivating the environment
|
||||||
|
|
||||||
|
* To deactivate the environment, use the following command:
|
||||||
|
```
|
||||||
|
conda deactivate
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running the tests
|
||||||
|
|
||||||
|
* After setting up the test environment and while the environment is activated, you can run the tests with the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
make test
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information about PyScript's testing framework, head over to the [development process](developing.md) page.
|
||||||
|
|
||||||
|
# Setting up your documentation environment
|
||||||
|
|
||||||
|
The documentation environment is separate from the development environment. It is used for updating and reviewing the documentation before deployment.
|
||||||
|
|
||||||
|
## Installing the dependencies
|
||||||
|
|
||||||
|
* change directory into the `docs` using this command:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cd pyscript/docs
|
||||||
|
```
|
||||||
|
|
||||||
|
* The following command will download, install the dependencies, and create the environment for you:
|
||||||
|
|
||||||
|
```
|
||||||
|
make setup
|
||||||
|
```
|
||||||
|
|
||||||
|
(activating-documentation-environment)=
|
||||||
|
## Activating the environment
|
||||||
|
|
||||||
|
* After the above `make setup` command is completed, it will print out the command for activating the environment using the following format:
|
||||||
|
|
||||||
|
```
|
||||||
|
conda activate <docs environment name>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that the docs environment path is different from the developer's environment path.
|
||||||
|
|
||||||
|
## Deactivating the environment
|
||||||
|
|
||||||
|
* To deactivate the environment, use the following command:
|
||||||
|
```
|
||||||
|
conda deactivate
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing to the documentation
|
||||||
|
|
||||||
|
* Before sending a pull request, we recommend that your documentation conforms with [PyScript's code of conduct](https://github.com/pyscript/governance/blob/main/CODE-OF-CONDUCT.md) and with the general principles of [Diataxis](https://diataxis.fr/). Don't worry about reading too much on it, just do your best to keep your contributions on the correct axis.
|
||||||
|
|
||||||
|
* Write your documentation files using [Markedly Structured Text](https://myst-parser.readthedocs.io/en/latest/syntax/optional.html). This is similar to Markdown but with some addons to create the documentation infrastructure.
|
||||||
|
|
||||||
|
## Reviewing your work
|
||||||
|
|
||||||
|
* Before sending a Pull Request, review your work by starting the documentation server. To do this, use the following command:
|
||||||
|
|
||||||
```
|
```
|
||||||
make livehtml
|
make livehtml
|
||||||
```
|
```
|
||||||
|
|
||||||
Visible here: [http://127.0.0.1:8000](http://127.0.0.1:8000)
|
You can visit the documentation server by opening a browser and visiting [http://127.0.0.1:8000](http://127.0.0.1:8000).
|
||||||
|
|
||||||
|
* Alternately, you can open a static documentation server. Unlike the above, this will not automatically update any changes done after running this server. To see the changes done, you will need to manually stop and restart the server. To do this, use the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
make htmlserve
|
||||||
|
```
|
||||||
|
|
||||||
|
You can visit the documentation server by opening a browser and visiting [http://127.0.0.1:8080](http://127.0.0.1:8080).
|
||||||
|
|
||||||
|
* To stop either server, press `ctrl+C` or `command+C` while the shell running the command is active.
|
||||||
|
|
||||||
|
* Note: If the above make commands failed, you need to activate the documentation environment first before running any of the commands. Refer to [Activating the environment](#activating-documentation-environment) section above.
|
||||||
|
|
||||||
|
# PyScript Demonstrator
|
||||||
|
|
||||||
|
A simple webapp to demonstrate the capabilities of PyScript.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
1. If you don't already have Node.js, install it. The official installer for the
|
||||||
|
LTS version of Node is available from [nodejs.org](https://nodejs.org/).
|
||||||
|
|
||||||
|
2. If you don't already have Rollup, install it. Rollup can be installed as a
|
||||||
|
global resource using:
|
||||||
|
|
||||||
|
$ npm install --global rollup
|
||||||
|
|
||||||
|
3. Install the demo apps requirements:
|
||||||
|
|
||||||
|
$ npm install
|
||||||
|
|
||||||
|
4. Start the server:
|
||||||
|
|
||||||
|
$ npm run dev
|
||||||
|
|
||||||
|
This will compile the resources for the app, and start the development server.
|
||||||
|
|
||||||
|
5. When the compilation completes, it will display something like:
|
||||||
|
|
||||||
|
Your application is ready~! 🚀
|
||||||
|
|
||||||
|
- Local: http://localhost:8080
|
||||||
|
- Network: Add `--host` to expose
|
||||||
|
|
||||||
|
────────────────── LOGS ──────────────────
|
||||||
|
|
||||||
|
Once this is visible, open a browser at
|
||||||
|
[http://localhost:8080](http://localhost:8080). This will provide a list of
|
||||||
|
demos that you can run.
|
||||||
|
|
||||||
|
## More information
|
||||||
|
|
||||||
|
For more information:
|
||||||
|
|
||||||
|
* [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)
|
||||||
|
|
||||||
|
We use Discord as the main place for our discussions
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ dependencies:
|
|||||||
- sphinx-copybutton
|
- sphinx-copybutton
|
||||||
- sphinx-design
|
- sphinx-design
|
||||||
- sphinx-togglebutton
|
- sphinx-togglebutton
|
||||||
|
- nodejs=16
|
||||||
|
|
||||||
- pip:
|
- pip:
|
||||||
- sphinxemoji
|
- sphinxemoji
|
||||||
|
|||||||
225
docs/guides/custom-plugins.md
Normal file
225
docs/guides/custom-plugins.md
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
# Creating custom pyscript plugins
|
||||||
|
|
||||||
|
Pyscript has a few built-in plugins, but you can also create your own ones. This guide will show you how to develop both Javascript and Python plugins.
|
||||||
|
|
||||||
|
```{warning}
|
||||||
|
Pyscript plugins are currently under active development. The API is likely to go through breaking changes between releases.
|
||||||
|
```
|
||||||
|
|
||||||
|
You can add your custom plugins to the `<py-config>` tag on your page. For example:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<py-config>
|
||||||
|
plugins = ["http://example.com/hello-world.py"]
|
||||||
|
</py-config>
|
||||||
|
```
|
||||||
|
|
||||||
|
Currently, only single files with the extension `.py` and `.js` files can be used as plugins.
|
||||||
|
|
||||||
|
## Python plugins
|
||||||
|
|
||||||
|
Python plugins allow you to write plugins in pure Python. We first need to import `Plugin` from `pyscript` and create a new instance of it.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from pyscript import Plugin
|
||||||
|
|
||||||
|
plugin = Plugin("PyHelloWorld")
|
||||||
|
```
|
||||||
|
|
||||||
|
We can now create a new class containing our plugin code to add the text "Hello World" to the page.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from pyscript import Plugin, js
|
||||||
|
|
||||||
|
plugin = Plugin("PyHelloWorld")
|
||||||
|
|
||||||
|
class PyHelloWorld:
|
||||||
|
def __init__(self, element):
|
||||||
|
self.element = element
|
||||||
|
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
self.element.innerHTML = "<h1>Hello World!</h1>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Let's now create our `index.html` page and add the plugin.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Python Plugin</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://pyscript.net/unstable/pyscript.css" />
|
||||||
|
<script defer src="https://pyscript.net/unstable/pyscript.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<py-config>
|
||||||
|
plugins = ["./hello-world.py"]
|
||||||
|
</py-config>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we need to start a live server to serve our page. You can use Python's `http.server` module for this.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m http.server
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you can open your browser and go to `http://localhost:8000` to see the page. You might be surprised that the text "Hello World" is not on the page. This is because we need to do a few more things to make our plugin work.
|
||||||
|
|
||||||
|
First, we must create a custom element that our plugin will use. We can use a decorator in our `PyHelloWorld` class.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from pyscript import Plugin, js
|
||||||
|
|
||||||
|
plugin = Plugin("PyHelloWorld")
|
||||||
|
|
||||||
|
@plugin.register_custom_element("py-hello-world")
|
||||||
|
class PyHelloWorld:
|
||||||
|
def __init__(self, element):
|
||||||
|
self.element = element
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
self.element.innerHTML = "<div id='hello'>Hello World!</div>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Now that we have registered our custom element, we can use the custom tag `<py-hello-world>` to add our plugin to the page.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Python Plugin</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://pyscript.net/unstable/pyscript.css" />
|
||||||
|
<script defer src="https://pyscript.net/unstable/pyscript.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<py-config>
|
||||||
|
plugins = ["./hello-world.py"]
|
||||||
|
</py-config>
|
||||||
|
|
||||||
|
<py-hello-world></py-hello-world>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, if you go to `http://localhost:8000` you should see the text "Hello World" on the page.
|
||||||
|
|
||||||
|
Writing plugins in Python is an excellent way if you want to use PyScript's API's. However, if you want to write plugins in Javascript, you can do that too.
|
||||||
|
|
||||||
|
## Javascript plugins
|
||||||
|
|
||||||
|
Javascript plugins need to have a specific structure to be loaded by PyScript. The plugin export a default class with the following method, which may implement any, all, or none of the [Plugin lifecycle methods](https://github.com/pyscript/pyscript/blob/main/pyscriptjs/src/plugin.ts#L9-L65). These method will be called at the corresponding points in lifecycle of PyScript as it loads, configures itself and its Python interpreter, and executes `<py-script>` and `<py-repl>` tags.
|
||||||
|
|
||||||
|
```{note}
|
||||||
|
You need to specify the file extension `.js` when adding your custom plugin to the `<py-config>` tag.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating a Hello World plugin
|
||||||
|
|
||||||
|
Let's create a simple plugin that will add the text "Hello World" to the page. We will create a `hello-world.js` file and write the plugin class.
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default class HelloWorldPlugin {
|
||||||
|
afterStartup(runtime) {
|
||||||
|
// Code goes here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we need to add the code that will add the text to the page.
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default class HelloWorldPlugin {
|
||||||
|
afterStartup(runtime) {
|
||||||
|
const elem = document.createElement("h1");
|
||||||
|
elem.innerText = "Hello World";
|
||||||
|
document.body.appendChild(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally, we need to add the plugin to our page's `<py-config>` tag.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Javascript Plugin</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://pyscript.net/unstable/pyscript.css" />
|
||||||
|
<script defer src="https://pyscript.net/unstable/pyscript.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<py-config>
|
||||||
|
plugins = ["./hello-world.js"]
|
||||||
|
</py-config>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we need to start a live server to serve our page. You can use Python's `http.server` module for this.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m http.server
|
||||||
|
```
|
||||||
|
|
||||||
|
Now you can open your browser and go to `http://localhost:8000` to see the page. You should see the text "Hello World" on the page.
|
||||||
|
|
||||||
|
```{note}
|
||||||
|
Because we are using a local file, you must start a live server. Otherwise, Pyscript will not be able to fetch the file.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Expanding the Hello World plugin
|
||||||
|
|
||||||
|
As you can see, we could build all our plugin logic inside the `afterStartup` method. You may also want to create a custom html element for your plugin. Let's see how we can do that.
|
||||||
|
|
||||||
|
First, we need to create a custom html element. Let's start by creating our `PyHelloWorld` class that extends the `HTMLElement` class.
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
class PyHelloWorld extends HTMLElement {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
this.innerHTML = `<h1>Hello, world!</h1>`;
|
||||||
|
this.mount_name = this.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
We can now register our custom element in the `afterStartup` method of our `HelloWorldPlugin` class. We will also add the custom tag `py-hello-world` to the page.
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default class HelloWorldPlugin {
|
||||||
|
afterStartup(runtime) {
|
||||||
|
// Create a custom element called <py-hello-world>
|
||||||
|
customElements.define("py-hello-world", PyHelloWorld);
|
||||||
|
|
||||||
|
// Add the custom element to the page so we can see it
|
||||||
|
const elem = document.createElement('py-hello-world');
|
||||||
|
document.body.append(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we can open our page and see the custom element on the page.
|
||||||
|
|
||||||
|
By now, you should have a good idea for creating a custom plugin. Also, how powerful it can be to create custom elements that other users could use in their PyScript pages.
|
||||||
179
docs/guides/event-handlers.md
Normal file
179
docs/guides/event-handlers.md
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
# Event handlers in PyScript
|
||||||
|
|
||||||
|
PyScript offer two ways to subscribe to Javascript event handlers:
|
||||||
|
|
||||||
|
## Subscribe to event with `py-*` attributes
|
||||||
|
|
||||||
|
The value of the attribute contains python code which will be executed when the event is fired. A very common pattern is to call a function which does further work, for example:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<button id="noParam" py-click="say_hello_no_param()">
|
||||||
|
No Event - No Params py-click
|
||||||
|
</button>
|
||||||
|
<button id="withParam" py-click="say_hello_with_param('World')">
|
||||||
|
No Event - With Params py-click
|
||||||
|
</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
<py-script>
|
||||||
|
def say_hello_no_param():
|
||||||
|
print("Hello!")
|
||||||
|
|
||||||
|
def say_hello_with_param(name):
|
||||||
|
print("Hello " + name + "!")
|
||||||
|
</py-script>
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that py-\* attributes need a _function call_
|
||||||
|
|
||||||
|
Supported py-\* attributes can be seen in the [PyScript API reference](<[../api-reference.md](https://github.com/pyscript/pyscript/blob/66b57bf812dcc472ed6ffee075ace5ced89bbc7c/pyscriptjs/src/components/pyscript.ts#L119-L260)>).
|
||||||
|
|
||||||
|
## Subscribe to event with `addEventListener`
|
||||||
|
|
||||||
|
You can also subscribe to an event using the `addEventListener` method of the DOM element. This is useful if you want to pass event object to the event handler.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<button id="two">add_event_listener passes event</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
<py-script>
|
||||||
|
from js import console, document
|
||||||
|
from pyodide.ffi.wrappers import add_event_listener
|
||||||
|
|
||||||
|
def hello_args(*args):
|
||||||
|
console.log(f"Hi! I got some args! {args}")
|
||||||
|
|
||||||
|
add_event_listener(document.getElementById("two"), "click", hello_args)
|
||||||
|
</py-script>
|
||||||
|
```
|
||||||
|
|
||||||
|
or using the `addEventListener` method of the DOM element:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<button id="three">add_event_listener passes event</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
<py-script>
|
||||||
|
from js import console, document
|
||||||
|
from pyodide.ffi import create_proxy
|
||||||
|
|
||||||
|
def hello_args(*args):
|
||||||
|
console.log(f"Hi! I got some args! {args}")
|
||||||
|
|
||||||
|
document.getElementById("three").addEventListener("click", create_proxy(hello_args))
|
||||||
|
</py-script>
|
||||||
|
```
|
||||||
|
|
||||||
|
or using the PyScript Element class:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<button id="four">add_event_listener passes event</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
<py-script>
|
||||||
|
from js import console
|
||||||
|
from pyodide.ffi import create_proxy
|
||||||
|
|
||||||
|
def hello_args(*args):
|
||||||
|
console.log(f"Hi! I got some args! {args}")
|
||||||
|
|
||||||
|
Element("four").element.addEventListener("click", create_proxy(hello_args))
|
||||||
|
</py-script>
|
||||||
|
```
|
||||||
|
|
||||||
|
## JavaScript to PyScript and From PyScript to JavaScript
|
||||||
|
|
||||||
|
If you're wondering about how to pass objects from JavaScript to PyScript and/or the other way around head over to the [Passing Objects](passing-objects.md) page.
|
||||||
|
|
||||||
|
|
||||||
|
### Exporting all Global Python Objects
|
||||||
|
|
||||||
|
We can use our new `createObject` function to "export" the entire Python global object dictionary as a JavaScript object:
|
||||||
|
|
||||||
|
```python
|
||||||
|
<py-script>
|
||||||
|
from js import createObject
|
||||||
|
from pyodide.ffi import create_proxy
|
||||||
|
createObject(create_proxy(globals()), "pyodideGlobals")
|
||||||
|
</py-script>
|
||||||
|
```
|
||||||
|
|
||||||
|
This will make all Python global variables available in JavaScript with `pyodideGlobals.get('my_variable_name')`.
|
||||||
|
|
||||||
|
(Since PyScript tags evaluate _after_ all JavaScript on the page, we can't just dump a `console.log(...)` into a `<script>` tag, since that tag will evaluate before any PyScript has a chance to. We need to delay accessing the Python variable in JavaScript until after the Python code has a chance to run. The following example uses a button with `id="do-math"` to achieve this, but any method would be valid.)
|
||||||
|
|
||||||
|
```python
|
||||||
|
<py-script>
|
||||||
|
# create some Python objects:
|
||||||
|
symbols = {'pi': 3.1415926, 'e': 2.7182818}
|
||||||
|
|
||||||
|
def rough_exponential(x):
|
||||||
|
return symbols['e']**x
|
||||||
|
|
||||||
|
class Circle():
|
||||||
|
def __init__(self, radius):
|
||||||
|
self.radius = radius
|
||||||
|
|
||||||
|
@property
|
||||||
|
def area:
|
||||||
|
return symbols['pi'] * self.radius**2
|
||||||
|
</py-script>
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input type="button" value="Log Python Variables" id="do-mmath" />
|
||||||
|
<script>
|
||||||
|
document.getElementById("do-math").addEventListener("click", () => {
|
||||||
|
const exp = pyodideGlobals.get("rough_exponential");
|
||||||
|
console.log("e squared is about ${exp(2)}");
|
||||||
|
const c = pyodideGlobals.get("Circle")(4);
|
||||||
|
console.log("The area of c is ${c.area}");
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
### Exporting Individual Python Objects
|
||||||
|
|
||||||
|
We can also export individual Python objects to the JavaScript global scope if we wish.
|
||||||
|
|
||||||
|
(As above, the following example uses a button to delay the execution of the `<script>` until after the PyScript has run.)
|
||||||
|
|
||||||
|
```python
|
||||||
|
<py-script>
|
||||||
|
import js
|
||||||
|
from pyodide.ffi import create_proxy
|
||||||
|
|
||||||
|
# Create 3 python objects
|
||||||
|
language = "Python 3"
|
||||||
|
animals = ['dog', 'cat', 'bird']
|
||||||
|
multiply3 = lambda a, b, c: a * b * c
|
||||||
|
|
||||||
|
# js object can be named the same as Python objects...
|
||||||
|
js.createObject(language, "language")
|
||||||
|
|
||||||
|
# ...but don't have to be
|
||||||
|
js.createObject(create_proxy(animals), "animals_from_py")
|
||||||
|
|
||||||
|
# functions are objects too, in both Python and Javascript
|
||||||
|
js.createObject(create_proxy(multiply3), "multiply")
|
||||||
|
</py-script>
|
||||||
|
```
|
||||||
|
|
||||||
|
```html
|
||||||
|
<input type="button" value="Log Python Variables" id="log-python-variables" />
|
||||||
|
<script>
|
||||||
|
document
|
||||||
|
.getElementById("log-python-variables")
|
||||||
|
.addEventListener("click", () => {
|
||||||
|
console.log(`Nice job using ${language}`);
|
||||||
|
for (const animal of animals_from_py) {
|
||||||
|
console.log(`Do you like ${animal}s? `);
|
||||||
|
}
|
||||||
|
console.log(`2 times 3 times 4 is ${multiply(2, 3, 4)}`);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
```
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# How to make HTTP requests using `PyScript`, in pure Python
|
# How to make HTTP requests using `PyScript`, in pure Python
|
||||||
|
|
||||||
[Pyodide](https://pyodide.org), the runtime that underlies `PyScript`, does not have the `requests` module
|
[Pyodide](https://pyodide.org), the interpreter that underlies `PyScript`, does not have the `requests` module
|
||||||
(or other similar modules) available by default, which are traditionally used to make HTTP requests in Python.
|
(or other similar modules) available by default, which are traditionally used to make HTTP requests in Python.
|
||||||
However, it is possible to make HTTP requests in Pyodide using the modern `JavaScript` `fetch` API
|
However, it is possible to make HTTP requests in Pyodide using the modern `JavaScript` `fetch` API
|
||||||
([docs](https://developer.mozilla.org/en-US/docs/Web/API/fetch)). This example shows how to make common HTTP request
|
([docs](https://developer.mozilla.org/en-US/docs/Web/API/fetch)). This example shows how to make common HTTP request
|
||||||
@@ -35,7 +35,8 @@ for dealing with the response, such as `json()` or `status`. See the
|
|||||||
[FetchResponse documentation](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.FetchResponse)
|
[FetchResponse documentation](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.FetchResponse)
|
||||||
for more information.
|
for more information.
|
||||||
|
|
||||||
# Example
|
## Example
|
||||||
|
|
||||||
We will make async HTTP requests to [JSONPlaceholder](https://jsonplaceholder.typicode.com/)'s fake API using `pyfetch`.
|
We will make async HTTP requests to [JSONPlaceholder](https://jsonplaceholder.typicode.com/)'s fake API using `pyfetch`.
|
||||||
First we write a helper function in pure Python that makes a request and returns the response. This function
|
First we write a helper function in pure Python that makes a request and returns the response. This function
|
||||||
makes it easier to make specific types of requests with the most common parameters.
|
makes it easier to make specific types of requests with the most common parameters.
|
||||||
@@ -70,6 +71,7 @@ async def request(url: str, method: str = "GET", body: Optional[str] = None,
|
|||||||
response = await pyfetch(url, **kwargs)
|
response = await pyfetch(url, **kwargs)
|
||||||
return response
|
return response
|
||||||
```
|
```
|
||||||
|
|
||||||
This function is a wrapper for `pyfetch`, which is a wrapper for the `fetch` API. It is a coroutine function,
|
This function is a wrapper for `pyfetch`, which is a wrapper for the `fetch` API. It is a coroutine function,
|
||||||
so it must be awaited. It also has type hints, which are not required, but are useful for IDEs and other tools.
|
so it must be awaited. It also has type hints, which are not required, but are useful for IDEs and other tools.
|
||||||
The basic idea is that the `PyScript` will import and call this function, then await the response. Therefore,
|
The basic idea is that the `PyScript` will import and call this function, then await the response. Therefore,
|
||||||
@@ -160,7 +162,8 @@ concluding html code.
|
|||||||
The very first thing to notice is the `py-config` tag. This tag is used to import Python files into the `PyScript`.
|
The very first thing to notice is the `py-config` tag. This tag is used to import Python files into the `PyScript`.
|
||||||
In this case, we are importing the `request.py` file, which contains the `request` function we wrote above.
|
In this case, we are importing the `request.py` file, which contains the `request` function we wrote above.
|
||||||
|
|
||||||
### `py-script` tag for making async HTTP requests.
|
### `py-script` tag for making async HTTP requests
|
||||||
|
|
||||||
Next, the `py-script` tag contains the actual Python code where we import `asyncio` and `json`,
|
Next, the `py-script` tag contains the actual Python code where we import `asyncio` and `json`,
|
||||||
which are required or helpful for the `request` function.
|
which are required or helpful for the `request` function.
|
||||||
The `# GET`, `# POST`, `# PUT`, `# DELETE` blocks show examples of how to use the `request` function to make basic
|
The `# GET`, `# POST`, `# PUT`, `# DELETE` blocks show examples of how to use the `request` function to make basic
|
||||||
@@ -169,6 +172,7 @@ HTTP requests. The `await` keyword is required not only for the `request` functi
|
|||||||
faster ones.
|
faster ones.
|
||||||
|
|
||||||
### HTTP Requests
|
### HTTP Requests
|
||||||
|
|
||||||
HTTP requests are a very common way to communicate with a server. They are used for everything from getting data from
|
HTTP requests are a very common way to communicate with a server. They are used for everything from getting data from
|
||||||
a database, to sending emails, to authorization, and more. Due to safety concerns, files loaded from the
|
a database, to sending emails, to authorization, and more. Due to safety concerns, files loaded from the
|
||||||
local file system are not accessible by `PyScript`. Therefore, the proper way to load data into `PyScript` is also
|
local file system are not accessible by `PyScript`. Therefore, the proper way to load data into `PyScript` is also
|
||||||
@@ -182,31 +186,38 @@ function or to `pyfetch`. See the
|
|||||||
HTTP requests are defined by standards-setting bodies in [RFC 1945](https://www.rfc-editor.org/info/rfc1945) and
|
HTTP requests are defined by standards-setting bodies in [RFC 1945](https://www.rfc-editor.org/info/rfc1945) and
|
||||||
[RFC 9110](https://www.rfc-editor.org/info/rfc9110).
|
[RFC 9110](https://www.rfc-editor.org/info/rfc9110).
|
||||||
|
|
||||||
# Conclusion
|
## Conclusion
|
||||||
|
|
||||||
This tutorial demonstrates how to make HTTP requests using `pyfetch` and the `FetchResponse` objects. Importing Python
|
This tutorial demonstrates how to make HTTP requests using `pyfetch` and the `FetchResponse` objects. Importing Python
|
||||||
code/files into the `PyScript` using the `py-config` tag is also covered.
|
code/files into the `PyScript` using the `py-config` tag is also covered.
|
||||||
|
|
||||||
Although a simple example, the principals here can be used to create complex web applications inside of `PyScript`,
|
Although a simple example, the principals here can be used to create complex web applications inside of `PyScript`,
|
||||||
or load data into `PyScript` for use by an application, all served as a static HTML page, which is pretty amazing!
|
or load data into `PyScript` for use by an application, all served as a static HTML page, which is pretty amazing!
|
||||||
|
|
||||||
|
## API Quick Reference
|
||||||
|
|
||||||
# API Quick Reference
|
|
||||||
## pyodide.http.pyfetch
|
## pyodide.http.pyfetch
|
||||||
### Usage
|
|
||||||
|
### pyfetch Usage
|
||||||
|
|
||||||
```python
|
```python
|
||||||
await pyodide.http.pyfetch(url: str, **kwargs: Any) -> FetchResponse
|
await pyodide.http.pyfetch(url: str, **kwargs: Any) -> FetchResponse
|
||||||
```
|
```
|
||||||
|
|
||||||
Use `pyfetch` to make HTTP requests in `PyScript`. This is a wrapper around the `fetch` API. Returns a `FetchResponse`.
|
Use `pyfetch` to make HTTP requests in `PyScript`. This is a wrapper around the `fetch` API. Returns a `FetchResponse`.
|
||||||
|
|
||||||
- [`pyfetch` Docs.](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.pyfetch)
|
- [`pyfetch` Docs.](https://pyodide.org/en/stable/usage/api/python-api/http.html#pyodide.http.pyfetch)
|
||||||
|
|
||||||
## pyodide.http.FetchResponse
|
## pyodide.http.FetchResponse
|
||||||
### Usage
|
|
||||||
|
### FetchResponse Usage
|
||||||
|
|
||||||
```python
|
```python
|
||||||
response: pyodide.http.FetchResponse = await <pyfetch call>
|
response: pyodide.http.FetchResponse = await <pyfetch call>
|
||||||
status = response.status
|
status = response.status
|
||||||
json = await response.json()
|
json = await response.json()
|
||||||
```
|
```
|
||||||
|
|
||||||
Class for handling HTTP responses. This is a wrapper around the `JavaScript` fetch `Response`. Contains common (async)
|
Class for handling HTTP responses. This is a wrapper around the `JavaScript` fetch `Response`. Contains common (async)
|
||||||
methods and properties for handling HTTP responses, such as `json()`, `url`, `status`, `headers`, etc.
|
methods and properties for handling HTTP responses, such as `json()`, `url`, `status`, `headers`, etc.
|
||||||
|
|
||||||
|
|||||||
@@ -17,4 +17,6 @@ caption: 'Contents:'
|
|||||||
passing-objects
|
passing-objects
|
||||||
http-requests
|
http-requests
|
||||||
asyncio
|
asyncio
|
||||||
|
custom-plugins
|
||||||
|
event-handlers
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# How to Pass Objects from PyScript to Javascript (and Vice Versa)
|
# How to Pass Objects from PyScript to Javascript (and Vice Versa)
|
||||||
|
|
||||||
[Pyodide](https://pyodide.org), the runtime that underlies PyScript, does a lot of work under the hood to translate objects between Python and JavaScript. This allows code in one language to access objects defined in the other.
|
[Pyodide](https://pyodide.org), the interpreter that underlies PyScript, does a lot of work under the hood to translate objects between Python and JavaScript. This allows code in one language to access objects defined in the other.
|
||||||
|
|
||||||
This guide discusses how to pass objects between JavaScript and Python within PyScript. For more details on how Pyodide handles translating and proxying objects between the two languages, see the [Pyodide Type Translations Page](https://pyodide.org/en/stable/usage/type-conversions.html).
|
This guide discusses how to pass objects between JavaScript and Python within PyScript. For more details on how Pyodide handles translating and proxying objects between the two languages, see the [Pyodide Type Translations Page](https://pyodide.org/en/stable/usage/type-conversions.html).
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ We can use the syntax `from js import ...` to import JavaScript objects directly
|
|||||||
|
|
||||||
### Using Pyodide's globals access
|
### Using Pyodide's globals access
|
||||||
|
|
||||||
The [PyScript JavaScript module](../reference/modules/pyscript.md) exposes its underlying Pyodide runtime as `PyScript.runtime`, and maintains a reference to the [globals()](https://docs.python.org/3/library/functions.html#globals) dictionary of the Python namespace. Thus, any global variables in python are accessible in JavaScript at `PyScript.runtime.globals.get('my_variable_name')`
|
The [PyScript JavaScript module](../reference/modules/pyscript.md) exposes its underlying Pyodide interpreter as `PyScript.interpreter`, and maintains a reference to the [globals()](https://docs.python.org/3/library/functions.html#globals) dictionary of the Python namespace. Thus, any global variables in python are accessible in JavaScript at `PyScript.interpreter.globals.get('my_variable_name')`
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<body>
|
<body>
|
||||||
@@ -45,7 +45,7 @@ The [PyScript JavaScript module](../reference/modules/pyscript.md) exposes its
|
|||||||
<button onclick="showX()">Click Me to Get 'x' from Python</button>
|
<button onclick="showX()">Click Me to Get 'x' from Python</button>
|
||||||
<script>
|
<script>
|
||||||
function showX(){
|
function showX(){
|
||||||
console.log(`In Python right now, x = ${pyscript.runtime.globals.get('x')}`)
|
console.log(`In Python right now, x = ${pyscript.interpreter.globals.get('x')}`)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
@@ -59,7 +59,7 @@ Since [everything is an object](https://docs.python.org/3/reference/datamodel.ht
|
|||||||
<button onclick="sortInPython(['Candy', 'Donut', 'Apple', 'Banana'])">Sort In Python And Log</button>
|
<button onclick="sortInPython(['Candy', 'Donut', 'Apple', 'Banana'])">Sort In Python And Log</button>
|
||||||
<script>
|
<script>
|
||||||
function sortInPython(data){
|
function sortInPython(data){
|
||||||
js_sorted = pyscript.runtime.globals.get('sorted') //grab python's 'sorted' function
|
js_sorted = pyscript.interpreter.globals.get('sorted') //grab python's 'sorted' function
|
||||||
const sorted_data = js_sorted(data) //apply the function to the 'data' argument
|
const sorted_data = js_sorted(data) //apply the function to the 'data' argument
|
||||||
for (const item of sorted_data){
|
for (const item of sorted_data){
|
||||||
console.log(item)
|
console.log(item)
|
||||||
@@ -71,7 +71,7 @@ Since [everything is an object](https://docs.python.org/3/reference/datamodel.ht
|
|||||||
|
|
||||||
### Using JavaScript's eval()
|
### Using JavaScript's eval()
|
||||||
|
|
||||||
There may be some situations where it isn't possible or ideal to use `PyScript.runtime.globals.get()` to retrieve a variable from the Pyodide global dictionary. For example, some JavaScript frameworks may take a function/Callable as an html attribute in a context where code execution isn't allowed (i.e. `get()` fails). In these cases, you can create JavaScript proxies of Python objects more or less "manually" using [JavaScript's eval() function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval), which executes a string as code much like [Python's eval()](https://docs.python.org/3/library/functions.html#eval).
|
There may be some situations where it isn't possible or ideal to use `PyScript.interpreter.globals.get()` to retrieve a variable from the Pyodide global dictionary. For example, some JavaScript frameworks may take a function/Callable as an html attribute in a context where code execution isn't allowed (i.e. `get()` fails). In these cases, you can create JavaScript proxies of Python objects more or less "manually" using [JavaScript's eval() function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval), which executes a string as code much like [Python's eval()](https://docs.python.org/3/library/functions.html#eval).
|
||||||
|
|
||||||
First, we create a JS function `createObject` which takes an object and a string, then uses `eval()` to create a variable named after the string and bind it to that object. By calling this function from PyScript (where we have access to the Pyodide global namespace), we can bind JavaScript variables to Python objects without having direct access to that global namespace.
|
First, we create a JS function `createObject` which takes an object and a string, then uses `eval()` to create a variable named after the string and bind it to that object. By calling this function from PyScript (where we have access to the Pyodide global namespace), we can bind JavaScript variables to Python objects without having direct access to that global namespace.
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,24 @@
|
|||||||
|
|
||||||
Welcome to the PyScript documentation!
|
Welcome to the PyScript documentation!
|
||||||
|
|
||||||
PyScript provides a way for you to run Python code directly in your browser, giving
|
PyScript is a programming platform that allows you to create web applications that run in the browser, using Python.
|
||||||
anyone the ability to program without infrastructure barriers. Add an interactive
|
That creates some really interesting benefits:
|
||||||
Python REPL directly to your website, share an interactive dashboard with a colleague
|
|
||||||
as an HTML file, or create a client-side Python-powered web application. This documentation
|
* Using Python directly in the browser allows to create applications with an easier and more user friendly language
|
||||||
will show you how.
|
* Scalability: since applications run directly in the browser and not on a server somewhere, servers don't need to
|
||||||
|
scale as much if the number of users of an application grows exponentially
|
||||||
|
* Shareability: applications can be shared as easily as sharing an URL. Can't get easier than that ;)
|
||||||
|
* Multi-Platform support: since the browser is the underlying system where PyScript applications run, applications
|
||||||
|
can run anywhere a modern browser is installed, on windows, linux, mac, mobile, or even a Tesla! :)
|
||||||
|
* Security: since PyScript runs core in the Browser (via Web Assembly) in a sandbox fashion and the browsers offers
|
||||||
|
a very strict level of security, code never have access files or part of the underlying system without user permission,
|
||||||
|
making it a great option in terms of security.
|
||||||
|
* User Friendly APIs: web APIs are very vast and, sometimes, complicated. PyScript offers smaller and more user friendly
|
||||||
|
APIs for the most common use cases while also providing an option to access the full Web APIs as well.
|
||||||
|
|
||||||
|
We hope you'll enjoy the project and create so many incredible things with it! To learn more, consult our documentation.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
::::{grid} 2
|
::::{grid} 2
|
||||||
:gutter: 3
|
:gutter: 3
|
||||||
@@ -54,4 +67,5 @@ tutorials/index
|
|||||||
guides/index
|
guides/index
|
||||||
concepts/index
|
concepts/index
|
||||||
reference/index
|
reference/index
|
||||||
|
changelog
|
||||||
```
|
```
|
||||||
|
|||||||
85
docs/reference/API/attr_to_event.md
Normal file
85
docs/reference/API/attr_to_event.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
# List of PyScript Attributes to Events:
|
||||||
|
|
||||||
|
PyScript provides a convenient syntax for mapping JavaScript events to PyScript events, making it easy to connect events to HTML tags.
|
||||||
|
|
||||||
|
For example, you can use the following code to connect the click event to a button:
|
||||||
|
|
||||||
|
```
|
||||||
|
<button id="py-click" py-click="foo()">Click me</button>
|
||||||
|
```
|
||||||
|
|
||||||
|
Here is a list of all the available event mappings:
|
||||||
|
|
||||||
|
| PyScript Event Name | DOM Event Name |
|
||||||
|
|-------------------|----------------|
|
||||||
|
| py-afterprint | afterprint |
|
||||||
|
| py-beforeprint | beforeprint |
|
||||||
|
| py-beforeunload | beforeunload |
|
||||||
|
| py-error | error |
|
||||||
|
| py-hashchange | hashchange |
|
||||||
|
| py-load | load |
|
||||||
|
| py-message | message |
|
||||||
|
| py-offline | offline |
|
||||||
|
| py-online | online |
|
||||||
|
| py-pagehide | pagehide |
|
||||||
|
| py-pageshow | pageshow |
|
||||||
|
| py-popstate | popstate |
|
||||||
|
| py-resize | resize |
|
||||||
|
| py-storage | storage |
|
||||||
|
| py-unload | unload |
|
||||||
|
| py-blur | blur |
|
||||||
|
| py-change | change |
|
||||||
|
| py-contextmenu | contextmenu |
|
||||||
|
| py-focus | focus |
|
||||||
|
| py-input | input |
|
||||||
|
| py-invalid | invalid |
|
||||||
|
| py-reset | reset |
|
||||||
|
| py-search | search |
|
||||||
|
| py-select | select |
|
||||||
|
| py-submit | submit |
|
||||||
|
| py-keydown | keydown |
|
||||||
|
| py-keypress | keypress |
|
||||||
|
| py-keyup | keyup |
|
||||||
|
| py-click | click |
|
||||||
|
| py-dblclick | dblclick |
|
||||||
|
| py-mousedown | mousedown |
|
||||||
|
| py-mousemove | mousemove |
|
||||||
|
| py-mouseout | mouseout |
|
||||||
|
| py-mouseover | mouseover |
|
||||||
|
| py-mouseup | mouseup |
|
||||||
|
| py-mousewheel | mousewheel |
|
||||||
|
| py-wheel | wheel |
|
||||||
|
| py-drag | drag |
|
||||||
|
| py-dragend | dragend |
|
||||||
|
| py-dragenter | dragenter |
|
||||||
|
| py-dragleave | dragleave |
|
||||||
|
| py-dragover | dragover |
|
||||||
|
| py-dragstart | dragstart |
|
||||||
|
| py-drop | drop |
|
||||||
|
| py-scroll | scroll |
|
||||||
|
| py-copy | copy |
|
||||||
|
| py-cut | cut |
|
||||||
|
| py-paste | paste |
|
||||||
|
| py-abort | abort |
|
||||||
|
| py-canplay | canplay |
|
||||||
|
| py-canplaythrough | canplaythrough |
|
||||||
|
| py-cuechange | cuechange |
|
||||||
|
| py-durationchange | durationchange |
|
||||||
|
| py-emptied | emptied |
|
||||||
|
| py-ended | ended |
|
||||||
|
| py-loadeddata | loadeddata |
|
||||||
|
| py-loadedmetadata | loadedmetadata |
|
||||||
|
| py-loadstart | loadstart |
|
||||||
|
| py-pause | pause |
|
||||||
|
| py-play | play |
|
||||||
|
| py-playing | playing |
|
||||||
|
| py-progress | progress |
|
||||||
|
| py-ratechange | ratechange |
|
||||||
|
| py-seeked | seeked |
|
||||||
|
| py-seeking | seeking |
|
||||||
|
| py-stalled | stalled |
|
||||||
|
| py-suspend | suspend |
|
||||||
|
| py-timeupdate | timeupdate |
|
||||||
|
| py-volumechange | volumechange |
|
||||||
|
| py-waiting | waiting |
|
||||||
|
| py-toggle | toggle |
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
`*values` - the objects to be displayed. String objects are output as-written. For non-string objects, the default content to display is the the object's `repr()`. Objects may implement the following methods to indicate that they should be displayed as a different MIME type. MIME types with a * indicate that the content will be wrapped in the appropriate html tags and attributes before output:
|
`*values` - the objects to be displayed. String objects are output as-written. For non-string objects, the default content to display is the the object's {py:func}`repr`. Objects may implement the following methods to indicate that they should be displayed as a different MIME type. MIME types with a * indicate that the content will be wrapped in the appropriate html tags and attributes before output:
|
||||||
|
|
||||||
|
|
||||||
| Method | Inferred MIME type |
|
| Method | Inferred MIME type |
|
||||||
|---------------------|------------------------|
|
|---------------------|------------------------|
|
||||||
@@ -34,7 +35,7 @@ Display will throw an exception if the target is not clear. E.g. the following c
|
|||||||
# from event handlers
|
# from event handlers
|
||||||
display('hello')
|
display('hello')
|
||||||
</py-script>
|
</py-script>
|
||||||
<button id="my-button" py-onClick="display_hello()">Click me</button>
|
<button id="my-button" py-click="display_hello()">Click me</button>
|
||||||
```
|
```
|
||||||
|
|
||||||
Because it's considered unclear if the `hello` string should be displayed underneath the `<py-script>` tag or the `<button>` tag.
|
Because it's considered unclear if the `hello` string should be displayed underneath the `<py-script>` tag or the `<button>` tag.
|
||||||
@@ -44,12 +45,11 @@ To write compliant code, make sure to specify the target using the `target` para
|
|||||||
```html
|
```html
|
||||||
<py-script>
|
<py-script>
|
||||||
def display_hello():
|
def display_hello():
|
||||||
# this fails because we don't have any implicit target
|
# this works because we give an explicit target
|
||||||
# from event handlers
|
|
||||||
display('hello', target="helloDiv")
|
display('hello', target="helloDiv")
|
||||||
</py-script>
|
</py-script>
|
||||||
<div id="helloDiv"></div>
|
<div id="helloDiv"></div>
|
||||||
<button id="my-button" py-onClick="display_hello()">Click me</button>
|
<button id="my-button" py-click="display_hello()">Click me</button>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Using matplotlib with display
|
#### Using matplotlib with display
|
||||||
|
|||||||
51
docs/reference/API/when.md
Normal file
51
docs/reference/API/when.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# `@when`
|
||||||
|
|
||||||
|
`@when(event_type:str = None, selector:str = None)`
|
||||||
|
|
||||||
|
The `@when` decorator attaches the decorated function or Callable as an event handler for selected objects on the page. That is, when the named event is emitted by the selected DOM elements, the decorated Python function will be called.
|
||||||
|
|
||||||
|
If the decorated function takes a single (non-self) argument, it will be passed the [Event object](https://developer.mozilla.org/en-US/docs/Web/API/Event) corresponding to the triggered event. If the function takes no (non-self) argument, it will be called with no arguments.
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
|
||||||
|
`event_type` - A string representing the event type to match against. This can be any of the [https://developer.mozilla.org/en-US/docs/Web/Events#event_listing](https://developer.mozilla.org/en-US/docs/Web/Events) that HTML elements may emit, as appropriate to their element type.
|
||||||
|
|
||||||
|
`selector` = A string containing one or more [CSS selectors](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors). The selected DOM elements will have the decorated function attacehed as an event handler.
|
||||||
|
|
||||||
|
## Examples:
|
||||||
|
|
||||||
|
The following example prints "Hello, world!" whenever the button is clicked. It demonstrates using the `@when` decorator on a Callable which takes no arguments:
|
||||||
|
|
||||||
|
```html
|
||||||
|
<button id="my_btn">Click Me to Say Hi</button>
|
||||||
|
<py-script>
|
||||||
|
from pyscript import when
|
||||||
|
@when("click", selector="#my_btn")
|
||||||
|
def say_hello():
|
||||||
|
print(f"Hello, world!")
|
||||||
|
</py-script>
|
||||||
|
```
|
||||||
|
|
||||||
|
The following example includes three buttons - when any of the buttons is clicked, that button turns green, and the remaining two buttons turn red. This demonstrates using the `@when` decorator on a Callable which takes one argument, which is then passed the Event object from the associated event. When combined with the ability to look at other elements in on the page, this is quite a powerful feature.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<div id="container">
|
||||||
|
<button>First</button>
|
||||||
|
<button>Second</button>
|
||||||
|
<button>Third</button>
|
||||||
|
</div>
|
||||||
|
<py-script>
|
||||||
|
from pyscript import when
|
||||||
|
import js
|
||||||
|
|
||||||
|
@when("click", selector="#container button")
|
||||||
|
def highlight(evt):
|
||||||
|
#Set the clicked button's background to green
|
||||||
|
evt.target.style.backgroundColor = 'green'
|
||||||
|
|
||||||
|
#Set the background of all buttons to red
|
||||||
|
other_buttons = (button for button in js.document.querySelectorAll('button') if button != evt.target)
|
||||||
|
for button in other_buttons:
|
||||||
|
button.style.backgroundColor = 'red'
|
||||||
|
</py-script>
|
||||||
|
```
|
||||||
@@ -8,10 +8,10 @@ The `<py-config>` element should be placed within the `<body>` element.
|
|||||||
|
|
||||||
## Attributes
|
## Attributes
|
||||||
|
|
||||||
| attribute | type | default | description |
|
| attribute | type | default | description |
|
||||||
|-----------|--------|---------|---------------------------------------------------------------------------------------------------------|
|
|-----------|--------|---------|----------------------------------------------------------------------------------------------------------|
|
||||||
| **type** | string | "toml" | Syntax type of the `<py-config>`. Value can be `json` or `toml`. Default: "toml" if type is unspecifed. |
|
| **type** | string | "toml" | Syntax type of the `<py-config>`. Value can be `json` or `toml`. Default: "toml" if type is unspecified. |
|
||||||
| **src** | url | | Source url to an external configuration file. |
|
| **src** | url | | Source url to an external configuration file. |
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ The `<py-config>` element should be placed within the `<body>` element.
|
|||||||
- `<py-config>` using TOML (default)
|
- `<py-config>` using TOML (default)
|
||||||
|
|
||||||
```{note}
|
```{note}
|
||||||
Reminder: when using TOML, any Arrays of Tables defined with double-brackets (like `[[runtimes]]` and `[[fetch]]` must come after individual keys (like `plugins = ...` and `packages=...`)
|
Reminder: when using TOML, any Arrays of Tables defined with double-brackets (like `[[interpreters]]` and `[[fetch]]` must come after individual keys (like `plugins = ...` and `packages=...`)
|
||||||
```
|
```
|
||||||
|
|
||||||
```html
|
```html
|
||||||
@@ -28,7 +28,7 @@ Reminder: when using TOML, any Arrays of Tables defined with double-brackets (li
|
|||||||
[splashscreen]
|
[splashscreen]
|
||||||
autoclose = true
|
autoclose = true
|
||||||
|
|
||||||
[[runtimes]]
|
[[interpreters]]
|
||||||
src = "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js"
|
src = "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js"
|
||||||
name = "pyodide-0.21.2"
|
name = "pyodide-0.21.2"
|
||||||
lang = "python"
|
lang = "python"
|
||||||
@@ -43,7 +43,7 @@ Reminder: when using TOML, any Arrays of Tables defined with double-brackets (li
|
|||||||
"splashscreen": {
|
"splashscreen": {
|
||||||
"autoclose": true
|
"autoclose": true
|
||||||
},
|
},
|
||||||
"runtimes": [{
|
"interpreters": [{
|
||||||
"src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js",
|
"src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js",
|
||||||
"name": "pyodide-0.21.2",
|
"name": "pyodide-0.21.2",
|
||||||
"lang": "python"
|
"lang": "python"
|
||||||
@@ -65,7 +65,7 @@ where `custom.toml` contains
|
|||||||
[splashscreen]
|
[splashscreen]
|
||||||
autoclose = true
|
autoclose = true
|
||||||
|
|
||||||
[[runtimes]]
|
[[interpreters]]
|
||||||
src = "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js"
|
src = "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js"
|
||||||
name = "pyodide-0.21.2"
|
name = "pyodide-0.21.2"
|
||||||
lang = "python"
|
lang = "python"
|
||||||
@@ -83,7 +83,7 @@ where `custom.json` contains
|
|||||||
"splashscreen": {
|
"splashscreen": {
|
||||||
"autoclose": true,
|
"autoclose": true,
|
||||||
},
|
},
|
||||||
"runtimes": [{
|
"interpreters": [{
|
||||||
"src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js",
|
"src": "https://cdn.jsdelivr.net/pyodide/v0.21.2/full/pyodide.js",
|
||||||
"name": "pyodide-0.21.2",
|
"name": "pyodide-0.21.2",
|
||||||
"lang": "python"
|
"lang": "python"
|
||||||
@@ -127,7 +127,7 @@ The keys supplied through `inline` override the values present in config supplie
|
|||||||
One can also declare dependencies so as to get access to many 3rd party OSS packages that are supported by PyScript.
|
One can also declare dependencies so as to get access to many 3rd party OSS packages that are supported by PyScript.
|
||||||
You can also link to `.whl` files directly on disk like in our [toga example](https://github.com/pyscript/pyscript/blob/main/examples/toga/freedom.html).
|
You can also link to `.whl` files directly on disk like in our [toga example](https://github.com/pyscript/pyscript/blob/main/examples/toga/freedom.html).
|
||||||
|
|
||||||
Package dependencies in the `<py-config>` can be declared by using the direct link to the package URL (whl or any other format supported by the chosen runtime) or by just providing the package name [and version]. If only the name [and version] are provided, packages will be installed directly from what's provided by your runtime or from PyPI.
|
Package dependencies in the `<py-config>` can be declared by using the direct link to the package URL (whl or any other format supported by the chosen interpreter) or by just providing the package name [and version]. If only the name [and version] are provided, packages will be installed directly from what's provided by your interpreter or from PyPI.
|
||||||
|
|
||||||
NOTICE that only pure python packages from PyPI will work and packages with C dependencies will not. These need to be built specifically for WASM (please, consult the Pyodide project for more information about what's supported and on how to build packages with C dependencies)
|
NOTICE that only pure python packages from PyPI will work and packages with C dependencies will not. These need to be built specifically for WASM (please, consult the Pyodide project for more information about what's supported and on how to build packages with C dependencies)
|
||||||
|
|
||||||
@@ -246,7 +246,8 @@ The following optional values are supported by `<py-config>`:
|
|||||||
| `packages` | List of Packages | Dependencies on 3rd party OSS packages are specified here. The default value is an empty list. |
|
| `packages` | List of Packages | Dependencies on 3rd party OSS packages are specified here. The default value is an empty list. |
|
||||||
| `fetch` | List of Stuff to fetch | Local Python modules OR resources from the internet are to be specified here using a Fetch Configuration, described below. The default value is an empty list. |
|
| `fetch` | List of Stuff to fetch | Local Python modules OR resources from the internet are to be specified here using a Fetch Configuration, described below. The default value is an empty list. |
|
||||||
| `plugins` | List of Plugins | List of Plugins are to be specified here. The default value is an empty list. |
|
| `plugins` | List of Plugins | List of Plugins are to be specified here. The default value is an empty list. |
|
||||||
| `runtimes` | List of Runtimes | List of runtime configurations, described below. The default value contains a single Pyodide based runtime. |
|
| `interpreters` | List of Interpreters| List of Interpreter configurations, described below. The default value contains a single Pyodide based interpreter. **Note:** Currently, only a single interpreter is supported. |
|
||||||
|
| `runtimes` {bdg-warning-line}`Deprecated` | List of Runtimes | This value is deprecated, please use `interpreters`. List of runtime configurations, described below. The default value contains a single Pyodide based interpreter. |
|
||||||
|
|
||||||
### <a name="fetch">Fetch</a>
|
### <a name="fetch">Fetch</a>
|
||||||
|
|
||||||
@@ -440,28 +441,33 @@ content/
|
|||||||
</py-script>
|
</py-script>
|
||||||
```
|
```
|
||||||
|
|
||||||
### Runtime
|
### Interpreter
|
||||||
|
|
||||||
|
An interpreter configuration consists of the following:
|
||||||
|
|
||||||
A runtime configuration consists of the following:
|
|
||||||
| Value | Type | Description |
|
| Value | Type | Description |
|
||||||
|--------|-------------------|-------------|
|
|--------|-------------------|-------------|
|
||||||
| `src` | string (Required) | URL to the runtime source. |
|
| `src` | string (Required) | URL to the interpreter source. |
|
||||||
| `name` | string | Name of the runtime. This field can be any string and is to be used by the application author for their own customization purposes |
|
| `name` | string | Name of the interpreter. This field can be any string and is to be used by the application author for their own customization purposes |
|
||||||
| `lang` | string | Programming language supported by the runtime. This field can be used by the application author to provide clarification. It currently has no implications on how PyScript behaves. |
|
| `lang` | string | Programming language supported by the interpreter. This field can be used by the application author to provide clarification. It currently has no implications on how PyScript behaves. |
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
- The default runtime is `pyodide`, another version of which can be specified as following
|
- The default interpreter is `pyodide`, another version of which can be specified as following
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<py-config>
|
<py-config>
|
||||||
[[runtimes]]
|
[[interpreters]]
|
||||||
src = "https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js"
|
src = "https://cdn.jsdelivr.net/pyodide/v0.20.0/full/pyodide.js"
|
||||||
name = "pyodide-0.20.0"
|
name = "pyodide-0.20.0"
|
||||||
lang = "python"
|
lang = "python"
|
||||||
</py-config>
|
</py-config>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```{note}
|
||||||
|
Currently, PyScript supports a single interpreter, this may change in the future.
|
||||||
|
```
|
||||||
|
|
||||||
## Supplying extra information (or metadata)
|
## Supplying extra information (or metadata)
|
||||||
|
|
||||||
Besides the above schema, a user can also supply any extra keys and values that are relevant as metadata information or perhaps are being used within the application.
|
Besides the above schema, a user can also supply any extra keys and values that are relevant as metadata information or perhaps are being used within the application.
|
||||||
|
|||||||
@@ -4,27 +4,59 @@ The `<py-repl>` element provides a REPL(Read Eval Print Loop) to evaluate multi-
|
|||||||
|
|
||||||
## Attributes
|
## Attributes
|
||||||
|
|
||||||
| attribute | type | default | description |
|
| attribute | type | default | description |
|
||||||
|-------------------|---------|---------|---------------------------------------|
|
|-------------------|---------|---------|--------------------------------------|
|
||||||
| **auto-generate** | boolean | | Auto-generates REPL after evaluation |
|
| **auto-generate** | boolean | | Auto-generates REPL after evaluation |
|
||||||
| **output** | string | | The element to write output into |
|
| **output-mode** | string | "" | Determines whether the output element is cleared prior to writing output |
|
||||||
|
| **output** | string | | The id of the element to write `stdout` and `stderr` to |
|
||||||
|
| **stderr** | string | | The id of the element to write `stderr` to |
|
||||||
|
| **src** | string | | Resource to be preloaded into the REPL |
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
#### `<py-repl>` element set to auto-generate
|
### `auto-generate`
|
||||||
|
If a \<py-repl\> tag has the `auto-generate` attribute, upon execution, another \<pr-repl\> tag will be created and added to the DOM as a sibling of the current tag.
|
||||||
|
|
||||||
|
### `output-mode`
|
||||||
|
By default, the element which displays the output from a REPL is cleared (`innerHTML` set to "") prior to each new execution of the REPL. If `output-mode` == "append", that element is not cleared, and the output is appended instead.
|
||||||
|
|
||||||
|
### `output`
|
||||||
|
The ID of an element in the DOM that `stdout` (e.g. `print()`), `stderr`, and the results of executing the repl are written to. Defaults to an automatically-generated \<div\> as the next sibling of the REPL itself.
|
||||||
|
|
||||||
|
### `stderr`
|
||||||
|
The ID of an element in the DOM that `stderr` will be written to. Defaults to None, though writes to `stderr` will still appear in the location specified by `output`.
|
||||||
|
|
||||||
|
### `src`
|
||||||
|
If a \<py-repl\> tag has the `src` attribute, during page initialization, resource in the `src` will be preloaded into the REPL. Please note that this will not run in advance. If there is content in the \<py-repl\> tag, it will be cleared and replaced with preloaded resource.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### `<py-repl>` element set to auto-generate
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<py-repl auto-generate="true"> </py-repl>
|
<py-repl auto-generate="true"> </py-repl>
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `<py-repl>` element with output
|
### `<py-repl>` element with output
|
||||||
|
|
||||||
|
The following will write "Hello! World!" to the div with id `replOutput`.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<div id="replOutput"></div>
|
<div id="replOutput"></div>
|
||||||
<py-repl output="replOutput">
|
<py-repl output="replOutput">
|
||||||
hello = "Hello world!"
|
print("Hello!")
|
||||||
|
hello = "World!"
|
||||||
hello
|
hello
|
||||||
</py-repl>
|
</py-repl>
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that if we `print` any element in the repl, the output will be printed in the [`py-terminal`](../plugins/py-terminal.md) if is enabled.
|
Note that if we `print` from the REPL (or otherwise write to `sys.stdout`), the output will be printed in the [`py-terminal`](../plugins/py-terminal.md) if is enabled.
|
||||||
|
|
||||||
|
### `<py-repl>` element with src
|
||||||
|
Preload resource from src into the REPL
|
||||||
|
```html
|
||||||
|
<py-repl id="py-repl" output="replOutput" src="./src/py/py_code.py">
|
||||||
|
If a py-repl tag has the src attribute,
|
||||||
|
the content here will be cleared and replaced.
|
||||||
|
</py-repl>
|
||||||
|
<div id="replOutput"></div>
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,12 +1,27 @@
|
|||||||
# <py-script>
|
# <py-script>
|
||||||
|
|
||||||
The `<py-script>` element lets you execute multi-line Python scripts both inline and via a src attribute.
|
The `<py-script>` element, also available as `<script type="py-script">`, lets you execute multi-line Python scripts both inline and via a src attribute.
|
||||||
|
|
||||||
## Attributes
|
## Attributes
|
||||||
|
|
||||||
| attribute | type | default | description |
|
| attribute | type | default | description |
|
||||||
|-----------|------|---------|------------------------------|
|
|-----------|--------|---------|------------------------------|
|
||||||
| **src** | url | | Url of a python source file. |
|
| **src** | url | | You don't need to add long python code in py-script, you can provide url of the python source file in the py-script tag with the `src` attribute. When a Python file is referred with the `src` attribute it is executed, and then added to the namespace where it was referred. |
|
||||||
|
| **output**| string | | The id of a DOM element to route `sys.stdout` and `stderr` to, in addition to sending it to the `<py-terminal>`|
|
||||||
|
| **stderr**| string | | The id of a DOM element to route just `sys.stderr` to, in addition to sending it to the `<py-terminal>`|
|
||||||
|
|
||||||
|
### output
|
||||||
|
|
||||||
|
If the `output` attribute is provided, any output to [sys.stdout](https://docs.python.org/3/library/sys.html#sys.stdout) or [sys.stderr](https://docs.python.org/3/library/sys.html#sys.stderr) is written to the DOM element with the ID matching the attribute. If no DOM element is found with a matching ID, a warning is shown. The msg is output to the `innerHTML` of the HTML Element, with newlines (`\n'`) converted to breaks (`<br/>`).
|
||||||
|
|
||||||
|
This output is in addition to the output being written to the developer console and the `<py-terminal>` if it is being used.
|
||||||
|
|
||||||
|
### stderr
|
||||||
|
|
||||||
|
If the `stderr` attribute is provided, any output to [sys.stderr](https://docs.python.org/3/library/sys.html#sys.stderr) is written to the DOM element with the ID matching the attribute. If no DOM element is found with a matching ID, a warning is shown. The msg is output to the `innerHTML` of the HTML Element, with newlines (`\n'`) converted to breaks (`<br/>`).
|
||||||
|
|
||||||
|
This output is in addition to the output being written to the developer console and the `<py-terminal>` if it is being used.
|
||||||
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ This reference guide contains the error codes you might find and a description o
|
|||||||
|------------|--------------------------------|--------------------|
|
|------------|--------------------------------|--------------------|
|
||||||
| PY1000 | Invalid configuration supplied | Confirm that your `py-config` tag is using a valid `TOML` or `JSON` syntax and is using the correct configuration type. |
|
| PY1000 | Invalid configuration supplied | Confirm that your `py-config` tag is using a valid `TOML` or `JSON` syntax and is using the correct configuration type. |
|
||||||
| PY1001 | Unable to install package(s) | Confirm that the package contains a pure Python 3 wheel or the name of the package is correct. |
|
| PY1001 | Unable to install package(s) | Confirm that the package contains a pure Python 3 wheel or the name of the package is correct. |
|
||||||
|
| PY2000 | Invalid plugin file extension | Only `.js` and `.py` files can be used when loading user plugins. Please confirm your path contains the file extension. |
|
||||||
|
| PY2001 | Plugin doesn't contain a default export | Please add `export default` to the main plugin class. |
|
||||||
| PY9000 | Top level await is deprecated | Create a coroutine with your code and schedule it with `asyncio.ensure_future` or similar |
|
| PY9000 | Top level await is deprecated | Create a coroutine with your code and schedule it with `asyncio.ensure_future` or similar |
|
||||||
|
|
||||||
|
|
||||||
@@ -37,3 +39,14 @@ Pyscript cannot install the package(s) you specified in your `py-config` tag. Th
|
|||||||
- An error occurred while trying to install the package
|
- An error occurred while trying to install the package
|
||||||
|
|
||||||
An error banner should appear on your page with the error code and a description of the error or a traceback. You can also check the developer console for more information.
|
An error banner should appear on your page with the error code and a description of the error or a traceback. You can also check the developer console for more information.
|
||||||
|
|
||||||
|
## PY2001
|
||||||
|
|
||||||
|
Javascript plugins must export a default class. This is required for PyScript to be able to load the plugin. Please add `export default` to the main plugin class. For example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default class HelloWorldPlugin {
|
||||||
|
afterStartup(runtime) {
|
||||||
|
console.log("Hello World from the plugin!");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -155,6 +155,6 @@ Requests and Black do not work out of the box because they weren’t meant for t
|
|||||||
|
|
||||||
For Black, it’s a design choice that can be patched. This is currently being addressed by the team at Pyodide.
|
For Black, it’s a design choice that can be patched. This is currently being addressed by the team at Pyodide.
|
||||||
|
|
||||||
Requests do not work because of the sockets issue (sockets and websockets are two different things) and requests are blocking—which you don’t want in the browser. It’ll require putting the runtime on a webworker and utilizing an assistant, but on the main thread it’s unlikely that it’ll work.
|
Requests do not work because of the sockets issue (sockets and websockets are two different things) and requests are blocking—which you don’t want in the browser. It’ll require putting the interpreter on a webworker and utilizing an assistant, but on the main thread it’s unlikely that it’ll work.
|
||||||
|
|
||||||
There are options as a path forward. For example, Requests can be leveraged using javascript libraries, or building a python async version of Requests API or a python wrapper for fetch (pyfetch), etc. The websockets library has a client side that could be made to work—given that it has all asynchronous APIs, there’s nothing fundamentally difficult about getting it to work.
|
There are options as a path forward. For example, Requests can be leveraged using javascript libraries, or building a python async version of Requests API or a python wrapper for fetch (pyfetch), etc. The websockets library has a client side that could be made to work—given that it has all asynchronous APIs, there’s nothing fundamentally difficult about getting it to work.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# pyscript
|
# pyscript
|
||||||
|
|
||||||
The code underlying PyScript is a TypeScript/JavaScript module, which is loaded and executed by the browser. This is what loads when you include, for example, `<script defer src="https://pyscript.net/latest/pyscript.js">` in your HTML.
|
The code underlying PyScript is a JavaScript module, which is loaded and executed by the browser. This is what loads when you include, for example, `<script defer src="https://pyscript.net/latest/pyscript.js">` in your HTML.
|
||||||
|
|
||||||
The module is exported to the browser as `pyscript`. The exports from this module are:
|
The module is exported to the browser as `pyscript`. The exports from this module are:
|
||||||
|
|
||||||
@@ -15,35 +15,35 @@ Once `pyscript.js` has loaded, the version of PyScript that is currently running
|
|||||||
Object { year: 2022, month: 11, patch: 1, releaselevel: "dev" }
|
Object { year: 2022, month: 11, patch: 1, releaselevel: "dev" }
|
||||||
```
|
```
|
||||||
|
|
||||||
## pyscript.runtime
|
## pyscript.interpreter
|
||||||
|
|
||||||
The RunTime object which is responsible for executing Python code in the Browser. Currently, all runtimes are assumed to be Pyodide runtimes, but there is flexibility to expand this to other web-based Python runtimes in future versions.
|
The Interpreter object which is responsible for executing Python code in the Browser. Currently, all interpreters are assumed to be Pyodide interpreters, but there is flexibility to expand this to other web-based Python interpreters in future versions.
|
||||||
|
|
||||||
The RunTime object has the following attributes
|
The Interpreter object has the following attributes
|
||||||
|
|
||||||
| attribute | type | description |
|
| attribute | type | description |
|
||||||
|---------------------|---------------------|-----------------------------------------------------------------------------|
|
|---------------------|-----------------------|---------------------------------------------------------------------------------|
|
||||||
| **src** | string | The URL from which the current runtime was fetched |
|
| **src** | string | The URL from which the current interpreter was fetched |
|
||||||
| **interpreter** | RuntimeInterpreter | A reference to the runtime object itself |
|
| **interface** | InterpreterInterface | A reference to the interpreter object itself |
|
||||||
| **globals** | any | The globals dictionary of the runtime, if applicable/accessible |
|
| **globals** | any | The globals dictionary of the interpreter, if applicable/accessible |
|
||||||
| **name (optional)** | string | A user-designated name for the runtime |
|
| **name (optional)** | string | A user-designated name for the interpreter |
|
||||||
| **lang (optional)** | string | A user-designation for the language the runtime runs ('Python', 'C++', etc) |
|
| **lang (optional)** | string | A user-designation for the language the interpreter runs ('Python', 'C++', etc) |
|
||||||
|
|
||||||
### pyscript.runtime.src
|
### pyscript.interpreter.src
|
||||||
|
|
||||||
The URL from which the current runtime was fetched.
|
The URL from which the current interpreter was fetched.
|
||||||
|
|
||||||
### pyscript.runtime.interpreter
|
### pyscript.interpreter.interface
|
||||||
|
|
||||||
A reference to the Runtime wrapper that PyScript uses to execute code. object itself. This allows other frameworks, modules etc to interact with the same [(Pyodide) runtime instance](https://pyodide.org/en/stable/usage/api/js-api.html) that PyScript uses.
|
A reference to the Interpreter wrapper that PyScript uses to execute code. object itself. This allows other frameworks, modules etc to interact with the same [(Pyodide) interpreter instance](https://pyodide.org/en/stable/usage/api/js-api.html) that PyScript uses.
|
||||||
|
|
||||||
For example, assuming we've loaded Pyodide, we can access the methods of the Pyodide runtime as follows:
|
For example, assuming we've loaded Pyodide, we can access the methods of the Pyodide interpreter as follows:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<button onclick="logFromPython()">Click Me to Run Some Python</button>
|
<button onclick="logFromPython()">Click Me to Run Some Python</button>
|
||||||
<script>
|
<script>
|
||||||
function logFromPython(){
|
function logFromPython(){
|
||||||
pyscript.runtime.interpreter.runPython(`
|
pyscript.interpreter.interface.runPython(`
|
||||||
animal = "Python"
|
animal = "Python"
|
||||||
sound = "sss"
|
sound = "sss"
|
||||||
console.warn(f"{animal}s go " + sound * 5)
|
console.warn(f"{animal}s go " + sound * 5)
|
||||||
@@ -52,9 +52,9 @@ For example, assuming we've loaded Pyodide, we can access the methods of the Pyo
|
|||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
### pyscript.runtime.globals
|
### pyscript.interpreter.globals
|
||||||
|
|
||||||
A proxy for the runtime's `globals()` dictionary. For example:
|
A proxy for the interpreter's `globals()` dictionary. For example:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<body>
|
<body>
|
||||||
@@ -63,15 +63,15 @@ A proxy for the runtime's `globals()` dictionary. For example:
|
|||||||
<button onclick="showX()">Click Me to Get 'x' from Python</button>
|
<button onclick="showX()">Click Me to Get 'x' from Python</button>
|
||||||
<script>
|
<script>
|
||||||
function showX(){
|
function showX(){
|
||||||
console.log(`In Python right now, x = ${pyscript.runtime.globals.get('x')}`)
|
console.log(`In Python right now, x = ${pyscript.interpreter.globals.get('x')}`)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
```
|
```
|
||||||
### pyscript.runtime.name
|
### pyscript.interpreter.name
|
||||||
|
|
||||||
A user-supplied string for the runtime given at its creation. For user reference only - does not affect the operation of the runtime or PyScript.
|
A user-supplied string for the interpreter given at its creation. For user reference only - does not affect the operation of the interpreter or PyScript.
|
||||||
|
|
||||||
### PyScript.runtime.lang
|
### PyScript.interpreter.lang
|
||||||
|
|
||||||
A user-supplied string for the language the runtime uses given at its creation. For user reference only - does not affect the operation of the runtime or PyScript.
|
A user-supplied string for the language the interpreter uses given at its creation. For user reference only - does not affect the operation of the interpreter or PyScript.
|
||||||
|
|||||||
65
docs/reference/plugins/py-splashscreen.md
Normal file
65
docs/reference/plugins/py-splashscreen.md
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
|
||||||
|
# <py-splashscreen>
|
||||||
|
|
||||||
|
This is one of the core plugins in PyScript, which is active by default. The splashscreen is the first thing you see when you open a page with Pyscript while it is loading itself and all the necessary resources.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
You can control how `<py-splashscreen>` behaves by setting the value of the `splashscreen` configuration in your `<py-config>`.
|
||||||
|
|
||||||
|
|
||||||
|
| parameter | default | description |
|
||||||
|
|-------------|-----------|-------------|
|
||||||
|
| `autoclose` | `true` | Whether to close the splashscreen automatically when the page is ready or not |
|
||||||
|
| `enabled` | `true` | Whether to show the splashscreen or not |
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
#### Disabling the splashscreen
|
||||||
|
|
||||||
|
If you don't want the splashscreen to show and log any loading messages, you can disable it by setting the splashscreen option `enabled` to `false`.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<py-config>
|
||||||
|
[splashscreen]
|
||||||
|
enabled = false
|
||||||
|
</py-config>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Disabling autoclose
|
||||||
|
|
||||||
|
If you want to keep the splashscreen open even after the page is ready, you can disable autoclose by setting `autoclose` to `false`.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<py-config>
|
||||||
|
[splashscreen]
|
||||||
|
autoclose = false
|
||||||
|
</py-config>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding custom messages
|
||||||
|
|
||||||
|
You can add custom messages to the splashscreen. This is useful if you want to show the user that something is happening in the background for your PyScript app.
|
||||||
|
|
||||||
|
There are two ways to add your custom messages to the splashscreen, either by dispatching a new custom event, `py-status-message` to the document:
|
||||||
|
|
||||||
|
|
||||||
|
```js
|
||||||
|
document.dispatchEvent(new CustomEvent("py-status-message", {detail: "Hello, world!"}))
|
||||||
|
```
|
||||||
|
|
||||||
|
Or by using the `log` method of the `py-splashscreen` tag directly:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const splashscreen = document.querySelector("py-splashscreen")
|
||||||
|
splashscreen.log("Hello, world!")
|
||||||
|
```
|
||||||
|
|
||||||
|
If you wish, you can also send messages directly to the splashscreen from your python code:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from js import document
|
||||||
|
|
||||||
|
splashscreen = document.querySelector("py-splashscreen")
|
||||||
|
splashscreen.log("Hello, world!")
|
||||||
|
```
|
||||||
@@ -4,7 +4,9 @@ This is one of the core plugins in PyScript, which is active by default. With it
|
|||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
You can control how `<py-terminal>` behaves by setting the value of the `terminal` configuration in your `<py-config>`.
|
You can control how `<py-terminal>` behaves by setting the values of the `terminal`, `docked`, and `xterm` fields in your configuration in your `<py-config>`.
|
||||||
|
|
||||||
|
For the **terminal** field, these are the values:
|
||||||
|
|
||||||
| value | description |
|
| value | description |
|
||||||
|-------|-------------|
|
|-------|-------------|
|
||||||
@@ -12,11 +14,50 @@ You can control how `<py-terminal>` behaves by setting the value of the `termin
|
|||||||
| `true` | Automatically add a `<py-terminal>` to the page |
|
| `true` | Automatically add a `<py-terminal>` to the page |
|
||||||
| `"auto"` | This is the default. Automatically add a `<py-terminal auto>`, to the page. The terminal is initially hidden and automatically shown as soon as something writes to `stdout` and/or `stderr` |
|
| `"auto"` | This is the default. Automatically add a `<py-terminal auto>`, to the page. The terminal is initially hidden and automatically shown as soon as something writes to `stdout` and/or `stderr` |
|
||||||
|
|
||||||
|
For the **docked** field, these are the values:
|
||||||
|
|
||||||
|
| value | description |
|
||||||
|
|-------|-------------|
|
||||||
|
| `false` | Don't dock `<py-terminal>` to the page |
|
||||||
|
| `true` | Automatically dock a `<py-terminal>` to the page |
|
||||||
|
| `"docked"` | This is the default. Automatically add a `<py-terminal docked>`, to the page. The terminal, once visible, is automatically shown at the bottom of the page, covering the width of such page |
|
||||||
|
|
||||||
|
Please note that **docked** mode is currently used as default only when `terminal="auto"`, or *terminal* default, is used.
|
||||||
|
|
||||||
|
In all other cases it's up to the user decide if a terminal should be docked or not.
|
||||||
|
|
||||||
|
For the **xterm** field, these are the values:
|
||||||
|
|
||||||
|
| value | description |
|
||||||
|
|-------|-------------|
|
||||||
|
| `false` | This is the default. The `<py-terminal>` is a simple `<pre>` tag with some CSS styling. |
|
||||||
|
| `true` or `xterm` | The [xtermjs](http://xtermjs.org/) library is loaded and its Terminal object is used as the `<py-terminal>`. It's visibility and position are determined by the `docked` and `auto` keys in the same way as the default `<py-terminal>` |
|
||||||
|
|
||||||
|
The xterm.js [Terminal object](http://xtermjs.org/docs/api/terminal/classes/terminal/) can be accessed directly if you want to adjust its properties, add [custom parser hooks](http://xtermjs.org/docs/guides/hooks/), introduce [xterm.js addons](http://xtermjs.org/docs/guides/using-addons/), etc. Access is best achieved by awaiting the `xtermReady` attribute of the `<py-terminal>` HTML element itself:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import js
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
async def adjust_term_size(columns, rows):
|
||||||
|
xterm = await js.document.querySelector('py-terminal').xtermReady
|
||||||
|
xterm.resize(columns, rows)
|
||||||
|
|
||||||
|
asyncio.ensure_future(adjust_term_size(40,10))
|
||||||
|
```
|
||||||
|
|
||||||
|
Some terminal-formatting packages read from specific environment variables to determine whether they should emit formatted output; PyScript does not set these variables explicitly - you may need to set them yourself, or force your terminal-formatting package into a state where it outputs correctly formatted output.
|
||||||
|
|
||||||
|
A couple of specific examples:
|
||||||
|
- the [rich](https://github.com/Textualize/rich) will not, by default, output colorful text, but passing `256` or `truecolor` as an argument as the `color_system` parameter to the [Console constructor](https://rich.readthedocs.io/en/stable/reference/console.html#rich.console.Console) will force it to do so. (As of rich v13)
|
||||||
|
- [termcolor](https://github.com/termcolor/termcolor) will not, by default, output colorful text, but setting `os.environ["FORCE_COLOR"] = "True"` or by passing `force_color=True` to the `colored()` function will force it to do so. (As of termcolor v2.3)
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<py-config>
|
<py-config>
|
||||||
terminal = true
|
terminal = true
|
||||||
|
docked = false
|
||||||
</py-config>
|
</py-config>
|
||||||
|
|
||||||
<py-script>
|
<py-script>
|
||||||
|
|||||||
@@ -1,50 +1,93 @@
|
|||||||
# Getting started with PyScript
|
# Getting started with PyScript
|
||||||
|
|
||||||
This page will guide you through getting started with PyScript.
|
To start developing a PyScript, like with most applications development, you need a **development environment** where you
|
||||||
|
write your code, a way to install the programming libraries and dependencies your code needs, and way to build and distribute
|
||||||
|
your application.
|
||||||
|
|
||||||
|
Luckily, PyScript makes many of these steps much easier.
|
||||||
|
|
||||||
## Development setup
|
## Development setup
|
||||||
|
|
||||||
PyScript does not require any development environment other
|
PyScript does not require any specific development environment other
|
||||||
then a web browser (we recommend using [Chrome](https://www.google.com/chrome/)) and a text editor, even though using your [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) of choice might be convenient.
|
than a web browser (we recommend using [Chrome](https://www.google.com/chrome/)) and a text editor, even though using your [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) of choice might be convenient.
|
||||||
|
|
||||||
If you're using [VSCode](https://code.visualstudio.com/), the
|
If you're using [VSCode](https://code.visualstudio.com/), the
|
||||||
[Live Server extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)
|
[Live Server extension](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer)
|
||||||
can be used to reload the page as you edit the HTML file.
|
can be used to reload the page as you edit the HTML file.
|
||||||
|
|
||||||
|
**NOTE:** The easier way to get a development setup for PyScript is to use [pyscript.com](pyscript.com). It is a free service that allows
|
||||||
|
users to create new projects from pre-created templates that already have all the project structure created and allows users
|
||||||
|
to edit their apps, preview it and deploy with just a link, all in the same place.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
There is no installation required. In this document, we'll use
|
There is no PyScript specific installation required in your system to start using PyScript in your browser. All you need to do is to
|
||||||
the PyScript assets served on [https://pyscript.net](https://pyscript.net).
|
simply add a reference in your application code to where your application should get PyScript from.
|
||||||
|
|
||||||
If you want to download the source and build it yourself, follow
|
If you are not an experienced developer and it all sounds very complicated, don't worry, we'll get you through it in the following steps.
|
||||||
the instructions in the [README.md](https://github.com/pyscript/pyscript/blob/main/README.md) file.
|
|
||||||
|
|
||||||
## Your first PyScript HTML file
|
## Writing your first PyScript application
|
||||||
|
|
||||||
Here's a "Hello, world!" example using PyScript.
|
As we hinted earlier, writing a PyScript application means writing a web application that can run code writted in Python (and other languages)
|
||||||
|
on the web. This means that the way we create PyScript applications starts in a very similar way to how we write web applications: from an
|
||||||
|
HTML file.
|
||||||
|
|
||||||
Using your favorite editor, create a new file called `hello.html` in
|
To demonstrate the above, let's start from the most popular "first application example": let's write a "Hello, world!"
|
||||||
the same directory as your PyScript, JavaScript, and CSS files with the
|
example using PyScript.
|
||||||
following content, and open the file in your web browser. You can typically
|
|
||||||
open an HTML by double-clicking it in your file explorer.
|
Using your favorite editor, create a new file called `hello.html` and paste in the following content and open it in your web browser. (You can typically
|
||||||
|
open an HTML by double-clicking it in your file explorer.):
|
||||||
|
|
||||||
```html
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<meta charset="utf-8" />
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>My First PyScript APP: Hello World!</title>
|
||||||
|
<script
|
||||||
|
type="module"
|
||||||
|
src="https://esm.sh/@pyscript/core@latest/core.js"
|
||||||
|
></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<py-script>
|
<py-script>
|
||||||
|
from pyscript import display
|
||||||
print('Hello, World!')
|
print('Hello, World!')
|
||||||
|
display('Hello, World!')
|
||||||
</py-script>
|
</py-script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
<a href="https://fpliger.pyscriptapps.com/hello-world-minimal-example/latest/" target="_blank">or open this example on pyscript.com</a>
|
||||||
|
|
||||||
|
You should see "Hello World!" printed in your page and in your Javascript Console (don't worry if
|
||||||
|
you don't know what it means yet, we'll get into that later).
|
||||||
|
|
||||||
|
## Serving your application
|
||||||
|
|
||||||
|
Now what we have written our first application, it's important talk about how we can access it.
|
||||||
|
|
||||||
|
In the example above, we were able to visualize it by simply opening the local file from our
|
||||||
|
system directly with the browser. While that's a very simple and fast way to open our application,
|
||||||
|
it is not very recommended because browsers will forbid many features when accessing files this way,
|
||||||
|
for security reasons. When this is the case, you may see your Python code in the text of the webpage,
|
||||||
|
and the [browser developer console](https://balsamiq.com/support/faqs/browserconsole/) may show an
|
||||||
|
error like *"Cross origin requests are only supported for HTTP."*
|
||||||
|
|
||||||
|
In short, when browsers visualize a web page, they expect them to be served by a
|
||||||
|
web server.
|
||||||
|
|
||||||
|
For the rest of this documentation, we'll be presenting examples and snippets and host them on
|
||||||
|
pyscript.com. Users can reference the [serving your application](serving-your-application.md) at
|
||||||
|
anytime for other options.
|
||||||
|
|
||||||
## A more complex example
|
## A more complex example
|
||||||
|
|
||||||
Now that we know how you can create a simple 'Hello, World!' example, let's see a more complex example. This example will use the Demo created by [Cheuk Ting Ho](https://github.com/Cheukting). In this example, we will use more features from PyScript.
|
Now that we know how you can create a simple 'Hello, World!' example, let's see a more complex example.
|
||||||
|
This example will use the Demo created by [Cheuk Ting Ho](https://github.com/Cheukting). In this example, we will use more features from PyScript.
|
||||||
|
|
||||||
### Setting up the base index file
|
### Setting up the base index file
|
||||||
|
|
||||||
@@ -197,6 +240,7 @@ Now that we have a way to explore the data using `py-repl` and a way to create t
|
|||||||
</py-config>
|
</py-config>
|
||||||
|
|
||||||
<py-script>
|
<py-script>
|
||||||
|
import js
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
@@ -209,7 +253,7 @@ Now that we have a way to explore the data using `py-repl` and a way to create t
|
|||||||
ice_data = pd.read_csv(open_url(url))
|
ice_data = pd.read_csv(open_url(url))
|
||||||
|
|
||||||
current_selected = []
|
current_selected = []
|
||||||
flavour_elements = document.getElementsByName("flavour")
|
flavour_elements = js.document.getElementsByName("flavour")
|
||||||
|
|
||||||
def plot(data):
|
def plot(data):
|
||||||
plt.rcParams["figure.figsize"] = (22,20)
|
plt.rcParams["figure.figsize"] = (22,20)
|
||||||
@@ -248,8 +292,8 @@ Now that we have a way to explore the data using `py-repl` and a way to create t
|
|||||||
<label for="all"> All 🍧</label>
|
<label for="all"> All 🍧</label>
|
||||||
<input type="radio" id="chocolate" name="flavour" value="COCOA">
|
<input type="radio" id="chocolate" name="flavour" value="COCOA">
|
||||||
<label for="chocolate"> Chocolate 🍫</label>
|
<label for="chocolate"> Chocolate 🍫</label>
|
||||||
<input type="radio" id="cherrie" name="flavour" value="CHERRIES">
|
<input type="radio" id="cherry" name="flavour" value="CHERRIES">
|
||||||
<label for="cherrie"> Cherries 🍒</label>
|
<label for="cherry"> Cherries 🍒</label>
|
||||||
<input type="radio" id="berries" name="flavour" value="BERRY">
|
<input type="radio" id="berries" name="flavour" value="BERRY">
|
||||||
<label for="berries"> Berries 🍓</label>
|
<label for="berries"> Berries 🍓</label>
|
||||||
<input type="radio" id="cheese" name="flavour" value="CHEESE">
|
<input type="radio" id="cheese" name="flavour" value="CHEESE">
|
||||||
|
|||||||
@@ -1,13 +1,38 @@
|
|||||||
# Tutorials
|
# Tutorials
|
||||||
|
|
||||||
This is the tutorials section for beginners.
|
This section contains pyscript tutorials. Each tutorial is a self-contained document that will guide you through a specific topic.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
This tutorial will guide you through getting started with PyScript, from installation to writing your first PyScript application. The getting started will show you how to specify dependencies, read a csv file from the web, use `pandas` and `matplotlib` and how to handle user input.
|
||||||
|
|
||||||
|
[Read the get started tutorial](getting-started.md)
|
||||||
|
|
||||||
|
|
||||||
|
## Basics
|
||||||
|
|
||||||
|
This section contains tutorials about the basics of PyScript.
|
||||||
|
|
||||||
```{toctree}
|
```{toctree}
|
||||||
---
|
---
|
||||||
maxdepth: 2
|
maxdepth: 1
|
||||||
|
glob:
|
||||||
---
|
---
|
||||||
getting-started
|
|
||||||
py-config-fetch
|
|
||||||
py-config-runtime
|
|
||||||
writing-to-page
|
writing-to-page
|
||||||
|
py-click
|
||||||
|
requests
|
||||||
|
```
|
||||||
|
|
||||||
|
## PyScript Configuration
|
||||||
|
|
||||||
|
This section contains tutorials about the PyScript configuration using the `<py-config>` tag.
|
||||||
|
|
||||||
|
|
||||||
|
```{toctree}
|
||||||
|
---
|
||||||
|
maxdepth: 1
|
||||||
|
glob:
|
||||||
|
---
|
||||||
|
py-config-fetch
|
||||||
|
py-config-interpreter
|
||||||
```
|
```
|
||||||
|
|||||||
127
docs/tutorials/py-click.md
Normal file
127
docs/tutorials/py-click.md
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# Handling click events
|
||||||
|
|
||||||
|
This tutorial will show you how to use the `py-click` attribute to handle mouse clicks on elements on your page. The `py-click` attribute is a special attribute that allows you to specify a Python function that will be called when the element is clicked. There are many other events such as py-mouseover, py-focus, py-input, py-keyress etc, which can be used as well. They are listed here [Attr-to-Event](../reference/API/attr_to_event.html)
|
||||||
|
|
||||||
|
## Development setup
|
||||||
|
|
||||||
|
Let's start by building the base HTML page. We will create an HTML page with a button and a paragraph. When the button is clicked, the paragraph will show the current time.
|
||||||
|
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Current Time</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding elements to the page
|
||||||
|
|
||||||
|
Let's add a button and a paragraph to the page. The button will have the `py-click` attribute, and the paragraph will have the `id` attribute. The `id` attribute is used to identify the element on the page, and the `py-click` attribute will be used to specify the function that will be called when the button is clicked.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Current Time</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<button py-click="current_time()" id="get-time" class="py-button">Get current time</button>
|
||||||
|
<p id="current-time"></p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
There are two things to note here:
|
||||||
|
|
||||||
|
- You must specify an id for an element that uses any `py-*` attribute
|
||||||
|
- We used the `py-button` class to style the button, this is optional, and these rules are coming from the pyscript.css that we added in the `<head>` section.
|
||||||
|
|
||||||
|
## Creating the Python function
|
||||||
|
|
||||||
|
In this step, we will create the Python function that will be called when the button is clicked. This function will get the current time and update the paragraph with the current time. We will use a `<py-script>` tag to specify the Python code that will be executed when the page is loaded.
|
||||||
|
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Current Time</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<button py-click="current_time()" id="get-time" class="py-button">Get current time</button>
|
||||||
|
<p id="current-time"></p>
|
||||||
|
|
||||||
|
<py-script>
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
def current_time():
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
</py-script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Writing the time to the page
|
||||||
|
|
||||||
|
If you run the example, you will notice that nothing happened. This is because we still need to update the paragraph with the current time. We can do this by using the [`Element` API](../reference/API/element.md) to get the paragraph element and then update it with the current time with the `write` method.
|
||||||
|
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Current Time</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<button py-click="current_time()" id="get-time" class="py-button">Get current time</button>
|
||||||
|
<p id="current-time"></p>
|
||||||
|
|
||||||
|
<py-script>
|
||||||
|
from pyscript import Element
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
def current_time():
|
||||||
|
now = datetime.datetime.now()
|
||||||
|
|
||||||
|
# Get paragraph element by id
|
||||||
|
paragraph = Element("current-time")
|
||||||
|
|
||||||
|
# Add current time to the paragraph element
|
||||||
|
paragraph.write(now.strftime("%Y-%m-%d %H:%M:%S"))
|
||||||
|
</py-script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, if you refresh the page and click the button, the paragraph will be updated with the current time.
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Setting a pyodide runtime
|
# Setting a pyodide interpreter
|
||||||
|
|
||||||
Pyscript will automatically set the runtime for you, but you can also set it manually. This is useful if you want to use a different version than the one set by default.
|
Pyscript will automatically set the interpreter for you, but you can also set it manually. This is useful if you want to use a different version than the one set by default.
|
||||||
|
|
||||||
## Development setup
|
## Development setup
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ To get started, let's create a new `index.html` file and import `pyscript.js`.
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
<title>Runtime</title>
|
<title>Interpreter</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
@@ -25,11 +25,11 @@ To get started, let's create a new `index.html` file and import `pyscript.js`.
|
|||||||
</html>
|
</html>
|
||||||
```
|
```
|
||||||
|
|
||||||
We are using the pyodide CDN to setup our runtime, but you can also download the files from [the pyodide GitHub release](https://github.com/pyodide/pyodide/releases/tag/0.22.0a3), unzip them and use the `pyodide.js` file as your runtime.
|
We are using the pyodide CDN to setup our interpreter, but you can also download the files from [the pyodide GitHub releases](https://github.com/pyodide/pyodide/releases/), unzip them and use the `pyodide.js` file as your interpreter.
|
||||||
|
|
||||||
## Setting the runtime
|
## Setting the interpreter
|
||||||
|
|
||||||
To set the runtime, you can use the `runtime` configuration in the `py-config` element. In this tutorial, we will use the default `TOML` format, but know that you can also use `json` if you prefer by changing the `type` attribute of the `py-config` element.
|
To set the interpreter, you can use the `interpreter` configuration in the `py-config` element. In this tutorial, we will use the default `TOML` format, but know that you can also use `json` if you prefer by changing the `type` attribute of the `py-config` element.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@@ -38,7 +38,7 @@ To set the runtime, you can use the `runtime` configuration in the `py-config` e
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
<title>Runtime</title>
|
<title>Interpreter</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
@@ -46,18 +46,18 @@ To set the runtime, you can use the `runtime` configuration in the `py-config` e
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<py-config>
|
<py-config>
|
||||||
[[runtimes]]
|
[[interpreters]]
|
||||||
src = "https://cdn.jsdelivr.net/pyodide/v0.22.0a3/full/pyodide.js"
|
src = "https://cdn.jsdelivr.net/pyodide/v0.23.0/full/pyodide.js"
|
||||||
name = "pyodide-0.22.0a3"
|
name = "pyodide-0.23.0"
|
||||||
lang = "python"
|
lang = "python"
|
||||||
</py-config>
|
</py-config>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Confirming the runtime version
|
## Confirming the interpreter version
|
||||||
|
|
||||||
To confirm that the runtime is set correctly, you can open the DevTools and check the version from the console. But for the sake of this tutorial, let's create a `py-script` tag and print pyodide's version.
|
To confirm that the interpreter is set correctly, you can open the DevTools and check the version from the console. But for the sake of this tutorial, let's create a `py-script` tag and print pyodide's version.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
@@ -66,7 +66,7 @@ To confirm that the runtime is set correctly, you can open the DevTools and chec
|
|||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
<title>Runtime</title>
|
<title>Interpreter</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
@@ -74,9 +74,9 @@ To confirm that the runtime is set correctly, you can open the DevTools and chec
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<py-config>
|
<py-config>
|
||||||
[[runtimes]]
|
[[interpreters]]
|
||||||
src = "https://cdn.jsdelivr.net/pyodide/v0.22.0a3/full/pyodide.js"
|
src = "https://cdn.jsdelivr.net/pyodide/v0.23.0/full/pyodide.js"
|
||||||
name = "pyodide-0.22.0a3"
|
name = "pyodide-0.23.0"
|
||||||
lang = "python"
|
lang = "python"
|
||||||
</py-config>
|
</py-config>
|
||||||
<py-script>
|
<py-script>
|
||||||
123
docs/tutorials/requests.md
Normal file
123
docs/tutorials/requests.md
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
# Calling an API using Requests
|
||||||
|
|
||||||
|
This tutorial will show you how to interact with an API using the [Requests](https://requests.readthedocs.io/en/master/) library. Requests is a popular library, but it doesn't work out of the box with Pyscript. We will use the [pyodide-http](https://github.com/koenvo/pyodide-http) library to patch the Requests library, so it works with Pyscript.
|
||||||
|
|
||||||
|
We will use the [JSON Placeholder API](https://jsonplaceholder.typicode.com/), a free fake API that returns fake data.
|
||||||
|
|
||||||
|
## Development Setup
|
||||||
|
|
||||||
|
Let's build the base HTML page to add our `py-config` and `py-script` tags in the next steps.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Requests Tutorial</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installing the dependencies
|
||||||
|
|
||||||
|
In this step, we will install the dependencies we need to use the Requests library. We will use the `py-config` tag to specify the dependencies we need to install.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Requests Tutorial</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<py-config>
|
||||||
|
packages = ["requests", "pyodide-http"]
|
||||||
|
</py-config>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Patching the Requests library
|
||||||
|
|
||||||
|
Now that we have installed the dependencies, we need to patch the Requests library to work with Pyscript. We will use the `py-script` tag to specify the code that will be executed when the page is loaded.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Requests Tutorial</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<py-config>
|
||||||
|
packages = ["requests", "pyodide-http"]
|
||||||
|
</py-config>
|
||||||
|
|
||||||
|
<py-script>
|
||||||
|
import pyodide_http
|
||||||
|
pyodide_http.patch_all()
|
||||||
|
</py-script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Making a request
|
||||||
|
|
||||||
|
Finally, let's make a request to the JSON Placeholder API to confirm that everything is working.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
|
<title>Requests Tutorial</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
||||||
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<py-config>
|
||||||
|
packages = ["requests", "pyodide-http"]
|
||||||
|
</py-config>
|
||||||
|
|
||||||
|
<py-script>
|
||||||
|
import requests
|
||||||
|
import pyodide_http
|
||||||
|
|
||||||
|
# Patch the Requests library so it works with Pyscript
|
||||||
|
pyodide_http.patch_all()
|
||||||
|
|
||||||
|
# Make a request to the JSON Placeholder API
|
||||||
|
response = requests.get("https://jsonplaceholder.typicode.com/todos")
|
||||||
|
print(response.json())
|
||||||
|
</py-script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
In this tutorial, we learned how to use the Requests library to make requests to an API. We also learned how to use the `py-config` and `py-script` tags to install dependencies and execute code when the page is loaded.
|
||||||
|
|
||||||
|
Depending on the API you use, you may need to add additional headers to your request. You can read the [Requests documentation](https://requests.readthedocs.io/en/master/user/quickstart/#custom-headers) to learn more about how to do this.
|
||||||
|
|
||||||
|
You may also be interested in creating your module to make requests. You can read the in-depth guide on [How to make HTTP requests using `PyScript`, in pure Python](../guides/http-requests.md) to learn more about how to do this.
|
||||||
@@ -1,154 +1,90 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Altair</title>
|
<title>Altair</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<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://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
rel="stylesheet"
|
||||||
<link rel="stylesheet" href="./assets/prism/prism.css" />
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
/>
|
||||||
<script defer src="./assets/prism/prism.js"></script>
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
|
<style>
|
||||||
|
py-script {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script
|
||||||
|
type="module"
|
||||||
|
src="https://esm.sh/@pyscript/core@latest/core.js"
|
||||||
|
></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar" style="background-color: #000000;">
|
<nav class="navbar" style="background-color: #000000">
|
||||||
<div class="app-header">
|
<div class="app-header">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<img src="./logo.png" class="logo">
|
<img src="./logo.png" class="logo" />
|
||||||
</a>
|
</a>
|
||||||
<a class="title" href="" style="color: #f0ab3c;">Altair</a>
|
<a class="title" href="" style="color: #f0ab3c">Altair</a>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<section class="pyscript">
|
<section class="pyscript">
|
||||||
<div id="altair"></div>
|
<div id="altair"></div>
|
||||||
<py-config>
|
<py-tutor>
|
||||||
packages = [
|
<py-config>
|
||||||
"altair",
|
packages = [
|
||||||
"pandas",
|
"altair",
|
||||||
"vega_datasets"
|
"pandas",
|
||||||
]
|
"vega_datasets"
|
||||||
</py-config>
|
]
|
||||||
<py-script>
|
plugins = [
|
||||||
import altair as alt
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
from vega_datasets import data
|
]
|
||||||
|
</py-config>
|
||||||
|
<py-script>
|
||||||
|
from pyscript import display
|
||||||
|
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(
|
rect = alt.Chart(data.movies.url).mark_rect().encode(
|
||||||
alt.X('IMDB_Rating:Q', bin=True),
|
alt.X('IMDB_Rating:Q', bin=True),
|
||||||
alt.Y('Rotten_Tomatoes_Rating:Q', bin=True),
|
alt.Y('Rotten_Tomatoes_Rating:Q', bin=True),
|
||||||
alt.Color('count()',
|
alt.Color('count()',
|
||||||
scale=alt.Scale(scheme='greenblue'),
|
scale=alt.Scale(scheme='greenblue'),
|
||||||
legend=alt.Legend(title='Total Records')
|
legend=alt.Legend(title='Total Records')
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
circ = rect.mark_point().encode(
|
circ = rect.mark_point().encode(
|
||||||
alt.ColorValue('grey'),
|
alt.ColorValue('grey'),
|
||||||
alt.Size('count()',
|
alt.Size('count()',
|
||||||
legend=alt.Legend(title='Records in Selection')
|
legend=alt.Legend(title='Records in Selection')
|
||||||
)
|
)
|
||||||
).transform_filter(
|
).transform_filter(
|
||||||
pts
|
pts
|
||||||
)
|
)
|
||||||
|
|
||||||
bar = alt.Chart(source).mark_bar().encode(
|
bar = alt.Chart(source).mark_bar().encode(
|
||||||
x='Major_Genre:N',
|
x='Major_Genre:N',
|
||||||
y='count()',
|
y='count()',
|
||||||
color=alt.condition(pts, alt.ColorValue("steelblue"), alt.ColorValue("grey"))
|
color=alt.condition(pts, alt.ColorValue("steelblue"), alt.ColorValue("grey"))
|
||||||
).properties(
|
).properties(
|
||||||
width=550,
|
width=550,
|
||||||
height=200
|
height=200
|
||||||
).add_selection(pts)
|
).add_selection(pts)
|
||||||
|
|
||||||
display(alt.vconcat(
|
display(alt.vconcat(
|
||||||
rect + circ,
|
rect + circ,
|
||||||
bar
|
bar
|
||||||
).resolve_legend(
|
).resolve_legend(
|
||||||
color="independent",
|
color="independent",
|
||||||
size="independent"
|
size="independent"
|
||||||
), target="altair")
|
), target="altair")
|
||||||
</py-script>
|
</py-script>
|
||||||
|
</py-tutor>
|
||||||
</section>
|
</section>
|
||||||
<section class="code">
|
</body>
|
||||||
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
|
|
||||||
<div id="code-section" class="code-section-hidden">
|
|
||||||
<p>index.html</p>
|
|
||||||
<pre class="prism-code language-html">
|
|
||||||
<code class="language-html">
|
|
||||||
<py-config>
|
|
||||||
packages = [
|
|
||||||
"altair",
|
|
||||||
"pandas",
|
|
||||||
"vega_datasets"
|
|
||||||
]
|
|
||||||
</py-config>
|
|
||||||
<py-script>
|
|
||||||
import altair as alt
|
|
||||||
from vega_datasets import data
|
|
||||||
|
|
||||||
source = data.movies.url
|
|
||||||
|
|
||||||
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')
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
display(alt.vconcat(
|
|
||||||
rect + circ,
|
|
||||||
bar
|
|
||||||
).resolve_legend(
|
|
||||||
color="independent",
|
|
||||||
size="independent"
|
|
||||||
), target="altair")
|
|
||||||
</py-script>
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</body>
|
|
||||||
<script>
|
|
||||||
const viewCodeButton = document.getElementById("view-code-button");
|
|
||||||
const codeSection = document.getElementById("code-section");
|
|
||||||
const handleClick = () => {
|
|
||||||
if (codeSection.classList.contains("code-section-hidden")) {
|
|
||||||
codeSection.classList.remove("code-section-hidden");
|
|
||||||
codeSection.classList.add("code-section-visible");
|
|
||||||
} else {
|
|
||||||
codeSection.classList.remove("code-section-visible");
|
|
||||||
codeSection.classList.add("code-section-hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
viewCodeButton.addEventListener("click", handleClick)
|
|
||||||
viewCodeButton.addEventListener("keydown", (e) => {
|
|
||||||
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
|
|
||||||
handleClick();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,118 +1,39 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Antigravity</title>
|
<title>Antigravity</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<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://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
rel="stylesheet"
|
||||||
<link rel="stylesheet" href="./assets/prism/prism.css" />
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
/>
|
||||||
<script defer src="./assets/prism/prism.js"></script>
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
</head>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
<body>
|
</head>
|
||||||
<nav class="navbar" style="background-color: #000000;">
|
<body>
|
||||||
<div class="app-header">
|
<nav class="navbar" style="background-color: #000000">
|
||||||
<a href="/">
|
<div class="app-header">
|
||||||
<img src="./logo.png" class="logo">
|
<a href="/">
|
||||||
</a>
|
<img src="./logo.png" class="logo" />
|
||||||
<a class="title" href="" style="color: #f0ab3c;">Antigravity</a>
|
</a>
|
||||||
</div>
|
<a class="title" href="" style="color: #f0ab3c">Antigravity</a>
|
||||||
</nav>
|
</div>
|
||||||
<section class="pyscript">
|
</nav>
|
||||||
<py-config>
|
<py-tutor modules="antigravity.py">
|
||||||
[[fetch]]
|
<section class="pyscript">
|
||||||
files = ["./antigravity.py"]
|
<py-config>
|
||||||
</py-config>
|
plugins = [
|
||||||
<b>Based on xkcd: antigravity https://xkcd.com/353/.</b>
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
<py-script>
|
]
|
||||||
import antigravity
|
[[fetch]]
|
||||||
antigravity.fly()
|
files = ["./antigravity.py"]
|
||||||
</py-script>
|
</py-config>
|
||||||
</section>
|
<b>Based on xkcd: antigravity https://xkcd.com/353/.</b>
|
||||||
<section class="code">
|
<py-script>
|
||||||
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
|
import antigravity
|
||||||
<div id="code-section" class="code-section-hidden">
|
antigravity.fly()
|
||||||
<p>index.html</p>
|
</py-script>
|
||||||
<pre class="prism-code language-html">
|
</section>
|
||||||
<code class="language-html">
|
</py-tutor>
|
||||||
<py-config>
|
</body>
|
||||||
[[fetch]]
|
|
||||||
files = ["./antigravity.py"]
|
|
||||||
</py-config>
|
|
||||||
<py-script>
|
|
||||||
import antigravity
|
|
||||||
antigravity.fly()
|
|
||||||
</py-script>
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
<p>antigravity.py</p>
|
|
||||||
<pre class="prism-code language-python">
|
|
||||||
<code class="language-python">
|
|
||||||
import random
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from js import DOMParser, document, setInterval
|
|
||||||
from pyodide.ffi import create_proxy
|
|
||||||
from pyodide.http import open_url
|
|
||||||
|
|
||||||
|
|
||||||
class Antigravity:
|
|
||||||
|
|
||||||
url = "./antigravity.svg"
|
|
||||||
|
|
||||||
def __init__(self, target=None, interval=10, append=True, fly=False):
|
|
||||||
target = target or sys.stdout._out
|
|
||||||
self.target = (
|
|
||||||
document.getElementById(target) if isinstance(target, str) else target
|
|
||||||
)
|
|
||||||
doc = DOMParser.new().parseFromString(
|
|
||||||
open_url(self.url).read(), "image/svg+xml"
|
|
||||||
)
|
|
||||||
self.node = doc.documentElement
|
|
||||||
if append:
|
|
||||||
self.target.append(self.node)
|
|
||||||
else:
|
|
||||||
self.target.replaceChildren(self.node)
|
|
||||||
self.xoffset, self.yoffset = 0, 0
|
|
||||||
self.interval = interval
|
|
||||||
if fly:
|
|
||||||
self.fly()
|
|
||||||
|
|
||||||
def fly(self):
|
|
||||||
setInterval(create_proxy(self.move), self.interval)
|
|
||||||
|
|
||||||
def move(self):
|
|
||||||
char = self.node.getElementsByTagName("g")[1]
|
|
||||||
char.setAttribute("transform", f"translate({self.xoffset}, {-self.yoffset})")
|
|
||||||
self.xoffset += random.normalvariate(0, 1) / 20
|
|
||||||
if self.yoffset < 50:
|
|
||||||
self.yoffset += 0.1
|
|
||||||
else:
|
|
||||||
self.yoffset += random.normalvariate(0, 1) / 20
|
|
||||||
|
|
||||||
_auto = Antigravity(append=True)
|
|
||||||
fly = _auto.fly
|
|
||||||
</code>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</body>
|
|
||||||
<script>
|
|
||||||
const viewCodeButton = document.getElementById("view-code-button");
|
|
||||||
const codeSection = document.getElementById("code-section");
|
|
||||||
const handleClick = () => {
|
|
||||||
if (codeSection.classList.contains("code-section-hidden")) {
|
|
||||||
codeSection.classList.remove("code-section-hidden");
|
|
||||||
codeSection.classList.add("code-section-visible");
|
|
||||||
} else {
|
|
||||||
codeSection.classList.remove("code-section-visible");
|
|
||||||
codeSection.classList.add("code-section-hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
viewCodeButton.addEventListener("click", handleClick)
|
|
||||||
viewCodeButton.addEventListener("keydown", (e) => {
|
|
||||||
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
|
|
||||||
handleClick();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ from pyodide.http import open_url
|
|||||||
|
|
||||||
|
|
||||||
class Antigravity:
|
class Antigravity:
|
||||||
|
|
||||||
url = "./antigravity.svg"
|
url = "./antigravity.svg"
|
||||||
|
|
||||||
def __init__(self, target=None, interval=10, append=True, fly=False):
|
def __init__(self, target=None, interval=10, append=True, fly=False):
|
||||||
|
|||||||
@@ -36,20 +36,21 @@ body {
|
|||||||
border-radius: 10px 0px 0px 10px;
|
border-radius: 10px 0px 0px 10px;
|
||||||
color: #c6c6c8;
|
color: #c6c6c8;
|
||||||
}
|
}
|
||||||
.code-section-visible p{
|
.code-section-visible p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-size: small;
|
font-size: small;
|
||||||
}
|
}
|
||||||
|
|
||||||
.language-html, .language-python {
|
.language-html,
|
||||||
|
.language-python {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
#view-code-button {
|
#view-code-button {
|
||||||
writing-mode: tb-rl;
|
writing-mode: tb-rl;
|
||||||
text-orientation: sideways-right;
|
text-orientation: sideways-right;
|
||||||
background-color: #1D1D22;
|
background-color: #1d1d22;
|
||||||
color: white;
|
color: white;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
margin-bottom: 5rem;
|
margin-bottom: 5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.example h2{
|
.example h2 {
|
||||||
/* color: #000000; */
|
/* color: #000000; */
|
||||||
font-family: "Inconsolata", monospace;
|
font-family: "Inconsolata", monospace;
|
||||||
font-size: 2.25rem;
|
font-size: 2.25rem;
|
||||||
@@ -16,9 +16,12 @@
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card:hover, .card:hover a, .card:hover a:visited, .card:hover h2 {
|
.card:hover,
|
||||||
|
.card:hover a,
|
||||||
|
.card:hover a:visited,
|
||||||
|
.card:hover h2 {
|
||||||
background-color: var(--color-primary);
|
background-color: var(--color-primary);
|
||||||
color: #1D1D22
|
color: #1d1d22;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card a h2 {
|
.card a h2 {
|
||||||
@@ -46,7 +49,8 @@ a .card {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-content a, .card-content a:visited {
|
.card-content a,
|
||||||
|
.card-content a:visited {
|
||||||
color: var(--color-primary);
|
color: var(--color-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
@import "./variables.css";
|
@import "./variables.css";
|
||||||
@import "./reset.css";
|
@import "./reset.css";
|
||||||
|
|
||||||
|
|
||||||
body {
|
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: #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;
|
background-attachment: fixed;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
color: var(--text-color)
|
color: var(--text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
:root {
|
:root {
|
||||||
--color-primary: #FDA703;
|
--color-primary: #fda703;
|
||||||
--color-secondary: #1D1D22;
|
--color-secondary: #1d1d22;
|
||||||
--text-color: white;
|
--text-color: white;
|
||||||
--card-shadow: 0px 5px 11px 0px rgb(0 0 0 / 15%);
|
--card-shadow: 0px 5px 11px 0px rgb(0 0 0 / 15%);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,29 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
rel="stylesheet"
|
||||||
</head>
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
<body>
|
/>
|
||||||
<py-script>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
import js
|
</head>
|
||||||
import asyncio
|
<body>
|
||||||
for i in range(3):
|
<py-script>
|
||||||
js.console.log('A', i)
|
import js
|
||||||
await asyncio.sleep(0.1)
|
import asyncio
|
||||||
</py-script>
|
for i in range(3):
|
||||||
<py-script>
|
js.console.log('A', i)
|
||||||
import js
|
await asyncio.sleep(0.1)
|
||||||
import asyncio
|
</py-script>
|
||||||
for i in range(3):
|
<py-script>
|
||||||
js.console.log('B', i)
|
import js
|
||||||
await asyncio.sleep(0.1)
|
import asyncio
|
||||||
</py-script>
|
for i in range(3):
|
||||||
</body>
|
js.console.log('B', i)
|
||||||
|
await asyncio.sleep(0.1)
|
||||||
|
</py-script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,40 +1,45 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
rel="stylesheet"
|
||||||
</head>
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
<body>
|
/>
|
||||||
<div>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
Pyscript - FIRST ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
</head>
|
||||||
<py-script>
|
<body>
|
||||||
import js
|
<div>
|
||||||
import asyncio
|
Pyscript - FIRST ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME
|
||||||
|
LEVEL AS LOOP Pyscript writing to console.log:
|
||||||
|
<py-script>
|
||||||
|
import js
|
||||||
|
import asyncio
|
||||||
|
|
||||||
async def asyncCallLoop1():
|
async def asyncCallLoop1():
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
js.console.log('A', i)
|
js.console.log('A', i)
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
|
|
||||||
asyncCallLoop1()
|
asyncCallLoop1()
|
||||||
</py-script>
|
</py-script>
|
||||||
</div>
|
</div>
|
||||||
<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
|
||||||
<py-script>
|
LEVEL AS LOOP Pyscript writing to console.log:
|
||||||
import js
|
<py-script>
|
||||||
import asyncio
|
import js
|
||||||
|
import asyncio
|
||||||
|
|
||||||
async def asyncCallLoop2():
|
async def asyncCallLoop2():
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
js.console.log('B', i)
|
js.console.log('B', i)
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
|
|
||||||
asyncCallLoop2()
|
asyncCallLoop2()
|
||||||
</py-script>
|
</py-script>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,37 +1,42 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
rel="stylesheet"
|
||||||
</head>
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
<body>
|
/>
|
||||||
<div>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
Pyscript - FIRST ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
</head>
|
||||||
<py-script>
|
<body>
|
||||||
import js
|
<div>
|
||||||
import asyncio
|
Pyscript - FIRST ASYNC WITH INVOKED LOOP BLOCKING AWAIT AT SAME
|
||||||
|
LEVEL AS LOOP Pyscript writing to console.log:
|
||||||
|
<py-script>
|
||||||
|
import js
|
||||||
|
import asyncio
|
||||||
|
|
||||||
async def asyncCallLoop1():
|
async def asyncCallLoop1():
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
js.console.log('A', i)
|
js.console.log('A', i)
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
|
|
||||||
asyncCallLoop1()
|
asyncCallLoop1()
|
||||||
</py-script>
|
</py-script>
|
||||||
</div>
|
</div>
|
||||||
<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
|
||||||
<py-script>
|
LEVEL AS LOOP Pyscript writing to console.log:
|
||||||
import js
|
<py-script>
|
||||||
import asyncio
|
import js
|
||||||
|
import asyncio
|
||||||
|
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
js.console.log('B', i)
|
js.console.log('B', i)
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
</py-script>
|
</py-script>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,40 +1,45 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title>Async Await NON-BLOCKING Pyscript Twice</title>
|
<title>Async Await NON-BLOCKING Pyscript Twice</title>
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
rel="stylesheet"
|
||||||
</head>
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
<body>
|
/>
|
||||||
<div>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
Pyscript - FIRST ASYNC WITH NON-BLOCKING AWAIT AT ONE LEVEL LOWER THAN LOOP Pyscript writing to console.log:
|
</head>
|
||||||
<py-script>
|
<body>
|
||||||
import js
|
<div>
|
||||||
import asyncio
|
Pyscript - FIRST ASYNC WITH NON-BLOCKING AWAIT AT ONE LEVEL LOWER
|
||||||
|
THAN LOOP Pyscript writing to console.log:
|
||||||
|
<py-script>
|
||||||
|
import js
|
||||||
|
import asyncio
|
||||||
|
|
||||||
async def asyncCall1():
|
async def asyncCall1():
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
|
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
js.console.log('A', i)
|
js.console.log('A', i)
|
||||||
asyncCall1()
|
asyncCall1()
|
||||||
</py-script>
|
</py-script>
|
||||||
</div>
|
</div>
|
||||||
<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
|
||||||
<py-script>
|
THAN LOOP Pyscript writing to console.log:
|
||||||
import js
|
<py-script>
|
||||||
import asyncio
|
import js
|
||||||
|
import asyncio
|
||||||
|
|
||||||
async def asyncCall2():
|
async def asyncCall2():
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
|
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
js.console.log('B', i)
|
js.console.log('B', i)
|
||||||
asyncCall2()
|
asyncCall2()
|
||||||
</py-script>
|
</py-script>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,34 +1,39 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
rel="stylesheet"
|
||||||
</head>
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
<body>
|
/>
|
||||||
<div>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
Pyscript - FIRST ASYNC WITH TOP-LEVEL LOOP BLOCKING AWAIT AT SAME LEVEL AS LOOP Pyscript writing to console.log:
|
</head>
|
||||||
<py-script>
|
<body>
|
||||||
import js
|
<div>
|
||||||
import asyncio
|
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):
|
for i in range(3):
|
||||||
js.console.log('A', i)
|
js.console.log('A', i)
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
</py-script>
|
</py-script>
|
||||||
</div>
|
</div>
|
||||||
<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
|
||||||
<py-script>
|
LEVEL AS LOOP Pyscript writing to console.log:
|
||||||
import js
|
<py-script>
|
||||||
import asyncio
|
import js
|
||||||
|
import asyncio
|
||||||
|
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
js.console.log('B', i)
|
js.console.log('B', i)
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
</py-script>
|
</py-script>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,19 +1,22 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
<title>Async Await BLOCKING LOOP Pyscript Twice</title>
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
rel="stylesheet"
|
||||||
</head>
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
<body>
|
/>
|
||||||
<py-script>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
import asyncio
|
</head>
|
||||||
from itertools import count
|
<body>
|
||||||
for i in count():
|
<py-script>
|
||||||
print(f"Count: {i}")
|
import asyncio
|
||||||
await asyncio.sleep(1)
|
from itertools import count
|
||||||
</py-script>
|
for i in count():
|
||||||
</body>
|
print(f"Count: {i}")
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
</py-script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,115 +1,94 @@
|
|||||||
<html><head>
|
<html>
|
||||||
<title>Bokeh Example</title>
|
<head>
|
||||||
<meta charset="iso-8859-1">
|
<title>Bokeh Example</title>
|
||||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
<meta charset="iso-8859-1" />
|
||||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js"></script>
|
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.2.min.js"></script>
|
<script
|
||||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js"></script>
|
type="text/javascript"
|
||||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js"></script>
|
src="https://cdn.bokeh.org/bokeh/release/bokeh-3.0.3.min.js"
|
||||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.2.min.js"></script>
|
></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">
|
<script type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<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" />
|
||||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
<style>
|
||||||
<link rel="stylesheet" href="./assets/prism/prism.css" />
|
py-script {
|
||||||
<script defer src="./assets/prism/prism.js"></script>
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script
|
||||||
|
type="module"
|
||||||
|
src="https://esm.sh/@pyscript/core@latest/core.js"
|
||||||
|
></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar" style="background-color: #000000;">
|
<nav class="navbar" style="background-color: #000000">
|
||||||
<div class="app-header">
|
<div class="app-header">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<img src="./logo.png" class="logo">
|
<img src="./logo.png" class="logo" />
|
||||||
</a>
|
</a>
|
||||||
<a class="title" href="" style="color: #f0ab3c;">Bokeh Example</a>
|
<a class="title" href="" style="color: #f0ab3c"
|
||||||
</div>
|
>Bokeh Example</a
|
||||||
</nav>
|
>
|
||||||
<section class="pyscript">
|
</div>
|
||||||
<div id="myplot"></div>
|
</nav>
|
||||||
|
<py-tutor>
|
||||||
|
<section class="pyscript">
|
||||||
|
<div id="myplot"></div>
|
||||||
|
|
||||||
<py-config>
|
<py-config>
|
||||||
packages = [
|
packages = [
|
||||||
"bokeh",
|
"pandas",
|
||||||
"numpy"
|
"bokeh",
|
||||||
]
|
"xyzservices"
|
||||||
</py-config>
|
]
|
||||||
|
plugins = [
|
||||||
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
|
]
|
||||||
|
</py-config>
|
||||||
|
|
||||||
<py-script id="main">
|
<py-script id="main">
|
||||||
import json
|
import json
|
||||||
import pyodide
|
import pyodide
|
||||||
|
|
||||||
from js import Bokeh, console, JSON
|
from js import Bokeh, console, JSON
|
||||||
|
|
||||||
from bokeh.embed import json_item
|
from bokeh.embed import json_item
|
||||||
from bokeh.plotting import figure
|
from bokeh.plotting import figure
|
||||||
from bokeh.resources import CDN
|
from bokeh.resources import CDN
|
||||||
|
|
||||||
# create a new plot with default tools, using figure
|
# create a new plot with default tools, using figure
|
||||||
p = figure(plot_width=400, plot_height=400)
|
p = figure(width=400, height=400)
|
||||||
|
|
||||||
# add a circle renderer with x and y coordinates, size, color, and alpha
|
# 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.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"))
|
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>
|
</py-script>
|
||||||
</section>
|
</section>
|
||||||
<section class="code">
|
</py-tutor>
|
||||||
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
|
</body>
|
||||||
<div id="code-section" class="code-section-hidden">
|
|
||||||
<p>index.html</p>
|
|
||||||
<pre class="prism-code language-html">
|
|
||||||
<code class="language-html">
|
|
||||||
<py-config>
|
|
||||||
packages = [
|
|
||||||
"bokeh",
|
|
||||||
"numpy"
|
|
||||||
]
|
|
||||||
</py-config>
|
|
||||||
<py-script id="main">
|
|
||||||
import json
|
|
||||||
import pyodide
|
|
||||||
|
|
||||||
from js import Bokeh, console, JSON
|
|
||||||
|
|
||||||
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(plot_width=400, plot_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"))
|
|
||||||
|
|
||||||
Bokeh.embed.embed_item(JSON.parse(p_json))
|
|
||||||
</py-script>
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</body>
|
|
||||||
<script>
|
|
||||||
const viewCodeButton = document.getElementById("view-code-button");
|
|
||||||
const codeSection = document.getElementById("code-section");
|
|
||||||
const handleClick = () => {
|
|
||||||
if (codeSection.classList.contains("code-section-hidden")) {
|
|
||||||
codeSection.classList.remove("code-section-hidden");
|
|
||||||
codeSection.classList.add("code-section-visible");
|
|
||||||
} else {
|
|
||||||
codeSection.classList.remove("code-section-visible");
|
|
||||||
codeSection.classList.add("code-section-hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
viewCodeButton.addEventListener("click", handleClick)
|
|
||||||
viewCodeButton.addEventListener("keydown", (e) => {
|
|
||||||
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
|
|
||||||
handleClick();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,216 +1,136 @@
|
|||||||
<html><head>
|
<html>
|
||||||
<title>Bokeh Example</title>
|
<head>
|
||||||
<meta charset="iso-8859-1">
|
<title>Bokeh Example</title>
|
||||||
<link rel="icon" type="image/x-icon" href="./favicon.png">
|
<meta charset="iso-8859-1" />
|
||||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.js"></script>
|
<link rel="icon" type="image/x-icon" href="./favicon.png" />
|
||||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-2.4.2.min.js"></script>
|
<script
|
||||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js"></script>
|
type="text/javascript"
|
||||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js"></script>
|
src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.3.js"
|
||||||
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.2.min.js"></script>
|
></script>
|
||||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
<script
|
||||||
<link rel="stylesheet" href="./assets/prism/prism.css" />
|
type="text/javascript"
|
||||||
<script defer src="./assets/prism/prism.js"></script>
|
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">
|
<script type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
|
/>
|
||||||
|
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar" style="background-color: #000000;">
|
<nav class="navbar" style="background-color: #000000">
|
||||||
<div class="app-header">
|
<div class="app-header">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<img src="./logo.png" class="logo">
|
<img src="./logo.png" class="logo" />
|
||||||
</a>
|
</a>
|
||||||
<a class="title" href="" style="color: #f0ab3c;">Bokeh Example</a>
|
<a class="title" href="" style="color: #f0ab3c"
|
||||||
</div>
|
>Bokeh Example</a
|
||||||
</nav>
|
>
|
||||||
<section class="pyscript">
|
</div>
|
||||||
<h1>Bokeh Example</h1>
|
</nav>
|
||||||
<div id="myplot"></div>
|
<py-tutor>
|
||||||
|
<section class="pyscript">
|
||||||
|
<h1>Bokeh Example</h1>
|
||||||
|
<div id="myplot"></div>
|
||||||
|
|
||||||
<py-config>
|
<py-config>
|
||||||
packages = [
|
packages = [
|
||||||
"bokeh",
|
"https://cdn.holoviz.org/panel/0.14.3/dist/wheels/bokeh-2.4.3-py3-none-any.whl",
|
||||||
"numpy"
|
"numpy",
|
||||||
]
|
]
|
||||||
</py-config>
|
plugins = [
|
||||||
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
|
]
|
||||||
|
</py-config>
|
||||||
|
|
||||||
<py-script id="main">
|
<py-script id="main">
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import pyodide
|
import pyodide
|
||||||
|
|
||||||
from js import Bokeh, console, JSON
|
from js import Bokeh, console, JSON
|
||||||
|
|
||||||
from bokeh import __version__
|
from bokeh import __version__
|
||||||
from bokeh.document import Document
|
from bokeh.document import Document
|
||||||
from bokeh.embed.util import OutputDocumentFor, standalone_docs_json_and_render_items
|
from bokeh.embed.util import OutputDocumentFor, standalone_docs_json_and_render_items
|
||||||
from bokeh.models import Slider, Div
|
from bokeh.models import Slider, Div
|
||||||
from bokeh.layouts import Row
|
from bokeh.layouts import Row
|
||||||
from bokeh.protocol.messages.patch_doc import process_document_events
|
from bokeh.protocol.messages.patch_doc import process_document_events
|
||||||
|
|
||||||
# create a new plot with default tools, using figure
|
# create a new plot with default tools, using figure
|
||||||
p = Slider(start=0.1, end=10, value=1, step=.1, title="Amplitude")
|
p = Slider(start=0.1, end=10, value=1, step=.1, title="Amplitude")
|
||||||
div = Div(text=f'Amplitude is: {p.value}')
|
div = Div(text=f'Amplitude is: {p.value}')
|
||||||
|
|
||||||
def callback(attr, old, new):
|
def callback(attr, old, new):
|
||||||
div.text = f'Amplitude is: {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):
|
def doc_json(model, target):
|
||||||
with OutputDocumentFor([model]) as doc:
|
with OutputDocumentFor([model]) as doc:
|
||||||
doc.title = ""
|
doc.title = ""
|
||||||
docs_json, _ = standalone_docs_json_and_render_items(
|
docs_json, _ = standalone_docs_json_and_render_items(
|
||||||
[model], suppress_callback_warning=True
|
[model], suppress_callback_warning=True
|
||||||
)
|
)
|
||||||
|
|
||||||
doc_json = list(docs_json.values())[0]
|
doc_json = list(docs_json.values())[0]
|
||||||
root_id = doc_json['roots']['root_ids'][0]
|
root_id = doc_json['roots']['root_ids'][0]
|
||||||
|
|
||||||
return doc, json.dumps(dict(
|
return doc, json.dumps(dict(
|
||||||
target_id = target,
|
target_id = target,
|
||||||
root_id = root_id,
|
root_id = root_id,
|
||||||
doc = doc_json,
|
doc = doc_json,
|
||||||
version = __version__,
|
version = __version__,
|
||||||
))
|
))
|
||||||
|
|
||||||
def _link_docs(pydoc, jsdoc):
|
def _link_docs(pydoc, jsdoc):
|
||||||
def jssync(event):
|
def jssync(event):
|
||||||
if getattr(event, 'setter_id', None) is not None:
|
if getattr(event, 'setter_id', None) is not None:
|
||||||
return
|
return
|
||||||
events = [event]
|
events = [event]
|
||||||
json_patch = jsdoc.create_json_patch_string(pyodide.ffi.to_js(events))
|
json_patch = jsdoc.create_json_patch_string(pyodide.ffi.to_js(events))
|
||||||
pydoc.apply_json_patch(json.loads(json_patch))
|
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):
|
def pysync(event):
|
||||||
json_patch, buffers = process_document_events([event], use_buffers=True)
|
json_patch, buffers = process_document_events([event], use_buffers=True)
|
||||||
buffer_map = {}
|
buffer_map = {}
|
||||||
for (ref, buffer) in buffers:
|
for (ref, buffer) in buffers:
|
||||||
buffer_map[ref['id']] = buffer
|
buffer_map[ref['id']] = buffer
|
||||||
jsdoc.apply_json_patch(JSON.parse(json_patch), pyodide.ffi.to_js(buffer_map), setter_id='js')
|
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):
|
async def show(plot, target):
|
||||||
pydoc, model_json = doc_json(plot, target)
|
pydoc, model_json = doc_json(plot, target)
|
||||||
views = await Bokeh.embed.embed_item(JSON.parse(model_json))
|
views = await Bokeh.embed.embed_item(JSON.parse(model_json))
|
||||||
jsdoc = views[0].model.document
|
jsdoc = views[0].model.document
|
||||||
_link_docs(pydoc, jsdoc)
|
_link_docs(pydoc, jsdoc)
|
||||||
|
|
||||||
asyncio.ensure_future(show(row, 'myplot'))
|
asyncio.ensure_future(show(row, 'myplot'))
|
||||||
</py-script>
|
</py-script>
|
||||||
</section>
|
</section>
|
||||||
<section class="code">
|
</py-tutor>
|
||||||
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
|
</body>
|
||||||
<div id="code-section" class="code-section-hidden">
|
|
||||||
<p>index.html</p>
|
|
||||||
<pre class="prism-code language-html">
|
|
||||||
<code class="language-html">
|
|
||||||
<py-config>
|
|
||||||
packages = [
|
|
||||||
"bokeh",
|
|
||||||
"numpy"
|
|
||||||
]
|
|
||||||
</py-config>
|
|
||||||
<py-script id="main">
|
|
||||||
import asyncio
|
|
||||||
import json
|
|
||||||
import pyodide
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
# 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}'
|
|
||||||
|
|
||||||
p.on_change('value', callback)
|
|
||||||
|
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
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__,
|
|
||||||
))
|
|
||||||
|
|
||||||
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))
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
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>
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</body>
|
|
||||||
<script>
|
|
||||||
const viewCodeButton = document.getElementById("view-code-button");
|
|
||||||
const codeSection = document.getElementById("code-section");
|
|
||||||
const handleClick = () => {
|
|
||||||
if (codeSection.classList.contains("code-section-hidden")) {
|
|
||||||
codeSection.classList.remove("code-section-hidden");
|
|
||||||
codeSection.classList.add("code-section-visible");
|
|
||||||
} else {
|
|
||||||
codeSection.classList.remove("code-section-visible");
|
|
||||||
codeSection.classList.add("code-section-hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
viewCodeButton.addEventListener("click", handleClick)
|
|
||||||
viewCodeButton.addEventListener("keydown", (e) => {
|
|
||||||
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
|
|
||||||
handleClick();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
404
examples/d3.html
404
examples/d3.html
@@ -1,314 +1,138 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>d3: JavaScript & PyScript visualizations side-by-side</title>
|
<title>d3: JavaScript & PyScript visualizations side-by-side</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<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://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
rel="stylesheet"
|
||||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
<link rel="stylesheet" href="./assets/prism/prism.css" />
|
/>
|
||||||
<script defer src="./assets/prism/prism.js"></script>
|
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
||||||
<script src="https://d3js.org/d3.v7.min.js"></script>
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
<style>
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
||||||
.loading {
|
<style>
|
||||||
display: inline-block;
|
.loading {
|
||||||
width: 50px;
|
display: inline-block;
|
||||||
height: 50px;
|
width: 50px;
|
||||||
border: 3px solid rgba(255, 255, 255, 0.3);
|
height: 50px;
|
||||||
border-radius: 50%;
|
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||||
border-top-color: black;
|
border-radius: 50%;
|
||||||
animation: spin 1s ease-in-out infinite;
|
border-top-color: black;
|
||||||
}
|
animation: spin 1s ease-in-out infinite;
|
||||||
|
}
|
||||||
@keyframes spin {
|
|
||||||
to {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar" style="background-color: #000000;">
|
<nav class="navbar" style="background-color: #000000">
|
||||||
<div class="app-header">
|
<div class="app-header">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<img src="./logo.png" class="logo">
|
<img src="./logo.png" class="logo" />
|
||||||
</a>
|
</a>
|
||||||
<a class="title" href="" style="color: #f0ab3c;">Simple d3 visualization</a>
|
<a class="title" href="" style="color: #f0ab3c"
|
||||||
</div>
|
>Simple d3 visualization</a
|
||||||
</nav>
|
>
|
||||||
<section class="pyscript">
|
</div>
|
||||||
<b>
|
</nav>
|
||||||
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>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="module">
|
<section class="pyscript">
|
||||||
|
<py-tutor modules="d3.py">
|
||||||
const fruits = [
|
<py-config>
|
||||||
{name: "🍊", count: 21},
|
plugins = [
|
||||||
{name: "🍇", count: 13},
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
{name: "🍏", count: 8},
|
]
|
||||||
{name: "🍌", count: 5},
|
[[fetch]]
|
||||||
{name: "🍐", count: 3},
|
files = ["./d3.py"]
|
||||||
{name: "🍋", count: 2},
|
</py-config>
|
||||||
{name: "🍎", count: 1},
|
</py-tutor>
|
||||||
{name: "🍉", count: 1},
|
<b>
|
||||||
]
|
Based on
|
||||||
|
<i
|
||||||
const fn = (d) => d.count
|
><a
|
||||||
const data = d3.pie().value(fn)(fruits)
|
href="https://observablehq.com/@d3/learn-d3-shapes?collection=@d3/learn-d3>"
|
||||||
|
>Learn D3: Shapes</a
|
||||||
const arc = d3.arc()
|
></i
|
||||||
.innerRadius(210)
|
>
|
||||||
.outerRadius(310)
|
tutorial.
|
||||||
.padRadius(300)
|
</b>
|
||||||
.padAngle(2 / 300)
|
<div style="display: flex; flex-direction: row">
|
||||||
.cornerRadius(8)
|
<div>
|
||||||
|
<div style="text-align: center">JavaScript version</div>
|
||||||
const js = d3.select("#js")
|
<div id="js" style="width: 400px; height: 400px">
|
||||||
js.select(".loading").remove()
|
<div class="loading"></div>
|
||||||
|
</div>
|
||||||
const svg = js
|
</div>
|
||||||
.append("svg")
|
<div>
|
||||||
.attr("viewBox", "-320 -320 640 640")
|
<div style="text-align: center">PyScript version</div>
|
||||||
.attr("width", "400")
|
<div id="py" style="width: 400px; height: 400px">
|
||||||
.attr("height", "400")
|
<div class="loading"></div>
|
||||||
|
</div>
|
||||||
for (const d of data) {
|
</div>
|
||||||
svg.append("path")
|
</div>
|
||||||
.style("fill", "steelblue")
|
<py-script src="d3.py"></py-script>
|
||||||
.attr("d", arc(d))
|
</section>
|
||||||
|
|
||||||
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", "18")
|
|
||||||
.attr("x", "0")
|
|
||||||
.attr("dy", "1.3em")
|
|
||||||
.text(d.value)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<py-script>
|
|
||||||
import js
|
|
||||||
from pyodide.ffi import create_proxy, to_js
|
|
||||||
d3 = js.d3
|
|
||||||
|
|
||||||
fruits = [
|
|
||||||
dict(name="🍊", count=21),
|
|
||||||
dict(name="🍇", count=13),
|
|
||||||
dict(name="🍏", count=8),
|
|
||||||
dict(name="🍌", count=5),
|
|
||||||
dict(name="🍐", count=3),
|
|
||||||
dict(name="🍋", count=2),
|
|
||||||
dict(name="🍎", count=1),
|
|
||||||
dict(name="🍉", count=1),
|
|
||||||
]
|
|
||||||
|
|
||||||
fn = create_proxy(lambda d, *_: d["count"])
|
|
||||||
data = d3.pie().value(fn)(to_js(fruits))
|
|
||||||
|
|
||||||
arc = (d3.arc()
|
|
||||||
.innerRadius(210)
|
|
||||||
.outerRadius(310)
|
|
||||||
.padRadius(300)
|
|
||||||
.padAngle(2 / 300)
|
|
||||||
.cornerRadius(8))
|
|
||||||
|
|
||||||
py = d3.select("#py")
|
|
||||||
py.select(".loading").remove()
|
|
||||||
|
|
||||||
svg = (py
|
|
||||||
.append("svg")
|
|
||||||
.attr("viewBox", "-320 -320 640 640")
|
|
||||||
.attr("width", "400")
|
|
||||||
.attr("height", "400"))
|
|
||||||
|
|
||||||
for d in data:
|
|
||||||
d_py = d.to_py()
|
|
||||||
|
|
||||||
(svg.append("path")
|
|
||||||
.style("fill", "steelblue")
|
|
||||||
.attr("d", arc(d)))
|
|
||||||
|
|
||||||
text = (svg.append("text")
|
|
||||||
.style("fill", "white")
|
|
||||||
.attr("transform", f"translate({arc.centroid(d).join(',')})")
|
|
||||||
.attr("text-anchor", "middle"))
|
|
||||||
|
|
||||||
(text.append("tspan")
|
|
||||||
.style("font-size", "24")
|
|
||||||
.attr("x", "0")
|
|
||||||
.text(d_py["data"]["name"]))
|
|
||||||
|
|
||||||
(text.append("tspan")
|
|
||||||
.style("font-size", "18")
|
|
||||||
.attr("x", "0")
|
|
||||||
.attr("dy", "1.3em")
|
|
||||||
.text(d_py["value"]))
|
|
||||||
</py-script>
|
|
||||||
</section>
|
|
||||||
<section class="code">
|
|
||||||
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
|
|
||||||
<div id="code-section" class="code-section-hidden">
|
|
||||||
<p>index.html</p>
|
|
||||||
<pre class="prism-code language-html">
|
|
||||||
<code class="language-html">
|
|
||||||
<script>
|
|
||||||
import * as d3 from "https://cdn.skypack.dev/pin/d3@v7.6.1-1Q0NZ0WZnbYeSjDusJT3/mode=imports,min/optimized/d3.js";
|
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
const fruits = [
|
const fruits = [
|
||||||
{name: "🍊", count: 21},
|
{ name: "🍊", count: 21 },
|
||||||
{name: "🍇", count: 13},
|
{ name: "🍇", count: 13 },
|
||||||
{name: "🍏", count: 8},
|
{ name: "🍏", count: 8 },
|
||||||
{name: "🍌", count: 5},
|
{ name: "🍌", count: 5 },
|
||||||
{name: "🍐", count: 3},
|
{ name: "🍐", count: 3 },
|
||||||
{name: "🍋", count: 2},
|
{ name: "🍋", count: 2 },
|
||||||
{name: "🍎", count: 1},
|
{ name: "🍎", count: 1 },
|
||||||
{name: "🍉", count: 1},
|
{ name: "🍉", count: 1 },
|
||||||
]
|
];
|
||||||
|
|
||||||
const fn = (d) => d.count
|
const fn = (d) => d.count;
|
||||||
const data = d3.pie().value(fn)(fruits)
|
const data = d3.pie().value(fn)(fruits);
|
||||||
|
|
||||||
const arc = d3.arc()
|
const arc = d3
|
||||||
.innerRadius(210)
|
.arc()
|
||||||
.outerRadius(310)
|
|
||||||
.padRadius(300)
|
|
||||||
.padAngle(2 / 300)
|
|
||||||
.cornerRadius(8)
|
|
||||||
|
|
||||||
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")
|
|
||||||
|
|
||||||
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")
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<py-script>
|
|
||||||
from pyodide.ffi import create_proxy, to_js
|
|
||||||
import d3
|
|
||||||
|
|
||||||
fruits = [
|
|
||||||
dict(name="🍊", count=21),
|
|
||||||
dict(name="🍇", count=13),
|
|
||||||
dict(name="🍏", count=8),
|
|
||||||
dict(name="🍌", count=5),
|
|
||||||
dict(name="🍐", count=3),
|
|
||||||
dict(name="🍋", count=2),
|
|
||||||
dict(name="🍎", count=1),
|
|
||||||
dict(name="🍉", count=1),
|
|
||||||
]
|
|
||||||
|
|
||||||
fn = create_proxy(lambda d, *_: d["count"])
|
|
||||||
data = d3.pie().value(fn)(to_js(fruits))
|
|
||||||
|
|
||||||
arc = (d3.arc()
|
|
||||||
.innerRadius(210)
|
.innerRadius(210)
|
||||||
.outerRadius(310)
|
.outerRadius(310)
|
||||||
.padRadius(300)
|
.padRadius(300)
|
||||||
.padAngle(2 / 300)
|
.padAngle(2 / 300)
|
||||||
.cornerRadius(8))
|
.cornerRadius(8);
|
||||||
|
|
||||||
py = d3.select("#py")
|
const js = d3.select("#js");
|
||||||
py.select(".loading").remove()
|
js.select(".loading").remove();
|
||||||
|
|
||||||
svg = (py
|
const svg = js
|
||||||
.append("svg")
|
.append("svg")
|
||||||
.attr("viewBox", "-320 -320 640 640")
|
.attr("viewBox", "-320 -320 640 640")
|
||||||
.attr("width", "400")
|
.attr("width", "400")
|
||||||
.attr("height", "400"))
|
.attr("height", "400");
|
||||||
|
|
||||||
for d in data:
|
for (const d of data) {
|
||||||
d_py = d.to_py()
|
svg.append("path").style("fill", "steelblue").attr("d", arc(d));
|
||||||
|
|
||||||
(svg.append("path")
|
const text = svg
|
||||||
.style("fill", "steelblue")
|
.append("text")
|
||||||
.attr("d", arc(d)))
|
.style("fill", "white")
|
||||||
|
.attr(
|
||||||
|
"transform",
|
||||||
|
`translate(${arc.centroid(d).join(",")})`,
|
||||||
|
)
|
||||||
|
.attr("text-anchor", "middle");
|
||||||
|
|
||||||
text = (svg.append("text")
|
text.append("tspan")
|
||||||
.style("fill", "white")
|
.style("font-size", "24")
|
||||||
.attr("transform", f"translate({arc.centroid(d).join(',')})")
|
.attr("x", "0")
|
||||||
.attr("text-anchor", "middle"))
|
.text(d.data.name);
|
||||||
|
|
||||||
(text.append("tspan")
|
text.append("tspan")
|
||||||
.style("font-size", "24")
|
.style("font-size", "18")
|
||||||
.attr("x", "0")
|
.attr("x", "0")
|
||||||
.text(d_py["data"]["name"]))
|
.attr("dy", "1.3em")
|
||||||
|
.text(d.value);
|
||||||
(text.append("tspan")
|
}
|
||||||
.style("font-size", "18")
|
</script>
|
||||||
.attr("x", "0")
|
</body>
|
||||||
.attr("dy", "1.3em")
|
|
||||||
.text(d_py["value"]))
|
|
||||||
</py-script>
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</body>
|
|
||||||
<script>
|
|
||||||
const viewCodeButton = document.getElementById("view-code-button");
|
|
||||||
const codeSection = document.getElementById("code-section");
|
|
||||||
const handleClick = () => {
|
|
||||||
if (codeSection.classList.contains("code-section-hidden")) {
|
|
||||||
codeSection.classList.remove("code-section-hidden");
|
|
||||||
codeSection.classList.add("code-section-visible");
|
|
||||||
} else {
|
|
||||||
codeSection.classList.remove("code-section-visible");
|
|
||||||
codeSection.classList.add("code-section-hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
viewCodeButton.addEventListener("click", handleClick)
|
|
||||||
viewCodeButton.addEventListener("keydown", (e) => {
|
|
||||||
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
|
|
||||||
handleClick();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
64
examples/d3.py
Normal file
64
examples/d3.py
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import js
|
||||||
|
from pyodide.ffi import create_proxy, to_js
|
||||||
|
|
||||||
|
d3 = js.d3
|
||||||
|
|
||||||
|
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},
|
||||||
|
]
|
||||||
|
|
||||||
|
fn = create_proxy(lambda d, *_: d["count"])
|
||||||
|
data = d3.pie().value(fn)(to_js(fruits))
|
||||||
|
|
||||||
|
arc = (
|
||||||
|
d3.arc()
|
||||||
|
.innerRadius(210)
|
||||||
|
.outerRadius(310)
|
||||||
|
.padRadius(300)
|
||||||
|
.padAngle(2 / 300)
|
||||||
|
.cornerRadius(8)
|
||||||
|
)
|
||||||
|
|
||||||
|
py = d3.select("#py")
|
||||||
|
py.select(".loading").remove()
|
||||||
|
|
||||||
|
svg = (
|
||||||
|
py.append("svg")
|
||||||
|
.attr("viewBox", "-320 -320 640 640")
|
||||||
|
.attr("width", "400")
|
||||||
|
.attr("height", "400")
|
||||||
|
)
|
||||||
|
|
||||||
|
for d in data:
|
||||||
|
d_py = d.to_py()
|
||||||
|
|
||||||
|
(svg.append("path").style("fill", "steelblue").attr("d", arc(d)))
|
||||||
|
|
||||||
|
text = (
|
||||||
|
svg.append("text")
|
||||||
|
.style("fill", "white")
|
||||||
|
.attr("transform", f"translate({arc.centroid(d).join(',')})")
|
||||||
|
.attr("text-anchor", "middle")
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
text.append("tspan")
|
||||||
|
.style("font-size", "24")
|
||||||
|
.attr("x", "0")
|
||||||
|
.text(d_py["data"]["name"])
|
||||||
|
)
|
||||||
|
|
||||||
|
(
|
||||||
|
text.append("tspan")
|
||||||
|
.style("font-size", "18")
|
||||||
|
.attr("x", "0")
|
||||||
|
.attr("dy", "1.3em")
|
||||||
|
.text(d_py["value"])
|
||||||
|
)
|
||||||
@@ -1,136 +1,81 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Folium</title>
|
<title>Folium</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<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://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
rel="stylesheet"
|
||||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
<link rel="stylesheet" href="./assets/prism/prism.css" />
|
/>
|
||||||
<script defer src="./assets/prism/prism.js"></script>
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
|
<style>
|
||||||
|
py-script {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script
|
||||||
|
type="module"
|
||||||
|
src="https://esm.sh/@pyscript/core@latest/core.js"
|
||||||
|
></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar" style="background-color: #000000;">
|
<nav class="navbar" style="background-color: #000000">
|
||||||
<div class="app-header">
|
<div class="app-header">
|
||||||
<a href="/">
|
<a href="/">
|
||||||
<img src="./logo.png" class="logo">
|
<img src="./logo.png" class="logo" />
|
||||||
</a>
|
</a>
|
||||||
<a class="title" href="" style="color: #f0ab3c;">Folium</a>
|
<a class="title" href="" style="color: #f0ab3c">Folium</a>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<section class="pyscript">
|
<section class="pyscript">
|
||||||
<div id="folium"></div>
|
<div id="folium"></div>
|
||||||
|
|
||||||
<py-config>
|
<py-tutor>
|
||||||
packages = [
|
<py-config>
|
||||||
"folium",
|
packages = [
|
||||||
"pandas"
|
"folium",
|
||||||
]
|
"pandas"
|
||||||
</py-config>
|
]
|
||||||
|
plugins = [
|
||||||
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
|
]
|
||||||
|
</py-config>
|
||||||
|
|
||||||
<py-script>
|
<py-script>
|
||||||
import folium
|
from pyscript import display
|
||||||
import json
|
import folium
|
||||||
import pandas as pd
|
import json
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
from pyodide.http import open_url
|
from pyodide.http import open_url
|
||||||
|
|
||||||
url = (
|
url = (
|
||||||
"https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
|
"https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
|
||||||
)
|
)
|
||||||
state_geo = f"{url}/us-states.json"
|
state_geo = f"{url}/us-states.json"
|
||||||
state_unemployment = f"{url}/US_Unemployment_Oct2012.csv"
|
state_unemployment = f"{url}/US_Unemployment_Oct2012.csv"
|
||||||
state_data = pd.read_csv(open_url(state_unemployment))
|
state_data = pd.read_csv(open_url(state_unemployment))
|
||||||
geo_json = json.loads(open_url(state_geo).read())
|
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(
|
folium.Choropleth(
|
||||||
geo_data=geo_json,
|
geo_data=geo_json,
|
||||||
name="choropleth",
|
name="choropleth",
|
||||||
data=state_data,
|
data=state_data,
|
||||||
columns=["State", "Unemployment"],
|
columns=["State", "Unemployment"],
|
||||||
key_on="feature.id",
|
key_on="feature.id",
|
||||||
fill_color="YlGn",
|
fill_color="YlGn",
|
||||||
fill_opacity=0.7,
|
fill_opacity=0.7,
|
||||||
line_opacity=0.2,
|
line_opacity=0.2,
|
||||||
legend_name="Unemployment Rate (%)",
|
legend_name="Unemployment Rate (%)",
|
||||||
).add_to(m)
|
).add_to(m)
|
||||||
|
|
||||||
folium.LayerControl().add_to(m)
|
folium.LayerControl().add_to(m)
|
||||||
|
|
||||||
display(m, target="folium")
|
display(m, target="folium")
|
||||||
</py-script>
|
</py-script>
|
||||||
</section>
|
</py-tutor>
|
||||||
<section class="code">
|
</section>
|
||||||
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
|
</body>
|
||||||
<div id="code-section" class="code-section-hidden">
|
|
||||||
<p>index.html</p>
|
|
||||||
<pre class="prism-code language-html">
|
|
||||||
<code class="language-html">
|
|
||||||
|
|
||||||
<div id="folium"></div>
|
|
||||||
<py-config>
|
|
||||||
packages = [
|
|
||||||
"folium",
|
|
||||||
"pandas"
|
|
||||||
]
|
|
||||||
</py-config>
|
|
||||||
<py-script>
|
|
||||||
import folium
|
|
||||||
import json
|
|
||||||
import pandas as pd
|
|
||||||
|
|
||||||
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())
|
|
||||||
|
|
||||||
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.LayerControl().add_to(m)
|
|
||||||
|
|
||||||
display(m, target="folium")
|
|
||||||
</py-script>
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</body>
|
|
||||||
<script>
|
|
||||||
const viewCodeButton = document.getElementById("view-code-button");
|
|
||||||
const codeSection = document.getElementById("code-section");
|
|
||||||
const handleClick = () => {
|
|
||||||
if (codeSection.classList.contains("code-section-hidden")) {
|
|
||||||
codeSection.classList.remove("code-section-hidden");
|
|
||||||
codeSection.classList.add("code-section-visible");
|
|
||||||
} else {
|
|
||||||
codeSection.classList.remove("code-section-visible");
|
|
||||||
codeSection.classList.add("code-section-hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
viewCodeButton.addEventListener("click", handleClick)
|
|
||||||
viewCodeButton.addEventListener("keydown", (e) => {
|
|
||||||
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
|
|
||||||
handleClick();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,122 +1,138 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
<title>Say Hello</title>
|
<title>Say Hello</title>
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="../favicon.png" />
|
<link rel="icon" type="image/png" href="../favicon.png" />
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
|
/>
|
||||||
|
<script defer src="../../pyscriptjs/build/pyscript.js"></script>
|
||||||
|
<!-- <script defer src="https://pyscript.net/latest/pyscript.js"></script> -->
|
||||||
|
</head>
|
||||||
|
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
<body>
|
||||||
</head>
|
<py-script>
|
||||||
|
from js import handTrack, requestAnimationFrame, console
|
||||||
|
from pyodide import create_once_callable
|
||||||
|
import asyncio
|
||||||
|
|
||||||
<body>
|
update_note = Element("update-note")
|
||||||
<py-script>
|
canvas = Element("canvas")
|
||||||
from js import handTrack, requestAnimationFrame
|
video = Element("myvideo")
|
||||||
from pyodide import create_once_callable
|
context = canvas.element.getContext("2d")
|
||||||
import asyncio
|
|
||||||
|
|
||||||
context = canvas.element.getContext("2d")
|
isVideo = False
|
||||||
|
model = None
|
||||||
|
|
||||||
isVideo = False
|
modelParams = {
|
||||||
model = None
|
"flipHorizontal": True, # flip e.g for video
|
||||||
|
"maxNumBoxes": 20, # maximum number of boxes to detect
|
||||||
|
"iouThreshold": 0.5, # ioU threshold for non-max suppression
|
||||||
|
"scoreThreshold": 0.6, # confidence threshold for predictions.
|
||||||
|
}
|
||||||
|
|
||||||
modelParams = {
|
def toggle_video():
|
||||||
"flipHorizontal": True, # flip e.g for video
|
global isVideo
|
||||||
"maxNumBoxes": 20, # maximum number of boxes to detect
|
if (not isVideo):
|
||||||
"iouThreshold": 0.5, # ioU threshold for non-max suppression
|
update_note.write("Starting video")
|
||||||
"scoreThreshold": 0.6, # confidence threshold for predictions.
|
pyscript.run_until_complete(start_video())
|
||||||
}
|
else:
|
||||||
|
update_note.write("Stopping video")
|
||||||
|
handTrack.stopVideo(video.element)
|
||||||
|
isVideo = False
|
||||||
|
update_note.write("Video stopped")
|
||||||
|
|
||||||
def toggle_video(evt):
|
async def start_video():
|
||||||
global isVideo
|
global isVideo
|
||||||
if (not isVideo):
|
update_note.write("Inside sstart video")
|
||||||
update_note.write("Starting video")
|
status = await handTrack.startVideo(video.element)
|
||||||
pyscript.run_until_complete(start_video())
|
console.log("video started", status)
|
||||||
else:
|
if status:
|
||||||
update_note.write("Stopping video")
|
update_note.write("Video started. Now tracking")
|
||||||
handTrack.stopVideo(video.element)
|
isVideo = True
|
||||||
isVideo = False
|
console.log( "Calling RUN DETECTION")
|
||||||
update_note.write("Video stopped")
|
y = await run_detection()
|
||||||
|
else:
|
||||||
|
update_note.write( "Please enable video")
|
||||||
|
|
||||||
async def start_video():
|
def sync_run_detection(evt):
|
||||||
global isVideo
|
pyscript.run_until_complete(run_detection())
|
||||||
update_note.write("Inside sstart video")
|
|
||||||
status = await handTrack.startVideo(video.element)
|
|
||||||
console.log("video started", status)
|
|
||||||
if status:
|
|
||||||
update_note.write("Video started. Now tracking")
|
|
||||||
isVideo = True
|
|
||||||
console.log( "Calling RUN DETECTION")
|
|
||||||
y = await run_detection()
|
|
||||||
else:
|
|
||||||
update_note.write( "Please enable video")
|
|
||||||
|
|
||||||
def sync_run_detection(evt):
|
async def run_detection():
|
||||||
pyscript.run_until_complete(run_detection())
|
console.log("in RUN DETECTION: ");
|
||||||
|
global model
|
||||||
|
global isVideo
|
||||||
|
|
||||||
async def run_detection():
|
console.log("...1")
|
||||||
console.log("in RUN DETECTION: ");
|
|
||||||
global model
|
|
||||||
global isVideo
|
|
||||||
|
|
||||||
console.log("...1")
|
predictions = await model.detect(video.element)
|
||||||
|
console.log("done...1")
|
||||||
|
console.log("Predictions: ", predictions);
|
||||||
|
model.renderPredictions(predictions, canvas.element, context, video.element);
|
||||||
|
console.log("is Video?", isVideo)
|
||||||
|
if (isVideo):
|
||||||
|
console.log("requestingAnimation!")
|
||||||
|
await requestAnimationFrame(create_once_callable(sync_run_detection));
|
||||||
|
console.log("...2")
|
||||||
|
|
||||||
predictions = await model.detect(video.element)
|
def run_detection_image(img):
|
||||||
console.log("done...1")
|
console.log("in RUN DETECTION IMAGE", predictions);
|
||||||
console.log("Predictions: ", predictions);
|
global model
|
||||||
model.renderPredictions(predictions, canvas.element, context, video.element);
|
def detect(predition):
|
||||||
console.log("is Video?", isVideo)
|
console.log("Predictions: ", predictions);
|
||||||
if (isVideo):
|
model.renderPredictions(predictions, canvas, context, img);
|
||||||
console.log("requestingAnimation!")
|
console.log("...3")
|
||||||
await requestAnimationFrame(create_once_callable(sync_run_detection));
|
model.detect(img).then(detect)
|
||||||
console.log("...2")
|
console.log("...4")
|
||||||
|
|
||||||
def run_detection_image(img):
|
def handle_model(lmodel):
|
||||||
console.log("in RUN DETECTION IMAGE", predictions);
|
global model
|
||||||
global model
|
model = lmodel
|
||||||
def detect(predition):
|
update_note.write("Loaded Model!")
|
||||||
console.log("Predictions: ", predictions);
|
|
||||||
model.renderPredictions(predictions, canvas, context, img);
|
|
||||||
console.log("...3")
|
|
||||||
model.detect(img).then(detect)
|
|
||||||
console.log("...4")
|
|
||||||
|
|
||||||
def handle_model(lmodel):
|
async def start():
|
||||||
global model
|
console.log("creating x")
|
||||||
model = lmodel
|
console.log("calling x")
|
||||||
update_note.write("Loaded Model!")
|
model = await handTrack.load(modelParams)#.then(handle_model)
|
||||||
|
console.log("loaded model!")
|
||||||
|
console.log(model)
|
||||||
|
handle_model(model)
|
||||||
|
print(dir(x))
|
||||||
|
print(x)
|
||||||
|
|
||||||
async def start():
|
pyscript.run_until_complete(start())
|
||||||
console.log("creating x")
|
|
||||||
console.log("calling x")
|
|
||||||
model = await handTrack.load(modelParams)#.then(handle_model)
|
|
||||||
console.log("loaded model!")
|
|
||||||
console.log(model)
|
|
||||||
handle_model(model)
|
|
||||||
print(dir(x))
|
|
||||||
print(x)
|
|
||||||
|
|
||||||
pyscript.run_until_complete(start())
|
#});
|
||||||
|
</py-script>
|
||||||
|
|
||||||
#});
|
<div class="mb10">
|
||||||
|
<button
|
||||||
</py-script>
|
id="trackbutton"
|
||||||
|
class="bx--btn bx--btn--secondary"
|
||||||
<div class="mb10">
|
type="button"
|
||||||
<button id="trackbutton" class="bx--btn bx--btn--secondary" type="button" py-onClick="toggle_video()">
|
py-click="toggle_video()"
|
||||||
Toggle Video
|
>
|
||||||
</button>
|
Toggle Video
|
||||||
<button id="nextimagebutton" class="mt10 bx--btn bx--btn--secondary" type="button" disabled>
|
</button>
|
||||||
Next Image
|
<button
|
||||||
</button>
|
id="nextimagebutton"
|
||||||
<div id="update-note" py-mount class="updatenote mt10">loading model ..</div>
|
class="mt10 bx--btn bx--btn--secondary"
|
||||||
</div>
|
type="button"
|
||||||
<div>
|
disabled
|
||||||
<video autoplay="autoplay" id="myvideo" py-mount="video"></video>
|
>
|
||||||
<canvas id="canvas" py-mount class="border canvasbox"></canvas>
|
Next Image
|
||||||
</div>
|
</button>
|
||||||
<script src="lib/handtrack.min.js"> </script>
|
<div id="update-note" class="updatenote mt10">loading model ..</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<video autoplay="autoplay" id="myvideo" py-mount="video"></video>
|
||||||
|
<canvas id="canvas" class="border canvasbox"></canvas>
|
||||||
|
</div>
|
||||||
|
<script src="lib/handtrack.min.js"></script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,71 +1,55 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
|
|
||||||
<title>PyScript Hello World</title>
|
<title>PyScript Hello World</title>
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="favicon.png" />
|
<link rel="icon" type="image/png" href="favicon.png" />
|
||||||
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
|
<link
|
||||||
<link rel="stylesheet" href="./assets/css/examples.css" />
|
rel="stylesheet"
|
||||||
<link rel="stylesheet" href="./assets/prism/prism.css" />
|
href="https://pyscript.net/latest/pyscript.css"
|
||||||
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
|
/>
|
||||||
<script defer src="./assets/prism/prism.js"></script>
|
<link rel="stylesheet" href="./assets/css/examples.css" />
|
||||||
</head>
|
<style>
|
||||||
|
py-script {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script
|
||||||
|
type="module"
|
||||||
|
src="https://esm.sh/@pyscript/core@latest/core.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">Hello World</a>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<body>
|
<py-tutor>
|
||||||
<nav class="navbar" style="background-color: #000000;">
|
<py-config>
|
||||||
<div class="app-header">
|
plugins = [
|
||||||
<a href="/">
|
"https://pyscript.net/latest/plugins/python/py_tutor.py"
|
||||||
<img src="./logo.png" class="logo">
|
]
|
||||||
</a>
|
</py-config>
|
||||||
<a class="title" href="" style="color: #f0ab3c;">Hello World</a>
|
|
||||||
</div>
|
<section class="pyscript">
|
||||||
</nav>
|
Hello world! <br />
|
||||||
<section class="pyscript">
|
This is the current date and time, as computed by Python:
|
||||||
Hello world! <br>
|
<py-script>
|
||||||
This is the current date and time, as computed by Python:
|
from pyscript import display
|
||||||
<py-script>
|
from datetime import datetime
|
||||||
from datetime import datetime
|
now = datetime.now()
|
||||||
now = datetime.now()
|
display(now.strftime("%m/%d/%Y, %H:%M:%S"))
|
||||||
display(now.strftime("%m/%d/%Y, %H:%M:%S"))
|
</py-script>
|
||||||
</py-script>
|
</section>
|
||||||
</section>
|
</py-tutor>
|
||||||
<section class="code">
|
</body>
|
||||||
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
|
|
||||||
<div id="code-section" class="code-section-hidden">
|
|
||||||
<p>index.html</p>
|
|
||||||
<pre class="prism-code language-html">
|
|
||||||
<code class="language-html">
|
|
||||||
<py-script>
|
|
||||||
from datetime import datetime
|
|
||||||
now = datetime.now()
|
|
||||||
display(now.strftime("%m/%d/%Y, %H:%M:%S"))
|
|
||||||
</py-script>
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</body>
|
|
||||||
<script>
|
|
||||||
const viewCodeButton = document.getElementById("view-code-button");
|
|
||||||
const codeSection = document.getElementById("code-section");
|
|
||||||
const handleClick = () => {
|
|
||||||
if (codeSection.classList.contains("code-section-hidden")) {
|
|
||||||
codeSection.classList.remove("code-section-hidden");
|
|
||||||
codeSection.classList.add("code-section-visible");
|
|
||||||
} else {
|
|
||||||
codeSection.classList.remove("code-section-visible");
|
|
||||||
codeSection.classList.add("code-section-hidden");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
viewCodeButton.addEventListener("click", handleClick)
|
|
||||||
viewCodeButton.addEventListener("keydown", (e) => {
|
|
||||||
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
|
|
||||||
handleClick();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,276 +1,315 @@
|
|||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||||
<title>PyScript demo</title>
|
<title>PyScript demo</title>
|
||||||
<link rel="icon" type="image/png" href="favicon.png" />
|
<link rel="icon" type="image/png" href="favicon.png" />
|
||||||
<link rel="stylesheet" href="./assets/css/main.css" />
|
<link rel="stylesheet" href="./assets/css/main.css" />
|
||||||
<link rel="stylesheet" href="./assets/css/index.css" />
|
<link rel="stylesheet" href="./assets/css/index.css" />
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="container">
|
<body class="container">
|
||||||
<h1 class="title-main">PyScript demos</h1>
|
<h1 class="title-main">PyScript demos</h1>
|
||||||
<section class="example">
|
<section class="example">
|
||||||
<h2>Basic examples</h2>
|
<h2>Basic examples</h2>
|
||||||
<div class="container-card">
|
<div class="container-card">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./hello_world.html" target="_blank">
|
<a href="./hello_world.html" target="_blank">
|
||||||
<h2>Hello world</h2>
|
<h2>Hello world</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
A static demo of the <code><py-script></code> tag
|
A static demo of the
|
||||||
</p>
|
<code><py-script></code> tag
|
||||||
</div>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./simple_clock.html" target="_blank">
|
<a href="./simple_clock.html" target="_blank">
|
||||||
<h2>Simple clock</h2>
|
<h2>Simple clock</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
A dynamic demo of the <code><py-script></code> tag
|
A dynamic demo of the
|
||||||
</p>
|
<code><py-script></code> tag
|
||||||
</div>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./repl.html" target="_blank">
|
<a href="./repl.html" target="_blank">
|
||||||
<h2>REPL</h2>
|
<h2>REPL</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>A Python REPL (Read Eval Print Loop)</p>
|
||||||
A Python REPL (Read Eval Print Loop)
|
</div>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./repl2.html" target="_blank">
|
<a href="./repl2.html" target="_blank">
|
||||||
<h2>REPL2</h2>
|
<h2>REPL2</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
A Python REPL (Read Eval Print Loop) with slightly better formatting
|
A Python REPL (Read Eval Print Loop) with slightly
|
||||||
</p>
|
better formatting
|
||||||
</div>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./todo.html" target="_blank">
|
<a href="./todo.html" target="_blank">
|
||||||
<h2>TODO App</h2>
|
<h2>TODO App</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>Simple TODO App</p>
|
||||||
Simple TODO App
|
</div>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./todo-pylist.html" target="_blank">
|
<a href="./todo-pylist.html" target="_blank">
|
||||||
<h2>PyScript Native TODO App</h2>
|
<h2>PyScript Native TODO App</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
Simple TODO App using <code><py-list></code>
|
Simple TODO App using <code><py-list></code>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="example">
|
<section class="example">
|
||||||
<h2>MIME Rendering</h2>
|
<h2>MIME Rendering</h2>
|
||||||
<div class="container-card">
|
<div class="container-card">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./matplotlib.html" target="_blank">
|
<a href="./matplotlib.html" target="_blank">
|
||||||
<h2>Matplotlib</h2>
|
<h2>Matplotlib</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
Demonstrates rendering a <a href="https://matplotlib.org/" target="_blank">Matplotlib</a> figure as output of the py-script tag
|
Demonstrates rendering a
|
||||||
</p>
|
<a href="https://matplotlib.org/" target="_blank"
|
||||||
</div>
|
>Matplotlib</a
|
||||||
</div>
|
>
|
||||||
|
figure as output of the py-script tag
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./altair.html" target="_blank">
|
<a href="./altair.html" target="_blank">
|
||||||
<h2>
|
<h2>Altair</h2>
|
||||||
Altair
|
</a>
|
||||||
</h2>
|
<p>
|
||||||
</a>
|
Demonstrates rendering a
|
||||||
<p>
|
<a
|
||||||
Demonstrates rendering a <a href="https://altair-viz.github.io/" target="_blank">Altair</a> plot as output of the py-script tag
|
href="https://altair-viz.github.io/"
|
||||||
</p>
|
target="_blank"
|
||||||
</div>
|
>Altair</a
|
||||||
</div>
|
>
|
||||||
|
plot as output of the py-script tag
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./folium.html" target="_blank">
|
<a href="./folium.html" target="_blank">
|
||||||
<h2>
|
<h2>Folium</h2>
|
||||||
Folium
|
</a>
|
||||||
</h2>
|
<p>
|
||||||
</a>
|
Demonstrates rendering a
|
||||||
<p>
|
<a
|
||||||
Demonstrates rendering a
|
href="https://python-visualization.github.io/folium/"
|
||||||
<a href="https://python-visualization.github.io/folium/" target="_blank">Folium</a>
|
target="_blank"
|
||||||
map as output of the py-script tag
|
>Folium</a
|
||||||
</p>
|
>
|
||||||
</div>
|
map as output of the py-script tag
|
||||||
</div>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="example">
|
<section class="example">
|
||||||
<h2>JS Interaction</h2>
|
<h2>JS Interaction</h2>
|
||||||
<div class="container-card">
|
<div class="container-card">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./d3.html" target="_blank">
|
<a href="./d3.html" target="_blank">
|
||||||
<h2>
|
<h2>Simple d3 visualization</h2>
|
||||||
Simple d3 visualization
|
</a>
|
||||||
</h2>
|
<p>
|
||||||
</a>
|
Minimal
|
||||||
<p>
|
<a href="https://d3js.org/" target="_blank">D3</a>
|
||||||
Minimal <a href="https://d3js.org/" target="_blank">D3</a>
|
demo demonstrating how to create a visualization
|
||||||
demo demonstrating how to create a visualization
|
</p>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./webgl/raycaster/index.html" target="_blank">
|
<a href="./webgl/raycaster/index.html" target="_blank">
|
||||||
<h2>
|
<h2>Webgl Icosahedron Example</h2>
|
||||||
Webgl Icosahedron Example
|
</a>
|
||||||
</h2>
|
<p>
|
||||||
</a>
|
Demo showing how a Simple
|
||||||
<p>
|
<a
|
||||||
Demo showing how a Simple <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API" target="_blank">WebGL</a>
|
href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API"
|
||||||
scene would work in PyScript</code> tag
|
target="_blank"
|
||||||
</p>
|
>WebGL</a
|
||||||
</div>
|
>
|
||||||
</div>
|
scene would work in the
|
||||||
</div>
|
<code><py-script></code> tag
|
||||||
</section>
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<section class="example">
|
<section class="example">
|
||||||
<h2>Visualizations & Dashboards</h2>
|
<h2>Visualizations & Dashboards</h2>
|
||||||
<div class="container-card">
|
<div class="container-card">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./bokeh.html" target="_blank">
|
<a href="./bokeh.html" target="_blank">
|
||||||
<h2>
|
<h2>Simple Static Bokeh Plot</h2>
|
||||||
Simple Static Bokeh Plot
|
</a>
|
||||||
</h2>
|
<p>
|
||||||
</a>
|
Minimal Bokeh demo demonstrating how to create a
|
||||||
<p>
|
simple
|
||||||
Minimal Bokeh demo demonstrating how to create a simple
|
<a href="https://bokeh.org/" target="_blank"
|
||||||
<a href="https://bokeh.org/" target="_blank">Bokeh</a>
|
>Bokeh</a
|
||||||
plot from code
|
>
|
||||||
</p>
|
plot from code
|
||||||
</div>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./bokeh_interactive.html" target="_blank">
|
<a href="./bokeh_interactive.html" target="_blank">
|
||||||
<h2 class="text-2xl font-bold text-blue-600">
|
<h2 class="text-2xl font-bold text-blue-600">
|
||||||
Bokeh Interactive
|
Bokeh Interactive
|
||||||
</h2>
|
</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
Interactive demo using a
|
Interactive demo using a
|
||||||
<a href="https://bokeh.org/" target="_blank">Bokeh</a>
|
<a href="https://bokeh.org/" target="_blank"
|
||||||
slider widget to dynamically change a value in the page
|
>Bokeh</a
|
||||||
WARNING: This examples takes a little longer to load. So be patient :)
|
>
|
||||||
</p>
|
slider widget to dynamically change a value in the
|
||||||
</div>
|
page WARNING: This examples takes a little longer to
|
||||||
</div>
|
load. So be patient :)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./panel_kmeans.html" target="_blank">
|
<a href="./panel_kmeans.html" target="_blank">
|
||||||
<h2 class="text-2xl font-bold text-blue-600">
|
<h2 class="text-2xl font-bold text-blue-600">
|
||||||
KMeans Demo in Panel
|
KMeans Demo in Panel
|
||||||
</h2>
|
</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
Interactive KMeans Chart using
|
Interactive KMeans Chart using
|
||||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a>
|
<a href="https://panel.holoviz.org/" target="_blank"
|
||||||
WARNING: This examples takes a little longer to load. So be patient :)
|
>Panel</a
|
||||||
</p>
|
>
|
||||||
</div>
|
WARNING: This examples takes a little longer to
|
||||||
</div>
|
load. So be patient :)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./panel_stream.html" target="_blank">
|
<a href="./panel_stream.html" target="_blank">
|
||||||
<h2 class="text-2xl font-bold text-blue-600">
|
<h2 class="text-2xl font-bold text-blue-600">
|
||||||
Streaming Demo in Panel
|
Streaming Demo in Panel
|
||||||
</h2>
|
</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
Interactive Streaming Table and Bokeh plot using
|
Interactive Streaming Table and Bokeh plot using
|
||||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a>
|
<a href="https://panel.holoviz.org/" target="_blank"
|
||||||
WARNING: This examples takes a little longer to load. So be patient :)
|
>Panel</a
|
||||||
</p>
|
>
|
||||||
</div>
|
WARNING: This examples takes a little longer to
|
||||||
</div>
|
load. So be patient :)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./panel.html" target="_blank">
|
<a href="./panel.html" target="_blank">
|
||||||
<h2 class="text-3xl font-bold text-blue-600">
|
<h2 class="text-3xl font-bold text-blue-600">
|
||||||
Simple Panel Demo
|
Simple Panel Demo
|
||||||
</h2>
|
</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
Simple demo showing
|
Simple demo showing
|
||||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a>
|
<a href="https://panel.holoviz.org/" target="_blank"
|
||||||
widgets interacting with parts of the page
|
>Panel</a
|
||||||
WARNING: This examples takes a little longer to load. So be patient :)
|
>
|
||||||
</p>
|
widgets interacting with parts of the page WARNING:
|
||||||
</div>
|
This examples takes a little longer to load. So be
|
||||||
</div>
|
patient :)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./panel_deckgl.html" target="_blank">
|
<a href="./panel_deckgl.html" target="_blank">
|
||||||
<h2 class="text-2xl font-bold text-blue-600">
|
<h2 class="text-2xl font-bold text-blue-600">
|
||||||
NYC Taxi Data Panel DeckGL Demo
|
NYC Taxi Data Panel DeckGL Demo
|
||||||
</h2>
|
</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
Interactive application exploring the NYC Taxi dataset using
|
Interactive application exploring the NYC Taxi
|
||||||
<a href="https://panel.holoviz.org/" target="_blank">Panel</a> and <a href="https://deck.gl/" target="_blank">DeckGL</a>
|
dataset using
|
||||||
WARNING: This examples takes a little longer to load. So be patient :)
|
<a href="https://panel.holoviz.org/" target="_blank"
|
||||||
</p>
|
>Panel</a
|
||||||
</div>
|
>
|
||||||
</div>
|
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 class="card">
|
<div class="card">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<a href="./numpy_canvas_fractals.html" target="_blank">
|
<a href="./numpy_canvas_fractals.html" target="_blank">
|
||||||
<h2 class="text-2xl font-bold text-blue-600">
|
<h2 class="text-2xl font-bold text-blue-600">
|
||||||
Fractals with NumPy and canvas
|
Fractals with NumPy and canvas
|
||||||
</h2>
|
</h2>
|
||||||
</a>
|
</a>
|
||||||
<p>
|
<p>
|
||||||
Visualization of Mandelbrot and Julia sets with
|
Visualization of Mandelbrot and Julia sets with
|
||||||
<a href="https://numpy.org/" target="_blank">Numpy</a> and
|
<a href="https://numpy.org/" target="_blank"
|
||||||
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API" target="_blank">
|
>Numpy</a
|
||||||
HTML5 canvas
|
>
|
||||||
</a>
|
and
|
||||||
</p>
|
<a
|
||||||
</div>
|
href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API"
|
||||||
</div>
|
target="_blank"
|
||||||
</div>
|
>
|
||||||
</section>
|
HTML5 canvas
|
||||||
</body>
|
</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,32 +1,35 @@
|
|||||||
html, body, ul, li {
|
html,
|
||||||
margin: 0;
|
body,
|
||||||
border: 0;
|
ul,
|
||||||
padding: 0;
|
li {
|
||||||
|
margin: 0;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
display: block;
|
display: block;
|
||||||
width: 762;
|
width: 762;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
background-color: blue;
|
background-color: blue;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +1,43 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
window.Mario = {};
|
|
||||||
|
|
||||||
var Bcoin = Mario.Bcoin = function(pos) {
|
var Bcoin = (Mario.Bcoin = function (pos) {
|
||||||
Mario.Entity.call(this, {
|
Mario.Entity.call(this, {
|
||||||
pos: pos,
|
pos: pos,
|
||||||
sprite: level.bcoinSprite(),
|
sprite: level.bcoinSprite(),
|
||||||
hitbox: [0,0,16,16]
|
hitbox: [0, 0, 16, 16],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Mario.Util.inherits(Bcoin, Mario.Entity);
|
Mario.Util.inherits(Bcoin, Mario.Entity);
|
||||||
|
|
||||||
//I'm not sure whether it makes sense to use an array for vel and acc here
|
//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
|
//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.
|
//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.currentTime = 0.05;
|
||||||
sounds.coin.play();
|
sounds.coin.play();
|
||||||
this.idx = level.items.length;
|
this.idx = level.items.length;
|
||||||
level.items.push(this);
|
level.items.push(this);
|
||||||
this.active = true;
|
this.active = true;
|
||||||
this.vel = -12;
|
this.vel = -12;
|
||||||
this.targetpos = this.pos[1] - 32;
|
this.targetpos = this.pos[1] - 32;
|
||||||
}
|
};
|
||||||
|
|
||||||
Bcoin.prototype.update = function(dt) {
|
Bcoin.prototype.update = function (dt) {
|
||||||
if (!this.active) return;
|
if (!this.active) return;
|
||||||
|
|
||||||
if (this.vel > 0 && this.pos[1] >= this.targetpos) {
|
if (this.vel > 0 && this.pos[1] >= this.targetpos) {
|
||||||
player.coins += 1;
|
player.coins += 1;
|
||||||
//spawn a score thingy.
|
//spawn a score thingy.
|
||||||
delete level.items[this.idx];
|
delete level.items[this.idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
this.acc = 0.75;
|
this.acc = 0.75;
|
||||||
this.vel += this.acc;
|
this.vel += this.acc;
|
||||||
this.pos[1] += this.vel;
|
this.pos[1] += this.vel;
|
||||||
this.sprite.update(dt);
|
this.sprite.update(dt);
|
||||||
}
|
};
|
||||||
|
|
||||||
Bcoin.prototype.checkCollisions = function() {;}
|
|
||||||
|
|
||||||
|
Bcoin.prototype.checkCollisions = function () {};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,81 +1,84 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
window.Mario = {};
|
|
||||||
|
|
||||||
//TODO: clean up the logic for sprite switching.
|
//TODO: clean up the logic for sprite switching.
|
||||||
//TODO: There's a weird bug with the collision logic. Look into it.
|
//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.item = options.item;
|
||||||
this.usedSprite = options.usedSprite;
|
this.usedSprite = options.usedSprite;
|
||||||
this.bounceSprite = options.bounceSprite;
|
this.bounceSprite = options.bounceSprite;
|
||||||
this.breakable = options.breakable;
|
this.breakable = options.breakable;
|
||||||
|
|
||||||
Mario.Entity.call(this, {
|
Mario.Entity.call(this, {
|
||||||
pos: options.pos,
|
pos: options.pos,
|
||||||
sprite: options.sprite,
|
sprite: options.sprite,
|
||||||
hitbox: [0,0,16,16]
|
hitbox: [0, 0, 16, 16],
|
||||||
|
});
|
||||||
|
|
||||||
|
this.standing = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.standing = true;
|
Mario.Util.inherits(Block, Mario.Floor);
|
||||||
}
|
|
||||||
|
|
||||||
Mario.Util.inherits(Block, Mario.Floor);
|
Block.prototype.break = function () {
|
||||||
|
sounds.breakBlock.play();
|
||||||
Block.prototype.break = function() {
|
new Mario.Rubble().spawn(this.pos);
|
||||||
sounds.breakBlock.play();
|
var x = this.pos[0] / 16,
|
||||||
(new Mario.Rubble()).spawn(this.pos);
|
y = this.pos[1] / 16;
|
||||||
var x = this.pos[0] / 16, y = this.pos[1] / 16;
|
|
||||||
delete level.blocks[y][x];
|
|
||||||
}
|
|
||||||
|
|
||||||
Block.prototype.bonk = function(power) {
|
|
||||||
sounds.bump.play();
|
|
||||||
if (power > 0 && this.breakable) {
|
|
||||||
this.break();
|
|
||||||
} else if (this.standing){
|
|
||||||
this.standing = false;
|
|
||||||
if (this.item) {
|
|
||||||
this.item.spawn();
|
|
||||||
this.item = null;
|
|
||||||
}
|
|
||||||
this.opos = [];
|
|
||||||
this.opos[0] = this.pos[0];
|
|
||||||
this.opos[1] = this.pos[1];
|
|
||||||
if (this.bounceSprite) {
|
|
||||||
this.osprite = this.sprite;
|
|
||||||
this.sprite = this.bounceSprite;
|
|
||||||
} else {
|
|
||||||
this.sprite = this.usedSprite;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.vel[1] = -2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Block.prototype.update = function(dt, gameTime) {
|
|
||||||
if (!this.standing) {
|
|
||||||
if (this.pos[1] < this.opos[1] - 8) {
|
|
||||||
this.vel[1] = 2;
|
|
||||||
}
|
|
||||||
if (this.pos[1] > this.opos[1]) {
|
|
||||||
this.vel[1] = 0;
|
|
||||||
this.pos = this.opos;
|
|
||||||
if (this.osprite) {
|
|
||||||
this.sprite = this.osprite;
|
|
||||||
}
|
|
||||||
this.standing = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (this.sprite === this.usedSprite) {
|
|
||||||
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];
|
delete level.blocks[y][x];
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
this.pos[1] += this.vel[1];
|
Block.prototype.bonk = function (power) {
|
||||||
this.sprite.update(dt, gameTime);
|
sounds.bump.play();
|
||||||
}
|
if (power > 0 && this.breakable) {
|
||||||
|
this.break();
|
||||||
|
} else if (this.standing) {
|
||||||
|
this.standing = false;
|
||||||
|
if (this.item) {
|
||||||
|
this.item.spawn();
|
||||||
|
this.item = null;
|
||||||
|
}
|
||||||
|
this.opos = [];
|
||||||
|
this.opos[0] = this.pos[0];
|
||||||
|
this.opos[1] = this.pos[1];
|
||||||
|
if (this.bounceSprite) {
|
||||||
|
this.osprite = this.sprite;
|
||||||
|
this.sprite = this.bounceSprite;
|
||||||
|
} else {
|
||||||
|
this.sprite = this.usedSprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vel[1] = -2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Block.prototype.update = function (dt, gameTime) {
|
||||||
|
if (!this.standing) {
|
||||||
|
if (this.pos[1] < this.opos[1] - 8) {
|
||||||
|
this.vel[1] = 2;
|
||||||
|
}
|
||||||
|
if (this.pos[1] > this.opos[1]) {
|
||||||
|
this.vel[1] = 0;
|
||||||
|
this.pos = this.opos;
|
||||||
|
if (this.osprite) {
|
||||||
|
this.sprite = this.osprite;
|
||||||
|
}
|
||||||
|
this.standing = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.sprite === this.usedSprite) {
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.pos[1] += this.vel[1];
|
||||||
|
this.sprite.update(dt, gameTime);
|
||||||
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,47 +1,62 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
window.Mario = {};
|
|
||||||
|
|
||||||
var Coin = Mario.Coin = function(pos, sprite) {
|
var Coin = (Mario.Coin = function (pos, sprite) {
|
||||||
Mario.Entity.call(this, {
|
Mario.Entity.call(this, {
|
||||||
pos: pos,
|
pos: pos,
|
||||||
sprite: sprite,
|
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);
|
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.
|
//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 hpos1 = [
|
||||||
var hpos2 = [player.pos[0] + player.hitbox[0], player.pos[1] + player.hitbox[1]];
|
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],
|
||||||
|
];
|
||||||
|
|
||||||
//if the hitboxes actually overlap
|
//if the hitboxes actually overlap
|
||||||
if (!(hpos1[0] > hpos2[0]+player.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
if (
|
||||||
if (!(hpos1[1] > hpos2[1]+player.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
!(
|
||||||
this.collect();
|
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);
|
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||||
}
|
};
|
||||||
|
|
||||||
//money is not affected by gravity, you see.
|
//money is not affected by gravity, you see.
|
||||||
Coin.prototype.update = function(dt) {
|
Coin.prototype.update = function (dt) {
|
||||||
this.sprite.update(dt);
|
this.sprite.update(dt);
|
||||||
}
|
};
|
||||||
Coin.prototype.checkCollisions = function() {
|
Coin.prototype.checkCollisions = function () {
|
||||||
this.isPlayerCollided();
|
this.isPlayerCollided();
|
||||||
}
|
};
|
||||||
|
|
||||||
Coin.prototype.collect = function() {
|
Coin.prototype.collect = function () {
|
||||||
sounds.coin.currentTime = 0.05;
|
sounds.coin.currentTime = 0.05;
|
||||||
sounds.coin.play();
|
sounds.coin.play();
|
||||||
player.coins += 1;
|
player.coins += 1;
|
||||||
delete level.items[this.idx]
|
delete level.items[this.idx];
|
||||||
}
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,34 +1,34 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
window.Mario = {};
|
|
||||||
|
|
||||||
var Entity = Mario.Entity = function(options) {
|
var Entity = (Mario.Entity = function (options) {
|
||||||
this.vel = [0,0];
|
this.vel = [0, 0];
|
||||||
this.acc = [0,0];
|
this.acc = [0, 0];
|
||||||
this.standing = true;
|
this.standing = true;
|
||||||
this.pos = options.pos;
|
this.pos = options.pos;
|
||||||
this.sprite = options.sprite;
|
this.sprite = options.sprite;
|
||||||
this.hitbox = options.hitbox;
|
this.hitbox = options.hitbox;
|
||||||
this.left = false;
|
this.left = false;
|
||||||
}
|
});
|
||||||
|
|
||||||
Entity.prototype.render = function(ctx, vX, vY) {
|
Entity.prototype.render = function (ctx, vX, vY) {
|
||||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY)
|
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||||
}
|
};
|
||||||
|
|
||||||
Entity.prototype.collideWall = function(wall) {
|
Entity.prototype.collideWall = function (wall) {
|
||||||
//the wall will always be a 16x16 block with hitbox = [0,0,16,16].
|
//the wall will always be a 16x16 block with hitbox = [0,0,16,16].
|
||||||
if (this.pos[0] > wall.pos[0]) {
|
if (this.pos[0] > wall.pos[0]) {
|
||||||
//from the right
|
//from the right
|
||||||
this.pos[0] = wall.pos[0] + wall.hitbox[2] - this.hitbox[0];
|
this.pos[0] = wall.pos[0] + wall.hitbox[2] - this.hitbox[0];
|
||||||
this.vel[0] = Math.max(0, this.vel[0]);
|
this.vel[0] = Math.max(0, this.vel[0]);
|
||||||
this.acc[0] = Math.max(0, this.acc[0]);
|
this.acc[0] = Math.max(0, this.acc[0]);
|
||||||
} else {
|
} else {
|
||||||
this.pos[0] = wall.pos[0] + wall.hitbox[0] - this.hitbox[2] - this.hitbox[0];
|
this.pos[0] =
|
||||||
this.vel[0] = Math.min(0, this.vel[0]);
|
wall.pos[0] + wall.hitbox[0] - this.hitbox[2] - this.hitbox[0];
|
||||||
this.acc[0] = Math.min(0, this.acc[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,126 +1,145 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
window.Mario = {};
|
|
||||||
|
|
||||||
var Fireball = Mario.Fireball = function(pos) {
|
var Fireball = (Mario.Fireball = function (pos) {
|
||||||
this.hit = 0;
|
this.hit = 0;
|
||||||
this.standing = false;
|
this.standing = false;
|
||||||
|
|
||||||
Mario.Entity.call(this, {
|
Mario.Entity.call(this, {
|
||||||
pos: pos,
|
pos: pos,
|
||||||
sprite: new Mario.Sprite('sprites/items.png', [96, 144], [8,8], 5, [0,1,2,3]),
|
sprite: new Mario.Sprite(
|
||||||
hitbox: [0,0,8,8]
|
"sprites/items.png",
|
||||||
|
[96, 144],
|
||||||
|
[8, 8],
|
||||||
|
5,
|
||||||
|
[0, 1, 2, 3],
|
||||||
|
),
|
||||||
|
hitbox: [0, 0, 8, 8],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Mario.Util.inherits(Fireball, Mario.Entity);
|
Mario.Util.inherits(Fireball, Mario.Entity);
|
||||||
|
|
||||||
Fireball.prototype.spawn = function(left) {
|
Fireball.prototype.spawn = function (left) {
|
||||||
sounds.fireball.currentTime = 0;
|
sounds.fireball.currentTime = 0;
|
||||||
sounds.fireball.play();
|
sounds.fireball.play();
|
||||||
if (fireballs[0]) {
|
if (fireballs[0]) {
|
||||||
this.idx = 1;
|
this.idx = 1;
|
||||||
fireballs[1] = this;
|
fireballs[1] = this;
|
||||||
} else {
|
} else {
|
||||||
this.idx = 0;
|
this.idx = 0;
|
||||||
fireballs[0] = this;
|
fireballs[0] = this;
|
||||||
}
|
|
||||||
this.vel[0] = (left ? -5 : 5);
|
|
||||||
this.standing = false;
|
|
||||||
this.vel[1] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Fireball.prototype.render = function(ctx, vX, vY) {
|
|
||||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
|
||||||
}
|
|
||||||
|
|
||||||
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.speed = 8;
|
|
||||||
this.hit += 1;
|
|
||||||
return;
|
|
||||||
} else if (this.hit == 5) {
|
|
||||||
delete fireballs[this.idx];
|
|
||||||
player.fireballs -= 1;
|
|
||||||
return;
|
|
||||||
} else if (this.hit) {
|
|
||||||
this.hit += 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//In retrospect, the way collision is being handled is RIDICULOUS
|
|
||||||
//but I don't have to use some horrible kludge for this.
|
|
||||||
if (this.standing) {
|
|
||||||
this.standing = false;
|
|
||||||
this.vel[1] = -4;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.acc[1] = 0.5;
|
|
||||||
|
|
||||||
this.vel[1] += this.acc[1];
|
|
||||||
this.pos[0] += this.vel[0];
|
|
||||||
this.pos[1] += this.vel[1];
|
|
||||||
if (this.pos[0] < vX || this.pos[0] > vX + 256) {
|
|
||||||
this.hit = 1;
|
|
||||||
}
|
|
||||||
this.sprite.update(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
Fireball.prototype.collideWall = function() {
|
|
||||||
if (!this.hit) this.hit = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
var baseX = Math.floor(this.pos[0] / 16);
|
|
||||||
var baseY = Math.floor(this.pos[1] / 16);
|
|
||||||
|
|
||||||
if (baseY + h > 15) {
|
|
||||||
delete fireballs[this.idx];
|
|
||||||
player.fireballs -= 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < h; i++) {
|
|
||||||
for (var j = 0; j < w; j++) {
|
|
||||||
if (level.statics[baseY + i][baseX + j]) {
|
|
||||||
level.statics[baseY + i][baseX + j].isCollideWith(this);
|
|
||||||
}
|
}
|
||||||
if (level.blocks[baseY + i][baseX + j]) {
|
this.vel[0] = left ? -5 : 5;
|
||||||
level.blocks[baseY + i][baseX + j].isCollideWith(this);
|
this.standing = false;
|
||||||
|
this.vel[1] = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Fireball.prototype.render = function (ctx, vX, vY) {
|
||||||
|
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||||
|
};
|
||||||
|
|
||||||
|
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.speed = 8;
|
||||||
|
this.hit += 1;
|
||||||
|
return;
|
||||||
|
} else if (this.hit == 5) {
|
||||||
|
delete fireballs[this.idx];
|
||||||
|
player.fireballs -= 1;
|
||||||
|
return;
|
||||||
|
} else if (this.hit) {
|
||||||
|
this.hit += 1;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var that = this;
|
//In retrospect, the way collision is being handled is RIDICULOUS
|
||||||
level.enemies.forEach(function(enemy){
|
//but I don't have to use some horrible kludge for this.
|
||||||
if (enemy.flipping || enemy.pos[0] - vX > 336){ //stop checking once we get to far away dudes.
|
if (this.standing) {
|
||||||
return;
|
this.standing = false;
|
||||||
} else {
|
this.vel[1] = -4;
|
||||||
that.isCollideWith(enemy);
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Fireball.prototype.isCollideWith = function(ent) {
|
this.acc[1] = 0.5;
|
||||||
//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
|
this.vel[1] += this.acc[1];
|
||||||
if (!(hpos1[0] > hpos2[0]+ent.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
this.pos[0] += this.vel[0];
|
||||||
if (!(hpos1[1] > hpos2[1]+ent.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
this.pos[1] += this.vel[1];
|
||||||
this.hit = 1;
|
if (this.pos[0] < vX || this.pos[0] > vX + 256) {
|
||||||
ent.bump();
|
this.hit = 1;
|
||||||
}
|
}
|
||||||
}
|
this.sprite.update(dt);
|
||||||
};
|
};
|
||||||
|
|
||||||
Fireball.prototype.bump = function() {;}
|
Fireball.prototype.collideWall = function () {
|
||||||
|
if (!this.hit) this.hit = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
var baseX = Math.floor(this.pos[0] / 16);
|
||||||
|
var baseY = Math.floor(this.pos[1] / 16);
|
||||||
|
|
||||||
|
if (baseY + h > 15) {
|
||||||
|
delete fireballs[this.idx];
|
||||||
|
player.fireballs -= 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < h; i++) {
|
||||||
|
for (var j = 0; j < w; j++) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
that.isCollideWith(enemy);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
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]
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
this.hit = 1;
|
||||||
|
ent.bump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Fireball.prototype.bump = function () {};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,74 +1,90 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
window.Mario = {};
|
|
||||||
|
|
||||||
var Fireflower = Mario.Fireflower = function(pos) {
|
var Fireflower = (Mario.Fireflower = function (pos) {
|
||||||
this.spawning = false;
|
this.spawning = false;
|
||||||
this.waiting = 0;
|
this.waiting = 0;
|
||||||
|
|
||||||
Mario.Entity.call(this, {
|
Mario.Entity.call(this, {
|
||||||
pos: pos,
|
pos: pos,
|
||||||
sprite: level.fireFlowerSprite,
|
sprite: level.fireFlowerSprite,
|
||||||
hitbox: [0,0,16,16]
|
hitbox: [0, 0, 16, 16],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Mario.Util.inherits(Fireflower, Mario.Entity);
|
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;
|
if (this.spawning > 1) return;
|
||||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||||
}
|
};
|
||||||
|
|
||||||
Fireflower.prototype.spawn = function() {
|
Fireflower.prototype.spawn = function () {
|
||||||
sounds.itemAppear.play();
|
sounds.itemAppear.play();
|
||||||
this.idx = level.items.length;
|
this.idx = level.items.length;
|
||||||
level.items.push(this);
|
level.items.push(this);
|
||||||
this.spawning = 12;
|
this.spawning = 12;
|
||||||
this.targetpos = [];
|
this.targetpos = [];
|
||||||
this.targetpos[0] = this.pos[0];
|
this.targetpos[0] = this.pos[0];
|
||||||
this.targetpos[1] = this.pos[1] - 16;
|
this.targetpos[1] = this.pos[1] - 16;
|
||||||
}
|
};
|
||||||
|
|
||||||
Fireflower.prototype.update = function(dt) {
|
Fireflower.prototype.update = function (dt) {
|
||||||
if (this.spawning > 1) {
|
if (this.spawning > 1) {
|
||||||
this.spawning -= 1;
|
this.spawning -= 1;
|
||||||
if (this.spawning == 1) this.vel[1] = -.5;
|
if (this.spawning == 1) this.vel[1] = -0.5;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (this.spawning) {
|
if (this.spawning) {
|
||||||
if (this.pos[1] <= this.targetpos[1]) {
|
if (this.pos[1] <= this.targetpos[1]) {
|
||||||
this.pos[1] = this.targetpos[1];
|
this.pos[1] = this.targetpos[1];
|
||||||
this.vel[1] = 0;
|
this.vel[1] = 0;
|
||||||
this.spawning = 0;
|
this.spawning = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.vel[1] += this.acc[1];
|
this.vel[1] += this.acc[1];
|
||||||
this.pos[0] += this.vel[0];
|
this.pos[0] += this.vel[0];
|
||||||
this.pos[1] += this.vel[1];
|
this.pos[1] += this.vel[1];
|
||||||
this.sprite.update(dt);
|
this.sprite.update(dt);
|
||||||
}
|
};
|
||||||
|
|
||||||
Fireflower.prototype.checkCollisions = function() {
|
Fireflower.prototype.checkCollisions = function () {
|
||||||
if (this.spawning) {return;}
|
if (this.spawning) {
|
||||||
this.isPlayerCollided();
|
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.
|
//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 hpos1 = [
|
||||||
var hpos2 = [player.pos[0] + player.hitbox[0], player.pos[1] + player.hitbox[1]];
|
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],
|
||||||
|
];
|
||||||
|
|
||||||
//if the hitboxes actually overlap
|
//if the hitboxes actually overlap
|
||||||
if (!(hpos1[0] > hpos2[0]+player.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
if (
|
||||||
if (!(hpos1[1] > hpos2[1]+player.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
!(
|
||||||
player.powerUp(this.idx);
|
hpos1[0] > hpos2[0] + player.hitbox[2] ||
|
||||||
}
|
hpos1[0] + this.hitbox[2] < hpos2[0]
|
||||||
}
|
)
|
||||||
}
|
) {
|
||||||
|
if (
|
||||||
//This should never be called, but just in case.
|
!(
|
||||||
Fireflower.prototype.bump = function() {;}
|
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 () {};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,47 +1,51 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
window.Mario = {};
|
|
||||||
|
|
||||||
Flag = Mario.Flag = function(pos) {
|
Flag = Mario.Flag = function (pos) {
|
||||||
//afaik flags always have the same height and Y-position
|
//afaik flags always have the same height and Y-position
|
||||||
this.pos = [pos, 49];
|
this.pos = [pos, 49];
|
||||||
this.hitbox = [0,0,0,0];
|
this.hitbox = [0, 0, 0, 0];
|
||||||
this.vel = [0,0];
|
this.vel = [0, 0];
|
||||||
this.acc = [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) {
|
if (!this.done && this.pos[1] >= 170) {
|
||||||
this.vel = [0,0];
|
this.vel = [0, 0];
|
||||||
this.pos[1] = 170;
|
this.pos[1] = 170;
|
||||||
player.exit();
|
player.exit();
|
||||||
this.done = true;
|
this.done = true;
|
||||||
}
|
}
|
||||||
this.pos[1] += this.vel[1];
|
this.pos[1] += this.vel[1];
|
||||||
}
|
};
|
||||||
|
|
||||||
Flag.prototype.checkCollisions = function() {
|
Flag.prototype.checkCollisions = function () {
|
||||||
this.isPlayerCollided();
|
this.isPlayerCollided();
|
||||||
}
|
};
|
||||||
|
|
||||||
Flag.prototype.isPlayerCollided = function() {
|
Flag.prototype.isPlayerCollided = function () {
|
||||||
if (this.hit) return;
|
if (this.hit) return;
|
||||||
if (player.pos[0] + 8 >= this.pos[0]) {
|
if (player.pos[0] + 8 >= this.pos[0]) {
|
||||||
music.overworld.pause();
|
music.overworld.pause();
|
||||||
sounds.flagpole.play();
|
sounds.flagpole.play();
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
music.clear.play();
|
music.clear.play();
|
||||||
}, 2000);
|
}, 2000);
|
||||||
this.hit = true;
|
this.hit = true;
|
||||||
player.flag();
|
player.flag();
|
||||||
this.vel = [0, 2];
|
this.vel = [0, 2];
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
Flag.prototype.render = function() {
|
Flag.prototype.render = function () {
|
||||||
level.flagpoleSprites[2].render(ctx, this.pos[0]-8, this.pos[1], vX, vY);
|
level.flagpoleSprites[2].render(
|
||||||
}
|
ctx,
|
||||||
|
this.pos[0] - 8,
|
||||||
|
this.pos[1],
|
||||||
|
vX,
|
||||||
|
vY,
|
||||||
|
);
|
||||||
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,56 +1,83 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
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, {
|
Mario.Util.inherits(Floor, Mario.Entity);
|
||||||
pos: pos,
|
|
||||||
sprite: sprite,
|
|
||||||
hitbox: [0,0,16,16]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
//if the hitboxes actually overlap
|
||||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
if (
|
||||||
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])];
|
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
|
Floor.prototype.bonk = function () {};
|
||||||
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() {;}
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,20 +1,22 @@
|
|||||||
var requestAnimFrame = (function(){
|
var requestAnimFrame = (function () {
|
||||||
return window.requestAnimationFrame ||
|
return (
|
||||||
window.webkitRequestAnimationFrame ||
|
window.requestAnimationFrame ||
|
||||||
window.mozRequestAnimationFrame ||
|
window.webkitRequestAnimationFrame ||
|
||||||
window.oRequestAnimationFrame ||
|
window.mozRequestAnimationFrame ||
|
||||||
window.msRequestAnimationFrame ||
|
window.oRequestAnimationFrame ||
|
||||||
function(callback){
|
window.msRequestAnimationFrame ||
|
||||||
window.setTimeout(callback, 1000 / 60);
|
function (callback) {
|
||||||
};
|
window.setTimeout(callback, 1000 / 60);
|
||||||
|
}
|
||||||
|
);
|
||||||
})();
|
})();
|
||||||
|
|
||||||
//create the canvas
|
//create the canvas
|
||||||
var canvas = document.createElement("canvas");
|
var canvas = document.createElement("canvas");
|
||||||
var ctx = canvas.getContext('2d');
|
var ctx = canvas.getContext("2d");
|
||||||
var updateables = [];
|
var updateables = [];
|
||||||
var fireballs = [];
|
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
|
//we might have to get the size and calculate the scaling
|
||||||
//but this method should let us make it however big.
|
//but this method should let us make it however big.
|
||||||
@@ -23,7 +25,7 @@ var player = new Mario.Player([0,0]);
|
|||||||
//TODO: fiddling with scaled sprites looks BETTER, but not perfect. Hmm.
|
//TODO: fiddling with scaled sprites looks BETTER, but not perfect. Hmm.
|
||||||
canvas.width = 762;
|
canvas.width = 762;
|
||||||
canvas.height = 720;
|
canvas.height = 720;
|
||||||
ctx.scale(3,3);
|
ctx.scale(3, 3);
|
||||||
document.body.appendChild(canvas);
|
document.body.appendChild(canvas);
|
||||||
|
|
||||||
//viewport
|
//viewport
|
||||||
@@ -34,12 +36,12 @@ var vX = 0,
|
|||||||
|
|
||||||
//load our images
|
//load our images
|
||||||
resources.load([
|
resources.load([
|
||||||
'sprites/player.png',
|
"sprites/player.png",
|
||||||
'sprites/enemy.png',
|
"sprites/enemy.png",
|
||||||
'sprites/tiles.png',
|
"sprites/tiles.png",
|
||||||
'sprites/playerl.png',
|
"sprites/playerl.png",
|
||||||
'sprites/items.png',
|
"sprites/items.png",
|
||||||
'sprites/enemyr.png',
|
"sprites/enemyr.png",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
resources.onReady(init);
|
resources.onReady(init);
|
||||||
@@ -50,192 +52,202 @@ var music;
|
|||||||
//initialize
|
//initialize
|
||||||
var lastTime;
|
var lastTime;
|
||||||
function init() {
|
function init() {
|
||||||
music = {
|
music = {
|
||||||
overworld: new Audio('sounds/aboveground_bgm.ogg'),
|
overworld: new Audio("sounds/aboveground_bgm.ogg"),
|
||||||
underground: new Audio('sounds/underground_bgm.ogg'),
|
underground: new Audio("sounds/underground_bgm.ogg"),
|
||||||
clear: new Audio('sounds/stage_clear.wav'),
|
clear: new Audio("sounds/stage_clear.wav"),
|
||||||
death: new Audio('sounds/mariodie.wav')
|
death: new Audio("sounds/mariodie.wav"),
|
||||||
};
|
};
|
||||||
sounds = {
|
sounds = {
|
||||||
smallJump: new Audio('sounds/jump-small.wav'),
|
smallJump: new Audio("sounds/jump-small.wav"),
|
||||||
bigJump: new Audio('sounds/jump-super.wav'),
|
bigJump: new Audio("sounds/jump-super.wav"),
|
||||||
breakBlock: new Audio('sounds/breakblock.wav'),
|
breakBlock: new Audio("sounds/breakblock.wav"),
|
||||||
bump: new Audio('sounds/bump.wav'),
|
bump: new Audio("sounds/bump.wav"),
|
||||||
coin: new Audio('sounds/coin.wav'),
|
coin: new Audio("sounds/coin.wav"),
|
||||||
fireball: new Audio('sounds/fireball.wav'),
|
fireball: new Audio("sounds/fireball.wav"),
|
||||||
flagpole: new Audio('sounds/flagpole.wav'),
|
flagpole: new Audio("sounds/flagpole.wav"),
|
||||||
kick: new Audio('sounds/kick.wav'),
|
kick: new Audio("sounds/kick.wav"),
|
||||||
pipe: new Audio('sounds/pipe.wav'),
|
pipe: new Audio("sounds/pipe.wav"),
|
||||||
itemAppear: new Audio('sounds/itemAppear.wav'),
|
itemAppear: new Audio("sounds/itemAppear.wav"),
|
||||||
powerup: new Audio('sounds/powerup.wav'),
|
powerup: new Audio("sounds/powerup.wav"),
|
||||||
stomp: new Audio('sounds/stomp.wav')
|
stomp: new Audio("sounds/stomp.wav"),
|
||||||
};
|
};
|
||||||
Mario.oneone();
|
Mario.oneone();
|
||||||
lastTime = Date.now();
|
lastTime = Date.now();
|
||||||
main();
|
main();
|
||||||
}
|
}
|
||||||
|
|
||||||
var gameTime = 0;
|
var gameTime = 0;
|
||||||
|
|
||||||
//set up the game loop
|
//set up the game loop
|
||||||
function main() {
|
function main() {
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
var dt = (now - lastTime) / 1000.0;
|
var dt = (now - lastTime) / 1000.0;
|
||||||
|
|
||||||
update(dt);
|
update(dt);
|
||||||
render();
|
render();
|
||||||
|
|
||||||
lastTime = now;
|
lastTime = now;
|
||||||
requestAnimFrame(main);
|
requestAnimFrame(main);
|
||||||
}
|
}
|
||||||
|
|
||||||
function update(dt) {
|
function update(dt) {
|
||||||
gameTime += dt;
|
gameTime += dt;
|
||||||
|
|
||||||
handleInput(dt);
|
handleInput(dt);
|
||||||
updateEntities(dt, gameTime);
|
updateEntities(dt, gameTime);
|
||||||
|
|
||||||
checkCollisions();
|
checkCollisions();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleInput(dt) {
|
function handleInput(dt) {
|
||||||
if (player.piping || player.dying || player.noInput) return; //don't accept input
|
if (player.piping || player.dying || player.noInput) return; //don't accept input
|
||||||
|
|
||||||
if (input.isDown('RUN')){
|
if (input.isDown("RUN")) {
|
||||||
player.run();
|
player.run();
|
||||||
} else {
|
} else {
|
||||||
player.noRun();
|
player.noRun();
|
||||||
}
|
}
|
||||||
if (input.isDown('JUMP')) {
|
if (input.isDown("JUMP")) {
|
||||||
player.jump();
|
player.jump();
|
||||||
} else {
|
} else {
|
||||||
//we need this to handle the timing for how long you hold it
|
//we need this to handle the timing for how long you hold it
|
||||||
player.noJump();
|
player.noJump();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.isDown('DOWN')) {
|
if (input.isDown("DOWN")) {
|
||||||
player.crouch();
|
player.crouch();
|
||||||
} else {
|
} else {
|
||||||
player.noCrouch();
|
player.noCrouch();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input.isDown('LEFT')) { // 'd' or left arrow
|
if (input.isDown("LEFT")) {
|
||||||
player.moveLeft();
|
// 'd' or left arrow
|
||||||
}
|
player.moveLeft();
|
||||||
else if (input.isDown('RIGHT')) { // 'k' or right arrow
|
} else if (input.isDown("RIGHT")) {
|
||||||
player.moveRight();
|
// 'k' or right arrow
|
||||||
} else {
|
player.moveRight();
|
||||||
player.noWalk();
|
} else {
|
||||||
}
|
player.noWalk();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//update all the moving stuff
|
//update all the moving stuff
|
||||||
function updateEntities(dt, gameTime) {
|
function updateEntities(dt, gameTime) {
|
||||||
player.update(dt, vX);
|
player.update(dt, vX);
|
||||||
updateables.forEach (function(ent) {
|
updateables.forEach(function (ent) {
|
||||||
ent.update(dt, gameTime);
|
ent.update(dt, gameTime);
|
||||||
});
|
});
|
||||||
|
|
||||||
//This should stop the jump when he switches sides on the flag.
|
//This should stop the jump when he switches sides on the flag.
|
||||||
if (player.exiting) {
|
if (player.exiting) {
|
||||||
if (player.pos[0] > vX + 96)
|
if (player.pos[0] > vX + 96) vX = player.pos[0] - 96;
|
||||||
vX = player.pos[0] - 96
|
} else if (level.scrolling && player.pos[0] > vX + 80) {
|
||||||
}else if (level.scrolling && player.pos[0] > vX + 80) {
|
vX = player.pos[0] - 80;
|
||||||
vX = player.pos[0] - 80;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (player.powering.length !== 0 || player.dying) { return; }
|
if (player.powering.length !== 0 || player.dying) {
|
||||||
level.items.forEach (function(ent) {
|
return;
|
||||||
ent.update(dt);
|
}
|
||||||
});
|
level.items.forEach(function (ent) {
|
||||||
|
ent.update(dt);
|
||||||
|
});
|
||||||
|
|
||||||
level.enemies.forEach (function(ent) {
|
level.enemies.forEach(function (ent) {
|
||||||
ent.update(dt, vX);
|
ent.update(dt, vX);
|
||||||
});
|
});
|
||||||
|
|
||||||
fireballs.forEach(function(fireball) {
|
fireballs.forEach(function (fireball) {
|
||||||
fireball.update(dt);
|
fireball.update(dt);
|
||||||
});
|
});
|
||||||
level.pipes.forEach (function(pipe) {
|
level.pipes.forEach(function (pipe) {
|
||||||
pipe.update(dt);
|
pipe.update(dt);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//scan for collisions
|
//scan for collisions
|
||||||
function checkCollisions() {
|
function checkCollisions() {
|
||||||
if (player.powering.length !== 0 || player.dying) { return; }
|
if (player.powering.length !== 0 || player.dying) {
|
||||||
player.checkCollisions();
|
return;
|
||||||
|
}
|
||||||
|
player.checkCollisions();
|
||||||
|
|
||||||
//Apparently for each will just skip indices where things were deleted.
|
//Apparently for each will just skip indices where things were deleted.
|
||||||
level.items.forEach(function(item) {
|
level.items.forEach(function (item) {
|
||||||
item.checkCollisions();
|
item.checkCollisions();
|
||||||
});
|
});
|
||||||
level.enemies.forEach (function(ent) {
|
level.enemies.forEach(function (ent) {
|
||||||
ent.checkCollisions();
|
ent.checkCollisions();
|
||||||
});
|
});
|
||||||
fireballs.forEach(function(fireball){
|
fireballs.forEach(function (fireball) {
|
||||||
fireball.checkCollisions();
|
fireball.checkCollisions();
|
||||||
});
|
});
|
||||||
level.pipes.forEach (function(pipe) {
|
level.pipes.forEach(function (pipe) {
|
||||||
pipe.checkCollisions();
|
pipe.checkCollisions();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//draw the game!
|
//draw the game!
|
||||||
function render() {
|
function render() {
|
||||||
updateables = [];
|
updateables = [];
|
||||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||||
ctx.fillStyle = level.background;
|
ctx.fillStyle = level.background;
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
//scenery gets drawn first to get layering right.
|
//scenery gets drawn first to get layering right.
|
||||||
for(var i = 0; i < 15; i++) {
|
for (var i = 0; i < 15; i++) {
|
||||||
for (var j = Math.floor(vX / 16) - 1; j < Math.floor(vX / 16) + 20; j++){
|
for (
|
||||||
if (level.scenery[i][j]) {
|
var j = Math.floor(vX / 16) - 1;
|
||||||
renderEntity(level.scenery[i][j]);
|
j < Math.floor(vX / 16) + 20;
|
||||||
}
|
j++
|
||||||
|
) {
|
||||||
|
if (level.scenery[i][j]) {
|
||||||
|
renderEntity(level.scenery[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//then items
|
//then items
|
||||||
level.items.forEach (function (item) {
|
level.items.forEach(function (item) {
|
||||||
renderEntity(item);
|
renderEntity(item);
|
||||||
});
|
});
|
||||||
|
|
||||||
level.enemies.forEach (function(enemy) {
|
level.enemies.forEach(function (enemy) {
|
||||||
renderEntity(enemy);
|
renderEntity(enemy);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fireballs.forEach(function (fireball) {
|
||||||
|
renderEntity(fireball);
|
||||||
|
});
|
||||||
|
|
||||||
|
//then we draw every static object.
|
||||||
fireballs.forEach(function(fireball) {
|
for (var i = 0; i < 15; i++) {
|
||||||
renderEntity(fireball);
|
for (
|
||||||
})
|
var j = Math.floor(vX / 16) - 1;
|
||||||
|
j < Math.floor(vX / 16) + 20;
|
||||||
//then we draw every static object.
|
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]) {
|
||||||
if (level.statics[i][j]) {
|
renderEntity(level.statics[i][j]);
|
||||||
renderEntity(level.statics[i][j]);
|
}
|
||||||
}
|
if (level.blocks[i][j]) {
|
||||||
if (level.blocks[i][j]) {
|
renderEntity(level.blocks[i][j]);
|
||||||
renderEntity(level.blocks[i][j]);
|
updateables.push(level.blocks[i][j]);
|
||||||
updateables.push(level.blocks[i][j]);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//then the player
|
//then the player
|
||||||
if (player.invincibility % 2 === 0) {
|
if (player.invincibility % 2 === 0) {
|
||||||
renderEntity(player);
|
renderEntity(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Mario goes INTO pipes, so naturally they go after.
|
//Mario goes INTO pipes, so naturally they go after.
|
||||||
level.pipes.forEach (function(pipe) {
|
level.pipes.forEach(function (pipe) {
|
||||||
renderEntity(pipe);
|
renderEntity(pipe);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderEntity(entity) {
|
function renderEntity(entity) {
|
||||||
entity.render(ctx, vX, vY);
|
entity.render(ctx, vX, vY);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,129 +1,147 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
window.Mario = {};
|
|
||||||
|
|
||||||
//TODO: On console the hitbox is smaller. Measure it and edit this.
|
//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;
|
this.dying = false;
|
||||||
Mario.Entity.call(this, {
|
Mario.Entity.call(this, {
|
||||||
pos: pos,
|
pos: pos,
|
||||||
sprite: sprite,
|
sprite: sprite,
|
||||||
hitbox: [0,0,16,16]
|
hitbox: [0, 0, 16, 16],
|
||||||
|
});
|
||||||
|
this.vel[0] = -0.5;
|
||||||
|
this.idx = level.enemies.length;
|
||||||
});
|
});
|
||||||
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);
|
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||||
};
|
};
|
||||||
|
|
||||||
Goomba.prototype.update = function(dt, vX) {
|
Goomba.prototype.update = function (dt, vX) {
|
||||||
if (this.pos[0] - vX > 336) { //if we're too far away, do nothing.
|
if (this.pos[0] - vX > 336) {
|
||||||
return;
|
//if we're too far away, do nothing.
|
||||||
} else if (this.pos[0] - vX < -32) {
|
return;
|
||||||
delete level.enemies[this.idx];
|
} else if (this.pos[0] - vX < -32) {
|
||||||
}
|
delete level.enemies[this.idx];
|
||||||
|
|
||||||
if (this.dying) {
|
|
||||||
this.dying -= 1;
|
|
||||||
if (!this.dying) {
|
|
||||||
delete level.enemies[this.idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.acc[1] = 0.2;
|
|
||||||
this.vel[1] += this.acc[1];
|
|
||||||
this.pos[0] += this.vel[0];
|
|
||||||
this.pos[1] += this.vel[1];
|
|
||||||
this.sprite.update(dt);
|
|
||||||
};
|
|
||||||
|
|
||||||
Goomba.prototype.collideWall = function() {
|
|
||||||
this.vel[0] = -this.vel[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
Goomba.prototype.checkCollisions = function() {
|
|
||||||
if (this.flipping) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var h = this.pos[1] % 16 === 0 ? 1 : 2;
|
|
||||||
var w = this.pos[0] % 16 === 0 ? 1 : 2;
|
|
||||||
|
|
||||||
var baseX = Math.floor(this.pos[0] / 16);
|
|
||||||
var baseY = Math.floor(this.pos[1] / 16);
|
|
||||||
|
|
||||||
if (baseY + h > 15) {
|
|
||||||
delete level.enemies[this.idx];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < h; i++) {
|
|
||||||
for (var j = 0; j < w; j++) {
|
|
||||||
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);
|
if (this.dying) {
|
||||||
|
this.dying -= 1;
|
||||||
|
if (!this.dying) {
|
||||||
|
delete level.enemies[this.idx];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
this.acc[1] = 0.2;
|
||||||
}
|
this.vel[1] += this.acc[1];
|
||||||
var that = this;
|
this.pos[0] += this.vel[0];
|
||||||
level.enemies.forEach(function(enemy){
|
this.pos[1] += this.vel[1];
|
||||||
if (enemy === that) { //don't check collisions with ourselves.
|
this.sprite.update(dt);
|
||||||
return;
|
};
|
||||||
} else if (enemy.pos[0] - vX > 336){ //stop checking once we get to far away dudes.
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
that.isCollideWith(enemy);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.isCollideWith(player);
|
|
||||||
};
|
|
||||||
|
|
||||||
Goomba.prototype.isCollideWith = function(ent) {
|
Goomba.prototype.collideWall = function () {
|
||||||
if (ent instanceof Mario.Player && (this.dying || ent.invincibility)) {
|
this.vel[0] = -this.vel[0];
|
||||||
return;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
//the first two elements of the hitbox array are an offset, so let's do this now.
|
Goomba.prototype.checkCollisions = function () {
|
||||||
var hpos1 = [this.pos[0] + this.hitbox[0], this.pos[1] + this.hitbox[1]];
|
if (this.flipping) {
|
||||||
var hpos2 = [ent.pos[0] + ent.hitbox[0], ent.pos[1] + ent.hitbox[1]];
|
return;
|
||||||
|
|
||||||
//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
|
|
||||||
this.stomp();
|
|
||||||
} else if (ent.starTime) {
|
|
||||||
this.bump();
|
|
||||||
} else { //or the player gets hit
|
|
||||||
ent.damage();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.collideWall();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Goomba.prototype.stomp = function() {
|
var h = this.pos[1] % 16 === 0 ? 1 : 2;
|
||||||
sounds.stomp.play();
|
var w = this.pos[0] % 16 === 0 ? 1 : 2;
|
||||||
player.bounce = true;
|
|
||||||
this.sprite.pos[0] = 32;
|
|
||||||
this.sprite.speed = 0;
|
|
||||||
this.vel[0] = 0;
|
|
||||||
this.dying = 10;
|
|
||||||
};
|
|
||||||
|
|
||||||
Goomba.prototype.bump = function() {
|
var baseX = Math.floor(this.pos[0] / 16);
|
||||||
sounds.kick.play();
|
var baseY = Math.floor(this.pos[1] / 16);
|
||||||
this.sprite.img = 'sprites/enemyr.png';
|
|
||||||
this.flipping = true;
|
if (baseY + h > 15) {
|
||||||
this.pos[1] -= 1;
|
delete level.enemies[this.idx];
|
||||||
this.vel[0] = 0;
|
return;
|
||||||
this.vel[1] = -2.5;
|
}
|
||||||
};
|
|
||||||
|
for (var i = 0; i < h; i++) {
|
||||||
|
for (var j = 0; j < w; j++) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var that = this;
|
||||||
|
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.
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
that.isCollideWith(enemy);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.isCollideWith(player);
|
||||||
|
};
|
||||||
|
|
||||||
|
Goomba.prototype.isCollideWith = function (ent) {
|
||||||
|
if (ent instanceof Mario.Player && (this.dying || ent.invincibility)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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 (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
|
||||||
|
ent.damage();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.collideWall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Goomba.prototype.stomp = function () {
|
||||||
|
sounds.stomp.play();
|
||||||
|
player.bounce = true;
|
||||||
|
this.sprite.pos[0] = 32;
|
||||||
|
this.sprite.speed = 0;
|
||||||
|
this.vel[0] = 0;
|
||||||
|
this.dying = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
Goomba.prototype.bump = function () {
|
||||||
|
sounds.kick.play();
|
||||||
|
this.sprite.img = "sprites/enemyr.png";
|
||||||
|
this.flipping = true;
|
||||||
|
this.pos[1] -= 1;
|
||||||
|
this.vel[0] = 0;
|
||||||
|
this.vel[1] = -2.5;
|
||||||
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,54 +1,61 @@
|
|||||||
(function() {
|
(function () {
|
||||||
var pressedKeys = {};
|
var pressedKeys = {};
|
||||||
|
|
||||||
function setKey(event, status) {
|
function setKey(event, status) {
|
||||||
var code = event.keyCode;
|
var code = event.keyCode;
|
||||||
var key;
|
var key;
|
||||||
|
|
||||||
switch(code) {
|
switch (code) {
|
||||||
case 32:
|
case 32:
|
||||||
key = 'SPACE'; break;
|
key = "SPACE";
|
||||||
case 37:
|
break;
|
||||||
key = 'LEFT'; break;
|
case 37:
|
||||||
case 38:
|
key = "LEFT";
|
||||||
key = 'UP'; break;
|
break;
|
||||||
case 39:
|
case 38:
|
||||||
key = 'RIGHT'; break;
|
key = "UP";
|
||||||
case 40:
|
break;
|
||||||
key = 'DOWN'; break;
|
case 39:
|
||||||
case 88:
|
key = "RIGHT";
|
||||||
key = 'JUMP'; break;
|
break;
|
||||||
case 90:
|
case 40:
|
||||||
key = 'RUN'; break;
|
key = "DOWN";
|
||||||
default:
|
break;
|
||||||
key = String.fromCharCode(code);
|
case 88:
|
||||||
|
key = "JUMP";
|
||||||
|
break;
|
||||||
|
case 90:
|
||||||
|
key = "RUN";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
key = String.fromCharCode(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
pressedKeys[key] = status;
|
pressedKeys[key] = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('keydown', function(e) {
|
document.addEventListener("keydown", function (e) {
|
||||||
setKey(e, true);
|
setKey(e, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('keyup', function(e) {
|
document.addEventListener("keyup", function (e) {
|
||||||
setKey(e, false);
|
setKey(e, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
window.addEventListener('blur', function() {
|
window.addEventListener("blur", function () {
|
||||||
pressedKeys = {};
|
pressedKeys = {};
|
||||||
});
|
});
|
||||||
|
|
||||||
window.input = {
|
window.input = {
|
||||||
isDown: function(key) {
|
isDown: function (key) {
|
||||||
return pressedKeys[key.toUpperCase()];
|
return pressedKeys[key.toUpperCase()];
|
||||||
},
|
},
|
||||||
reset: function() {
|
reset: function () {
|
||||||
pressedKeys['RUN'] = false;
|
pressedKeys["RUN"] = false;
|
||||||
pressedKeys['LEFT'] = false;
|
pressedKeys["LEFT"] = false;
|
||||||
pressedKeys['RIGHT'] = false;
|
pressedKeys["RIGHT"] = false;
|
||||||
pressedKeys['DOWN'] = false;
|
pressedKeys["DOWN"] = false;
|
||||||
pressedKeys['JUMP'] = false;
|
pressedKeys["JUMP"] = false;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,211 +1,228 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
window.Mario = {};
|
|
||||||
|
|
||||||
var Koopa = Mario.Koopa = function(pos, sprite, para) {
|
var Koopa = (Mario.Koopa = function (pos, sprite, para) {
|
||||||
this.dying = false;
|
this.dying = false;
|
||||||
this.shell = false;
|
this.shell = false;
|
||||||
|
|
||||||
this.para = para; //para. As in, is it a paratroopa?
|
this.para = para; //para. As in, is it a paratroopa?
|
||||||
|
|
||||||
//So, funny story. The actual hitboxes don't reach all the way to the ground.
|
//So, funny story. The actual hitboxes don't reach all the way to the ground.
|
||||||
//What that means is, as long as I use them to keep things on the floor
|
//What that means is, as long as I use them to keep things on the floor
|
||||||
//making the hitboxes accurate will make enemies sink into the ground.
|
//making the hitboxes accurate will make enemies sink into the ground.
|
||||||
Mario.Entity.call(this, {
|
Mario.Entity.call(this, {
|
||||||
pos: pos,
|
pos: pos,
|
||||||
sprite: sprite,
|
sprite: sprite,
|
||||||
hitbox: [2,8,12,24]
|
hitbox: [2, 8, 12, 24],
|
||||||
|
});
|
||||||
|
this.vel[0] = -0.5;
|
||||||
|
this.idx = level.enemies.length;
|
||||||
});
|
});
|
||||||
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);
|
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) {
|
if (this.turn) {
|
||||||
this.vel[0] = -this.vel[0];
|
this.vel[0] = -this.vel[0];
|
||||||
if (this.shell) sounds.bump.play();
|
if (this.shell) sounds.bump.play();
|
||||||
this.turn = false;
|
this.turn = false;
|
||||||
}
|
|
||||||
if (this.vel[0] != 0) {
|
|
||||||
this.left = (this.vel[0] < 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.left) {
|
|
||||||
this.sprite.img = 'sprites/enemy.png';
|
|
||||||
} else {
|
|
||||||
this.sprite.img = 'sprites/enemyr.png';
|
|
||||||
}
|
|
||||||
|
|
||||||
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];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.dying) {
|
|
||||||
this.dying -= 1;
|
|
||||||
if (!this.dying) {
|
|
||||||
delete level.enemies[this.idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.shell) {
|
|
||||||
if (this.vel[0] == 0) {
|
|
||||||
this.shell -= 1;
|
|
||||||
if (this.shell < 120) {
|
|
||||||
this.sprite.speed = 5;
|
|
||||||
}
|
}
|
||||||
if (this.shell == 0) {
|
if (this.vel[0] != 0) {
|
||||||
this.sprite = level.koopaSprite();
|
this.left = this.vel[0] < 0;
|
||||||
this.hitbox = [2,8,12,24]
|
|
||||||
if (this.left) {
|
|
||||||
this.sprite.img = 'sprites/enemyr.png';
|
|
||||||
this.vel[0] = 0.5;
|
|
||||||
this.left = false;
|
|
||||||
} else {
|
|
||||||
this.vel[0] = -0.5;
|
|
||||||
this.left = true;
|
|
||||||
}
|
|
||||||
this.pos[1] -= 16;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
this.shell = 360;
|
|
||||||
this.sprite.speed = 0;
|
|
||||||
this.sprite.setFrame(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.acc[1] = 0.2;
|
|
||||||
this.vel[1] += this.acc[1];
|
|
||||||
this.pos[0] += this.vel[0];
|
|
||||||
this.pos[1] += this.vel[1];
|
|
||||||
this.sprite.update(dt);
|
|
||||||
};
|
|
||||||
|
|
||||||
Koopa.prototype.collideWall = function() {
|
if (this.left) {
|
||||||
//This stops us from flipping twice on the same frame if we collide
|
this.sprite.img = "sprites/enemy.png";
|
||||||
//with multiple wall tiles simultaneously.
|
|
||||||
this.turn = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
Koopa.prototype.checkCollisions = function() {
|
|
||||||
var h = this.shell ? 1 : 2;
|
|
||||||
if (this.pos[1] % 16 !== 0) {
|
|
||||||
h += 1;
|
|
||||||
}
|
|
||||||
var w = this.pos[0] % 16 === 0 ? 1 : 2;
|
|
||||||
|
|
||||||
var baseX = Math.floor(this.pos[0] / 16);
|
|
||||||
var baseY = Math.floor(this.pos[1] / 16);
|
|
||||||
|
|
||||||
if (baseY + h > 15) {
|
|
||||||
delete level.enemies[this.idx];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.flipping) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < h; i++) {
|
|
||||||
for (var j = 0; j < w; j++) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var that = this;
|
|
||||||
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.
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
that.isCollideWith(enemy);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.isCollideWith(player);
|
|
||||||
};
|
|
||||||
|
|
||||||
Koopa.prototype.isCollideWith = function(ent) {
|
|
||||||
if (ent instanceof Mario.Player && (this.dying || ent.invincibility)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//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 (ent instanceof Mario.Player) {
|
|
||||||
if (ent.vel[1] > 0) {
|
|
||||||
player.bounce = true;
|
|
||||||
}
|
|
||||||
if (this.shell) {
|
|
||||||
sounds.kick.play();
|
|
||||||
if (this.vel[0] === 0) {
|
|
||||||
if (ent.left) { //I'm pretty sure this isn't the real logic.
|
|
||||||
this.vel[0] = -4;
|
|
||||||
} else {
|
|
||||||
this.vel[0] = 4;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (ent.bounce) {
|
|
||||||
this.vel[0] = 0;
|
|
||||||
} else ent.damage();
|
|
||||||
}
|
|
||||||
} else if (ent.vel[1] > 0) { //then we get BOPPED.
|
|
||||||
this.stomp();
|
|
||||||
} else { //or the player gets hit
|
|
||||||
ent.damage();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (this.shell && (ent instanceof Mario.Goomba)) {
|
this.sprite.img = "sprites/enemyr.png";
|
||||||
ent.bump();
|
|
||||||
} else this.collideWall();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Koopa.prototype.stomp = function() {
|
if (this.pos[0] - vX > 336) {
|
||||||
//Turn this thing into a shell if it isn't already. Kick it if it is.
|
//if we're too far away, do nothing.
|
||||||
player.bounce = true;
|
return;
|
||||||
if (this.para) {
|
} else if (this.pos[0] - vX < -32) {
|
||||||
this.para = false;
|
delete level.enemies[this.idx];
|
||||||
this.sprite.pos[0] -= 32;
|
}
|
||||||
} else {
|
|
||||||
sounds.stomp.play();
|
|
||||||
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.speed = 0;
|
|
||||||
this.frames = [0,1];
|
|
||||||
this.vel = [0,0];
|
|
||||||
this.pos[1] += 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
if (this.dying) {
|
||||||
|
this.dying -= 1;
|
||||||
|
if (!this.dying) {
|
||||||
|
delete level.enemies[this.idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Koopa.prototype.bump = function() {
|
if (this.shell) {
|
||||||
sounds.kick.play();
|
if (this.vel[0] == 0) {
|
||||||
if (this.flipping) return;
|
this.shell -= 1;
|
||||||
this.flipping = true;
|
if (this.shell < 120) {
|
||||||
this.sprite.pos = [160, 0];
|
this.sprite.speed = 5;
|
||||||
this.sprite.size = [16,16];
|
}
|
||||||
this.hitbox = [2, 0, 12, 16];
|
if (this.shell == 0) {
|
||||||
this.sprite.speed = 0;
|
this.sprite = level.koopaSprite();
|
||||||
this.vel[0] = 0;
|
this.hitbox = [2, 8, 12, 24];
|
||||||
this.vel[1] = -2.5;
|
if (this.left) {
|
||||||
};
|
this.sprite.img = "sprites/enemyr.png";
|
||||||
|
this.vel[0] = 0.5;
|
||||||
|
this.left = false;
|
||||||
|
} else {
|
||||||
|
this.vel[0] = -0.5;
|
||||||
|
this.left = true;
|
||||||
|
}
|
||||||
|
this.pos[1] -= 16;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.shell = 360;
|
||||||
|
this.sprite.speed = 0;
|
||||||
|
this.sprite.setFrame(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.acc[1] = 0.2;
|
||||||
|
this.vel[1] += this.acc[1];
|
||||||
|
this.pos[0] += this.vel[0];
|
||||||
|
this.pos[1] += this.vel[1];
|
||||||
|
this.sprite.update(dt);
|
||||||
|
};
|
||||||
|
|
||||||
|
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 () {
|
||||||
|
var h = this.shell ? 1 : 2;
|
||||||
|
if (this.pos[1] % 16 !== 0) {
|
||||||
|
h += 1;
|
||||||
|
}
|
||||||
|
var w = this.pos[0] % 16 === 0 ? 1 : 2;
|
||||||
|
|
||||||
|
var baseX = Math.floor(this.pos[0] / 16);
|
||||||
|
var baseY = Math.floor(this.pos[1] / 16);
|
||||||
|
|
||||||
|
if (baseY + h > 15) {
|
||||||
|
delete level.enemies[this.idx];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.flipping) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < h; i++) {
|
||||||
|
for (var j = 0; j < w; j++) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var that = this;
|
||||||
|
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.
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
that.isCollideWith(enemy);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.isCollideWith(player);
|
||||||
|
};
|
||||||
|
|
||||||
|
Koopa.prototype.isCollideWith = function (ent) {
|
||||||
|
if (ent instanceof Mario.Player && (this.dying || ent.invincibility)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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 (ent instanceof Mario.Player) {
|
||||||
|
if (ent.vel[1] > 0) {
|
||||||
|
player.bounce = true;
|
||||||
|
}
|
||||||
|
if (this.shell) {
|
||||||
|
sounds.kick.play();
|
||||||
|
if (this.vel[0] === 0) {
|
||||||
|
if (ent.left) {
|
||||||
|
//I'm pretty sure this isn't the real logic.
|
||||||
|
this.vel[0] = -4;
|
||||||
|
} else {
|
||||||
|
this.vel[0] = 4;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ent.bounce) {
|
||||||
|
this.vel[0] = 0;
|
||||||
|
} else ent.damage();
|
||||||
|
}
|
||||||
|
} else if (ent.vel[1] > 0) {
|
||||||
|
//then we get BOPPED.
|
||||||
|
this.stomp();
|
||||||
|
} else {
|
||||||
|
//or the player gets hit
|
||||||
|
ent.damage();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.shell && ent instanceof Mario.Goomba) {
|
||||||
|
ent.bump();
|
||||||
|
} else this.collideWall();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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) {
|
||||||
|
this.para = false;
|
||||||
|
this.sprite.pos[0] -= 32;
|
||||||
|
} else {
|
||||||
|
sounds.stomp.play();
|
||||||
|
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.speed = 0;
|
||||||
|
this.frames = [0, 1];
|
||||||
|
this.vel = [0, 0];
|
||||||
|
this.pos[1] += 16;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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.hitbox = [2, 0, 12, 16];
|
||||||
|
this.sprite.speed = 0;
|
||||||
|
this.vel[0] = 0;
|
||||||
|
this.vel[1] = -2.5;
|
||||||
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,219 +1,341 @@
|
|||||||
var oneone = Mario.oneone = function() {
|
var oneone = (Mario.oneone = function () {
|
||||||
//The things that need to be passed in are basically just dependent on what
|
//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
|
//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.
|
//TODO: put as much of this in the Level object definition as possible.
|
||||||
level = new Mario.Level({
|
level = new Mario.Level({
|
||||||
playerPos: [56,192],
|
playerPos: [56, 192],
|
||||||
loader: Mario.oneone,
|
loader: Mario.oneone,
|
||||||
background: "#7974FF",
|
background: "#7974FF",
|
||||||
scrolling: true,
|
scrolling: true,
|
||||||
invincibility: [144, 192, 240],
|
invincibility: [144, 192, 240],
|
||||||
exit: 204,
|
exit: 204,
|
||||||
floorSprite: new Mario.Sprite('sprites/tiles.png', [0,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),
|
cloudSprite: new Mario.Sprite(
|
||||||
wallSprite: new Mario.Sprite('sprites/tiles.png', [0, 16],[16,16],0),
|
"sprites/tiles.png",
|
||||||
brickSprite: new Mario.Sprite('sprites/tiles.png', [16, 0], [16,16], 0),
|
[0, 320],
|
||||||
brickBounceSprite: new Mario.Sprite('sprites/tiles.png',[32,0],[16,16],0),
|
[48, 32],
|
||||||
rubbleSprite: function () {
|
0,
|
||||||
return new Mario.Sprite('sprites/items.png', [64,0], [8,8], 3, [0,1])
|
),
|
||||||
},
|
wallSprite: new Mario.Sprite("sprites/tiles.png", [0, 16], [16, 16], 0),
|
||||||
ublockSprite: new Mario.Sprite('sprites/tiles.png', [48, 0], [16,16],0),
|
brickSprite: new Mario.Sprite(
|
||||||
superShroomSprite: new Mario.Sprite('sprites/items.png', [0,0], [16,16], 0),
|
"sprites/tiles.png",
|
||||||
fireFlowerSprite: new Mario.Sprite('sprites/items.png', [0,32], [16,16], 20, [0,1,2,3]),
|
[16, 0],
|
||||||
starSprite: new Mario.Sprite('sprites/items.png', [0,48], [16,16], 20, [0,1,2,3]),
|
[16, 16],
|
||||||
pipeLEndSprite: new Mario.Sprite('sprites/tiles.png', [0, 128], [16,16], 0),
|
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),
|
brickBounceSprite: new Mario.Sprite(
|
||||||
pipeRMidSprite: new Mario.Sprite('sprites/tiles.png', [16, 144], [16,16], 0),
|
"sprites/tiles.png",
|
||||||
|
[32, 0],
|
||||||
|
[16, 16],
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
rubbleSprite: function () {
|
||||||
|
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,
|
||||||
|
),
|
||||||
|
|
||||||
pipeUpMid: new Mario.Sprite('sprites/tiles.png', [0, 144], [32,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),
|
pipeSideMid: new Mario.Sprite(
|
||||||
pipeLeft: new Mario.Sprite('sprites/tiles.png', [32, 128], [16,32], 0),
|
"sprites/tiles.png",
|
||||||
pipeTop: new Mario.Sprite('sprites/tiles.png', [0, 128], [32,16], 0),
|
[48, 128],
|
||||||
qblockSprite: new Mario.Sprite('sprites/tiles.png', [384, 0], [16,16], 8, [0,0,0,0,1,2,1]),
|
[16, 32],
|
||||||
bcoinSprite: function() {
|
0,
|
||||||
return new Mario.Sprite('sprites/items.png', [0,112],[16,16], 20,[0,1,2,3]);
|
),
|
||||||
},
|
pipeLeft: new Mario.Sprite("sprites/tiles.png", [32, 128], [16, 32], 0),
|
||||||
cloudSprites:[
|
pipeTop: new Mario.Sprite("sprites/tiles.png", [0, 128], [32, 16], 0),
|
||||||
new Mario.Sprite('sprites/tiles.png', [0,320],[16,32],0),
|
qblockSprite: new Mario.Sprite(
|
||||||
new Mario.Sprite('sprites/tiles.png', [16,320],[16,32],0),
|
"sprites/tiles.png",
|
||||||
new Mario.Sprite('sprites/tiles.png', [32,320],[16,32],0)
|
[384, 0],
|
||||||
],
|
[16, 16],
|
||||||
hillSprites: [
|
8,
|
||||||
new Mario.Sprite('sprites/tiles.png', [128,128],[16,16],0),
|
[0, 0, 0, 0, 1, 2, 1],
|
||||||
new Mario.Sprite('sprites/tiles.png', [144,128],[16,16],0),
|
),
|
||||||
new Mario.Sprite('sprites/tiles.png', [160,128],[16,16],0),
|
bcoinSprite: function () {
|
||||||
new Mario.Sprite('sprites/tiles.png', [128,144],[16,16],0),
|
return new Mario.Sprite(
|
||||||
new Mario.Sprite('sprites/tiles.png', [144,144],[16,16],0),
|
"sprites/items.png",
|
||||||
new Mario.Sprite('sprites/tiles.png', [160,144],[16,16],0)
|
[0, 112],
|
||||||
],
|
[16, 16],
|
||||||
bushSprite: new Mario.Sprite('sprites/tiles.png', [176, 144], [48, 16], 0),
|
20,
|
||||||
bushSprites: [
|
[0, 1, 2, 3],
|
||||||
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)],
|
cloudSprites: [
|
||||||
goombaSprite: function() {
|
new Mario.Sprite("sprites/tiles.png", [0, 320], [16, 32], 0),
|
||||||
return new Mario.Sprite('sprites/enemy.png', [0, 16], [16,16], 3, [0,1]);
|
new Mario.Sprite("sprites/tiles.png", [16, 320], [16, 32], 0),
|
||||||
},
|
new Mario.Sprite("sprites/tiles.png", [32, 320], [16, 32], 0),
|
||||||
koopaSprite: function() {
|
],
|
||||||
return new Mario.Sprite('sprites/enemy.png', [96,0], [16,32], 2, [0,1]);
|
hillSprites: [
|
||||||
},
|
new Mario.Sprite("sprites/tiles.png", [128, 128], [16, 16], 0),
|
||||||
flagPoleSprites: [
|
new Mario.Sprite("sprites/tiles.png", [144, 128], [16, 16], 0),
|
||||||
new Mario.Sprite('sprites/tiles.png', [256, 128], [16,16], 0),
|
new Mario.Sprite("sprites/tiles.png", [160, 128], [16, 16], 0),
|
||||||
new Mario.Sprite('sprites/tiles.png', [256, 144], [16,16], 0),
|
new Mario.Sprite("sprites/tiles.png", [128, 144], [16, 16], 0),
|
||||||
new Mario.Sprite('sprites/items.png', [128, 32], [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),
|
||||||
});
|
],
|
||||||
ground = [[0,69],[71,86],[89,153],[155,212]];
|
bushSprite: new Mario.Sprite(
|
||||||
player.pos[0] = level.playerPos[0];
|
"sprites/tiles.png",
|
||||||
player.pos[1] = level.playerPos[1];
|
[176, 144],
|
||||||
vX = 0;
|
[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],
|
||||||
|
];
|
||||||
|
player.pos[0] = level.playerPos[0];
|
||||||
|
player.pos[1] = level.playerPos[1];
|
||||||
|
vX = 0;
|
||||||
|
|
||||||
//build THE GROUND
|
//build THE GROUND
|
||||||
ground.forEach(function(loc) {
|
ground.forEach(function (loc) {
|
||||||
level.putFloor(loc[0],loc[1]);
|
level.putFloor(loc[0], loc[1]);
|
||||||
});
|
});
|
||||||
|
|
||||||
//build scenery
|
//build scenery
|
||||||
clouds = [[7,3],[19, 2],[56, 3],[67, 2],[87, 2],[103, 2],[152, 3],[163, 2],[200, 3]];
|
clouds = [
|
||||||
clouds.forEach(function(cloud){
|
[7, 3],
|
||||||
level.putCloud(cloud[0],cloud[1]);
|
[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 = [
|
||||||
twoClouds.forEach(function(cloud){
|
[36, 2],
|
||||||
level.putTwoCloud(cloud[0],cloud[1]);
|
[132, 2],
|
||||||
});
|
[180, 2],
|
||||||
|
];
|
||||||
|
twoClouds.forEach(function (cloud) {
|
||||||
|
level.putTwoCloud(cloud[0], cloud[1]);
|
||||||
|
});
|
||||||
|
|
||||||
threeClouds = [[27,3],[75,3],[123,3],[171,3]];
|
threeClouds = [
|
||||||
threeClouds.forEach(function(cloud){
|
[27, 3],
|
||||||
level.putThreeCloud(cloud[0],cloud[1]);
|
[75, 3],
|
||||||
});
|
[123, 3],
|
||||||
|
[171, 3],
|
||||||
|
];
|
||||||
|
threeClouds.forEach(function (cloud) {
|
||||||
|
level.putThreeCloud(cloud[0], cloud[1]);
|
||||||
|
});
|
||||||
|
|
||||||
bHills = [0,48,96,144,192]
|
bHills = [0, 48, 96, 144, 192];
|
||||||
bHills.forEach(function(hill) {
|
bHills.forEach(function (hill) {
|
||||||
level.putBigHill(hill, 12);
|
level.putBigHill(hill, 12);
|
||||||
});
|
});
|
||||||
|
|
||||||
sHills = [16,64,111,160];
|
sHills = [16, 64, 111, 160];
|
||||||
sHills.forEach(function(hill) {
|
sHills.forEach(function (hill) {
|
||||||
level.putSmallHill(hill, 12);
|
level.putSmallHill(hill, 12);
|
||||||
});
|
});
|
||||||
|
|
||||||
bushes = [23,71,118,167];
|
bushes = [23, 71, 118, 167];
|
||||||
bushes.forEach(function(bush) {
|
bushes.forEach(function (bush) {
|
||||||
level.putBush(bush, 12);
|
level.putBush(bush, 12);
|
||||||
});
|
});
|
||||||
|
|
||||||
twoBushes = [41,89,137];
|
twoBushes = [41, 89, 137];
|
||||||
twoBushes.forEach(function(bush) {
|
twoBushes.forEach(function (bush) {
|
||||||
level.putTwoBush(bush, 12);
|
level.putTwoBush(bush, 12);
|
||||||
});
|
});
|
||||||
|
|
||||||
threeBushes = [11,59,106];
|
threeBushes = [11, 59, 106];
|
||||||
threeBushes.forEach(function(bush) {
|
threeBushes.forEach(function (bush) {
|
||||||
level.putThreeBush(bush, 12);
|
level.putThreeBush(bush, 12);
|
||||||
});
|
});
|
||||||
|
|
||||||
//interactable terrain
|
//interactable terrain
|
||||||
level.putQBlock(16, 9, new Mario.Bcoin([256, 144]));
|
level.putQBlock(16, 9, new Mario.Bcoin([256, 144]));
|
||||||
level.putBrick(20, 9, null);
|
level.putBrick(20, 9, null);
|
||||||
level.putQBlock(21, 9, new Mario.Mushroom([336, 144]));
|
level.putQBlock(21, 9, new Mario.Mushroom([336, 144]));
|
||||||
level.putBrick(22, 9, null);
|
level.putBrick(22, 9, null);
|
||||||
level.putQBlock(22, 5, new Mario.Bcoin([352, 80]));
|
level.putQBlock(22, 5, new Mario.Bcoin([352, 80]));
|
||||||
level.putQBlock(23, 9, new Mario.Bcoin([368, 144]));
|
level.putQBlock(23, 9, new Mario.Bcoin([368, 144]));
|
||||||
level.putBrick(24, 9, null);
|
level.putBrick(24, 9, null);
|
||||||
level.putPipe(28, 13, 2);
|
level.putPipe(28, 13, 2);
|
||||||
level.putPipe(38, 13, 3);
|
level.putPipe(38, 13, 3);
|
||||||
level.putPipe(46, 13, 4);
|
level.putPipe(46, 13, 4);
|
||||||
level.putRealPipe(57, 9, 4, "DOWN", Mario.oneonetunnel);
|
level.putRealPipe(57, 9, 4, "DOWN", Mario.oneonetunnel);
|
||||||
level.putBrick(77, 9, null);
|
level.putBrick(77, 9, null);
|
||||||
level.putQBlock(78, 9, new Mario.Mushroom([1248, 144]));
|
level.putQBlock(78, 9, new Mario.Mushroom([1248, 144]));
|
||||||
level.putBrick(79, 9, null);
|
level.putBrick(79, 9, null);
|
||||||
level.putBrick(80, 5, null);
|
level.putBrick(80, 5, null);
|
||||||
level.putBrick(81, 5, null);
|
level.putBrick(81, 5, null);
|
||||||
level.putBrick(82, 5, null);
|
level.putBrick(82, 5, null);
|
||||||
level.putBrick(83, 5, null);
|
level.putBrick(83, 5, null);
|
||||||
level.putBrick(84, 5, null);
|
level.putBrick(84, 5, null);
|
||||||
level.putBrick(85, 5, null);
|
level.putBrick(85, 5, null);
|
||||||
level.putBrick(86, 5, null);
|
level.putBrick(86, 5, null);
|
||||||
level.putBrick(87, 5, null);
|
level.putBrick(87, 5, null);
|
||||||
level.putBrick(91, 5, null);
|
level.putBrick(91, 5, null);
|
||||||
level.putBrick(92, 5, null);
|
level.putBrick(92, 5, null);
|
||||||
level.putBrick(93, 5, null);
|
level.putBrick(93, 5, null);
|
||||||
level.putQBlock(94, 5, new Mario.Bcoin([1504, 80]));
|
level.putQBlock(94, 5, new Mario.Bcoin([1504, 80]));
|
||||||
level.putBrick(94, 9, null);
|
level.putBrick(94, 9, null);
|
||||||
level.putBrick(100, 9, new Mario.Star([1600, 144]));
|
level.putBrick(100, 9, new Mario.Star([1600, 144]));
|
||||||
level.putBrick(101, 9, null);
|
level.putBrick(101, 9, null);
|
||||||
level.putQBlock(105, 9, new Mario.Bcoin([1680, 144]));
|
level.putQBlock(105, 9, new Mario.Bcoin([1680, 144]));
|
||||||
level.putQBlock(108, 9, new Mario.Bcoin([1728, 144]));
|
level.putQBlock(108, 9, new Mario.Bcoin([1728, 144]));
|
||||||
level.putQBlock(108, 5, new Mario.Mushroom([1728, 80]));
|
level.putQBlock(108, 5, new Mario.Mushroom([1728, 80]));
|
||||||
level.putQBlock(111, 9, new Mario.Bcoin([1776, 144]));
|
level.putQBlock(111, 9, new Mario.Bcoin([1776, 144]));
|
||||||
level.putBrick(117, 9, null);
|
level.putBrick(117, 9, null);
|
||||||
level.putBrick(120, 5, null);
|
level.putBrick(120, 5, null);
|
||||||
level.putBrick(121, 5, null);
|
level.putBrick(121, 5, null);
|
||||||
level.putBrick(122, 5, null);
|
level.putBrick(122, 5, null);
|
||||||
level.putBrick(123, 5, null);
|
level.putBrick(123, 5, null);
|
||||||
level.putBrick(128, 5, null);
|
level.putBrick(128, 5, null);
|
||||||
level.putQBlock(129, 5, new Mario.Bcoin([2074, 80]));
|
level.putQBlock(129, 5, new Mario.Bcoin([2074, 80]));
|
||||||
level.putBrick(129, 9, null);
|
level.putBrick(129, 9, null);
|
||||||
level.putQBlock(130, 5, new Mario.Bcoin([2080, 80]));
|
level.putQBlock(130, 5, new Mario.Bcoin([2080, 80]));
|
||||||
level.putBrick(130, 9, null);
|
level.putBrick(130, 9, null);
|
||||||
level.putBrick(131, 5, null);
|
level.putBrick(131, 5, null);
|
||||||
level.putWall(134, 13, 1);
|
level.putWall(134, 13, 1);
|
||||||
level.putWall(135, 13, 2);
|
level.putWall(135, 13, 2);
|
||||||
level.putWall(136, 13, 3);
|
level.putWall(136, 13, 3);
|
||||||
level.putWall(137, 13, 4);
|
level.putWall(137, 13, 4);
|
||||||
level.putWall(140, 13, 4);
|
level.putWall(140, 13, 4);
|
||||||
level.putWall(141, 13, 3);
|
level.putWall(141, 13, 3);
|
||||||
level.putWall(142, 13, 2);
|
level.putWall(142, 13, 2);
|
||||||
level.putWall(143, 13, 1);
|
level.putWall(143, 13, 1);
|
||||||
level.putWall(148, 13, 1);
|
level.putWall(148, 13, 1);
|
||||||
level.putWall(149, 13, 2);
|
level.putWall(149, 13, 2);
|
||||||
level.putWall(150, 13, 3);
|
level.putWall(150, 13, 3);
|
||||||
level.putWall(151, 13, 4);
|
level.putWall(151, 13, 4);
|
||||||
level.putWall(152, 13, 4);
|
level.putWall(152, 13, 4);
|
||||||
level.putWall(155, 13, 4);
|
level.putWall(155, 13, 4);
|
||||||
level.putWall(156, 13, 3);
|
level.putWall(156, 13, 3);
|
||||||
level.putWall(157, 13, 2);
|
level.putWall(157, 13, 2);
|
||||||
level.putWall(158, 13, 1);
|
level.putWall(158, 13, 1);
|
||||||
level.putPipe(163, 13, 2);
|
level.putPipe(163, 13, 2);
|
||||||
level.putBrick(168, 9, null);
|
level.putBrick(168, 9, null);
|
||||||
level.putBrick(169, 9, null);
|
level.putBrick(169, 9, null);
|
||||||
level.putQBlock(170, 9, new Mario.Bcoin([2720, 144]));
|
level.putQBlock(170, 9, new Mario.Bcoin([2720, 144]));
|
||||||
level.putBrick(171, 9, null);
|
level.putBrick(171, 9, null);
|
||||||
level.putPipe(179, 13, 2);
|
level.putPipe(179, 13, 2);
|
||||||
level.putWall(181, 13, 1);
|
level.putWall(181, 13, 1);
|
||||||
level.putWall(182, 13, 2);
|
level.putWall(182, 13, 2);
|
||||||
level.putWall(183, 13, 3);
|
level.putWall(183, 13, 3);
|
||||||
level.putWall(184, 13, 4);
|
level.putWall(184, 13, 4);
|
||||||
level.putWall(185, 13, 5);
|
level.putWall(185, 13, 5);
|
||||||
level.putWall(186, 13, 6);
|
level.putWall(186, 13, 6);
|
||||||
level.putWall(187, 13, 7);
|
level.putWall(187, 13, 7);
|
||||||
level.putWall(188, 13, 8);
|
level.putWall(188, 13, 8);
|
||||||
level.putWall(189, 13, 8);
|
level.putWall(189, 13, 8);
|
||||||
level.putFlagpole(198);
|
level.putFlagpole(198);
|
||||||
|
|
||||||
//and enemies
|
//and enemies
|
||||||
level.putGoomba(22, 12);
|
level.putGoomba(22, 12);
|
||||||
level.putGoomba(40, 12);
|
level.putGoomba(40, 12);
|
||||||
level.putGoomba(50, 12);
|
level.putGoomba(50, 12);
|
||||||
level.putGoomba(51, 12);
|
level.putGoomba(51, 12);
|
||||||
level.putGoomba(82, 4);
|
level.putGoomba(82, 4);
|
||||||
level.putGoomba(84, 4);
|
level.putGoomba(84, 4);
|
||||||
level.putGoomba(100, 12);
|
level.putGoomba(100, 12);
|
||||||
level.putGoomba(102, 12);
|
level.putGoomba(102, 12);
|
||||||
level.putGoomba(114, 12);
|
level.putGoomba(114, 12);
|
||||||
level.putGoomba(115, 12);
|
level.putGoomba(115, 12);
|
||||||
level.putGoomba(122, 12);
|
level.putGoomba(122, 12);
|
||||||
level.putGoomba(123, 12);
|
level.putGoomba(123, 12);
|
||||||
level.putGoomba(125, 12);
|
level.putGoomba(125, 12);
|
||||||
level.putGoomba(126, 12);
|
level.putGoomba(126, 12);
|
||||||
level.putGoomba(170, 12);
|
level.putGoomba(170, 12);
|
||||||
level.putGoomba(172, 12);
|
level.putGoomba(172, 12);
|
||||||
level.putKoopa(35, 11);
|
level.putKoopa(35, 11);
|
||||||
|
|
||||||
music.underground.pause();
|
music.underground.pause();
|
||||||
// music.overworld.currentTime = 0;
|
// music.overworld.currentTime = 0;
|
||||||
music.overworld.play();
|
music.overworld.play();
|
||||||
};
|
});
|
||||||
|
|||||||
@@ -1,65 +1,138 @@
|
|||||||
var oneonetunnel = Mario.oneonetunnel = function() {
|
var oneonetunnel = (Mario.oneonetunnel = function () {
|
||||||
level = new Mario.Level({
|
level = new Mario.Level({
|
||||||
playerPos: [40,16],
|
playerPos: [40, 16],
|
||||||
loader: Mario.oneonetunnel,
|
loader: Mario.oneonetunnel,
|
||||||
background: "#000000",
|
background: "#000000",
|
||||||
scrolling: false,
|
scrolling: false,
|
||||||
coinSprite: function() {
|
coinSprite: function () {
|
||||||
return new Mario.Sprite('sprites/items.png', [0,96],[16,16], 6,[0,0,0,0,1,2,1]);
|
return new Mario.Sprite(
|
||||||
},
|
"sprites/items.png",
|
||||||
floorSprite: new Mario.Sprite('sprites/tiles.png', [0,32],[16,16],0),
|
[0, 96],
|
||||||
wallSprite: new Mario.Sprite('sprites/tiles.png', [32, 32],[16,16],0),
|
[16, 16],
|
||||||
brickSprite: new Mario.Sprite('sprites/tiles.png', [16, 0], [16,16], 0),
|
6,
|
||||||
brickBounceSprite: new Mario.Sprite('sprites/tiles.png',[32,0],[16,16],0),
|
[0, 0, 0, 0, 1, 2, 1],
|
||||||
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),
|
floorSprite: new Mario.Sprite(
|
||||||
pipeLEndSprite: new Mario.Sprite('sprites/tiles.png', [0, 128], [16,16], 0),
|
"sprites/tiles.png",
|
||||||
pipeREndSprite: new Mario.Sprite('sprites/tiles.png', [16, 128], [16,16], 0),
|
[0, 32],
|
||||||
pipeUpMid: new Mario.Sprite('sprites/tiles.png', [0, 144], [32,16], 0),
|
[16, 16],
|
||||||
pipeSideMid: new Mario.Sprite('sprites/tiles.png', [48, 128], [16,32], 0),
|
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),
|
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:[
|
LPipeSprites: [
|
||||||
new Mario.Sprite('sprites/tiles.png', [32,128],[16,16],0),
|
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", [32, 144], [16, 16], 0),
|
||||||
new Mario.Sprite('sprites/tiles.png', [48,128],[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", [48, 144], [16, 16], 0),
|
||||||
new Mario.Sprite('sprites/tiles.png', [64,128],[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),
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
player.pos[0] = level.playerPos[0];
|
coins = [
|
||||||
player.pos[1] = level.playerPos[1];
|
[5, 5],
|
||||||
vX = 0;
|
[6, 5],
|
||||||
level.putFloor(0,16);
|
[7, 5],
|
||||||
level.putWall(0,13,11);
|
[8, 5],
|
||||||
walls = [4,5,6,7,8,9,10];
|
[9, 5],
|
||||||
walls.forEach(function(loc){
|
[4, 7],
|
||||||
level.putWall(loc,13,3);
|
[5, 7],
|
||||||
level.putWall(loc,3,1);
|
[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],
|
//level.putLeftPipe(13,11);
|
||||||
[4,7], [5,7], [6,7], [7,7], [8,7], [9,7], [10,7],
|
level.putRealPipe(13, 11, 3, "RIGHT", function () {
|
||||||
[4,9], [5,9], [6,9], [7,9], [8,9], [9,9], [10,9]];
|
Mario.oneone.call();
|
||||||
coins.forEach(function(pos){
|
player.pos = [2616, 177];
|
||||||
level.putCoin(pos[0],pos[1]);
|
player.pipe("UP", function () {});
|
||||||
});
|
});
|
||||||
|
|
||||||
//level.putLeftPipe(13,11);
|
level.putPipe(15, 13, 13);
|
||||||
level.putRealPipe(13,11,3,"RIGHT", function() {
|
|
||||||
Mario.oneone.call();
|
|
||||||
player.pos = [2616, 177]
|
|
||||||
player.pipe("UP", function() {;});
|
|
||||||
});
|
|
||||||
|
|
||||||
level.putPipe(15,13,13);
|
music.overworld.pause();
|
||||||
|
music.underground.currentTime = 0;
|
||||||
music.overworld.pause();
|
music.underground.play();
|
||||||
music.underground.currentTime = 0;
|
});
|
||||||
music.underground.play();
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -1,218 +1,348 @@
|
|||||||
(function() {
|
(function () {
|
||||||
var Level = Mario.Level = function(options) {
|
var Level = (Mario.Level = function (options) {
|
||||||
this.playerPos = options.playerPos;
|
this.playerPos = options.playerPos;
|
||||||
this.scrolling = options.scrolling;
|
this.scrolling = options.scrolling;
|
||||||
this.loader = options.loader;
|
this.loader = options.loader;
|
||||||
this.background = options.background;
|
this.background = options.background;
|
||||||
this.exit = options.exit;
|
this.exit = options.exit;
|
||||||
|
|
||||||
this.floorSprite = options.floorSprite;
|
this.floorSprite = options.floorSprite;
|
||||||
this.cloudSprite = options.cloudSprite;
|
this.cloudSprite = options.cloudSprite;
|
||||||
this.wallSprite = options.wallSprite;
|
this.wallSprite = options.wallSprite;
|
||||||
this.brickSprite = options.brickSprite;
|
this.brickSprite = options.brickSprite;
|
||||||
this.rubbleSprite = options.rubbleSprite;
|
this.rubbleSprite = options.rubbleSprite;
|
||||||
this.brickBounceSprite = options.brickBounceSprite;
|
this.brickBounceSprite = options.brickBounceSprite;
|
||||||
this.ublockSprite = options.ublockSprite;
|
this.ublockSprite = options.ublockSprite;
|
||||||
this.superShroomSprite = options.superShroomSprite;
|
this.superShroomSprite = options.superShroomSprite;
|
||||||
this.fireFlowerSprite = options.fireFlowerSprite;
|
this.fireFlowerSprite = options.fireFlowerSprite;
|
||||||
this.starSprite = options.starSprite;
|
this.starSprite = options.starSprite;
|
||||||
this.coinSprite = options.coinSprite;
|
this.coinSprite = options.coinSprite;
|
||||||
this.bcoinSprite = options.bcoinSprite;
|
this.bcoinSprite = options.bcoinSprite;
|
||||||
this.goombaSprite = options.goombaSprite;
|
this.goombaSprite = options.goombaSprite;
|
||||||
this.koopaSprite = options.koopaSprite;
|
this.koopaSprite = options.koopaSprite;
|
||||||
|
|
||||||
//prop pipe sprites, to be phased out
|
//prop pipe sprites, to be phased out
|
||||||
this.pipeLEndSprite = options.pipeLEndSprite;
|
this.pipeLEndSprite = options.pipeLEndSprite;
|
||||||
this.pipeREndSprite = options.pipeREndSprite;
|
this.pipeREndSprite = options.pipeREndSprite;
|
||||||
this.pipeLMidSprite = options.pipeLMidSprite;
|
this.pipeLMidSprite = options.pipeLMidSprite;
|
||||||
this.pipeRMidSprite = options.pipeRMidSprite;
|
this.pipeRMidSprite = options.pipeRMidSprite;
|
||||||
|
|
||||||
//real pipe sprites, use these.
|
//real pipe sprites, use these.
|
||||||
this.pipeUpMid = options.pipeUpMid;
|
this.pipeUpMid = options.pipeUpMid;
|
||||||
this.pipeSideMid = options.pipeSideMid;
|
this.pipeSideMid = options.pipeSideMid;
|
||||||
this.pipeLeft = options.pipeLeft;
|
this.pipeLeft = options.pipeLeft;
|
||||||
this.pipeTop = options.pipeTop;
|
this.pipeTop = options.pipeTop;
|
||||||
|
|
||||||
this.flagpoleSprites = options.flagPoleSprites;
|
this.flagpoleSprites = options.flagPoleSprites;
|
||||||
|
|
||||||
this.LPipeSprites = options.LPipeSprites;
|
this.LPipeSprites = options.LPipeSprites;
|
||||||
this.cloudSprites = options.cloudSprites;
|
this.cloudSprites = options.cloudSprites;
|
||||||
this.hillSprites = options.hillSprites;
|
this.hillSprites = options.hillSprites;
|
||||||
this.bushSprite = options.bushSprite;
|
this.bushSprite = options.bushSprite;
|
||||||
this.bushSprites = options.bushSprites;
|
this.bushSprites = options.bushSprites;
|
||||||
this.qblockSprite = options.qblockSprite;
|
this.qblockSprite = options.qblockSprite;
|
||||||
|
|
||||||
this.invincibility = options.invincibility;
|
this.invincibility = options.invincibility;
|
||||||
this.statics = [];
|
this.statics = [];
|
||||||
this.scenery = [];
|
this.scenery = [];
|
||||||
this.blocks = [];
|
this.blocks = [];
|
||||||
this.enemies = [];
|
this.enemies = [];
|
||||||
this.items = [];
|
this.items = [];
|
||||||
this.pipes = [];
|
this.pipes = [];
|
||||||
|
|
||||||
for (var i = 0; i < 15; i++) {
|
for (var i = 0; i < 15; i++) {
|
||||||
this.statics[i] = [];
|
this.statics[i] = [];
|
||||||
this.scenery[i] = [];
|
this.scenery[i] = [];
|
||||||
this.blocks[i] = [];
|
this.blocks[i] = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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.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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//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.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.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
|
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
Level.prototype.putBrick = function(x,y,item) {
|
Level.prototype.putFloor = function (start, end) {
|
||||||
this.blocks[y][x] = new Mario.Block({
|
for (var i = start; i < end; i++) {
|
||||||
pos: [x*16, y*16],
|
this.statics[13][i] = new Mario.Floor(
|
||||||
item: item,
|
[16 * i, 208],
|
||||||
sprite: this.brickSprite,
|
this.floorSprite,
|
||||||
bounceSprite: this.brickBounceSprite,
|
);
|
||||||
usedSprite: this.ublockSprite,
|
this.statics[14][i] = new Mario.Floor(
|
||||||
breakable: !item
|
[16 * i, 224],
|
||||||
});
|
this.floorSprite,
|
||||||
};
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Level.prototype.putBigHill = function(x, y) {
|
Level.prototype.putGoomba = function (x, y) {
|
||||||
var px = x*16, py = y*16;
|
this.enemies.push(
|
||||||
this.scenery[y][x] = new Mario.Prop([px, py], this.hillSprites[0]);
|
new Mario.Goomba([16 * x, 16 * y], this.goombaSprite()),
|
||||||
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) {
|
Level.prototype.putKoopa = function (x, y) {
|
||||||
this.scenery[y][x] = new Mario.Prop([x*16, y*16], this.bushSprite);
|
this.enemies.push(
|
||||||
};
|
new Mario.Koopa([16 * x, 16 * y], this.koopaSprite(), false),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
Level.prototype.putThreeBush = function(x,y) {
|
Level.prototype.putWall = function (x, y, height) {
|
||||||
px = x*16;
|
//y is the bottom of the wall in this case.
|
||||||
py = y*16;
|
for (var i = y - height; i < y; i++) {
|
||||||
this.scenery[y][x] = new Mario.Prop([px, py], this.bushSprites[0]);
|
this.statics[i][x] = new Mario.Floor(
|
||||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.bushSprites[1]);
|
[16 * x, 16 * i],
|
||||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.bushSprites[1]);
|
this.wallSprite,
|
||||||
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) {
|
Level.prototype.putPipe = function (x, y, height) {
|
||||||
px = x*16;
|
for (var i = y - height; i < y; i++) {
|
||||||
py = y*16;
|
if (i === y - height) {
|
||||||
this.scenery[y][x] = new Mario.Prop([px, py], this.bushSprites[0]);
|
this.statics[i][x] = new Mario.Floor(
|
||||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.bushSprites[1]);
|
[16 * x, 16 * i],
|
||||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.bushSprites[1]);
|
this.pipeLEndSprite,
|
||||||
this.scenery[y][x+3] = new Mario.Prop([px+48, py], this.bushSprites[2]);
|
);
|
||||||
};
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Level.prototype.putSmallHill = function(x, y) {
|
//sometimes, pipes don't go straight up and down.
|
||||||
var px = x*16, py = y*16;
|
Level.prototype.putLeftPipe = function (x, y) {
|
||||||
this.scenery[y][x] = new Mario.Prop([px, py], this.hillSprites[0]);
|
this.statics[y][x] = new Mario.Floor(
|
||||||
this.scenery[y][x+1] = new Mario.Prop([px+16, py], this.hillSprites[3]);
|
[16 * x, 16 * y],
|
||||||
this.scenery[y-1][x+1] = new Mario.Prop([px+16, py-16], this.hillSprites[1]);
|
this.LPipeSprites[0],
|
||||||
this.scenery[y][x+2] = new Mario.Prop([px+32, py], this.hillSprites[2]);
|
);
|
||||||
};
|
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.putTwoCloud = function(x,y) {
|
Level.prototype.putCoin = function (x, y) {
|
||||||
px = x*16;
|
this.items.push(new Mario.Coin([x * 16, y * 16], this.coinSprite()));
|
||||||
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]);
|
|
||||||
};
|
|
||||||
|
|
||||||
Level.prototype.putThreeCloud = function(x,y) {
|
Level.prototype.putCloud = function (x, y) {
|
||||||
px = x*16;
|
this.scenery[y][x] = new Mario.Prop([x * 16, y * 16], this.cloudSprite);
|
||||||
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]);
|
|
||||||
};
|
|
||||||
|
|
||||||
Level.prototype.putRealPipe = function(x, y, length, direction, destination) {
|
Level.prototype.putQBlock = function (x, y, item) {
|
||||||
px = x*16;
|
this.blocks[y][x] = new Mario.Block({
|
||||||
py = y*16;
|
pos: [x * 16, y * 16],
|
||||||
this.pipes.push(new Mario.Pipe({
|
item: item,
|
||||||
pos: [px, py],
|
sprite: this.qblockSprite,
|
||||||
length: length,
|
usedSprite: this.ublockSprite,
|
||||||
direction: direction,
|
});
|
||||||
destination: destination
|
};
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
Level.prototype.putFlagpole = function(x) {
|
Level.prototype.putBrick = function (x, y, item) {
|
||||||
this.statics[12][x] = new Mario.Floor([16*x, 192], this.wallSprite);
|
this.blocks[y][x] = new Mario.Block({
|
||||||
for (i=3; i < 12; i++) {
|
pos: [x * 16, y * 16],
|
||||||
this.scenery[i][x] = new Mario.Prop([16*x, 16*i], this.flagpoleSprites[1])
|
item: item,
|
||||||
}
|
sprite: this.brickSprite,
|
||||||
this.scenery[2][x] = new Mario.Prop([16*x, 32], this.flagpoleSprites[0]);
|
bounceSprite: this.brickBounceSprite,
|
||||||
this.items.push(new Mario.Flag(16*x));
|
usedSprite: this.ublockSprite,
|
||||||
}
|
breakable: !item,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
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],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
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],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.scenery[2][x] = new Mario.Prop(
|
||||||
|
[16 * x, 32],
|
||||||
|
this.flagpoleSprites[0],
|
||||||
|
);
|
||||||
|
this.items.push(new Mario.Flag(16 * x));
|
||||||
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,118 +1,132 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
window.Mario = {};
|
|
||||||
|
|
||||||
var Mushroom = Mario.Mushroom = function(pos) {
|
var Mushroom = (Mario.Mushroom = function (pos) {
|
||||||
this.spawning = false;
|
this.spawning = false;
|
||||||
this.waiting = 0;
|
this.waiting = 0;
|
||||||
|
|
||||||
Mario.Entity.call(this, {
|
Mario.Entity.call(this, {
|
||||||
pos: pos,
|
pos: pos,
|
||||||
sprite: level.superShroomSprite,
|
sprite: level.superShroomSprite,
|
||||||
hitbox: [0,0,16,16]
|
hitbox: [0, 0, 16, 16],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
Mario.Util.inherits(Mushroom, Mario.Entity);
|
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;
|
if (this.spawning > 1) return;
|
||||||
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
this.sprite.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
||||||
}
|
};
|
||||||
|
|
||||||
Mushroom.prototype.spawn = function() {
|
Mushroom.prototype.spawn = function () {
|
||||||
if (player.power > 0) {
|
if (player.power > 0) {
|
||||||
//replace this with a fire flower
|
//replace this with a fire flower
|
||||||
var ff = new Mario.Fireflower(this.pos)
|
var ff = new Mario.Fireflower(this.pos);
|
||||||
ff.spawn();
|
ff.spawn();
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
sounds.itemAppear.play();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Mushroom.prototype.update = function(dt) {
|
|
||||||
if (this.spawning > 1) {
|
|
||||||
this.spawning -= 1;
|
|
||||||
if (this.spawning == 1) this.vel[1] = -.5;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.spawning) {
|
|
||||||
if (this.pos[1] <= this.targetpos[1]) {
|
|
||||||
this.pos[1] = this.targetpos[1];
|
|
||||||
this.vel[1] = 0;
|
|
||||||
this.waiting = 5;
|
|
||||||
this.spawning = 0;
|
|
||||||
this.vel[0] = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.acc[1] = 0.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.waiting) {
|
|
||||||
this.waiting -= 1;
|
|
||||||
} else {
|
|
||||||
this.vel[1] += this.acc[1];
|
|
||||||
this.pos[0] += this.vel[0];
|
|
||||||
this.pos[1] += this.vel[1];
|
|
||||||
this.sprite.update(dt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Mushroom.prototype.collideWall = function() {
|
|
||||||
this.vel[0] = -this.vel[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
Mushroom.prototype.checkCollisions = function() {
|
|
||||||
if(this.spawning) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var h = this.pos[1] % 16 == 0 ? 1 : 2;
|
|
||||||
var w = this.pos[0] % 16 == 0 ? 1 : 2;
|
|
||||||
|
|
||||||
var baseX = Math.floor(this.pos[0] / 16);
|
|
||||||
var baseY = Math.floor(this.pos[1] / 16);
|
|
||||||
|
|
||||||
if (baseY + h > 15) {
|
|
||||||
delete level.items[this.idx];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < h; i++) {
|
|
||||||
for (var j = 0; j < w; j++) {
|
|
||||||
if (level.statics[baseY + i][baseX + j]) {
|
|
||||||
level.statics[baseY + i][baseX + j].isCollideWith(this);
|
|
||||||
}
|
}
|
||||||
if (level.blocks[baseY + i][baseX + j]) {
|
sounds.itemAppear.play();
|
||||||
level.blocks[baseY + i][baseX + j].isCollideWith(this);
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
Mushroom.prototype.update = function (dt) {
|
||||||
|
if (this.spawning > 1) {
|
||||||
|
this.spawning -= 1;
|
||||||
|
if (this.spawning == 1) this.vel[1] = -0.5;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.spawning) {
|
||||||
|
if (this.pos[1] <= this.targetpos[1]) {
|
||||||
|
this.pos[1] = this.targetpos[1];
|
||||||
|
this.vel[1] = 0;
|
||||||
|
this.waiting = 5;
|
||||||
|
this.spawning = 0;
|
||||||
|
this.vel[0] = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.acc[1] = 0.2;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isPlayerCollided();
|
if (this.waiting) {
|
||||||
}
|
this.waiting -= 1;
|
||||||
|
} else {
|
||||||
|
this.vel[1] += this.acc[1];
|
||||||
|
this.pos[0] += this.vel[0];
|
||||||
|
this.pos[1] += this.vel[1];
|
||||||
|
this.sprite.update(dt);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//we have access to player everywhere, so let's just do this.
|
Mushroom.prototype.collideWall = function () {
|
||||||
Mushroom.prototype.isPlayerCollided = function() {
|
this.vel[0] = -this.vel[0];
|
||||||
//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]];
|
|
||||||
|
|
||||||
//if the hitboxes actually overlap
|
Mushroom.prototype.checkCollisions = function () {
|
||||||
if (!(hpos1[0] > hpos2[0]+player.hitbox[2] || (hpos1[0]+this.hitbox[2] < hpos2[0]))) {
|
if (this.spawning) {
|
||||||
if (!(hpos1[1] > hpos2[1]+player.hitbox[3] || (hpos1[1]+this.hitbox[3] < hpos2[1]))) {
|
return;
|
||||||
player.powerUp(this.idx);
|
}
|
||||||
}
|
var h = this.pos[1] % 16 == 0 ? 1 : 2;
|
||||||
}
|
var w = this.pos[0] % 16 == 0 ? 1 : 2;
|
||||||
}
|
|
||||||
|
|
||||||
Mushroom.prototype.bump = function() {
|
var baseX = Math.floor(this.pos[0] / 16);
|
||||||
this.vel[1] = -2;
|
var baseY = Math.floor(this.pos[1] / 16);
|
||||||
}
|
|
||||||
|
|
||||||
|
if (baseY + h > 15) {
|
||||||
|
delete level.items[this.idx];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < h; i++) {
|
||||||
|
for (var j = 0; j < w; j++) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isPlayerCollided();
|
||||||
|
};
|
||||||
|
|
||||||
|
//we have access to player everywhere, so let's just do this.
|
||||||
|
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],
|
||||||
|
];
|
||||||
|
|
||||||
|
//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]
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
player.powerUp(this.idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Mushroom.prototype.bump = function () {
|
||||||
|
this.vel[1] = -2;
|
||||||
|
};
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,160 +1,228 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
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;
|
||||||
|
|
||||||
//there are too many possible configurations of pipe to capture in a reasonable
|
//NOTE: direction is the direction you move INTO the pipe.
|
||||||
//set of simple variables. Joints, etc. are just too much.
|
this.direction = options.direction;
|
||||||
//To that end, the pipe class handles simple pipes, and we'll put together
|
this.destination = options.destination;
|
||||||
//anything more complex with individual props. OK? OK.
|
this.length = options.length;
|
||||||
Pipe = Mario.Pipe = function(options) {
|
|
||||||
this.pos = options.pos
|
|
||||||
|
|
||||||
//NOTE: direction is the direction you move INTO the pipe.
|
if (this.direction === "UP" || this.direction === "DOWN") {
|
||||||
this.direction = options.direction
|
this.hitbox = [0, 0, 32, this.length * 16];
|
||||||
this.destination = options.destination
|
this.midsection = level.pipeUpMid;
|
||||||
this.length = options.length;
|
this.endsection = level.pipeTop;
|
||||||
|
|
||||||
if (this.direction === "UP" || this.direction === "DOWN") {
|
|
||||||
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.midsection = level.pipeSideMid;
|
|
||||||
this.endsection = level.pipeLeft;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Pipe.prototype.checkPipe = function() {
|
|
||||||
if (this.destination === undefined || !input.isDown(this.direction)) return;
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
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() {
|
|
||||||
var that = this;
|
|
||||||
level.enemies.forEach (function(ent) {
|
|
||||||
that.isCollideWith(ent);
|
|
||||||
});
|
|
||||||
|
|
||||||
level.items.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])];
|
|
||||||
|
|
||||||
//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 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]) {
|
|
||||||
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) {
|
|
||||||
ent.jumping = 0;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
//entity is hitting it from the side, we're a wall
|
this.hitbox = [0, 0, 16 * this.length, 32];
|
||||||
ent.collideWall(this);
|
this.midsection = level.pipeSideMid;
|
||||||
|
this.endsection = level.pipeLeft;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//we COULD try to write some shenanigans so that the check gets put into the
|
Pipe.prototype.checkPipe = function () {
|
||||||
//collision code, but there won't ever be more than a handful of pipes in a level
|
if (this.destination === undefined || !input.isDown(this.direction))
|
||||||
//so the performance hit of scanning all of them is miniscule.
|
return;
|
||||||
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
|
var h = player.power === 0 ? 16 : 32;
|
||||||
//I honestly have no idea if javascript does this, but I feel like it makes sense
|
var x = Math.floor(player.pos[0]);
|
||||||
//stylistically to prefer branching outside of loops when possible as convention
|
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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//TODO: edit the spritesheet so UP and LEFT pipes aren't backwards.
|
//Note to self: next time, decide on a convention for which thing checks for collisions
|
||||||
Pipe.prototype.render = function(ctx, vX, vY) {
|
//and stick to it. This is a pain.
|
||||||
switch (this.direction) {
|
Pipe.prototype.checkCollisions = function () {
|
||||||
case "DOWN":
|
var that = this;
|
||||||
this.endsection.render(ctx, this.pos[0], this.pos[1], vX, vY);
|
level.enemies.forEach(function (ent) {
|
||||||
for (var i = 1; i < this.length; i++) {
|
that.isCollideWith(ent);
|
||||||
this.midsection.render(ctx, this.pos[0], this.pos[1]+i*16, vX, vY)
|
});
|
||||||
|
|
||||||
|
level.items.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]),
|
||||||
|
];
|
||||||
|
|
||||||
|
//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 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]
|
||||||
|
) {
|
||||||
|
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) {
|
||||||
|
ent.jumping = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//entity is hitting it from the side, we're a wall
|
||||||
|
ent.collideWall(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
};
|
||||||
case "UP":
|
|
||||||
this.endsection.render(ctx, this.pos[0], this.pos[1]+16*(this.length-1), vX, vY)
|
//we COULD try to write some shenanigans so that the check gets put into the
|
||||||
for (var i=0; i < this.length - 1; i++) {
|
//collision code, but there won't ever be more than a handful of pipes in a level
|
||||||
this.midsection.render(ctx, this.pos[0], this.pos[1]+i*16, vX, vY)
|
//so the performance hit of scanning all of them is miniscule.
|
||||||
|
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) {
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "RIGHT":
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
};
|
||||||
case "RIGHT":
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,446 +1,505 @@
|
|||||||
(function() {
|
(function () {
|
||||||
if (typeof Mario === 'undefined')
|
if (typeof Mario === "undefined") window.Mario = {};
|
||||||
window.Mario = {};
|
|
||||||
|
|
||||||
var Player = Mario.Player = function(pos) {
|
var Player = (Mario.Player = function (pos) {
|
||||||
//I know, I know, there are a lot of variables tracking Mario's state.
|
//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.
|
//Maybe these can be consolidated some way? We'll see once they're all in.
|
||||||
this.power = 0;
|
this.power = 0;
|
||||||
this.coins = 0;
|
this.coins = 0;
|
||||||
this.powering = [];
|
this.powering = [];
|
||||||
this.bounce = false;
|
this.bounce = false;
|
||||||
this.jumping = 0;
|
this.jumping = 0;
|
||||||
this.canJump = true;
|
this.canJump = true;
|
||||||
this.invincibility = 0;
|
this.invincibility = 0;
|
||||||
this.crouching = false;
|
this.crouching = false;
|
||||||
this.fireballs = 0;
|
this.fireballs = 0;
|
||||||
this.runheld = false;
|
this.runheld = false;
|
||||||
this.noInput = false;
|
this.noInput = false;
|
||||||
this.targetPos = [];
|
this.targetPos = [];
|
||||||
|
|
||||||
Mario.Entity.call(this, {
|
Mario.Entity.call(this, {
|
||||||
pos: pos,
|
pos: pos,
|
||||||
sprite: new Mario.Sprite('sprites/player.png', [80,32],[16,16],0),
|
sprite: new Mario.Sprite(
|
||||||
hitbox: [0,0,16,16]
|
"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() {
|
Player.prototype.run = function () {
|
||||||
this.maxSpeed = 2.5;
|
this.maxSpeed = 2.5;
|
||||||
if (this.power == 2 && !this.runheld) {
|
if (this.power == 2 && !this.runheld) {
|
||||||
this.shoot();
|
this.shoot();
|
||||||
}
|
}
|
||||||
this.runheld = true;
|
this.runheld = true;
|
||||||
}
|
};
|
||||||
|
|
||||||
Player.prototype.shoot = function() {
|
Player.prototype.shoot = function () {
|
||||||
if (this.fireballs >= 2) return; //Projectile limit!
|
if (this.fireballs >= 2) return; //Projectile limit!
|
||||||
this.fireballs += 1;
|
this.fireballs += 1;
|
||||||
var fb = new Mario.Fireball([this.pos[0]+8,this.pos[1]]); //I hate you, Javascript.
|
var fb = new Mario.Fireball([this.pos[0] + 8, this.pos[1]]); //I hate you, Javascript.
|
||||||
fb.spawn(this.left);
|
fb.spawn(this.left);
|
||||||
this.shooting = 2;
|
this.shooting = 2;
|
||||||
}
|
};
|
||||||
|
|
||||||
Player.prototype.noRun = function() {
|
Player.prototype.noRun = function () {
|
||||||
this.maxSpeed = 1.5;
|
this.maxSpeed = 1.5;
|
||||||
this.moveAcc = 0.07;
|
this.moveAcc = 0.07;
|
||||||
this.runheld = false;
|
this.runheld = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
Player.prototype.moveRight = function() {
|
Player.prototype.moveRight = function () {
|
||||||
//we're on the ground
|
//we're on the ground
|
||||||
if (this.vel[1] === 0 && this.standing) {
|
if (this.vel[1] === 0 && this.standing) {
|
||||||
if (this.crouching) {
|
if (this.crouching) {
|
||||||
this.noWalk();
|
this.noWalk();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.acc[0] = this.moveAcc;
|
this.acc[0] = this.moveAcc;
|
||||||
this.left = false;
|
this.left = false;
|
||||||
} else {
|
} else {
|
||||||
this.acc[0] = this.moveAcc;
|
this.acc[0] = this.moveAcc;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Player.prototype.moveLeft = function() {
|
Player.prototype.moveLeft = function () {
|
||||||
if (this.vel[1] === 0 && this.standing) {
|
if (this.vel[1] === 0 && this.standing) {
|
||||||
if (this.crouching) {
|
if (this.crouching) {
|
||||||
this.noWalk();
|
this.noWalk();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.acc[0] = -this.moveAcc;
|
this.acc[0] = -this.moveAcc;
|
||||||
this.left = true;
|
this.left = true;
|
||||||
} else {
|
} else {
|
||||||
this.acc[0] = -this.moveAcc;
|
this.acc[0] = -this.moveAcc;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Player.prototype.noWalk = function() {
|
Player.prototype.noWalk = function () {
|
||||||
this.maxSpeed = 0;
|
this.maxSpeed = 0;
|
||||||
if (this.vel[0] === 0) return;
|
if (this.vel[0] === 0) return;
|
||||||
|
|
||||||
if (Math.abs(this.vel[0]) <= 0.1) {
|
if (Math.abs(this.vel[0]) <= 0.1) {
|
||||||
this.vel[0] = 0;
|
this.vel[0] = 0;
|
||||||
this.acc[0] = 0;
|
this.acc[0] = 0;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
};
|
Player.prototype.crouch = function () {
|
||||||
|
if (this.power === 0) {
|
||||||
|
this.crouching = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Player.prototype.crouch = function() {
|
if (this.standing) this.crouching = true;
|
||||||
if (this.power === 0) {
|
};
|
||||||
this.crouching = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.standing) this.crouching = true;
|
Player.prototype.noCrouch = function () {
|
||||||
}
|
this.crouching = false;
|
||||||
|
};
|
||||||
|
|
||||||
Player.prototype.noCrouch = function() {
|
Player.prototype.jump = function () {
|
||||||
this.crouching = false;
|
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.jump = function() {
|
Player.prototype.noJump = function () {
|
||||||
if (this.vel[1] > 0) {
|
this.canJump = true;
|
||||||
return;
|
if (this.jumping) {
|
||||||
}
|
if (this.jumping <= 16) {
|
||||||
if (this.jumping) {
|
this.vel[1] = 0;
|
||||||
this.jumping -= 1;
|
this.jumping = 0;
|
||||||
} else if (this.standing && this.canJump) {
|
} else this.jumping -= 1;
|
||||||
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() {
|
Player.prototype.setAnimation = function () {
|
||||||
this.canJump = true;
|
if (this.dying) return;
|
||||||
if (this.jumping) {
|
|
||||||
if (this.jumping <= 16) {
|
|
||||||
this.vel[1] = 0;
|
|
||||||
this.jumping = 0;
|
|
||||||
} else this.jumping -= 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Player.prototype.setAnimation = function() {
|
if (this.starTime) {
|
||||||
if (this.dying) return;
|
var index;
|
||||||
|
if (this.starTime > 60) index = Math.floor(this.starTime / 2) % 3;
|
||||||
|
else index = Math.floor(this.starTime / 8) % 3;
|
||||||
|
|
||||||
if (this.starTime) {
|
this.sprite.pos[1] = level.invincibility[index];
|
||||||
var index;
|
if (this.power == 0) {
|
||||||
if (this.starTime > 60)
|
this.sprite.pos[1] += 32;
|
||||||
index = Math.floor(this.starTime / 2) % 3;
|
}
|
||||||
else index = Math.floor(this.starTime / 8) % 3;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
this.sprite.pos[1] = level.invincibility[index];
|
if (this.jumping) {
|
||||||
if (this.power == 0) {
|
this.sprite.pos[0] = 160;
|
||||||
this.sprite.pos[1] += 32;
|
this.sprite.speed = 0;
|
||||||
}
|
} else if (this.standing) {
|
||||||
this.starTime -= 1;
|
if (Math.abs(this.vel[0]) > 0) {
|
||||||
if (this.starTime == 0) {
|
if (this.vel[0] * this.acc[0] >= 0) {
|
||||||
switch(this.power) {
|
this.sprite.pos[0] = 96;
|
||||||
case 0: this.sprite.pos[1] = 32; break;
|
this.sprite.frames = [0, 1, 2];
|
||||||
case 1: this.sprite.pos[1] = 0; break;
|
if (this.vel[0] < 0.2) {
|
||||||
case 2: this.sprite.pos[1] = 96; break;
|
this.sprite.speed = 5;
|
||||||
}
|
} else {
|
||||||
}
|
this.sprite.speed = Math.abs(this.vel[0]) * 8;
|
||||||
}
|
}
|
||||||
//okay cool, now set the sprite
|
} else if (
|
||||||
if (this.crouching) {
|
(this.vel[0] > 0 && this.left) ||
|
||||||
this.sprite.pos[0] = 176;
|
(this.vel[0] < 0 && !this.left)
|
||||||
this.sprite.speed = 0;
|
) {
|
||||||
return;
|
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.jumping) {
|
if (this.flagging) {
|
||||||
this.sprite.pos[0] = 160;
|
this.sprite.pos[0] = 192;
|
||||||
this.sprite.speed = 0;
|
this.sprite.frames = [0, 1];
|
||||||
} else if (this.standing) {
|
this.sprite.speed = 10;
|
||||||
if (Math.abs(this.vel[0]) > 0) {
|
if (this.vel[1] === 0) this.sprite.frames = [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) {
|
//which way are we facing?
|
||||||
this.sprite.pos[0] = 192;
|
if (this.left) {
|
||||||
this.sprite.frames = [0,1];
|
this.sprite.img = "sprites/playerl.png";
|
||||||
this.sprite.speed = 10;
|
} else {
|
||||||
if (this.vel[1] === 0) this.sprite.frames = [0];
|
this.sprite.img = "sprites/player.png";
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//which way are we facing?
|
Player.prototype.update = function (dt, vX) {
|
||||||
if (this.left) {
|
if (this.powering.length !== 0) {
|
||||||
this.sprite.img = 'sprites/playerl.png';
|
var next = this.powering.shift();
|
||||||
} else {
|
if (next == 5) return;
|
||||||
this.sprite.img = 'sprites/player.png';
|
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.update = function(dt, vX) {
|
if (this.invincibility) {
|
||||||
if (this.powering.length !== 0) {
|
this.invincibility -= Math.round(dt * 60);
|
||||||
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) {
|
if (this.waiting) {
|
||||||
this.invincibility -= Math.round(dt * 60);
|
this.waiting -= dt;
|
||||||
}
|
if (this.waiting <= 0) {
|
||||||
|
this.waiting = 0;
|
||||||
|
} else return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.waiting) {
|
if (this.bounce) {
|
||||||
this.waiting -= dt;
|
this.bounce = false;
|
||||||
if (this.waiting <= 0) {
|
this.standing = false;
|
||||||
this.waiting = 0;
|
this.vel[1] = -3;
|
||||||
} else return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (this.bounce) {
|
if (this.pos[0] <= vX) {
|
||||||
this.bounce = false;
|
this.pos[0] = vX;
|
||||||
this.standing = false;
|
this.vel[0] = Math.max(this.vel[0], 0);
|
||||||
this.vel[1] = -3;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (this.pos[0] <= vX) {
|
if (Math.abs(this.vel[0]) > this.maxSpeed) {
|
||||||
this.pos[0] = vX;
|
this.vel[0] -= (0.05 * this.vel[0]) / Math.abs(this.vel[0]);
|
||||||
this.vel[0] = Math.max(this.vel[0], 0);
|
this.acc[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Math.abs(this.vel[0]) > this.maxSpeed) {
|
if (this.dying) {
|
||||||
this.vel[0] -= 0.05 * this.vel[0] / Math.abs(this.vel[0]);
|
if (this.pos[1] < this.targetPos[1]) {
|
||||||
this.acc[0] = 0;
|
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.dying){
|
if (this.piping) {
|
||||||
if (this.pos[1] < this.targetPos[1]) {
|
this.acc = [0, 0];
|
||||||
this.vel[1] = 1;
|
var pos = [Math.round(this.pos[0]), Math.round(this.pos[1])];
|
||||||
}
|
if (pos[0] === this.targetPos[0] && pos[1] === this.targetPos[1]) {
|
||||||
this.dying -= 1 * dt;
|
this.piping = false;
|
||||||
if (this.dying <= 0) {
|
this.pipeLoc.call();
|
||||||
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) {
|
if (this.flagging) {
|
||||||
this.acc = [0,0];
|
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) {
|
if (this.exiting) {
|
||||||
this.acc = [0,0];
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (this.exiting) {
|
//approximate acceleration
|
||||||
this.left = false;
|
this.vel[0] += this.acc[0];
|
||||||
this.flagging = false;
|
this.vel[1] += this.acc[1];
|
||||||
this.vel[0] = 1.5;
|
this.pos[0] += this.vel[0];
|
||||||
if (this.pos[0] >= this.targetPos[0]) {
|
this.pos[1] += this.vel[1];
|
||||||
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.setAnimation();
|
||||||
this.vel[0] += this.acc[0];
|
this.sprite.update(dt);
|
||||||
this.vel[1] += this.acc[1];
|
};
|
||||||
this.pos[0] += this.vel[0];
|
|
||||||
this.pos[1] += this.vel[1];
|
|
||||||
|
|
||||||
this.setAnimation();
|
Player.prototype.checkCollisions = function () {
|
||||||
this.sprite.update(dt);
|
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() {
|
for (var i = 0; i < h; i++) {
|
||||||
if (this.piping || this.dying) return;
|
if (baseY + i < 0 || baseY + i >= 15) continue;
|
||||||
//x-axis first!
|
for (var j = 0; j < w; j++) {
|
||||||
var h = this.power > 0 ? 2 : 1;
|
if (baseY < 0) {
|
||||||
var w = 1;
|
i++;
|
||||||
if (this.pos[1] % 16 !== 0) {
|
}
|
||||||
h += 1;
|
if (level.statics[baseY + i][baseX + j]) {
|
||||||
}
|
level.statics[baseY + i][baseX + j].isCollideWith(this);
|
||||||
if (this.pos[0] % 16 !== 0) {
|
}
|
||||||
w += 1;
|
if (level.blocks[baseY + i][baseX + j]) {
|
||||||
}
|
level.blocks[baseY + i][baseX + j].isCollideWith(this);
|
||||||
var baseX = Math.floor(this.pos[0] / 16);
|
}
|
||||||
var baseY = Math.floor(this.pos[1] / 16);
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
for (var i = 0; i < h; i++) {
|
Player.prototype.powerUp = function (idx) {
|
||||||
if (baseY + i < 0 || baseY + i >= 15) continue;
|
sounds.powerup.play();
|
||||||
for (var j = 0; j < w; j++) {
|
this.powering = [
|
||||||
if (baseY < 0) { i++;}
|
0, 5, 2, 5, 1, 5, 2, 5, 1, 5, 2, 5, 3, 5, 1, 5, 2, 5, 3, 5, 1, 5, 4,
|
||||||
if (level.statics[baseY + i][baseX + j]) {
|
];
|
||||||
level.statics[baseY + i][baseX + j].isCollideWith(this);
|
this.touchedItem = idx;
|
||||||
}
|
|
||||||
if (level.blocks[baseY + i][baseX + j]) {
|
|
||||||
level.blocks[baseY + i][baseX + j].isCollideWith(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Player.prototype.powerUp = function(idx) {
|
if (this.power === 0) {
|
||||||
sounds.powerup.play();
|
this.sprite.pos[0] = 80;
|
||||||
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];
|
var newy = this.sprite.pos[1] - 32;
|
||||||
this.touchedItem = idx;
|
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) {
|
Player.prototype.damage = function () {
|
||||||
this.sprite.pos[0] = 80;
|
if (this.power === 0) {
|
||||||
var newy = this.sprite.pos[1] - 32;
|
//if you're already small, you dead!
|
||||||
this.powerSprites = [[80, newy+32], [80, newy+32], [320, newy], [80, newy], [128, newy]];
|
this.die();
|
||||||
this.powerSizes = [[16,16],[16,16],[16,32],[16,32],[16,32]];
|
} else {
|
||||||
this.shift = [0,16,-16,0,-16];
|
//otherwise, you get turned into small mario
|
||||||
this.power = 1;
|
sounds.pipe.play();
|
||||||
this.hitbox = [0,0,16,32];
|
this.powering = [
|
||||||
} else if (this.power == 1) {
|
0, 5, 1, 5, 2, 5, 1, 5, 2, 5, 1, 5, 2, 5, 1, 5, 2, 5, 1, 5, 2,
|
||||||
var curx = this.sprite.pos[0];
|
5, 3,
|
||||||
this.powerSprites = [[curx, 96], [curx, level.invincibility[0]],
|
];
|
||||||
[curx, level.invincibility[1]], [curx, level.invincibility[2]],
|
this.shift = [0, 16, -16, 16];
|
||||||
[curx, 96]];
|
this.sprite.pos = [160, 0];
|
||||||
this.powerSizes[[16,32],[16,32],[16,32],[16,32],[16,32]];
|
this.powerSprites = [
|
||||||
this.shift = [0,0,0,0,0];
|
[160, 0],
|
||||||
this.power = 2;
|
[240, 32],
|
||||||
} else {
|
[240, 0],
|
||||||
this.powering = [];
|
[160, 32],
|
||||||
delete level.items[idx];
|
];
|
||||||
//no animation, but we play the sound and you get 5000 points.
|
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() {
|
Player.prototype.die = function () {
|
||||||
if (this.power === 0) { //if you're already small, you dead!
|
//TODO: rewrite the way sounds work to emulate the channels of an NES.
|
||||||
this.die();
|
music.overworld.pause();
|
||||||
} else { //otherwise, you get turned into small mario
|
music.underground.pause();
|
||||||
sounds.pipe.play();
|
music.overworld.currentTime = 0;
|
||||||
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];
|
music.death.play();
|
||||||
this.shift = [0,16,-16,16];
|
this.noWalk();
|
||||||
this.sprite.pos = [160, 0];
|
this.noRun();
|
||||||
this.powerSprites = [[160,0], [240, 32], [240, 0], [160, 32]];
|
this.noJump();
|
||||||
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 () {
|
this.acc[0] = 0;
|
||||||
//TODO: rewrite the way sounds work to emulate the channels of an NES.
|
this.sprite.pos = [176, 32];
|
||||||
music.overworld.pause();
|
this.sprite.speed = 0;
|
||||||
music.underground.pause();
|
this.power = 0;
|
||||||
music.overworld.currentTime = 0;
|
this.waiting = 0.5;
|
||||||
music.death.play();
|
this.dying = 2;
|
||||||
this.noWalk();
|
|
||||||
this.noRun();
|
|
||||||
this.noJump();
|
|
||||||
|
|
||||||
this.acc[0] = 0;
|
if (this.pos[1] < 240) {
|
||||||
this.sprite.pos = [176, 32];
|
//falling into a pit doesn't do the animation.
|
||||||
this.sprite.speed = 0;
|
this.targetPos = [this.pos[0], this.pos[1] - 128];
|
||||||
this.power = 0;
|
this.vel = [0, -5];
|
||||||
this.waiting = 0.5;
|
} else {
|
||||||
this.dying = 2;
|
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.
|
Player.prototype.star = function (idx) {
|
||||||
this.targetPos = [this.pos[0], this.pos[1]-128];
|
delete level.items[idx];
|
||||||
this.vel = [0,-5];
|
this.starTime = 660;
|
||||||
} else {
|
};
|
||||||
this.vel = [0,0];
|
|
||||||
this.targetPos = [this.pos[0], this.pos[1] - 16];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Player.prototype.star = function(idx) {
|
Player.prototype.pipe = function (direction, destination) {
|
||||||
delete level.items[idx];
|
sounds.pipe.play();
|
||||||
this.starTime = 660;
|
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) {
|
Player.prototype.flag = function () {
|
||||||
sounds.pipe.play();
|
this.noInput = true;
|
||||||
this.piping = true;
|
this.flagging = true;
|
||||||
this.pipeLoc = destination;
|
this.vel = [0, 2];
|
||||||
switch(direction) {
|
this.acc = [0, 0];
|
||||||
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() {
|
Player.prototype.exit = function () {
|
||||||
this.noInput = true;
|
this.pos[0] += 16;
|
||||||
this.flagging = true;
|
this.targetPos[0] = level.exit * 16;
|
||||||
this.vel = [0, 2];
|
this.left = true;
|
||||||
this.acc = [0, 0];
|
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;
|
|
||||||
}
|
|
||||||
})();
|
})();
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user