Как обновить JS Typed Array из Reason? - PullRequest
1 голос
/ 16 марта 2019

Я пытаюсь обновить ImageData контекста изображения Canvas, и когда я пытаюсь установить элементы в массиве данных, я получаю сообщение об ошибке, в котором говорится, что массив имеет тип Js.Typed_array.Uint8ClampedArray.t, когда что-то ожидается array('a).

Почему я не могу обновить реализацию JS TypedArray?

Вот мой код компонента (несколько упрощенный для ясности):

let make = _children => {
    let map = FeatureMap.make(100, 100);
    let (width, height) = map.dimensions;

    {...component,
        initialState: () => {
            map: map,
            canvasRef: ref(None)
        },
        didMount: self => switch (self.state.canvasRef^) {
            | None => ()
            | Some(canvas) => {
                let ctx = getContext2d(canvas);
                let imageData = createImageDataCoords(ctx, ~width=float_of_int(width), ~height=float_of_int(height));
                let data = Webapi.Dom.Image.data(imageData);

                Array.iteri((x, row) => {
                    Array.iteri((y, weight) => {
                        let index = (x * width + y) * 4;
                        let (r, g, b) = weight;
                        data[index + 0] = r;
                        data[index + 1] = g;
                        data[index + 2] = b;
                        data[index + 3] = 0;
                    }, row);
                }, map.weights);

                ctx |> putImageData(imageData, 0., 0., 0., 0., float_of_int(width), float_of_int(height));  
            }
        },
        render: _self => <canvas id="weight-map"
                        width={string_of_int(width)}
                        height={string_of_int(width)}
                        ref={_self.handle(setCanvasRef)}></canvas>
    };
};

1 Ответ

3 голосов
/ 17 марта 2019

Для компилятора тип array('a) отличается от типа Js.Typed_array.Uint8ClampedArray.t, поэтому их операции (включая индексирование) не являются взаимозаменяемыми.Это тот же принцип, по которому вы не можете добавлять int и float.

Чтобы установить типизированный элемент массива, вам нужно найти (или написать) привязку, которая позволяет вам делать это явно, а нечем с помощью оператора индексации.Чтобы сделать это, вы можете посмотреть в модуле Js.Typed_array - есть module type S, который мы можем обозначить как «все модули типизированного массива должны соответствовать этой сигнатуре модуля».И это включает в себя модуль Js.Typed_array.Uint8ClampedArray.Таким образом, вы можете использовать функцию unsafe_set типа модуля S для установки элементов типизированного массива, потому что Js.Typed_array.Uint8ClampedArray реализует это:

let module UI8s = Js.Typed_array.Uint8ClampedArray;
UI8s.unsafe_set(data, index, r);
UI8s.unsafe_set(data, index + 1, g);
UI8s.unsafe_set(data, index + 2, b);
UI8s.unsafe_set(data, index + 3, 0);
...