Openlayer tiles do not render on build - css

I am using ol version 7.1 with react 18.04 and next 13
This is the code
import { Feature } from "ol";
import { Point } from "ol/geom";
import TileLayer from "ol/layer/Tile";
import VectorLayer from "ol/layer/Vector";
import Map from "ol/Map";
import "ol/ol.css";
import { fromLonLat } from "ol/proj";
import OSM from "ol/source/OSM";
import VectorSource from "ol/source/Vector";
import Icon from "ol/style/Icon";
import Style from "ol/style/Style";
import View from "ol/View";
import type { FunctionComponent, PropsWithChildren } from "react";
import { useEffect, useRef } from "react";
export const Map: FunctionComponent<
PropsWithChildren<{ coordinates: number[] }>
> = ({ children, coordinates }) => {
const transformedCoordinates = fromLonLat(coordinates);
const mapElement = useRef<HTMLDivElement>(null);
const mapRef = useRef<Map>();
useEffect(() => {
const point = new Point(transformedCoordinates);
const feature = new Feature({ geometry: point });
const drawSource = new VectorSource({ wrapX: false, features: [feature] });
const svg = 'some svg'
const style = new Style({
image: new Icon({
opacity: 1,
src,
scale: 0.08,
}),
});
if (mapElement.current && !mapRef.current) {
mapRef.current = new Map({
target: mapElement.current ?? undefined,
layers: [
new TileLayer({
source: new OSM(),
}),
new VectorLayer({
source: drawSource,
style,
}),
],
view: new View({
center: transformedCoordinates,
zoom: 14,
}),
});
}
}, [transformedCoordinates]);
return (
<div
id="map"
className="map"
style={{ height: "100%", width: "100%" }}
ref={mapElement}
>
{children}
</div>
);
};
Used this way:
<div className="relative h-[250px] w-[350px]">
<Map coordinates={data} />
</div>
Using next dev is rendering the map totally fine:
But using next build, does not display the map, but just the outer style. What am I missing?
I tried adding some Scripts which I saw from ol, but the threads were pretty old and it did not change anything.
I do not know where ol gets the map styling etc. from. It seems like somehow this gets missing in build mode?
I am also using JOY ui & tailwind css, not sure if there are classnames which could override something in ol?

Try setting swcMinify to false in next.config. Since Next v13 swcMinify is true by default.

Related

Why my Vue3 Webcomponent has no css in its shadow dom

I have built a Vue3 web component and try to embed it in an other project.
This is my main.js for building the web component.
import {createApp, getCurrentInstance, h} from 'vue'
import App from './App.vue'
import {createPinia} from 'pinia'
import i18n from './services/i18n'
import {router} from '#/helpers'
import VueApexCharts from "vue3-apexcharts";
import "bootstrap/dist/css/bootstrap.min.css"
import "bootstrap"
import './assets/main.css'
import './assets/sweetalert2.min.css'
import contextmenu from "v-contextmenu";
import "v-contextmenu/dist/themes/default.css";
import {defineCustomElement} from "vue";
const clickOutside = {
beforeMount: (el, binding) => {
el.clickOutsideEvent = event => {
// here I check that click was outside the el and his children
if (!(el == event.target || el.contains(event.target))) {
// and if it did, call method provided in attribute value
binding.value();
}
};
document.addEventListener("click", el.clickOutsideEvent);
},
unmounted: el => {
document.removeEventListener("click", el.clickOutsideEvent);
},
};
const pinia = createPinia()
export const createElementInstance = ({
component = null,
props = [],
sharedStoreInstance = false,
plugins = [],
renderOptions = {}
} = {}) => {
return defineCustomElement({
props: props,
setup() {
const app = createApp();
if (!sharedStoreInstance) {
const pinia = createPinia();
app.use(pinia);
}
app
.use(router)
.use(VueApexCharts)
.use(pinia)
.use(contextmenu)
.use(i18n)
.directive("click-outside", clickOutside)
const inst = getCurrentInstance();
Object.assign(inst.appContext, app._context);
Object.assign(inst.provides, app._context.provides);
},
render: () => h(component, renderOptions)
})
}
const config = {
component: App,
props: {title: String},
sharedStoreInstance: true,
renderOptions: {ref: 'component'}
}
customElements.define('ma-ansicht', createElementInstance(config, {
shadow: true
}));
I have 2 files to import in the other project
<script type="module" crossorigin src="/assets/index.3f46efca.js"></script>
<link rel="stylesheet" href="/assets/index.ac2fca12.css">
The shadow dom of the component doesnt have any css and the generated css file appears in the header of the skeleton application.
How can I build a Web Component which includes my css in the shadow dom?
I have tried different build options like npm run build and
vue-cli-service build --target lib --name ma-ansicht src/main.js
I have tried to embed the wc in different skeleton apps
I expect that my app as web component is fully functional and styled

