GithubHelp home page GithubHelp logo

morphic.js's Introduction

morphic.js

a lively Web-GUI inspired by Squeak

written by Jens Mönig
[email protected]

Copyright (C) 2010-2024 by Jens Mönig

Morphic.js is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License along with this program. If not, see https://www.gnu.org/licenses/.

Want to use Morphic.js but scared by the open-source license? Get in touch, we'll make it work.

morphic.js's People

Contributors

jmoenig avatar brollb avatar ccrraaiigg avatar ego-lay-atman-bay avatar bromagosa avatar dragazo avatar lowellbander avatar

Stargazers

liuxing3169 avatar  avatar  avatar Pouya Kary ✨ avatar Sara Tasche avatar Delon R. Newman avatar  avatar oven avatar Cyclotomic Fields avatar Hamish 'James' Coates avatar  avatar  avatar latrokles avatar  avatar Philip Weaver avatar Ryan Daum avatar  avatar Brian Burns avatar Austin Pahl avatar Ali Osman Aksu avatar Delphy avatar Marcin Dąbrowski avatar Otavio Coelho avatar Ezequiel Birman avatar lily celeste newton avatar Jeff Carpenter avatar Tanjim Hossain avatar Edward O avatar  avatar Keeney avatar Eli Mellen avatar Joubert Nel avatar Second Datke avatar  avatar Kate Lin avatar Rajiv Abraham avatar parasuram avatar  avatar Riceball LEE avatar shenyu avatar John Smith avatar OftenGuy avatar Kristian Kankainen avatar Dafydd Rees avatar Azlen Elza avatar Max Krieger avatar xuegoo avatar zhifeng avatar CodeDmitry avatar Martin Pravda avatar  avatar Andrew Foltz-Morrison avatar Hridya Agrawal avatar  avatar Francisco José Marín Pérez avatar Silviu Daniel Eftimie avatar  avatar  avatar Ezequiel R. Aguerre avatar jinho park avatar Harvey Shih avatar Calloway Sutton avatar Kyle Hayes avatar Stephen De Gabrielle avatar Shein Lin Phyo avatar Andrew Spiece avatar Ramin Honary avatar Alexandro Rocha avatar Alejandro Linarez Rangel avatar  avatar Vasilii avatar Dmitry avatar Guido Bartolucci avatar George Marecheau avatar Ricardo Araújo avatar Mauricio Verano Merino avatar Zetian Lin avatar Mr7Cat avatar  avatar Ajinkya Kulkarni avatar ajith avatar Nissi Nassime avatar BenDerPan avatar Yusuke Hirao avatar Ilya Volkov avatar  avatar Jack Armitage avatar none-p avatar  avatar Jonathan van Alteren avatar Michael Pabst avatar Joe avatar Tim Käck avatar xuduo avatar David Overholt avatar Kyle Miller avatar Tim Johnson avatar  avatar Mariano Montone avatar GAURAV avatar

Watchers

Duncan Mak avatar  avatar Tom Elam avatar roadlabs avatar Bogus curry avatar  avatar Davide Della Casa avatar James Cloos avatar  avatar Tim Käck avatar Michal Moc avatar Michael Ball avatar Michael Anthony avatar Kyle Hayes avatar Stephen Spaeth avatar  avatar Jörg Rade avatar  avatar liuxing3169 avatar Jan B. Krejčí avatar BenDerPan avatar Dawid Kraiński avatar  avatar  avatar  avatar OftenGuy avatar

morphic.js's Issues

right clicking something in a menu closes the menu

in most guis, you can use right click as well as left click to select options in a context menu. in some it may do something else or nothing. but in snap it just closes the menu. i thought some options are not working at first. please make it do the same as left click

Code submission - "copy" code

