I have this path:
<path id="secnb1l1" class="lungon"
fill="none" stroke="black" stroke-width="1"
d="M 93.00,444.00
C 93.00,444.00 114.00,506.00 114.00,506.00
102.30,512.28 100.00,518.71 100.00,531.00
100.00,531.00 86.00,534.00 86.00,534.00
86.00,534.00 68.95,485.00 68.95,485.00
68.95,485.00 58.00,452.00 58.00,452.00
58.00,452.00 93.00,444.00 93.00,444.00 Z
M 75.00,458.00
C 75.00,458.00 79.00,458.00 79.00,458.00
78.99,466.29 79.26,463.93 76.00,471.00
76.00,471.00 86.00,471.00 86.00,471.00
82.12,462.60 83.00,464.37 83.00,455.00
83.00,455.00 75.00,458.00 75.00,458.00 Z" />
And I want to convert it into JSON. Just like on this LINK
quick example of SVG converted into JSON:
(SVG):
<path d=" M 10 25
L 10 75
L 60 75
L 10 25"
stroke="red" stroke-width="2" fill="none" />
(JSON):
var lineData = [ { "x": 1, "y": 5}, { "x": 20, "y": 20},
{ "x": 40, "y": 10}, { "x": 60, "y": 40},
{ "x": 80, "y": 5}, { "x": 100, "y": 60}];
I'm afraid that there's no generator to make my works easier. It's a pain to convert it manually.
Thanks in advance for your help :)
EDIT
I'm using d3.js for zoom and pan.
If you do not want to fiddle around with string operations, you can also use the DOM Interface.
Interface
PathSegList
From there you can iterate over the path elements path segments list and create a json string from that.
var path = document.getElementById(<pathid>),
seglist = path.pathSegList,
length = seglist.numberOfItems, i = 0, seg,
out = [], data, type;
for (; i < length; i++) {
seg = seglist.getItem(i);
type = seg.pathSegTypeAsLetter;
data = { type: seg.pathSegTypeAsLetter };
switch (type) {
case 'M':
case 'm':
case 'l' :
case 'L' :
data.x = seg.x;
data.y = seg.y;
break;
case 'C':
case 'c':
data.x = seg.x;
data.y = seg.x;
data.x1 = seg.x1;
data.y1 = seg.y1;
data.x2 = seg.x2;
data.y2 = seg.y2;
break;
/*
* to
* be
* continued
*/
}
out.push(data);
}
return JSON.stringify(out);
I have not test the code above, it should outline the basic process of iterating the Paths' segments. Since there are quite a couple of different types of segments, you can, as outlines above, »switch« over the type and create suitable data from there. Or, instead of path.pathSegList you could use path.normalizedPathSegList what return a list of segments, where each segment is converted to the type of cubic Bezier, but when tried it the last time, I got an »Not yet implemented Error«.
I have created a fiddle showing that the code works!
Given that you haven't specified things such as resolution etc. for your path around curves, I've just created a JSON with an extra property for the path type from that co-ordinate to the next one.
var d = document.getElementById('secnb1l1').getAttribute('d');
d = d.replace(/\s{2,}/g, ' '); // Remove multiple spaces
d = d.replace(/([a-zA-Z])\s[0-9]/g, '$1,'); // Add letters to coords group
d = d.split(" "); // Split on space
var coords = [];
for (var i = 0; i < d.length; i++) {
var coordString = d[i];
var coordArray = coordString.split(",");
var coord = {
x: coordArray[coordArray.length - 2],
y: coordArray[coordArray.length - 1]
};
if (coordArray.length > 2) {
coord.path = coordArray[0];
}
coords.push(coord);
}
You can see it working in this fiddle.
You can head over here, we have both node packages and API, as well as a simple web interface.
Github: https://github.com/Rexfont/svgJson
The API instruction is given in there as well
example:
svgjson({data: 'filepath/string', web: false, file: true, remove: true, output: true, filename: 'example.txt'})
You can use the API if you wish to use it multiple times on web or use the npm for node
Related
This bounty has ended. Answers to this question are eligible for a +100 reputation bounty. Bounty grace period ends in 21 hours.
Basj is looking for a canonical answer:
The current answer is useful. One detail: how to have one of the layers (for example, the background layer) as an RGB image instead of just a z-axis heatmap?
I'm trying to port this answer to a 100% Plotly.JS solution.
TL;DR : how to have two heatmaps on top of eacher with an opacity slider, with Plotly.JS (no Python)?
Beginning of solution, but how to add the second trace?
const z = [];
for (let i = 0; i < 500; i++)
z.push(Array.from({ length: 600 }, () => Math.floor(Math.random() * 100)));
const data = [{ z: z, colorscale: "YlGnBu", type: "heatmap" }];
const steps = [];
for (let i = 0; i <= 100; i++)
steps.push({ label: i + "%", execute: true, method: "restyle", args: [{ opacity: i / 100 }] });
const layout = { sliders: [{ name: "slider", steps: steps, active: 100 }] };
Plotly.newPlot("graph", data, layout);
<script src="https://cdn.plot.ly/plotly-2.16.2.min.js"></script>
<div id="graph"></div>
For reference: original Python solution:
from PIL import Image
import plotly.graph_objects as go
import numpy as np
import scipy.misc
imgA = scipy.misc.face()
imgB = Image.fromarray(np.random.random(imgA.shape[:2])*255).convert('RGB')
fig = go.Figure([
go.Image(name='raccoon', z=imgA, opacity=1), # trace 0
go.Image(name='noise', z=imgB, opacity=0.5) # trace 1
])
slider = {
'active': 50,
'currentvalue': {'prefix': 'Noise: '},
'steps': [{
'value': step/100,
'label': f'{step}%',
'visible': True,
'execute': True,
'method': 'restyle',
'args': [{'opacity': step/100}, [1]] # apply to trace [1] only
} for step in range(101)]
}
fig.update_layout(sliders=[slider])
fig.show(renderer='browser')
The second trace goes into the data array as well. The thing to note is that indexing matters : the trace at index 1 is drawn above the trace at index 0, and so on.
For the slider configuration, it should be the same as in python : each step change triggers the same 'restyle' method with the same arguments, ie. Plotly.restyle(graphDiv, ...args), that is, with args such that the method call matches the signature :
Plotly.restyle(graphDiv, update [, traceIndices])
Now, the most important thing is which trace (traceIndices) the slider should target, that is, which index or which name for explicitly named traces (default is all if I'm not wrong), but again here it doesn't change between Python and Javascript.
Here is a full example (play around with it on codepen.io) :
// Random z data
const w = {length: 600};
const h = {length: 400};
const z0 = Array.from(h, () => Array.from(w, () => Math.floor(Math.random() * 100)));
const z1 = Array.from(h, () => Array.from(w, () => Math.floor(Math.random() * 100)));
// Initial opacity for the trace 'above'
const op_init = 0.5;
const data = [
// Nb. Trace 1 drawn on top of trace 0
{type: 'heatmap', z: z0, colorscale: 'Greys'}, // trace 0
{type: 'heatmap', z: z1, colorscale: 'Cividis', opacity: op_init} // trace 1
];
// Steps for the opacity slider
const steps = [];
const n_steps = 100; // number of steps above step 0
for (let i = 0; i <= n_steps; i++) {
steps.push({
label: i + '%',
execute: true,
method: 'restyle',
args: [{
opacity: i/n_steps
}, [1]] // <- Nb. this applies only to trace 1
});
}
const layout = {
width: 600,
sliders: [{
steps: steps,
active: Math.round(op_init * n_steps), // slider default matches op_init
pad: {t: 30},
currentvalue: {prefix: 'opacity: '}
}]
};
Plotly.newPlot('plot', data, layout);
Image vs Heatmap
A Heatmap works only with single channel data (individual value-to-color mappings according to a given colorscale).
When working with rgb (or rgba, rgba256, hsl, hsla), one has to use the image type. The difference is that z must be a 2-dimensional array in which each element is an array of 3 or 4 numbers representing a color (the colormodel should be set accordingly).
For example, setting an rgb image made of noise as the background layer :
const z0 = Array.from(h, () => Array.from(w, () => ['r', 'g', 'b'].map(() => Math.floor(Math.random() * 255)) ));
// ...
const data = [
{type: 'image', z: z0, colormodel: 'rgb'}, // trace 0
{type: 'heatmap', z: z1, colorscale: 'Cividis', opacity: op_init} // trace 1
];
Here a second example where we have an rgb[a] image (DOM object img) and its pixel data represented as a 1-dimensional Uint8Array (uint8Arr), which need to be converted in 2d :
const z0 = [];
const nChannels = uint8Arr.length / img.width / img.height;
const chunkSize = uint8Arr.length / img.height;
const z0_model = nChannels === 4 ? 'rgba' : 'rgb';
for (let i = 0; i < uint8Arr.length; i += chunkSize) {
const chunk = uint8Arr.slice(i, i + chunkSize);
const row = [];
for (let j = 0; j < chunk.length; j += nChannels)
row.push(chunk.slice(j, j + nChannels));
z0.push(row);
}
// ...
const data = [
{type: 'image', z: z0, colormodel: z0_model}, // trace 0
{type: 'heatmap', z: z1, colorscale: 'Cividis', opacity: op_init} // trace 1
];
Nb. When you plot an image, the yaxis is automatically reversed (unless specified otherwise, which would display the image upside down). This affects the orientation of the heatmap y-labels, as they're on the same plot, but only the labels not the data.
Here is the layout settings ensuring that both traces share the same aspect ratio and that the image is oriented correctly :
const layout = {
// ...
xaxis: {anchor: 'y', scaleanchor: 'y', constrain: 'domain'},
yaxis: {anchor: 'x', autorange: 'reversed', constrain: 'domain'},
};
why it is showing me 36 even though the minimum number is 27
var combination = [27, 36]
for (let x in combination) {
if (combination[x] < 50) {
var min = Math.min(combination[x])
}
}
console.log(min)
i tried this multiple ways like
var combination = [27, 30, 40, 44, 3, 239, 329, 2, 5, 20923, 96]
for (let x in combination) {
if (combination[x] < 50) {
var min = Math.min(combination[x])
}
}
console.log(min) //output-- 5 //it should be 2
in this third example i add (-) to 2
var combination = [27, 30, 40, 44, 3, 239, 329, -2, 5, 20923, 96]
for (let x in combination) {
if (combination[x] < 50) {
var min = Math.min(combination[x])
}
}
console.log(min) // output-- still 5 // it should be -2
again when am adding (-) to other numbers like in -96 or -5 the output was okay (-96) but when im adding (-) to 2 it is not showing me -2 in the output instead it showing me 5
not only in javascript i tried this with lua, php but output was same as js
can anyone explain me why this happen and how solve this
You're not comparing values to determine the minimum, but instead just replacing the min variable with the last number in the array that is smaller than 50. This can be fixed as follows:
let min = undefined;
for (let x in combination) {
if (combination[x] < 50) {
min = min == undefined ? combination[x] : Math.min(min, combination[x])
}
}
Using filter and reduce, this can be made a lot shorter:
combination.filter(x => x < 50).reduce((x, y) => Math.min(x, y))
Im new to SVG and paths on HTML5 and I have some issues with an animation im trying to do:
In the next link its a preview of what im trying to do: http://jsfiddle.net/fxwL68hr/1/
The problem is: only works on Google Chrome and Firefox Developer Edition.
In summary: When I hover the SVG, all the triangles do an animation. However triangles 3 and 4 actually change the paths coords to create a bigger triangle. How I can animate this change of coords in those triangles without using css d: path() so it can work in all (or at least the majority of) browsers.
The next link is a : CodePen with my solution
I'm not very sure you will like it.
In the HTML I'm adding a defs element with the target path for triangles 3 & 4:
<svg id="svg" class="svg_bg" width="50%" viewBox="0 0 100 75">
<defs>
<path id="t3Target" d="M 100 75 L 0 0 L 0 75 Z" />
<path id="t4Target" d="M 100 75 L 100 0 L 0 0 Z" />
</defs>
<path id="triangle1" class="triangle1" d="M 17.5 28.5 L 55 75 L 81 75 Z"></path>
<path id="triangle2" class="triangle2" d="M 36.5 8 L 54.5 75 L 87 75 Z"></path>
<path id="triangle3" class="triangle3" d="M 110 -25 L 38 75 L 77 75 Z"></path>
<path id="triangle4" class="triangle4" d="M 49 75 L 84 75 L 120 41.5 Z"></path>
</svg>
For the triangles 3 & 4 I'm using JavaScript.
let rid = null;
let shapesRy = [];
class Shape{
constructor(path_a,path_b,morphingPath){
this.target = getArgsRy(path_a);
this.vals = getArgsRy(path_b);
this.morphingPath = morphingPath;
this.memory = [];
for(let i=0; i < this.vals.length; i++){
this.memory[i] = [];
this.memory[i][0] = this.target[i].slice();
this.memory[i][1] = this.vals[i].slice();
this.updatePath();
}
}
updateValues() {
for(let i = 0;i < this.memory.length; i++){
let dist_x = this.target[i][1] - this.vals[i][1];
let vel_x = dist_x/10;
this.vals[i][1] += vel_x;
let dist_y = this.target[i][2] - this.vals[i][2];
let vel_y = dist_y/10;
this.vals[i][2] += vel_y;
}
let dist_x = this.target[0][1] - this.vals[0][1];
if (Math.abs(dist_x) < .01) {
if(rid){window.cancelAnimationFrame(rid);
rid = null;
}
}
}
updatePath() {
let d=`M${this.vals[0][1]},${this.vals[0][2]}`;
for(let i = 1;i < this.vals.length -1; i++){
d += `L${this.vals[i][1]},${this.vals[i][2]}`
}
d +="Z";
this.morphingPath.setAttributeNS(null, "d", d);
}
}
shapesRy.push(new Shape(t3Target,triangle3,triangle3));
shapesRy.push(new Shape(t4Target,triangle4,triangle4));
function Frame() {
rid = window.requestAnimationFrame(Frame);
shapesRy.map((s) => {
s.updateValues();
s.updatePath();
})
}
svg.addEventListener(
"mouseover",
function() {
if (rid) {
window.cancelAnimationFrame(rid);
rid = null;
}
shapesRy.map((s) => {
for(let i = 0;i < s.memory.length; i++){
s.memory[i].reverse();
s.target[i] = s.memory[i][1].slice();
}
})
Frame();
},
false
);
svg.addEventListener(
"mouseout",
eAction,
false
);
function eAction(){
{
if (rid) {
window.cancelAnimationFrame(rid);
rid = null;
}
shapesRy.map((s) => {
for(let i = 0;i < s.memory.length; i++){
s.memory[i].reverse();
s.target[i] = s.memory[i][1].slice();
}
})
Frame();
}
}
function getArgsRy(path) {
let d = path.getAttribute("d").replace(/\r?\n|\r/g, ""); //remove breaklines
if (d.charAt(0) == "m") {
d = "M" + d.slice(1);
}
let argsRX = /(?=[a-zA-Z])/;
let args = d.split(argsRX);
let ArgsRy = [];
args.map(arg => {
let argRy = arg
.slice(1)
.replace(/\-/g, " -")
.split(/[ ,]+/);
argRy.map((p, i) => {
if (p == "") {
argRy.splice(i, 1);
}
});
for (let i = 0; i < argRy.length; i++) {
argRy[i] = parseFloat(argRy[i]);
}
argRy.unshift(arg[0]);
ArgsRy.push(argRy);
});
return ArgsRy;
}
This is a blog post where I'm explaining the code: Morphing in SVG - first steps
There is an additional problem with the CSS animation for the triangles 1 & 2 (your CSS) since CSS transforms on SVG elements are extremely buggy.
You may want to read this article: Transforms on SVG Elements
Alternatively you may want to use JavaScript for all 4 triangles.
There always is a finite transform from one triangle to another. The math behind that is non-trivial, but with a bit of fiddling around with the grafical transformation tool for example of Inkscape, you can find it. That way, I got to the following:
triangle 3: matrix(0, 1.92308, -1,0.634615, 75, -120.673)
triangle 4: matrix(0, -2.14286, 2.98507, -2.30277, -123.881, 352.708)
Addendum: I have done the appropriate math now. I've even described it already in the context of another answer: Draw circle svg orthogonal projections. While in that answer, three points were used to describe a square that then underwent an orthogonal projection, the mathematical content is just this: take three separate points (not in one line) as source and another three points (same constraints) as target, and the function generate() quoted in that answer will give you the transform matrix.
The animation has to run between the neutral matrix(1, 0, 0, 1, 0, 0) and the one above as a transform property. See it working in this fiddle.
Downside: according to Can I Use, IE does not support CSS transforms on SVG elements, but that was also true for your first two triangles.
In addition, why don't you use a CSS transition instead of an animation? You go from one state to a second and back. Describe the base state and the hover state and transition: transform 1s ease does the rest.
I'm trying to extend the JS from this Codrops article:
https://tympanus.net/Development/StorytellingMap/
I'm attempting to animate multiple SVG lines to "split" the SVG path. To simulate it I created multiple paths overlaid on one another. The pertinent SVG code is as such (for reference, example):
<g id="trail-path" display="none">
<path display="inline" d="M1058.75,817.41a159.76,159.76,0,0,0,11.15-18.24c1.16-2.23,2.31-4.72,1.75-7.17-.64-2.81-3.29-4.65-5.8-6.06a77.9,77.9,0,0,0-29.34-9.42c-4.94-.55-10-.63-14.73-2.09s-9-4.25-13.21-7Q982,749.77,956.19,731.08c-5.52-4-6.81-10.78-7.54-17.56s-1.07-14-5.05-19.56c-6.48-9-20-10.06-27.26-18.47-6.31-7.34-6.07-18.23-4-27.69.83-3.83,1.91-7.67,1.73-11.59-.33-7-4.6-13.1-8.71-18.77-5.63-7.76-11.87-16-21-18.91-6-1.91-10.76-6.9-15-11.53s-8.06-9.68-12.69-13.93c-6-5.48-13.25-9.54-18.62-15.63-6.34-7.2-9.47-16.58-13-25.51-.94-2.38-2.11-5-4.46-6-10.45-4.59-20.41-11.33-27.17-20.53-3.37-4.58-5.63-9.85-7.87-15.07-2.61-6.1-5.27-12.39-5.4-19-.17-8.82,4.17-17.39,3.26-26.16-.5-4.79-2.53-9.26-4.53-13.64l-15.15-33.08
M1058.75,817.41a159.76,159.76,0,0,0,11.15-18.24c1.16-2.23,2.31-4.72,1.75-7.17-.64-2.81-3.29-4.65-5.8-6.06a77.9,77.9,0,0,0-29.34-9.42c-4.94-.55-10-.63-14.73-2.09s-9-4.25-13.21-7Q982,749.77,956.19,731.08c-5.52-4-6.81-10.78-7.54-17.56s-1.07-14-5.05-19.56c-6.48-9-20-10.06-27.26-18.47-6.31-7.34-6.07-18.23-4-27.69,2.67-12.28-.83-25.88,6.72-36.71,3.74-5.37,9.15-9.33,13.36-14.35,11.71-14,12.1-36.16.89-50.53-7.54-9.65-19.06-15.39-27.38-24.38-5.24-5.66-9.07-12.45-12.85-19.17" fill="none" stroke="red" stroke-miterlimit="10" stroke-width="5"/>
</g>
I'm 90% sure that the code I should primarily be focusing on is here. I just need a way to iterate it for each path component. I'm looking at "t.trailPath" and the path contained within "#trail-path." I initially tried multiple grouped path elements and iterating them but it didn't work (and rightfully so since I realized that was the wrong approach).
(0, p.default)(this.props.mapSrc).then(function(e) {
t.mapSVG = Array.from((new DOMParser).parseFromString(e, "image/svg+xml").childNodes).filter(function(t) {
var e = t.tagName;
return "undefined" == typeof e ? !1 : "svg" == e.toLowerCase()
})[0], t.cameraPath = t.mapSVG.querySelector("#camera-path path"), t.trailPath = t.mapSVG.querySelector("#trail-path path"), t.points = Array.from(t.mapSVG.querySelectorAll("#points circle")).map(function(e) {
var i = parseFloat(e.getAttribute("cx")),
r = parseFloat(e.getAttribute("cy"));
return {
x: i,
y: r,
length: d.getLengthAtPoint(t.trailPath, {
x: i,
y: r
}),
label: (e.getAttribute("id") || "").replace(/_/g, " "),
color: e.getAttribute("fill") || "black",
radius: parseFloat(e.getAttribute("r"))
}
}).sort(function(t, e) {
return t.length - e.length
}), t.cameraSubdivisions = d.subdividePath(t.cameraPath, t.cameraSubdivisionSize, !0), t.cameraLength = d.getLength(t.cameraPath), t.cameraBreakpoints = t.setupBreakpoints(t.cameraPath), t.trailSubdivisions = d.subdividePath(t.trailPath, t.trailSubdivisionSize, !0), t.trailBreakpoints = t.setupBreakpoints(t.trailPath), t.trailLength = d.getLength(t.trailPath), (0, l.loadImage)(t.props.mapSrc).then(function(e) {
t.mapWidth = e.width, t.mapHeight = e.height, 0 == t.mapHeight && (t.mapWidth = 2040, t.mapHeight = 1178), t.map = b(t.mapScales).map(function(i, r) {
var n = 1 + (t.mapMaxScale - 1) / (t.mapScales - 1) * r,
s = (0, h.default)(t.mapWidth * n, t.mapHeight * n),
a = s.getContext("2d", {
alpha: !1
});
return a.fillStyle = "#a8cecf", a.fillRect(0, 0, t.mapWidth * n, t.mapHeight * n), a.drawImage(e, 0, 0, t.mapWidth * n, t.mapHeight * n), {
map: s,
scale: n
}
}), t.mapBuffer = (0, h.default)(1, 1), t.mapBufferCtx = t.mapBuffer.getContext("2d", {
alpha: !1
}), t.updateMapBufferSize(), t.mapBufferCtx.fillStyle = "#a8cecf", t.mapBufferCtx.fillRect(0, 0, t.mapBufferSize.x, t.mapBufferSize.y), t.mapBufferOffset = {
x: 0,
y: 0
}, t.mapBufferScale = t.mapScale, t.ready = !0, document.addEventListener("scroll", t.onScroll.bind(t)), t.onScroll()
})
})
The site for reference. It's not updated to include attempts as obviously it breaks it. It focuses on Giarratana alongside Chiaramonte as it should, but no dice on getting the path traced or highlighted.
https://adrianatwell.github.io/bond-of-strangers/code/html/
The code is here for reference. It's 6.5K lines though so it wouldn't be much help.
https://github.com/adrianatwell/bond-of-strangers/blob/master/code/html/assets/js/app.js
I'm way in over my head with this script it seems, I've been tooling around with it and Google for the past 72 hours. Haha.
I'm trying to iterate through a Redis bitmap and get the offset of all set bits.
I tried several methods but all of them have failed, here is a snipped I got from Redis Essentials book by Maxwell. I went through the code several times, still unable to figure out whats going wrong.
var bitmap = 'test';
redisClient.get(bitmap, function(err, bitmapValue){
var userIds = [];
var data = bitmapValue.toJSON().data;
data.forEach(function(byte, byteIndex){
for(var bitIndex = 7; bitIndex >= 0; bitIndex--) {
var visited = byte >> bitIndex & 1;
}
if(visited === 1) {
var userId = byteIndex * 8 + (7 - bitIndex);
userIds.push(userId);
}
})
console.log(userIds);
});
Most of the time I get empty result, usually when the bitmap is small. When I try large bitmaps I get array full of multiples of 8. A sample result I got is shown below, which is incorrect, the bitcount of that bitmap is 690, while I got only 91.
[8,
16,
32,
144,
176,
256,
320,
440,
456,
520,
584,
592,
624,
640,
648,
680,
696,
704,
712,
720,
752,
760,
848,
1056,
1088,
1104,
1112,
1120,
1136,
1144,
1160,
1168,
1224,
1248,
1264,
1280,
1312,
1328,
1424,
1480,
1496,
1544,
1600,
1680,
1792,
1824,
1840,
1904,
1976,
2080,
2112,
2144,
2224,
2240,
2296,
2392,
2400,
2504,
2512,
2584,
2616,
2712,
2856,
2880,
2912,
2976,
3048,
3288,
3328,
3352,
3360,
3368,
3376,
3432,
3440,
3496,
3600,
3616,
3624,
3632,
3704,
3752,
3776,
3832,
3880,
3936,
4056,
4264,
4296,
4352,
4376]
I don't have the bitmap you've stored under the key test, so testing is difficult. However, reading the code it looks like the if statement is placed wrongly - it should be:
var bitmap = 'test';
redisClient.get(bitmap, function(err, bitmapValue){
var userIds = [];
var data = bitmapValue.toJSON().data;
data.forEach(function(byte, byteIndex){
for(var bitIndex = 7; bitIndex >= 0; bitIndex--) {
var visited = byte >> bitIndex & 1;
if(visited === 1) {
var userId = byteIndex * 8 + (7 - bitIndex);
userIds.push(userId);
}
}
})
console.log(userIds);
});