Aligning a JS object to the middle of a div - javascript

I recently started playing around with js, and specifically - with this graphing library.
I ran some of their example code, and I got somewhat of a noob HTML / js question.
this is their example code:
When I run this code, the graph appears on the left of the div.
I wanted to know how I can align this object to the mid of the div.
I don't really know if this is a "HTML / CSS" task - or rather a "js task" which means I should obtain this behaviour via the object API (tbh, I tried looking into the API and I saw no alignment options).
Sorry if this is a really noobie question, I tried solving it, but I had no success.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Tutorial Demo</title>
</head>
<body>
<div id="mountNode"></div>
<script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.7.1/dist/g6.min.js"></script>
<script>
const graph = new G6.Graph({
container: 'mountNode',
width: 800,
height: 600,
// Default properties for all the nodes
defaultNode: {
labelCfg: {
style: {
fill: '#fff',
},
},
},
// Default properties for all the edges
defaultEdge: {
labelCfg: {
autoRotate: true,
},
},
// The node styles in different states
nodeStateStyles: {
// The node style when the state 'hover' is true
hover: {
fill: 'lightsteelblue',
},
// The node style when the state 'click' is true
click: {
stroke: '#000',
lineWidth: 3,
},
},
// The edge styles in different states
edgeStateStyles: {
// The edge style when the state 'click' is true
click: {
stroke: 'steelblue',
},
},
// Layout
layout: {
type: 'force',
linkDistance: 100,
preventOverlap: true,
nodeStrength: -30,
edgeStrength: 0.1,
},
// Built-in Behaviors
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node'],
},
});
const main = async () => {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/6cae02ab-4c29-44b2-b1fd-4005688febcb.json',
);
const remoteData = await response.json();
const nodes = remoteData.nodes;
const edges = remoteData.edges;
nodes.forEach((node) => {
if (!node.style) {
node.style = {};
}
node.style.lineWidth = 1;
node.style.stroke = '#666';
node.style.fill = 'steelblue';
switch (node.class) {
case 'c0': {
node.type = 'circle';
node.size = 30;
break;
}
case 'c1': {
node.type = 'rect';
node.size = [35, 20];
break;
}
case 'c2': {
node.type = 'ellipse';
node.size = [35, 20];
break;
}
}
});
edges.forEach((edge) => {
if (!edge.style) {
edge.style = {};
}
edge.style.lineWidth = edge.weight;
edge.style.opacity = 0.6;
edge.style.stroke = 'grey';
});
graph.data(remoteData);
graph.render();
// Mouse enter a node
graph.on('node:mouseenter', (e) => {
const nodeItem = e.item; // Get the target item
graph.setItemState(nodeItem, 'hover', true); // Set the state 'hover' of the item to be true
});
// Mouse leave a node
graph.on('node:mouseleave', (e) => {
const nodeItem = e.item; // Get the target item
graph.setItemState(nodeItem, 'hover', false); // Set the state 'hover' of the item to be false
});
// Click a node
graph.on('node:click', (e) => {
// Swich the 'click' state of the node to be false
const clickNodes = graph.findAllByState('node', 'click');
clickNodes.forEach((cn) => {
graph.setItemState(cn, 'click', false);
});
const nodeItem = e.item; // et the clicked item
graph.setItemState(nodeItem, 'click', true); // Set the state 'click' of the item to be true
});
// Click an edge
graph.on('edge:click', (e) => {
// Swich the 'click' state of the edge to be false
const clickEdges = graph.findAllByState('edge', 'click');
clickEdges.forEach((ce) => {
graph.setItemState(ce, 'click', false);
});
const edgeItem = e.item; // Get the clicked item
graph.setItemState(edgeItem, 'click', true); // Set the state 'click' of the item to be true
});
};
main();
</script>
</body>
</html>