Coffeescript:

    # snippets of clipboard-handling code taken from
    # http://codebits.glennjones.net/editing/setclipboarddata.htm
    # Note that this works only in Chrome. Firefox and Safari need a piece of
    # text to be selected in order to even trigger the copy event. Chrome does
    # enable clipboard access instead even if nothing is selected.
    # There are a couple of solutions to this - one is to keep a hidden textfield that
    # handles all copy/paste operations.
    # Another one is to not use a clipboard, but rather an internal string as
    # local memory. So the OS clipboard wouldn't be used, but at least there would
    # be some copy/paste working. Also one would need to intercept the copy/paste
    # key combinations manually instead of from the copy/paste events.
    document.body.addEventListener "copy", ((event) =>
      if @cursor
        selectedText = @cursor.target.selection()
        if event.clipboardData
          event.preventDefault()
          setStatus = event.clipboardData.setData("text/plain", selectedText)

        #log('setData: ' + setStatus);
        if window.clipboardData
          event.returnValue = false
          setStatus = window.clipboardData.setData "Text", selectedText

        #log('setData: ' + setStatus);
    ), false

Javascript:

    // snippets of clipboard-handling code taken from
    // http://codebits.glennjones.net/editing/setclipboarddata.htm
    // Note that this works only in Chrome. Firefox and Safari need a piece of
    // text to be selected in order to even trigger the copy event. Chrome does
    // enable clipboard access instead even if nothing is selected.
    // There are a couple of solutions to this - one is to keep a hidden textfield that
    // handles all copy/paste operations.
    // Another one is to not use a clipboard, but rather an internal string as
    // local memory. So the OS clipboard wouldn't be used, but at least there would
    // be some copy/paste working. Also one would need to intercept the copy/paste
    // key combinations manually instead of from the copy/paste events.

var _this = this;

document.body.addEventListener("copy", (function(event) {
  var selectedText, setStatus;
  if (_this.cursor) {
    selectedText = _this.cursor.target.selection();
    if (event.clipboardData) {
      event.preventDefault();
      setStatus = event.clipboardData.setData("text/plain", selectedText);
    }
    if (window.clipboardData) {
      event.returnValue = false;
      return setStatus = window.clipboardData.setData("Text", selectedText);
    }
  }
}), false);

improvement: high-dpi screens support (aka retina displays)

While entry level devices (used for education) will most likely remain at "normal" dpi tiers, 50% of the "medium level" devices and all of the high-end devices (including most tablets) are moving to high-dpi screens.

davidedc/Fizzygum@42a7def and davidedc/Fizzygum@2c8bdfa in Zombie Kernel provide support for high-dpi screens support (aka retina displays). Actual side-by-side screenshot of the difference below:

screen shot 2015-02-17 at 20 32 39

I'll likely have refactoring and optimisation in following commits, but the links above give the bulk of it. I tested on my test cases and it's OK. There is likely some excessive blitting and some of the "dormant" code I don't use has no adjustments...

minor: Array.splice used with "null" argument instead of zero

in:
this.children.splice(0, null, aNode);

it seems like the spec-proper way to write it would be
this.children.splice(0, 0, aNode);

Now - it works just fine, but in all the specs I've seen that null would really be an integer. Null not being an integer, nor a number (it's an object), I'd suggest changing that to 0.

It probably works out OK in all implementations and maybe it could be even formally correct for some oddity of Javascript, but... (minor, I know.)

Complex morph duplication error

Morph copying doesn't seem to work.

Steps:

  1. open scroll morph
  2. drag a text into it
  3. open the inspector of the text and attach it to the scroll morph, so now the scrollmorph contains the text and its inspector
  4. change a property of the text via the inspector, e.g. alpha
  5. duplicate the whole scrollmorph

expected: the new scroll morph has its own textmorph and its own inspector. The new inspector should be hooked to the new textmoprh, and it's possible to change the transparency similarly to what was done within the first scrollMorph.

result: the new inspector is not linked to the new textmorph, we can't change the opacity as we did within the first scrollmorph.

screen shot 2015-06-25 at 16 05 19

Some glitches in morphs duplication mechanism

steps:

  • create an inspector
  • duplicate the inspector

