How to add a label over slider selector - plotly-dash

How can I get a little label telling me what number I have selected on a slider in Dash for python? I am using dash_core_components.Slider().
I essentially want to have something with the little blue "500" label shown on the first slider here.

Update on this issue: always-visible tooltips (i.e. value labels) are now available for dcc.Slider() and dcc.RangeSlider() as of Dash 1.0 with the argument tooltip:
import dash
import dash_core_components as dcc
...
dcc.Slider(..., tooltip = { 'always_visible': True })
You can install Dash >=1.0 with
pip install dash
The latest version of Dash is 1.9.1

The first example given here shows how to update a label according to the value of the slider. I have modified it a bit in the code below to use a Slider as you wanted (instead of RangeSlider), and to update the label while dragging (instead of on mouse-up):
import dash
import dash_html_components as html
import dash_core_components as dcc
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(id='slider-wrapper', children=[
dcc.Slider(
id='my-slider',
min=0,
max=20,
step=0.5,
value=5,
updatemode='drag',
),
html.Div(id='output-container-range-slider'),
# Need onload script: $('#slider-wrapper .rc-slider-handle').appendChild($('#output-container-range-slider'));
])
#app.callback(
dash.dependencies.Output('output-container-range-slider', 'children'),
[dash.dependencies.Input('my-slider', 'value')])
def update_output(value):
return str(value)
if __name__ == '__main__':
app.run_server(debug=True)
Unfortunately, this does not place the label as a small flag above the slider as you wanted. There is no simple solution for that, but you could use JavaScript to make the label div follow the slider handle, and execute it on page load.
You can add your own CSS and JavaScript to dash apps, so add the following snippets:
CSS:
#slider-wrapper {
margin-top: 100px;
}
#output-container-range-slider {
position: absolute;
left: -12px;
top: -40px;
background-color: #428BCA;
color: #FFFFFF;
font-weight: bold;
height: 35px;
padding: 5px;
width: 34px;
text-align: center;
display: none; /* Hide flag until it is moved */
}
JS:
function appendToSlider() {
var flag = document.getElementById('output-container-range-slider');
document.querySelector('#slider-wrapper .rc-slider-handle').appendChild(flag);
flag.style.display = 'block'; // Make visible after moving
}
setTimeout(appendToSlider, 2000);
Notice the workaround using setTimeout - ideally you want the appendToSlider function to get executed right after the slider is rendered, if there was such an event to attach it to. I could not find a way to that, but that is an issue for a separate thread.

Related

Svelte - Carbon component import breaks debugging

