mhkeller / layercake Goto Github PK
View Code? Open in Web Editor NEWgraphics framework for sveltejs
Home Page: https://layercake.graphics
License: MIT License
graphics framework for sveltejs
Home Page: https://layercake.graphics
License: MIT License
Hi, I am exploring how to best make multi-panel figures. I see you have one small multiple, but I want something that has much more freedom in placement than css grids.
I would want a main plotting area and then put Layercake graphs at certain coordinates (so you can recreated grids, but you can also just have e.g. the small multiples arranged in a circle.
I tried moving the graphs with xrange/yrange but Layercake seem to still consider the whole area as its playground and one can't have two Layercakes in one div? (terrible example here)
Do you have any hints how to achieve this, e.g. multiple graphs with separate coordinate systems within one svg? Or would I have to use one coordinate system from layer cake and then mak my own component to translate figure coordinates within that?
May be a LayerGroup component with translated coordinates and position in which one use the visualisation components...just a thought
Already done on the custom-ranges branch. This would allow you to set your range to something like half the height, which is what you do for a radar plot. Needs tests.
Hi,
I keep getting this error message that says 'TypeError: The first argument of calcExtents() must be an array.'
However my data I am passing passes the Array.isArray test and is an array of objects
Is there something I am missing?
Murali
After upgrading to SvelteKit 1.0.0-next.202
which includes Vite 2.7, I receive the following when importing LayerCake:
10:36:36 PM [vite] Error when evaluating SSR module /src/lib/components/Chart.svelte:
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".svelte" for /Users/techniq/Documents/Development/open-source/layerchart/node_modules/layercake/src/LayerCake.svelte
at new NodeError (node:internal/errors:371:5)
at Object.file: (node:internal/modules/esm/get_format:72:15)
at defaultGetFormat (node:internal/modules/esm/get_format:85:38)
at defaultLoad (node:internal/modules/esm/load:13:42)
at ESMLoader.load (node:internal/modules/esm/loader:303:26)
at ESMLoader.moduleProvider (node:internal/modules/esm/loader:230:58)
at new ModuleJob (node:internal/modules/esm/module_job:63:26)
at ESMLoader.getModuleJob (node:internal/modules/esm/loader:244:11)
at async ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:78:21)
at async Promise.all (index 0)
While I'm not 100% certain, I believe the heuristic changed with Vite 2.7 to detect a svelte package, and the best tell now is to include a svelte
property in package.json
(along with main
/exports
). If using SvelteKit to build packages, running svelte-kit package
now sets this for you. This PR along with the associated issue and code provides some additional info.
Sending a PR your way...
Currently you can set a hard extent via xDomain={[0, 1]}
but if you area also dynamically changing the xKey
, then it becomes too much logic to set a hard extent or float to the computed extent.
If extents
were exposed and accepted a key of extents the same as is used internally and outputted by calcExtents then you could start to do this more elegantly and also define which extents are used for each field
I'm trying to debug this but can't seem to figure it out.
I place my visualizations in several containers, using tailwind. There's a max-width in pixels on the main container, and I'm using 100% w/h for my chart containers.
Developing locally seems fine, but if I run npm run build
and deploy my visualizations are expanding, forever.
It's adding +1 to the svg height dynamically. I'm getting the 'Target div has a negative width' error in the console, but only in Safari.
Sorry about being vague, but I'm a bit stuck :)
@mhkeller In the docs you mention:
The chart will actually render before the container width is measured and you'll get a flash of a chart before it adjusts itself. You can set a default width here that it will render to for that moment. It might be better to just now show the chart during this period but including this option for now. Defaults to 350.
I think this is the culprit of some of my graphs misbehaving with my current setup, depending on the browser I'm using. Do you have a way to not render the chart until after this flash?
Thanks for the awesome library. I'm just beginning to experiment with Svelte (coming from React) and your library has been very useful to learn how to integrate with d3 (I've contributed to the React vx library in the past and considering porting the Text component to Svelte).
Looking at the guide and example, I see you have a xScale
, yScale
, zScale
, and rScale
for the scales. For the Stacked Column example, zScale
is used to represent the stack.
I was curious, how would this translate to a Grouped Bar Chart or even further with a Grouped Stacked Bar Chart. I know typically the use of x0/x1
and y0/y1
scales are used. I didn't know if it made since to include at least x1Scale
and y1Scale
in LayerCake.
Currently we follow the D3 convention of passing in an object setting up the padding rules. This works fine but often you want to change the padding on mobile. We could do it where you pass in a function that gets the new width or maybe it's better to grab the CSS padding on the container itself and use that instead of having this object at all.
The uniques() function checks if each item is in an array of seen items, which I think leads to quadratic complexity overall. There are probably use cases such as a scatter plot with thousands of points where this would take a noticeable length of time.
Would it be worth making seen
a Set
? I think it would just need the following changes:
const seen = [];
-> const seen = new Set();
seen.includes(computed)
-> seen.has(computed)
seen.push(computed)
-> seen.add(computed)
Do you have suggestions / an example for implementing tooltips on a bar chart? My naive attempts to do it with d3-quadtree are not immediately working, probably because I'm passing it the wrong things. For a bar chart with <50 bars I'm sorta tempted to rewrite QuadTree.svelte's findItem, probably by ripping out d3-quadtree and replacing it with some elementary school math on the bar widths / heights. (the tear-it-down-and-replace-with-javascript-circa-1999 is an instinct I try to suppress, not always successfully). I can start putting these issues on the examples repo too if that makes more sense to you.
Unrelatedly I think I can contribute a HorizontalCategoricalMapScale component to the layer cake examples if that's at all useful, it's totally trivial to build, but the sorta thing that's handy to have all the same.
I'm a little new to interactive plotting on the web. If I wanted to plot a zoom- and pannable map of Germany and display some markers on it, could I use layercake
? I'm guessing I would need to find a Topo/GeoJSON file for Germany and then figure out a way to convert lat/lng coordinates to SVG coordinates? Is layercake the right tool for this?
esm
doesn't seem to work with this module.
This looks like it may be a bug or I may just have something way off, but it might be useful to provide a main
field, and not just a module
field.
And it might be worth updating the documentation that the module is only provided in ES module syntax.
Thanks for the help and great library.
We currently expose element
for these layouts which is the parent <svg>
element. It's also useful to work inside the <g>
so you can use padding. Currently you can do element.querySelector('g')
but seems nicer to something like innerElement
.
I recently moved to the latest SvelteKit based on Vite (1.0.0-next.50
) and Layer Cake throws an error when imported:
500
Unexpected token 'export'
/Users/techniq/Documents/Development/playground/svelte-kit-layercake/node_modules/layercake/src/index.js:1
export { default as LayerCake } from './LayerCake.svelte';
^^^^^^
SyntaxError: Unexpected token 'export'
at wrapSafe (internal/modules/cjs/loader.js:979:16)
at Module._compile (internal/modules/cjs/loader.js:1027:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1092:10)
at Module.load (internal/modules/cjs/loader.js:928:32)
at Function.Module._load (internal/modules/cjs/loader.js:769:14)
at Module.require (internal/modules/cjs/loader.js:952:19)
at require (internal/modules/cjs/helpers.js:88:18)
at nodeRequire (/Users/techniq/Documents/Development/playground/svelte-kit-layercake/node_modules/vite/dist/node/chunks/dep-efe32886.js:68907:17)
at ssrImport (/Users/techniq/Documents/Development/playground/svelte-kit-layercake/node_modules/vite/dist/node/chunks/dep-efe32886.js:68865:20)
at eval (/src/lib/Chart.svelte:7:31)
It looks like it's being detected as commonjs instead of esm. I'm not 100% sure if the issue is with Layer Cake, Vite (as it worked with older SvelteKit based on Snowpack), SvelteKit recently adding type: module to package.json
(I was on an older SvelteKit/Snowpack before this change) or something else.
I see Layer Cake has main and module defined in package.json, but not an export map which from my limited understanding is the best tell for ESM for Vite/Snowpack/etc.
I've created a repo to demonstrate the issue.
I just ran npm init svelte@next
, added layercake
and a simple chart example. When I initially ran this example last night the issue didn't present itself, but when I tried to identify what else was different between this example and my project just now, it show'd up. I've cleared and re-installed node_modules
as well as the .svelte
directly (trying to clear any cache) but the issue persists. I'm using node v14.14.0
.
Sorry if this is the wrong place to ask, but don't see any other community forum/chat.
I just wanted to verify that I am not missing user contributed Typescript types for Layer Cake that you might be aware of?
Hi, I'm wondering how you'd suggest overlaying bubbles on top of a map layer? It seems like there could be a way to do this with https://layercake.graphics/example/MapLayered but don't immediately see how I would do this for a point layer in unprojected lat/lngs? Would I have to explicitly project them into viewport coordinates? Am not married to it being in canvas or svg, probably either would be fine. Am looking at tens of bubbles, probably not thousands? If this would need to be a new component, do you have any suggestions on implementation? Thanks in advance.
So, I took a very basic crack at making LayerCake a component.
https://github.com/zzolo/layercake-ssr-testing/tree/e362b7ea8de4713f869b32b9aa550a37dc6bb761
Building and running it is the same as described in #5 .
The main LayerCake component and parts are in layercake/
. Note that I only implemented an SVG layer. Also, I just sort of implemented this from scratch just as an example and was not going for parity with LayerCake as far as options and methods.
https://github.com/zzolo/layercake-ssr-testing/tree/e362b7ea8de4713f869b32b9aa550a37dc6bb761/layercake
Then, in components/
, you can see it implemented in Chart.html
, and this gets called with data in Page.html
.
https://github.com/zzolo/layercake-ssr-testing/tree/e362b7ea8de4713f869b32b9aa550a37dc6bb761/components
The main difference is that we have to pass data around components, so there's many {...props}
attributes in components, where props
is just the full state of the current component. For instance:
<SVG {...props} layers="{ svgLayers }" />
...
computed: {
props: state => state,
}
This is not great, mostly because it's just kind of messy and it's not a two-way data source. But, I think in practice it is not so bad.
There's also an open question in LayerCake's current form and here on how might be the best way to handle events like clicking. I feel like the general idea is to create reusable components, such as an axis, and I am not sure of a good way to define a click handler as an option. This is probably just a Svelte limitation where the data in a component doesn't have access to this
, like a method does.
Hi, I am getting a strange error:
<script>
import { data, e2eData } from '../../stores/datastore.js';
import { LayerCake, Svg, flatten, calcExtents, Html } from 'layercake';
import {
scaleLinear,
scaleBand,
scaleTime,
scaleDiverging,
scaleOrdinal,
scaleSequential
} from 'd3-scale';
import * as aq from 'arquero';
import AxisX from '../layercake/AxisX.svelte';
import AxisY from '../layercake/AxisY.svelte';
import Tooltip from '../layercake/custom/MyTooltip.svelte';
import Heatmap from '../layercake/custom/Heatmap.svelte';
const margin = { top: 10, right: 10, bottom: 10, left: 10 };
const tFormat = timeFormat('%d-%b-%y');
let groupedData;
let width = 1000;
let height = 1000;
let xScale;
let xDomain;
let yScale;
let zScale;
let zDomain;
let yDomain;
let xRange;
let zRange;
const dt = $e2eData
.groupby('L2_Process', 'Anchoring_Function')
.count()
.filter((d) => d.Anchoring_Function !== null && d.L2_Process !== null)
.orderby(aq.desc('count'));
groupedData = dt.objects();
/*******************
* Chart props
*/
// width = document.body.clientWidth - margin.left - margin.right;
// height = document.body.clientHeight - margin.top - margin.bottom;
// zScale = scaleOrdinal();
// zDomain = groupedData;
xDomain = dt.array('L2_Process');
yDomain = dt.array('Anchoring_Function');
// zRange = colors; // quantize(interpolateHcl('#f4e153', '#362142'), 38);
xScale = scaleBand(dt.array('L2_Process'), [margin.left, width - margin.right]).round(true);
yScale = scaleBand(yDomain, [margin.top, height - margin.bottom]).round(true);
console.log(xScale('4.2 - Network Build'), yScale('NSRs'));
/*****************/
</script>
<div style="height:{height}px;width:{width}px">
<LayerCake
x="L2_Process"
y="Anchoring_Function"
xScale
yScale
xDomain
yDomain
data={groupedData}
>
<Svg>
<!-- <AxisY ticks={10} />
<AxisX gridlines={true} /> -->
<Heatmap />
</Svg>
</LayerCake>
</div>
<style>
/*
The wrapper div needs to have an explicit width and height in CSS.
It can also be a flexbox child or CSS grid element.
The point being it needs dimensions since the <LayerCake> element will
expand to fill it.
*/
.chart-container {
width: 100%;
height: 100%;
}
</style>
This is my heatmap file
<script>
import { getContext } from 'svelte';
// import { scaleQuantize } from 'd3-scale';
// import { timeFormat } from 'd3-time-format';
// import { timeDay } from 'd3-time';
import { scaleLinear, scaleTime, scaleBand, scaleDiverging, scaleSequential } from 'd3-scale';
import { interpolateRdBu, interpolateReds } from 'd3-scale-chromatic';
import { range, extent } from 'd3-array';
const { data, xGet, x, y, yGet, zGet, xScale, yScale, custom, width, height, xDomain } =
getContext('LayerCake');
// $data.forEach((d) => console.log(d));
// let [min, max] = extent($data, (d) => d.count);
// const zScale = scaleSequential(interpolateReds).domain([0, max]);
// $data.sort((a, b) => a.date.localCompare(b.date));
console.log('--', $yScale('NSRs'));
// $: fillColor = (d) => {
// console.log($xScale(d), $y(d));
// // if (d.count < 0) {
// // max = Math.max(-min, max);
// // let newScale = scaleDiverging([-max, 0, max], (t) => interpolateRdBu(1 - t));
// // return newScale(d.count);
// // }
// // return zScale(d.count);
// };
</script>
<!-- <g>
{#each $data as d}
<rect
x={$xGet(d)}
y={$yGet(d)}
width={$xScale.bandwidth()}
height={$yScale.bandwidth() - 1}
stroke="white"
stroke-width="1"
/>
{/each}
</g> -->
I get two errors
Any suggestions on what's going on?
This should be doable as long as its replacement has the same API. Mostly the following methods:
We'll need both scaleLinear and scaleSqrt
The padding option works for linear scales but wouldn't work great for log or power scales since it's based on a proportion.
The related issue is perhaps this will be included as a basic D3 scale feature: d3/d3-scale#150
That issue also has information on Vega's implementation of this idea, which could serve as a blueprint.
Thank you for writing LayerCake, it is a fantastic base to make custom plots on top of! We are moving from a more "component" based library and really enjoy the control Layer Cake provides. Particularly being able to trivally combine SVG (ease) with Canvas (high volume data layers).
That said, I have been playing with Canvas based plots today in anticipation of needing to plot a large amount of data soon. It seems that putting two components in one <Canvas>
results in an update loop that never ends.
I wonder if I am doing something wrong?
You can see the issue in this REPL. It works as shown with two <Canvas>
tags. You can see the issue by moving <Scatter />
into <Line />
's <Canvas>
(while also commenting the two scaleLayer and clear rect lines from <Scatter />
). WARNING: It will bind up your tab as soon as the REPL rebuilds.
Also, I wonder if multiple <Canvas>
is better in the end anyway?
Hi, thanks for a great component. I am seeing some extra elements in my charts. They seem to be iframe elements and look like this:
<iframe style="display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; border: 0; opacity: 0; pointer-events: none; z-index: -1;" aria-hidden="true" tabindex="-1" src="about:blank"></iframe>
Is this something that is part of LayerCake. I also see it in the svelte-virtual-list component. Inspecting the LayerCake page also shows this iframe for each component.
It could be useful in some instances to allow the user access to the root svg or div element when constructing a layout. This could for an escape hatch if they want to use something like d3.zoom that operates on the root svg node. Some questions
svg
and g
can both be exposedhtml
, div
, layoutDiv
?canvas
. The ctx
is already exposed via a child svelte context object.Current branch: 9350d3f
For some reason, the package.json isn't exposing the component properly when rendered inside of Node. Here's a reproduction: https://github.com/mhkeller/lc-ssr-test
As a workaround, you can simply drag the layercake/
dir from node_modules
and require the svelte components directly, instead of pointing to src/index.js
.
Currently, the second argument to calcExtents
is an array of objects defining a field and accessor. It might make more sense for this to be an object like
{
x: d => d.x,
y: d => d.y
}
Because the output of this function is a similarly structured object, it makes a bit more sense that the input matches the output. Also I think it would make it examples like the SmallMultiple wrapper be a bit easier where you wouldn't have to loop through the input array:
<LayerCake
padding={{ top: 2, right: 6, bottom: 2, left: 6 }}
x={extentGetters.find(d => d.field === 'x').accessor}
y={extentGetters.find(d => d.field === 'y').accessor}
{data}
xDomain={$xDomain}
yDomain={$yDomain}
>
<Svg>
<Line
stroke={'#000'}
/>
</Svg>
</LayerCake>
Would become:
<LayerCake
padding={{ top: 2, right: 6, bottom: 2, left: 6 }}
x={extentGetters.x.accessor}
y={extentGetters.x.accessor}
{data}
xDomain={$xDomain}
yDomain={$yDomain}
>
<Svg>
<Line
stroke={'#000'}
/>
</Svg>
</LayerCake>
There was maybe a reason why I made the input an array, though, so I'll look into this. It would also be a breaking change.
Per, #53 (comment), would it make more sense to rename the flatData
to dataForExtents
? It speaks more to what it's used for, which is a little less mysterious than describing what it must be.
This would be a breaking change but we can still support flatData
for a little bit so things wouldn't actually break. I'm just about ready to publish version 6.0.0, which is the svelte-kit version. There are no other changes though – just figured it would be good to bump the major version in case it breaks a build process or something.
Great resource!
Looks like a recent update may have messed up some links required for documentation!
E.g., clicking on any of the chart thumbnails from https://layercake.graphics/components yields the following error:
500
Failed to fetch dynamically imported module: https://layercake.graphics/_app/pages/components/_slug_.svelte-998c6316.js
TypeError: Failed to fetch dynamically imported module: https://layercake.graphics/_app/pages/components/_slug_.svelte-998c6316.js
How can I use Layercake in my Svelte , web component. ? If not tagged with options, compiler throws the error Illegal Constructor
For reference sveltejs/svelte#4132 [url edited by @mhkeller]
I have some naive questions about Layercake and would like to hear feedback about the tools.
Is there a forum (e.g. Discourse) for this?
I'm opening this issue here for anyone having issues using Layer Cake inside of svelte-scroller. There's an issue in that library where the width is hardcoded at 0
. Because Layer Cake will expand to fill the parent's dimensions, if you don't override this value somehow, Layer Cake won't have any width. That library should hopefully have a fix soon.
Hi!
Just getting into Svelte and Layer Cake, but it seems all but 2 examples when opened in the REPL are broken?
The data gets drawn but there's no responsiveness
They all throw
message: "Cannot read property 'defaultView' of null"
stack: TypeError: Cannot read property 'defaultView' of null
The only 2 that seem to still work are the circle packing examples.
Not sure if this is a problem with the REPL, or the library.
Currently, all of the components have jsdoc comments but the vs code extension doesn't seem to recognize them well.
The component description only gets pulled in (when hovering over the component's import statement) if the format is such where the @type
definitions are included in one big comment at the top immediately above the exported variables like this:
<script>
/**
Generates an SVG marker containing a marker for a triangle makes a nice arrowhead. Add it to the named slot called "defs" on the SVG layout component.
@type {String} [fill='#000'] – The arrowhead's fill color.
@type {String} [stroke='#000'] – The arrowhead's fill color.
*/
export let fill = '#000';
export let stroke = '#f0c';
</script>
<marker id="arrowhead" viewBox="-10 -10 20 20" markerWidth="17" markerHeight="17" orient="auto">
<path d="M-6,-6 L 0,0 L -6,6" fill="{fill}" stroke="{stroke}"/>
</marker>
This yields a popup when imported like this, which is helpful because it has the comment description. It has undefined
for the props though:
In that format the popups over each individual property are also undefined and it pulls in that entire first comment, which isn't great:
When the component is formatted like this:
<script>
/**
Generates an SVG marker containing a marker for a triangle makes a nice arrowhead. Add it to the named slot called "defs" on the SVG layout component.
*/
/** @type {String} [fill='#000'] – The arrowhead's fill color. */
export let fill = '#000';
/** @type {String} [stroke='#000'] – The arrowhead's fill color. */
export let stroke = '#f0c';
</script>
<marker id="arrowhead" viewBox="-10 -10 20 20" markerWidth="17" markerHeight="17" orient="auto">
<path d="M-6,-6 L 0,0 L -6,6" fill="{fill}" stroke="{stroke}"/>
</marker>
The top-level hover now loses the main comment, but the individual props are nicely annotated:
But it still shows a lot of undefined
fields.
Any thoughts?
im trying to make an editable chart, where i can click and drag data points
use case: interactive linear interpolation, similar to smooth.js and jsplinter
could be generalized to a svelte svg editor : )
i noticed that the accessor functions are made only for read access
we could extend the existing design like
function accessor(dataPoint, newValue = undefined) {
if (newValue == undefined) {
// get
return dataPoint.x;
}
// set
dataPoint.x = newValue;
return true; // success
}
but for better performance, we should have separate getter and setter functions (unswitching)
the api could look like
<LayerCake
x={p => p.myX}
xSetter={(p, v) => (p.myX = v)}
>
in the trivial case <LayerCake x={'myX'}>
, layercake can auto-generate a setter function
here is my modified Scatter.svg.svelte
<script>
import { getContext } from 'svelte';
const { data, xGet, yGet, xScale, yScale } = getContext('LayerCake');
export let r = 5;
export let fill = '#000';
export let stroke = '#0cf';
export let strokeWidth = 0;
export let dx = 0;
export let dy = 0;
function handleMouseDown(startEvent, dataIndex) {
const moveMouse = (moveEvent) => {
// https://github.com/d3/d3-scale#continuous_invert
$data[dataIndex] = {
// TODO fix offset. why 25 x 10?
myX: $xScale.invert(moveEvent.offsetX - 25),
myY: $yScale.invert(moveEvent.offsetY - 10)
};
};
const stopMove = (stopEvent) => {
console.log('stop move');
document.removeEventListener('mousemove', moveMouse);
document.removeEventListener('mouseup', stopMove);
//document.removeEventListener('mouseleave', stopMove); // TODO
};
document.addEventListener('mouseup', stopMove);
//document.addEventListener('mouseleave', stopMove); // TODO
// start moving
document.addEventListener('mousemove', moveMouse);
}
</script>
<g class="scatter-group">
{#each $data as d, dIdx}
<circle
cx={$xGet(d) + (typeof dx === 'function' ? dx($xScale) : dx)}
cy={$yGet(d) + (typeof dy === 'function' ? dy($yScale) : dy)}
{r}
{fill}
{stroke}
stroke-width={strokeWidth}
on:mousedown={(event) => handleMouseDown(event, dIdx)}
/>
{/each}
</g>
<style>
.scatter-group circle:hover {
fill: red !important;
}
</style>
I haven't tried to do it, but it seems like it wouldn't work since LayerCake depends on a DOM element. Maybe there is some way around this that I don't know about.
You can also do stuff like:
const vals = calcExtents([{start: 0, end: 1}, {start: -10000, end: 0}], [
{ field: 'y', accessor: d => [d.start, d.end] }
]);
// [-10000, 1]
Add a test for this scenario
.. to make it easier to find source files
Hey @mhkeller thanks again for handling a steady stream of questions from me... What is the "right" way to set a given axis to a scaleLog? I see scaleLinear and scaleSqrt are set as defaults in defaultScales.js and the scale types seem to be passed to the Axis components as, like, yScale and xScale with getContext('LayerCake'). Does this have to do with the availability of a nice function in createScale? Should I be trying to set this in /components/AxisY.svelte ?
If you want, say, a multi-series line chart, the best data structure would be an array of arrays of objects with the same x and y keys like this
[
[{x: 1, y: 10},{x: 2, y: 12},{x: 3, y: 15}],
[{x: 1, y: 20},{x: 2, y: 22},{x: 3, y: 25}]
]
The problem is how can calcExtents properly measure the extents of this data?
Consider also this common data structure, which is similar to the output from d3.nest()
[
{key: 'group1', values: [{x: 1, y: 10},{x: 2, y: 12},{x: 3, y: 15}]},
{key: 'group2', values: [{x: 1, y: 10},{x: 2, y: 12},{x: 3, y: 15}]}
]
You could set a property in the store to flatten: true
which could flatten this data, or have that be the default. This would also then help with D3 stack layouts.
Let the user set their own function with flatten
. This can be annoying though if the user doesn't really want to deal with flattening arrays of arrays properly
This has the same problem as 3 but might also be a good idea in general in case the user is already flattening their data elsewhere or maybe it was loaded in flat and then they nested it, they can pass that in we avoid restructuring the data.
These aren't mutually exclusive and I could see an argument for including all of them since they offer convenience for casual users plus escape hatches if things get tricky.
This in general seems like a messy concept to have to handle but I'm not sure what a good solution is. The "do nothing" solution would be have calcExtents
balk at anything that is array of arrays and require you to set your domains manually in that scenario. That could be problem though if you have a data structure like this below, which it seems would be silly to not support :
[
[0, 1], [1, 4]
]
I don't think this really matters but it would be more to the spec.
The logic for doing domain padding breaks when you have a large domain or large numbers, @aubergene pointed out. Started doing it on the fix-domain-padding branch. It needs more tests and would be good to detect how this changes for logarithmic and power scales. d3 scales are duck typed so have to detect what we're dealing with.
In stacked charts, you have multiple y values, representing the min and max. You should be able to return an array from an accessor so the user doesn't have to choose which one.
Changes needed:
I don't think partialDomain needs any adjustment.
Currently, Layer Cake measures the extent of the data and the dimensions of the div to create scales. This is most useful to linear scales and all others require you to calculate your own domain, such as for scaleOrdinal
. It would be nice if the user put in a scaleOrdinal
, Layer Cake took the key for that dimension and calculated unique fields on its own. The user could override these just as they can do currently but it would be a nice way to get quickly up and running.
The blocker on this is that there's no easy way to determine what d3 scale is being used since they're all duck typed. You could write out logic to figure out what the scale is based on the methods but that seems easy to mess up and hard to maintain and test. You could pass a string for the scale but then you'd have to import all of d3-scale – not sure if that would be tree-shook. This is on hold for now but it's an interesting idea if other progress can be made.
Hi,
the error I got is
> Using @sveltejs/adapter-static
TypeError: Cannot destructure property 'width' of 'getContext(...)' as it is undefined.
at file:///D:/sveltekit%20projects/capacitor/.svelte-kit/output/server/entries/pages/layercake/AxisX.svelte
...
I rename the component folder to layercake and put it inside route, npm run dev works fine, I thought the problem is getContext but I tried using other component that use getContext and build normally, any tips ?
Thanks
Help me creating pie chart in layercake
On the ssr-features branch there's a new SVG component that follows Rich's pancake styling to allow for properly scaled SVG charts rendered server-side and scaled with Viewbox.
I called it SvgSsr
for now but it's not the best name. It's a bit obscure from what it actually is doing and I don't really like typing it. Something like ScaledSvg
makes more sense or SvgScaled
if it seems more consistent to have Svg
come first.
I noticed that adding an on:blur event handler creates an outline around the focused element, this results in strange behavior when clicking a path. See examples below:
To fix this issue on the Map component, I just added .feature-path:focus { outline: none; }
to the <style/> block in the map component.
After reading through :focus' MDN docs, I'm not sure this is the best or most accessible solution. Thoughts? I'm happy to work on implementing a fix but I'm not entirely sure what the most accessible solution is.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.