observed:

  • the buttons in the second inspector affect the first inspector
  • selecting properties in the second inspector inspects them in the first inspector

expected:

  • the two inspectors behave independently

(This is fixed in Zombie Kernel but it would need bisecting to find the fix as this was long ago)

Glitches in scroll morph scrolling when editing text inside it

steps:

  • open a scrollmorph
  • drop a rectangle inside it
  • also drop a string inside it

screen shot 2015-02-12 at 00 12 23

  • select the string so caret appears

observed:

  • the rectangle disappears
    screen shot 2015-02-12 at 00 12 29

expected;

  • the rectangle should still be visible while user edits the string

(this was fixed in Zombie Kernel sometime in the past month)

menu option given for morph to be attached to non-overlapping clipped morphs

steps:

  • open a scrollframe
  • drop in the scrollframe an animation demo
  • create a rectangle and position it just under the scrollmorph like so:
    screen shot 2015-02-12 at 01 29 24
  • right-click on the rectangle and choose attach to...

obtained:

  • options are given to select the frame morph and the bounce morphs, none of which overlaps with the rectangle like so:
    screen shot 2015-02-12 at 01 29 32

expected:

  • no morphs are eligible for attachment
    screen shot 2015-02-12 at 01 29 41

(this was fixed in Zombie Kernel but I can't remember when, would need bisection)

Can't select the first character of a StringMorph or a TextMorph...

  1. go with the cursor to the left of the first character of a StringMorph or a TextMorph.
  2. holding shift, go right

expected: the cursor moves one position to the right and the first character is selected.
obtained: the cursor moves but the first character is not selected.

(Also going left from the first character causes cursor to be drawn at the end of text/string)

(this was fixed in Zombie Kernel but can't remember when, would need bisection)

Rectangle.intersect can give negative rectangles - worth a comment

This is correct, but I think it deserves a comment, because, say, it matters if one wants to implement a proper isEmpty routine (which I didn't, and costed me several hours of debugging :-)

new Rectangle(10,10,20,20).intersect(new Rectangle(15,25,19,25))

gives a rectangle with the corner above the origin:

  origin: Point
    x: 15
    y: 25
  corner: Point
    x: 19
    y: 20

(the proper "is empty" test indeed is already in morphic.js
!dirty.extent().gt(new Point(0, 0))
, just not in a dedicated routine)

Also note how a negative rectangle can be expanded to be positive (which again is correct but worth a comment, as the intuition might otherwise suggest that many operations including expansion should be "void" on an empty rectangle):

new Rectangle(10,10,20,20).intersect(new Rectangle(15,25,19,25)).expandBy(3).area() -> 10

improvement: first shot at serialization / deserialization

Implemented a first draft of serialization / deserialization. It works on a morph. The morph can be complex (e.g. be a frame with multiple inspectors inside), but for the time being it needs to be self-contained to be functional (e.g. no references to morphs outside the hierarchy of the selected morph).

Since JSON doesn't handle closures, quite a lot of refactoring was needed of the callback system here davidedc/Fizzygum@c33275e and here davidedc/Fizzygum@da0d3d2 . (Closures in callbacks can be just transformed into "normal" method and accompanying parameters to be passed at call time).

Serialisation now hinges on a more generic deepCopy mechanism which replaces the previous "fullCopy" implementation here davidedc/Fizzygum@3e7dfee .

JSON doesn't handle cyclic data structures, or preserve the identity of shared references (i.e. two references to a single object will be restored as references to two equal, but not identical copies), so some work was done to cater for both here davidedc/Fizzygum@6a63643

Improvements will follow to a) allow for "notable" references to Morphs outside the hierarchy of the selected morph (e.g. references to the world morph) b) letting Morphs to pre-process and post/process their state before/after serialisation as they see fit (e.g. to discard transient data that can/should be recalculated, etc.)

Little example animation of one of the tests is attached, note that serialisation / deserialisation at the moment can only be triggered via the console - proper menus and export to file will follow. A frame here is created containing a rectangle and its inspector. The frame is serialized, the world is cleaned, then the frame is deserialized and lastly it's added to the world. All buffers and references work fine.

Note a little glitch: in the deserialised frame, the inspector still has the label containing the ID of the original rectangle (#1), even though it's correctly pointing to a second, new, independent rectangle (#2). In the next iterations the Inspector will have to be given a chance to update its contents based on the state of the new world it appears in...

serialisationdeserialisation

SecurityError at line 3014

oopsies
When I move the mouse in my Starlings game, I get a SecurityError at line 3014 in morphic.js as of commit 28abbad.

Call stack:
Morph.prototype.isTransparentAt: morphic.js (3014, 9)
Anonymous function: morphic.js (9390, 9)
Array.prototype.forEach: luismark.js (54, 9)
HandMorph.prototype.morphAtPointer: morphic.js (9389, 5)
HandMorph.prototype.processMouseMove: morphic.js (9665, 5)
Anonymous function: morphic.js (10292, 13)

luismark.js version: here

A color picker can affect a frame or a scrollframe, but not if it's attached inside them...

...take a color picker and move it inside a frame, then use the setTarget from the color picker. Result: the color picker modifies the desktop instead of the frame.

note that if you get the color picker to partially overlap the frame instead, setting the target does the right thing: user is asked of whether the desktop or the frame should be set as target, and everything behaves well.

Same thing with scrollframe instead of frame

(this was fixed in Zombie Kernel but not sure when, would need bisection)

Incorrect TextMorph.prototype.slotAt when short line

When there is a TextMorph with a short line (such as the final line in "import a picture from another web page or from a file on your computer by dropping it here" in Snap!), slotAt can return an invalid column.

Here is the problematic code. This error is not obvious as context.measureText(undefined) === context.measureText("undefined"). That is, measureText appears to cast undefined input to a string.

This is problematic after adding the URL detection as the character (fetched using the slot from slotAt) is undefined and has no .match function. Of course, this would be problematic for any other (regex) character detection relying on slotAt for the character such as https://github.com/jmoenig/morphic.js/blob/master/morphic.js#L1322

Differences between morphic.txt and morphic.js (header area)

After read the documentation of morphic.js, I noticed some differences between the morphic.txt file and the header section of morphic.js, I presume that at some point some differences were introduced as consequence of the maintenance of 2 separate files with the same content. Please see the following images:

morphic-header-diff-01
morphic-header-diff-02

For more details please the following diff file:

--- morphic.header.js   2014-11-23 21:44:11.000000000 -0600
+++ morphic.txt 2014-11-24 00:35:07.000000000 -0600
@@ -1,29 +1,30 @@
-/*

-    morphic.js
+   morphic.js

-    a lively Web-GUI
-    inspired by Squeak
+   a lively Web-GUI
+   inspired by Squeak

-    written by Jens Mönig
-    [email protected]
+   written by Jens Mönig
+   [email protected]

-    Copyright (C) 2014 by Jens Mönig
+   Copyright (C) 2012 by Jens Mönig

-    This file is part of Snap!.
+   this documentation last changed: April 07, 2013

-    Snap! is free software: you can redistribute it and/or modify
-    it under the terms of the GNU Affero General Public License as
-    published by the Free Software Foundation, either version 3 of
-    the License, or (at your option) any later version.
+   This file is part of Snap!.

-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU Affero General Public License for more details.
+   Snap! is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Affero General Public License as
+   published by the Free Software Foundation, either version 3 of
+   the License, or (at your option) any later version.

-    You should have received a copy of the GNU Affero General Public License
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU Affero General Public License for more details.
+
+   You should have received a copy of the GNU Affero General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.


     documentation contents
@@ -464,15 +465,9 @@

         MyMorph.prototype.mouseMove = function(pos) {};

-    All of these methods have as optional parameter a Point object
+    The only optional parameter of such a method is a Point object
     indicating the current position of the Hand inside the World's
-    coordinate system. The
-
-        mouseMove(pos, button)
-
-    event method has an additional optional parameter indicating the
-    currently pressed mouse button, which is either 'left' or 'right'.
-    You can use this to let users interact with 3D environments.
+    coordinate system.

     Events may be "bubbled" up a morph's owner chain by calling

@@ -1034,4 +1029,3 @@
     Davide Della Casa contributed performance optimizations for Firefox.

     - Jens Mönig
-*/

You can find one way to avoid these differences in the pull request #12, following this pattern you only need to update the morphic.txt file in order to produce the most recent version of the header section of the morphic.js.

scrollmorph doesn't update scrollbars when morph is attached inside it

steps:

  • open scrollframe
  • open a morph so it only partially overlaps
  • attach the morph to the frame inside the scrollframe

like so:
screen shot 2015-02-12 at 01 47 10

obtained:

  • the part of the morph outside the scrollframe is not cleared
  • the scrollframe doesn't show scrollbars
    screen shot 2015-02-12 at 01 47 52

expected:

  • the part of the morph outside the scrollframe should be cleared
  • the scrollframe should update its scrollbars
    screen shot 2015-02-12 at 01 47 26

(this is fixed in Zombie Kernel but can't reference exact commit, bisection might be necessary)

Some glitches in repainting (example: rectangle attached to frame)

steps:

  • create a frame
  • create a rectangle
  • attach the rectangle to the frame so it's only partially inside the frame, like so:
    screen shot 2015-02-12 at 00 04 44

obtained:

  • moving the frame causes the rectangle to sort of break like so:
    screen shot 2015-02-12 at 00 04 49

expected:

  • the rectangle should be clipped at the frame edge as soon as attached to the frame, like so:
    screen shot 2015-02-12 at 00 13 44

(This is fixed in Zombie Kernel but it would need bisecting to find the fix since I fixed this long ago)

left scrollpane of inspector not rendered correctly in "pic..." feature

Steps to reproduce:

  • open the minimal world
  • open the inspector of the WorldMorph
  • right click on inspector and select the inspector
  • select the "pic..." functionality
  • a new tab opens with the pic of the inspector

expected: the left scrollpane is rendered correctly

obtained: the left scrollpane is rendered above the window, painting over the title of the
window and the window frame. The scrollpane is rendered below the "Show..." button.

See attached picture
scrollPaneRenderedIncorrectly

popUpCenteredInWorld does not center menu

When calling popUpCenteredInWorld, the menu is centered using the pre-rendered size (the actual size isn't computed until this.createItems() is called in popup). This isn't noticeable for small menus but becomes obvious when the menu is large:
DeepinScreenshot_chromium_20210630101857

improvement: test system (and automations recorder)

While in theory "turtles all the way down" systems should sort of self-test themselves with just basic usage, I found this not be true in practice (I don't know if because of the project at hand or some deeper reason).

For many refactorings I've done, things have broken in rather subtle ways and I found them quite late.

Hence over the months (and two versions) I've made a test system to checkpoint any change big or small. Being morphic a direct and live system, I though to make a direct and live test system, where the user simply records actions, and the test system will compare "before" vs "after" screenshots taken during such recorded actions. The playback can be totally left unattended. As long as no visual changes occur, the system will test itself unattended. In case that visual changes occur, they are highlighted and can be accepted quickly.

The test harness looks like this right now:
screen shot 2015-04-20 at 21 27 35

There are right now around 40 tests ( https://github.com/davidedc/Zombie-Kernel-tests/tree/master/tests ) for around 40 minutes of total test time, trying to exercise basic behaviours, and also subtle behaviours.

The test time can be reduced: an included script launches 9 windows splitting the tests among them. (Also I'll look into "speedups" of the playback as the system should for most tests react well to "rapid fire" events).

screen shot 2015-04-20 at 20 25 28

Should all the tests allocated to the window pass, a green signal is provided.

screen shot 2015-04-20 at 20 30 26

The actions can to some degree abstract from things that change easily such as morphs size and location, insertion/deletion of items in menus, and the presence of other spurious morphs in the background: tests maintenance across code changes is kept within reason. (such abstraction is provided via a couple of ways of identifying the morphs and recording the pointer location within them).

On the other hand, the screenshots would highlight even the most minute Canvas rendering implementation changes across minor browser releases, but luckily these changes can be very quickly accepted - it takes seconds to tell apart "malign" from "circumstantial" changes, as differences are highlighted in red like this one:

diff-obtained-systemtest_buildallmorphs_image_1-error-18256-diffnumber-1

The system can also keep several screenshots obtained in different browsers / browser versions and will "pass" the screenshot test if any of the reference screenshots is matched.

"Unclosable" MenuMorphs

After customizing some of the menus in NetsBlox, I noticed that menus can sometimes be unable to be closed on background click. It seems the issue is related to an already closed MenuMorph being destroyed more than once.

In my specific case, the showMessage method in the IDE_Morph is calling destroy on the menu regardless of the fact that it has already been destroyed (and there is a different active menu already). Since the MenuMorph assumes it is the activeMenu, this results in world.activeMenu being set to null and the actual active menu is no longer closed on background click.

This could be addressed a couple different ways but it seems safe to say that a menu should not be clearing world.activeMenu unless it is the current active menu.

Steps to reproduce:

  • Display a MenuMorph
  • Display a new MenuMorph
  • Call destroy() on the first MenuMorph

Syntax error SCRIPT5021 in F12

When debugging a HTML file using Morphic, I find a error in Morphic.js:

SCRIPT5021: Intervalo inválido no conjunto de carateres
Ficheiro: morphic.js, Linha: 1284, Coluna: 42

This means line 1284, column 42 in morphic.js. This can be fixed by replacing À with \xc0 and ÿ with \xff. The fixed line would look like this:

return aCharacter.match(/[A-z\xc0-\xff0-9]/);

subtle (and probably premature) note about destroying mechanism (potential memory leaks source)

looks like the current "destroy" implementations are non-recursive. One (or a few) nodes are severed from the tree.

While this removes an entire branch from the world in terms of visibility and interaction, there could be a memory leak if destroyed morphs "down the branch" are targets of living morphs, or if callbacks from living objects reference them.

A recursive destroy would give the chance to check such links (which could prevent the morphs from being garbage-collected) and decide what to do about them.

Probably not a material concern, but if a leak is observed, this could be a place where it could come from...

suggestion: splitting morphic.js in multiple files

morphic.js now counts 10471 lines and has passed the limit of what Github can handle to show diffs online. Also I found myself investigating a few times what the history of a particular class was.

Both issues prompt me to suggest a splitting of the file into smaller ones. If having one unique morphic.js file is critical, a barebone build system that is entirely cross-plarform and requires zero installations is possible: just a simple script (.sh in unix and .bat in windows) that "cat >>"s (unix) or "copy >>"es (windows) multiple files into a concatenated file.

I am a hipster coder, I code in Comic Sans and I know that not having a build system on a > 10K LOC project is very punk rock and a worthy topic of discussion with the snotty professional coders, I get it.

Still, I put forward my suggestion, I volunteer to provide implementation.

question about crossProduct function in Point

the crossProduct function in Point is:

Point.prototype.crossProduct = function (aPoint) {
return this.multiplyBy(aPoint.mirror());
};

which if I'm not mistaken returns another point. On the other hand, it looks like the consensus on 2d cross product it's that it's a scalar

http://mathworld.wolfram.com/CrossProduct.html

This function is not used in morphic.js, so I couldn't figure out the actual use/meaning of this piece of code. Is it possible to document this function a little more?

improvement: displaylist based drawing of Morphs

each morphic.js' morph currently completely draws itself in a backing buffer, which is then blitted onto the damaged parts of the screen.

These changes below introduce a displaylist-based drawing for the FrameMorph and the BoxMorph:

davidedc/Fizzygum@f8b1dc0
davidedc/Fizzygum@73a332e
davidedc/Fizzygum@daeef2a

The BoxMorph is interesting because it requires the use of a further clipping mask (8 lines of code) and the rewriting of the hit test method (currently named isTransparentAt, 27 lines of code that can be refactored into a third of that size).

The advantage of having a displaylist-based redraw is a) reduced memory usage (just the desktop itself, in retina display and 800x600 , would need a backing buffer of 7.5MB) and b) it works better with affine transforms than the buffer-based method.

Note that the PenMorph can only be used on a dedicated CanvasMorph now - which exposes its "raster" nature - other morphs won't expose their buffer. I could have put a different mechanism in place where Morphs switch from one redraw mode to the other in case a Pen is attached to them but I was happy with this solution...

Some refactoring and renaming will follow, and more Morphs will be moved over to the new system.

question with suggestion: expensive copy/modify semantics of Point and Rectangle

The current edit/copy model of Point and Rectangle creates one or more objects for any "write" operation (apart from setTo).

I'm familiar with Java and similar APIs, where a Rectangle "translate" implies a change to the original object, so I' m biased. One could claim that it's a matter of idioms, and Java Rectangle is messy, as for example "union" and "intersect" return a new Rectangle, so it's kind of different rules for different methods, which is bad.

That said, the current implementation in morphic.js is very memory-intensive - several Rectangles/Points are created for any operation. A Rectangle "translateBy" creates 1 Rectangle (which creates 2 more points) and 2 additional "transient" Points (and I suspect those are not immediately freed but rather end up in garbage collection, because they are not created locally, they are created from an object that is outside of the function scope), for a total of 5 objects.

Of the 5 "translate" calls in morphic.js, 4 re-assign the new Rectangle to the original instance (so the original Rectangle and its two points end up in garbage collection), and one is "area.copy().translateBy(delta).round();", which makes an extra copy which I believe is redundant.

Although this might seem like a nitpick over minor operations, those are quite at the "bottom of the stack", so I'd guess there are several dozens of those in each frame, plus memory allocations / garbage collection are actually a major source of slowness in js, and jittery animation (which is worse, cause it's more difficult to pinpoint the source and fix).

The question is whether there is a deeper reason that I can't see of why the model is as is (e.g. that's just how Morphic engine(s) work whether one likes it or not period)?.

If the system grew like this organically, then a suggestion would be to switch to a model where all operations assume a direct change of the invoking instance. If one needs a copy, one has to explicitly wrap a new Rectangle(originalRectToBeLeftIntact) so it's super-clear that a copy is being made, so the syntax also gives an idea of more "expensive" steps that are otherwise less visible...

Inspector duplication error

steps:

  1. open textmorph
  2. inspect it
  3. duplicate inspector

expected: the second inspector can change properties of the textMorph (e.g. alpha)
obtained: not the case

screen shot 2015-06-25 at 16 15 25

scrolling cursor down on content-filled textbox causes entire world to scroll

detected on firefox/safari/chrome on OSX

steps to reproduce:

  • open minimal.html
  • open inspector
  • show...-> methods
  • scroll down to the "contextMenu" method
  • click on top right panel and press arrow down
  • observed: the cursor scrolls down, the entire world scrolls up (revealing white page background at the bottom)
  • expected: no world scrolling

I think what's happening here is that the invisible "behind the curtains" DOM textbox that is created for handling the text entry is actually bigger than the world menu, and scrolling down for some reason causes the world to scroll as to reveal the bottom part of the invisible text entry. I think that's what's happening because in Chrome I have set the "show redraw regions", which shows all the invisible elements, and I can see the huge textbox.

missing carriage returns in methods as visualised by the inspector

steps to reproduce:

  • open minimal.html
  • open inspector of the WorldMorph
  • select show -> methods
  • pick any method with more than one line
  • obtained: the content of the method is shown without any carriage returns
  • expected: the content of the method is shown with carriage returns

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.