How to Scroll to the top on page change in React Location?

How to make ScrollToTop component like in React Router? I would like to move page view to the top on page change.
Here's an example:
index.js
import React from "react";
import ReactDOM from "react-dom/client";
import {
createBrowserRouter,
RouterProvider,
} from "react-router-dom";
import ScrollToTop from "./ScrollToTop"
import "./index.css";
const router = createBrowserRouter([
{
path: "/",
element: <div>Hello world!</div>,
},
]);
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<ScrollToTop/>
<RouterProvider router={router} />
</React.StrictMode>
);
ScrollToTop.js
import { useEffect } from "react";
import { useLocation } from "react-router-dom";
export default function ScrollToTop() {
const { pathname } = useLocation();
useEffect(() => {
// "document.documentElement.scrollTo" is the magic for React Router Dom v6
document.documentElement.scrollTo({
top: 0,
left: 0,
behavior: "instant", // Optional if you want to skip the scrolling animation
});
}, [pathname]);
return null;
}
How to create the same with the use of React Location (Tanstack Router)?
We can achieve the same behaviour by using useLocation() hook in the TanStack library, but the props will be different - instead of pathname it is called current.
Here's the code for ScrollToTop.js:
import {useEffect } from "react";
import {useLocation} from "#tanstack/react-location";
export default function ScrollToTop() {
const {current} = useLocation();
useEffect(() => {
document.documentElement.scrollTo({
top: 0,
left: 0,
behavior: "instant", // Optional if you want to skip the scrolling animation
});
}, [current]);
return null;
}

How to allow customization of a React component's style via props, when withStyles api is used?

