diff --git a/.github/workflows/semantic-pull-request.yml b/.github/workflows/semantic-pull-request.yml index 339859494..d22ad0add 100644 --- a/.github/workflows/semantic-pull-request.yml +++ b/.github/workflows/semantic-pull-request.yml @@ -14,4 +14,31 @@ jobs: steps: - uses: amannn/action-semantic-pull-request@v5 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + # Configure which types are allowed (newline-delimited). + types: | + feat + fix + ci + chore + docs + refactor + test + # Configure which scopes are allowed. + scopes: | + core + track + data-fetcher + api + editor + # Configure if a scope must always be provided. + requireScope: true + # Configure which scopes are disallowed in PR titles (newline-delimited). + # Anything but `feat` and `fix` + disallowScopes: | + ci + chore + docs + refactor + test diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e2146bbb..d3f7e3940 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,52 @@ +## [0.10.1](https://github.com/gosling-lang/gosling.js/compare/v0.10.0...v0.10.1) (2023-08-02) + + +### Bug Fixes + +* **data-fetcher:** gmod/gff stream issue ([#957](https://github.com/gosling-lang/gosling.js/issues/957)) ([c698785](https://github.com/gosling-lang/gosling.js/commit/c6987855c73e82a44a0ea10d7f822f121d480943)) + + + +# [0.10.0](https://github.com/gosling-lang/gosling.js/compare/v0.9.33...v0.10.0) (2023-08-01) + + +### Bug Fixes + +* **core:** do not override ID in tracks from views ([#954](https://github.com/gosling-lang/gosling.js/issues/954)) ([6654e0d](https://github.com/gosling-lang/gosling.js/commit/6654e0d315a40978ce26d97fdcf38168472a088b)) +* **data-fetcher:** correctly calculate the distance to previous mutation in VCF (`DISTPREV`) ([#949](https://github.com/gosling-lang/gosling.js/issues/949)) ([ef5f58f](https://github.com/gosling-lang/gosling.js/commit/ef5f58f43ee33ca2de068a547f21ed1767426437)) +* **track:** remove private properties from draw() ([#952](https://github.com/gosling-lang/gosling.js/issues/952)) ([529e9a3](https://github.com/gosling-lang/gosling.js/commit/529e9a38484fe81b624292a582870ae0cc144d28)) + + +### Features + +* **api:** consistent track/view IDs for JS API ([#944](https://github.com/gosling-lang/gosling.js/issues/944)) ([1c2b766](https://github.com/gosling-lang/gosling.js/commit/1c2b7669660856cae98f88ba38d9326b788c75e1)) +* **api:** onNewTrack, onNewView ([#943](https://github.com/gosling-lang/gosling.js/issues/943)) ([a98ee69](https://github.com/gosling-lang/gosling.js/commit/a98ee69367273943becbeae8696b1511b35f04e4)) +* **api:** subscription for genomic axis changes ([#935](https://github.com/gosling-lang/gosling.js/issues/935)) ([a2c36f5](https://github.com/gosling-lang/gosling.js/commit/a2c36f500f0d8e1181c9c72a970eb385af4fe3b5)) +* **core, api, editor:** support using view IDs ([#939](https://github.com/gosling-lang/gosling.js/issues/939)) ([cd8d300](https://github.com/gosling-lang/gosling.js/commit/cd8d3000f7e1e86422ec89f765585f6056d64a9f)) +* **data-fetcher:** GFF3 with tabix ([#923](https://github.com/gosling-lang/gosling.js/issues/923)) ([526882f](https://github.com/gosling-lang/gosling.js/commit/526882fb82463ad4262568d9569840431c709fc9)) +* **track:** dummy-track ([#946](https://github.com/gosling-lang/gosling.js/issues/946)) ([ee02d38](https://github.com/gosling-lang/gosling.js/commit/ee02d38312ae7431ccd460a6d5e1904013488427)) + + + +## [0.9.33](https://github.com/gosling-lang/gosling.js/compare/v0.9.32...v0.9.33) (2023-07-11) + + +### Bug Fixes + +* **data-fetcher:** Bump tabix-js version to fix errors when loading BED files ([#938](https://github.com/gosling-lang/gosling.js/issues/938)) ([d901232](https://github.com/gosling-lang/gosling.js/commit/d9012326f4eadbf0c50f3c70424951c4735dcb69)) +* **data-fetcher:** support genomicFieldsToConvert ([#932](https://github.com/gosling-lang/gosling.js/issues/932)) ([c94ecae](https://github.com/gosling-lang/gosling.js/commit/c94ecaea5ac010e17603816c6bf01c2d2b2a086c)) + + + +## [0.9.32](https://github.com/gosling-lang/gosling.js/compare/v0.9.31...v0.9.32) (2023-07-05) + + +### Bug Fixes + +* fix duplicated data and odd tile load timing in the bam data fetcher ([#927](https://github.com/gosling-lang/gosling.js/issues/927)) ([4e52907](https://github.com/gosling-lang/gosling.js/commit/4e52907b8ed79cc08d8c9ce1b823b72f026a4004)) + + + ## [0.9.31](https://github.com/gosling-lang/gosling.js/compare/v0.9.30...v0.9.31) (2023-05-31) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fdb5b4928..e2abbb4b4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,6 +16,39 @@ yarn start Then, you can open http://localhost:3000/ in a web browser to test the online editor. +## Commit Messages + +We use [commitlint](https://github.com/conventional-changelog/commitlint#what-is-commitlint) to maintain commit messages in a consistent manner and automatically update a [CHANGELOG.md](/CHANGELOG.md) based on the commit messages. + +The allowed pattern of commit messages is: + +```sh +type(scope?): subject # scope is optional; multiple scopes are supported (current delimiter options: "/", "\" and ",") +``` + +where `type` can be either `feat`, `fix`, `ci`, `chore`, `docs`, `perf`, `refactor`, or `test`. + +Additionally, `scope` should be defined for `feat` and `fix` which should be one of the following: + +- `core`: any general updates to the library, e.g., grammar change, new rendering, etc. +- `track`: any updates that are specific to tracks in the library, including `gosling-track` and `gosling-axis`. +- `data-fetcher`: any updates related to data fetchers +- `editor`: UI and other updates to the online editor +- `api`: the Gosling APIs + +Example commit messages are as follows: + +```sh +git commit -m 'fix(core): correctly position views' +git commit -m 'feat(editor): add a data preview panel in editor' +git commit -m 'docs: add details about commitlint in README.md' +``` + +To learn more about the commitlint, please visit [conventional-changelog/commitlint](https://github.com/conventional-changelog/commitlint#what-is-commitlint). + +## Opening Pull Requests +We use the [commitlint](#commitlint) for the title of PR. So, if the title of PR is not following the commitlint conventions, [Semantic Pull Request](https://github.com/zeke/semantic-pull-requests) will complain about it, disallowing your PR to be merged. When your PR is accepted and merged into the master branch, the title of the PR will be recorded as a single commit message which will then added as a single item in [CHANGELOG.md](/CHANGELOG.md). + ## Testing Production Build Using Editor It is sometimes necessary to test the production build of Gosling.js. This frequently happened to us when we needed to ensure that certain data fetchers, like BAM and VCF, work correctly without errors in a deployed app. @@ -24,6 +57,7 @@ To test this, you need to build the project first and then preview the productio ```sh yarn build +yarn build-editor yarn preview ``` @@ -96,27 +130,38 @@ If there is an example you would like to add to the editor example library, plea 5. Select the example in the editor to make sure your example works as expected. -## Commit Messages - -We use [commitlint](https://github.com/conventional-changelog/commitlint#what-is-commitlint) to maintain commit messages in a consistent manner and automatically update a [CHANGELOG.md](/CHANGELOG.md) based on the commit messages. +## Bumping Gosling.js -The allowed pattern of commit messages is: +GitHub Action handles bumping the version of Gosling.js. The pattern looks like the following: -```sh -type(scope?): subject # scope is optional; multiple scopes are supported (current delimiter options: "/", "\" and ",") +``` +yarn version --patch +git push origin master --tags ``` -where `type` can be either `build`, `ci`, `chore`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, or `test`. +# Internal Explanations +## How does a Gosling spec get turned into a HiGlass spec? +A Gosling schema goes through the following steps: -Example commit messages are as follows: +1. **Preprocessing**: The implicit aspects of the Gosling schema is made explicit here. Default values are added, properties set in parent elements are added to child elements, and IDs for every Gosling track and view are generated if they aren't specified by the user. +2. **Track data intermediate representation**: From the preprocessed schema, a Gosling track-based intermediate representation is created. All the information from the schema gets converted into an array of Gosling track data objects, each with track-specific data. What happens to Gosling views? View specifications get applied to each track intermediate representation. +3. **HiGlass schema generation**: By iterating over the Gosling track intermediate representations, a HiGlass schema is generated. Each Gosling track corresponds to a HiGlass view. This HiGlass view will contain one or more HiGlass track, depending on the Gosling track it was derived from. -```sh -git commit -m 'fix: correctly position views' -git commit -m 'feat: add a data preview panel in editor' -git commit -m 'docs: add details about commitlint in README.md' -``` +One important nuance to the Gosling schema to HiGlass schema conversion is that there is not a direct correspondence between Gosling tracks and view and HiGlass tracks and views. Instead, each Gosling track corresponds to a HiGlass view. Please examine the relationship between the view and track IDs. -To learn more about the commitlint, please visit [conventional-changelog/commitlint](https://github.com/conventional-changelog/commitlint#what-is-commitlint). +- **Gosling track ID**: ID that is associated with each track. It is set by the user or is generated during the preprocessing step. +- **Gosling view ID**: ID associated with each view. It is set by the user or is generated during the preprocessing step. +- **HiGlass track ID**: The HiGlass track ID is the same as the Gosling track ID with `-track` appended to it. +- **HiGlass view ID**: Each HiGlass view has an ID, and *this ID is the same as the Gosling track ID.* An instance of GoslingTrackClass knows what the Gosling track ID is by calling `context.viewUid`, which is the HiGlass view ID which is the same as the Gosling track ID. -## Opening Pull Requests -We use the [commitlint](#commitlint) for the title of PR. So, if the title of PR is not following the commitlint conventions, [Semantic Pull Request](https://github.com/zeke/semantic-pull-requests) will complain about it, disallowing your PR to be merged. When your PR is accepted and merged into the master branch, the title of the PR will be recorded as a single commit message which will then added as a single item in [CHANGELOG.md](/CHANGELOG.md). +The one exception to this are overlaid tracks where the `id` defined at the root level of an overlaid track is used as the HiGlass' view ID. This limits the number of gosling-track instances generated (i.e., multiple tracks that are overlaid can share the same data, hence reducing the number of data requests). +``` +tracks: [ + { ..., id: '1' }, // ← This is a track in Gosling. This becomes a HiGlass view '1' + { ..., alignment: 'overlay', id: '2', // ← This is actually a view in Gosling, but this becomes a HiGlass view '2' + tracks: [ + { ..., id: '3' }, // ← This track is included in a HiGlass view '2' + { ..., id: '4' }, // ← This track is included in a HiGlass view '2' + ]} +] +``` \ No newline at end of file diff --git a/README.md b/README.md index 13df2a10d..5c9f1acb7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Gosling.js -[![npm version](https://img.shields.io/npm/v/gosling.js.svg?style=flat-square)](https://www.npmjs.com/package/gosling.js) [![editor status](https://github.com/gosling-lang/gosling.js/actions/workflows/deploy-editor.yml/badge.svg)](https://github.com/gosling-lang/gosling.js/actions/workflows/deploy-editor.yml) [![build status](https://github.com/gosling-lang/gosling.js/actions/workflows/ci.yml/badge.svg)](https://github.com/gosling-lang/gosling.js/actions/workflows/ci.yml) [![codecov](https://img.shields.io/codecov/c/github/gosling-lang/gosling.js/master.svg?style=flat-square&?cacheSeconds=60)](https://codecov.io/gh/gosling-lang/gosling.js) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) [![online editor](https://img.shields.io/badge/demo-online_editor-E08243.svg?style=flat-square)](https://gosling.js.org/) [![docs](https://img.shields.io/badge/docs-📖-57B4E9.svg?style=flat-square)](http://gosling-lang.org/docs/) +[![npm version](https://img.shields.io/npm/v/gosling.js.svg)](https://www.npmjs.com/package/gosling.js) [![editor status](https://github.com/gosling-lang/gosling.js/actions/workflows/deploy-editor.yml/badge.svg)](https://github.com/gosling-lang/gosling.js/actions/workflows/deploy-editor.yml) [![build status](https://github.com/gosling-lang/gosling.js/actions/workflows/ci.yml/badge.svg)](https://github.com/gosling-lang/gosling.js/actions/workflows/ci.yml) [![codecov](https://img.shields.io/codecov/c/github/gosling-lang/gosling.js/master.svg?cacheSeconds=60)](https://codecov.io/gh/gosling-lang/gosling.js) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) [![online editor](https://img.shields.io/badge/demo-online_editor-E08243.svg)](https://gosling.js.org/) [![docs](https://img.shields.io/badge/docs-📖-57B4E9.svg)](http://gosling-lang.org/docs/) **Gosling.js is a declarative grammar for interactive (epi)genomics visualization on the Web.** diff --git a/editor/Editor.tsx b/editor/Editor.tsx index 13bba3093..2903e21ff 100644 --- a/editor/Editor.tsx +++ b/editor/Editor.tsx @@ -14,19 +14,20 @@ import 'allotment/dist/style.css'; import { debounce, isEqual } from 'lodash-es'; import stripJsonComments from 'strip-json-comments'; import JSONCrush from 'jsoncrush'; -import type { HiGlassSpec } from '@higlass.schema'; -import type { Datum } from '@gosling.schema'; +import type { HiGlassSpec } from '@gosling-lang/higlass-schema'; +import type { Datum } from '@gosling-lang/gosling-schema'; import { Themes } from 'gosling-theme'; import { ICONS, type ICON_INFO } from './icon'; import { getHtmlTemplate } from './html-template'; import ErrorBoundary from './error-boundary'; -import { traverseTracksAndViews } from '../src/core/utils/spec-preprocess'; +import { traverseTracksAndViews } from '../src/compiler/spec-preprocess'; import { examples, type Example } from './example'; import EditorPanel, { type EditorLangauge } from './EditorPanel'; import EditorExamples from './EditorExamples'; import './Editor.css'; +import { v4 } from 'uuid'; import type { AltGoslingSpec, AltTrack } from '../../gosling.js/src/alt-text/alt-gosling-schema'; import { altUpdateSpecWithData } from '../../gosling.js/src/alt-text/alt-from-data'; @@ -266,6 +267,7 @@ function Editor(props: RouteComponentProps) { const [gistTitle, setGistTitle] = useState(); const [description, setDescription] = useState(); + const [showViews, setShowViews] = useState(false); const [expertMode, setExpertMode] = useState(false); // This parameter only matter when a markdown description was loaded from a gist but the user wants to hide it @@ -349,12 +351,24 @@ function Editor(props: RouteComponentProps) { // gosRef.current.api.subscribe('trackClick', (type, eventData) => { // console.warn(type, eventData.id, eventData.spec, eventData.shape); // }); + // Location API + // gosRef.current.api.subscribe('location', (type, eventData) => { + // console.warn(type, eventData.id, eventData.genomicRange); + // New Track + // gosRef.current.api.subscribe('onNewTrack', (type, eventData) => { + // console.warn(type, eventData); + // }); + // New View + // gosRef.current.api.subscribe('onNewView', (type, eventData) => { + // console.warn(type, eventData); + // }); } return () => { // gosRef.current?.api.unsubscribe('mouseOver'); // gosRef.current?.api.unsubscribe('click'); // gosRef.current?.api.unsubscribe('rangeSelect'); // gosRef.current?.api.unsubscribe('trackClick'); + // gosRef.current?.api.unsubscribe('location'); }; }, [gosRef.current]); @@ -753,6 +767,44 @@ function Editor(props: RouteComponentProps) { setHideDescription(true); } + // Layers to be shown on top of the Gosling visualization to show the hiererchy of Gosling views and tracks + const VisHierarchy = useMemo(() => { + const tracksAndViews = gosRef.current?.api.getTracksAndViews(); + const maxHeight = Math.max(...(tracksAndViews?.map(d => d.shape.height) ?? [])); + return ( +
+ {tracksAndViews + ?.sort(a => (a.type === 'track' ? 1 : -1)) + ?.map(d => { + let { x: left, y: top, width, height } = d.shape; + let background = 'rgba(255, 50, 50, 0.3)'; + if (d.type === 'view') { + const VIEW_PADDING = 3; + left -= VIEW_PADDING; + top -= VIEW_PADDING; + width += VIEW_PADDING * 2; + height += VIEW_PADDING * 2; + background = 'rgba(50, 50, 255, 0.1)'; + } + return ( +
+ ); + })} +
+ ); + }, [hg, demo]); + // console.log('editor.render()'); return ( <> @@ -1055,7 +1107,20 @@ function Editor(props: RouteComponentProps) { - +
{/* {expertMode && false ? (