I've setup a Svelte and Electron that uses Carbon Components. I have it working for the most part, but I'm stuck at debugging.
Here's a sample component I'm using for testing:
<script lang="ts">
import { Tile } from 'carbon-components-svelte'
let name = 'John Doe'
function test() {
console.log('You clicked me!')
}
</script>
<div>
<Tile>
<h2>{name}</h2>
<button on:click={test}>Click me</button>
</Tile>
</div>
When I load the component into a dev environment, I can't set breakpoints in Chrome's dev tools:
However, if I open my svelte.config.js, which initially look:
import sveltePreprocess from 'svelte-preprocess'
import { optimizeImports } from "carbon-preprocess-svelte";
export default {
preprocess: [ sveltePreprocess(), optimizeImports() ]
}
And remove the optimizeImports() call, then breakpoints work correctly.
Does anyone have any clue why this is happening? Clearly it's something to do with the carbon-preprocess-svelte library. I created a basic project that reproduces the issue: https://github.com/troncoso/carbon-svelte-bug
TL;DR: The inline source map is kinda broken, it's a bug in carbon-preprocess-svelte.
When you use: import { Tile } from 'carbon-components-svelte', the default module resolution will import the named export Tile from a big umbrella file at carbon-components-svelte/lib/index.js, which is a big minified code bundle. Clearly this is not optimal.
optimizeImports from carbon-preprocess-svelte is a preprocessor that tries to optimize it by reading your import code then rewriting it into sth like import Tile from "carbon-components-svelte/src/Tile/Tile.svelte".
Obviously there's some kind of bug in this preprocessor, that produces a broken source map. To be precise, it produces a source map that misses out some mapping positions. Chrome devtool relies on these mapping positions to set a breakpoint. When it's missing, it cannot set one.
When you manually rewrite the import, you skip this preprocessor, thus you avoid the wrong behavior. This is consistent to your current finding.
We might rest our case here and conclude that you should avoid using optimizeImports for now, and just report the bug to carbon team. Below will dive into more details.
This is the inline source map of the bad case:
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FDQSxJQUFBLE1BQUEsK0NBQUE7Ozs7Ozs7Ozs7Ozs7O2FBUThCLFVBQ2xCO3VCQUFDLEdBQUs7Ozs7O0dBRGhCLFVBRVE7Ozs7O3dEQUZVLEdBQVM7Ozs7O3VEQUNoQixHQUFLOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztLQVJsQixLQUFBLEdBQUEsQ0FBQTs7T0FDQSxTQUFBO2tCQUNBLEtBQUEsSUFBQSxDQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7IiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIkNvdW50ZXIuc3ZlbHRlIl0sInNvdXJjZXNDb250ZW50IjpbIjxzY3JpcHQgbGFuZz1cInRzXCI+XG4gIGltcG9ydCBUaWxlIGZyb20gJ2NhcmJvbi1jb21wb25lbnRzLXN2ZWx0ZS9zcmMvVGlsZS9UaWxlLnN2ZWx0ZSdcbiAgbGV0IGNvdW50OiBudW1iZXIgPSAwXG4gIGNvbnN0IGluY3JlbWVudCA9ICgpID0+IHtcbiAgICBjb3VudCArPSAxXG4gIH1cbjwvc2NyaXB0PlxuXG48VGlsZT5cbiAgPGJ1dHRvbiBvbjpjbGljaz17aW5jcmVtZW50fT5cbiAgICBDbGlja3M6IHtjb3VudH1cbiAgPC9idXR0b24+XG48L1RpbGU+XG5cbjxzdHlsZT5cbiAgYnV0dG9uIHtcbiAgICBmb250LWZhbWlseTogaW5oZXJpdDtcbiAgICBmb250LXNpemU6IGluaGVyaXQ7XG4gICAgcGFkZGluZzogMWVtIDJlbTtcbiAgICBjb2xvcjogI2ZmM2UwMDtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDI1NSwgNjIsIDAsIDAuMSk7XG4gICAgYm9yZGVyLXJhZGl1czogMmVtO1xuICAgIGJvcmRlcjogMnB4IHNvbGlkIHJnYmEoMjU1LCA2MiwgMCwgMCk7XG4gICAgb3V0bGluZTogbm9uZTtcbiAgICB3aWR0aDogMjAwcHg7XG4gICAgZm9udC12YXJpYW50LW51bWVyaWM6IHRhYnVsYXItbnVtcztcbiAgICBjdXJzb3I6IHBvaW50ZXI7XG4gIH1cblxuICBidXR0b246Zm9jdXMge1xuICAgIGJvcmRlcjogMnB4IHNvbGlkICNmZjNlMDA7XG4gIH1cblxuICBidXR0b246YWN0aXZlIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDI1NSwgNjIsIDAsIDAuMik7XG4gIH1cbjwvc3R5bGU+XG4iXX0=
And here's the one of the good case:
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FDQSxJQUFBLE1BQUEsK0NBQUE7Ozs7Ozs7Ozs7Ozs7O2FBUThCLFVBQ2xCO3VCQUFDLEdBQUs7Ozs7O0dBRGhCLFVBRVE7Ozs7O3dEQUZVLEdBQVM7Ozs7O3VEQUNoQixHQUFLOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztLQVJsQixLQUFBLEdBQUEsQ0FBQTs7T0FDQSxTQUFBO2tCQUNBLEtBQUEsSUFBQSxDQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7IiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIkNvdW50ZXIuc3ZlbHRlIl0sInNvdXJjZXNDb250ZW50IjpbIjxzY3JpcHQgbGFuZz1cInRzXCI+XG4gIGltcG9ydCBUaWxlIGZyb20gJ2NhcmJvbi1jb21wb25lbnRzLXN2ZWx0ZS9zcmMvVGlsZS9UaWxlLnN2ZWx0ZSdcbiAgbGV0IGNvdW50OiBudW1iZXIgPSAwXG4gIGNvbnN0IGluY3JlbWVudCA9ICgpID0+IHtcbiAgICBjb3VudCArPSAxXG4gIH1cbjwvc2NyaXB0PlxuXG48VGlsZT5cbiAgPGJ1dHRvbiBvbjpjbGljaz17aW5jcmVtZW50fT5cbiAgICBDbGlja3M6IHtjb3VudH1cbiAgPC9idXR0b24+XG48L1RpbGU+XG5cbjxzdHlsZT5cbiAgYnV0dG9uIHtcbiAgICBmb250LWZhbWlseTogaW5oZXJpdDtcbiAgICBmb250LXNpemU6IGluaGVyaXQ7XG4gICAgcGFkZGluZzogMWVtIDJlbTtcbiAgICBjb2xvcjogI2ZmM2UwMDtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDI1NSwgNjIsIDAsIDAuMSk7XG4gICAgYm9yZGVyLXJhZGl1czogMmVtO1xuICAgIGJvcmRlcjogMnB4IHNvbGlkIHJnYmEoMjU1LCA2MiwgMCwgMCk7XG4gICAgb3V0bGluZTogbm9uZTtcbiAgICB3aWR0aDogMjAwcHg7XG4gICAgZm9udC12YXJpYW50LW51bWVyaWM6IHRhYnVsYXItbnVtcztcbiAgICBjdXJzb3I6IHBvaW50ZXI7XG4gIH1cblxuICBidXR0b246Zm9jdXMge1xuICAgIGJvcmRlcjogMnB4IHNvbGlkICNmZjNlMDA7XG4gIH1cblxuICBidXR0b246YWN0aXZlIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDI1NSwgNjIsIDAsIDAuMik7XG4gIH1cbjwvc3R5bGU+XG4iXX0=
They're base64 encoded json, if we decoded them, we get:
bad case:
{
"version": 3,
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;OAAiB,IAAA,MAAA,+CAAA;;;;;;;;;;;;;;aASa,UAClB;uBAAC,GAAK;;;;;GADhB,UAEQ;;;;;wDAFU,GAAS;;;;;uDAChB,GAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;",
"names": [],
"sources": ["Counter.svelte"],
"sourcesContent": [
"<script lang=\"ts\">\n import { Tile } from 'carbon-components-svelte'\n let count: number = 0\n const increment = () => {\n count += 1\n }\n</script>\n\n<Tile>\n <button on:click={increment}>\n Clicks: {count}\n </button>\n</Tile>\n\n<style>\n button {\n font-family: inherit;\n font-size: inherit;\n padding: 1em 2em;\n color: #ff3e00;\n background-color: rgba(255, 62, 0, 0.1);\n border-radius: 2em;\n border: 2px solid rgba(255, 62, 0, 0);\n outline: none;\n width: 200px;\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n }\n\n button:focus {\n border: 2px solid #ff3e00;\n }\n\n button:active {\n background-color: rgba(255, 62, 0, 0.2);\n }\n</style>\n"
]
}
good case:
{
"version": 3,
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;OACA,IAAA,MAAA,+CAAA;;;;;;;;;;;;;;aAQ8B,UAClB;uBAAC,GAAK;;;;;GADhB,UAEQ;;;;;wDAFU,GAAS;;;;;uDAChB,GAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KARlB,KAAA,GAAA,CAAA;;OACA,SAAA;kBACA,KAAA,IAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;",
"names": [],
"sources": ["Counter.svelte"],
"sourcesContent": [
"<script lang=\"ts\">\n import Tile from 'carbon-components-svelte/src/Tile/Tile.svelte'\n let count: number = 0\n const increment = () => {\n count += 1\n }\n</script>\n\n<Tile>\n <button on:click={increment}>\n Clicks: {count}\n </button>\n</Tile>\n\n<style>\n button {\n font-family: inherit;\n font-size: inherit;\n padding: 1em 2em;\n color: #ff3e00;\n background-color: rgba(255, 62, 0, 0.1);\n border-radius: 2em;\n border: 2px solid rgba(255, 62, 0, 0);\n outline: none;\n width: 200px;\n font-variant-numeric: tabular-nums;\n cursor: pointer;\n }\n\n button:focus {\n border: 2px solid #ff3e00;\n }\n\n button:active {\n background-color: rgba(255, 62, 0, 0.2);\n }\n</style>\n"
]
}
Problem lies in the mappings field. You can make sense of both files with the source map decoder then compare by clicking the dump button. You'll see that some mapping information are simply missing in the bad case file.
This article Anatomy of source maps, if it interests you, will guide you through the technical details of the js source map format (to understand the mysterious ;;OAAiB,IAAA,MAAA,+CAAA;; part).
But for now let's simply read the human-friendly dump:
Counter.svelte,137,27,5,0,null
translates to:
position 137:27 from compiled file `Counter.js`
maps to
position 5:0 from original source file `Counter.svelte`
And here's the dump for both files.
bad case mapping dump:
Counter.svelte,24,7,1,17,null
Counter.svelte,24,11,1,17,null
Counter.svelte,24,17,1,17,null
Counter.svelte,24,64,1,17,null
Counter.svelte,38,13,10,30,null
Counter.svelte,38,23,11,12,null
Counter.svelte,39,23,11,13,null
Counter.svelte,39,26,11,18,null
Counter.svelte,44,3,10,2,null
Counter.svelte,44,13,12,10,null
Counter.svelte,49,56,10,20,null
Counter.svelte,49,59,10,29,null
Counter.svelte,54,55,11,13,null
Counter.svelte,54,58,11,18,null
good case mapping dump:
Counter.svelte,24,7,2,0,null
Counter.svelte,24,11,2,0,null
Counter.svelte,24,17,2,0,null
Counter.svelte,24,64,2,0,null
Counter.svelte,38,13,10,30,null
Counter.svelte,38,23,11,12,null
Counter.svelte,39,23,11,13,null
Counter.svelte,39,26,11,18,null
Counter.svelte,44,3,10,2,null
Counter.svelte,44,13,12,10,null
Counter.svelte,49,56,10,20,null
Counter.svelte,49,59,10,29,null
Counter.svelte,54,55,11,13,null
Counter.svelte,54,58,11,18,null
Counter.svelte,134,5,3,0,null
Counter.svelte,134,10,3,0,null
Counter.svelte,134,13,3,0,null
Counter.svelte,134,14,3,0,null
Counter.svelte,136,7,4,0,null
Counter.svelte,136,16,4,0,null
Counter.svelte,137,18,5,0,null
Counter.svelte,137,23,5,0,null
Counter.svelte,137,27,5,0,null
Counter.svelte,137,28,5,0,null
Read #hackape's answer for details. But ultimately it seems like a bug with carbon-preprocess-svelte, specifically the optimizeImports() plugin. I created an issue on that project: https://github.com/carbon-design-system/carbon-preprocess-svelte/issues/18
In the meantime, I came up with a solution that made sure the source maps work and I still get tree shaking. I created a carbon.ts file:
import { Button } from 'carbon-components-svelte/src/Button'
import { Tile, ClickableTile } from 'carbon-components-svelte/src/Tile'
import { StructuredList, StructuredListHead, StructuredListBody, StructuredListRow,
StructuredListCell } from 'carbon-components-svelte/src/StructuredList'
import { Header, HeaderGlobalAction, HeaderUtilities, Content }
from 'carbon-components-svelte/src/UIShell'
import { Theme } from 'carbon-components-svelte/src/Theme'
import { TooltipDefinition } from 'carbon-components-svelte/src/TooltipDefinition'
export {
Button,
Tile,
ClickableTile,
StructuredList,
StructuredListBody,
StructuredListCell,
StructuredListHead,
StructuredListRow,
Header,
HeaderGlobalAction,
HeaderUtilities,
Theme,
TooltipDefinition,
Content
}
When I need a component, I just add it to this file. Then I import the component like this:
<script lang="ts">
import { Button } from '#/components/carbon'
</script>
I know I could have just done the imports in the svelte files themselves, but this way when the bug is fixed I can much more easily find and replace all the imports. Just search for "#/components/carbon" and replace it with "carbon-components-svelte".

