Skip to content

Commit

Permalink
fix(core): publish events on first render (#1024)
Browse files Browse the repository at this point in the history
* fix: subscription events

* fix: ? instead of undefined

Co-authored-by: Sehi L'Yi <sehilyi@gmail.com>

* chore: linting

* chore: use compile spec default

---------

Co-authored-by: Sehi L'Yi <sehilyi@gmail.com>
  • Loading branch information
etowahadams and sehilyi committed Jan 10, 2024
1 parent a7142c2 commit bf470c1
Showing 1 changed file with 74 additions and 58 deletions.
132 changes: 74 additions & 58 deletions src/core/gosling-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type CompiledCallbackFn = (
goslingSpec: gosling.GoslingSpec,
higlassSpec: gosling.HiGlassSpec,
_additionalData: { _processedSpec: gosling.GoslingSpec }
) => void
) => void;

interface GoslingCompProps {
spec?: gosling.GoslingSpec;
Expand All @@ -52,6 +52,8 @@ export type GoslingRef = {

export const GoslingComponent = forwardRef<GoslingRef, GoslingCompProps>((props, ref) => {
const [viewConfig, setViewConfig] = useState<gosling.HiGlassSpec>();
// Keeping track of whether the initial render has occured is important so the API works pr
const [isInitialRender, setIsInitialRender] = useState(true);
const [size, setSize] = useState({ width: 200, height: 200 });
const wrapperSize = useRef<undefined | { width: number; height: number }>();
const wrapperParentSize = useRef<undefined | { width: number; height: number }>();
Expand Down Expand Up @@ -96,63 +98,67 @@ export const GoslingComponent = forwardRef<GoslingRef, GoslingCompProps>((props,
);

// TODO: add a `force` parameter since changing `linkingId` might not update vis
const compile = useCallback(() => {
if (props.spec) {
const valid = gosling.validateGoslingSpec(props.spec);
const compile = useCallback(
(altSpec?: gosling.GoslingSpec) => {
const spec = altSpec ?? props.spec;
if (spec) {
const valid = gosling.validateGoslingSpec(spec);

if (valid.state === 'error') {
console.warn('Gosling spec is not valid. Please refer to the console message.');
return;
}
if (valid.state === 'error') {
console.warn('Gosling spec is not valid. Please refer to the console message.');
return;
}

gosling.compile(
props.spec,
(newHiGlassSpec, newSize, newGoslingSpec, newTracksAndViews, newIdTable) => {
// TODO: `linkingId` should be updated
// We may not want to re-render this
if (
prevSpec.current &&
isEqual(omitDeep(prevSpec.current, ['linkingId']), omitDeep(newGoslingSpec, ['linkingId']))
) {
return;
}

// If a callback function is provided, return compiled information.
props.compiled?.(props.spec!, newHiGlassSpec, { _processedSpec: newGoslingSpec });

// Change the size of wrapper `<div/>` elements
setSize(newSize);

// Update the compiled view config
const isMountedOnce = typeof viewConfig !== 'undefined';
if (props.experimental?.reactive && isMountedOnce) {
// Use API to update visualization.
setTimeout(() => {
preverseZoomStatus(
newHiGlassSpec,
hgRef.current?.api.getViewConfig() as gosling.HiGlassSpec
);
hgRef.current?.api.setViewConfig(newHiGlassSpec);
}, DELAY_FOR_CONTAINER_RESIZE_BEFORE_RERENDER);
} else {
// Mount `HiGlassComponent` using this view config.
setViewConfig(newHiGlassSpec);
}
publishOnNewView(newTracksAndViews);
prevSpec.current = newGoslingSpec;
tracksAndViews.current = newTracksAndViews;
idTable.current = newIdTable;
},
[...GoslingTemplates], // TODO: allow user definitions
theme,
{
containerSize: wrapperSize.current,
containerParentSize: wrapperParentSize.current
},
props.urlToFetchOptions
);
}
}, [props.spec, theme]);
gosling.compile(
spec,
(newHiGlassSpec, newSize, newGoslingSpec, newTracksAndViews, newIdTable) => {
// TODO: `linkingId` should be updated
// We may not want to re-render this
if (
prevSpec.current &&
isEqual(omitDeep(prevSpec.current, ['linkingId']), omitDeep(newGoslingSpec, ['linkingId']))
) {
return;
}

// If a callback function is provided, return compiled information.
props.compiled?.(spec, newHiGlassSpec, { _processedSpec: newGoslingSpec });

// Change the size of wrapper `<div/>` elements
setSize(newSize);

// Update the compiled view config
const isMountedOnce = typeof viewConfig !== 'undefined';
if (props.experimental?.reactive && isMountedOnce) {
// Use API to update visualization.
setTimeout(() => {
preverseZoomStatus(
newHiGlassSpec,
hgRef.current?.api.getViewConfig() as gosling.HiGlassSpec
);
hgRef.current?.api.setViewConfig(newHiGlassSpec);
}, DELAY_FOR_CONTAINER_RESIZE_BEFORE_RERENDER);
} else {
// Mount `HiGlassComponent` using this view config.
setViewConfig(newHiGlassSpec);
}
publishOnNewView(newTracksAndViews);
prevSpec.current = newGoslingSpec;
tracksAndViews.current = newTracksAndViews;
idTable.current = newIdTable;
},
[...GoslingTemplates], // TODO: allow user definitions
theme,
{
containerSize: wrapperSize.current,
containerParentSize: wrapperParentSize.current
},
props.urlToFetchOptions
);
}
},
[props.spec, theme]
);

// TODO: If not necessary, do not update `wrapperSize` (i.e., when responsiveSize is not set)
useEffect(() => {
Expand Down Expand Up @@ -193,8 +199,18 @@ export const GoslingComponent = forwardRef<GoslingRef, GoslingCompProps>((props,
});

useEffect(() => {
compile();
}, [props.spec, theme]);
// If this is the initial render, we want to render a blank visualization so that the
// ref is associated with the DOM element. This is necessary for the API to work.
if (isInitialRender) {
compile({
title: ' ',
tracks: [{}]
});
setIsInitialRender(false);
} else {
compile();
}
}, [props.spec, theme, isInitialRender]);

const responsiveHeight =
typeof props.spec?.responsiveSize !== 'object' ? props.spec?.responsiveSize : props.spec.responsiveSize.height;
Expand Down

0 comments on commit bf470c1

Please sign in to comment.