How can I get image properties like scaleX in react-kova? - konvajs

Like the example shown for shape, this has x,y,rotation etc. https://konvajs.github.io/docs/select_and_transform/Transform_Events.html
Image in react-konva also extends shape.
How can I get these values for image(with transformer) in react-konva.

You can listen transform event and then read all properties from the image node.
handleTransform = () => {
const props = {
x: this.image.x(),
y: this.image.y(),
rotatio: this.image.rotation(),
width: this.image.width(),
height: this.image.height(),
scaleX: this.image.scaleX(),
scaleY: this.image.scaleY()
};
console.log(props);
};
render() {
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Image
image={this.state.image}
ref={node => {
this.image = node;
}}
draggable
onTransform={this.handleTransform}
onDragMove={this.handleTransform}
/>
<Transformer
ref={node => {
this.transformer = node;
}}
/>
</Layer>
</Stage>
);
}
Demo: https://codesandbox.io/s/wq184owy45

Related

getting react-konva context in a parent handler - is there a better way than my code below?

Is there a better way, that is: (a) having to pass the child event back to the parent to be able to extract the stage/layer to then be able to do a konva node "find", and (b) having to "find" nodes using this approach (as using Konva-React JSX I don't have references to them in the code)
import { Stage, Layer, Text } from "react-konva";
import { KonvaEventObject } from "konva/lib/Node";
// ----------------------------------------------
type TestTileProps = {
id: String;
hodh: (e: KonvaEventObject<DragEvent>) => void;
};
const TestTile = function ({ id, hodh }: TestTileProps) {
const handleOnDragMove = (e: KonvaEventObject<DragEvent>) => {
hodh(e);
};
return (
<Text
y={20}
text={id + " <=="}
draggable={true}
onDragMove={handleOnDragMove}
/>
);
};
// ----------------------------------------------
const App = () => {
const higherOrderDragHandler = (e: KonvaEventObject<DragEvent>) => {
const layer = e.target.getLayer();
const textNode = layer.find(".MainText")[0];
textNode.position({
x: e.target.position().y,
y: textNode.position().y
});
};
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Text name="MainText" text="Heading 123" />
<TestTile id={"Value pass"} hodh={higherOrderDragHandler} />
</Layer>
</Stage>
);
};
export default App;
// ----------------------------------------------

Konva onDragMove and onDragEnd not updating position?

I'm trying to onDragMove to manually update an elements position. The shape itself is dragging around, and the is updating the objects, but it is not being rendered?
Same with onDragEnd. Both are updating the array of shapes correctly, but it is not appearing on the render, even though
import React, { useState, useEffect } from "react";
import { Stage, Layer, Rect } from "react-konva";
import "./styles.css";
export default function App() {
const [objects, setObject] = useState([{ id: "rect1", x: 50, y: 50 }]);
// Function
const updatePosition = (id) => {
let update = objects.map((entry) => {
if (entry.id !== id) return entry;
else return { ...entry, x: 100, y: 0 };
});
setObject(update);
};
// We can see the object is updated with the new coords
useEffect(() => {
console.log(objects);
});
return (
<main style={{ background: "lightgrey" }}>
<Stage width={800} height={800}>
<Layer>
{objects.map((object) => {
// This shows an updated X value correclty
console.log(object.x);
// It doesn't render the new x position at all
return (
<Rect
key={object.id}
fill={"green"}
width={200}
height={300}
x={object.x}
y={object.y}
draggable
onDragMove={() => updatePosition(object.id)}
onDragEnd={() => updatePosition(object.id)}
/>
);
})}
</Layer>
</Stage>
</main>
);
}
https://codesandbox.io/s/priceless-dust-cjr6z?file=/src/App.js:0-1323
From your demo, I see that you are setting the same {x, y} position to the shape:
const updatePosition = (id) => {
let update = objects.map((entry) => {
if (entry.id !== id) return entry;
else return { ...entry, x: 100, y: 0 };
});
setObject(update);
};
By default react-konva will set 100, 0 position just once. On the next render calls, properties for <Rect /> element are not changing. react-konva will update only CHANGED from previous render properties.
If you want to strictly set the last properties, you should use strict mode

Konva - react drag drop without moving drag element

