도형 채우기

SpreadJS를 사용하면 단색 채우기, 그라데이션 채우기, 그림 채우기 및 질감 채우기 등 도형에 특별한 채우기 효과를 추가할 수 있습니다.

도형을 선택한 다음 오른쪽 패널에서 채우기 설정을 변경하면 됩니다.

다음 샘플은 채우기 없음 설정을 보여줍니다. 다음 샘플은 단색 채우기 설정을 보여줍니다. 선형 그라데이션과 방사형 그라데이션을 지원합니다. 선형 그라데이션을 사용하면 각도 또는 방향 필드를 사용하여 그라데이션을 지정할 수 있습니다. 하지만 방향과 각도를 동시에 설정하면 방향이 적용됩니다. 다음 샘플은 그라데이션 채우기 설정을 보여줍니다. 다음 샘플은 그림 채우기 설정을 보여줍니다. 현재 base64 형식 그림만 지원합니다. 다음 샘플은 질감 채우기 설정을 보여줍니다.
import * as React from 'react'; import * as ReactDOM from 'react-dom'; import './styles.css'; import { AppFunc } from './app-func'; // import { App } from './app-class'; // 1. Functional Component sample ReactDOM.render(<AppFunc />, document.getElementById('app')); // 2. Class Component sample // ReactDOM.render(<App />, document.getElementById('app'));
import * as React from 'react'; import GC from '@mescius/spread-sheets'; import "@mescius/spread-sheets-shapes"; import { SpreadSheets } from "@mescius/spread-sheets-react"; import '@mescius/spread-sheets-resources-ko'; GC.Spread.Common.CultureManager.culture("ko-kr"); const defaultSrc = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAMAAABrrFhUAAAC5VBMVEUAAACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvABHaHJoAAAA93RSTlMAAhZNh7re8/3/3QEIS6Lh/qFgz/xGyPvJKKipEYTxBV/cPMDBIZ75DXnsVNU0txqU9glu5krNLK4UifIGZN9BxSWj+g9+7wNa2Vk4vB6Z9wtz6U/RMLIXjvRp4ynwg5+t4MSkJO7Y+B10UD8+B4W2IM4f09IcwppdXBuPjSeIEJjbr5t2aFVMUmNwgpWqvuirOxhtue1RLle750QEauKXR5wKE0mW5Qx/OVMretaxMb9DtEBOZ+SGw3uRsz3KfIvG1BUqpmEmb8uMvUiAp6AynbUO60JxL5KKzIH1NlbqrHIz1zV1uHiQZlhlfcciNxJbRdotOtCTPYHQWQAAEOJJREFUeAHklQWiGzEMBcOxgwoztmFmZob7n6fyllt9RjsK467kmWfdR5QebwajyWyxMs6sNrPJaNDevZHS23UOp8vNAPj3AmBuj9Ohs+tvon29zuH1cQDw+xmA6N7vx1fc53WIDxUvsciBIAcWYvAHAdprHg4IPFSnPxL1c7Hk/M8SIPjx/VhEaQ8Q8HgiKdrHjv8t4GIEyUQcv6Ys/al0hjOy/Z8jYDyTTiEoasqf/aK1CMDpAtDG8zUrXFFP/ly+QNBPeVDI53BgislfLJVJ+mkPyqUi/kgh+vWVKtH+fSOoVvSIjSry1+qk/PdHQb0mzFFB/kazRcn/YBS0mg0cn/Tytztdgv7HedDttPEv5Ka/18dWgKD/YQ/E7/o9AZG89A+GjBPyPz4KOBsOJPUA2x+NJ0+Un4qCyXgk4QjQ3Ols/nT5ySiYz6b4h7LJv1g+fut7cEtcLgRSMtG/Wm+eLT8VBZv1ShoPENbtbv8i+ako2O+2+NdS0H84nl4sPxUFp/MB4fr88l+uryE/GQXXyzfm7BorogCKwTC0uFuJbmZ85inutv+ek0MbnB+SBTy9uSOf+pVd/m6v/yvT73vQ73X1kHPLPxiOfnP6TQ9Gw4FOlDn9s+OJbl8DS2Tp9RFMxrOBPdAlFeWSK/+vr4KlskjrgW6/qhug/H4VNHWlRxCFPe0xVH6/Co5bMVIQ9myZjz6yBzmMpIs4EfaAt++/Ha/tiJGisYdeBadnYqQw7AGSwkgee/Y/Lj+6Cvb+j5GEPedH9PQDjIRhDxCAkTDsAQIwEoc9QABGwrAHCM1IPPYACWAkPeR5jz18AhhJ2HNhsOfv4xnpQoyUiz1APCOB2HNJl59kJB57Mj4SrwhGEvZcbwaW3zPSjekBgz2hq+DWMBKBPcGr4M4zEo89bHhG8thzz08/wkgPP14Fwp7HET39sYwk7HkCsAcJwEjTUwT28DGMlIs9sYw0S2IPH8NIs1+9/+eX8q46QI7bV2vu0pzVCeg1/mXCzMx4DecmzMzMzMzMzFwIc1JmZmZmZvr3waqs7t7e7rjn3ee/2rA+6ZO/sWRLFnsSlgeYf0LWEHBg4qTymLjmS3VcvuhEcLJgf0q1YMlvQSqYnAJO1PZPyYdeQpsvIfBw6jRworR/zPQksF8iMGNmVAi4UGEWekSEybSIyMMyFcCNBoDZ0v4kQWB2FAA4MAd10tnPCGicC06m/p/XBBUSJt8iVNhkXmYx4MB89IgwGReRhwvAySQACmZgctrPmihjYeQQcGDRvxQA9Pf1L4XAInAiBsDikqjItOFKac/ztFZK8f+F/lcp4ziQwpKLI4WAD+NQEZlMxJ6nIt0e97QyiAKRwnHgR2LAEvTI1N+tPYWEhGrg0mHLludYsXLOqu6rU1PXtFu7bv2GjZumb24Zig9UnjblBfJwSUQOpE9FbUKHkvIUEmFajy3r22ydUsEFuXJt67l6e40dJUcjEZIhEDTWqxVxD0hDosDjXnmEhDs35djVfCLwch3/L8v5HZIKu/c02ruPI0ERIQW8D4zc70ZIAamoKGDr+VRl6exVY9yQ5WysXAzKr+GZsr/1NTuRkLyA44DQW5AO4dYBOIgeBd23QHjo8JEKoRTjuyCXhIFRGLPnaE7kOEAK8J/U7FgEACpiSwrWfGy5d84NmRsvUQAAaHXjTU2QSAf3cUKENx+PAMAJbBnseWTf/zrpQmzFCTcE2eJTW4ohqcAgICxW4d8AgBC1xppHT7MhMS43hNyIM2dDECAlDgBM/nPnId7iHMPXZc8FjQyBtQDIg9i2uzj2A6lP+xcveQyB/QCw+3WNxdL8eGrU7uVqsj3NRgD4APLmK3EHv4Sgbn4OApsBYP/jhSlG2pQmXr0Fld0AsP3ljoFv6HLeRlQ2A8D232qsV9GHXLehJmsBYPtvN9iwWxzaoLIWALb/hEH7wYH2hBYDQBrvMPo67AE4ZXEEEGpcdgBco+3ad9qaA9j+Kr3BMXlZYeJ8i3cBIqx5F/gm3b/1blTWKkEijfeAb9D9re7tjLYqQSbAfblMuv/I/bJtxSYAiFRTcIy5/4FOHtr8NUjk4WBT9jsAlXNK91sGAGY8CK6huzpjHkJi8+0EgAOgDzhm3O88vE+eBNgGgMKRj4BrxP0L75THAPYB4GEncEwkv/RHR0r3WwcAEeqT4BjY+85fkO63EQCNm0y4/1jrNOl+SwE4CH7g7i/1mHS/lQAQYbHm4AatfB8fLdxvawRofCJw9z9ZRUgfeyPAw6fAD1b5ztZS+dpMgRvBCVL5rmoi3W8xAAoHlgU3OOnT8WmpfC0HYMbEAJXvWql8LQdAY7Xg3F/wktz7LAeAPHwGnICU7zqpfO0HIKAvQceFZ0sL9ycGADnAt1L52gyAdP9dQvkmDgCPgxO38l0glG8CAfAcOHG6/8azQvokDADo4Z1xuj9l+T8qXyJS3FSPZLcOyFc8cOVLSMQ/SEieJiKyWAnu7AhuzNJnWiFWvihv/yNlDC3Zvy+S3afCRHgEnJiV72aZ/NjgtOfXTZhS5IWGC+sOekyj0kiUVJ/DrHyfRyXdj1rji4sW/qk15KVlNleGNJaJUfm+nBHG/eqZjgDgO+7/rVAD+ZP3MwJ2UqDzK+DEoHzLsPvlbfe2qaH4+EuwLH6aEbDzULQ1+Fl1f5cTfaX7+b2DV4vITiMH3NdsLY+TwirHs+r+Ca//s/sV5mvKjXYSszcYAfsAIIUlwM+K+xf3kcqXu6zfLHocHDfMb2uEmogsLI1pfCxXVtxfVypfdj8Oeyt8n6XrQjnUVgJAGq+CH637ex+VypfdP3DFxEh9hi4cu4AaycL+AIU554EbnfJ9eyhqjf/k/h2nM2myd2DEIVRI9gFAOor6MCvfwmGUL75z1c/0j/BDrZLWAcB58BT4mSvf67uFU77vlgUnCgihE2oi+wBAhYdGgJOJ+wdMDqd8D7WBKF95mZcTlX0AIKHGC8fAjah83wurfAdvi7bJ2oerHAL2dYpqLAeuG37ve39WROUL0a5cj6G2EgDS2Ci8hunyVFjle4dQvpFDoAQqItsAYGfiG9KUX5VvvcyUb/TreBVUZOuFiddccEAq3/lhle8goXwzD4HWqMnaKzMPtRIfslD3g7DK98Os3zByYXdnJLL20lSPi3xd/H8XXwPv+FxY5fuRUL7RrTKoLb4213LjXQf+cFf9e18Mp3w/lso3Sg48hR7ZenEStUIv/xs3Fnxg8QPN93/SoWbMyjeCGjxiGwWEriV8s06Tm9PY1TEq3whJoONOVBbfHifS3h8lDZH8Qsq3HcRTTis+FbXdDyhwVYvY9VL5lmPlG/u6Ez17ARBLKN/VEGc1FY6iR4kHALHy/ZSVb1wAPJ6IAHBCnHo5/svVPhRNFACE8l3PyjdeACYlHADs/tuE8o2RAn0SAgChfMey8g0AgMH2AyDdX+3B4B5WmWyzDuAllO9nrHwDWRNn2KkEI2jjjVOCc78LUzLsBkAo37yfQ6AN9U8ikcUACOX7XO9AH9bw4QR69gIglO+o3IG/K9PB2IGIAeU7f3HA76q4MGKgrRSQe1+98YG734eVlh6KSvf3faOLiWd1OtgPALt/VlVwHQOPCXlIdgPA7s/oGoDyjfz+s3kALFC+IgU2H4mKrH9RstsXvqkXFRagR+YBsEf5ivevR1rUH2Be+coAKMcBYHFlSB9l5WvG/vGK7OoREsr3g7omB2BPbIYayeL3BEcHq3yFCDzD/TGWRoDCehNMut+HrW+iTZ2iwv5Xaxl0P7iQMh012goAaZxsLPmz/c4Qtt9SABRWhgNgbjnQRyQAy5qktpp9UPJLbjSxOALmQnGD9p+R9tuWA27LBb6xFxUHSfvt2wU29jazC/pQaznbbzUAqLD/F+nBQ+D60PEJYb+dSpDwqyfd4N/WX90fPVsnTIiTAPX8XRAgBI4Dre7wpP/t/RpU2LLXS07IcYGYD1fOWv+ipIBAb3r7GI9IiTf44ZUGiqx/UVKO/iesUvFr9mBcE2YenN1X9pnaP2aHIRhYeE0rbhuOMfbdbwanGXlR0vyoLeIJWZhzw5EXgK+BZ8n3DgB8+92O8tx1SogGRm0ZHrZG+OuUwZLLV81kn/pOVMaHtOTx7zcMRRJttvEDcN+xCGrrSuDj9njWYKUd91x8ABiFyPP2+Kdmnlryw6+PaAQ+bq9PuqmBi5GnTVKdHYve/rECZDZxMX1E90lPVOJZg8J6wwMXAdLzoTYycVN7ISaPLrmjxvbcr2ybCHLB8Wk/tXtq48+N0ci0SV4ap9aCbB26SkTYcvP0JwrXeGPd2s93paauvlJ57tWPbp297LYfMhQS/j50lcwPXc2GsbtKe5qQwmdNT2fn2F0XipgdvCwmL4f+R05ezq7By+BAo+Qfvf3/e/h6QXCTYPy+wRkILsxsggopGe1HhU0yf+TCgTnIiTjp/E8a54ATRfVlOXpElHz2ezgbXIgCgAqzGIGks79MhShfeZk5nQ8gk4n/5OGMmVGWrRyYli+5ECBUHk6dxvZHhUDKZNQ6WSDgtpXnU9j+KBGYOKm8PIhNyMUn9aMHpYOTtULkhPxICQ8Bm0/41V3guFktxebq1x9VgvOAj+gPrZwITkxDfvv0TehUwOTvuyCFy1SxQNCzFyUsDzj66dwrMZrPPHC792AeUKKZz9H/c3c3rgqd40CXrt0YggQk/+auXcBx4i7OjenUOcFSAZO/85IxMUW/5AG072D/lii2vr3tA6lPMwR+u1GCB3ZH/6h2PpsfWItC65GCB/ZG/8gvXwAn6CaVES1aWq+OWfe2bDHCQJuSA9B0mEgFNpJ/2GVJ/oB4kH59E04FFpO/ydp0Gf3B8aBho8acCiwlf+NFDWX0BwtB/SGKU4GF5FdD6hswX6SCuvVE24YNupfw9bpmyC9SQa3adTgVWEX+OrVrCfIb40H1GjU5FVhD/pq/VBfRb5QHVavZsSXy1ofVqoroNw2BU7mKBTzg6K9S2TFvvkwFFSpWymYI2PxKFSuYI3/kVFB2cPlsTAVM/vLlypolf+RUUKpMxFRgnvxlSkUkv3kIipcomS084OgvWaK4afMzTwVFihYzyYMI0V+saBER/dmSCgYU0kIdm9e9utAAC8xnHsB/CohUYJr8Bf7D5LdhOabLSJL8/fvlMrn12VZGEsWePnw5z6blAPS8k5gHpos9vXpaYr4oI40zWkYijv4eXOyxbnEZaay5MhKb322sLPZYlQo6dhrNqcAI+Ud36mhd9Ist8aSBMhKTHzucFFufjRD4bdoGzAOO/rZtfFvNF2WkExkB8oCjP+NEK4vJL1JB8+FeQOqYda83vLnd5Jep4KVmMacCSf5mL9lPfllG+mIop4K4yT/0C1nsSQgePPBaGqeCuMif9toDIvoTBoIfG2S1jCSKPQ1+FOYnVCrIPTUrZSRR7JmaW5I/wVLBsUdjKSMx+fc9ekySP/F4MG9DdGUkUezZME9Gf2Ly4MOPM98Sxdb38YcJHP2ijLTqbNQ84Og/u8pJbPNFGenMzqggYPN3npHFnoRPBV+HykiIFNH80Gvsg78W5E+KVHBXJmUkJj/OuitZyC/LSNddG4EHHP3XXlc8eaJf8uDbSbKM9Jdiz6Rvky36RRmpsEatBQ2ItEa9URZ7kjAVHLkbSf35gRCi0P/j3UeSk/yyjPTwz/zOkCJ+YEQTEea7ThZ7kpYHuVbnOaT+FAEqb57VuZI6+kUZCVJSc1yTM02hSrv2mhypKfyj2bD+B0JWDE5gxeP8AAAAAElFTkSuQmCC"; let spread = null; let sheet = null; let shapes = null; export function AppFunc() { const [fillEffectOption, setFillEffectOption] = React.useState({ active: false, color: '#00A2E8', transparency: 0, type: 0, direction: 0, angle: 0, stops: [ { position: 0, color: "#82BC00" }, { position: 0.5, color: "white" }, { position: 1, color: "orange" } ], src: defaultSrc, tilePictureAsTexture: false, offsetLeft: 0, offsetRight: 0, offsetTop: 0, offsetBottom: 0, offsetX: 0, offsetY: 0, scaleX: 1, scaleY: 1, alignment: 0, mirrorType: 0, }); const initSpread = (currSpread) => { spread = currSpread; sheet = spread.getActiveSheet(); shapes = sheet.shapes; addDefaultShape(); sheet.bind(GC.Spread.Sheets.Events.ShapeSelectionChanged, shapeSelectionChangedHandler); } const shapeSelectionChangedHandler = () => { var selectedShape = shapes.all().filter(function (sp) { return sp.isSelected() && sp instanceof GC.Spread.Sheets.Shapes.Shape; }); if (selectedShape.length === 1) { setFillEffectOption({ ...fillEffectOption, active: true }); } else { setFillEffectOption({ ...fillEffectOption, active: false }); } } const addDefaultShape = () => { let x = 30, y = 30, width = 200, height = 100, xGap = 260, yGap = 160; for (var i = 0; i < 9; i++) { var tx = x + xGap * (i % 3); var ty = y + yGap * Math.floor(i / 3); shapes.add("shape" + (i + 1), GC.Spread.Sheets.Shapes.AutoShapeType.rectangle, tx, ty, width, height); } setFill(shapes.get('shape1'), { type: GC.Spread.Sheets.Shapes.GradientFillType.linear, direction: GC.Spread.Sheets.Shapes.LinearGradientFillDirection.linearRight, stops: [ { color: '#f7a711', position: 0 }, { color: '#f7a711', position: 0.25 }, { color: '#f6c65e', position: 0.25 }, { color: '#f6c65e', position: 0.50 }, { color: '#f8e29c', position: 0.50 }, { color: '#f8e29c', position: 0.75 }, { color: '#fffada', position: 0.75 }, { color: '#fffada', position: 1 }, ] }); setFill(shapes.get('shape2'), { type: GC.Spread.Sheets.Shapes.GradientFillType.linear, direction: GC.Spread.Sheets.Shapes.LinearGradientFillDirection.linearDown, stops: [ { color: '#f7a711', position: 0 }, { color: '#ffffff', position: 1 }, ] }); setFill(shapes.get('shape3'), { type: GC.Spread.Sheets.Shapes.GradientFillType.linear, direction: GC.Spread.Sheets.Shapes.LinearGradientFillDirection.topLeftToBottomRight, stops: [ { color: '#82bc00', position: 0 }, { color: '#ffffff', position: 1 }, ] }); setFill(shapes.get('shape4'), { type: GC.Spread.Sheets.Shapes.GradientFillType.radial, direction: GC.Spread.Sheets.Shapes.RadialGradientFillDirection.fromCenter, stops: [ { color: '#82bc00', position: 0 }, { color: '#82bc00', position: 0.25 }, { color: '#afd25e', position: 0.25 }, { color: '#afd25e', position: 0.50 }, { color: '#d6e89e', position: 0.50 }, { color: '#d6e89e', position: 0.75 }, { color: '#f9ffdd', position: 0.75 }, { color: '#f9ffdd', position: 1 }, ] }); setFill(shapes.get('shape5'), { type: GC.Spread.Sheets.Shapes.GradientFillType.radial, direction: GC.Spread.Sheets.Shapes.RadialGradientFillDirection.fromCenter, stops: [ { color: '#82bc00', position: 0 }, { color: '#ffffff', position: 1 }, ] }); setFill(shapes.get('shape6'), { type: GC.Spread.Sheets.Shapes.GradientFillType.radial, direction: GC.Spread.Sheets.Shapes.RadialGradientFillDirection.fromBottomLeft, stops: [ { color: '#f7a711', position: 0 }, { color: '#ffffff', position: 1 }, ] }); loadImage("$DEMOROOT$/spread/source/images/logo.jpg", function (src) { setFill(shapes.get('shape7'), { src: src }); }); loadImage("$DEMOROOT$/spread/source/images/splogo.png", function (src) { setFill(shapes.get('shape8'), { src: src }); }); loadImage("$DEMOROOT$/spread/source/images/splogo.png", function (src) { setFill(shapes.get('shape9'), { src: src, tilePictureAsTexture: true, scaleX: 0.25, scaleY: 0.25 }); }); } const loadImage = (url, callback) => { try { var xhr = new XMLHttpRequest(); xhr.onload = function () { var blob = xhr.response; var fileReader = new FileReader(); fileReader.onload = function () { callback(fileReader.result); }; fileReader.readAsDataURL(blob); }; xhr.responseType = "blob"; xhr.open("GET", url); xhr.send(); } catch (error) { callback(defaultSrc); } } const setGradientFill = () => { setFill(getSelectedShape(), { type: fillEffectOption.type, direction: isNaN(fillEffectOption.direction) ? undefined : fillEffectOption.direction, angle: fillEffectOption.angle, stops: fillEffectOption.stops, }) } const setPictureOrTextureFill = () => { setFill(getSelectedShape(), { src: fillEffectOption.src, transparency: fillEffectOption.transparency, tilePictureAsTexture: fillEffectOption.tilePictureAsTexture, offsetLeft: fillEffectOption.offsetLeft, offsetRight: fillEffectOption.offsetRight, offsetTop: fillEffectOption.offsetTop, offsetBottom: fillEffectOption.offsetBottom, offsetX: fillEffectOption.offsetX, offsetY: fillEffectOption.offsetY, scaleX: fillEffectOption.scaleX, scaleY: fillEffectOption.scaleY, alignment: fillEffectOption.alignment, mirrorType: fillEffectOption.mirrorType, }); } const onImgChange = (e) => { var blob = e.target.files[0]; var fileReader = new FileReader(); fileReader.addEventListener('load', function () { setFillEffectOption({ ...fillEffectOption, src: fileReader.result }) }); fileReader.readAsDataURL(blob); } const getSelectedShape = () => { let selectedShape = null; shapes.all().forEach(shape => { if (shape.isSelected()) { selectedShape = shape; } }); return selectedShape; } const setFill = (shape, fill) => { let style = shape.style(); style.fill = fill; shape.style(style); } const tipEl = <div id="tip" class="options-container">Try selecting a shape to apply a fill effect.</div>; const linearDirectionItems = <React.Fragment> <option value="undefined">none</option> <option value="0">linearRight</option> <option value="45">topLeftToBottomRight</option> <option value="90">linearDown</option> <option value="135">topRightToBottomLeft</option> <option value="180">linearLeft</option> <option value="225">bottomRightToTopLeft</option> <option value="270">linearUp</option> <option value="315">bottomLeftToTopRight</option> </React.Fragment>; const radialDirectionItems = <React.Fragment> <option value="0">fromCenter</option> <option value="1">fromTopLeft</option> <option value="2">fromTopRight</option> <option value="3">fromBottomLeft</option> <option value="4">fromBottomRight</option> </React.Fragment>; const pictureFillOption = <div id="pictureFillOption"> <label>offsetLeft:</label> <input class="offsetLeft" type="number" min="-1" max="1" step="0.01" value={fillEffectOption.offsetLeft} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, offsetLeft: Number(e.target.value) }) }} /> <label>offsetRight:</label> <input class="offsetRight" type="number" min="-1" max="1" step="0.01" value={fillEffectOption.offsetRight} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, offsetRight: Number(e.target.value) }) }} /> <label>offsetTop:</label> <input class="offsetTop" type="number" min="-1" max="1" step="0.01" value={fillEffectOption.offsetTop} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, offsetTop: Number(e.target.value) }) }} /> <label>offsetBottom:</label> <input class="offsetBottom" type="number" min="-1" max="1" step="0.01" value={fillEffectOption.offsetBottom} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, offsetBottom: Number(e.target.value) }) }} /> </div> const textureFillOption = <div id='textureFillOption'> <label>offsetX:</label> <input class="offsetX" type="number" step="1" value={fillEffectOption.offsetX} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, offsetX: Number(e.target.value) }) }} /> <label>offsetY:</label> <input class="offsetY" type="number" step="1" value={fillEffectOption.offsetY} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, offsetY: Number(e.target.value) }) }} /> <label>scaleX:</label> <input class="scaleX" type="number" min="0" max="1" step="0.01" value={fillEffectOption.scaleX} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, scaleX: Number(e.target.value) }) }} /> <label>scaleY:</label> <input class="scaleY" type="number" min="0" max="1" step="0.01" value={fillEffectOption.scaleY} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, scaleY: Number(e.target.value) }) }} /> <label>alignment:</label> <select class="alignment" value={fillEffectOption.alignment} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, alignment: Number(e.target.value) }) }}> <option value="0">Top Left</option> <option value="1">Top </option> <option value="2">Top Right</option> <option value="3">Left</option> <option value="4">Center</option> <option value="5">Right</option> <option value="6">Bottom Left</option> <option value="7">Bottom</option> <option value="8">Bottom Right</option> </select> <label>mirrorType:</label> <select class="mirrorType" value={fillEffectOption.mirrorType} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, mirrorType: Number(e.target.value) }) }}> <option value="0">None</option> <option value="1">Horizontal</option> <option value="2">Vertical</option> <option value="3">Both</option> </select> </div> const propEl = <div id="fillProp" class="options-container"> <div id="shapeGradientFill" class="option-row"> <label class="title">Gradient Fill</label> <label>Graient Fill Type: </label> <select class='type' value={fillEffectOption.type} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, type: Number(e.target.value), direction: 0 }) }}> <option value="0">linear</option> <option value="1">radial</option> </select> <label>Direction: </label> <select class='direction' value={fillEffectOption.direction} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, direction: Number(e.target.value) }) }}> {fillEffectOption.type === 0 ? linearDirectionItems : radialDirectionItems} </select> <label>Angle: </label> <input class='angle' type="number" value={fillEffectOption.angle} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, angle: Number(e.target.value) }) }} /> <label>Color Stops: </label> <textarea class='stops' rows="10" value={JSON.stringify(fillEffectOption.stops, null, 2)} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, stops: JSON.parse(e.target.value) }) }}></textarea> <button class='setBtn' onClick={setGradientFill}>Set Gradient Fill</button> </div> <div class="divide-line"></div> <label class="title">Picture Or Texture Fill</label> <div id="pictureOrTextureFill" class="option-row"> <label>Image: </label> <input class="imgInput" type="file" accept="image/*" onChange={(e) => { onImgChange(e) }} /> <label>transparency: </label> <input class="transparency" type="number" min="0" max="1" step="0.01" value={fillEffectOption.transparency} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, transparency: Number(e.target.value) }) }} /> <br></br> tilePictureAsTexture: <input class="tilePictureAsTexture" type="checkbox" checked={fillEffectOption.tilePictureAsTexture} onChange={(e) => { setFillEffectOption({ ...fillEffectOption, tilePictureAsTexture: e.target.checked }) }} /> <div class="divide-line"></div> {fillEffectOption.tilePictureAsTexture ? textureFillOption : pictureFillOption} <div class="divide-line"></div> <button class='setBtn' onClick={setPictureOrTextureFill}>Set Picture Or Texture Fill</button> </div> </div> return ( <div class="sample-tutorial"> <div id="ss" class="sample-spreadsheets"> <SpreadSheets workbookInitialized={spread => initSpread(spread)}> </SpreadSheets> </div> {fillEffectOption.active ? propEl : tipEl} </div> ); }
import * as React from 'react'; import GC from '@mescius/spread-sheets'; import "@mescius/spread-sheets-shapes"; import { SpreadSheets } from "@mescius/spread-sheets-react"; import '@mescius/spread-sheets-resources-ko'; GC.Spread.Common.CultureManager.culture("ko-kr"); const defaultSrc = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAMAAABrrFhUAAAC5VBMVEUAAACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvACCvABHaHJoAAAA93RSTlMAAhZNh7re8/3/3QEIS6Lh/qFgz/xGyPvJKKipEYTxBV/cPMDBIZ75DXnsVNU0txqU9glu5krNLK4UifIGZN9BxSWj+g9+7wNa2Vk4vB6Z9wtz6U/RMLIXjvRp4ynwg5+t4MSkJO7Y+B10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"; const Component = React.Component; export class App extends Component { constructor(props) { super(props); this.spread = null; this.state = { active: false, color: '#00A2E8', transparency: 0, type: 0, direction: 0, angle: 0, stops: [ { position: 0, color: "#82BC00" }, { position: 0.5, color: "white" }, { position: 1, color: "orange" } ], src: defaultSrc, tilePictureAsTexture: false, offsetLeft: 0, offsetRight: 0, offsetTop: 0, offsetBottom: 0, offsetX: 0, offsetY: 0, scaleX: 1, scaleY: 1, alignment: 0, mirrorType: 0, } this.setGradientFill = this.setGradientFill.bind(this); this.setPictureOrTextureFill = this.setPictureOrTextureFill.bind(this); this.onImgChange = this.onImgChange.bind(this); this.shapeSelectionChangedHandler = this.shapeSelectionChangedHandler.bind(this); } render() { const tipEl = <div id="tip" class="options-container">Try selecting a shape to apply a fill effect.</div>; const linearDirectionItems = <React.Fragment> <option value="undefined">none</option> <option value="0">linearRight</option> <option value="45">topLeftToBottomRight</option> <option value="90">linearDown</option> <option value="135">topRightToBottomLeft</option> <option value="180">linearLeft</option> <option value="225">bottomRightToTopLeft</option> <option value="270">linearUp</option> <option value="315">bottomLeftToTopRight</option> </React.Fragment>; const radialDirectionItems = <React.Fragment> <option value="0">fromCenter</option> <option value="1">fromTopLeft</option> <option value="2">fromTopRight</option> <option value="3">fromBottomLeft</option> <option value="4">fromBottomRight</option> </React.Fragment>; const pictureFillOption = <div id="pictureFillOption"> <label>offsetLeft:</label> <input class="offsetLeft" type="number" min="-1" max="1" step="0.01" value={this.state.offsetLeft} onChange={(e) => { this.setState({ offsetLeft: Number(e.target.value) }) }} /> <label>offsetRight:</label> <input class="offsetRight" type="number" min="-1" max="1" step="0.01" value={this.state.offsetRight} onChange={(e) => { this.setState({ offsetRight: Number(e.target.value) }) }} /> <label>offsetTop:</label> <input class="offsetTop" type="number" min="-1" max="1" step="0.01" value={this.state.offsetTop} onChange={(e) => { this.setState({ offsetTop: Number(e.target.value) }) }} /> <label>offsetBottom:</label> <input class="offsetBottom" type="number" min="-1" max="1" step="0.01" value={this.state.offsetBottom} onChange={(e) => { this.setState({ offsetBottom: Number(e.target.value) }) }} /> </div> const textureFillOption = <div id='textureFillOption'> <label>offsetX:</label> <input class="offsetX" type="number" step="1" value={this.state.offsetX} onChange={(e) => { this.setState({ offsetX: Number(e.target.value) }) }} /> <label>offsetY:</label> <input class="offsetY" type="number" step="1" value={this.state.offsetY} onChange={(e) => { this.setState({ offsetY: Number(e.target.value) }) }} /> <label>scaleX:</label> <input class="scaleX" type="number" min="0" max="1" step="0.01" value={this.state.scaleX} onChange={(e) => { this.setState({ scaleX: Number(e.target.value) }) }} /> <label>scaleY:</label> <input class="scaleY" type="number" min="0" max="1" step="0.01" value={this.state.scaleY} onChange={(e) => { this.setState({ scaleY: Number(e.target.value) }) }} /> <label>alignment:</label> <select class="alignment" value={this.state.alignment} onChange={(e) => { this.setState({ alignment: Number(e.target.value) }) }}> <option value="0">Top Left</option> <option value="1">Top </option> <option value="2">Top Right</option> <option value="3">Left</option> <option value="4">Center</option> <option value="5">Right</option> <option value="6">Bottom Left</option> <option value="7">Bottom</option> <option value="8">Bottom Right</option> </select> <label>mirrorType:</label> <select class="mirrorType" value={this.state.mirrorType} onChange={(e) => { this.setState({ mirrorType: Number(e.target.value) }) }}> <option value="0">None</option> <option value="1">Horizontal</option> <option value="2">Vertical</option> <option value="3">Both</option> </select> </div> const propEl = <div id="fillProp" class="options-container"> <div id="shapeGradientFill" class="option-row"> <label class="title">Gradient Fill</label> <label>Graient Fill Type: </label> <select class='type' value={this.state.type} onChange={(e) => { this.setState({ type: Number(e.target.value), direction: 0 }) }}> <option value="0">linear</option> <option value="1">radial</option> </select> <label>Direction: </label> <select class='direction' value={this.state.direction} onChange={(e) => { this.setState({ direction: Number(e.target.value) }) }}> {this.state.type === 0 ? linearDirectionItems : radialDirectionItems} </select> <label>Angle: </label> <input class='angle' type="number" value={this.state.angle} onChange={(e) => { this.setState({ angle: Number(e.target.value) }) }} /> <label>Color Stops: </label> <textarea class='stops' rows="10" value={JSON.stringify(this.state.stops, null, 2)} onChange={(e) => { this.setState({ stops: JSON.parse(e.target.value) }) }}></textarea> <button class='setBtn' onClick={this.setGradientFill}>Set Gradient Fill</button> </div> <div class="divide-line"></div> <label class="title">Picture Or Texture Fill</label> <div id="pictureOrTextureFill" class="option-row"> <label>Image: </label> <input class="imgInput" type="file" accept="image/*" onChange={(e) => { this.onImgChange(e) }} /> <label>transparency: </label> <input class="transparency" type="number" min="0" max="1" step="0.01" value={this.state.transparency} onChange={(e) => { this.setState({ transparency: Number(e.target.value) }) }} /> <br></br> tilePictureAsTexture: <input class="tilePictureAsTexture" type="checkbox" checked={this.state.tilePictureAsTexture} onChange={(e) => { this.setState({ tilePictureAsTexture: e.target.checked }) }} /> <div class="divide-line"></div> {this.state.tilePictureAsTexture ? textureFillOption : pictureFillOption} <div class="divide-line"></div> <button class='setBtn' onClick={this.setPictureOrTextureFill}>Set Picture Or Texture Fill</button> </div> </div> return ( <div class="sample-tutorial"> <div id="ss" class="sample-spreadsheets"> <SpreadSheets workbookInitialized={spread => this.initSpread(spread)}> </SpreadSheets> </div> {this.state.active ? propEl : tipEl} </div> ); } initSpread(spread) { this.spread = spread; this.sheet = this.spread.getActiveSheet(); this.shapes = this.sheet.shapes; this.addDefaultShape(); this.sheet.bind(GC.Spread.Sheets.Events.ShapeSelectionChanged, this.shapeSelectionChangedHandler); } shapeSelectionChangedHandler() { var selectedShape = this.shapes.all().filter(function (sp) { return sp.isSelected() && sp instanceof GC.Spread.Sheets.Shapes.Shape; }); if (selectedShape.length === 1) { this.setState({ active: true }); } else { this.setState({ active: false }); } } addDefaultShape() { let shapes = this.shapes, setFill = this.setFill, loadImage = this.loadImage; let x = 30, y = 30, width = 200, height = 100, xGap = 260, yGap = 160; for (var i = 0; i < 9; i++) { var tx = x + xGap * (i % 3); var ty = y + yGap * Math.floor(i / 3); shapes.add("shape" + (i + 1), GC.Spread.Sheets.Shapes.AutoShapeType.rectangle, tx, ty, width, height); } setFill(shapes.get('shape1'), { type: GC.Spread.Sheets.Shapes.GradientFillType.linear, direction: GC.Spread.Sheets.Shapes.LinearGradientFillDirection.linearRight, stops: [ { color: '#f7a711', position: 0 }, { color: '#f7a711', position: 0.25 }, { color: '#f6c65e', position: 0.25 }, { color: '#f6c65e', position: 0.50 }, { color: '#f8e29c', position: 0.50 }, { color: '#f8e29c', position: 0.75 }, { color: '#fffada', position: 0.75 }, { color: '#fffada', position: 1 }, ] }); setFill(shapes.get('shape2'), { type: GC.Spread.Sheets.Shapes.GradientFillType.linear, direction: GC.Spread.Sheets.Shapes.LinearGradientFillDirection.linearDown, stops: [ { color: '#f7a711', position: 0 }, { color: '#ffffff', position: 1 }, ] }); setFill(shapes.get('shape3'), { type: GC.Spread.Sheets.Shapes.GradientFillType.linear, direction: GC.Spread.Sheets.Shapes.LinearGradientFillDirection.topLeftToBottomRight, stops: [ { color: '#82bc00', position: 0 }, { color: '#ffffff', position: 1 }, ] }); setFill(shapes.get('shape4'), { type: GC.Spread.Sheets.Shapes.GradientFillType.radial, direction: GC.Spread.Sheets.Shapes.RadialGradientFillDirection.fromCenter, stops: [ { color: '#82bc00', position: 0 }, { color: '#82bc00', position: 0.25 }, { color: '#afd25e', position: 0.25 }, { color: '#afd25e', position: 0.50 }, { color: '#d6e89e', position: 0.50 }, { color: '#d6e89e', position: 0.75 }, { color: '#f9ffdd', position: 0.75 }, { color: '#f9ffdd', position: 1 }, ] }); setFill(shapes.get('shape5'), { type: GC.Spread.Sheets.Shapes.GradientFillType.radial, direction: GC.Spread.Sheets.Shapes.RadialGradientFillDirection.fromCenter, stops: [ { color: '#82bc00', position: 0 }, { color: '#ffffff', position: 1 }, ] }); setFill(shapes.get('shape6'), { type: GC.Spread.Sheets.Shapes.GradientFillType.radial, direction: GC.Spread.Sheets.Shapes.RadialGradientFillDirection.fromBottomLeft, stops: [ { color: '#f7a711', position: 0 }, { color: '#ffffff', position: 1 }, ] }); loadImage("$DEMOROOT$/spread/source/images/logo.jpg", function (src) { setFill(shapes.get('shape7'), { src: src }); }); loadImage("$DEMOROOT$/spread/source/images/splogo.png", function (src) { setFill(shapes.get('shape8'), { src: src }); }); loadImage("$DEMOROOT$/spread/source/images/splogo.png", function (src) { setFill(shapes.get('shape9'), { src: src, tilePictureAsTexture: true, scaleX: 0.25, scaleY: 0.25 }); }); } loadImage(url, callback) { try { var xhr = new XMLHttpRequest(); xhr.onload = function () { var blob = xhr.response; var fileReader = new FileReader(); fileReader.onload = function () { callback(fileReader.result); }; fileReader.readAsDataURL(blob); }; xhr.responseType = "blob"; xhr.open("GET", url); xhr.send(); } catch (error) { callback(defaultSrc); } } setGradientFill() { this.setFill(this.getSelectedShape(), { type: this.state.type, direction: isNaN(this.state.direction) ? undefined : this.state.direction, angle: this.state.angle, stops: this.state.stops, }) } setPictureOrTextureFill() { this.setFill(this.getSelectedShape(), { src: this.state.src, transparency: this.state.transparency, tilePictureAsTexture: this.state.tilePictureAsTexture, offsetLeft: this.state.offsetLeft, offsetRight: this.state.offsetRight, offsetTop: this.state.offsetTop, offsetBottom: this.state.offsetBottom, offsetX: this.state.offsetX, offsetY: this.state.offsetY, scaleX: this.state.scaleX, scaleY: this.state.scaleY, alignment: this.state.alignment, mirrorType: this.state.mirrorType, }); } onImgChange(e) { var self = this; var blob = e.target.files[0]; var fileReader = new FileReader(); fileReader.addEventListener('load', function () { self.setState({ src: fileReader.result }) }); fileReader.readAsDataURL(blob); } getSelectedShape() { let selectedShape = null; this.shapes.all().forEach(shape => { if (shape.isSelected()) { selectedShape = shape; } }); return selectedShape; } setFill(shape, fill) { let style = shape.style(); style.fill = fill; shape.style(style); } }
<!doctype html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/ko/react/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <!-- SystemJS --> <script src="$DEMOROOT$/ko/react/node_modules/systemjs/dist/system.src.js"></script> <script src="systemjs.config.js"></script> <script> System.import('$DEMOROOT$/ko/lib/react/license.js').then(function () { System.import('./src/app'); }); </script> </head> <body> <div id="app"></div> </body> </html>
.sample-tutorial { position: relative; height: 100%; overflow: hidden; } .sample-spreadsheets { width: calc(100% - 280px); height: 100%; overflow: hidden; float: left; } .options-container { float: right; width: 280px; padding: 12px; height: 100%; box-sizing: border-box; background: #fbfbfb; overflow: auto; } .option-row { font-size: 14px; padding-left: 5px; } .divide-line { width: 100%; height: 1px; background: #cbcbcb; margin-top: 10px; margin-bottom: 3px; } .title { text-align: center; font-weight: bold; } label { display: block; margin-top: 15px; margin-bottom: 5px; } p { padding: 2px 10px; background-color: #F4F8EB; } input { margin-left: 10px; display: inline; } input[type=button] { width: 50px; margin-left: 1px; } select { width: 160px; margin-left: 10px; display: inline; } textarea { width: 210px; margin: 0px 0px; margin-left: 10px; padding: 2px; } body { position: absolute; top: 0; bottom: 0; left: 0; right: 0; } .setBtn { width: 220px; height: 31px; margin: 12px 10px; } #app { height: 100%; }
(function (global) { System.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true, react: true }, meta: { '*.css': { loader: 'css' } }, paths: { // paths serve as alias 'npm:': 'node_modules/' }, // map tells the System loader where to look for things map: { '@mescius/spread-sheets': 'npm:@mescius/spread-sheets/index.js', '@mescius/spread-sheets-shapes': 'npm:@mescius/spread-sheets-shapes/index.js', '@mescius/spread-sheets-react': 'npm:@mescius/spread-sheets-react/index.js', '@mescius/spread-sheets-resources-ko': 'npm:@mescius/spread-sheets-resources-ko/index.js', '@grapecity/jsob-test-dependency-package/react-components': 'npm:@grapecity/jsob-test-dependency-package/react-components/index.js', 'react': 'npm:react/umd/react.production.min.js', 'react-dom': 'npm:react-dom/umd/react-dom.production.min.js', 'css': 'npm:systemjs-plugin-css/css.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', 'systemjs-babel-build':'npm:systemjs-plugin-babel/systemjs-babel-browser.js' }, // packages tells the System loader how to load when no filename and/or no extension packages: { src: { defaultExtension: 'jsx' }, "node_modules": { defaultExtension: 'js' }, } }); })(this);