show legend by default on a kepler gl point map

I would like to export my point map done using kepler gl to an interactive html file. This interactive html file should have a legend (colour key) visible by default. What I mean is i shouldn't click on the show legend button to see the meaning of colours on the map - the show legend should be visible and fixed by default after exporting. Is this possible? Can anyone please guide me on how to achive this?
I am not sure about html exporting thing, and I am also not sure if you mean how to do it with the demo, basically using a front-end (GUI), or by the API components.
Since I made the legend open by default using react, I'll talk about it.
/* store.js */
// some of your import
import { createStore, applyMiddleware } from "redux";
import keplerGlReducer, { uiStateUpdaters } from 'kepler.gl/reducers';
import { taskMiddleware } from "react-palm/tasks";
// rest of them
const customizedKeplerGlReducer = keplerGlReducer
.initialState({
uiState: {
mapControls: {
...uiStateUpdaters.DEFAULT_MAP_CONTROLS,
mapLegend: {
show: true,
active: false
},
/* another map controls */
//toggle3d: {
// show: true
//},
}
}
});
export default createStore(customizedKeplerGlReducer, {}, applyMiddleware(taskMiddleware));
This way your legend will be open (clicked) by default, unless this is not what you asked for.
Full example by kepler.gl

i18next/i18n Change Language not working with the whole website