Similar to having drag and drop without moving the element in Konva, is there a way to do the same with Konva-react?
Tried doing this. But, could not find a way to add cloned shape back to the Layer.
Thank you and any help would be appreciated.
Update:
Code used:
Trying to clone "Shp1" in the below code
class Shp1 extends Component {
state = {
x1: 0,
y1: 0
};
handleDragStart = e => {
e.target.setAttrs({
scaleX: 1.1,
scaleY: 1.1
});
//clone code goes here
};
handleDragEnd = e => {
this.setState({
x1: e.target.x(),
y1: e.target.y()
});
};
render() {
return(
<Group x={this.state.x1} y={this.state.y1}
id="shp1" draggable onDragStart={this.handleDragStart} onDragEnd={this.handleDragEnd}
onMouseOver={this.handleMouseOver} onMouseOut={this.handleMouseOut}>
<RegularPolygon x={110} y={160} sides={3} radius={80}
fill="black" rotation={90}/>
<Circle x={190} y={160} radius={30}
fill="black"/>
</Group>
);
}
}
class App extends Component {
render() {
return (
<Stage id='stg1' width={window.innerWidth} height={window.innerHeight} draggable={false}>
<Layer id="menu" className="layer" x={0} y={0} width={200} height={window.innerHeight} visible={true}>
<Shp1/>
</Layer>
</Stage>
);
}
}

go to view in animated.Scrollview

Using this code i try to add on each marker an onpress option
there is the source source and there is a sample of my work
after many try i give up ... is there a way to add on my onpress the x position to my Animated.ScrollView
when i scroll i can see the marker changing but i want to add an onpress function in each marker. when press one off the marker i want to the scrollview set to the position of my maker
componentWillMount() {
this.index = 0;
this.animation = new Animated.Value(0);
}
componentDidMount() {
// We should detect when scrolling has stopped then animate
// We should just debounce the event listener here
AsyncStorage.getItem('userToken', (err, result) => {
if (this.state.userToken == null) {
this.setState({ userToken: result })
this.GetAllMarker()
}
});
this.animation.addListener(({ value }) => {
console.log(value)
let index = Math.floor(value / CARD_WIDTH + 0.3); // animate 30% away from landing on the next item
if (index >= this.state.markers.length) {
index = this.state.markers.length - 1;
}
if (index <= 0) {
index = 0;
}
clearTimeout(this.regionTimeout);
this.regionTimeout = setTimeout(() => {
if (this.index !== index) {
this.index = index;
const { coordinates } = this.state.markers[index];
console.log(index)
this.map.animateToRegion(
{
...coordinates,
latitudeDelta: this.state.region.latitudeDelta,
longitudeDelta: this.state.region.longitudeDelta,
},
350
);
}
}, 10);
});
}
GenerateBearer() {
let tmp = `Bearer ` + this.state.userToken
tmp = tmp.replace('"', '');
tmp = tmp.replace('"', '');
return (tmp)
}
GetAllMarker() {
let Bearer = this.GenerateBearer();
console.log(Bearer)
fetch(Config.API_URL + "/api/public/user/aroundMe?latitude=" + this.state.region.latitude + "&longitude=" + this.state.region.longitude + "&rayon=50", {
method: 'GET',
headers: {
'Accept': '*/*',
'Content-Type': 'application/json',
'Authorization': Bearer,
}
})
.then(res => res.json())
.then(res => {
this.setState({ markers: res })
})
.catch(error => {
this.setState({ error: error });
});
}
handleMarkerPress(e){
this.state.markers[1] = e
console.log(e)
}
render() {
const interpolations = this.state.markers.map((marker, index) => {
const inputRange = [
(index - 1) * CARD_WIDTH,
index * CARD_WIDTH,
((index + 1) * CARD_WIDTH),
];
const scale = this.animation.interpolate({
inputRange,
outputRange: [1, 2.5, 1],
extrapolate: "clamp",
});
const opacity = this.animation.interpolate({
inputRange,
outputRange: [0.35, 1, 0.35],
extrapolate: "clamp",
});
return { scale, opacity };
});
return (
<View style={styles.container}>
<MapView
ref={map => this.map = map}
initialRegion={this.state.region}
style={styles.container}
>
<UrlTile
urlTemplate="http://ip/styles/klokantech-basic/{z}/{x}/{y}.png"
zIndex={-1}
/>
{this.state.markers.map((marker, index) => {
const scaleStyle = {
transform: [
{
scale: interpolations[index].scale,
},
],
};
const opacityStyle = {
opacity: interpolations[index].opacity,
};
return (
<MapView.Marker key={index} coordinate={marker.coordinates} onPress={(event) => this.handleMarkerPress(index)} >
<Animated.View style={[styles.markerWrap, opacityStyle]} >
<Animated.View style={[styles.ring, scaleStyle]} />
<View style={styles.marker} />
</Animated.View>
</MapView.Marker>
);
})}
</MapView>
<Animated.ScrollView
horizontal
scrollEventThrottle={1}
showsHorizontalScrollIndicator={true}
snapToInterval={CARD_WIDTH}
onScroll={Animated.event(
[{nativeEvent: {
contentOffset: {
x: this.animation,
},
},},],
{ useNativeDriver: true }
)}
style={styles.scrollView}
contentContainerStyle={styles.endPadding}
>
{this.state.markers.map((marker, index) => {
if (marker.isAlerte == false)
return (
<View style={styles.card} key={index}>
<Image
source={marker.image}
style={styles.cardImage}
resizeMode="cover"
/>
<View style={styles.textContent}>
<Text numberOfLines={1} style={styles.cardtitle}>{marker.espace.titre}</Text>
<Text numberOfLines={1} style={styles.cardDescription}>
{marker.description}
</Text>
</View>
</View>)
else
return (
<View style={styles.card} key={index}>
<Image
source={marker.image}
style={styles.cardImage}
resizeMode="cover"
/>
<View style={styles.textContent}>
<Text numberOfLines={1} style={styles.cardtitle}>{marker.alerte.type}</Text>
<Text numberOfLines={1} style={styles.cardDescription}>
{marker.description}
</Text>
</View>
</View>)
})
}
</Animated.ScrollView>
</View>
);
}
}
found the solution
Add
<Animated.ScrollView
horizontal
ref={(c) => {this.scroll = c}}
scrollEventThrottle={1}
showsHorizontalScrollIndicator={true}
snapToInterval={CARD_WIDTH}
onScroll={Animated.event( [{ nativeEvent: { contentOffset: { x: this.animation, }, }, },], { useNativeDriver: true } )}
style={styles.scrollView}
contentContainerStyle={styles.endPadding} >
and this for the map view marker
<MapView.Marker
key={index}
coordinate={marker.coordinates}
onPress={() => this.handleMarkerPress(index)} >
and the handlemarkerpress
this.scroll.getNode().scrollTo({x: e * 375, y: 0, animated: true});
(375 for my card width)
To scroll to a position x,y in your scroll view. Use the scrollTo function in the scroll view. Checkout here the react native documentation about it https://facebook.github.io/react-native/docs/scrollview#scrollto.
Use the ref property to execute the method in your scrollview.
Now you need to identify the x and y of your markers so you can scroll to them. Never done something like that but here is an article of someone calculating the x and y of react native elements https://github.com/facebook/react-native/issues/1374.