I'm writing some simple reusable component for our React(with MaterialUI) application.
The problem is, that i want to allow different styles of this same reusable component, to be customized via props, by the consuming component.
This is some of the code:
import { withStyles } from '#material-ui/core';
const styles = theme => ({
image: {
maxHeight: '200px'
}
});
render() {
const classes = this.props.classes
return (
<div>
...
<img className={classes.image} src={this.state.filePreviewSrc} alt="" />
...
</div>
);
}
Let's say, i want to allow the programmer to customize the appearance of classes.image. Can the hard-coded image class be overwritten somehow?
Is using withStyles api is even the correct approach, for creating components whose appearance can be customized by the consuming component/programmer?
There are three main approaches available for how to support customization of styles:
Leverage props within your styles
Leverage props to determine whether or not certain classes should be applied
Do customization via withStyles
For option 3, the styles of the wrapping component will be merged with the original, but the CSS classes of the wrapping component will occur later in the <head> and will win over the original.
Below is an example showing all three approaches:
ReusableComponent.js
import React from "react";
import { withStyles } from "#material-ui/core/styles";
const styles = {
root: props => ({
backgroundColor: props.rootBackgroundColor
? props.rootBackgroundColor
: "green"
}),
inner: props => ({
backgroundColor: props.innerBackgroundColor
? props.innerBackgroundColor
: "red"
})
};
const ReusableComponent = ({ classes, children, suppressInnerDiv = false }) => {
return (
<div className={classes.root}>
Outer div
{suppressInnerDiv && <div>{children}</div>}
{!suppressInnerDiv && (
<div className={classes.inner}>
Inner div
<div>{children}</div>
</div>
)}
</div>
);
};
export default withStyles(styles)(ReusableComponent);
index.js
import React from "react";
import ReactDOM from "react-dom";
import { withStyles } from "#material-ui/core/styles";
import ReusableComponent from "./ReusableComponent";
const styles1 = theme => ({
root: {
backgroundColor: "lightblue",
margin: theme.spacing(2)
},
inner: {
minHeight: 100,
backgroundColor: "yellow"
}
});
const Customization1 = withStyles(styles1)(ReusableComponent);
const styles2 = {
inner: {
backgroundColor: "purple",
color: "white"
}
};
const Customization2 = withStyles(styles2)(ReusableComponent);
function App() {
return (
<div className="App">
<ReusableComponent>Not customized</ReusableComponent>
<Customization1>Customization 1 via withStyles</Customization1>
<Customization2>Customization 2 via withStyles</Customization2>
<ReusableComponent rootBackgroundColor="lightgrey" suppressInnerDiv>
Customization via props
</ReusableComponent>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Trying to create simple component with React-JSS

I'm trying to create a simple component, styled with React-JSS:
import React from 'react';
import { createUseStyles, useTheme } from 'react-jss';
import { useSessionState, useSessionDispatch } from '../../../contexts/SessionContext';
const useStyles = createUseStyles({
messageSuccess: {
backgroundColor: 'green'
}
});
const SystemMessage = () => {
const dispatch = useSessionDispatch();
const theme = useTheme();
const classes = useStyles({theme});
return (
<div className={classes.messageSuccess}>
abcd
</div>
);
}
export default SystemMessage;
Upon running it, I get this message:
TypeError: Object(...) is not a function
const useStyles = createUseStyles({
What am I doing wrong?
You should update your react-css version to 10.0.0

Dynamically add, update, delete markers in react-google-maps

Looking at the docs about react-google-maps, I was able to hack together some code to render a map with static data. Now I need to make changes to the map based on new data coming in from API or periodic updates and don't see any talk about how to do this.
To make the initial application, I did an "npx create-react-app xxx" to create an app and then added the necessary npm packages for react-google-maps. Here's basic code:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import * as serviceWorker from './serviceWorker';
import { withScriptjs, withGoogleMap, GoogleMap, Marker } from "react-google-maps"
let markers = []
function createMarkers(numMarkers){
for(let i = 0; i < numMarkers; i++){
markers.push(<Marker key={i} position={{ lat: 45.123 + (i * 0.005), lng: -75.987 }} />)
}
return markers;
}
setInterval(function(){
if(markers.length > 0 && markers[0].props.position){
let marker = markers[0];
//debugger;
let position = marker.props.position;
position.lat = position.lat - 0.005;
position.lng = position.lng - 0.005;
marker.props.position = position;
}
}, 1000)
const MyGreatMap = withScriptjs( withGoogleMap(props => <GoogleMap
defaultZoom={14}
defaultCenter={{ lat: 45.123, lng: -75.978 }}
>
{createMarkers(10)}
</GoogleMap>));
ReactDOM.render(
<MyGreatMap
googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=AIzaSyDS-TFZqRfUx9xPXTJrPH6eml-gGo-btZ0"
loadingElement={<div style={{ height: `100%` }} />}
containerElement={<div style={{ height: `800px` }} />}
mapElement={<div style={{ height: `100%` }} />}
/>,
document.getElementById('root'));
When I update the props, nothing happens. I'm sure that's wrong and it should be updating state somehow, but the lat/lng info in the markers are props.
What is the best way to update things in react-google-maps? Google maps in general is a very javascript intensive API so I don't know if it can work "the react way". What's the best way to make changes to react-google-maps to get them to efficiently re-render with changes?
I'm sure that's wrong and it should be updating state somehow, but the
lat/lng info in the markers are props.
that's right, markers needs to moved to local state, For that matter a component could be introduced which accepts markers props as initial state and then state updated like this:
class MapWithMarkers extends React.Component {
constructor(props) {
super(props);
this.state= {markers: this.props.markers}; //1.initialize initial state from props
}
updateMarker() {
this.setState(prevState => {
const markers = [...prevState.markers];
markers[index] = {lat: <val>, lng: <val>};
return {markers};
})
}
componentDidMount() {
this.intervalId = setInterval(this.updateMarker.bind(this), 1000);
}
componentWillUnmount(){
clearInterval(this.intervalId);
}
render() {
return (
<Map center={this.props.center} zoom={this.props.zoom} places={this.state.markers} />
);
}
}
Demo

Resources