{"id":18393216,"url":"https://github.com/tomcl/hlp21-project-skeleton","last_synced_at":"2025-08-17T03:35:34.786Z","repository":{"id":80868145,"uuid":"321919242","full_name":"tomcl/hlp21-project-skeleton","owner":"tomcl","description":null,"archived":false,"fork":false,"pushed_at":"2021-02-20T22:32:47.000Z","size":1514,"stargazers_count":0,"open_issues_count":0,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-07T03:35:41.300Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"F#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tomcl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-12-16T08:35:56.000Z","updated_at":"2021-02-19T10:34:46.000Z","dependencies_parsed_at":"2023-04-25T21:31:51.909Z","dependency_job_id":null,"html_url":"https://github.com/tomcl/hlp21-project-skeleton","commit_stats":null,"previous_names":[],"tags_count":0,"template":true,"template_full_name":null,"purl":"pkg:github/tomcl/hlp21-project-skeleton","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomcl%2Fhlp21-project-skeleton","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomcl%2Fhlp21-project-skeleton/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomcl%2Fhlp21-project-skeleton/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomcl%2Fhlp21-project-skeleton/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tomcl","download_url":"https://codeload.github.com/tomcl/hlp21-project-skeleton/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomcl%2Fhlp21-project-skeleton/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270803374,"owners_count":24648685,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-17T02:00:09.016Z","response_time":129,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-06T01:59:46.586Z","updated_at":"2025-08-17T03:35:34.778Z","avatar_url":"https://github.com/tomcl.png","language":"F#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SVG Draw Application Project Skeleton Code For HLP Project 2021\n\nSee [The SVG Demo README](https://github.com/tomcl/hlp21-svg-elmish-demo/blob/master/README.md) for \ncode structure and how to build the dev environment: this is the same as the WS 3 SVG demo.\n\nYou should already have looked at the SVG Demo code and have some understanding of how an Elmish application works, using\na `model`, `view`, and `update` function with messages used to update the model. The project skeleton code \nillustrates a more complex example of Elmish code, \nwith three separate modules: `Symbol`, `BusWire`, `Sheet` each operating as individual Elmish components.\n\nFork, clone, and build this repo. Look at the code in an IDE with intellisense.\n\nIn order to see the functionality currently used by [Issie](https://github.com/tomcl/ISSIE) you can \ndownload the Issie binaries and try it out. There is a video which introduces the project objectives and explains\nwhat is good and bad about the current (Draw2D) Issie Draw block functionality. You can also fork and clone the Issie repo, \nand build its code. The build is very similar to the project skeleton\nbut a lot more complex (10K lines of F#).\n\nThe project work specification contains details of expected work during individual work phase in each of the three modules.\n\n## Introduction\n\nThe skeleton code draws circles and (random) lines on an svg canvas. It is interactive; circles can be moved as in the WS 3 demo.\nIn addition lines are drawn between circles that move with the circles; this is similar to the functionality needed for symbols and\nwires. The given implementation will need to be modified even for this basic functionality because:\n* The skeleton drag mechanism does not use programmatic bounding boxes, but instead HTML to determine which circle is clicked.\n* The skeleton `Symbol` code does not used correctly compensated coordinates. Try it setting zoom=3. How does dragging of circles\ngo wrong?\n* The skeleton code does not understand ports - connection points on the edge of symbols.\n* The skeleton wires are not right-angled multi-segment.\n\nThe skeleton introduces a modular structure which can be used to combine individual coding from 3 people into a single \nfully working schematic draw program, and some initial messages most of which will be useful in project code. You are free to\nchange message types as you like within  a group. Messages or functions `Symbol:symbolPos` owned by any component\nused to communicate with other components should not be changed in a way that alters their specification without \nconsultation with those affected.\n\n\n## Information on Elmish \u0026 Code Structure\n\nIn the demo code the three modules each have views that create objects on the SVG canvas:\n* Symbol: the component outlines\n* BusWire: the connecting wires and wire annotations\n* Sheet: The rubber band showing the new connection during drag-and drop connection. The dyanmically sized circles showing \nconnection end-points. Possibly dynamic guides showing component algnment.\n\nThese have a parent child relationship:\n\n`Sheet --\u003e BusWire --\u003e Symbol`\n\nSo the `BusWire` module can have a view function that depends on the `Symbol` module state (`Symbol.model`). The `Symbol` view \nfunction cannot depend on anything except `Symbol.model`. This dependence is needed because wire endpoints are defined \nby symbol and port positions. The alternative, keeping `BusWire` and `Symbol` as separate children of `Sheet`:\n\n```\nSheet --\u003e BusWire \n      --\u003e Symbol\n```\n\nwould require \neverything that updated port positions to also send a message to `Wire` to update wire endpoints. Thus the endpoint data is  effectively duplicated. That might sometimes be required for performance reasons, but is bad practice unless forced because it makes it more difficult to write correct code.\n\n\nGood overview of how Elmish large-scale structure is supported by various built-in Elmish functions. This is written in the context\nof a web application with (effectively) multiple pages written as a SPA (single-page application). The sections on Commands are helpful, some other parts less so.\n* [Working with Elmish](https://medium.com/@MangelMaxime/my-tips-for-working-with-elmish-ab8d193d52fd). \n\n## Information on SVG React Helpers for Elmish\n\nSee SVG syntax below, and the skeleton, and [w3schools](https://www.w3schools.com/graphics/svg_intro.asp) for how to use SVG elements. \nFor project work the SVG elements certainly needed are:\n* `line` (as in skeleton `Buswire`)\n   * Possibly better alternatives `polyline` and `polygon` which take a sequence of points. See skeleton for example of polygon.\n* For more complex objects `path` which can do anything.\n* `text` for text - see [w3schools](https://www.w3schools.com/graphics/svg_text.asp) etc\n* `g` which groups elemnets (like `div` for normal HTML), see skeleton.\n* `svg` which creates an SVG canvas of specified size, see skeleton.\n\nNote also that the order in which elements are put onto a canvas matters. the *last* element will be on top. In the skeleton\n* the blue overlay translucent triangle is on top, because it is last in its `g` list of elements.\n* That means that it alters the color of the elements underneath (opacity 0.1). Also mouse clicks are collected by that element\nand not passed through to the underlying svg circles. Therefore the skeleton dragging does not work. \nThe solution is to use bounding boxes and determine which object is clicke dprogrammatically.\n\n## Keyboard Interface Gotcha\n\nThe SVG window is not focussed to receive key presses - electron does not therefore support them directly, and the `OnKeyPress`, \n`OnKeyDown` DOM attributes will now work. Instead you can use a subscription and define electron global shortcuts for \nthe keys you need in (perhaps invisible) electron menus as in the skeleton code.\n\n\n## SVG Geometry\n\n### Zoom\n\nThe skeleton code uses a fixed size SVG canvas of 1000X1000 pixels. This is then transformed by zoom. Possibly 1000X1000\nis too small (though good for a demo) 2000X2000 would be more typical for zoom=1 to fill the screen, but it is not very critical.\nBecause zoom is variable all\nthat matters is the relative size of components (symbols) and the canvas, which determines how large is the canvas \nrelative to the objects on it. Symbols will probably also have fixed size text and this must be readable after zoom.\n\nIt is important that zoom is separated from all other use of coordinates, so that the current zoom \ncan be ignored when writing all other SVG code.\n\nThe skeleton code has working zoom, but does not quite do this perfectly. It would need to \n\n\n\n### Bounding boxes\n\nA common technique used in 2d drawing is that of bounding boxes. Objects are approximated by rectangles, specified by two pairs\nof corner coordinates: *bounding boxes*. It is easy to write code that determines:\n* Is a point within a bounding box?\n* Do two bounding boxes intersect?\nCode to do these things is inherently fast can get slower if there are a very large number of objects.\nIn that case there are various speedups by sorting the\nbox coordinates along one dimension and doing a binary search. The Draw2d (as currently used by Issie) authors claim that Draw2d is slow \nbecause of the very inefficient checks of bounding boxes used in its implementation. Even fast techniques can be a problem if\nused badly!\n\nOne typical example is in deciding which object (or objects) are clicked by mouse clicks and rectangular drags:\n* The skeleton code follows WS2 svg demo and uses custom mouse event handlers embedded in the svg.\n* This is not flexible enough for project work.\n* You should use the `mouseMsg` message to detect mouse `up`, `down` and movement. \n* You can determine which object is clicked programmatically by using bounding boxes and checking whether the click coordinates\nlie inside the bounding box. This allows:\n   * two objects close together to be disambiguated as required\n   * wires that are thin to have larger bounding boxes\n   * symbols that are complex to have suitably sized bounding boxes which are processed by other code as well as for mouse clicks.\n\n\n## Elmish Helper SVG Syntax\n\n\nReact virtual DOM elements are created in Elmish using F# helper functions of form:\n\n```\nelementName (props:IProp list) (children: ReactElement list)\n```\n\nThey divide into SVG elements (that can be used as children of an `svg` element that creates an SVG canvas) and DOM elments \nthat correspond to HTML DOM elements. There are also some `void` elements:\n\n```\nvoidElementName (props: IProp list)\n```\n\nThat deals with elements that are not allowed to have children.\n\nSee [Fable standard react documentation](https://github.com/fable-compiler/fable-react/blob/master/src/Fable.React.Standard.fs) \nfor the list of SVG, DOM and Void React element helper functions. The large number of valid `props` can be found listed\n[here](https://github.com/fable-compiler/fable-react/blob/master/src/Fable.React.Props.fs). Props can also be discovered \nfrom the IDE by autocompletion for example `SVGattr.`\n\n## Electron Documentation\n\nThe Electron framework API - and associated Node libraries - is extensive and complex. \nLuckily 99% of what you need for the project work is demonstrated in this project skeleton. In order to change or\nenhance these features you will sometimes need the [electron API documentation](https://www.electronjs.org/docs). Note\nthat 95% of the electron features are accessible via F# interfaces which define types functions and discriminated\nunions.\n\nOne way to find useful code examples is the [Issie application](https://github.com/tomcl/ISSIE). The files under `src/renderer/UI`\nall contain code using the electron framework. Fork and clone (or clone) the Issie repo to get a copy of the files. \nBuild them once to get fully working intellisense and view the code (with type information and documentation) in an IDE.\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomcl%2Fhlp21-project-skeleton","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftomcl%2Fhlp21-project-skeleton","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomcl%2Fhlp21-project-skeleton/lists"}