just use flexbox.
#mountNode{
display:flex;
justify-content:center;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Tutorial Demo</title>
</head>
<body>
<div id="mountNode"></div>
<script src="https://gw.alipayobjects.com/os/antv/pkg/_antv.g6-3.7.1/dist/g6.min.js"></script>
<script>
const graph = new G6.Graph({
container: 'mountNode',
width: 800,
height: 600,
// Default properties for all the nodes
defaultNode: {
labelCfg: {
style: {
fill: '#fff',
},
},
},
// Default properties for all the edges
defaultEdge: {
labelCfg: {
autoRotate: true,
},
},
// The node styles in different states
nodeStateStyles: {
// The node style when the state 'hover' is true
hover: {
fill: 'lightsteelblue',
},
// The node style when the state 'click' is true
click: {
stroke: '#000',
lineWidth: 3,
},
},
// The edge styles in different states
edgeStateStyles: {
// The edge style when the state 'click' is true
click: {
stroke: 'steelblue',
},
},
// Layout
layout: {
type: 'force',
linkDistance: 100,
preventOverlap: true,
nodeStrength: -30,
edgeStrength: 0.1,
},
// Built-in Behaviors
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node'],
},
});
const main = async () => {
const response = await fetch(
'https://gw.alipayobjects.com/os/basement_prod/6cae02ab-4c29-44b2-b1fd-4005688febcb.json',
);
const remoteData = await response.json();
const nodes = remoteData.nodes;
const edges = remoteData.edges;
nodes.forEach((node) => {
if (!node.style) {
node.style = {};
}
node.style.lineWidth = 1;
node.style.stroke = '#666';
node.style.fill = 'steelblue';
switch (node.class) {
case 'c0': {
node.type = 'circle';
node.size = 30;
break;
}
case 'c1': {
node.type = 'rect';
node.size = [35, 20];
break;
}
case 'c2': {
node.type = 'ellipse';
node.size = [35, 20];
break;
}
}
});
edges.forEach((edge) => {
if (!edge.style) {
edge.style = {};
}
edge.style.lineWidth = edge.weight;
edge.style.opacity = 0.6;
edge.style.stroke = 'grey';
});
graph.data(remoteData);
graph.render();
// Mouse enter a node
graph.on('node:mouseenter', (e) => {
const nodeItem = e.item; // Get the target item
graph.setItemState(nodeItem, 'hover', true); // Set the state 'hover' of the item to be true
});
// Mouse leave a node
graph.on('node:mouseleave', (e) => {
const nodeItem = e.item; // Get the target item
graph.setItemState(nodeItem, 'hover', false); // Set the state 'hover' of the item to be false
});
// Click a node
graph.on('node:click', (e) => {
// Swich the 'click' state of the node to be false
const clickNodes = graph.findAllByState('node', 'click');
clickNodes.forEach((cn) => {
graph.setItemState(cn, 'click', false);
});
const nodeItem = e.item; // et the clicked item
graph.setItemState(nodeItem, 'click', true); // Set the state 'click' of the item to be true
});
// Click an edge
graph.on('edge:click', (e) => {
// Swich the 'click' state of the edge to be false
const clickEdges = graph.findAllByState('edge', 'click');
clickEdges.forEach((ce) => {
graph.setItemState(ce, 'click', false);
});
const edgeItem = e.item; // Get the clicked item
graph.setItemState(edgeItem, 'click', true); // Set the state 'click' of the item to be true
});
};
main();
</script>
</body>
</html>

Related

Mapbox Cluster Map opens all pop-ups on location click