React.createElement : type should not be null

I copied the code from here.
This throws this warning:
.
How to fix this warning?
Code:
'use strict';
var React = require('react-native');
// I have import the ScrollView and RefreshControl
var{
StyleSheet,
Image,
ScrollView,
RefreshControl,
View,
} = React;
var Carousel = require('react-native-looped-carousel');
var Dimensions = require('Dimensions');
var {width, height} = Dimensions.get('window');
var NewsListView = React.createClass({
getInitialState: function () {
return {
isRefreshing: false,
loaded: 0,
};
},
componentDidMount: function () {
},
render: function () {
return (
// if I remove RefreshControl , the warming missing. how to fix this problem
<ScrollView
style={styles.scrollview}
refreshControl={
<RefreshControl
refreshing={this.state.isRefreshing}
onRefresh={this._onRefresh}
tintColor="#ff0000"
title="Loading..."
/>
}>
<View>
<Carousel delay={5000} style={{width: width, height: height/4 }}>
<Image
source={require('RT_XiaoYiSiGou/Image/img_banner.png')
}
style={{width: width, height: height/4}}
/>
<Image
source={require('RT_XiaoYiSiGou/Image/img_banner2.png')}
style={{width: width, height: height/4}}
/>
<Image
source={require('RT_XiaoYiSiGou/Image/img_banner3.png')}
style={{width: width, height: height/4}}
/>
</Carousel>
</View>
</ScrollView>
);
},
_onRefresh() {
this.setState({isRefreshing: true});
setTimeout(() => {
this.setState({
loaded: this.state.loaded + 10,
isRefreshing: false,
});
}, 5000);
},
});
var styles = StyleSheet.create({
scrollview: {
flex: 1,
},
});
module.exports = NewsListView;
What I "suggest" because I can't do more from your code is:
1) The error you get is because you do not call the React.createElement correctly. You should write your code in simple segments, I suggest chopping it up in three parts, definition, creation and render...
// define your element
var definitionObject = {
// a property called render which is a function which returns your markup.
render: function() {
return (
<h1 className="peterPan">
Peter Pan.
</h1>
);
}
}
// create the actual element
var PeterPanElement = React.createClass(definitionObject);
ReactDOM.render(
<PeterPanElement />,
document.getElementById('willBeReplacedByPeterPanElement')
);
I hope you agree I can't deduce more from your question, if you clean the question up we might be able to help you out more...

Resources