cartodb / carto-react Goto Github PK
View Code? Open in Web Editor NEWCARTO for React packages
Home Page: https://docs.carto.com/react/
License: MIT License
CARTO for React packages
Home Page: https://docs.carto.com/react/
License: MIT License
The project created via the CRA template doesn't work with try to use hygen
to generate new componets:
$ yarn hygen view new
yarn run v1.22.19
$ hygen view new
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/edumac/dev/workspaces/my-app/node_modules/d3-array/src/index.js from /Users/edumac/dev/workspaces/my-app/node_modules/@deck.gl/carto/dist/es5/api/layer-map.js not supported.
Instead change the require of index.js in /Users/edumac/dev/workspaces/my-app/node_modules/@deck.gl/carto/dist/es5/api/layer-map.js to a dynamic import() which is available in all CommonJS modules.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
Command used to generate the project: yarn create react-app my-app --template @carto/base-3
Version of C4R: 1.4.6
Currently, in both widget and widget ui there isn't a way to disable filtering/category selection.
Add a property called: filtering
or interactivity
in every widget, with true by default, that allows to have static widgets if false.
In professional services projects it's a common use case where we need to show static widgets once we've made an analysis and we don't want the user to change the filters already applied.
This strange behavior also happens in Builder with long datasets.
In this case, we use a dataset with 1.4M of rows.
We are trying to use the C4R FormulaWidget
with the following source and trying different combinations:
const POS_SOURCE_ID = 'posSource'
const source = {
id: POS_SOURCE_ID,
type: MAP_TYPES.TABLE,
connection: 'xxxxx',
data: 'xxxxxxxxxxxx.shared.usa_pos',
}
export default source
View component:
import posSource from '@/data/sources/posSource'
...
<FormulaWidget
id='mechants'
title='Formula TEST C4R'
dataSource={posSource.id}
column='geoid'
operation={AggregationTypes.COUNT}
wrapperProps={{
disabled:false,
}}
global={false}
onError={console.error}
/>
When reducing the zoom levels to show data, the FormulaWidget
stays with the infinite loader, gives no error on the console, and does not display any data even when the zoom level is 20.
Steps we have tried:
In none of the scenarios does it works with none of these versions:
A very common feature requested by customers in PS is the ability to create custom geometries to filter data and then, reuse those geometries later to apply the filters. Right now, the functionality of creating a custom geometry is built thanks to the FeatureSelectionLayer
, but the shape is lost once the user removes it. This RFC exposes the need to provide the user the ability to save this shape with a name to be used in the following sessions.
A possible implementation could be to assign a name to the geojson of the drawn shape and store in a remote component through a specific API. This API should provide the CRUD actions to operate with this entities.
Another possible implementation could be store those custom geometries in the local storage of the browser. The cons here is that you won't share these geometries with others users in the app, but the main pro is related to lack of a specific backend for this.
Hi,
I was trying to run this container in a separate server, and finally everything works great!
After while i was trying to create an Application under /oauth_apps
and i got my clientId
to use with my carto react app, unfortunately, i had this problem :
I wsa trying to connect to my self hosted container for this purpose, but while using the official cartodb server, i do not have the same error, and i was able to connect successfully to my react app.
I had to change the credentials.apiBaseUrl
oauth.domain
oauth.audience
oauth.authorizeEndPoint
...
"@auth0/auth0-react": "^1.8.0",
"@carto/react-api": "^1.1.0",
"react": "^17.0.2",
Thank You !
A very common feature requested by customers in PS is the ability to perform some filters in the map through widgets and save the state of these filters to use them in future sessions. Depending on the customer the use of this functionality can be called as Filters (B6) or Plans (Radarview, XY Italy).
A possible implementation could be to assign a name to the configuration of the filters and store the state in the React Store in a remote component through a specific API. This API should provide the CRUD actions to operate with these entities.
Another possible implementation could be store those filters in the local storage of the browser. The cons here is that you won't share these filters with others users in the app, but the main pro is related to the lack of a specific backend for this.
The executeSQL
function returns the backend message but not the status error if the request fails
https://github.com/CartoDB/carto-react/blob/master/packages/react-api/src/api/SQL.js#L48
Currently, the CategoryWidgetUI
component of react-ui
package does not provide a way to set the decimal precision when displaying the "Other" category that contains the sum of all remaining categories. This can result in an issue where adding two numbers with decimal precision can lead to unexpected results due to the limitation of JavaScript's floating-point arithmetic.
Below is the screenshot of this issue:
In order to avoid this issue, I would like to request an enhancement in the CategoryWidgetUI
component that allows users to set the decimal precision for the "Other" category. This would enable users to ensure that the sum of all remaining categories is displayed accurately, without the need to manipulate the data beforehand.
Below is the code snippet which is causing this floating-point arithmetic issue:
File: https://github.com/CartoDB/carto-react/blob/master/packages/react-ui/src/widgets/CategoryWidgetUI.js
Snippet:
// Showing top or selected categories
if (!blockedCategories.length) {
const main = list.slice(0, maxItems);
if (main.length < list.length) {
const rest = list.slice(maxItems).reduce(
(acum, elem) => {
acum.value += elem.value;
return acum;
},
{ name: REST_CATEGORY, value: 0 }
);
return [...main, rest];
} else {
return main;
}
Ideally, this enhancement could be implemented by adding a new prop to the CategoryWidgetUI
component, such as decimalPrecision
, which would allow users to set the number of decimal places to display for the "Other" category. For example, if decimalPrecision
is set to 2, the sum of the other categories will be rounded to two decimal places. If this is not feasible, I would appreciate any alternative solutions that can achieve the same goal.
This enhancement will provide greater control over the display of the sum of the other categories and prevent potential issues due to the limitation of JavaScript's floating-point arithmetic.
Thank you for your consideration.
We need the functionality to add more than one geometry to allow filtering or drawing on the map.
Implementing his feature right now is not possible without ejecting it from the Carto4React completely and rebuilding them all from scratch. The current widget FeatureSelectionWidget
available in the Carto4React library does not provide this functionality.
That could be used to share the same implementation across many projects and reduce the time of development for the applications, focussing on providing real value for our customers.
The proposed implementation is divided into two different implementations.
The widget must allow the show of various geometries together and if the union between them is inclusive or exclusive.
The spatial filter feature must allow saving multiple geometries and show them in FeatureSelectionLayer
and MaskLayer
Version of C4R ^1.4.5
After the last update of the C4R
version and working with spatial indexes layers, in this case, a quadbin
layer, the quadbin
library seems than isn't imported correctly.
Uncaught TypeError: (0 , A._quadbinZoom) is not a function
at 6676cb64-5f27-45d4-bd28-0d8487d404eb:2:231929
at $A (6676cb64-5f27-45d4-bd28-0d8487d404eb:2:231989)
at te (6676cb64-5f27-45d4-bd28-0d8487d404eb:2:233793)
at 6676cb64-5f27-45d4-bd28-0d8487d404eb:2:243324
at onmessage (6676cb64-5f27-45d4-bd28-0d8487d404eb:2:243445)
You must sign in with [email protected]
credentials. Ping me to provide +info
Version of C4R: 1.4.3
I want to use the method executeModel
to retrieve the data for a formula model in the same way the widgets do in global mode. The issue is that if the payload is too big (and the POST is required) the http call doesn't include the body with the payload and the API returns a 400 error.
Deeping into the code, I can see this method executes makeCall
as the final statement as follows:
return makeCall({
url,
credentials: source.credentials,
opts: {
...opts,
method: isGet ? 'GET' : 'POST',
...(!isGet && { body: JSON.stringify(queryParams) })
}
});
You can see how the body is correctly passed as opts
properties, but if we dig into the makeCall
method, we can see how this is doing nothing with the opts
param in the fetch
method:
response = await fetch(url.toString(), {
headers: {
Authorization: `Bearer ${credentials.accessToken}`
},
signal: opts?.abortController?.signal,
...opts?.otherOptions,
})
To test this, you can use the following call:
const data = _executeModel({
"model": "formula",
"source": {
"id": "1ad570b2-ab65-4d38-87f1-8153a5826e06",
"data": "SELECT * FROM `carto-demo-data.demo_tables.airports` WHERE ST_INTERSECTS(geom, ST_GEOGFROMGEOJSON({\"type\":\"Polygon\",\"coordinates\":[[[-73.97362977542117,40.88551034127466],[-73.9804977096428,40.88525505590902],[-73.98729934431839,40.88449166422513],[-73.99396902447981,40.88322753550163],[-74.0004423778718,40.881474872241135],[-74.00665694027215,40.8792505915634],[-74.01255276176673,40.87657616081757],[-74.0180729879589,40.87347738905398],[-74.02316441036703,40.86998417643237],[-74.02777798059954,40.86613022405908],[-74.0318692832896,40.86195270713292],[-74.03539896321358,40.85749191463605],[-74.03833310250556,40.852790859128255],[-74.04064354440604,40.847894860487415],[-74.04230816053987,40.84285110768259],[-74.04331105930117,40.83770820286829],[-74.04364273352061,40.832515692245714],[-74.04330014620157,40.82732358825008],[-74.04228675372366,40.822181887690256],[-74.04061246652275,40.8171400904888],[-74.0382935478577,40.81224672364775],[-74.03535245186067,40.80754887499792],[-74.03181760263375,40.803091741179756],[-74.02772311669695,40.798918194152385],[-74.02310847160543,40.795068370337134],[-74.0180181240335,40.791579286274704],[-74.01250108106872,40.7884844844132],[-74.00661042886418,40.78581371235102],[-74.00040282316434,40.78359263853708],[-73.99393794654144,40.781842607082204],[-73.98727793746001,40.78058043396701],[-73.98048679652038,40.779818246540906],[-73.97362977542117,40.779563367803384],[-73.96677275432198,40.779818246540906],[-73.95998161338235,40.78058043396701],[-73.95332160430092,40.781842607082204],[-73.94685672767802,40.78359263853708],[-73.94064912197818,40.78581371235102],[-73.93475846977364,40.7884844844132],[-73.92924142680886,40.791579286274704],[-73.92415107923694,40.795068370337134],[-73.91953643414541,40.798918194152385],[-73.91544194820861,40.803091741179756],[-73.91190709898169,40.80754887499792],[-73.90896600298466,40.81224672364775],[-73.90664708431962,40.8171400904888],[-73.9049727971187,40.822181887690256],[-73.90395940464079,40.82732358825008],[-73.90361681732175,40.832515692245714],[-73.90394849154119,40.83770820286829],[-73.90495139030249,40.84285110768259],[-73.90661600643634,40.847894860487415],[-73.9089264483368,40.852790859128255],[-73.91186058762878,40.85749191463605],[-73.91539026755277,40.86195270713292],[-73.91948157024282,40.86613022405908],[-73.92409514047533,40.86998417643237],[-73.92918656288346,40.87347738905398],[-73.93470678907565,40.87657616081757],[-73.94060261057021,40.8792505915634],[-73.94681717297055,40.881474872241135],[-73.95329052636255,40.88322753550163],[-73.95996020652397,40.88449166422513],[-73.96676184119956,40.88525505590902],[-73.97362977542117,40.88551034127466]]]}))",
"type": "query",
"credentials": credentials,
"connection": "carto_dw",
"filtersLogicalOperator": "and",
"queryParameters": [],
"filters": {}
},
"params": {
"column": "*",
"operation": "count"
},
"opts": {}
})
Currently, we already cover three filters:
IN
: filters by certain categoriesBETWEEN
: filters by certain ranges.TIME
: special case of BETWEEN for time filtering.Using a structure of these filters, we can build a filtering function that is used in workers and in getFilterValue for deck.gl DataFilterExtension.
We don't have any way to filter spatially but a certain geometry, for example: a isochrone.
Add new filter called: INTERSECTION
.
Use as value: a geojson.
Returns: if a feature intersects with the given value using @turf/boolean-intersects
.
Problem
AnimatedNumber
could not be imported from C4R library
Why do we need that
We are developing a comparative Formula Widget specific for a project , whose requirements don't match the current component in C4R
AnimatedNumber
component could be reused from the one existing in C4R. In that case we could reuse the component of your code avoiding to repeat code (components, hooks) in our projects.
Proposal
Export AnimatedNumber from C4R so that other projects could use it isolated from FormulaWidget. This component could be really useful for Professional Services.
CC @aaranadev
In PS we are facing the project Telus Insight which has a requirement to support widgets and UI components in both English and French.
The default behavior for UI labels could be as is working right now, but we can add the ability to switch to another language just by putting a properties file with the translation in the root folder.
Currently, a widget like CategoryWidget have a state called selectedCategories
that starts empty by default, when the user selects a category, a filter is applied and the selectedCategories state is updated.
The problem with this approach is that we're managing widget selected categories in two ways: one inside the widget with the selectedCategories
state and another one with the source filters. This cause that if the filter that that widget creates is already added (because, for example, we saved a previous state that we want to apply again) in the source, the widget doesn't know it because it doesn't update its internal state with filter value.
I'd advocate for removing widget internal selectedCategories
state and using filter value as replacement to feed the UI and managing the state.
This improvement will be in every widget.
Hey!
From the guide and doc I saw that it's work fine in CRA and even generates some files which needed, but is it works by the same principle in Next application?
Previous version of C4R: 1.3.0
Actual version of C4R: 1.5.0-alpha.1
executeSQL from @carto/react-api
{
"error": "Invalid queryParameters, it must be a list of parameters",
"status": 400,
"message": "Invalid queryParameters, it must be a list of parameters"
}
{
"client": "carto-react",
"q": "SELECT ....",
"queryParameters": "[]",
"access_token": "eyJhbGciOiJSUzI1NiIsInR..."
}
Seems like in the new version, the queryParameters is required to specify any value to avoid 400 error like this:
const data = await executeSQL<GetCategoriesRes | Record<string, number>[]>({
// @ts-ignore
credentials,
query,
connection,
queryParameters: null, // TODO: avoid error
opts: { abortController },
});
I just check inside and i found the posible bug is on the SQL.js
function createRequest
. (line.58)
function createRequest({ credentials, connection, query, opts = {}, **queryParameters = []** }) {
const { abortController, ...otherOptions } = opts;
const { apiVersion = API_VERSIONS.V2 } = credentials;
const rawParams = {
client: CLIENT,
q: query?.trim(),
...otherOptions,
queryParameters: queryParameters ? JSON.stringify(queryParameters) : undefined
};
If i downgrade the versions i don't have this issue.
Sometimes the content of the widgets is not self explanatory, and customers complain about not understanding the information.
Clear information is key in the site selection, we need to be transparent in terms of communication to build trust and reliability for our customers.
Add an optional "i" in the upper right customer of the widgets that would display explanatory text upon clicking.
CC @aaranadev
In products like Site Selection or CPG, there is a feature called Drop a Pin that provides the ability to pin a point in the map through a geometry based on a buffer or isochrone to get some insights into this catchment area.
To cover this feature, Carto4React could include this component as a widget with some options like:
Parameter queryParameters
is now supported in the SQL & Map APIs, so we should allow this parameter to be received in carto-react
in order to have the widgets in sync with the actual features shown in the map.
We developed a PoC to show a typical datepicker use case
queryParameters
need to be pass along the following packages / functions:
SQL -
executeSQL
Hooks -useCartoLayerProps
cartoSlice -
addSource
{
query: `SELECT * FROM \`heartquakes\` WHERE date >= @start AND date <= @end`,
queryParameters: [
{
name: "start",
type: "date",
value: "2020-01-01"
},
{
name: "end",
type: "date",
value: "2021-01-01"
}
]
}
The BarWidgetUI isn't working correctly when we use multiple data and modify the array.
Demo:
The problem is the component echarts-for-react
custom that does not dispatch the event, I've changed own custom to the original, and works for me with a blink event.
Demo:
I've looked and I've seen that we've used a PR opened in the echart-for-react
repository.
Own:
echart-for-react:
Many projects from PS (Site Selection, Initiative, etc) need the functionality of comparing two or more sets of widgets side to side, comparing data from many different sources in different form and aggregations.
You can check the zeplin designs for projects Site Selection and Initiative to get a grasp on the visual aspect here.
Implementing his feature right now is not possible without ejecting from the Carto4React widgets UI and models completely and rebuilding them all from scratch. The current widgets available in the Carto4React library do not provide this functionality.
This causes all PS projects that require this functionality to take care of building the whole widget stack from scratch every time. Every time widgets are built according to the project specific use cases and customizations, thus reducing compatiibility of widgets built between project and defeating the purpose of carto4react library of standarization of the carto brand and look and feel across all its related apps and products.
If carto4react would have a comparative widgets stack, that could be used to share the same implementation across many projects and reduce the time of development for the applications, focussing on providing real value for our customers.
The proposed implementation consists on developing new components for the comparative widgets, but only adding the presentation (UI) part.
Developing the logic to extract the data from the models would be left out of the scope of this RFC.
Note: it is important to separate the current single-dataset widget implementation from the comparative widgets implementation in order to avoid breaking changes in the library release proccess. In my opinion, the current UI layer of the widgets provided by the carto4react library are complex enough and we should not add more complexity to them by implementing this feature in the same components. Separating normal single-dataset widgets from multiple-dataset comparative widgets UI layer would provide for a simpler interface, not disrupting the current experience for any user, adding this new feature seamlessly and following good practices of the industry.
The implemented design would be the one from site selection from the first section above.
Here are some code snippets displaying the shape of the new comparative widgets UI layer:
<MultipleFormulaWidgetUI
data={[1245, 3435.9]}
colors={[{ note: palette.comparisonPrimary }, { note: palette.comparisonSecondary }]}
labels={[{ note: 'reference POI name' }, { note: 'compared POI name' }]}
formatter={numberFormatter}
animated={true}
/>
<MultiplePieWidgetUI
names={['POI name 1', 'POI name 2']}
data={[
[{ name: 'column 1', value: 40 }, { name: 'column 2', value: 60 }],
[{ name: 'column 1', value: 30 }, { name: 'column 2', value: 70 }],
]}
labels={[['column label 1', 'column label 2'], ['column label 1', 'column label 2']]}
colors={[['purple', 'green'], ['red', 'orange']]}
/>
<MultipleHistogramWidgetUI
data={[[40, 50, 60], [50, 60, 70]]}
labels={['column label 1', 'column label 2']}
names={['POI name 1', 'POI name 2']}
totals={[150, 180]}
colors={['#f00', '#ff0']}
/>
Currently, there are methods in the worker for:
Load data:
Consume data (grouped):
There are some problems with that approach:
GET_RAW_FEATURES
that receive source filters (also the prop proposed in task 2 to be able to filter by viewport). Also, create a model that execute this method.VIEWPORT_FEATURES_FORMULA
as GET_FORMULA
(the same for other consume-data methods)currentViewportFeatures
variable for grouping.currentGeoJSON
if defined, otherwise use currentViewportFeatures
variable for grouping.VIEWPORT_FEATURES
as LOAD_TILES_VIEWPORT_FEATURES
and VIEWPORT_FEATURES_GEOJSON
as CALCULATE_GEOJSON_VIEWPORT_FEATURES
.Describe the bug
Hi guys! I've detected a bug in useCartoLayerProps
derived from Geojson support. We have tried using it in a GeoJSON layer but we have several issues.
The workflow is set to be used in onDataLoad
that is used the Layer, but the problem is that GeoJSON Layer hasn't onDataLoad
prop.
We have resolved this issue by creating a new CompositeLayer and adding a new prop to the Layer called onDataLoad
that is used to set the data in the Layer.
GeoJSON uses the feature useGeojsonFeatures
to set the data in the Layer, but this feature uses setGeoJsonLoaded
to set the flag geoJsonLoaded
to true. This flag is used in useCartoLayerProps
to put the data in the Layer, but that function is not exist in useFeaturesCommons
which is used in useGeojsonFeatures
so the workflow is not worked.
export default function useGeojsonFeatures({
source,
viewport,
spatialFilter,
uniqueIdProperty,
debounceTimeout = 250,
}: any) {
const [
debounceIdRef,
isGeoJsonLoaded,
setGeoJsonLoaded,
clearDebounce,
stopAnyCompute,
setSourceFeaturesReady,
] = useFeaturesCommons({ source })
const onDataLoad = useCallback(
(geojson) => {
// @ts-ignore
stopAnyCompute()
// @ts-ignore
setSourceFeaturesReady(false)
// @ts-ignore
executeTask(sourceId, Methods.LOAD_GEOJSON_FEATURES, { geojson })
// @ts-ignore
.then(() => setGeoJsonLoaded(true))
// .catch(throwError)
},
[sourceId, setSourceFeaturesReady, stopAnyCompute, setGeoJsonLoaded],
)
Hello.
I need create layer for my map dynamically instead of static like all the examples.
How I could do this?
Thanks
We are currently not able to control the widgets size, I think we can control them horizontally but not vertically.
We are defining a new way of working where we don't always display the widgets in a sidebar and we need to control the size so we can modify the display configuration.
We would need modularized widgets so we can design new and dynamic views and layouts (horizontally and vertically).
CC @aaranadev
Many projects from PS need the functionality of filtering some layers (and widgets) based on territory (state, city, county, DMA, FSA, ...). Some examples of projects that use this feature would be Telus Insight or Radarview, where a user wants to focus the data exploration on a specific geometry that comes from a well-known territory.
To cover this functionality, the framework C4R could provide a widget composed of a UI component to select a territory (single dropdown select or autocomplete) that uses a source to show the geometry in the map by using the Spatial Filter to filter some layers. An extra ball for business strategy could be to support directly territory geometries from the DO, like https://carto.com/spatial-data-catalog/browser/geography/cdb_block_96b823a2/ or https://carto.com/spatial-data-catalog/browser/geography/mbi_counties_46ea8aaa
Some options for this widget can be:
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.