I am trying to create a cluster map with multiple locations in the same area. Now, I have this pop-up with data which is coming from my API. I have a click event that toggles the pop-up on click for each location. But the problem is even when I specified the click unique ID to toggle it still opens all the pop-ups. Also, the zoom is not working for the clusters count circles.
This is my code:
import mapboxgl from 'mapbox-gl';
import MapboxLanguage from '#mapbox/mapbox-gl-language';
import apiFetch from '#wordpress/api-fetch';
(() => {
const mapContainer = document.querySelector('[data-gewoon-wonen]');
if (!mapContainer) {
return;
}
mapboxgl.accessToken = process.env.MAP_TOKEN_KEY;
const filterGroup = document.getElementById('map-filter');
const resetButton = filterGroup.querySelector('.hidden');
const center = [4.387733, 51.862419];
const locations = {
type: 'FeatureCollection',
features: []
};
apiFetch({ path: '/wp-json/wp/v2/map?_embed' }).then((maps) => {
maps.forEach((item) => {
const {
id,
title: { rendered: title },
_embedded,
acf
} = item;
const image =
_embedded && _embedded['wp:featuredmedia'][0]?.source_url;
const {
map_location_subtitle: subtitle,
map_location_delivery: delivery,
map_location_project: project,
map_location_content: description,
map_location_coordinates_lat: lat,
map_location_coordinates_lng: lng,
map_location_status: status,
map_location_website: website
} = acf;
const getStatus = (currentStatus) => {
let statusObj = {
bouwfase: 'marker-gray',
planfase: 'marker-bright-pink',
opgeleverd: 'marker-bright-blue',
default: ''
};
let icon = statusObj[currentStatus] || statusObj['default'];
return icon;
};
const object = {
type: 'Feature',
properties: {
id,
status,
image,
icon: getStatus(status),
title,
subtitle,
project,
website,
delivery,
description
},
geometry: {
type: 'Point',
coordinates: [lng, lat]
}
};
locations.features.push(object);
});
});
const map = new mapboxgl.Map({
container: mapContainer,
style: 'mapbox://styles/.../clcz9eocm000p14o3vh42tqfj',
center,
zoom: 10,
minZoom: 10,
maxZoom: 18,
attributionControl: false,
cooperativeGestures: true
});
map.addControl(
new MapboxLanguage({
defaultLanguage: 'mul'
})
);
const resetActiveItems = () => {
document
.querySelectorAll('.active')
.forEach((e) => e.classList.remove('active'));
};
const closePopUps = () => {
const popups = document.getElementsByClassName('mapboxgl-popup');
if (popups.length) {
popups[0].remove();
}
};
map.on('load', () => {
map.addSource('locations', {
type: 'geojson',
data: locations,
cluster: true,
clusterMaxZoom: 14, // Max zoom to cluster points on
clusterRadius: 50 // Radius of each cluster when clustering points (defaults to 50)s
});
locations.features.forEach((location) => {
const {
description,
delivery,
title,
subtitle,
project,
status,
image,
website,
id
} = location.properties;
const { coordinates } = location.geometry;
const layerID = `status-${status}-${id}`;
// Add a layer for this symbol type if it hasn't been added already.
if (!map.getLayer(layerID)) {
map.addLayer({
id: layerID,
type: 'symbol',
source: 'locations',
layout: {
'icon-image': ['get', 'icon'],
'icon-size': 0.9,
'icon-allow-overlap': true
},
// filter: ['==', 'id', id]
filter: ['!', ['has', 'point_count']]
});
map.addLayer({
id: `clusters-${id}`,
type: 'circle',
source: 'locations',
filter: ['has', 'point_count'],
paint: {
// Use step expressions (https://docs.mapbox.com/mapbox-gl-js/style-spec/#expressions-step)
// with three steps to implement three types of circles:
// * Blue, 20px circles when point count is less than 100
// * Yellow, 30px circles when point count is between 100 and 750
// * Pink, 40px circles when point count is greater than or equal to 750
'circle-color': [
'step',
['get', 'point_count'],
'#51bbd6',
100,
'#f1f075',
750,
'#f28cb1'
],
'circle-radius': [
'step',
['get', 'point_count'],
20,
100,
30,
750,
40
]
}
});
map.addLayer({
id: `cluster-count-${id}`,
type: 'symbol',
source: 'locations',
filter: ['has', 'point_count'],
layout: {
'text-field': ['get', 'point_count_abbreviated'],
'text-font': [
'DIN Offc Pro Medium',
'Arial Unicode MS Bold'
],
'text-size': 12
}
});
}
const hasImage = image
? `<img src=${image} class="map__image" />`
: '';
const statusClass = image ? 'map__status--overlay' : '';
const popup = new mapboxgl.Popup({
offset: 25,
maxWidth: null,
className: image ? 'map__content--image' : ''
});
const content = `
${hasImage}
<span class="map__status map__status--${status} ${statusClass}">${status}</span>
<h4 class="map__title">${title}</h4>
<p class="map__subtitle">${subtitle}</p>
<p class="map__subtitle">${
delivery ? `Oplevering ${delivery}` : ''
}</p>
<p class="map__project">${project}</p>
<p class="map__info">${description}</p>
Meer informatie
`;
map.on('click', layerID, (e) => {
// Copy coordinates array.
const coordinateSlice = coordinates.slice();
resetButton.classList.remove('hidden');
// Ensure that if the map is zoomed out such that multiple
// copies of the feature are visible, the popup appears
// over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinateSlice[0]) > 180) {
coordinateSlice[0] +=
e.lngLat.lng > coordinateSlice[0] ? 360 : -360;
}
popup.setLngLat(coordinates).setHTML(content).addTo(map);
});
// Change the cursor to a pointer when the mouse is over the places layer.
map.on('mouseenter', layerID, () => {
map.getCanvas().style.cursor = 'pointer';
});
// Change it back to a pointer when it leaves.
map.on('mouseleave', layerID, () => {
map.getCanvas().style.cursor = '';
});
});
const statusTypes = locations.features.map(
(feature) => feature.properties.status
);
const uniqueStatusTypes = Array.from(new Set(statusTypes));
const newGeoJSON = { ...locations };
resetButton.addEventListener('click', () => {
newGeoJSON.features = [...locations.features];
map.getSource('locations').setData(newGeoJSON);
map.setZoom(10).setCenter(center);
resetButton.classList.add('hidden');
resetActiveItems();
closePopUps();
});
const sortedStatusTypes = [
uniqueStatusTypes[0],
uniqueStatusTypes[2],
uniqueStatusTypes[1]
].filter((status) => status !== undefined && status !== null);
sortedStatusTypes.forEach((statusType) => {
const input = document.createElement('input');
input.value = statusType;
input.name = statusType;
input.type = 'button';
input.className = `status--${statusType}`;
input.innerText = statusType;
filterGroup.appendChild(input);
input.onclick = () => {
const statusType = input.value;
resetActiveItems();
closePopUps();
if (statusType) {
input.classList.add('active');
resetButton.classList.remove('hidden');
newGeoJSON.features = locations.features.filter(
(feature) => feature.properties.status === statusType
);
}
map.getSource('locations').setData(newGeoJSON);
};
});
// disable map rotation using right click + drag
map.dragRotate.disable();
// disable map rotation using touch rotation gesture
map.touchZoomRotate.disableRotation();
// Add zoom and rotation controls to the map.
const nav = new mapboxgl.NavigationControl({
showCompass: false
});
const fullscreen = new mapboxgl.FullscreenControl();
map.addControl(fullscreen, 'top-right');
map.addControl(nav, 'bottom-right');
});
})();