I'm doing a react-typescript app where I need to be able to translate the site. I'm using the i18next library. In the main page the user can change the language using a button which runs this method.
changeLang(lang:string):any{
i18next.changeLanguage(lang).then(() => {
this.props.close();
i18next.options.lng = lang;
});
}
This works great for changing the language of the main page. However when I go to the next page it goes back to the original language. I can't seem to get the whole site running on a different language.
My index.tsx file
import React from 'react';
import ReactDOM from 'react-dom';
import './styles/index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import Amplify from 'aws-amplify';
import awsmobile from "./aws-exports";
import * as enTranslations from "./locales/en"; /* This import refers to all of the texts in english */
import * as ptTranslations from "./locales/pt" /* This import refers to all of the texts in portuguese */
import {initReactI18next, I18nextProvider} from 'react-i18next'; /* Import needed for the use of the dictionary/translation */
import LanguageDetector from "i18next-browser-languagedetector"; /* Import needed for the use of the dictionary/translation */
import i18next from "i18next"; /* Import needed for the use of the dictionary/translation */
/* Configure Amplify on the client so that we can use it to interact with our backend services */
Amplify.configure(awsmobile);
/* Extract the translations */
const resources = {
en: {messages: enTranslations},
pt: {messages: ptTranslations}
};
/* Setting up the dictionary/translator */
const i18n = i18next.use(LanguageDetector).use(initReactI18next);
i18n.init({
react: {
wait: true,
},
resources: resources,
lng: 'pt', /* Main Language */
fallbackLng: 'en',
keySeparator: '.',
interpolation: {
escapeValue: false,
},
ns: ['messages'],
defaultNS: 'messages',
fallbackNS: [],
});
ReactDOM.render(
<I18nextProvider i18n={i18n}>
<App />
</I18nextProvider>,
document.getElementById('root')
);
reportWebVitals();
All the pages on my website have the following structure:
import { Component } from "react"
import { AuthProps } from "../../#types/auth" // Imports Auth props used to authenticate user
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome" /* Import needed to be able to use the custom FontAwesome font */
import { faChevronLeft } from "#fortawesome/free-solid-svg-icons" /* Import needed to get the desired font elements */
import i18next from "i18next"; /* Import needed for the use of the dictionary/translation */
import { withTranslation } from 'react-i18next'; /* Import needed for the use of the dictionary/translation */
import '../styles/views/change-password-confirm.css';
/**
* Simple page that tells our user that his password has been changed
*/
class ChangePasswordConfirmation extends Component<AuthProps> {
render() {
return (
<div className="change-password-confirm-background">
<div className="change-password-confirm-main">
<div className="change-password-confirm-container">
{/* Button used to go back to the login page */}
<FontAwesomeIcon icon={faChevronLeft}></FontAwesomeIcon>
<h1>{i18next.t('ChangePasswordConfirm.catchphrase')}</h1>
<p>{i18next.t('ChangePasswordConfirm.secondaryText')}</p>
</div>
</div>
</div>
)
}
}
export default withTranslation()(ChangePasswordConfirmation)
As you can see I use i18next.t('my-key') to get the translations and I export every component/page with "withTranslation()". So I don't know why the whole website doesn't change language. Can anyone help me?
So I think the problem here is that you're importing i18next from the library on every page. What you're supposed to do is that you export the i18n you created in your index file and import it in every other file instead of importing a new i18next for every component you have there. Also try putting the language value of the whole website in some kinda global context incase you wanna change the language in other pages. I hope this was helpful!
I was running into the same issue with i18n.changeLanguage() method. So,I end up fixing this by getting the current language that the user is using in their browser,
const getUserLanguage = () => window.navigator.userLanguage || window.navigator.language;
window.navigator.language works for most of the modern browsers but to be on the safe side adding window.navigator.userLanguage
Now get the userlanguage by calling the getUserLangauge() method. And based on that change the language.
Something like this,
i18n.use(initReactI18next).init({
resources,
lng: `${userLanguage}`,
fallbackLng: 'en',
keySeparator: false,
interpolation: {
escapeValue: false,
},
});
But the downside is that we need to refresh the page when we switch the language. Note that, in production, it is just going to check the user's browser setting and render the specific language based on that. Users are not able to switch the language(the only way to switch is to change their language setting in their browser and refresh the page)
Just putting out there as someone can have the same issue, double check your imports of locales/lang/translations.json. I had a bad copy paste that make two of my language point to the same translation file, hence it was not translating anything

