mirror of
https://github.com/penpot/penpot.git
synced 2025-12-26 07:58:49 -05:00
Compare commits
17 Commits
develop
...
skia-rende
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
00ce454ba6 | ||
|
|
fa84b1e67d | ||
|
|
4cf1406cae | ||
|
|
5b8c8e93b2 | ||
|
|
b3871c8bfc | ||
|
|
1579be27cc | ||
|
|
218b5e52e5 | ||
|
|
495a42db0c | ||
|
|
fed74fccc5 | ||
|
|
279e0d8bea | ||
|
|
b5d3de9fab | ||
|
|
cd04a41d98 | ||
|
|
66aa5fd01f | ||
|
|
721d9ee399 | ||
|
|
69582add4b | ||
|
|
a1da3065f7 | ||
|
|
71de1a28fc |
@@ -76,6 +76,7 @@
|
||||
"vite": "^5.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"canvaskit-wasm": "^0.39.1",
|
||||
"date-fns": "^2.30.0",
|
||||
"draft-js": "^0.11.7",
|
||||
"eventsource-parser": "^1.1.1",
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
[app.main.ui.workspace.viewport.rules :as rules]
|
||||
[app.main.ui.workspace.viewport.scroll-bars :as scroll-bars]
|
||||
[app.main.ui.workspace.viewport.selection :as selection]
|
||||
[app.main.ui.workspace.viewport.sk :as sk]
|
||||
[app.main.ui.workspace.viewport.snap-distances :as snap-distances]
|
||||
[app.main.ui.workspace.viewport.snap-points :as snap-points]
|
||||
[app.main.ui.workspace.viewport.top-bar :as top-bar]
|
||||
@@ -92,6 +93,7 @@
|
||||
|
||||
;; CONTEXT
|
||||
page-id (mf/use-ctx ctx/current-page-id)
|
||||
page (mf/deref refs/workspace-page)
|
||||
|
||||
;; DEREFS
|
||||
drawing (mf/deref refs/workspace-drawing)
|
||||
@@ -302,49 +304,54 @@
|
||||
|
||||
[:& top-bar/top-bar]]
|
||||
|
||||
[:svg.render-shapes
|
||||
{:id "render"
|
||||
:xmlns "http://www.w3.org/2000/svg"
|
||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
:xmlns:penpot "https://penpot.app/xmlns"
|
||||
:preserveAspectRatio "xMidYMid meet"
|
||||
:key (str "render" page-id)
|
||||
:width (:width vport 0)
|
||||
:height (:height vport 0)
|
||||
:view-box (utils/format-viewbox vbox)
|
||||
:style {:background-color background
|
||||
:pointer-events "none"}
|
||||
:fill "none"}
|
||||
#_[:svg.render-shapes
|
||||
{:id "render"
|
||||
:xmlns "http://www.w3.org/2000/svg"
|
||||
:xmlnsXlink "http://www.w3.org/1999/xlink"
|
||||
:xmlns:penpot "https://penpot.app/xmlns"
|
||||
:preserveAspectRatio "xMidYMid meet"
|
||||
:key (str "render" page-id)
|
||||
:width (:width vport 0)
|
||||
:height (:height vport 0)
|
||||
:view-box (utils/format-viewbox vbox)
|
||||
:style {:background-color background
|
||||
:pointer-events "none"}
|
||||
:fill "none"}
|
||||
|
||||
[:defs
|
||||
[:linearGradient {:id "frame-placeholder-gradient"}
|
||||
[:animateTransform
|
||||
{:attributeName "gradientTransform"
|
||||
:type "translate"
|
||||
:from "-1 0"
|
||||
:to "1 0"
|
||||
:dur "2s"
|
||||
:repeatCount "indefinite"}]
|
||||
[:stop {:offset "0%" :stop-color (str "color-mix(in srgb-linear, " background " 90%, #777)") :stop-opacity 1}]
|
||||
[:stop {:offset "50%" :stop-color (str "color-mix(in srgb-linear, " background " 80%, #777)") :stop-opacity 1}]
|
||||
[:stop {:offset "100%" :stop-color (str "color-mix(in srgb-linear, " background " 90%, #777)") :stop-opacity 1}]]]
|
||||
[:defs
|
||||
[:linearGradient {:id "frame-placeholder-gradient"}
|
||||
[:animateTransform
|
||||
{:attributeName "gradientTransform"
|
||||
:type "translate"
|
||||
:from "-1 0"
|
||||
:to "1 0"
|
||||
:dur "2s"
|
||||
:repeatCount "indefinite"}]
|
||||
[:stop {:offset "0%" :stop-color (str "color-mix(in srgb-linear, " background " 90%, #777)") :stop-opacity 1}]
|
||||
[:stop {:offset "50%" :stop-color (str "color-mix(in srgb-linear, " background " 80%, #777)") :stop-opacity 1}]
|
||||
[:stop {:offset "100%" :stop-color (str "color-mix(in srgb-linear, " background " 90%, #777)") :stop-opacity 1}]]]
|
||||
|
||||
(when (dbg/enabled? :show-export-metadata)
|
||||
[:& use/export-page {:options options}])
|
||||
(when (dbg/enabled? :show-export-metadata)
|
||||
[:& use/export-page {:options options}])
|
||||
|
||||
;; We need a "real" background shape so layer transforms work properly in firefox
|
||||
[:rect {:width (:width vbox 0)
|
||||
:height (:height vbox 0)
|
||||
:x (:x vbox 0)
|
||||
:y (:y vbox 0)
|
||||
:fill background}]
|
||||
[:rect {:width (:width vbox 0)
|
||||
:height (:height vbox 0)
|
||||
:x (:x vbox 0)
|
||||
:y (:y vbox 0)
|
||||
:fill background}]
|
||||
|
||||
[:& (mf/provider ctx/current-vbox) {:value vbox'}
|
||||
[:& (mf/provider use/include-metadata-ctx) {:value (dbg/enabled? :show-export-metadata)}
|
||||
[:& (mf/provider ctx/current-vbox) {:value vbox'}
|
||||
[:& (mf/provider use/include-metadata-ctx) {:value (dbg/enabled? :show-export-metadata)}
|
||||
;; Render root shape
|
||||
[:& shapes/root-shape {:key page-id
|
||||
:objects base-objects
|
||||
:active-frames @active-frames}]]]]
|
||||
[:& shapes/root-shape {:key page-id
|
||||
:objects base-objects
|
||||
:active-frames @active-frames}]]]]
|
||||
|
||||
;; IT's MAGIC!
|
||||
[sk/canvas {:objects base-objects
|
||||
:active-frames @active-frames
|
||||
:vbox vbox}]
|
||||
|
||||
[:svg.viewport-controls
|
||||
{:xmlns "http://www.w3.org/2000/svg"
|
||||
@@ -629,4 +636,10 @@
|
||||
:objects base-objects
|
||||
:modifiers modifiers
|
||||
:shape frame
|
||||
:view-only true}]))]]]]))
|
||||
:view-only true}]))]]]
|
||||
|
||||
(when (= (:name page) "DOOM")
|
||||
[:iframe {:src "/wasm/doom/index.html"
|
||||
:width 1280
|
||||
:height 720
|
||||
:style {:position "absolute" :top 0 :left 0 :z-index 10000 :pointer-events "all"}}])]))
|
||||
|
||||
49
frontend/src/app/main/ui/workspace/viewport/sk.cljs
Normal file
49
frontend/src/app/main/ui/workspace/viewport/sk.cljs
Normal file
@@ -0,0 +1,49 @@
|
||||
(ns app.main.ui.workspace.viewport.sk
|
||||
(:require-macros [app.main.style :as stl])
|
||||
(:require
|
||||
;; TODO el cp de node_modules/canvaskit-wasm/bin/canvaskit.wasm
|
||||
["./sk_impl.js" :as impl]
|
||||
[rumext.v2 :as mf]))
|
||||
|
||||
(defn get-objects-as-iterable
|
||||
[objects]
|
||||
(.values js/Object (clj->js objects)))
|
||||
|
||||
(mf/defc canvas
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [objects (unchecked-get props "objects")
|
||||
vbox (unchecked-get props "vbox")
|
||||
canvas-ref (mf/use-ref nil)
|
||||
canvas-kit (mf/use-state nil)]
|
||||
|
||||
(mf/with-effect [vbox]
|
||||
(let [k @canvas-kit
|
||||
objects (get-objects-as-iterable objects)]
|
||||
(when (some? k)
|
||||
(.setVbox ^js k vbox)
|
||||
(.draw k objects))))
|
||||
|
||||
(mf/with-effect [objects]
|
||||
(js/console.log "whatever")
|
||||
(let [k @canvas-kit
|
||||
objects (get-objects-as-iterable objects)]
|
||||
(when (some? k)
|
||||
(.draw k objects))))
|
||||
|
||||
(mf/with-effect [canvas-ref vbox]
|
||||
(let [canvas (mf/ref-val canvas-ref)
|
||||
objects (get-objects-as-iterable objects)]
|
||||
(when (and (some? canvas) (some? vbox))
|
||||
(set! (.-width canvas) (.-clientWidth canvas))
|
||||
(set! (.-height canvas) (.-clientHeight canvas))
|
||||
(println "init vbox" vbox)
|
||||
(-> (.initialize impl/CanvasKit "skia-canvas" vbox)
|
||||
(.then (fn [k]
|
||||
(reset! canvas-kit k)
|
||||
(println "init complete")
|
||||
(.draw k objects)))))))
|
||||
|
||||
[:canvas {:id "skia-canvas"
|
||||
:class (stl/css :canvas)
|
||||
:ref canvas-ref}]))
|
||||
13
frontend/src/app/main/ui/workspace/viewport/sk.scss
Normal file
13
frontend/src/app/main/ui/workspace/viewport/sk.scss
Normal file
@@ -0,0 +1,13 @@
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
//
|
||||
// Copyright (c) KALEIDOS INC
|
||||
|
||||
@import "refactor/common-refactor.scss";
|
||||
|
||||
.canvas {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
621
frontend/src/app/main/ui/workspace/viewport/sk_impl.js
Normal file
621
frontend/src/app/main/ui/workspace/viewport/sk_impl.js
Normal file
@@ -0,0 +1,621 @@
|
||||
import CanvasKitInit from 'canvaskit-wasm/bin/canvaskit.js';
|
||||
|
||||
class CanvasKit {
|
||||
constructor(canvasId, CanvasKit, fontManager, vbox) {
|
||||
this.canvasId = canvasId;
|
||||
this.CanvasKit = CanvasKit;
|
||||
this.vbox = vbox;
|
||||
this.fontManager = fontManager;
|
||||
this.onDraw = this.onDraw.bind(this)
|
||||
}
|
||||
|
||||
static async loadFont(url) {
|
||||
const response = await fetch(url)
|
||||
return response.arrayBuffer()
|
||||
}
|
||||
|
||||
static async initialize(canvasId, vbox) {
|
||||
const kit = await CanvasKitInit();
|
||||
const fontData = await this.loadFont("/fonts/WorkSans-Regular.woff2");
|
||||
const fontManager = kit.FontMgr.FromData([fontData]);
|
||||
return new CanvasKit(canvasId, kit, fontManager, vbox);
|
||||
}
|
||||
|
||||
setVbox(vbox) {
|
||||
this.vbox = vbox;
|
||||
}
|
||||
|
||||
getTextDirectionFromString(textDirection) {
|
||||
switch (textDirection) {
|
||||
case 'ltr': return this.CanvasKit.TextDirection.LTR;
|
||||
case 'rtl': return this.CanvasKit.TextDirection.RTL;
|
||||
default: return this.CanvasKit.TextDirection.LTR;
|
||||
}
|
||||
}
|
||||
|
||||
getTextDecorationFromString(textDecoration) {
|
||||
switch(textDecoration) {
|
||||
case 'underline': return this.CanvasKit.UnderlineDecoration;
|
||||
case 'overline': return this.CanvasKit.OverlineDecoration;
|
||||
case 'line-through': return this.CanvasKit.LineThroughDecoration;
|
||||
case 'none': return this.CanvasKit.NoDecoration;
|
||||
default: return this.CanvasKit.NoDecoration;
|
||||
}
|
||||
}
|
||||
|
||||
getTextAlignFromString(textAlign) {
|
||||
console.log('text-align-from-string', textAlign)
|
||||
switch (textAlign) {
|
||||
case 'left': return this.CanvasKit.TextAlign.Left;
|
||||
case 'center': return this.CanvasKit.TextAlign.Center;
|
||||
case 'right': return this.CanvasKit.TextAlign.Right;
|
||||
case 'justify': return this.CanvasKit.TextAlign.Justify;
|
||||
case 'start': return this.CanvasKit.TextAlign.Start;
|
||||
case 'end': return this.CanvasKit.TextAlign.End;
|
||||
default: return this.CanvasKit.TextAlign.Left;
|
||||
}
|
||||
}
|
||||
|
||||
getBlendModeFromObject(object) {
|
||||
switch (object['blend-mode']) {
|
||||
case 'normal': return this.CanvasKit.BlendMode.SrcOver;
|
||||
case 'multiply': return this.CanvasKit.BlendMode.Multiply;
|
||||
case 'screen': return this.CanvasKit.BlendMode.Screen;
|
||||
case 'overlay': return this.CanvasKit.BlendMode.Overlay;
|
||||
case 'darken': return this.CanvasKit.BlendMode.Darken;
|
||||
case 'lighten': return this.CanvasKit.BlendMode.Lighten;
|
||||
case 'color-dodge': return this.CanvasKit.BlendMode.ColorDodge;
|
||||
case 'color-burn': return this.CanvasKit.BlendMode.ColorBurn;
|
||||
case 'hard-light': return this.CanvasKit.BlendMode.HardLight;
|
||||
case 'soft-light': return this.CanvasKit.BlendMode.SoftLight;
|
||||
case 'difference': return this.CanvasKit.BlendMode.Difference;
|
||||
case 'exclusion': return this.CanvasKit.BlendMode.Exclusion;
|
||||
case 'hue': return this.CanvasKit.BlendMode.Hue;
|
||||
case 'saturation': return this.CanvasKit.BlendMode.Saturation;
|
||||
case 'color': return this.CanvasKit.BlendMode.Color;
|
||||
case 'luminosity': return this.CanvasKit.BlendMode.Luminosity;
|
||||
default: return this.CanvasKit.BlendMode.SrcOver;
|
||||
}
|
||||
}
|
||||
|
||||
drawFrame(canvas, object) {
|
||||
this.drawRect(canvas, object)
|
||||
}
|
||||
|
||||
drawRect(canvas, shape) {
|
||||
let blur = null
|
||||
const paint = new this.CanvasKit.Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setBlendMode(this.getBlendModeFromObject(shape));
|
||||
const rx = shape['rx'] || shape['r1'] || 0;
|
||||
const ry = shape['ry'] || shape['r1'] || 0;
|
||||
if (shape.blur) {
|
||||
blur = this.CanvasKit.ImageFilter.MakeBlur(shape.blur.value, shape.blur.value, this.CanvasKit.TileMode.Decal, null);
|
||||
}
|
||||
if (shape.shadow) {
|
||||
for (const shadow of shape.shadow.reverse()) {
|
||||
const paintShadow = new this.CanvasKit.Paint();
|
||||
const color = this.CanvasKit.parseColorString(shadow.color.color)
|
||||
color[3] = shadow.color.opacity
|
||||
const shadowFilter = this.CanvasKit.ImageFilter.MakeDropShadowOnly(shadow['offset-x'], shadow['offset-y'], shadow.blur, shadow.blur, color, blur);
|
||||
const shadowRect = this.CanvasKit.RRectXY(
|
||||
this.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height),
|
||||
rx,
|
||||
ry)
|
||||
paintShadow.setImageFilter(shadowFilter)
|
||||
canvas.drawRRect(shadowRect, paintShadow)
|
||||
paintShadow.delete()
|
||||
}
|
||||
}
|
||||
// Drawing fills
|
||||
if (shape.fills) {
|
||||
for (const fill of shape.fills.reverse()) {
|
||||
if (fill["fill-color"]) {
|
||||
paint.setStyle(this.CanvasKit.PaintStyle.Fill);
|
||||
const color = this.CanvasKit.parseColorString(fill["fill-color"]);
|
||||
const opacity = fill["fill-opacity"];
|
||||
color[3] = opacity;
|
||||
paint.setColor(color);
|
||||
const rr = this.CanvasKit.RRectXY(
|
||||
this.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height),
|
||||
rx,
|
||||
ry,
|
||||
);
|
||||
canvas.drawRRect(rr, paint);
|
||||
}
|
||||
else if (fill["fill-image"]) {
|
||||
let realPromise = fetch("/assets/by-file-media-id/" + fill["fill-image"].id)
|
||||
.then((response) => response.blob())
|
||||
.then((blob) => createImageBitmap(blob))
|
||||
.then((bitmap) => this.CanvasKit.MakeImageFromCanvasImageSource(bitmap))
|
||||
.then((img) => {
|
||||
const self = this;
|
||||
const s = this.CanvasKit.MakeCanvasSurface(self.canvasId);
|
||||
s.drawOnce((c) => {
|
||||
c.drawImage(img, shape.x, shape.y, null)
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Drawing strokes
|
||||
if (shape.strokes) {
|
||||
for (const stroke of shape.strokes.reverse()) {
|
||||
paint.setStyle(this.CanvasKit.PaintStyle.Stroke);
|
||||
const color = this.CanvasKit.parseColorString(stroke["stroke-color"]);
|
||||
const opacity = stroke["stroke-opacity"];
|
||||
const strokeWidth = stroke["stroke-width"];
|
||||
paint.setStrokeWidth(strokeWidth);
|
||||
console.log("stroke", stroke, stroke["stroke-color"], stroke["stroke-opacity"], strokeWidth);
|
||||
color[3] = opacity;
|
||||
paint.setColor(color);
|
||||
const rr = this.CanvasKit.RRectXY(
|
||||
this.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height),
|
||||
rx,
|
||||
ry,
|
||||
);
|
||||
canvas.drawRRect(rr, paint);
|
||||
}
|
||||
}
|
||||
if (shape.blur) {
|
||||
const paintBlur = new this.CanvasKit.Paint();
|
||||
if (!shape.shadow) {
|
||||
const blurRect = this.CanvasKit.RRectXY(
|
||||
this.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height),
|
||||
rx,
|
||||
ry)
|
||||
paintBlur.setImageFilter(blur)
|
||||
canvas.drawRRect(blurRect, paintBlur)
|
||||
paintBlur.delete()
|
||||
}
|
||||
}
|
||||
paint.delete();
|
||||
}
|
||||
|
||||
drawCircle(canvas, shape) {
|
||||
let blur = null
|
||||
const paint = new this.CanvasKit.Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setBlendMode(this.getBlendModeFromObject(shape));
|
||||
if (shape.blur) {
|
||||
blur = this.CanvasKit.ImageFilter.MakeBlur(shape.blur.value, shape.blur.value, this.CanvasKit.TileMode.Decal, null);
|
||||
}
|
||||
if (shape.shadow) {
|
||||
for (const shadow of shape.shadow.reverse()) {
|
||||
const paintShadow = new this.CanvasKit.Paint();
|
||||
const color = this.CanvasKit.parseColorString(shadow.color.color)
|
||||
color[3] = shadow.color.opacity
|
||||
const shadowFilter = this.CanvasKit.ImageFilter.MakeDropShadowOnly(shadow['offset-x'], shadow['offset-y'], shadow.blur, shadow.blur, color, blur);
|
||||
const shadowRect = this.CanvasKit.RRectXY(
|
||||
this.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height),
|
||||
0,
|
||||
0)
|
||||
paintShadow.setImageFilter(shadowFilter)
|
||||
canvas.drawOval(shadowRect, paintShadow)
|
||||
paintShadow.delete()
|
||||
}
|
||||
}
|
||||
// Drawing fills
|
||||
if (shape.fills) {
|
||||
for (const fill of shape.fills.reverse()) {
|
||||
paint.setStyle(this.CanvasKit.PaintStyle.Fill);
|
||||
const color = this.CanvasKit.parseColorString(fill["fill-color"]);
|
||||
const opacity = fill["fill-opacity"];
|
||||
color[3] = opacity;
|
||||
paint.setColor(color);
|
||||
const rr = this.CanvasKit.RRectXY(
|
||||
this.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height),
|
||||
0,
|
||||
0,
|
||||
);
|
||||
canvas.drawOval(rr, paint);
|
||||
}
|
||||
}
|
||||
// Drawing strokes
|
||||
if (shape.strokes) {
|
||||
for (const stroke of shape.strokes.reverse()) {
|
||||
paint.setStyle(this.CanvasKit.PaintStyle.Stroke);
|
||||
const color = this.CanvasKit.parseColorString(stroke["stroke-color"]);
|
||||
const opacity = stroke["stroke-opacity"];
|
||||
const strokeWidth = stroke["stroke-width"];
|
||||
paint.setStrokeWidth(strokeWidth);
|
||||
color[3] = opacity;
|
||||
paint.setColor(color);
|
||||
const rr = this.CanvasKit.RRectXY(
|
||||
this.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height),
|
||||
0,
|
||||
0,
|
||||
);
|
||||
canvas.drawOval(rr, paint);
|
||||
}
|
||||
}
|
||||
if (shape.blur) {
|
||||
const paintBlur = new this.CanvasKit.Paint();
|
||||
if (!shape.shadow) {
|
||||
const blurRect = this.CanvasKit.RRectXY(
|
||||
this.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height),
|
||||
0,
|
||||
0)
|
||||
paintBlur.setImageFilter(blur)
|
||||
canvas.drawOval(blurRect, paintBlur)
|
||||
paintBlur.delete()
|
||||
}
|
||||
}
|
||||
paint.delete();
|
||||
}
|
||||
|
||||
drawPath(canvas, shape) {
|
||||
const path = new this.CanvasKit.Path();
|
||||
for (const { command, params } of shape.content) {
|
||||
switch (command) {
|
||||
// :move-to "M"
|
||||
// :close-path "Z"
|
||||
// :line-to "L"
|
||||
// :line-to-horizontal "H"
|
||||
// :line-to-vertical "V"
|
||||
// :curve-to "C"
|
||||
// :smooth-curve-to "S"
|
||||
// :quadratic-bezier-curve-to "Q"
|
||||
// :smooth-quadratic-bezier-curve-to "T"
|
||||
// :elliptical-arc "A"
|
||||
case 'move-to': path.moveTo(params.x, params.y); break;
|
||||
case 'line-to': path.lineTo(params.x, params.y); break;
|
||||
case 'line-to-horizontal': /* path.lineTo(...params); */ break;
|
||||
case 'line-to-vertical': /* path.lineTo(...params); */ break;
|
||||
case 'curve-to': path.cubicTo(params.c1x, params.c1y, params.c2x, params.c2y, params.x, params.y); break;
|
||||
case 'smooth-curve-to': path.cubicTo(...params); break;
|
||||
case 'quadratic-bezier-to': path.quadTo(...params); break;
|
||||
case 'smooth-quadratic-bezier-curve-to': path.quadTo(...params); break;
|
||||
case 'elliptical-arc': path.arcTo(...params); break;
|
||||
case 'close-path': path.close(); break;
|
||||
}
|
||||
}
|
||||
|
||||
const paint = new this.CanvasKit.Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setBlendMode(this.getBlendModeFromObject(shape));
|
||||
// Drawing fills
|
||||
if (shape.fills) {
|
||||
for (const fill of shape.fills.reverse()) {
|
||||
paint.setStyle(this.CanvasKit.PaintStyle.Fill);
|
||||
const color = this.CanvasKit.parseColorString(fill["fill-color"]);
|
||||
const opacity = fill["fill-opacity"];
|
||||
color[3] = opacity;
|
||||
paint.setColor(color);
|
||||
const rr = this.CanvasKit.RRectXY(
|
||||
this.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height),
|
||||
0,
|
||||
0,
|
||||
);
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
}
|
||||
// Drawing strokes
|
||||
if (shape.strokes) {
|
||||
for (const stroke of shape.strokes.reverse()) {
|
||||
paint.setStyle(this.CanvasKit.PaintStyle.Stroke);
|
||||
const color = this.CanvasKit.parseColorString(stroke["stroke-color"]);
|
||||
const opacity = stroke["stroke-opacity"];
|
||||
const strokeWidth = stroke["stroke-width"];
|
||||
paint.setStrokeWidth(strokeWidth);
|
||||
color[3] = opacity;
|
||||
paint.setColor(color);
|
||||
const rr = this.CanvasKit.RRectXY(
|
||||
this.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height),
|
||||
0,
|
||||
0,
|
||||
);
|
||||
canvas.drawPath(path, paint);
|
||||
}
|
||||
}
|
||||
paint.delete();
|
||||
}
|
||||
|
||||
drawTextRun(canvas, shape, textRun) {
|
||||
if (!textRun.children) {
|
||||
console.warn('textRun.children is undefined', textRun)
|
||||
return;
|
||||
}
|
||||
for (const child of textRun.children) {
|
||||
if (child.type === 'paragraph') {
|
||||
const textDirection = this.getTextDirectionFromString(child["text-direction"]);
|
||||
const textAlign = this.getTextAlignFromString(child["text-align"]);
|
||||
console.log("text-align", textAlign);
|
||||
if (!child.children) {
|
||||
console.warn('child.children is undefined', child)
|
||||
continue
|
||||
}
|
||||
for (const paragraphText of child.children) {
|
||||
if (paragraphText.text === '') continue;
|
||||
for (const fill of paragraphText.fills) {
|
||||
const color = this.CanvasKit.parseColorString(fill["fill-color"]);
|
||||
color[3] = fill["fill-opacity"];
|
||||
const decoration = this.getTextDecorationFromString(paragraphText["text-decoration"]);
|
||||
const paragraphStyle = new this.CanvasKit.ParagraphStyle({
|
||||
textDirection,
|
||||
textStyle: {
|
||||
color,
|
||||
decoration,
|
||||
fontFamilies: [paragraphText["font-family"]],
|
||||
fontSize: parseInt(paragraphText["font-size"], 10),
|
||||
/*
|
||||
// TODO: Hacer una función que devuelva el weight o un valor de los del enum
|
||||
fontStyle: {
|
||||
weight: parseInt(textRun['font-weight'], 10),
|
||||
},
|
||||
*/
|
||||
letterSpacing: parseFloat(paragraphText["letter-spacing"]) || -1,
|
||||
},
|
||||
textAlign,
|
||||
});
|
||||
const text = paragraphText.text;
|
||||
const builder = this.CanvasKit.ParagraphBuilder.Make(paragraphStyle, this.fontManager);
|
||||
builder.addText(text);
|
||||
const paragraph = builder.build();
|
||||
const layoutWidth = shape["grow-type"] === "fixed" ? shape.width : Infinity;
|
||||
console.log(layoutWidth)
|
||||
paragraph.layout(layoutWidth); // width in pixels to use when wrapping text
|
||||
canvas.drawParagraph(paragraph, shape.x, shape.y);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.drawTextRun(canvas, shape, child)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
drawText(canvas, shape) {
|
||||
console.log('drawText', shape)
|
||||
if (!shape.content) {
|
||||
console.warn('drawText: shape.content is undefined', shape);
|
||||
return;
|
||||
}
|
||||
this.drawTextRun(canvas, shape, shape.content);
|
||||
}
|
||||
|
||||
drawGroup(canvas, object) {
|
||||
console.warn("To be implemented");
|
||||
}
|
||||
|
||||
drawObject(canvas, object) {
|
||||
canvas.save();
|
||||
canvas.rotate(object.rotation, object.x + object.width / 2, object.y + object.height / 2);
|
||||
switch (object.type) {
|
||||
case "frame":
|
||||
this.drawFrame(canvas, object);
|
||||
break;
|
||||
case "rect":
|
||||
this.drawRect(canvas, object);
|
||||
break;
|
||||
case "circle":
|
||||
this.drawCircle(canvas, object);
|
||||
break;
|
||||
case "path":
|
||||
this.drawPath(canvas, object);
|
||||
break;
|
||||
case "text":
|
||||
this.drawText(canvas, object);
|
||||
break;
|
||||
case "group":
|
||||
this.drawGroup(canvas, object);
|
||||
break;
|
||||
default:
|
||||
console.warn("Unknown object type", object.type);
|
||||
break;
|
||||
}
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
onDraw(canvas) {
|
||||
// Es posible que no haga falta.
|
||||
// canvas.clear(CanvasKit.TRANSPARENT);
|
||||
console.log(this.vbox);
|
||||
canvas.save()
|
||||
canvas.scale(this.surface.width() / this.vbox.width, this.surface.height() / this.vbox.height);
|
||||
canvas.translate(-this.vbox.x, -this.vbox.y);
|
||||
for (const object of this.objects) {
|
||||
this.drawObject(canvas, object);
|
||||
}
|
||||
canvas.restore()
|
||||
}
|
||||
|
||||
draw(objects) {
|
||||
this.objects = objects;
|
||||
this.surface = this.CanvasKit.MakeCanvasSurface(this.canvasId);
|
||||
this.surface.drawOnce(this.onDraw);
|
||||
}
|
||||
|
||||
paintRect(shape) {
|
||||
const surface = this.CanvasKit.MakeCanvasSurface(this.canvasId);
|
||||
|
||||
const self = this;
|
||||
function draw(canvas) {
|
||||
if (self.vbox) {
|
||||
canvas.translate(-self.vbox.x, -self.vbox.y);
|
||||
}
|
||||
|
||||
const paint = new self.CanvasKit.Paint();
|
||||
// Drawing fills
|
||||
if (shape.fills) {
|
||||
for (const fill of shape.fills.reverse()) {
|
||||
paint.setStyle(self.CanvasKit.PaintStyle.Fill);
|
||||
const color = self.CanvasKit.parseColorString(fill["fill-color"]);
|
||||
const opacity = fill["fill-opacity"];
|
||||
color[3] = opacity;
|
||||
paint.setColor(color);
|
||||
const rr = self.CanvasKit.RRectXY(
|
||||
self.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height),
|
||||
rx,
|
||||
ry,
|
||||
);
|
||||
canvas.drawRRect(rr, paint);
|
||||
}
|
||||
}
|
||||
// Drawing strokes
|
||||
if (shape.strokes) {
|
||||
for (const stroke of shape.strokes.reverse()) {
|
||||
paint.setStyle(self.CanvasKit.PaintStyle.Stroke);
|
||||
const color = self.CanvasKit.parseColorString(stroke["stroke-color"]);
|
||||
const opacity = stroke["stroke-opacity"];
|
||||
const strokeWidth = stroke["stroke-width"];
|
||||
paint.setStrokeWidth(strokeWidth);
|
||||
color[3] = opacity;
|
||||
paint.setColor(color);
|
||||
|
||||
const rr = self.CanvasKit.RRectXY(
|
||||
self.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height),
|
||||
rx,
|
||||
ry,
|
||||
);
|
||||
canvas.drawRRect(rr, paint);
|
||||
|
||||
// Inner stroke?
|
||||
// const rr2 = self.CanvasKit.RRectXY(self.CanvasKit.LTRBRect(shape.x, shape.y, shape.x + shape.width, shape.y + shape.height), 0, 0);
|
||||
// canvas.clipRRect(rr2, self.CanvasKit.ClipOp.Intersect, true);
|
||||
}
|
||||
}
|
||||
paint.delete();
|
||||
}
|
||||
|
||||
surface.drawOnce(draw);
|
||||
|
||||
// // Drawing another border
|
||||
// const paint2 = new this.CanvasKit.Paint();
|
||||
// paint2.setColor(this.CanvasKit.Color4f(0.9, 0, 1.0, 1.0));
|
||||
// paint2.setStyle(this.CanvasKit.PaintStyle.Stroke);
|
||||
// paint2.setStrokeWidth(25.0);
|
||||
// paint2.setAntiAlias(true);
|
||||
// const rr2 = this.CanvasKit.RRectXY(this.CanvasKit.LTRBRect(x, y, width, height), 0, 0);
|
||||
|
||||
// // Drawing a shadow
|
||||
// const paint3 = new this.CanvasKit.Paint();
|
||||
// paint3.setColor(this.CanvasKit.Color4f(0.9, 0, 1.0, 1.0));
|
||||
// paint3.setStyle(this.CanvasKit.PaintStyle.Fill);
|
||||
// const rr3 = this.CanvasKit.RRectXY(this.CanvasKit.LTRBRect(x, y, width, height), 0, 0);
|
||||
// const drop = this.CanvasKit.ImageFilter.MakeDropShadow(4, 4, 4, 4,this.CanvasKit.MAGENTA, null);
|
||||
// paint3.setImageFilter(drop)
|
||||
|
||||
// // Drawing a blur
|
||||
// const paint4 = new this.CanvasKit.Paint();
|
||||
// paint4.setColor(this.CanvasKit.Color4f(0.9, 0, 1.0, 1.0));
|
||||
// paint4.setStyle(this.CanvasKit.PaintStyle.Fill);
|
||||
// const rr4 = this.CanvasKit.RRectXY(this.CanvasKit.LTRBRect(x, y, width, height), 0, 0);
|
||||
// const blur = this.CanvasKit.ImageFilter.MakeBlur(4, 4, this.CanvasKit.TileMode.Decal, null);
|
||||
// paint4.setImageFilter(blur)
|
||||
// const self = this;
|
||||
// function draw(canvas) {
|
||||
// canvas.translate(- self.vbox.x, - self.vbox.y);
|
||||
// // canvas.scale(kk3, kk3);
|
||||
// for (const d of toDraw) {
|
||||
// canvas.drawRRect(d, paint);
|
||||
// }
|
||||
|
||||
// // canvas.drawRRect(rr2, paint2);
|
||||
// // canvas.drawRRect(rr3, paint3);
|
||||
// // canvas.drawRRect(rr4, paint4);
|
||||
// paint.delete();
|
||||
// // paint2.delete();
|
||||
// // paint3.delete();
|
||||
// // paint4.delete();
|
||||
// }
|
||||
// surface.drawOnce(draw);
|
||||
}
|
||||
}
|
||||
|
||||
export { CanvasKit };
|
||||
|
||||
export function init() {
|
||||
return CanvasKitInit();
|
||||
}
|
||||
|
||||
export function rect(CanvasKit, canvasId, x, y, width, height, kk1, kk2, kk3) {
|
||||
surface = CanvasKit.MakeCanvasSurface(canvasId)
|
||||
|
||||
// Drawing a border
|
||||
console.log("rect:", x, y, width, height)
|
||||
const paint = new CanvasKit.Paint();
|
||||
paint.setColor(CanvasKit.Color4f(0.9, 0, 0, 1.0));
|
||||
paint.setStyle(CanvasKit.PaintStyle.Stroke);
|
||||
paint.setStrokeWidth(50.0);
|
||||
// paint.setStrokeCap(CanvasKit.StrokeCap.Round);
|
||||
paint.setAntiAlias(true);
|
||||
const rr = CanvasKit.RRectXY(CanvasKit.LTRBRect(x, y, width, height), 0, 0);
|
||||
|
||||
// Drawing another border
|
||||
const paint2 = new CanvasKit.Paint();
|
||||
paint2.setColor(CanvasKit.Color4f(0.9, 0, 1.0, 1.0));
|
||||
paint2.setStyle(CanvasKit.PaintStyle.Stroke);
|
||||
paint2.setStrokeWidth(25.0);
|
||||
paint2.setAntiAlias(true);
|
||||
const rr2 = CanvasKit.RRectXY(CanvasKit.LTRBRect(x, y, width, height), 0, 0);
|
||||
|
||||
// Drawing a shadow
|
||||
const paint3 = new CanvasKit.Paint();
|
||||
paint3.setColor(CanvasKit.Color4f(0.9, 0, 1.0, 1.0));
|
||||
paint3.setStyle(CanvasKit.PaintStyle.Fill);
|
||||
const rr3 = CanvasKit.RRectXY(CanvasKit.LTRBRect(x, y, width, height), 0, 0);
|
||||
const drop = CanvasKit.ImageFilter.MakeDropShadow(4, 4, 4, 4, CanvasKit.MAGENTA, null);
|
||||
paint3.setImageFilter(drop)
|
||||
|
||||
|
||||
// Drawing a blur
|
||||
const paint4 = new CanvasKit.Paint();
|
||||
paint4.setColor(CanvasKit.Color4f(0.9, 0, 1.0, 1.0));
|
||||
paint4.setStyle(CanvasKit.PaintStyle.Fill);
|
||||
const rr4 = CanvasKit.RRectXY(CanvasKit.LTRBRect(x, y, width, height), 0, 0);
|
||||
const blur = CanvasKit.ImageFilter.MakeBlur(4, 4, CanvasKit.TileMode.Decal, null);
|
||||
paint4.setImageFilter(blur)
|
||||
|
||||
function draw(canvas) {
|
||||
canvas.translate(- kk1, - kk2);
|
||||
// canvas.scale(kk3, kk3);
|
||||
// canvas.drawRRect(rr, paint);
|
||||
// canvas.drawRRect(rr2, paint2);
|
||||
// canvas.drawRRect(rr3, paint3);
|
||||
canvas.drawRRect(rr4, paint4);
|
||||
paint.delete();
|
||||
paint2.delete();
|
||||
paint3.delete();
|
||||
}
|
||||
surface.drawOnce(draw);
|
||||
}
|
||||
|
||||
export function path(CanvasKit, canvasId, x, y, content, kk1, kk2, kk3) {
|
||||
// surface = CanvasKit.MakeCanvasSurface(canvasId)
|
||||
console.log("path:", x, y, content)
|
||||
|
||||
surface = CanvasKit.MakeCanvasSurface(canvasId)
|
||||
const paint = new CanvasKit.Paint();
|
||||
paint.setStrokeWidth(1.0);
|
||||
paint.setAntiAlias(true);
|
||||
paint.setColor(CanvasKit.Color4f(0.9, 0, 1.0, 1.0));
|
||||
paint.setStyle(CanvasKit.PaintStyle.Stroke);
|
||||
const path = CanvasKit.Path.MakeFromSVGString(content);
|
||||
|
||||
function draw(canvas) {
|
||||
canvas.translate(- kk1, - kk2);
|
||||
// canvas.scale(kk3, kk3);
|
||||
canvas.drawPath(path, paint);
|
||||
paint.delete();
|
||||
}
|
||||
surface.drawOnce(draw);
|
||||
}
|
||||
|
||||
// export function shadow(CanvasKit, canvasId, kk1, kk2, kk3) {
|
||||
// console.log("CanvasKit", CanvasKit)
|
||||
// console.log("CanvasKit.ImageFilter", CanvasKit.ImageFilter.MakeDropShadow())
|
||||
// const paint = new CanvasKit.Paint();
|
||||
// paint.setColor(CanvasKit.Color4f(0.9, 0, 1.0, 1.0));
|
||||
// paint.setStyle(CanvasKit.PaintStyle.Fill);
|
||||
// // var paint = SKPaint
|
||||
// // {
|
||||
// // Color = SKColors.Red,
|
||||
// // Style = SKPaintStyle.Fill
|
||||
// // };
|
||||
// const drop = CanvasKit.ImageFilter.MakeDropShadow(0, 0, 4.0, 2.0, CanvasKit.MAGENTA, null);
|
||||
// const paint = new CanvasKit.Paint();
|
||||
// paint.setImageFilter(drop)
|
||||
|
||||
// }
|
||||
|
||||
@@ -4167,6 +4167,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@webgpu/types@npm:0.1.21":
|
||||
version: 0.1.21
|
||||
resolution: "@webgpu/types@npm:0.1.21"
|
||||
checksum: 74de9683b70064aeadcdd31381747650b323e7e2183fb38f90a35f1a79f80ad267c0a2ee5010c264befb3d31ad213dbdffa04897e2808f6b04feff8d66bc53e0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@xmldom/xmldom@npm:^0.8.3":
|
||||
version: 0.8.10
|
||||
resolution: "@xmldom/xmldom@npm:0.8.10"
|
||||
@@ -5278,6 +5285,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"canvaskit-wasm@npm:^0.39.1":
|
||||
version: 0.39.1
|
||||
resolution: "canvaskit-wasm@npm:0.39.1"
|
||||
dependencies:
|
||||
"@webgpu/types": "npm:0.1.21"
|
||||
checksum: 0ae60ae5c430aaa88152f3a20f40fc9a6debb15714a2ce1bdebef93005ec6d5e72e0316b91ab637f50aab220dd8694101abac497209bcf16788d00db78f5a898
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chalk@npm:^2.4.1, chalk@npm:^2.4.2":
|
||||
version: 2.4.2
|
||||
resolution: "chalk@npm:2.4.2"
|
||||
@@ -7582,6 +7598,7 @@ __metadata:
|
||||
"@storybook/testing-library": "npm:^0.2.2"
|
||||
animate.css: "npm:^4.1.1"
|
||||
autoprefixer: "npm:^10.4.15"
|
||||
canvaskit-wasm: "npm:^0.39.1"
|
||||
concurrently: "npm:^8.2.2"
|
||||
date-fns: "npm:^2.30.0"
|
||||
draft-js: "npm:^0.11.7"
|
||||
|
||||
Reference in New Issue
Block a user