Go JS Tree view equivalent in React

I need to achieve the tree view (Go JS Tree View). The respective tree view sample source code without React JS is at (Tree View Source Code). I'm trying to do the same using React JS and have the following code written. But somehow I'm missing something and the diagram/tree view is not rendering. Can you please help me to figure out the issue?
import React from 'react';
import * as go from 'gojs';
import { ReactDiagram } from 'gojs-react';
import '../../../App.css';
go.Shape.defineFigureGenerator("ExpandedLine", function(shape, w, h) {
return new go.Geometry()
.add(new go.PathFigure(0, 0.25*h, false)
.add(new go.PathSegment(go.PathSegment.Line, .5 * w, 0.75*h))
.add(new go.PathSegment(go.PathSegment.Line, w, 0.25*h)));
});
// use a sideways V figure instead of PlusLine in the TreeExpanderButton
go.Shape.defineFigureGenerator("CollapsedLine", function(shape, w, h) {
return new go.Geometry()
.add(new go.PathFigure(0.25*w, 0, false)
.add(new go.PathSegment(go.PathSegment.Line, 0.75*w, .5 * h))
.add(new go.PathSegment(go.PathSegment.Line, 0.25*w, h)));
});
let nodeDataArray = [{ key: 0 }];
const initDiagram = () => {
let $ = go.GraphObject.make;
const diagram =
$(go.Diagram, "myDiagramDiv",
{
allowMove: false,
allowCopy: false,
allowDelete: false,
allowHorizontalScroll: false,
layout:
$(go.TreeLayout,
{
alignment: go.TreeLayout.AlignmentStart,
angle: 0,
compaction: go.TreeLayout.CompactionNone,
layerSpacing: 16,
layerSpacingParentOverlap: 1,
nodeIndentPastParent: 1.0,
nodeSpacing: 0,
setsPortSpot: false,
setsChildPortSpot: false
})
});
diagram.nodeTemplate =
$(go.Node,
{ // no Adornment: instead change panel background color by binding to Node.isSelected
selectionAdorned: false,
// a custom function to allow expanding/collapsing on double-click
// this uses similar logic to a TreeExpanderButton
doubleClick: function(e, node) {
let cmd = diagram.commandHandler;
if (node.isTreeExpanded) {
if (!cmd.canCollapseTree(node)) return;
} else {
if (!cmd.canExpandTree(node)) return;
}
e.handled = true;
if (node.isTreeExpanded) {
cmd.collapseTree(node);
} else {
cmd.expandTree(node);
}
}
},
$("TreeExpanderButton",
{ // customize the button's appearance
"_treeExpandedFigure": "ExpandedLine",
"_treeCollapsedFigure": "CollapsedLine",
"ButtonBorder.fill": "whitesmoke",
"ButtonBorder.stroke": null,
"_buttonFillOver": "rgba(0,128,255,0.25)",
"_buttonStrokeOver": null
}),
$(go.Panel, "Horizontal",
{ position: new go.Point(18, 0) },
new go.Binding("background", "isSelected",
s => (s ? 'lightblue' : 'white')).ofObject(),
$(go.Picture,
{
width: 18, height: 18,
margin: new go.Margin(0, 4, 0, 0),
imageStretch: go.GraphObject.Uniform
},
// bind the picture source on two properties of the Node
// to display open folder, closed folder, or document
new go.Binding("source", "isTreeExpanded", imageConverter).ofObject(),
new go.Binding("source", "isTreeLeaf", imageConverter).ofObject()),
$(go.TextBlock,
{ font: '9pt Verdana, sans-serif' },
new go.Binding("text", "key", function(s) { return "item " + s; }))
) // end Horizontal Panel
); // end Node
diagram.linkTemplate = $(go.Link);
let max = 499;
let count = 0;
while (count < max) {
count = makeTree(3, count, max, nodeDataArray, nodeDataArray[0]);
}
diagram.model = new go.TreeModel(nodeDataArray);
return diagram;
}
function makeTree(level, count, max, nodeDataArray, parentData) {
let numChildren = Math.floor(Math.random() * 10);
for (let i = 0; i < numChildren; i++) {
if (count >= max) return count;
count++;
let childData = { key: count, parent: parentData.key };
nodeDataArray.push(childData);
if (level > 0 && Math.random() > 0.5) {
count = makeTree(level - 1, count, max, nodeDataArray, childData);
}
}
return count;
}
function imageConverter(prop, picture) {
let node = picture.part;
if (node.isTreeLeaf) {
return "images/document.svg";
} else {
if (node.isTreeExpanded) {
return "images/openFolder.svg";
} else {
return "images/closedFolder.svg";
}
}
}
window.addEventListener('DOMContentLoaded', initDiagram);
const TreeView = () => {
return (
<>
GO JS
<div id="myDiagramDiv">
<ReactDiagram
initDiagram={initDiagram}
divClassName='diagram-component'
nodeDataArray={nodeDataArray}
skipsDiagramUpdate={false}
/>
</div>
</>
);
}
export default TreeView;
When React start executing, the DOMContentLoaded event have already been fired. Instead try to call initDiagram in a useEffect hook
const TreeView = () => {
useEffect(initDiagram);
return (
<>
GO JS
<div id="myDiagramDiv">
<ReactDiagram
initDiagram={initDiagram}
divClassName='diagram-component'
nodeDataArray={nodeDataArray}
skipsDiagramUpdate={false}
/>
</div>
</>
);
}