How to reserve space for responsive img (stop blocks jumping down)

How to solve a problem of jumping down blocks after image load if image should be responsive?
Codesandbox.
Info:
Image should shrink on window resize
Image max-width is it's own width
We don't know image size
JS can be used
Idea:
If it's not possible without any image size data, then can it be done only with image aspect ratio?
If you know image aspect ratio, you can calculate block height and put responsive image inside with some unused space (at least unused space will be not big on small window size).
Image loading:
Image loaded:
Html:
import React from "react";
import "./styles.css";
const img =
"https://s3.amazonaws.com/images.seroundtable.com/google-css-images-1515761601.jpg";
export default function App() {
return (
<div className="app">
<img alt="" src={img + `?${Date.now()}`} className="img" />
<h1>I always jump down :(</h1>
</div>
);
}
CSS:
.app {
box-sizing: border-box;
}
.img {
max-width: 100%;
}
h1 {
background-color: red;
}
AS #DBS sad, it seems that only solution is to wrap image in div block with calculated height based on window.width and aspect ratio (in my case i know it). If there is any better solutions, don't hesitate to answer.
Sandbox solution example.
import React from "react";
import "./styles.css";
import styled from "styled-components";
const aspectRatio = [1, 5];
const img =
"https://s3.amazonaws.com/images.seroundtable.com/google-css-images-1515761601.jpg";
export default function App() {
return (
<div className="app">
<StyledDiv>
<img alt="" src={img + `?${Date.now()}`} className="img" />
</StyledDiv>
<h1>I always jump down :(</h1>
</div>
);
}
const StyledDiv = styled.div`
height: calc(100vw / ${aspectRatio[1]});
overflow-y: hidden;
`;
As you've already determined, even when knowing the aspect ratio, we still have the problem of not knowing the width of the image, making the aspect ratio useless if we are to conform to your requirement Image max-width is it's own width.
What would work is a build time solution (if you know your image urls at build time). There are plenty of server side rendering options for react apps and I will not elaborate on them.
Instead there's a super rudimentary DIY approach.
Create a Node script to run on your server. It will build JSON file with image dimensions. Let's call it "buildImageDimensionData.js". It will output a JSON file imageDimensions.json.
var probe = require("probe-image-size"); // For getting image dimensions without downloading full image
const fs = require("fs"); // For writing our image dimensions to file
// Supply the image urls by hand, or build a webpack script to extract them etc...
const imageUrls = [
`http://localhost:5000/image1.jpg`,
`http://localhost:5000/image2.jpg`,
];
async function getImageDimensionsByUrl(urlList) {
const probePromises = urlList.map(async (imageUrl) => await probe(imageUrl));
let probedImagesData = [];
try {
probedImagesData = await Promise.all(probePromises);
} catch (error) {
// We are programming gods and there will be no error.
}
return probedImagesData.reduce((accumulator, imageData) => {
accumulator[imageData.url] = [imageData.width, imageData.height];
return accumulator;
}, {});
}
getImageDimensionsByUrl(imageUrls).then((dimensions) =>
fs.writeFileSync("imageDimensions.json", JSON.stringify(dimensions))
);
Run the script before build. For example, if you're using Create React App, in package.json:
...
"start": "buildImageDimensionData && react-scripts start",
"build": "buildImageDimensionData && react-scripts build",
...
In your react image component, import imageDimensions.json and use the data to set dimensions for image wrapper based on url of the image.
Note this is more for demonstraing how it could work and there will definitely be packages for doing this better.
Another, albeit poor option is of course just waiting for the images to load before rendering your other content so no jumps occur.
To ignore the jump down, you have to set margin of the next sibling to 0,
.app {
box-sizing: border-box;
}
.img {
max-width: 100%;
}
.app :nth-child(2) {
margin:0px
}

Error on bodymovin animation in react native?

I am using sample.json image file which is for bodymovin animation in my page through Lottie for React Native.
I am getting the image but the image is not fully retrieved, some parts of the image is missing and also in some side of the image, green color pasted on the image.
But i checked the sample.json through online json image viewr. But there is no issue with the image from the source
here is issue https://i.stack.imgur.com/yFZfg.jpg
here is original image https://i.stack.imgur.com/4sBzg.jpg
so here is my code
import React from 'react';
import { Animated, Easing, easing } from 'react-native';
import Animation from 'lottie-react-native';
export default class BasicExample extends React.Component {
constructor(props) {
super(props);
this.state = {
progress: new Animated.Value(0.5),
};
}
componentDidMount() {
this.startAnimation();
}
startAnimation() {
Animated.timing(
this.state.progress,
{
toValue: 1,
from: 0,
to: 1,
duration: 5000,
}
)
.start(() => {
// Restart at end
this.state.progress.setValue(0);
this.startAnimation();
});
}
render() {
const easing = Easing.inOut(Easing.quad);
const { Animate } = this.props;
return (
<Animation
style={{
width: 300,
height: 300,
}}
source={this.props.Animate}
progress={this.state.progress}
/>
);
}
}
i installed lottie npm also.
so this is my issue please help me to overcome this
Thanks in advance
UPDATE: Now that I looked your code closer I found out that you're animating by changing the value of progress prop. That's not how to do it. You need to use ref for referring the animation to.
return (
<Animation
ref={(animation) => this.myAnimation = animation}
style={{
width: 300,
height: 300,
}}
source={this.props.Animate}
/>
);
And then:
componentDidMount() {
this.startAnimation();
}
startAnimation() {
this.myAnimation.play();
}
OLD ANSWER:
Your code seems perfectly legit and if you see an image, it proofs that you're doing it right.
I'd assume there's either something wrong with the JSON or then Lottie just interprets values wrong.
I've encountered small styling issues on Android devices, but not with iOS. And they're mostly related to alignment.
If you don't get any proper answers here in SO, I'd suggest you to file an issue to github (see this for instance: https://github.com/airbnb/lottie-react-native/issues/182)