how to access class variables inside chart.js custom tooltip interface

on the below code snippet in custom tooltip under tooltip on click event, the class variable is not accessible when I try with this it showing values related to ChartElement only
#Output() valuechange = new EventEmitter<any>();
options: ChartOptions = {
responsive: true,
maintainAspectRatio: false,
tooltips: {
displayColors: false,
mode: 'nearest',
intersect: false,
enabled: false,
custom(tooltipModel: any) {
// tooltip element
let tooltipEl: any = document.querySelector('#chartjs-tooltip');
// create element on first render
if (!tooltipEl) {
tooltipEl = document.createElement('div');
tooltipEl.id = 'chartjs-tooltip';
tooltipEl.style.width = '124px';
tooltipEl.style.color = 'white';
tooltipEl.style.borderRadius = '6px';
tooltipEl.style.backgroundColor = 'rgba(55, 71, 79, 0.8)';
tooltipEl.innerHTML = '<div style ="display:flex;flex-direction:column">sample tooltip</div>';
document.body.appendChild(tooltipEl);
}
tooltipEl.onclick = () => {
// NOT ABLE TO Access this to emit event
// this.valuechange.emit('test');
console.log('hi); // working
};
}
}
To make this equal to the class, write it as an arrow function:
custom: () => {
console.log(this); // should be the class
}
But sometimes you need a handle of this and that where this is the class and that is the Chart object.
Create a utility function:
export const thisAsThat = (callBack: Function) => {
const self = this;
return function () {
return callBack.apply(self, [this].concat(Array.prototype.slice.call(arguments)));
};
}
Then:
import { thisAsThat } from './where/thisAsThat/is/located';
....
custom: thisAsThat((that: any, otherArgument: any) => {
console.log(this); // the class
console.log(that); // the chart object
})
TypeScript: How to use both fat arrow and this?

disabling a scrollmagic controller in an object literal es6

i am having an issue trying to reenable a scrollmagic controller if it has been disabled before.
i want to have the logo color change only triggered if its a narrow viewport (if the logo is in the colored area) and disabled if its wide..that works so far
but if i resize the window to narrow again it won't reenable the controller..i tried to destroy and reset the controller as well but somehow it won't reenable the controller...
codepen (gsap and scrollmagic used):
https://codepen.io/HendrikEng/pen/owyBYz?editors=0011
js:
const mobile = {
controller: new ScrollMagic.Controller(),
changeLogo: {
init: () => {
console.log("init tweens an scrollmagic");
const tweens = {
enterOuter: () => {
TweenMax.fromTo(
".c-logo__outer",
1,
{ fill: "#4dabfc" },
{ fill: "#fff" }
);
},
enterInner: () => {
TweenMax.fromTo(
".c-logo__inner",
1,
{ fill: "#fff" },
{ fill: "#4dabfc" }
);
},
leaveOuter: () => {
TweenMax.fromTo(
".c-logo__outer",
1,
{ fill: "#fff" },
{ fill: "#4dabfc" }
);
},
leaveInner: () => {
TweenMax.fromTo(
".c-logo__inner",
1,
{ fill: "#4dabfc" },
{ fill: "#fff" }
);
}
};
const trigger = document.querySelectorAll(".js-change-logo");
trigger.forEach(id => {
const scene = new ScrollMagic.Scene({
triggerElement: id,
reverse: true,
triggerHook: 0.065,
duration: id.clientHeight
})
.on("enter", () => {
tweens.enterOuter();
tweens.enterInner();
})
.on("leave", () => {
tweens.leaveOuter();
tweens.leaveInner();
})
.addIndicators()
.addTo(mobile.controller);
});
},
destroyTweens: () => {
console.log("kill tweens");
TweenMax.killTweensOf(".c-logo__outer");
TweenMax.killTweensOf(".c-logo__inner");
TweenMax.set(".c-logo__outer", { clearProps: "all" });
TweenMax.set(".c-logo__inner", { clearProps: "all" });
}
}
};
$(window).on("resize", function() {
var win = $(this); //this = window
if (win.width() <= 450) {
// reanble controller if disabledbed before - doesnt work
mobile.controller.enabled(true);
mobile.changeLogo.init();
} else {
// disable scrollmagic controller
mobile.controller.enabled(false);
// destroy tweens
mobile.changeLogo.destroyTweens();
}
}).resize();
#hendrikeng I hope you don't mind, but I changed your code quite a lot. I've found myself needing to do this exact thing numerous times recently, so I based a lot of it on my own work.
I think the largest issue was that you were running a lot of functions on every resize which is not very performant and also makes it difficult to keep track of what's initialised and what's not. Mine relies on an init_flag so that it is only setup once.
There are then methods to update (duration on resize if needed) and destroy.
https://codepen.io/motionimaging/pen/848366af015cdf3a90de5fb395193502/?editors=0100
const mobile = {
init_flag: false,
init: () => {
$(window).on('resize', function(){
const width = $(window).width();
if( width <= 450 ){
if(! mobile.init_flag ){
mobile.setup();
} else {
mobile.update();
}
} else {
if( mobile.init_flag ){
mobile.destroy();
}
}
});
},
setup: () => {
mobile.init_flag = true;
mobile.triggers = document.querySelectorAll('.js-change-logo');
const tweens = {
enterOuter: () => {
TweenMax.fromTo(
'.c-logo__outer',
1,
{ fill: '#4dabfc' },
{ fill: '#fff' }
);
},
enterInner: () => {
TweenMax.fromTo(
'.c-logo__inner',
1,
{ fill: '#fff' },
{ fill: '#4dabfc' }
);
},
leaveOuter: () => {
TweenMax.fromTo(
'.c-logo__outer',
1,
{ fill: '#fff' },
{ fill: '#4dabfc' }
);
},
leaveInner: () => {
TweenMax.fromTo(
'.c-logo__inner',
1,
{ fill: '#4dabfc' },
{ fill: '#fff' }
);
}
};
mobile.controller = new ScrollMagic.Controller();
mobile.triggers.forEach(el => {
el.scene = new ScrollMagic.Scene({
triggerElement: el,
reverse: true,
triggerHook: 0.065,
duration: el.clientHeight
})
.on('enter', () => {
tweens.enterOuter();
tweens.enterInner();
})
.on('leave', () => {
tweens.leaveOuter();
tweens.leaveInner();
})
.addIndicators()
.addTo(mobile.controller);
});
},
update: () => {
if( mobile.init_flag ){
mobile.triggers.forEach(el => {
el.scene.duration(el.clientHeight);
});
}
},
destroy: function(){
mobile.controller.destroy(true);
mobile.init_flag = false;
$('.c-logo > *').attr('style', '');
},
};
mobile.init();

On Touchable highlights add componant

I want to add exported component on TouchableHighlight in react-native.
var MessageBox = require('./GiftedMessengerContainer');
var MyAppName = React.createClass({
_openGiftedMessanger(){
return (<MessageBox style={styles.container}/>);
},
render: function() {
return (
<View style={styles.container}>
<TouchableHighlight
style={styles.imButton}
onPress={this._openGiftedMessanger}>
<Text>Open Chat Room</Text>
</TouchableHighlight>
}
</View>
);
}
AppRegistry.registerComponent('MyAppName', () => AppName);
And my module is,
import React, {
Linking,
Platform,
ActionSheetIOS,
Dimensions,
View,
Text,
//Navigator,
Component,
} from 'react-native';
var GiftedMessenger = require('react-native-gifted-messenger');
var Communications = require('react-native-communications');
// var STATUS_BAR_HEIGHT = Navigator.NavigationBar.Styles.General.StatusBarHeight;
// if (Platform.OS === 'android') {
// var ExtraDimensions = require('react-native-extra-dimensions-android');
// var STATUS_BAR_HEIGHT = ExtraDimensions.get('STATUS_BAR_HEIGHT');
// }
class GiftedMessengerContainer extends Component {
constructor(props) {
super(props);
this._isMounted = false;
this._messages = this.getInitialMessages();
this.state = {
messages: this._messages,
isLoadingEarlierMessages: false,
typingMessage: '',
allLoaded: false,
};
}
componentDidMount() {
this._isMounted = true;
setTimeout(() => {
this.setState({
typingMessage: 'React-Bot is typing a message...',
});
}, 1000); // simulating network
setTimeout(() => {
this.setState({
typingMessage: '',
});
}, 3000); // simulating network
setTimeout(() => {
this.handleReceive({
text: 'Hello Awesome Developer',
name: 'React-Bot',
image: {uri: 'https://facebook.github.io/react/img/logo_og.png'},
position: 'left',
date: new Date(),
uniqueId: Math.round(Math.random() * 10000), // simulating server-side unique id generation
});
}, 3300); // simulating network
}
componentWillUnmount() {
this._isMounted = false;
}
getInitialMessages() {
return [
{
text: 'Are you building a chat app?',
name: 'React-Bot',
image: {uri: 'https://facebook.github.io/react/img/logo_og.png'},
position: 'left',
date: new Date(2016, 3, 14, 13, 0),
uniqueId: Math.round(Math.random() * 10000), // simulating server-side unique id generation
},
{
text: "Yes, and I use Gifted Messenger!",
name: 'Awesome Developer',
image: null,
position: 'right',
date: new Date(2016, 3, 14, 13, 1),
uniqueId: Math.round(Math.random() * 10000), // simulating server-side unique id generation
},
];
}
setMessageStatus(uniqueId, status) {
let messages = [];
let found = false;
for (let i = 0; i < this._messages.length; i++) {
if (this._messages[i].uniqueId === uniqueId) {
let clone = Object.assign({}, this._messages[i]);
clone.status = status;
messages.push(clone);
found = true;
} else {
messages.push(this._messages[i]);
}
}
if (found === true) {
this.setMessages(messages);
}
}
setMessages(messages) {
this._messages = messages;
// append the message
this.setState({
messages: messages,
});
}
handleSend(message = {}) {
// Your logic here
// Send message.text to your server
message.uniqueId = Math.round(Math.random() * 10000); // simulating server-side unique id generation
this.setMessages(this._messages.concat(message));
// mark the sent message as Seen
setTimeout(() => {
this.setMessageStatus(message.uniqueId, 'Seen'); // here you can replace 'Seen' by any string you want
}, 1000);
// if you couldn't send the message to your server :
// this.setMessageStatus(message.uniqueId, 'ErrorButton');
}
onLoadEarlierMessages() {
// display a loader until you retrieve the messages from your server
this.setState({
isLoadingEarlierMessages: true,
});
// Your logic here
// Eg: Retrieve old messages from your server
// IMPORTANT
// Oldest messages have to be at the begining of the array
var earlierMessages = [
{
text: 'React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and React. https://github.com/facebook/react-native',
name: 'React-Bot',
image: {uri: 'https://facebook.github.io/react/img/logo_og.png'},
position: 'left',
date: new Date(2016, 0, 1, 20, 0),
uniqueId: Math.round(Math.random() * 10000), // simulating server-side unique id generation
}, {
text: 'This is a touchable phone number 0606060606 parsed by taskrabbit/react-native-parsed-text',
name: 'Awesome Developer',
image: null,
position: 'right',
date: new Date(2016, 0, 2, 12, 0),
uniqueId: Math.round(Math.random() * 10000), // simulating server-side unique id generation
},
];
setTimeout(() => {
this.setMessages(earlierMessages.concat(this._messages)); // prepend the earlier messages to your list
this.setState({
isLoadingEarlierMessages: false, // hide the loader
allLoaded: true, // hide the `Load earlier messages` button
});
}, 1000); // simulating network
}
handleReceive(message = {}) {
// make sure that your message contains :
// text, name, image, position: 'left', date, uniqueId
this.setMessages(this._messages.concat(message));
}
onErrorButtonPress(message = {}) {
// Your logic here
// re-send the failed message
// remove the status
this.setMessageStatus(message.uniqueId, '');
}
// will be triggered when the Image of a row is touched
onImagePress(message = {}) {
// Your logic here
// Eg: Navigate to the user profile
}
render() {
return (
<GiftedMessenger
ref={(c) => this._GiftedMessenger = c}
styles={{
bubbleRight: {
marginLeft: 70,
backgroundColor: '#007aff',
},
}}
autoFocus={false}
messages={this.state.messages}
handleSend={this.handleSend.bind(this)}
onErrorButtonPress={this.onErrorButtonPress.bind(this)}
maxHeight={Dimensions.get('window').height} //- Navigator.NavigationBar.Styles.General.NavBarHeight - STATUS_BAR_HEIGHT}
loadEarlierMessagesButton={!this.state.allLoaded}
onLoadEarlierMessages={this.onLoadEarlierMessages.bind(this)}
senderName='Awesome Developer'
senderImage={null}
onImagePress={this.onImagePress}
displayNames={true}
parseText={true} // enable handlePhonePress, handleUrlPress and handleEmailPress
handlePhonePress={this.handlePhonePress}
handleUrlPress={this.handleUrlPress}
handleEmailPress={this.handleEmailPress}
isLoadingEarlierMessages={this.state.isLoadingEarlierMessages}
typingMessage={this.state.typingMessage}
/>
);
}
handleUrlPress(url) {
Linking.openURL(url);
}
// TODO
// make this compatible with Android
handlePhonePress(phone) {
if (Platform.OS !== 'android') {
var BUTTONS = [
'Text message',
'Call',
'Cancel',
];
var CANCEL_INDEX = 2;
ActionSheetIOS.showActionSheetWithOptions({
options: BUTTONS,
cancelButtonIndex: CANCEL_INDEX
},
(buttonIndex) => {
switch (buttonIndex) {
case 0:
Communications.phonecall(phone, true);
break;
case 1:
Communications.text(phone);
break;
}
});
}
}
handleEmailPress(email) {
Communications.email(email, null, null, null, null);
}
}
module.exports = GiftedMessengerContainer;
How to add custom views on my screen?
You need to make use of something called as states (in React terms). When onPress function is invoked you set a state variable to open/close which then can be used to show/hide the custom view. For ex:
var MessageBox = require('./GiftedMessengerContainer');
var MyAppName = React.createClass({
getInitialState: function(){
return {
messageBoxShow: 'false'
}
},
_openGiftedMessanger:function(){
this.setState({
messageBoxShow: 'true'
});
},
render: function() {
return (
<View style={styles.container}>
<TouchableHighlight
style={styles.imButton}
onPress={this._openGiftedMessanger}>
<Text>Open Chat Room</Text>
</TouchableHighlight>
{this.state.messageBoxShow === 'true' ? <MessageBox style={styles.container}/> : null };
</View>
);
}
AppRegistry.registerComponent('MyAppName', () => AppName);

Categories